@rr0/ufoathome 0.65.3 → 0.65.4
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.
|
@@ -693,7 +693,7 @@ input[type=range] {
|
|
|
693
693
|
pointer-events: none;
|
|
694
694
|
white-space: nowrap;
|
|
695
695
|
}
|
|
696
|
-
`,Uo=[{id:"eye",name:{en:"Naked eye",fr:"Œil nu"},flare:0,projection:"equidistant",stabilization:.97},{id:"rectilinear-lens",name:{en:"Camera, unknown device",fr:"Appareil, modèle inconnu"},projection:"rectilinear",fNumber:8,fNumberRange:{min:2,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:8},apertureBlades:6},{id:"instamatic-126",name:{en:"Instamatic, 126 film",fr:"Instamatic, film 126"},projection:"rectilinear",frame:{widthMm:28,heightMm:28,focalLengthMm:43},fNumber:11,exposureSeconds:1/90,years:{from:1963,to:1988},apertureBlades:5,detailUm:20},{id:"slr-35mm-50",name:{en:"35 mm SLR, 50 mm lens",fr:"Reflex 35 mm, objectif 50 mm"},projection:"rectilinear",frame:{widthMm:36,heightMm:24,focalLengthMm:50},fNumber:8,fNumberRange:{min:2,max:16},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:3600},years:{from:1959},apertureBlades:6,detailUm:20},{id:"slr-35mm-zoom",name:{en:"35 mm SLR, 70-210 mm zoom",fr:"Reflex 35 mm, zoom 70-210 mm"},projection:"rectilinear",frame:{widthMm:36,heightMm:24,focalLengthMm:135,focalRangeMm:{minMm:70,maxMm:210}},fNumber:8,fNumberRange:{min:4,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:3600},apertureBlades:8,years:{from:1975},detailUm:20},{id:"phone-landscape",name:{en:"Phone, held sideways",fr:"Téléphone, tenu couché"},projection:"rectilinear",frame:{widthMm:7.6,heightMm:5.7,focalLengthMm:5.7},fNumber:1.8,exposureSeconds:1/120,exposureRangeSeconds:{min:1/8e3,max:10},years:{from:2007},apertureBlades:void 0,detailUm:1.4},{id:"phone-portrait",name:{en:"Phone, held upright",fr:"Téléphone, tenu debout"},projection:"rectilinear",frame:{widthMm:5.7,heightMm:7.6,focalLengthMm:5.7},fNumber:1.8,exposureSeconds:1/120,exposureRangeSeconds:{min:1/8e3,max:10},years:{from:2007},apertureBlades:void 0,detailUm:1.4}];class ri{static get default(){return Uo[0]}static byId(t){return Uo.find(e=>e.id===t)??this.default}static UNAIDED_FIELD_DEG=60;static UNAIDED_ASPECT=16/9;static fieldOfViewDeg(t){const e=t.frame;return e?2*Math.atan(e.heightMm/(2*e.focalLengthMm))*180/Math.PI:ri.UNAIDED_FIELD_DEG}static aspectOf(t){const e=t.frame;return e?e.widthMm/e.heightMm:ri.UNAIDED_ASPECT}static frameWidthPx(t,e){return Math.round(e*ri.aspectOf(t))}static availableAt(t){return t===void 0?Uo:Uo.filter(e=>!e.years||t>=e.years.from&&(e.years.to===void 0||t<=e.years.to))}static fieldOfViewDegAt(t,e){const i=t.frame;if(!(!i||e<=0))return 2*Math.atan(i.heightMm/(2*e))*180/Math.PI}static focalLengthMmFor(t,e){const i=t.frame;if(!(!i||e<=0||e>=180))return i.heightMm/(2*Math.tan(e*Math.PI/360))}static bladesShowing(t,e){const i=e??t.fNumber;if(i===void 0||t.apertureBlades===void 0)return 0;const n=t.fNumberRange;return!n||n.max<=n.min?1:Math.max(0,Math.min(1,(i-n.min)/(n.max-n.min)))}static LENS_FLARE_ARTIFACTS=1;static flareArtifactsOf(t){return t.flare??ri.LENS_FLARE_ARTIFACTS}static starPointsOf(t){const e=t.apertureBlades;return e===void 0||e<3?0:e%2===0?e:e*2}}class mo{constructor(t){this.points=t}static STATIONARY_M=5;static of(t){const e=[];for(const i of t.witnessTrack.allKeyframes){const{lat:n,lng:s,headingDeg:r}=i.pose;n===void 0||s===void 0||e.push({t:i.t,lat:n,lng:s,headingDeg:r})}if(e.length===0){const i=t.event.place?.[0];if(!i)return;e.push({t:0,lat:i.lat,lng:i.lng})}return new mo(e)}get moved(){return this.spanM>mo.STATIONARY_M}get spanM(){const t=this.box,e=(t.south+t.north)/2,i=(t.west+t.east)/2;return Math.max(Math.abs(li(e,t.east,e,t.west).x),Math.abs(li(t.north,i,t.south,i).z))}get center(){const t=this.box;return{lat:(t.south+t.north)/2,lng:(t.west+t.east)/2}}boundsAround(t,e){const{lat:i,lng:n}=this.center,s=Math.max(this.spanM*(1+e),t)/2;return{north:ps(0,-s,i,n).lat,south:ps(0,s,i,n).lat,east:ps(s,0,i,n).lng,west:ps(-s,0,i,n).lng}}get box(){const t=this.points.map(i=>i.lat),e=this.points.map(i=>i.lng);return{south:Math.min(...t),north:Math.max(...t),west:Math.min(...e),east:Math.max(...e)}}}class si{constructor(t,e){this.stretches=t,this.rotationPassed=e}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 STILL=Object.freeze({eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0});static of(t){const e=mo.of(t);if(!e||e.points.length<2)return;const i=[];let n=0;for(let s=1;s<e.points.length;s++){const r=e.points[s-1],o=e.points[s],c=(o.t-r.t)/1e3;if(c<=0)continue;const l=li(o.lat,o.lng,r.lat,r.lng),h=l.x,u=-l.z,d=Math.hypot(h,u),f=d/c,p=si.stepHzFor(f);i.push({startMs:r.t,endMs:o.t,speedMPerS:f,eastUnit:d>0?h/d:0,northUnit:d>0?u/d:0,stepHz:p,stepsBefore:n,rampsIn:!0,rampsOut:!0}),n+=p*c}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 si(i,1-(t.instrument.stabilization??0))}static stepHzFor(t){return t<si.SLOWEST_WALK_M_PER_S||t>si.FASTEST_WALK_M_PER_S?0:si.REFERENCE_STEP_HZ*Math.pow(t/si.REFERENCE_SPEED_M_PER_S,si.CADENCE_EXPONENT)}offsetAt(t){const e=this.stretches.find(c=>t>=c.startMs&&t<=c.endMs);if(!e||e.stepHz===0)return si.STILL;const i=e.stepsBefore+e.stepHz*(t-e.startMs)/1e3,n=2*Math.PI*i,s=this.amplitudeAt(e,t),r=si.SWAY_M*s*Math.cos(n/2),o=s*this.rotationPassed*e.speedMPerS/si.REFERENCE_SPEED_M_PER_S;return{eastM:r*e.northUnit,northM:-r*e.eastUnit,upM:si.RISE_M_PER_M_PER_S*e.speedMPerS*s*Math.cos(n),rollDeg:si.HEAD_ROLL_DEG*o*Math.cos(n/2),pitchDeg:-1.25*o*Math.cos(n),yawDeg:si.HEAD_YAW_DEG*o*Math.cos(n/2)}}amplitudeAt(t,e){const i=1e3/t.stepHz,n=Math.min(i,(t.endMs-t.startMs)/2);if(n<=0)return 1;const s=e-t.startMs,r=t.endMs-e,o=Math.min(t.rampsIn?s/n:1,t.rampsOut?r/n:1,1);return(1-Math.cos(Math.PI*Math.max(o,0)))/2}}class Re{static MOON_ANGULAR_WIDTH_DEG=.5237;static CANVAS_WIDTH_PX=640;static CANVAS_HEIGHT_PX=360;static angularWidthDeg(t){return 2*Math.atan(t.sizeM/(2*t.distanceM))*180/Math.PI}static inMoons(t){return t/Re.MOON_ANGULAR_WIDTH_DEG}static lerpAngular(t,e,i){if(!(!t||!e))return{widthDeg:t.widthDeg+(e.widthDeg-t.widthDeg)*i,heightDeg:t.heightDeg+(e.heightDeg-t.heightDeg)*i}}static sizeMAt(t,e){return 2*t*Math.tan(e*Math.PI/360)}static distanceMAt(t,e){return t/(2*Math.tan(e*Math.PI/360))}}function U1(a,t,e){if(!a||!t)return e<1?a:t;const i=((t.azimuthDeg-a.azimuthDeg)%360+540)%360-180;return{azimuthDeg:((a.azimuthDeg+i*e)%360+360)%360,altitudeDeg:a.altitudeDeg+(t.altitudeDeg-a.altitudeDeg)*e}}function F1(a,t,e){const{bounds:i}=a;return t>=i.x&&t<=i.x+i.width&&e>=i.y&&e<=i.y+i.height}function Gi(a,t,e){return a+(t-a)*e}function I0(a){const t=/^#([0-9a-f]{6})$/i.exec(a);if(!t)return;const e=parseInt(t[1],16);return[e>>16&255,e>>8&255,e&255]}function k1(a){return`#${a.map(t=>Math.round(t).toString(16).padStart(2,"0")).join("")}`}function z1(a,t,e){const i=I0(a),n=I0(t);return!i||!n?e<1?a:t:k1([Gi(i[0],n[0],e),Gi(i[1],n[1],e),Gi(i[2],n[2],e)])}function B1(a,t,e){const i={x:Gi(a.bounds.x,t.bounds.x,e),y:Gi(a.bounds.y,t.bounds.y,e),width:Gi(a.bounds.width,t.bounds.width,e),height:Gi(a.bounds.height,t.bounds.height,e)},n=Gi(a.angle,t.angle,e),s=Gi(a.transparency,t.transparency,e),r=Gi(a.haloScale,t.haloScale,e),o=Gi(a.blur??0,t.blur??0,e),c=Gi(a.brightness??0,t.brightness??0,e),l=z1(a.color,t.color,e),h=Re.lerpAngular(a.angular,t.angular,e),u=U1(a.aim,t.aim,e);return a.kind==="polygon"&&t.kind==="polygon"&&a.points.length===t.points.length?{...a,bounds:i,angle:n,transparency:s,haloScale:r,blur:o,brightness:c,color:l,angular:h,aim:u,points:a.points.map((d,f)=>({x:Gi(d.x,t.points[f].x,e),y:Gi(d.y,t.points[f].y,e)}))}:{...e<1?a:t,bounds:i,angle:n,transparency:s,haloScale:r,blur:o,brightness:c,color:l,angular:h,aim:u}}class _l{keyframes=[];order=[];groups=[];addKeyframe(t,e){const i=this.findInsertIndex(t);if(this.keyframes[i]?.t===t){const n=new Set(e.map(s=>s.sourceId));this.keyframes[i]={t,shapes:[...this.keyframes[i].shapes.filter(s=>!n.has(s.sourceId)),...e]}}else this.keyframes.splice(i,0,{t,shapes:[...e]});for(const n of e)this.order.includes(n.sourceId)||this.order.push(n.sourceId)}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}getKeyframeAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e];return i?.t===t?i:void 0}getShapeAt(t,e){return this.getKeyframeAt(t)?.shapes.find(i=>i.sourceId===e)?.shape}getLatestShapeAt(t,e){let i=this.findInsertIndex(t);for(this.keyframes[i]?.t!==t&&(i-=1);i>=0;i--){const n=this.keyframes[i].shapes.find(s=>s.sourceId===e);if(n)return n.shape}}getInterpolatedShapeAt(t,e){const i=this.findShapeAtOrBefore(t,e);if(i?.t===t)return i.shape;const n=this.findShapeAtOrAfter(t,e);return i?n?B1(i.shape,n.shape,(t-i.t)/(n.t-i.t)):i.shape:n?.shape}findShapeAtOrBefore(t,e){let i=this.findInsertIndex(t);for(this.keyframes[i]?.t!==t&&(i-=1);i>=0;i--){const n=this.keyframes[i].shapes.find(s=>s.sourceId===e);if(n)return{t:this.keyframes[i].t,shape:n.shape}}}findShapeAtOrAfter(t,e){for(let i=this.findInsertIndex(t);i<this.keyframes.length;i++){const n=this.keyframes[i].shapes.find(s=>s.sourceId===e);if(n)return{t:this.keyframes[i].t,shape:n.shape}}}hitTest(t,e,i,n){const s=this.sourceIds;for(let r=s.length-1;r>=0;r--){if(n?.has(s[r]))continue;const o=this.getInterpolatedShapeAt(t,s[r]);if(o&&F1(o,e,i))return{sourceId:s[r],shape:o}}}removeSource(t){for(let e=this.keyframes.length-1;e>=0;e--){const i=this.keyframes[e].shapes.filter(n=>n.sourceId!==t);i.length===0?this.keyframes.splice(e,1):i.length!==this.keyframes[e].shapes.length&&(this.keyframes[e]={t:this.keyframes[e].t,shapes:i})}this.order=this.order.filter(e=>e!==t),this.removeFromGroup(t)}group(t){if(!(t.length<2)){for(const e of t)this.removeFromGroup(e);this.groups.push([...t])}}ungroup(t){const e=this.groups.findIndex(i=>i.includes(t));e!==-1&&this.groups.splice(e,1)}groupMembers(t){return this.groups.find(e=>e.includes(t))}removeFromGroup(t){const e=this.groups.findIndex(n=>n.includes(t));if(e===-1)return;const i=this.groups[e].filter(n=>n!==t);i.length<2?this.groups.splice(e,1):this.groups[e]=i}bringToFront(t){const e=this.order.indexOf(t);e!==-1&&(this.order.splice(e,1),this.order.push(t))}sendToBack(t){const e=this.order.indexOf(t);e!==-1&&(this.order.splice(e,1),this.order.unshift(t))}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get sourceIds(){return[...this.order]}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes,order:this.order,groups:this.groups}}static fromJSON(t){const e=new _l;for(const i of t.keyframes)e.addKeyframe(i.t,i.shapes);if(t.order){const i=e.order.filter(n=>!t.order.includes(n));e.order=[...t.order,...i]}return t.groups&&(e.groups=t.groups.map(i=>i.filter(n=>e.order.includes(n))).filter(i=>i.length>=2)),e}}function H1(a,t,e){return Math.max(t,Math.min(e,a))}function G1(a,t,e){const i=((t-a)%360+540)%360-180;return((a+i*e)%360+360)%360}function Da(a,t,e){return a+(t-a)*e}function V1(a,t,e){return{lat:a.lat===void 0||t.lat===void 0?void 0:Da(a.lat,t.lat,e),lng:a.lng===void 0||t.lng===void 0?void 0:Da(a.lng,t.lng,e),elevationM:Da(a.elevationM,t.elevationM,e),headingDeg:a.headingDeg===void 0||t.headingDeg===void 0?void 0:G1(a.headingDeg,t.headingDeg,e),pitchDeg:Da(a.pitchDeg,t.pitchDeg,e),rollDeg:Da(a.rollDeg??0,t.rollDeg??0,e),fovDeg:Da(a.fovDeg,t.fovDeg,e),fNumber:a.fNumber,focusDistanceM:a.focusDistanceM}}class go{keyframes=[];addKeyframe(t,e){const i=this.findInsertIndex(t);this.keyframes[i]?.t===t?this.keyframes[i]={t,pose:e}:this.keyframes.splice(i,0,{t,pose:e})}clear(){this.keyframes.length=0}removeKeyframeAt(t){const e=this.findInsertIndex(t);this.keyframes[e]?.t===t&&this.keyframes.splice(e,1)}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}getLatestPoseAt(t){let e=this.findInsertIndex(t);return this.keyframes[e]?.t!==t&&(e-=1),e>=0?this.keyframes[e].pose:void 0}getInterpolatedPoseAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e]?.t===t?this.keyframes[e]:this.keyframes[e-1];if(i?.t===t)return i.pose;const n=this.keyframes[e]?.t===t?void 0:this.keyframes[e];return i?n?V1(i.pose,n.pose,H1((t-i.t)/(n.t-i.t),0,1)):i.pose:n?.pose}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(t){const e=new go;for(const i of t.keyframes)e.addKeyframe(i.t,i.pose);return e}}function Ie(a,t,e){return a+(t-a)*e}function Cd(a,t,e){const i=((t-a)%360+540)%360-180;return((a+i*e)%360+360)%360}function W1(a,t,e){return Math.max(t,Math.min(e,a))}function X1(a=[],t=[],e){if(!(!a.length&&!t.length))return[...new Set([...a.map(i=>i.id),...t.map(i=>i.id)])].map(i=>{const n=a.find(c=>c.id===i),s=t.find(c=>c.id===i),r=n??{...s,density:0},o=s??{...n,density:0};return{...r,eastM:Ie(r.eastM,o.eastM,e),northM:Ie(r.northM,o.northM,e),baseM:Ie(r.baseM,o.baseM,e),thicknessM:Ie(r.thicknessM,o.thicknessM,e),widthM:Ie(r.widthM,o.widthM,e),depthM:Ie(r.depthM,o.depthM,e),rotationDeg:Cd(r.rotationDeg,o.rotationDeg,e),density:Ie(r.density,o.density,e),darkness:Ie(r.darkness??0,o.darkness??0,e)}})}function q1(a,t,e){if(a.cloudLayers===void 0&&t.cloudLayers===void 0)return;const i=$c(a),n=$c(t);return e>=1?n.map(r=>({...r})):[...new Set([...i.map(r=>r.id),...n.map(r=>r.id)])].map(r=>{const o=i.find(u=>u.id===r),c=n.find(u=>u.id===r),l=o??{...c,coverage:0},h=c??{...o,coverage:0};return{...l,instances:X1(o?.instances,c?.instances,e),baseM:Ie(l.baseM,h.baseM,e),thicknessM:Ie(l.thicknessM,h.thicknessM,e),coverage:Ie(l.coverage,h.coverage,e),sizeM:Ie(l.sizeM,h.sizeM,e),density:Ie(l.density,h.density,e),darkness:Ie(l.darkness??a.cloudDarkness,h.darkness??t.cloudDarkness,e),iceCrystalAlignment:l.iceCrystalAlignment===void 0||h.iceCrystalAlignment===void 0?void 0:Ie(l.iceCrystalAlignment,h.iceCrystalAlignment,e),windSpeed:l.windSpeed===void 0&&h.windSpeed===void 0?void 0:Ie(l.windSpeed??a.windSpeed,h.windSpeed??t.windSpeed,e),windDirectionDeg:l.windDirectionDeg===void 0&&h.windDirectionDeg===void 0?void 0:Cd(l.windDirectionDeg??a.windDirectionDeg,h.windDirectionDeg??t.windDirectionDeg,e)}})}function Y1(a,t,e){return{cloudLayers:q1(a,t,e),cloudCover:Ie(a.cloudCover,t.cloudCover,e),cloudDarkness:Ie(a.cloudDarkness,t.cloudDarkness,e),highCloudCover:a.highCloudCover===void 0||t.highCloudCover===void 0?void 0:Ie(a.highCloudCover,t.highCloudCover,e),iceCrystalAlignment:a.iceCrystalAlignment===void 0||t.iceCrystalAlignment===void 0?void 0:Ie(a.iceCrystalAlignment,t.iceCrystalAlignment,e),lowerCloudCover:a.lowerCloudCover===void 0||t.lowerCloudCover===void 0?void 0:Ie(a.lowerCloudCover,t.lowerCloudCover,e),cloudBaseM:a.cloudBaseM===void 0||t.cloudBaseM===void 0?void 0:Ie(a.cloudBaseM,t.cloudBaseM,e),relativeHumidity:a.relativeHumidity===void 0||t.relativeHumidity===void 0?void 0:Ie(a.relativeHumidity,t.relativeHumidity,e),precipitationType:e<1?a.precipitationType:t.precipitationType,precipitationIntensity:Ie(a.precipitationIntensity,t.precipitationIntensity,e),windDirectionDeg:Cd(a.windDirectionDeg,t.windDirectionDeg,e),windSpeed:Ie(a.windSpeed,t.windSpeed,e),storm:e<1?a.storm:t.storm}}class vo{keyframes=[];addKeyframe(t,e){const i=this.findInsertIndex(t);this.keyframes[i]?.t===t?this.keyframes[i]={t,weather:e}:this.keyframes.splice(i,0,{t,weather:e})}clear(){this.keyframes.length=0}removeKeyframeAt(t){const e=this.findInsertIndex(t);this.keyframes[e]?.t===t&&this.keyframes.splice(e,1)}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}getLatestWeatherAt(t){let e=this.findInsertIndex(t);return this.keyframes[e]?.t!==t&&(e-=1),e>=0?this.keyframes[e].weather:void 0}getInterpolatedWeatherAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e]?.t===t?this.keyframes[e]:this.keyframes[e-1];if(i?.t===t)return i.weather;const n=this.keyframes[e]?.t===t?void 0:this.keyframes[e];return i?n?Y1(i.weather,n.weather,W1((t-i.t)/(n.t-i.t),0,1)):i.weather:n?.weather}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(t){const e=new vo;for(const i of t.keyframes)e.addKeyframe(i.t,i.weather);return e}}class Mo{keyframes=[];addKeyframe(t,e){const i=this.findInsertIndex(t);this.keyframes[i]?.t===t?this.keyframes[i]={t,sound:e}:this.keyframes.splice(i,0,{t,sound:e})}clear(){this.keyframes.length=0}removeKeyframeAt(t){const e=this.findInsertIndex(t);this.keyframes[e]?.t===t&&this.keyframes.splice(e,1)}getLatestSoundAt(t){let e=this.findInsertIndex(t);return this.keyframes[e]?.t!==t&&(e-=1),e>=0?this.keyframes[e].sound:void 0}getInterpolatedSoundAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e]?.t===t?this.keyframes[e]:this.keyframes[e-1];if(i?.t===t)return i.sound;const n=this.keyframes[e]?.t===t?void 0:this.keyframes[e];if(!i)return n?.sound;if(!n)return i.sound;const s=(t-i.t)/(n.t-i.t);return this.lerp(i.sound,n.sound,Math.max(0,Math.min(1,s)))}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(t){const e=new Mo;for(const i of t.keyframes)e.addKeyframe(i.t,i.sound);return e}lerp(t,e,i){return{kind:i<1?t.kind:e.kind,volume:t.volume+(e.volume-t.volume)*i,pitchHz:t.pitchHz+(e.pitchHz-t.pitchHz)*i,src:i<1?t.src:e.src}}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}}const K1=100,$1={kind:"none",volume:0,pitchHz:K1};class dn{constructor(t){this.entries=t}static empty(){return new dn(new Map)}get size(){return this.entries.size}at(t){return this.entries.get(t)}paths(){return[...this.entries.keys()]}set(t,e){e.basis==="stated"&&e.rationale===void 0?this.entries.delete(t):this.entries.set(t,e)}clear(t){for(const e of this.entries.keys())(e===t||e.startsWith(`${t}.`))&&this.entries.delete(e)}static strip(t){const e=new dn(new Map);return{recording:dn.stripValue(t,[],e),provenance:e}}static restore(t,e){if(e.size===0)return t;const i=structuredClone(t);for(const n of e.paths()){const s=e.at(n),r=n.split("."),o=dn.holderOf(i,r);if(!o)continue;const c=r[r.length-1],l=o[c];l!==void 0&&(s.of!==void 0&&JSON.stringify(s.of)!==JSON.stringify(l)||(o[c]={value:l,...s.basis==="stated"?{}:{basis:s.basis},...s.rationale===void 0?{}:{rationale:s.rationale}}))}return i}static isWrapper(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)&&"value"in t}static stripValue(t,e,i){return dn.isWrapper(t)?(i.set(e.join("."),{basis:t.basis??"stated",...t.rationale===void 0?{}:{rationale:t.rationale},of:t.value}),dn.stripValue(t.value,e,i)):Array.isArray(t)?t.map((n,s)=>dn.stripValue(n,[...e,String(s)],i)):typeof t=="object"&&t!==null?Object.fromEntries(Object.entries(t).map(([n,s])=>[n,dn.stripValue(s,[...e,n],i)])):t}static holderOf(t,e){let i=t;for(const n of e.slice(0,-1)){if(typeof i!="object"||i===null)return;i=i[n]}return typeof i=="object"&&i!==null?i:void 0}}function au(a){if(a.year!==void 0)return Date.UTC(a.year,(a.month??1)-1,a.day??1,a.hour??0,a.minute??0,a.second??0)}function P0(a){return(((a.day??0)*24+(a.hour??0))*60+(a.minute??0))*6e4+(a.second??0)*1e3}const Z1=["year","month","day","hour","minute"],J1=["day","hour","minute"];function L0(a,t){return t.filter(e=>a[e]!==void 0).join(",")}function j1(a){if(a.durationSeconds!==void 0)return a.durationSeconds*1e3;if(!a.time||!a.endTime)return;const t=a.time.year!==void 0&&a.endTime.year!==void 0,e=t?Z1:J1,i=L0(a.time,e);if(!(i===""||i!==L0(a.endTime,e)))return t?au(a.endTime)-au(a.time):P0(a.endTime)-P0(a.time)}class Sl{constructor(t,e,i,n,s,r,o,c,l=[],h,u,d,f=[],p=[],v=[]){this.event=t,this.timeline=e,this.witnessTrack=i,this.weatherTrack=n,this.soundTrack=s,this.witness=r,this.id=o,this.weather=c,this.decor=l,this.weatherSource=h,this.instrumentId=u,this.exposureSeconds=d,this.milestones=f,this.references=p,this.roads=v}provenance=dn.empty();testimony;interpretation;get witnessCount(){return 1+this.decor.filter(t=>t.kind==="witness").length}get exposure(){return this.exposureSeconds??this.instrument.exposureSeconds}get instrument(){return ri.byId(this.instrumentId)}static create(t,e,i){return new Sl({eventType:"sighting",time:t,place:e},new _l,new go,new vo,new Mo,i)}}const Q1=0,t2=0;function ai(a,t){const e=a.witnessTrack.getInterpolatedPoseAt(t);if(e)return e;const i=a.event.place?.[0];if(i)return{lat:i.lat,lng:i.lng,elevationM:Q1,headingDeg:void 0,pitchDeg:t2,fovDeg:ri.fieldOfViewDeg(a.instrument)}}function Qs(a,t){return a.weatherTrack.getInterpolatedWeatherAt(t)??a.weather??Om}function e2(a,t){return a.soundTrack.getInterpolatedSoundAt(t)??$1}class i2{constructor(t,e){this.timeline=t,this.onFrame=e}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 t=()=>{if(this.state!=="playing")return;const e=performance.now();if(this.currentT+=(e-this.lastWallTime)*this.playbackRate,this.lastWallTime=e,this.currentT>=this.seekableDuration){if(this.loop&&this.seekableDuration>0){this.currentT%=this.seekableDuration,this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(t);return}this.currentT=this.seekableDuration,this.stop(),this.resolveFrame(this.currentT),this.onEnded?.();return}this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(t)};this.rafId=requestAnimationFrame(t)}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(t){this.currentT=Math.max(0,Math.min(t,this.seekableDuration)),this.resolveFrame(this.currentT)}get playbackState(){return this.state}get time(){return this.currentT}resolveFrame(t){const e=new Map;for(const i of this.timeline.sourceIds){const n=this.timeline.getInterpolatedShapeAt(t,i);n&&e.set(i,n)}this.onFrame(t,e)}}const km=["nw","n","ne","e","se","s","sw","w"],n2=24,Fo=8,s2=3,a2=8;function ko(a,t,e){const i=a.x-t.x,n=a.y-t.y,s=Math.cos(e),r=Math.sin(e);return{x:t.x+i*s-n*r,y:t.y+i*r+n*s}}function Dr(a){return{x:a.x+a.width/2,y:a.y+a.height/2}}const r2={nw:{left:!0,top:!0},n:{top:!0},ne:{right:!0,top:!0},e:{right:!0},se:{right:!0,bottom:!0},s:{bottom:!0},sw:{left:!0,bottom:!0},w:{left:!0}};class ji{static handlePointsFor(t){const{x:e,y:i,width:n,height:s}=t.bounds,r={nw:{x:e,y:i},n:{x:e+n/2,y:i},ne:{x:e+n,y:i},e:{x:e+n,y:i+s/2},se:{x:e+n,y:i+s},s:{x:e+n/2,y:i+s},sw:{x:e,y:i+s},w:{x:e,y:i+s/2},rotate:{x:e+n/2,y:i-n2}},o=Dr(t.bounds),c={};for(const l of Object.keys(r))c[l]=ko(r[l],o,t.angle);return c}static hitTestHandle(t,e,i=8,n=[...km,"rotate"]){const s=ji.handlePointsFor(t);for(const r of n)if(Math.hypot(e.x-s[r].x,e.y-s[r].y)<=i)return r}static HANDLE_DIRECTION_DEG={e:0,se:45,s:90,sw:135,w:180,nw:225,n:270,ne:315};static resizeAxisFor(t,e){const n=((ji.HANDLE_DIRECTION_DEG[t]+e*180/Math.PI)%180+180)%180/45,s=["ew","nwse","ns","nesw"];return s[Math.round(n)%s.length]}static resizeBounds(t,e,i,n){const s=Dr(t),r=ko(n,s,-e),{x:o,y:c,width:l,height:h}=t,u=r2[i];let d=o,f=c,p=o+l,v=c+h;return u.left&&(d=Math.min(r.x,p-Fo)),u.right&&(p=Math.max(r.x,d+Fo)),u.top&&(f=Math.min(r.y,v-Fo)),u.bottom&&(v=Math.max(r.y,f+Fo)),{x:d,y:f,width:p-d,height:v-f}}static resizeShape(t,e,i){if(e==="rotate")throw new Error("resizeShape does not accept the rotate handle");const{width:n,height:s}=t.bounds,r=ji.resizeBounds(t.bounds,t.angle,e,i);if(t.kind==="oval")return{...t,bounds:r};const o=n===0?1:r.width/n,c=s===0?1:r.height/s;return{...t,bounds:r,points:t.points.map(l=>({x:l.x*o,y:l.y*c}))}}static rotateShape(t,e){const i=Dr(t.bounds),n=Math.atan2(e.y-i.y,e.x-i.x)+Math.PI/2;return{...t,angle:n}}static groupBoundsFor(t){const e=Math.min(...t.map(r=>r.x)),i=Math.min(...t.map(r=>r.y)),n=Math.max(...t.map(r=>r.x+r.width)),s=Math.max(...t.map(r=>r.y+r.height));return{x:e,y:i,width:n-e,height:s-i}}static vertexPointsFor(t){const e=Dr(t.bounds);return t.points.map(i=>ko({x:t.bounds.x+i.x,y:t.bounds.y+i.y},e,t.angle))}static hitTestVertex(t,e,i=a2){const n=ji.vertexPointsFor(t);let s,r=i;return n.forEach((o,c)=>{const l=Math.hypot(e.x-o.x,e.y-o.y);l<=r&&(r=l,s=c)}),s}static toLocalPoint(t,e){const i=Dr(t.bounds),n=ko(e,i,-t.angle);return{x:n.x-t.bounds.x,y:n.y-t.bounds.y}}static moveVertex(t,e,i){const n=t.points.map((u,d)=>d===e?ji.toLocalPoint(t,i):u),s=Math.min(...n.map(u=>u.x)),r=Math.min(...n.map(u=>u.y)),o=Math.max(...n.map(u=>u.x)),c=Math.max(...n.map(u=>u.y)),l={x:t.bounds.x+s,y:t.bounds.y+r,width:o-s,height:c-r},h=n.map(u=>({x:u.x-s,y:u.y-r}));return{...t,bounds:l,points:h}}static insertVertexNear(t,e){const i=ji.toLocalPoint(t,e),{points:n}=t;let s=n.length-1,r=1/0;for(let c=0;c<n.length;c++){const l=n[c],h=n[(c+1)%n.length],u=ji.distanceToSegment(i,l,h);u<r&&(r=u,s=c)}const o=[...n.slice(0,s+1),i,...n.slice(s+1)];return{...t,points:o}}static distanceToSegment(t,e,i){const n=i.x-e.x,s=i.y-e.y,r=n*n+s*s,o=r===0?0:Math.max(0,Math.min(1,((t.x-e.x)*n+(t.y-e.y)*s)/r)),c=e.x+o*n,l=e.y+o*s;return Math.hypot(t.x-c,t.y-l)}static deleteVertex(t,e){return t.points.length<=s2?t:{...t,points:t.points.filter((i,n)=>n!==e)}}}const ru=6,zo=ru/2,N0=20,O0=24,U0=9,F0=6,k0=7,z0=6,Un=4;class xo{constructor(t){this.ctx=t}starPoints=0;roll=0;clear(t,e){this.ctx.clearRect(0,0,t,e)}static paintExtent(t){const{x:e,y:i,width:n,height:s}=t.bounds,r=e+n/2,o=i+s/2,c=t.angle%(2*Math.PI)!==0,l=Math.hypot(n,s)/2,h=c?l:n/2,u=c?l:s/2,d=Math.max(n,s)/2,f=t.brightness??0,p=f>0?Math.max(d*(1+U0*f),z0*f)-d:0,v=f>0?d*(1+k0*f)-d:0,m=3*O0*(t.blur??0)+1.5*N0*t.haloScale,g=Math.max(p,v,0)+m+2;return{x:r-h-g,y:o-u-g,width:2*(h+g),height:2*(u+g)}}paintInto(t,e,i,n=!1){this.ctx.save(),this.ctx.scale(i,i),this.ctx.translate(-e.x,-e.y);const s=t.selected?{...t,selected:!1}:t;n?this.paintGhost(s,1.5):this.paintShape(s),this.ctx.restore()}paintShape(t){this.ctx.save(),this.ctx.globalAlpha=1-t.transparency;const e=t.blur??0;e>0&&(this.ctx.filter=`blur(${(O0*e).toFixed(2)}px)`);const i=t.brightness??0;i>0&&this.paintDazzle(t,i),t.haloScale>0&&this.paintHalo(t),this.paintBase(t),this.ctx.restore(),t.selected&&this.paintSelectionHandles(t)}setStarPoints(t){this.starPoints=Math.max(0,Math.floor(t))}setRoll(t){this.roll=t}paintDazzle(t,e){const{x:i,y:n,width:s,height:r}=t.bounds,o=i+s/2,c=n+r/2,l=Math.max(s,r)/2,h=Math.max(l*(1+U0*e),z0*e);if(h<=0)return;this.ctx.save(),this.ctx.globalCompositeOperation="lighter";const u=this.ctx.createRadialGradient(o,c,0,o,c,h);for(let d=0;d<=F0;d++){const f=d/F0,p=1/(1+24*f*f);this.ctx.globalAlpha=1,u.addColorStop(f,this.withAlpha(t.color,p*e*.55))}if(this.ctx.fillStyle=u,this.ctx.beginPath(),this.ctx.arc(o,c,h,0,2*Math.PI),this.ctx.fill(),this.starPoints>0){const d=l*(1+k0*e);this.ctx.lineWidth=Math.max(1,l*.12),this.ctx.lineCap="round";for(let f=0;f<this.starPoints;f++){const p=f/this.starPoints*Math.PI*2+this.roll,v=o+Math.cos(p)*d,m=c+Math.sin(p)*d,g=this.ctx.createLinearGradient(o,c,v,m);g.addColorStop(0,this.withAlpha(t.color,e*.55)),g.addColorStop(.35,this.withAlpha(t.color,e*.22)),g.addColorStop(1,this.withAlpha(t.color,0)),this.ctx.strokeStyle=g,this.ctx.beginPath(),this.ctx.moveTo(o,c),this.ctx.lineTo(v,m),this.ctx.stroke()}}this.ctx.restore()}dazzledFill(t,e){if(e<=0)return t.color;const i=/^#([0-9a-f]{6})$/i.exec(t.color.trim());if(!i)return t.color;const n=Number.parseInt(i[1],16),s=r=>Math.round(r+(255-r)*e);return`rgb(${s(n>>16&255)}, ${s(n>>8&255)}, ${s(n&255)})`}withAlpha(t,e){const i=Math.max(0,Math.min(1,e)),n=/^#([0-9a-f]{6})$/i.exec(t.trim());if(!n)return t;const s=Number.parseInt(n[1],16);return`rgba(${s>>16&255}, ${s>>8&255}, ${s&255}, ${i.toFixed(3)})`}paintBase(t){this.ctx.fillStyle=this.dazzledFill(t,t.brightness??0),this.tracePath(t),this.ctx.fill()}paintGhost(t,e){this.ctx.save(),this.tracePath(t),this.ctx.setLineDash([e*3,e*2]),this.ctx.lineWidth=e,this.ctx.strokeStyle=t.color,this.ctx.stroke(),this.ctx.restore()}tracePath(t){if(this.ctx.beginPath(),t.kind==="oval"){const{x:e,y:i,width:n,height:s}=t.bounds,r=n/2,o=s/2;this.ctx.ellipse(e+r,i+o,r,o,t.angle,0,2*Math.PI)}else{const{x:e,y:i,width:n,height:s}=t.bounds;this.ctx.save(),this.ctx.translate(e+n/2,i+s/2),this.ctx.rotate(t.angle),this.ctx.translate(-n/2,-s/2),t.points.forEach((r,o)=>{o===0?this.ctx.moveTo(r.x,r.y):this.ctx.lineTo(r.x,r.y)}),this.ctx.closePath(),this.ctx.restore()}}paintHalo(t){this.ctx.save(),this.ctx.shadowColor=t.color,this.ctx.shadowBlur=N0*t.haloScale,this.paintBase(t),this.ctx.restore()}paintSelectionHandles(t){this.paintHandleFrame(ji.handlePointsFor(t),{includeRotate:!0}),t.kind==="polygon"&&this.paintVertexHandles(t)}paintVertexHandles(t){this.ctx.fillStyle="#39f";for(const e of ji.vertexPointsFor(t))this.ctx.beginPath(),this.ctx.ellipse(e.x,e.y,Un,Un,0,0,2*Math.PI),this.ctx.fill()}paintMemberOutline(t){this.paintOutline(ji.handlePointsFor(t))}paintSelectionOnly(t){this.paintSelectionHandles(t)}paintPictureFrame(t,e,i){const n=this.ctx;if(n.save(),t&&t.length===4){n.strokeStyle="#39f",n.lineWidth=1.5,n.setLineDash([6,4]),n.beginPath(),n.moveTo(t[0].x,t[0].y);for(const s of t.slice(1))n.lineTo(s.x,s.y);n.closePath(),n.stroke(),n.setLineDash([])}for(const s of e){const r=xo.landmarkColour(s.residualDeg),o=s.selected?3:2;s.selected&&(n.strokeStyle="#fff",n.lineWidth=o+3,n.beginPath(),n.ellipse(s.picture.x,s.picture.y,Un+2,Un+2,0,0,2*Math.PI),n.stroke()),s.scene&&(n.strokeStyle=r,n.lineWidth=1,n.beginPath(),n.moveTo(s.picture.x,s.picture.y),n.lineTo(s.scene.x,s.scene.y),n.stroke(),n.fillStyle=r,n.beginPath(),n.ellipse(s.scene.x,s.scene.y,Un,Un,0,0,2*Math.PI),n.fill()),n.strokeStyle=r,n.lineWidth=o,n.beginPath(),n.ellipse(s.picture.x,s.picture.y,Un+2,Un+2,0,0,2*Math.PI),n.stroke(),this.paintLabel(s.label,s.picture.x+Un+5,s.picture.y-Un-2,r)}i&&this.paintLabel(i,8,8,"#fff",13),n.restore()}static landmarkColour(t){return t===void 0?"#ffb000":t<=1?"#3c3":t<=3?"#ffb000":"#f33"}paintLabel(t,e,i,n,s=11){const r=this.ctx;r.save(),r.font=`${s}px system-ui, sans-serif`,r.textBaseline="top";const o=r.measureText(t).width;r.fillStyle="rgba(0, 0, 0, 0.6)",r.fillRect(e-3,i-2,o+6,s+4),r.fillStyle=n,r.fillText(t,e,i),r.restore()}paintGroupHandles(t){this.paintHandleFrame(ji.handlePointsFor({bounds:t,angle:0}),{includeRotate:!0})}paintOutline(t){this.ctx.strokeStyle="lightgray",this.ctx.beginPath(),this.ctx.moveTo(t.nw.x,t.nw.y),this.ctx.lineTo(t.ne.x,t.ne.y),this.ctx.lineTo(t.se.x,t.se.y),this.ctx.lineTo(t.sw.x,t.sw.y),this.ctx.closePath(),this.ctx.stroke()}paintHandleFrame(t,{includeRotate:e}){this.paintOutline(t),this.ctx.fillStyle="lightgray";for(const i of km){const n=t[i];this.ctx.fillRect(n.x-zo,n.y-zo,ru,ru)}e&&(this.ctx.beginPath(),this.ctx.moveTo(t.n.x,t.n.y),this.ctx.lineTo(t.rotate.x,t.rotate.y),this.ctx.stroke(),this.ctx.beginPath(),this.ctx.ellipse(t.rotate.x,t.rotate.y,zo+1,zo+1,0,0,2*Math.PI),this.ctx.fill())}}const B0=.05,H0=.08,G0=2,V0=3,o2=14,c2=.02;class l2{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(t){console.warn("SightingAudio: Web Audio unavailable, the sighting stays silent:",t);return}}this.context.state==="suspended"&&this.context.resume()}setSound(t){if(this.requested=t,!this.context)return;const e=this.keyFor(t);if(!e){this.silence();return}if(this.voice?.key!==e){this.stopVoice();const i=++this.voiceToken;e.startsWith("src:")?this.buildRecordedVoice(t.src,e,i):this.voice=this.buildSynthesizedVoice(t,e)}this.applyTo(this.voice,t)}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(t){if(!(t.volume<=0))return t.src?`src:${t.src}`:t.kind==="none"?void 0:t.kind}applyTo(t,e){const i=this.context;if(!t||!i)return;const n=i.currentTime;t.volumeParam.setTargetAtTime(Math.max(0,Math.min(1,e.volume))*t.gainScale,n,B0);for(const{param:s,ratio:r}of t.pitch)s.setTargetAtTime(Math.min(e.pitchHz*r,i.sampleRate/2-1),n,B0)}buildSynthesizedVoice(t,e){const i=this.context;if(i)switch(t.kind){case"hum":return this.buildHum(i,e);case"whistle":return this.buildWhistle(i,e);case"rumble":return this.buildRumble(i,e);case"crackle":return this.buildCrackle(i,e);default:return}}buildHum(t,e){const i=t.createOscillator();i.type="sawtooth";const n=t.createOscillator();n.type="sawtooth";const s=t.createBiquadFilter();s.type="lowpass",s.Q.value=1;const r=t.createGain();return r.gain.value=0,i.connect(s),n.connect(s),s.connect(r).connect(t.destination),i.start(),n.start(),{key:e,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(t,e){const i=t.createOscillator();i.type="sine";const n=t.createOscillator();n.type="sine",n.frequency.value=5;const s=t.createGain(),r=t.createGain();return r.gain.value=0,n.connect(s).connect(i.frequency),i.connect(r).connect(t.destination),i.start(),n.start(),{key:e,nodes:[s,r],sources:[i,n],volumeParam:r.gain,gainScale:.22,pitch:[{param:i.frequency,ratio:1},{param:s.gain,ratio:.012}]}}buildRumble(t,e){const i=t.createBufferSource();i.buffer=this.brownNoise(t),i.loop=!0;const n=t.createBiquadFilter();n.type="lowpass",n.Q.value=.8;const s=t.createGain();return s.gain.value=0,i.connect(n).connect(s).connect(t.destination),i.start(),{key:e,nodes:[n,s],sources:[i],volumeParam:s.gain,gainScale:1.4,pitch:[{param:n.frequency,ratio:1}]}}buildCrackle(t,e){const i=t.createBufferSource();i.buffer=this.whiteNoise(t),i.loop=!0;const n=t.createBiquadFilter();n.type="bandpass",n.Q.value=1.2;const s=t.createGain();s.gain.value=0;const r=t.createBufferSource();r.buffer=this.crackleEnvelope(t),r.loop=!0;const o=t.createGain();return o.gain.value=0,r.connect(o).connect(s.gain),i.connect(n).connect(s).connect(t.destination),i.start(),r.start(),{key:e,nodes:[n,s,o],sources:[i,r],volumeParam:o.gain,gainScale:.9,pitch:[{param:n.frequency,ratio:4}]}}async buildRecordedVoice(t,e,i){const n=this.context;if(!n)return;let s;try{s=await this.getBuffer(t)}catch(c){console.warn("SightingAudio: the recorded sound failed to load, staying silent:",c);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:e,nodes:[o],sources:[r],volumeParam:o.gain,gainScale:1,pitch:[]},this.requested&&this.applyTo(this.voice,this.requested)}async getBuffer(t){const e=this.context;if(!e)throw new Error("SightingAudio: AudioContext not ready — resume() must be called first");let i=this.buffers.get(t);return i||(i=fetch(t).then(n=>{if(!n.ok)throw new Error(`Audio fetch failed (${n.status}): ${t}`);return n.arrayBuffer()}).then(n=>e.decodeAudioData(n)),this.buffers.set(t,i)),i}whiteNoise(t){if(!this.noiseBuffer){const e=t.createBuffer(1,Math.floor(t.sampleRate*G0),t.sampleRate),i=e.getChannelData(0);for(let n=0;n<i.length;n++)i[n]=Math.random()*2-1;this.noiseBuffer=e}return this.noiseBuffer}brownNoise(t){const e=t.createBuffer(1,Math.floor(t.sampleRate*G0),t.sampleRate),i=e.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 e}crackleEnvelope(t){if(!this.crackleBuffer){const e=t.createBuffer(1,Math.floor(t.sampleRate*V0),t.sampleRate),i=e.getChannelData(0),n=Math.max(1,Math.floor(c2*t.sampleRate)),s=Math.round(V0*o2);for(let r=0;r<s;r++){const o=Math.floor(Math.random()*i.length),c=.4+Math.random()*.6;for(let l=0;l<n&&o+l<i.length;l++)i[o+l]=Math.max(i[o+l],c*(1-l/n))}this.crackleBuffer=e}return this.crackleBuffer}stopVoice(){const t=this.voice,e=this.context;if(this.voice=void 0,!t||!e)return;const i=e.currentTime;t.volumeParam.cancelScheduledValues(i),t.volumeParam.setTargetAtTime(0,i,H0/3);const n=i+H0;for(const s of t.sources){s.onended=()=>{s.disconnect();for(const r of t.nodes)r.disconnect()};try{s.stop(n)}catch{s.disconnect();for(const r of t.nodes)r.disconnect()}}}}function Jc(a){return[...a].sort((t,e)=>t.t-e.t)}function W0(a,t){let e;for(const i of Jc(a)){if(i.t>t)break;e=i}return e}const zl=Math.PI/180,Bo=180/Math.PI;class ms{constructor(t,e,i){this.kind=t,this.canvasHeightPx=e,this.fovDeg=i;const n=i*zl/2;this.focalPx=t==="equidistant"?e/2/n:e/2/Math.tan(n)}focalPx;static of(t,e,i){return new ms(t.projection,e,i)}degToPx(t){const e=t*zl;return this.kind==="equidistant"?this.focalPx*e:2*this.focalPx*Math.tan(e/2)}pxToDeg(t){return this.kind==="equidistant"?t/this.focalPx*Bo:2*Math.atan(t/(2*this.focalPx))*Bo}angleDegToRadiusPx(t){const e=t*zl;return this.kind==="equidistant"?this.focalPx*e:this.focalPx*Math.tan(e)}halfWidthAngleDeg(t){return this.radiusPxToAngleDeg(this.canvasHeightPx*t/2)}radiusPxToAngleDeg(t){return this.kind==="equidistant"?t/this.focalPx*Bo:Math.atan(t/this.focalPx)*Bo}ofBounds(t){return{widthDeg:this.pxToDeg(t.width),heightDeg:this.pxToDeg(t.height)}}toBoundsSize(t){return{width:this.degToPx(t.widthDeg),height:this.degToPx(t.heightDeg)}}widthPx(t){return this.degToPx(Re.angularWidthDeg(t))}}class Wi{static fovOf(t,e){return ai(t,e)?.fovDeg??ri.fieldOfViewDeg(t.instrument)}static toAngular(t){this.eachKeyframe(t,(e,i)=>({...e,angular:i.ofBounds(e.bounds)}))}static toBounds(t){this.eachKeyframe(t,(e,i)=>{if(!e.angular)return e;const{width:n,height:s}=i.toBoundsSize(e.angular),r={x:e.bounds.x+(e.bounds.width-n)/2,y:e.bounds.y+(e.bounds.height-s)/2,width:n,height:s};if(e.kind!=="polygon")return{...e,bounds:r};const o=e.bounds.width===0?1:n/e.bounds.width,c=e.bounds.height===0?1:s/e.bounds.height;return{...e,bounds:r,points:e.points.map(l=>({x:l.x*o,y:l.y*c}))}})}static toAim(t){this.eachKeyframe(t,(e,i,n)=>{const s=e.aim&&this.positionOf(t,e.aim,e.bounds,i,n);if(s&&Math.abs(s.x-e.bounds.x)<Wi.UNMOVED_PX&&Math.abs(s.y-e.bounds.y)<Wi.UNMOVED_PX)return e;const r=this.aimFrom(t,i,n,e.bounds);return r?{...e,aim:r}:e})}static UNMOVED_PX=.01;static aimOf(t,e,i){const n=ms.of(t.instrument,Re.CANVAS_HEIGHT_PX,this.fovOf(t,e));return this.aimFrom(t,n,ai(t,e),i)}static aimFrom(t,e,i,n){if(i?.headingDeg===void 0)return;const s=this.frameCentre(t),r=e.radiusPxToAngleDeg(n.x+n.width/2-s.x),o=e.radiusPxToAngleDeg(s.y-(n.y+n.height/2));return{azimuthDeg:((i.headingDeg+r)%360+360)%360,altitudeDeg:i.pitchDeg+o}}static toPosition(t){this.eachKeyframe(t,(e,i,n)=>{const s=e.aim&&this.positionOf(t,e.aim,e.bounds,i,n);return s?{...e,bounds:{...e.bounds,...s}}:e})}static positionOf(t,e,i,n,s){if(s?.headingDeg===void 0)return;const r=this.frameCentre(t),o=this.shortestArc(e.azimuthDeg-s.headingDeg),c=e.altitudeDeg-s.pitchDeg;return{x:r.x+this.offAxisPx(n,o)-i.width/2,y:r.y-this.offAxisPx(n,c)-i.height/2}}static frameCentre(t){return{x:ri.frameWidthPx(t.instrument,Re.CANVAS_HEIGHT_PX)/2,y:Re.CANVAS_HEIGHT_PX/2}}static shortestArc(t){return(t%360+540)%360-180}static offAxisPx(t,e){return Math.abs(e)>=Wi.OFF_CANVAS_DEG?Math.sign(e)*Wi.OFF_CANVAS_PX:t.angleDegToRadiusPx(e)}static OFF_CANVAS_DEG=89;static OFF_CANVAS_PX=1e5;static reproject(t,e,i){const n=ri.frameWidthPx(e,Re.CANVAS_HEIGHT_PX)/2,s=ri.frameWidthPx(t.instrument,Re.CANVAS_HEIGHT_PX)/2,r=Re.CANVAS_HEIGHT_PX/2;for(const o of[...t.timeline.allKeyframes]){const c=this.fovOf(t,o.t),l=i?.get(o.t)??c,h=ms.of(e,Re.CANVAS_HEIGHT_PX,l),u=ms.of(t.instrument,Re.CANVAS_HEIGHT_PX,c);t.timeline.addKeyframe(o.t,o.shapes.map(d=>{const{bounds:f}=d.shape,p=f.x+f.width/2-n,v=f.y+f.height/2-r,m=Math.hypot(p,v),g=m===0?1:u.angleDegToRadiusPx(h.radiusPxToAngleDeg(m))/m,_={...f,x:s+p*g-f.width/2,y:r+v*g-f.height/2};return{...d,shape:{...d.shape,bounds:_}}}))}this.toBounds(t)}static eachKeyframe(t,e){const{timeline:i}=t;for(const n of[...i.allKeyframes]){const s=ai(t,n.t),r=this.fovOf(t,n.t),o=ms.of(t.instrument,Re.CANVAS_HEIGHT_PX,r);i.addKeyframe(n.t,n.shapes.map(c=>({...c,shape:e(c.shape,o,s)})))}}}function h2(a){return dn.restore(u2(a),a.provenance)}function u2(a){return Wi.toAngular(a),Wi.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,witness:a.witness,testimony:a.testimony,description:a.event.description,tags:a.event.tags,timeline:a.timeline.toJSON(),witnessTrack:a.witnessTrack.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,interpretation:a.interpretation}}function d2(a){const{recording:t,provenance:e}=dn.strip(a),i=f2(t);return i.provenance=e,i}function f2(a){const t=new Sl({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},_l.fromJSON(a.timeline),a.witnessTrack?go.fromJSON(a.witnessTrack):new go,a.weatherTrack?vo.fromJSON(a.weatherTrack):new vo,a.soundTrack?Mo.fromJSON(a.soundTrack):new Mo,a.witness&&{id:a.witness.id,title:a.witness.title,lastName:a.witness.lastName,firstNames:a.witness.firstNames},a.id,a.weather,a.decor??[],a.weatherSource,a.instrument,a.exposureSeconds??a.witnessTrack?.keyframes.map(e=>e.pose.exposureSeconds).find(e=>e!==void 0),Jc(a.milestones??[]),a.references??[],a.roads??[]);return t.testimony=a.testimony,t.interpretation=a.interpretation,Wi.toBounds(t),Wi.toPosition(t),t}const X0=2;function zm(a){return a==="building"||a==="vehicle"}function p2(a,t){const e=a.litKeyframes;if(!e||e.length===0)return a.lit??!1;let i=e[0];for(const n of e){if(n.t>t)break;i=n}return i.lit}function m2(a,t){return a.pattern.kind==="steady"?!0:Bm(a,t,t+1)>.5}function Bm(a,t,e){if(a.pattern.kind==="steady")return 1;const{perMinute:i,dutyCycle:n,phase:s=0}=a.pattern,r=Math.min(Math.max(n,0),1);if(r===0||i<=0)return 0;const o=6e4/i,c=t/o+s,l=e/o+s;if(l<=c)return Math.min(Math.max(c-Math.floor(c),0),r)<r?1:0;const h=u=>Math.floor(u)*r+Math.min(u-Math.floor(u),r);return(h(l)-h(c))/(l-c)}function Id(a,t){const e=a.track,i={eastM:a.eastM,northM:a.northM,altitudeM:0,headingDeg:a.headingDeg};if(!e||e.length===0)return i;if(e.length===1||t<=e[0].t)return q0(e[0],a);const n=e[e.length-1];if(t>=n.t)return q0(n,a);for(let s=0;s<e.length-1;s++){const r=e[s],o=e[s+1];if(t<r.t||t>o.t)continue;const c=o.t-r.t,l=c===0?0:(t-r.t)/c;return{eastM:r.eastM+(o.eastM-r.eastM)*l,northM:r.northM+(o.northM-r.northM)*l,altitudeM:(r.altitudeM??0)+((o.altitudeM??0)-(r.altitudeM??0))*l,headingDeg:r.headingDeg??a.headingDeg}}return i}function q0(a,t){return{eastM:a.eastM,northM:a.northM,altitudeM:a.altitudeM??0,headingDeg:a.headingDeg??t.headingDeg}}class En{static PIXELS_PER_INSTANT=2;static INSTANTS_PER_FLASH=2;static MAX_INSTANTS=512;static windowEndingAt(t,e){const i=Number.isFinite(e)?Math.max(0,e):0,n=Math.max(0,t-i*1e3),s=Math.max(0,t-n);return{fromMs:n,toMs:t,ms:s,seconds:s/1e3}}static instants(t,e,i,n,s){if(!(n>0))return 1;const r=s>0?En.travelDegOver(t,e,i,i+n*1e3)/s/En.PIXELS_PER_INSTANT:0,o=En.flashesOver(t,n)*En.INSTANTS_PER_FLASH,c=Math.ceil(Math.max(r,o));return c<2?1:Math.min(En.MAX_INSTANTS,c)}static travelDegOver(t,e,i,n){let s=0;for(const r of t){if(!r.track||r.track.length<2)continue;const o=En.directionAt(r,e,i),c=En.directionAt(r,e,n),l=Math.min(1,Math.max(-1,o.x*c.x+o.y*c.y+o.z*c.z));s=Math.max(s,Math.acos(l)*180/Math.PI)}return s}static flashesOver(t,e){let i=0;for(const n of t)for(const s of n.lights??[])s.pattern.kind==="flash"&&(i=Math.max(i,s.pattern.perMinute));return i/60*e}static directionAt(t,e,i){const n=Id(t,i),s=n.eastM,r=n.altitudeM-e,o=n.northM,c=Math.hypot(s,r,o);return c===0?{x:0,y:1,z:0}:{x:s/c,y:r/c,z:o/c}}}function jc(a,t){for(const e of a){const i=e.toLowerCase().split("-")[0];if(t.includes(i))return i}return"en"}class ao{static preferencesFor(t){const e=navigator.languages??[],i=this.declaredFor(t);return i?[i,...e]:e}static declaredFor(t){for(let e=t;e;){const i=e.closest("[lang]")?.getAttribute("lang")?.trim();if(i)return i;const n=e.getRootNode();e=n instanceof ShadowRoot?n.host:void 0}}}class zs{constructor(t){this.preferences=t}read(t){if(t===void 0||typeof t=="string")return t===""?void 0:t;for(const i of this.preferences){const n=t[i]??t[zs.base(i)];if(n)return n}const e=new Set(this.preferences.map(i=>zs.base(i)));for(const[i,n]of Object.entries(t))if(n&&e.has(zs.base(i)))return n;return Object.values(t).find(i=>i)??void 0}write(t,e,i){const n=e?.trim()?e.trim():void 0;if(t===void 0||typeof t=="string")return n;const s={...t},r=Object.keys(s).find(o=>o===i)??Object.keys(s).find(o=>zs.base(o)===zs.base(i))??i;return n===void 0?delete s[r]:s[r]=n,Object.keys(s).length===0?void 0:s}static base(t){return t.toLowerCase().split("-")[0]}}const g2=["en","fr"],v2={en:()=>Kc(()=>Promise.resolve().then(()=>x2),void 0,import.meta.url).then(a=>a.ufoMessages_en),fr:()=>Kc(()=>import("./UfoMessages_fr-CnenjNH2.js"),[],import.meta.url).then(a=>a.ufoMessages_fr)};function M2(a){return v2[a]()}const Hm={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",showWitnessMap:"Show where the witness was",hideWitnessMap:"Hide where the witness was",mapImageryUnavailable:"Aerial imagery unavailable",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",witnessHere:"The witness, here",decorHere:"Scenery"},x2=Object.freeze(Object.defineProperty({__proto__:null,ufoMessages_en:Hm},Symbol.toStringTag,{value:"Module"})),Gm=Math.PI/180,y2=180/Math.PI,_2=256,Vm=19,S2=1.25;function Wm(a,t){return 156543.03392*Math.cos(a*Gm)/2**t}function Xm(a,t){return Wm(a,t)*_2}function w2(a,t){let e=0;for(;e<Vm&&Xm(a,e+1)>=t;)e++;return e}function qm(a,t){return Xm(a,t)}function b2(a,t){const e=t*S2;let i=0;for(;i<Vm&&Wm(a,i)>e;)i++;return i}function kc(a){const t=a*Gm;return(1-Math.log(Math.tan(t)+1/Math.cos(t))/Math.PI)/2}function Ym(a,t,e){const i=2**e;return{x:(a+180)/360*i,y:kc(t)*i}}function Km(a,t,e){const i=kc(a.north),n=kc(a.south);return{x:(t-a.west)/(a.east-a.west),y:(kc(e)-i)/(n-i)}}function E2(a,t,e){const{x:i,y:n}=Ym(a,t,e);return{x:Math.floor(i),y:Math.floor(n),z:e}}function A2(a){const t=2**a.z,e=a.x/t*360-180,i=(a.x+1)/t*360-180,n=Y0(a.y,t);return{south:Y0(a.y+1,t),north:n,west:e,east:i}}function Y0(a,t){const e=a/t;return Math.atan(Math.sinh(Math.PI*(1-2*e)))*y2}function $m(a,t,e,i){const n=E2(a,t,e),s=Math.floor(i/2),r=[];for(let l=-s;l<=s;l++)for(let h=-s;h<=s;h++)r.push({x:n.x+h,y:n.y+l,z:e});const o=r.map(A2),c={south:Math.min(...o.map(l=>l.south)),north:Math.max(...o.map(l=>l.north)),west:Math.min(...o.map(l=>l.west)),east:Math.max(...o.map(l=>l.east))};return{tiles:r,bounds:c}}class oa{constructor(t){this.ctx=t}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(t,e){let i,n=1/0;for(const s of this.targets){const r=Math.hypot(s.x-t,s.y-e);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(t){const{ctx:e}=this;e.save(),this.targets=[],e.clearRect(0,0,this.width,this.height),this.paintGround(t),this.paintNight(t.nightFraction),this.paintPath(t),t.position?(this.paintCone(t,t.position),this.paintDecor(t),this.paintMarkers(t),this.paintWitness(t,t.position)):(this.paintDecor(t),this.paintMarkers(t)),this.paintNorth(),this.paintFooter(t.bounds,t.attribution),e.restore()}toCanvas(t,e,i){const n=Km(t,i,e);return{x:n.x*this.width,y:n.y*this.height}}paintGround(t){const{ctx:e}=this;e.fillStyle="#1d2321",e.fillRect(0,0,this.width,this.height);const i=t.imagery;if(!i)return;const n=this.toCanvas(t.bounds,i.bounds.north,i.bounds.west),s=this.toCanvas(t.bounds,i.bounds.south,i.bounds.east);e.drawImage(i.source,n.x,n.y,s.x-n.x,s.y-n.y)}paintNight(t=0){if(t<=0)return;const{ctx:e}=this;e.save(),e.fillStyle=`rgba(6, 12, 30, ${Math.min(t,1)*.78})`,e.fillRect(0,0,this.width,this.height),e.restore()}paintDecor(t){const{ctx:e}=this;for(const i of t.decor){const n=this.toCanvas(t.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}),e.beginPath(),e.rect(n.x-3.5,n.y-3.5,7,7),e.fillStyle="rgba(120, 220, 255, 0.85)",e.fill(),e.lineWidth=1.5,e.strokeStyle="rgba(0, 0, 0, 0.7)",e.stroke(),i.headingDeg===void 0)continue;const s=(i.headingDeg-90)*Math.PI/180;e.beginPath(),e.moveTo(n.x,n.y),e.lineTo(n.x+Math.cos(s)*10,n.y+Math.sin(s)*10),e.lineWidth=3,e.strokeStyle="rgba(0, 0, 0, 0.6)",e.stroke(),e.lineWidth=1.5,e.strokeStyle="rgba(120, 220, 255, 0.9)",e.stroke()}}paintPath(t){if(!t.path.moved)return;const{ctx:e}=this,i=t.path.points.map(n=>this.toCanvas(t.bounds,n.lat,n.lng));e.beginPath(),e.moveTo(i[0].x,i[0].y);for(const n of i.slice(1))e.lineTo(n.x,n.y);e.lineJoin="round",e.lineCap="round",e.strokeStyle="rgba(0, 0, 0, 0.65)",e.lineWidth=5,e.stroke(),e.strokeStyle="rgba(255, 255, 255, 0.9)",e.lineWidth=2,e.stroke()}paintCone(t,e){const{headingDeg:i,coneHalfAngleDeg:n}=t;if(i===void 0||n===void 0)return;const{ctx:s}=this,r=this.toCanvas(t.bounds,e.lat,e.lng),o=Math.hypot(this.width,this.height),c=(i-90)*Math.PI/180,l=n*Math.PI/180;s.save(),s.beginPath(),s.moveTo(r.x,r.y),s.arc(r.x,r.y,o,c-l,c+l),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(t){const{ctx:e}=this;e.textAlign="center",e.textBaseline="middle",e.font="bold 10px sans-serif";for(const i of[...t.markers].sort((n,s)=>Number(n.current)-Number(s.current))){const n=this.toCanvas(t.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:oa.MARKER_RADIUS_PX}),e.beginPath(),e.arc(n.x,n.y,oa.MARKER_RADIUS_PX,0,Math.PI*2),e.fillStyle=i.current?"rgba(255, 224, 130, 0.95)":"rgba(0, 0, 0, 0.55)",e.fill(),e.lineWidth=2,e.strokeStyle="rgba(255, 255, 255, 0.9)",e.stroke(),e.fillStyle=i.current?"#1d2321":"#fff",e.fillText(i.label,n.x,n.y)}}paintWitness(t,e){const{ctx:i}=this,n=this.toCanvas(t.bounds,e.lat,e.lng);t.witnessLabel&&this.targets.push({kind:"witness",label:t.witnessLabel,lat:e.lat,lng:e.lng,x:n.x,y:n.y,radius:8});const s=t.markers.some(r=>{if(!r.current)return!1;const o=li(r.lat,r.lng,e.lat,e.lng);return Math.hypot(o.x,o.z)<=oa.ON_MARKER_M});i.beginPath(),i.arc(n.x,n.y,s?oa.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:t}=this,e=this.width-14,i=16;t.beginPath(),t.moveTo(e,i-9),t.lineTo(e-4.5,i+5),t.lineTo(e,i+2),t.lineTo(e+4.5,i+5),t.closePath(),t.fillStyle="rgba(255, 255, 255, 0.92)",t.strokeStyle="rgba(0, 0, 0, 0.6)",t.lineWidth=1,t.fill(),t.stroke(),t.font="bold 9px sans-serif",t.textAlign="center",t.textBaseline="top",t.strokeText("N",e,i+6),t.fillText("N",e,i+6)}paintFooter(t,e){const{ctx:i}=this;i.font="9px sans-serif",i.textBaseline="bottom";const n=e?this.wrap(e,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=(t.south+t.north)/2,c=Math.abs(li(r,t.east,r,t.west).x)/this.width,l=oa.SCALE_STEPS_M.find(f=>f/c<=this.width/3);if(l===void 0)return;const h=l/c,u=8,d=s-3;i.lineWidth=3,i.strokeStyle="rgba(0, 0, 0, 0.6)",i.beginPath(),i.moveTo(u,d),i.lineTo(u+h,d),i.stroke(),i.lineWidth=1.5,i.strokeStyle="rgba(255, 255, 255, 0.95)",i.stroke(),i.textAlign="left",this.paintOutlinedText(l>=1e3?`${l/1e3} km`:`${l} m`,u,d-3)}paintOutlinedText(t,e,i){const{ctx:n}=this;n.lineWidth=3,n.strokeStyle="rgba(0, 0, 0, 0.75)",n.strokeText(t,e,i),n.fillStyle="#fff",n.fillText(t,e,i)}wrap(t,e){const i=[];let n="";for(const s of t.split(" ")){const r=n?`${n} ${s}`:s;n&&this.ctx.measureText(r).width>e?(i.push(n),n=s):n=r}return n&&i.push(n),i}}const on=256,K0=3,T2=32768;class R2{fetchImpl;tileUrlTemplate;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.tileUrlTemplate=t.tileUrlTemplate??"https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png"}async getElevationGrid(t,e){const i=(t.south+t.north)/2,n=(t.west+t.east)/2,s=Math.abs(li(i,t.east,i,t.west).x),r=Math.abs(li(t.north,n,t.south,n).z),o=w2(i,Math.max(s,r)),{tiles:c}=$m(n,i,o,K0),l=K0*on,h=new Float32Array(l*l),u=c[0];await Promise.all(c.map(f=>this.decodeTileInto(f,u,h,l)));const d=new Float32Array(e.width*e.height);for(let f=0;f<e.height;f++){const p=t.north+(t.south-t.north)*(f/(e.height-1));for(let v=0;v<e.width;v++){const m=t.west+(t.east-t.west)*(v/(e.width-1));d[f*e.width+v]=this.sampleAt(p,m,o,u,h,l)}}return{heights:d,width:e.width,height:e.height,bounds:t}}async decodeTileInto(t,e,i,n){const s=this.tileUrlTemplate.replace("{z}",String(t.z)).replace("{x}",String(t.x)).replace("{y}",String(t.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()),c=document.createElement("canvas");c.width=on,c.height=on;const l=c.getContext("2d");if(!l)throw new Error("2D canvas context unavailable");l.drawImage(o,0,0);const{data:h}=l.getImageData(0,0,on,on),u=(t.x-e.x)*on,d=(t.y-e.y)*on;for(let f=0;f<on;f++)for(let p=0;p<on;p++){const v=(f*on+p)*4,m=h[v]*256+h[v+1]+h[v+2]/256-T2,g=u+p,_=d+f;i[_*n+g]=m}}sampleAt(t,e,i,n,s,r){const{x:o,y:c}=Ym(e,t,i),l=(o-n.x)*on,h=(c-n.y)*on,u=Math.max(0,Math.min(r-1,Math.floor(l))),d=Math.max(0,Math.min(r-1,Math.floor(h))),f=Math.min(r-1,u+1),p=Math.min(r-1,d+1),v=l-u,m=h-d,g=s[d*r+u],_=s[d*r+f],w=s[p*r+u],M=s[p*r+f],S=g+(_-g)*v,b=w+(M-w)*v;return S+(b-S)*m}}const zc=256,D2=5;async function C2(a,t,e,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),c=Math.max(r,o),{zoom:l,gridSize:h}=I2(n,c,Math.max(t.width,t.height)),{tiles:u,bounds:d}=$m(s,n,l,h),f=h*zc,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=u[0];await Promise.all(u.map(async M=>{const S=e(M),b=await i(S);if(!b.ok)throw new Error(`Imagery tile fetch failed (${b.status}): ${S}`);const T=await createImageBitmap(await b.blob());v.drawImage(T,(M.x-m.x)*zc,(M.y-m.y)*zc)}));const g=Math.min(Math.max(t.width,t.height),f);if(g===f)return{source:p,width:f,height:f,bounds:d};const _=document.createElement("canvas");_.width=g,_.height=g;const w=_.getContext("2d");if(!w)throw new Error("2D canvas context unavailable");return w.drawImage(p,0,0,f,f,0,0,g,g),{source:_,width:g,height:g,bounds:d}}function I2(a,t,e){let i=b2(a,t/Math.max(1,e)),n=$0(a,i,t);for(;n>D2&&i>0;)i--,n=$0(a,i,t);return{zoom:i,gridSize:n,mPerPixel:qm(a,i)/zc}}function $0(a,t,e){const i=Math.ceil(e/2/qm(a,t));return Math.max(3,2*i+1)}class P2{attribution="Imagery © Esri, Maxar, Earthstar Geographics, and the GIS User Community";fetchImpl;tileUrlTemplate;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.tileUrlTemplate=t.tileUrlTemplate??"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"}async getImageryTexture(t,e){return C2(t,e,i=>this.tileUrlTemplate.replace("{z}",String(i.z)).replace("{y}",String(i.y)).replace("{x}",String(i.x)),this.fetchImpl)}}class Sn{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(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.endpoints=t.endpoints??Sn.ENDPOINTS}static queue=Promise.resolve();static RETRY_MS=4e3;async getRoads(t){const e=`${t.south},${t.west},${t.north},${t.east}`,i=`[out:json][timeout:30];way["highway"~"^(${Sn.DRIVABLE.join("|")})$"](${e});out geom;`;return this.waysFrom(await this.queued(()=>this.ask(i)))}waysFrom(t){const e=[];for(const i of t.elements??[]){const n=i.geometry,s=i.tags;!s||!n||n.length<2||e.push({id:`osm-${i.id??e.length}`,name:s.name,surface:Sn.surfaceOf(s),widthM:Sn.widthOf(s),points:n.map(r=>({lat:r.lat,lng:r.lon}))})}return e}queued(t){const e=Sn.queue.then(t,t);return Sn.queue=e.catch(()=>{}),e}async ask(t){let e;for(const i of this.endpoints)for(let n=0;n<2;n++){try{const s=await this.fetchImpl(`${i}?data=${encodeURIComponent(t)}`);if(s.ok)return await s.json();if(e=new Error(`${new URL(i).host} refused (${s.status})`),s.status!==429&&s.status!==504)break}catch(s){e=new Error(`${new URL(i).host} unreachable (${String(s)})`);break}await new Promise(s=>setTimeout(s,Sn.RETRY_MS))}throw e??new Error("No Overpass instance answered")}static widthOf(t){const e=Number.parseFloat(t.width??t.est_width??"");if(Number.isFinite(e)&&e>0)return e;const i=Number.parseInt(t.lanes??"",10);return Number.isFinite(i)&&i>0?i*3.5:Sn.WIDTH_M[t.highway]??Sn.DEFAULT_WIDTH_M}static surfaceOf(t){const e=t.surface;return e==="dirt"||e==="earth"||e==="mud"?"dirt":e==="gravel"||e==="fine_gravel"||e==="compacted"||e==="ground"||e==="sand"||e==="unpaved"?"gravel":e?"paved":t.highway==="track"?"gravel":"paved"}}const Bl="https://ufoathome.org/roads/index.json";class Pd{attributionRead;contemporaryRead;fetchImpl;indexUrls;fallback;index;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??Pd.defaultIndexUrls(),this.fallback=t.fallback}get attribution(){return this.attributionRead??this.fallback?.attribution??"Roads © OpenStreetMap contributors"}get contemporary(){return this.contemporaryRead??this.fallback?.contemporary??!0}async getRoads(t){const e=await this.held(t);if(e)return e;if(!this.fallback)return[];const i=await this.fallback.getRoads(t);return this.attributionRead=this.fallback.attribution,this.contemporaryRead=this.fallback.contemporary,i}async held(t){let e;try{e=await this.load()}catch{return}const i=e.find(({entry:n})=>n.north>=t.north&&n.south<=t.south&&n.east>=t.east&&n.west<=t.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 t of this.indexUrls)try{const e=await this.fetchImpl(t);if(!e.ok)continue;const i=await e.json();if(Array.isArray(i?.entries))return i.entries.map(n=>({entry:n,indexUrl:t}))}catch{}return[]}static defaultIndexUrls(){const t=`?v=${encodeURIComponent("0.65.3")}`,e=typeof location>"u"?void 0:new URL("/roads/index.json",location.href).href;return(e&&e!==Bl?[e,Bl]:[Bl]).map(i=>i+t)}}function L2(){return{elevation:new R2,imagery:Zm(),roads:N2()}}function Zm(){return new P2}function N2(){return new Pd({fallback:new Sn})}const O2=new Set,cr="show-witness-map",lr="hide-milestones";class Ki extends HTMLElement{static get observedAttributes(){return["src",cr,lr]}shadow;stageElement;canvas;canvasRenderer;tooltip;toolbar;playPauseButton;static WITNESS_MAP_MIN_SPAN_M=400;static WITNESS_MAP_MARGIN=.6;static WITNESS_MAP_IMAGERY_PX=768;fullscreenButton;witnessMapButton;referencesButton;referenceOpacityInput;referencesShownState=!0;referenceOpacityTouched=!1;milestonesButton;witnessMapPanel;witnessMapCanvas;witnessMapRenderer;seekInput;milestoneMarks;milestoneCaption;timeStartLabel;timeEndLabel;witnessPath;witnessMapBounds;witnessMapImagery;witnessMapImageryRequested=!1;witnessMapImageryCredit;witnessMapImageryFailed=!1;creditShownExternally=!1;lookYawDeg=0;lookPitchDeg=0;milestonesShown=!0;currentSighting=Sl.create();sightingAudio=new l2;soundPreview;player;loopEnabled=!1;playbackBeforeClick;highlightedSourceIds=new Set;paintsShapes=!0;selectionShown=!0;overlayPainter;enableClickToPlay=!0;fullscreenTarget;messages=Hm;realDurationMs;realStartMs;showClockTime=!0;handleFullscreenChange=()=>{this.updateFullscreenButton(),this.resizeWitnessMap()};witnessMapResizeObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>this.resizeWitnessMap());resizeWitnessMap(){this.witnessMapPanel.hidden||(this.sizeWitnessMapCanvas(),this.paintWitnessMap(this.currentTime))}simulatedFullscreen=!1;styleBeforeSimulatedFullscreen;bodyOverflowBeforeSimulatedFullscreen;handleSimulatedFullscreenKey=t=>{t.key==="Escape"&&this.exitSimulatedFullscreen()};handlePointerMove=t=>{const e=this.canvasPointFromEvent(t),i=e&&this.shapeAt(e.x,e.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=`${t.clientX-s.left+12}px`,this.tooltip.style.top=`${t.clientY-s.top+12}px`};handleWitnessMapPointerMove=t=>{const e=this.witnessMapTargetFrom(t);if(!e){this.tooltip.hidden=!0,this.witnessMapCanvas.style.cursor="default";return}this.witnessMapCanvas.style.cursor="pointer",this.tooltip.textContent=e.label,this.tooltip.hidden=!1;const i=this.stageElement.getBoundingClientRect();this.tooltip.style.left=`${t.clientX-i.left+12}px`,this.tooltip.style.top=`${t.clientY-i.top+12}px`};handleWitnessMapClick=t=>{const e=this.witnessMapTargetFrom(t);if(e){if(e.kind==="milestone"&&e.t!==void 0){this.player.seek(e.t);return}this.dispatchEvent(new CustomEvent("lookat",{detail:{lat:e.lat,lng:e.lng,kind:e.kind},bubbles:!0,composed:!0}))}};witnessMapTargetFrom(t){const e=this.witnessMapCanvas.getBoundingClientRect();if(!(e.width===0||e.height===0))return this.witnessMapRenderer.hitTest((t.clientX-e.left)/e.width*this.witnessMapCanvas.width,(t.clientY-e.top)/e.height*this.witnessMapCanvas.height)}handlePointerLeave=()=>{this.tooltip.hidden=!0};constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const t=document.createElement("template");t.innerHTML=`<style>${O1}</style>${N1}`,this.shadow.appendChild(t.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.canvas=this.shadow.getElementById("canvas"),this.canvasRenderer=new xo(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.witnessMapButton=this.shadow.getElementById("witness-map"),this.referencesButton=this.shadow.getElementById("references"),this.referenceOpacityInput=this.shadow.getElementById("reference-opacity"),this.milestonesButton=this.shadow.getElementById("milestones"),this.witnessMapPanel=this.shadow.getElementById("witness-map-panel"),this.witnessMapCanvas=this.shadow.getElementById("witness-map-canvas"),this.witnessMapRenderer=new oa(this.witnessMapCanvas.getContext("2d")),this.seekInput=this.shadow.getElementById("seek"),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 e of[this.timeStartLabel,this.timeEndLabel])e.addEventListener("click",()=>this.toggleTimeDisplay()),e.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.witnessMapButton.addEventListener("click",()=>this.toggleWitnessMap()),this.referencesButton.addEventListener("click",()=>this.toggleReferences()),this.referenceOpacityInput.addEventListener("input",()=>{this.referenceOpacityTouched=!0,this.dispatchReferenceView()}),this.milestonesButton.addEventListener("click",()=>this.toggleMilestones()),this.witnessMapCanvas.addEventListener("pointermove",this.handleWitnessMapPointerMove),this.witnessMapCanvas.addEventListener("pointerleave",this.handlePointerLeave),this.witnessMapCanvas.addEventListener("click",this.handleWitnessMapClick),this.seekInput.addEventListener("input",()=>this.player.seek(this.snapSeekToMark(Number(this.seekInput.value)))),this.seekInput.addEventListener("pointerdown",e=>{this.seekSnapArmed=!0,this.nameMarkUnder(e)}),this.seekInput.addEventListener("pointerup",()=>{this.seekSnapArmed=!1}),this.seekInput.addEventListener("pointermove",e=>this.nameMarkUnder(e)),this.seekInput.addEventListener("pointerleave",()=>this.seekInput.removeAttribute("title")),this.canvas.addEventListener("click",e=>{this.enableClickToPlay&&(e.detail<=1&&(this.playbackBeforeClick={state:this.playbackState,time:this.currentTime}),this.togglePlayPause())}),this.canvas.addEventListener("dblclick",e=>{this.enableClickToPlay&&(e.preventDefault(),this.restorePlayback(),this.toggleFullscreen())}),this.canvas.addEventListener("pointermove",this.handlePointerMove),this.canvas.addEventListener("pointerleave",this.handlePointerLeave),document.addEventListener("fullscreenchange",this.handleFullscreenChange),this.witnessMapResizeObserver?.observe(this.witnessMapPanel),this.hostControls(void 0),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateWitnessMapButton(),this.updateReferencesButton(),this.updateMilestonesButton(),this.refresh(),this.loadLocaleMessages()}connectedCallback(){this.saidTexts=void 0;const t=this.getAttribute("src");t&&this.loadFromSrc(t)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.handleFullscreenChange),this.witnessMapResizeObserver?.disconnect(),this.exitSimulatedFullscreen(),this.sightingAudio.dispose()}attributeChangedCallback(t,e,i){t==="src"&&i&&i!==e&&this.isConnected&&this.loadFromSrc(i),t===cr&&this.applyWitnessMapDefault(),t===lr&&this.setMilestonesShown(!this.hasAttribute(lr))}async loadFromSrc(t){this.sightingData=await Fm.json(t)}get sightingData(){return h2(this.currentSighting)}set sightingData(t){this.player.stop(),this.soundPreview=void 0,this.sightingAudio.silence(),this.currentSighting=d2(t),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.refresh(),this.applyWitnessMapDefault()}get sighting(){return this.currentSighting}previewSound(t){this.soundPreview=t,this.sightingAudio.resume(),this.sightingAudio.setSound(t)}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(t){this.player.seek(t)}get seekableDuration(){return this.player.seekableDuration}get autoReplayEnabled(){return this.loopEnabled}set autoReplayEnabled(t){t!==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(t){this.toolbar.classList.toggle("hidden",!t)}get playbackState(){return this.player.playbackState}get selectedSourceIds(){return this.highlightedSourceIds}get durationSeconds(){return this.currentSighting.event.durationSeconds}set durationSeconds(t){this.currentSighting.event.durationSeconds=t,this.updateTimeLabels(),this.refresh(),this.updatePlayPauseButton()}set selectedSourceIds(t){const e=new Set(t);e.size===this.highlightedSourceIds.size&&[...e].every(n=>this.highlightedSourceIds.has(n))||(this.highlightedSourceIds=e,this.refresh())}hasVisibleShapeAt(t,e){return this.shapeAt(t,e)!==void 0}refresh(){this.applyFrameFormat(),this.updateTimeLabels(),this.seekInput.max=String(this.player.seekableDuration),this.refreshMilestoneMarks(),this.updateMilestonesButton(),this.updateWitnessMap(),this.updateReferences(),this.player.seek(this.player.time)}hostControls(t){const e=[this.milestonesButton,this.referenceOpacityInput,this.referencesButton,this.witnessMapButton];if(t)for(const i of e)t.appendChild(i);else for(const i of e)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 t=this.currentSighting.references;!this.referenceOpacityTouched&&t.length>0&&(this.referenceOpacityInput.value=String(t[0].opacity)),this.updateReferencesButton()}updateReferencesButton(){const t=this.currentSighting.references.length>0;this.referencesButton.hidden=!t,this.referenceOpacityInput.hidden=!t||!this.referencesShownState,this.referencesButton.setAttribute("aria-pressed",String(this.referencesShownState));const e=this.referencesShownState?this.messages.hideReferences:this.messages.showReferences;this.referencesButton.title=e,this.referencesButton.setAttribute("aria-label",e),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 t=this.player.seekableDuration,e=t>0?Jc(this.sighting.milestones):[];this.milestoneMarks.replaceChildren(...e.map(i=>{const n=document.createElement("button");n.type="button",n.className="milestone-mark",n.style.left=`${Math.min(Math.max(i.t/t,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(t){const e=this.player.seekableDuration,i=this.seekInput.getBoundingClientRect().width;if(e<=0||i<=0)return;const n=Ki.MARK_SNAP_PX/i*e;let s;for(const r of this.milestoneMarks.children){const o=Number(r.dataset.t);Math.abs(o-t)>n||(!s||Math.abs(o-t)<Math.abs(s.t-t))&&(s={t:o,name:r.title})}return s}snapSeekToMark(t){return this.seekSnapArmed?(this.seekSnapArmed=!1,this.markNear(t)?.t??t):t}nameMarkUnder(t){const e=this.seekInput.getBoundingClientRect(),i=this.player.seekableDuration;if(e.width<=0||i<=0)return;const n=(t.clientX-e.left)/e.width*i,s=this.markNear(n);s?this.seekInput.title=s.name:this.seekInput.removeAttribute("title")}showMilestoneAt(t){const e=this.milestonesShown&&this.sighting.milestones.length>0?W0(this.sighting.milestones,t):void 0;if(this.milestoneCaption.hidden=e===void 0,!e)return;const i=document.createElement("b");i.textContent=this.said.read(e.label)??"";const n=this.said.read(e.note),s=n?` — ${n}`:"";this.milestoneCaption.replaceChildren(i,document.createTextNode(s))}exposureInstants(t){const e=this.exposureTimes(t),i=1/e.length;return e.map(n=>({shapes:this.shapesAt(n),share:i}))}exposureTimes(t=this.currentTime){const e=En.windowEndingAt(t,this.currentSighting.exposure??0);if(e.ms<Ki.SHORTEST_VISIBLE_EXPOSURE_MS)return[t];const i=Math.min(Ki.MAX_EXPOSURE_STEPS,Math.max(2,Math.round(e.ms/Ki.SHORTEST_VISIBLE_EXPOSURE_MS))),n=Math.ceil(this.travelPxOver(e.fromMs,e.ms)/Ki.EXPOSURE_STEP_PX),s=Math.min(Ki.MAX_TRAVEL_STEPS,Math.max(i,n)),r=[];for(let o=0;o<s;o++)r.push(e.fromMs+e.ms*o/(s-1));return r}travelPxOver(t,e){const i=this.shapesAt(t),n=this.shapesAt(t+e);let s=0;for(const[r,o]of i){const c=n.get(r);if(!c)continue;const l=c.bounds.x+c.bounds.width/2-(o.bounds.x+o.bounds.width/2),h=c.bounds.y+c.bounds.height/2-(o.bounds.y+o.bounds.height/2);s=Math.max(s,Math.hypot(l,h))}return s}shapeAt(t,e,i){for(const n of this.exposureTimes()){const s=this.currentSighting.timeline.hitTest(n,t,e,i);if(s)return s}}shapesAt(t){const e=new Map;for(const i of this.currentSighting.timeline.sourceIds){const n=this.currentSighting.timeline.getInterpolatedShapeAt(t,i);n&&e.set(i,n)}return e}static SHORTEST_VISIBLE_EXPOSURE_MS=20;static MAX_EXPOSURE_STEPS=48;static EXPOSURE_STEP_PX=2;static MAX_TRAVEL_STEPS=320;applyFrameFormat(){const t=ri.frameWidthPx(this.currentSighting.instrument,this.canvas.height);if(this.canvas.width===t)return;this.canvas.width=t,this.canvas.parentElement?.style.setProperty("--frame-aspect",`${t} / ${this.canvas.height}`)}canvasPointFromEvent(t){const e=this.canvas.getBoundingClientRect();if(!(e.width===0||e.height===0))return{x:(t.clientX-e.left)/e.width*this.canvas.width,y:(t.clientY-e.top)/e.height*this.canvas.height}}onFrame(t,e){this.canvasRenderer.clear(this.canvas.width,this.canvas.height);const i=this.playbackState!=="playing"?this.highlightedSourceIds:O2;this.canvasRenderer.setStarPoints(ri.starPointsOf(this.sighting.instrument));const n=(ai(this.sighting,t)?.rollDeg??0)+this.gaitAt(t).rollDeg;this.canvasRenderer.setRoll(n*Math.PI/180);const s=this.exposureInstants(t),r=this.frameShift;if(this.paintsShapes)for(const o of s)for(const[,c]of o.shapes){const l=o.share,h=l===1?c:{...c,transparency:1-(1-c.transparency)*l};this.canvasRenderer.paintShape(this.shifted(h,r))}for(const[o,c]of s[0].shapes)!this.selectionShown||!i.has(o)||(this.paintsShapes?i.size===1?this.canvasRenderer.paintShape({...c,selected:!0}):this.canvasRenderer.paintMemberOutline(c):this.canvasRenderer.paintSelectionOnly(this.shifted(c,r)));if(this.selectionShown&&i.size>1){const o=ji.groupBoundsFor([...e].filter(([c])=>i.has(c)).map(([,c])=>c.bounds));this.canvasRenderer.paintGroupHandles(o)}this.overlayPainter?.(this.canvasRenderer),this.mapShapeBounds=s.flatMap(o=>[...o.shapes.values()].filter(c=>c.transparency<1).map(c=>this.shifted(c,r).bounds)),this.keepWitnessMapClear(),this.seekInput.value=String(t),this.timeStartLabel.textContent=this.formatPosition(t),this.showMilestoneAt(t),this.paintWitnessMap(t),this.playbackState==="playing"?(this.soundPreview=void 0,this.sightingAudio.setSound(e2(this.currentSighting,t))):this.soundPreview?this.sightingAudio.setSound(this.soundPreview):this.sightingAudio.silence(),this.updatePlayPauseButton(),this.dispatchEvent(new CustomEvent("timeupdate",{detail:{time:t}}))}shifted(t,e){return e.x===0&&e.y===0?t:{...t,bounds:{...t.bounds,x:t.bounds.x+e.x,y:t.bounds.y+e.y}}}createPlayer(){const t=new i2(this.currentSighting.timeline,(e,i)=>this.onFrame(e,i));return t.loop=this.loopEnabled,t.onEnded=()=>{this.updatePlayPauseButton(),this.dispatchEvent(new CustomEvent("ended",{bubbles:!0,composed:!0}))},t}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())}updatePlayPauseButton(){const t=this.player.playbackState==="playing";this.playPauseButton.textContent=t?"⏸":"▶";const e=this.player.seekableDuration>0;this.playPauseButton.disabled=!e;const i=e?t?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 t=this.playbackBeforeClick;t&&(this.currentTime=t.time,t.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(t=>{console.error("<rr0-ufo>: requestFullscreen() failed —",t)})}enterSimulatedFullscreen(){const t=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen=t.getAttribute("style")??"",this.bodyOverflowBeforeSimulatedFullscreen=document.body.style.overflow;const e=t.style;e.setProperty("position","fixed"),e.setProperty("inset","0"),e.setProperty("margin","0"),e.setProperty("max-width","none"),e.setProperty("max-height","none"),e.setProperty("aspect-ratio","auto"),e.setProperty("z-index","2147483647"),e.setProperty("background","#000"),e.setProperty("width","100vw"),e.setProperty("width","100dvw"),e.setProperty("height","100vh"),e.setProperty("height","100dvh"),document.body.style.overflow="hidden",this.simulatedFullscreen=!0,document.addEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton()}exitSimulatedFullscreen(){if(!this.simulatedFullscreen)return;const t=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen?t.setAttribute("style",this.styleBeforeSimulatedFullscreen):t.removeAttribute("style"),document.body.style.overflow=this.bodyOverflowBeforeSimulatedFullscreen??"",this.simulatedFullscreen=!1,document.removeEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton()}toggleWitnessMap(){this.setWitnessMapOpen(this.witnessMapPanel.hidden)}applyWitnessMapDefault(){this.setWitnessMapOpen(this.hasAttribute(cr)&&this.witnessPath!==void 0)}setWitnessMapOpen(t){this.witnessMapPanel.hidden=!t,this.witnessMapPanel.removeAttribute("title"),this.witnessMapButton.setAttribute("aria-pressed",String(t)),this.updateWitnessMapButton(),t&&(this.sizeWitnessMapCanvas(),this.loadWitnessMapImagery(),this.paintWitnessMap(this.currentTime))}updateWitnessMapButton(){const e=!this.witnessMapPanel.hidden?this.messages.hideWitnessMap:this.messages.showWitnessMap;this.witnessMapButton.title=e,this.witnessMapButton.setAttribute("aria-label",e)}updateWitnessMap(){const t=this.witnessPath!==void 0;if(this.witnessPath=mo.of(this.currentSighting),this.witnessMapButton.hidden=this.witnessPath===void 0,!t&&this.witnessPath&&this.applyWitnessMapDefault(),!this.witnessPath){this.setWitnessMapOpen(!1),this.witnessMapBounds=void 0;return}const e=this.witnessPath.boundsAround(Ki.WITNESS_MAP_MIN_SPAN_M,Ki.WITNESS_MAP_MARGIN);(!this.witnessMapBounds||!this.sameGround(this.witnessMapBounds,e))&&(this.witnessMapBounds=e,this.witnessMapImagery=void 0,this.witnessMapImageryCredit=void 0,this.witnessMapImageryFailed=!1,this.witnessMapImageryRequested=!1,this.witnessMapPanel.hidden||this.loadWitnessMapImagery())}sameGround(t,e){const i=Math.abs(t.east-t.west)/20;return Math.abs(t.north-e.north)<i&&Math.abs(t.south-e.south)<i&&Math.abs(t.west-e.west)<i&&Math.abs(t.east-e.east)<i}async loadWitnessMapImagery(){if(this.witnessMapImageryRequested||!this.witnessMapBounds)return;this.witnessMapImageryRequested=!0;const t=Zm(),e=this.witnessMapBounds;try{const i=await t.getImageryTexture(e,{width:Ki.WITNESS_MAP_IMAGERY_PX,height:Ki.WITNESS_MAP_IMAGERY_PX});if(this.witnessMapBounds!==e)return;this.witnessMapImagery=i,this.witnessMapImageryCredit=t.attribution}catch{this.witnessMapImageryFailed=!0}this.paintWitnessMap(this.currentTime)}get witnessMapCredit(){return this.witnessMapImageryCredit}get witnessMapFooterLine(){return this.witnessMapImageryFailed?this.messages.mapImageryUnavailable:this.creditShownExternally?void 0:this.witnessMapImageryCredit}mapShapeBounds=[];mapSceneBounds=[];setMapSubjectBounds(t){this.mapSceneBounds=t.map(e=>({x:e.x*this.canvas.width,y:e.y*this.canvas.height,width:e.width*this.canvas.width,height:e.height*this.canvas.height})),this.keepWitnessMapClear()}keepWitnessMapClear(){if(this.witnessMapPanel.hidden)return;const t=this.witnessMapBoxPx;if(!t)return;const e=[...this.mapShapeBounds,...this.mapSceneBounds],i=(l,h,u)=>{for(const d of e)if(!(d.x+d.width<l-u||d.x>h+u)&&!(d.y>t.bottom+u||d.y+d.height<t.top-u))return!0;return!1},n=[this.canvas.width-t.width,this.canvas.width],s=[0,t.width],r=Ki.WITNESS_MAP_CLEARANCE_PX,o=i(...n,0),c=i(...s,0);if(this.witnessMapPanel.classList.toggle("subject-overlap",o&&c),this.witnessMapPanel.classList.contains("on-the-left")){!o&&(c||!i(n[0],n[1],r))&&this.witnessMapPanel.classList.remove("on-the-left");return}i(n[0],n[1],0)&&!i(s[0],s[1],0)&&this.witnessMapPanel.classList.add("on-the-left")}witnessMapBoxPx;static WITNESS_MAP_CLEARANCE_PX=24;sizeWitnessMapCanvas(){const t=this.witnessMapPanel.clientWidth;if(t===0)return;const e=Math.round(t*(globalThis.devicePixelRatio??1));this.measureWitnessMapBox(),this.witnessMapCanvas.width!==e&&(this.witnessMapCanvas.width=e,this.witnessMapCanvas.height=e)}measureWitnessMapBox(){const t=this.witnessMapPanel.getBoundingClientRect(),e=this.canvas.getBoundingClientRect();if(e.width===0||e.height===0)return;const i=this.canvas.width/e.width,n=this.canvas.height/e.height;this.witnessMapBoxPx={width:t.width*i,top:(t.top-e.top)*n,bottom:(t.bottom-e.top)*n}}paintWitnessMap(t){if(this.witnessMapPanel.hidden||!this.witnessPath||!this.witnessMapBounds)return;const e=ai(this.currentSighting,t),i=this.currentSighting.instrument,n=[],s=this.currentSighting.milestones.length>0?W0(this.currentSighting.milestones,t):void 0;for(const r of this.milestonesShown?Jc(this.currentSighting.milestones):[]){const o=ai(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.witnessMapRenderer.paint({bounds:this.witnessMapBounds,imagery:this.witnessMapImagery,path:this.witnessPath,position:e?.lat!==void 0&&e.lng!==void 0?{lat:e.lat,lng:e.lng}:void 0,headingDeg:e?.headingDeg===void 0?void 0:e.headingDeg+this.lookYawDeg,coneHalfAngleDeg:e?ms.of(i,this.canvas.height,e.fovDeg).halfWidthAngleDeg(ri.aspectOf(i)):void 0,markers:n,decor:this.witnessMapDecorAt(t),witnessLabel:this.said.read(this.currentSighting.witness?.title)??this.messages.witnessHere,nightFraction:this.witnessMapNightFraction,attribution:this.witnessMapFooterLine})}toggleMilestones(){this.setMilestonesShown(!this.milestonesShown)}setMilestonesShown(t){this.milestonesShown=t,this.milestoneMarks.hidden=!t,this.milestonesButton.setAttribute("aria-pressed",String(t)),this.updateMilestonesButton(),this.showMilestoneAt(this.currentTime),this.paintWitnessMap(this.currentTime)}updateMilestonesButton(){this.milestonesButton.hidden=this.currentSighting.milestones.length===0;const t=this.milestonesShown?this.messages.hideMilestones:this.messages.showMilestones;this.milestonesButton.title=t,this.milestonesButton.setAttribute("aria-label",t)}witnessMapDecorAt(t){const e=ai(this.currentSighting,0);return e?.lat===void 0||e.lng===void 0?[]:this.currentSighting.decor.filter(i=>i.kind!=="crop").map(i=>{const n=Id(i,t),{lat:s,lng:r}=ps(n.eastM,-n.northM,e.lat,e.lng);return{lat:s,lng:r,headingDeg:n.headingDeg,label:this.said.read(i.title)??this.messages.decorHere}})}witnessMapNightFraction;setSunAltitude(t){const e=t===void 0?void 0:Math.max(0,Math.min(1,-t/12));e!==this.witnessMapNightFraction&&(this.witnessMapNightFraction=e,this.paintWitnessMap(this.currentTime))}setLookOffset(t,e){t===this.lookYawDeg&&e===this.lookPitchDeg||(this.lookYawDeg=t,this.lookPitchDeg=e,this.refresh())}get frameShiftPx(){return this.frameShift}get frameShift(){const t=this.gaitAt(this.currentTime),e=this.lookYawDeg+t.yawDeg,i=this.lookPitchDeg+t.pitchDeg;if(e===0&&i===0)return{x:0,y:0};const n=ai(this.currentSighting,this.currentTime),s=ms.of(this.currentSighting.instrument,this.canvas.height,n?.fovDeg??60);return{x:-s.angleDegToRadiusPx(e),y:s.angleDegToRadiusPx(i)}}gaitAt(t){return si.of(this.currentSighting)?.offsetAt(t)??si.STILL}updateFullscreenButton(){const t=this.simulatedFullscreen||document.fullscreenElement===this.fullscreenTarget;this.fullscreenButton.title=t?this.messages.exitFullscreen:this.messages.fullscreen,this.fullscreenButton.setAttribute("aria-label",this.fullscreenButton.title)}get said(){return this.saidTexts??=new zs(ao.preferencesFor(this))}saidTexts;async loadLocaleMessages(){const t=jc(ao.preferencesFor(this),g2);t!=="en"&&this.applyMessages(await M2(t))}updateTimeLabelTitles(){const t=this.showClockTime?this.messages.switchToElapsed:this.messages.switchToClockTime,e=this.canSwitchTimeDisplay?` — ${t}`:"";this.timeStartLabel.title=this.messages.currentPosition+e,this.timeEndLabel.title=this.messages.duration+e;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(t){this.messages=t,this.updateTimeLabelTitles(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateWitnessMapButton(),this.updateReferencesButton(),this.updateMilestonesButton()}updateTimeLabels(){const t=this.currentSighting.event,e=j1(t);this.realDurationMs=e!==void 0&&e>0?e:void 0,this.realStartMs=t.time?au(t.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(t){if(this.realDurationMs===void 0)return Ho(t);const e=this.currentSighting.timeline.duration,i=e>0&&t<=e?t/e*this.realDurationMs:t;return this.canShowClockTime?J0(Z0(this.realStartMs+i)):Ho(i)}formatEndOfTimeline(){return this.realDurationMs===void 0?Ho(this.currentSighting.timeline.duration):this.canShowClockTime?J0(Z0(this.realStartMs+this.realDurationMs)):Ho(this.realDurationMs)}}function Z0(a){const t=new Date(a);return{hour:t.getUTCHours(),minute:t.getUTCMinutes(),second:t.getUTCSeconds()}}function J0(a){if(a.hour===void 0)return"0:00";const t=e=>String(e).padStart(2,"0");return a.second?`${t(a.hour)}:${t(a.minute??0)}:${t(a.second)}`:`${t(a.hour)}:${t(a.minute??0)}`}function Ho(a){const t=Math.round(a/1e3),e=Math.floor(t/60),i=t%60;return`${e}:${String(i).padStart(2,"0")}`}const ou="rr0-ufo";function Jm(){customElements.get(ou)||customElements.define(ou,Ki)}/**
|
|
696
|
+
`,Uo=[{id:"eye",name:{en:"Naked eye",fr:"Œil nu"},flare:0,projection:"equidistant",stabilization:.97},{id:"rectilinear-lens",name:{en:"Camera, unknown device",fr:"Appareil, modèle inconnu"},projection:"rectilinear",fNumber:8,fNumberRange:{min:2,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:8},apertureBlades:6},{id:"instamatic-126",name:{en:"Instamatic, 126 film",fr:"Instamatic, film 126"},projection:"rectilinear",frame:{widthMm:28,heightMm:28,focalLengthMm:43},fNumber:11,exposureSeconds:1/90,years:{from:1963,to:1988},apertureBlades:5,detailUm:20},{id:"slr-35mm-50",name:{en:"35 mm SLR, 50 mm lens",fr:"Reflex 35 mm, objectif 50 mm"},projection:"rectilinear",frame:{widthMm:36,heightMm:24,focalLengthMm:50},fNumber:8,fNumberRange:{min:2,max:16},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:3600},years:{from:1959},apertureBlades:6,detailUm:20},{id:"slr-35mm-zoom",name:{en:"35 mm SLR, 70-210 mm zoom",fr:"Reflex 35 mm, zoom 70-210 mm"},projection:"rectilinear",frame:{widthMm:36,heightMm:24,focalLengthMm:135,focalRangeMm:{minMm:70,maxMm:210}},fNumber:8,fNumberRange:{min:4,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:3600},apertureBlades:8,years:{from:1975},detailUm:20},{id:"phone-landscape",name:{en:"Phone, held sideways",fr:"Téléphone, tenu couché"},projection:"rectilinear",frame:{widthMm:7.6,heightMm:5.7,focalLengthMm:5.7},fNumber:1.8,exposureSeconds:1/120,exposureRangeSeconds:{min:1/8e3,max:10},years:{from:2007},apertureBlades:void 0,detailUm:1.4},{id:"phone-portrait",name:{en:"Phone, held upright",fr:"Téléphone, tenu debout"},projection:"rectilinear",frame:{widthMm:5.7,heightMm:7.6,focalLengthMm:5.7},fNumber:1.8,exposureSeconds:1/120,exposureRangeSeconds:{min:1/8e3,max:10},years:{from:2007},apertureBlades:void 0,detailUm:1.4}];class ri{static get default(){return Uo[0]}static byId(t){return Uo.find(e=>e.id===t)??this.default}static UNAIDED_FIELD_DEG=60;static UNAIDED_ASPECT=16/9;static fieldOfViewDeg(t){const e=t.frame;return e?2*Math.atan(e.heightMm/(2*e.focalLengthMm))*180/Math.PI:ri.UNAIDED_FIELD_DEG}static aspectOf(t){const e=t.frame;return e?e.widthMm/e.heightMm:ri.UNAIDED_ASPECT}static frameWidthPx(t,e){return Math.round(e*ri.aspectOf(t))}static availableAt(t){return t===void 0?Uo:Uo.filter(e=>!e.years||t>=e.years.from&&(e.years.to===void 0||t<=e.years.to))}static fieldOfViewDegAt(t,e){const i=t.frame;if(!(!i||e<=0))return 2*Math.atan(i.heightMm/(2*e))*180/Math.PI}static focalLengthMmFor(t,e){const i=t.frame;if(!(!i||e<=0||e>=180))return i.heightMm/(2*Math.tan(e*Math.PI/360))}static bladesShowing(t,e){const i=e??t.fNumber;if(i===void 0||t.apertureBlades===void 0)return 0;const n=t.fNumberRange;return!n||n.max<=n.min?1:Math.max(0,Math.min(1,(i-n.min)/(n.max-n.min)))}static LENS_FLARE_ARTIFACTS=1;static flareArtifactsOf(t){return t.flare??ri.LENS_FLARE_ARTIFACTS}static starPointsOf(t){const e=t.apertureBlades;return e===void 0||e<3?0:e%2===0?e:e*2}}class mo{constructor(t){this.points=t}static STATIONARY_M=5;static of(t){const e=[];for(const i of t.witnessTrack.allKeyframes){const{lat:n,lng:s,headingDeg:r}=i.pose;n===void 0||s===void 0||e.push({t:i.t,lat:n,lng:s,headingDeg:r})}if(e.length===0){const i=t.event.place?.[0];if(!i)return;e.push({t:0,lat:i.lat,lng:i.lng})}return new mo(e)}get moved(){return this.spanM>mo.STATIONARY_M}get spanM(){const t=this.box,e=(t.south+t.north)/2,i=(t.west+t.east)/2;return Math.max(Math.abs(li(e,t.east,e,t.west).x),Math.abs(li(t.north,i,t.south,i).z))}get center(){const t=this.box;return{lat:(t.south+t.north)/2,lng:(t.west+t.east)/2}}boundsAround(t,e){const{lat:i,lng:n}=this.center,s=Math.max(this.spanM*(1+e),t)/2;return{north:ps(0,-s,i,n).lat,south:ps(0,s,i,n).lat,east:ps(s,0,i,n).lng,west:ps(-s,0,i,n).lng}}get box(){const t=this.points.map(i=>i.lat),e=this.points.map(i=>i.lng);return{south:Math.min(...t),north:Math.max(...t),west:Math.min(...e),east:Math.max(...e)}}}class si{constructor(t,e){this.stretches=t,this.rotationPassed=e}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 STILL=Object.freeze({eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0});static of(t){const e=mo.of(t);if(!e||e.points.length<2)return;const i=[];let n=0;for(let s=1;s<e.points.length;s++){const r=e.points[s-1],o=e.points[s],c=(o.t-r.t)/1e3;if(c<=0)continue;const l=li(o.lat,o.lng,r.lat,r.lng),h=l.x,u=-l.z,d=Math.hypot(h,u),f=d/c,p=si.stepHzFor(f);i.push({startMs:r.t,endMs:o.t,speedMPerS:f,eastUnit:d>0?h/d:0,northUnit:d>0?u/d:0,stepHz:p,stepsBefore:n,rampsIn:!0,rampsOut:!0}),n+=p*c}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 si(i,1-(t.instrument.stabilization??0))}static stepHzFor(t){return t<si.SLOWEST_WALK_M_PER_S||t>si.FASTEST_WALK_M_PER_S?0:si.REFERENCE_STEP_HZ*Math.pow(t/si.REFERENCE_SPEED_M_PER_S,si.CADENCE_EXPONENT)}offsetAt(t){const e=this.stretches.find(c=>t>=c.startMs&&t<=c.endMs);if(!e||e.stepHz===0)return si.STILL;const i=e.stepsBefore+e.stepHz*(t-e.startMs)/1e3,n=2*Math.PI*i,s=this.amplitudeAt(e,t),r=si.SWAY_M*s*Math.cos(n/2),o=s*this.rotationPassed*e.speedMPerS/si.REFERENCE_SPEED_M_PER_S;return{eastM:r*e.northUnit,northM:-r*e.eastUnit,upM:si.RISE_M_PER_M_PER_S*e.speedMPerS*s*Math.cos(n),rollDeg:si.HEAD_ROLL_DEG*o*Math.cos(n/2),pitchDeg:-1.25*o*Math.cos(n),yawDeg:si.HEAD_YAW_DEG*o*Math.cos(n/2)}}amplitudeAt(t,e){const i=1e3/t.stepHz,n=Math.min(i,(t.endMs-t.startMs)/2);if(n<=0)return 1;const s=e-t.startMs,r=t.endMs-e,o=Math.min(t.rampsIn?s/n:1,t.rampsOut?r/n:1,1);return(1-Math.cos(Math.PI*Math.max(o,0)))/2}}class Re{static MOON_ANGULAR_WIDTH_DEG=.5237;static CANVAS_WIDTH_PX=640;static CANVAS_HEIGHT_PX=360;static angularWidthDeg(t){return 2*Math.atan(t.sizeM/(2*t.distanceM))*180/Math.PI}static inMoons(t){return t/Re.MOON_ANGULAR_WIDTH_DEG}static lerpAngular(t,e,i){if(!(!t||!e))return{widthDeg:t.widthDeg+(e.widthDeg-t.widthDeg)*i,heightDeg:t.heightDeg+(e.heightDeg-t.heightDeg)*i}}static sizeMAt(t,e){return 2*t*Math.tan(e*Math.PI/360)}static distanceMAt(t,e){return t/(2*Math.tan(e*Math.PI/360))}}function U1(a,t,e){if(!a||!t)return e<1?a:t;const i=((t.azimuthDeg-a.azimuthDeg)%360+540)%360-180;return{azimuthDeg:((a.azimuthDeg+i*e)%360+360)%360,altitudeDeg:a.altitudeDeg+(t.altitudeDeg-a.altitudeDeg)*e}}function F1(a,t,e){const{bounds:i}=a;return t>=i.x&&t<=i.x+i.width&&e>=i.y&&e<=i.y+i.height}function Gi(a,t,e){return a+(t-a)*e}function I0(a){const t=/^#([0-9a-f]{6})$/i.exec(a);if(!t)return;const e=parseInt(t[1],16);return[e>>16&255,e>>8&255,e&255]}function k1(a){return`#${a.map(t=>Math.round(t).toString(16).padStart(2,"0")).join("")}`}function z1(a,t,e){const i=I0(a),n=I0(t);return!i||!n?e<1?a:t:k1([Gi(i[0],n[0],e),Gi(i[1],n[1],e),Gi(i[2],n[2],e)])}function B1(a,t,e){const i={x:Gi(a.bounds.x,t.bounds.x,e),y:Gi(a.bounds.y,t.bounds.y,e),width:Gi(a.bounds.width,t.bounds.width,e),height:Gi(a.bounds.height,t.bounds.height,e)},n=Gi(a.angle,t.angle,e),s=Gi(a.transparency,t.transparency,e),r=Gi(a.haloScale,t.haloScale,e),o=Gi(a.blur??0,t.blur??0,e),c=Gi(a.brightness??0,t.brightness??0,e),l=z1(a.color,t.color,e),h=Re.lerpAngular(a.angular,t.angular,e),u=U1(a.aim,t.aim,e);return a.kind==="polygon"&&t.kind==="polygon"&&a.points.length===t.points.length?{...a,bounds:i,angle:n,transparency:s,haloScale:r,blur:o,brightness:c,color:l,angular:h,aim:u,points:a.points.map((d,f)=>({x:Gi(d.x,t.points[f].x,e),y:Gi(d.y,t.points[f].y,e)}))}:{...e<1?a:t,bounds:i,angle:n,transparency:s,haloScale:r,blur:o,brightness:c,color:l,angular:h,aim:u}}class _l{keyframes=[];order=[];groups=[];addKeyframe(t,e){const i=this.findInsertIndex(t);if(this.keyframes[i]?.t===t){const n=new Set(e.map(s=>s.sourceId));this.keyframes[i]={t,shapes:[...this.keyframes[i].shapes.filter(s=>!n.has(s.sourceId)),...e]}}else this.keyframes.splice(i,0,{t,shapes:[...e]});for(const n of e)this.order.includes(n.sourceId)||this.order.push(n.sourceId)}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}getKeyframeAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e];return i?.t===t?i:void 0}getShapeAt(t,e){return this.getKeyframeAt(t)?.shapes.find(i=>i.sourceId===e)?.shape}getLatestShapeAt(t,e){let i=this.findInsertIndex(t);for(this.keyframes[i]?.t!==t&&(i-=1);i>=0;i--){const n=this.keyframes[i].shapes.find(s=>s.sourceId===e);if(n)return n.shape}}getInterpolatedShapeAt(t,e){const i=this.findShapeAtOrBefore(t,e);if(i?.t===t)return i.shape;const n=this.findShapeAtOrAfter(t,e);return i?n?B1(i.shape,n.shape,(t-i.t)/(n.t-i.t)):i.shape:n?.shape}findShapeAtOrBefore(t,e){let i=this.findInsertIndex(t);for(this.keyframes[i]?.t!==t&&(i-=1);i>=0;i--){const n=this.keyframes[i].shapes.find(s=>s.sourceId===e);if(n)return{t:this.keyframes[i].t,shape:n.shape}}}findShapeAtOrAfter(t,e){for(let i=this.findInsertIndex(t);i<this.keyframes.length;i++){const n=this.keyframes[i].shapes.find(s=>s.sourceId===e);if(n)return{t:this.keyframes[i].t,shape:n.shape}}}hitTest(t,e,i,n){const s=this.sourceIds;for(let r=s.length-1;r>=0;r--){if(n?.has(s[r]))continue;const o=this.getInterpolatedShapeAt(t,s[r]);if(o&&F1(o,e,i))return{sourceId:s[r],shape:o}}}removeSource(t){for(let e=this.keyframes.length-1;e>=0;e--){const i=this.keyframes[e].shapes.filter(n=>n.sourceId!==t);i.length===0?this.keyframes.splice(e,1):i.length!==this.keyframes[e].shapes.length&&(this.keyframes[e]={t:this.keyframes[e].t,shapes:i})}this.order=this.order.filter(e=>e!==t),this.removeFromGroup(t)}group(t){if(!(t.length<2)){for(const e of t)this.removeFromGroup(e);this.groups.push([...t])}}ungroup(t){const e=this.groups.findIndex(i=>i.includes(t));e!==-1&&this.groups.splice(e,1)}groupMembers(t){return this.groups.find(e=>e.includes(t))}removeFromGroup(t){const e=this.groups.findIndex(n=>n.includes(t));if(e===-1)return;const i=this.groups[e].filter(n=>n!==t);i.length<2?this.groups.splice(e,1):this.groups[e]=i}bringToFront(t){const e=this.order.indexOf(t);e!==-1&&(this.order.splice(e,1),this.order.push(t))}sendToBack(t){const e=this.order.indexOf(t);e!==-1&&(this.order.splice(e,1),this.order.unshift(t))}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get sourceIds(){return[...this.order]}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes,order:this.order,groups:this.groups}}static fromJSON(t){const e=new _l;for(const i of t.keyframes)e.addKeyframe(i.t,i.shapes);if(t.order){const i=e.order.filter(n=>!t.order.includes(n));e.order=[...t.order,...i]}return t.groups&&(e.groups=t.groups.map(i=>i.filter(n=>e.order.includes(n))).filter(i=>i.length>=2)),e}}function H1(a,t,e){return Math.max(t,Math.min(e,a))}function G1(a,t,e){const i=((t-a)%360+540)%360-180;return((a+i*e)%360+360)%360}function Da(a,t,e){return a+(t-a)*e}function V1(a,t,e){return{lat:a.lat===void 0||t.lat===void 0?void 0:Da(a.lat,t.lat,e),lng:a.lng===void 0||t.lng===void 0?void 0:Da(a.lng,t.lng,e),elevationM:Da(a.elevationM,t.elevationM,e),headingDeg:a.headingDeg===void 0||t.headingDeg===void 0?void 0:G1(a.headingDeg,t.headingDeg,e),pitchDeg:Da(a.pitchDeg,t.pitchDeg,e),rollDeg:Da(a.rollDeg??0,t.rollDeg??0,e),fovDeg:Da(a.fovDeg,t.fovDeg,e),fNumber:a.fNumber,focusDistanceM:a.focusDistanceM}}class go{keyframes=[];addKeyframe(t,e){const i=this.findInsertIndex(t);this.keyframes[i]?.t===t?this.keyframes[i]={t,pose:e}:this.keyframes.splice(i,0,{t,pose:e})}clear(){this.keyframes.length=0}removeKeyframeAt(t){const e=this.findInsertIndex(t);this.keyframes[e]?.t===t&&this.keyframes.splice(e,1)}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}getLatestPoseAt(t){let e=this.findInsertIndex(t);return this.keyframes[e]?.t!==t&&(e-=1),e>=0?this.keyframes[e].pose:void 0}getInterpolatedPoseAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e]?.t===t?this.keyframes[e]:this.keyframes[e-1];if(i?.t===t)return i.pose;const n=this.keyframes[e]?.t===t?void 0:this.keyframes[e];return i?n?V1(i.pose,n.pose,H1((t-i.t)/(n.t-i.t),0,1)):i.pose:n?.pose}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(t){const e=new go;for(const i of t.keyframes)e.addKeyframe(i.t,i.pose);return e}}function Ie(a,t,e){return a+(t-a)*e}function Cd(a,t,e){const i=((t-a)%360+540)%360-180;return((a+i*e)%360+360)%360}function W1(a,t,e){return Math.max(t,Math.min(e,a))}function X1(a=[],t=[],e){if(!(!a.length&&!t.length))return[...new Set([...a.map(i=>i.id),...t.map(i=>i.id)])].map(i=>{const n=a.find(c=>c.id===i),s=t.find(c=>c.id===i),r=n??{...s,density:0},o=s??{...n,density:0};return{...r,eastM:Ie(r.eastM,o.eastM,e),northM:Ie(r.northM,o.northM,e),baseM:Ie(r.baseM,o.baseM,e),thicknessM:Ie(r.thicknessM,o.thicknessM,e),widthM:Ie(r.widthM,o.widthM,e),depthM:Ie(r.depthM,o.depthM,e),rotationDeg:Cd(r.rotationDeg,o.rotationDeg,e),density:Ie(r.density,o.density,e),darkness:Ie(r.darkness??0,o.darkness??0,e)}})}function q1(a,t,e){if(a.cloudLayers===void 0&&t.cloudLayers===void 0)return;const i=$c(a),n=$c(t);return e>=1?n.map(r=>({...r})):[...new Set([...i.map(r=>r.id),...n.map(r=>r.id)])].map(r=>{const o=i.find(u=>u.id===r),c=n.find(u=>u.id===r),l=o??{...c,coverage:0},h=c??{...o,coverage:0};return{...l,instances:X1(o?.instances,c?.instances,e),baseM:Ie(l.baseM,h.baseM,e),thicknessM:Ie(l.thicknessM,h.thicknessM,e),coverage:Ie(l.coverage,h.coverage,e),sizeM:Ie(l.sizeM,h.sizeM,e),density:Ie(l.density,h.density,e),darkness:Ie(l.darkness??a.cloudDarkness,h.darkness??t.cloudDarkness,e),iceCrystalAlignment:l.iceCrystalAlignment===void 0||h.iceCrystalAlignment===void 0?void 0:Ie(l.iceCrystalAlignment,h.iceCrystalAlignment,e),windSpeed:l.windSpeed===void 0&&h.windSpeed===void 0?void 0:Ie(l.windSpeed??a.windSpeed,h.windSpeed??t.windSpeed,e),windDirectionDeg:l.windDirectionDeg===void 0&&h.windDirectionDeg===void 0?void 0:Cd(l.windDirectionDeg??a.windDirectionDeg,h.windDirectionDeg??t.windDirectionDeg,e)}})}function Y1(a,t,e){return{cloudLayers:q1(a,t,e),cloudCover:Ie(a.cloudCover,t.cloudCover,e),cloudDarkness:Ie(a.cloudDarkness,t.cloudDarkness,e),highCloudCover:a.highCloudCover===void 0||t.highCloudCover===void 0?void 0:Ie(a.highCloudCover,t.highCloudCover,e),iceCrystalAlignment:a.iceCrystalAlignment===void 0||t.iceCrystalAlignment===void 0?void 0:Ie(a.iceCrystalAlignment,t.iceCrystalAlignment,e),lowerCloudCover:a.lowerCloudCover===void 0||t.lowerCloudCover===void 0?void 0:Ie(a.lowerCloudCover,t.lowerCloudCover,e),cloudBaseM:a.cloudBaseM===void 0||t.cloudBaseM===void 0?void 0:Ie(a.cloudBaseM,t.cloudBaseM,e),relativeHumidity:a.relativeHumidity===void 0||t.relativeHumidity===void 0?void 0:Ie(a.relativeHumidity,t.relativeHumidity,e),precipitationType:e<1?a.precipitationType:t.precipitationType,precipitationIntensity:Ie(a.precipitationIntensity,t.precipitationIntensity,e),windDirectionDeg:Cd(a.windDirectionDeg,t.windDirectionDeg,e),windSpeed:Ie(a.windSpeed,t.windSpeed,e),storm:e<1?a.storm:t.storm}}class vo{keyframes=[];addKeyframe(t,e){const i=this.findInsertIndex(t);this.keyframes[i]?.t===t?this.keyframes[i]={t,weather:e}:this.keyframes.splice(i,0,{t,weather:e})}clear(){this.keyframes.length=0}removeKeyframeAt(t){const e=this.findInsertIndex(t);this.keyframes[e]?.t===t&&this.keyframes.splice(e,1)}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}getLatestWeatherAt(t){let e=this.findInsertIndex(t);return this.keyframes[e]?.t!==t&&(e-=1),e>=0?this.keyframes[e].weather:void 0}getInterpolatedWeatherAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e]?.t===t?this.keyframes[e]:this.keyframes[e-1];if(i?.t===t)return i.weather;const n=this.keyframes[e]?.t===t?void 0:this.keyframes[e];return i?n?Y1(i.weather,n.weather,W1((t-i.t)/(n.t-i.t),0,1)):i.weather:n?.weather}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(t){const e=new vo;for(const i of t.keyframes)e.addKeyframe(i.t,i.weather);return e}}class Mo{keyframes=[];addKeyframe(t,e){const i=this.findInsertIndex(t);this.keyframes[i]?.t===t?this.keyframes[i]={t,sound:e}:this.keyframes.splice(i,0,{t,sound:e})}clear(){this.keyframes.length=0}removeKeyframeAt(t){const e=this.findInsertIndex(t);this.keyframes[e]?.t===t&&this.keyframes.splice(e,1)}getLatestSoundAt(t){let e=this.findInsertIndex(t);return this.keyframes[e]?.t!==t&&(e-=1),e>=0?this.keyframes[e].sound:void 0}getInterpolatedSoundAt(t){const e=this.findInsertIndex(t),i=this.keyframes[e]?.t===t?this.keyframes[e]:this.keyframes[e-1];if(i?.t===t)return i.sound;const n=this.keyframes[e]?.t===t?void 0:this.keyframes[e];if(!i)return n?.sound;if(!n)return i.sound;const s=(t-i.t)/(n.t-i.t);return this.lerp(i.sound,n.sound,Math.max(0,Math.min(1,s)))}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(t){const e=new Mo;for(const i of t.keyframes)e.addKeyframe(i.t,i.sound);return e}lerp(t,e,i){return{kind:i<1?t.kind:e.kind,volume:t.volume+(e.volume-t.volume)*i,pitchHz:t.pitchHz+(e.pitchHz-t.pitchHz)*i,src:i<1?t.src:e.src}}findInsertIndex(t){let e=0,i=this.keyframes.length;for(;e<i;){const n=e+i>>>1;this.keyframes[n].t<t?e=n+1:i=n}return e}}const K1=100,$1={kind:"none",volume:0,pitchHz:K1};class dn{constructor(t){this.entries=t}static empty(){return new dn(new Map)}get size(){return this.entries.size}at(t){return this.entries.get(t)}paths(){return[...this.entries.keys()]}set(t,e){e.basis==="stated"&&e.rationale===void 0?this.entries.delete(t):this.entries.set(t,e)}clear(t){for(const e of this.entries.keys())(e===t||e.startsWith(`${t}.`))&&this.entries.delete(e)}static strip(t){const e=new dn(new Map);return{recording:dn.stripValue(t,[],e),provenance:e}}static restore(t,e){if(e.size===0)return t;const i=structuredClone(t);for(const n of e.paths()){const s=e.at(n),r=n.split("."),o=dn.holderOf(i,r);if(!o)continue;const c=r[r.length-1],l=o[c];l!==void 0&&(s.of!==void 0&&JSON.stringify(s.of)!==JSON.stringify(l)||(o[c]={value:l,...s.basis==="stated"?{}:{basis:s.basis},...s.rationale===void 0?{}:{rationale:s.rationale}}))}return i}static isWrapper(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)&&"value"in t}static stripValue(t,e,i){return dn.isWrapper(t)?(i.set(e.join("."),{basis:t.basis??"stated",...t.rationale===void 0?{}:{rationale:t.rationale},of:t.value}),dn.stripValue(t.value,e,i)):Array.isArray(t)?t.map((n,s)=>dn.stripValue(n,[...e,String(s)],i)):typeof t=="object"&&t!==null?Object.fromEntries(Object.entries(t).map(([n,s])=>[n,dn.stripValue(s,[...e,n],i)])):t}static holderOf(t,e){let i=t;for(const n of e.slice(0,-1)){if(typeof i!="object"||i===null)return;i=i[n]}return typeof i=="object"&&i!==null?i:void 0}}function au(a){if(a.year!==void 0)return Date.UTC(a.year,(a.month??1)-1,a.day??1,a.hour??0,a.minute??0,a.second??0)}function P0(a){return(((a.day??0)*24+(a.hour??0))*60+(a.minute??0))*6e4+(a.second??0)*1e3}const Z1=["year","month","day","hour","minute"],J1=["day","hour","minute"];function L0(a,t){return t.filter(e=>a[e]!==void 0).join(",")}function j1(a){if(a.durationSeconds!==void 0)return a.durationSeconds*1e3;if(!a.time||!a.endTime)return;const t=a.time.year!==void 0&&a.endTime.year!==void 0,e=t?Z1:J1,i=L0(a.time,e);if(!(i===""||i!==L0(a.endTime,e)))return t?au(a.endTime)-au(a.time):P0(a.endTime)-P0(a.time)}class Sl{constructor(t,e,i,n,s,r,o,c,l=[],h,u,d,f=[],p=[],v=[]){this.event=t,this.timeline=e,this.witnessTrack=i,this.weatherTrack=n,this.soundTrack=s,this.witness=r,this.id=o,this.weather=c,this.decor=l,this.weatherSource=h,this.instrumentId=u,this.exposureSeconds=d,this.milestones=f,this.references=p,this.roads=v}provenance=dn.empty();testimony;interpretation;get witnessCount(){return 1+this.decor.filter(t=>t.kind==="witness").length}get exposure(){return this.exposureSeconds??this.instrument.exposureSeconds}get instrument(){return ri.byId(this.instrumentId)}static create(t,e,i){return new Sl({eventType:"sighting",time:t,place:e},new _l,new go,new vo,new Mo,i)}}const Q1=0,t2=0;function ai(a,t){const e=a.witnessTrack.getInterpolatedPoseAt(t);if(e)return e;const i=a.event.place?.[0];if(i)return{lat:i.lat,lng:i.lng,elevationM:Q1,headingDeg:void 0,pitchDeg:t2,fovDeg:ri.fieldOfViewDeg(a.instrument)}}function Qs(a,t){return a.weatherTrack.getInterpolatedWeatherAt(t)??a.weather??Om}function e2(a,t){return a.soundTrack.getInterpolatedSoundAt(t)??$1}class i2{constructor(t,e){this.timeline=t,this.onFrame=e}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 t=()=>{if(this.state!=="playing")return;const e=performance.now();if(this.currentT+=(e-this.lastWallTime)*this.playbackRate,this.lastWallTime=e,this.currentT>=this.seekableDuration){if(this.loop&&this.seekableDuration>0){this.currentT%=this.seekableDuration,this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(t);return}this.currentT=this.seekableDuration,this.stop(),this.resolveFrame(this.currentT),this.onEnded?.();return}this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(t)};this.rafId=requestAnimationFrame(t)}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(t){this.currentT=Math.max(0,Math.min(t,this.seekableDuration)),this.resolveFrame(this.currentT)}get playbackState(){return this.state}get time(){return this.currentT}resolveFrame(t){const e=new Map;for(const i of this.timeline.sourceIds){const n=this.timeline.getInterpolatedShapeAt(t,i);n&&e.set(i,n)}this.onFrame(t,e)}}const km=["nw","n","ne","e","se","s","sw","w"],n2=24,Fo=8,s2=3,a2=8;function ko(a,t,e){const i=a.x-t.x,n=a.y-t.y,s=Math.cos(e),r=Math.sin(e);return{x:t.x+i*s-n*r,y:t.y+i*r+n*s}}function Dr(a){return{x:a.x+a.width/2,y:a.y+a.height/2}}const r2={nw:{left:!0,top:!0},n:{top:!0},ne:{right:!0,top:!0},e:{right:!0},se:{right:!0,bottom:!0},s:{bottom:!0},sw:{left:!0,bottom:!0},w:{left:!0}};class ji{static handlePointsFor(t){const{x:e,y:i,width:n,height:s}=t.bounds,r={nw:{x:e,y:i},n:{x:e+n/2,y:i},ne:{x:e+n,y:i},e:{x:e+n,y:i+s/2},se:{x:e+n,y:i+s},s:{x:e+n/2,y:i+s},sw:{x:e,y:i+s},w:{x:e,y:i+s/2},rotate:{x:e+n/2,y:i-n2}},o=Dr(t.bounds),c={};for(const l of Object.keys(r))c[l]=ko(r[l],o,t.angle);return c}static hitTestHandle(t,e,i=8,n=[...km,"rotate"]){const s=ji.handlePointsFor(t);for(const r of n)if(Math.hypot(e.x-s[r].x,e.y-s[r].y)<=i)return r}static HANDLE_DIRECTION_DEG={e:0,se:45,s:90,sw:135,w:180,nw:225,n:270,ne:315};static resizeAxisFor(t,e){const n=((ji.HANDLE_DIRECTION_DEG[t]+e*180/Math.PI)%180+180)%180/45,s=["ew","nwse","ns","nesw"];return s[Math.round(n)%s.length]}static resizeBounds(t,e,i,n){const s=Dr(t),r=ko(n,s,-e),{x:o,y:c,width:l,height:h}=t,u=r2[i];let d=o,f=c,p=o+l,v=c+h;return u.left&&(d=Math.min(r.x,p-Fo)),u.right&&(p=Math.max(r.x,d+Fo)),u.top&&(f=Math.min(r.y,v-Fo)),u.bottom&&(v=Math.max(r.y,f+Fo)),{x:d,y:f,width:p-d,height:v-f}}static resizeShape(t,e,i){if(e==="rotate")throw new Error("resizeShape does not accept the rotate handle");const{width:n,height:s}=t.bounds,r=ji.resizeBounds(t.bounds,t.angle,e,i);if(t.kind==="oval")return{...t,bounds:r};const o=n===0?1:r.width/n,c=s===0?1:r.height/s;return{...t,bounds:r,points:t.points.map(l=>({x:l.x*o,y:l.y*c}))}}static rotateShape(t,e){const i=Dr(t.bounds),n=Math.atan2(e.y-i.y,e.x-i.x)+Math.PI/2;return{...t,angle:n}}static groupBoundsFor(t){const e=Math.min(...t.map(r=>r.x)),i=Math.min(...t.map(r=>r.y)),n=Math.max(...t.map(r=>r.x+r.width)),s=Math.max(...t.map(r=>r.y+r.height));return{x:e,y:i,width:n-e,height:s-i}}static vertexPointsFor(t){const e=Dr(t.bounds);return t.points.map(i=>ko({x:t.bounds.x+i.x,y:t.bounds.y+i.y},e,t.angle))}static hitTestVertex(t,e,i=a2){const n=ji.vertexPointsFor(t);let s,r=i;return n.forEach((o,c)=>{const l=Math.hypot(e.x-o.x,e.y-o.y);l<=r&&(r=l,s=c)}),s}static toLocalPoint(t,e){const i=Dr(t.bounds),n=ko(e,i,-t.angle);return{x:n.x-t.bounds.x,y:n.y-t.bounds.y}}static moveVertex(t,e,i){const n=t.points.map((u,d)=>d===e?ji.toLocalPoint(t,i):u),s=Math.min(...n.map(u=>u.x)),r=Math.min(...n.map(u=>u.y)),o=Math.max(...n.map(u=>u.x)),c=Math.max(...n.map(u=>u.y)),l={x:t.bounds.x+s,y:t.bounds.y+r,width:o-s,height:c-r},h=n.map(u=>({x:u.x-s,y:u.y-r}));return{...t,bounds:l,points:h}}static insertVertexNear(t,e){const i=ji.toLocalPoint(t,e),{points:n}=t;let s=n.length-1,r=1/0;for(let c=0;c<n.length;c++){const l=n[c],h=n[(c+1)%n.length],u=ji.distanceToSegment(i,l,h);u<r&&(r=u,s=c)}const o=[...n.slice(0,s+1),i,...n.slice(s+1)];return{...t,points:o}}static distanceToSegment(t,e,i){const n=i.x-e.x,s=i.y-e.y,r=n*n+s*s,o=r===0?0:Math.max(0,Math.min(1,((t.x-e.x)*n+(t.y-e.y)*s)/r)),c=e.x+o*n,l=e.y+o*s;return Math.hypot(t.x-c,t.y-l)}static deleteVertex(t,e){return t.points.length<=s2?t:{...t,points:t.points.filter((i,n)=>n!==e)}}}const ru=6,zo=ru/2,N0=20,O0=24,U0=9,F0=6,k0=7,z0=6,Un=4;class xo{constructor(t){this.ctx=t}starPoints=0;roll=0;clear(t,e){this.ctx.clearRect(0,0,t,e)}static paintExtent(t){const{x:e,y:i,width:n,height:s}=t.bounds,r=e+n/2,o=i+s/2,c=t.angle%(2*Math.PI)!==0,l=Math.hypot(n,s)/2,h=c?l:n/2,u=c?l:s/2,d=Math.max(n,s)/2,f=t.brightness??0,p=f>0?Math.max(d*(1+U0*f),z0*f)-d:0,v=f>0?d*(1+k0*f)-d:0,m=3*O0*(t.blur??0)+1.5*N0*t.haloScale,g=Math.max(p,v,0)+m+2;return{x:r-h-g,y:o-u-g,width:2*(h+g),height:2*(u+g)}}paintInto(t,e,i,n=!1){this.ctx.save(),this.ctx.scale(i,i),this.ctx.translate(-e.x,-e.y);const s=t.selected?{...t,selected:!1}:t;n?this.paintGhost(s,1.5):this.paintShape(s),this.ctx.restore()}paintShape(t){this.ctx.save(),this.ctx.globalAlpha=1-t.transparency;const e=t.blur??0;e>0&&(this.ctx.filter=`blur(${(O0*e).toFixed(2)}px)`);const i=t.brightness??0;i>0&&this.paintDazzle(t,i),t.haloScale>0&&this.paintHalo(t),this.paintBase(t),this.ctx.restore(),t.selected&&this.paintSelectionHandles(t)}setStarPoints(t){this.starPoints=Math.max(0,Math.floor(t))}setRoll(t){this.roll=t}paintDazzle(t,e){const{x:i,y:n,width:s,height:r}=t.bounds,o=i+s/2,c=n+r/2,l=Math.max(s,r)/2,h=Math.max(l*(1+U0*e),z0*e);if(h<=0)return;this.ctx.save(),this.ctx.globalCompositeOperation="lighter";const u=this.ctx.createRadialGradient(o,c,0,o,c,h);for(let d=0;d<=F0;d++){const f=d/F0,p=1/(1+24*f*f);this.ctx.globalAlpha=1,u.addColorStop(f,this.withAlpha(t.color,p*e*.55))}if(this.ctx.fillStyle=u,this.ctx.beginPath(),this.ctx.arc(o,c,h,0,2*Math.PI),this.ctx.fill(),this.starPoints>0){const d=l*(1+k0*e);this.ctx.lineWidth=Math.max(1,l*.12),this.ctx.lineCap="round";for(let f=0;f<this.starPoints;f++){const p=f/this.starPoints*Math.PI*2+this.roll,v=o+Math.cos(p)*d,m=c+Math.sin(p)*d,g=this.ctx.createLinearGradient(o,c,v,m);g.addColorStop(0,this.withAlpha(t.color,e*.55)),g.addColorStop(.35,this.withAlpha(t.color,e*.22)),g.addColorStop(1,this.withAlpha(t.color,0)),this.ctx.strokeStyle=g,this.ctx.beginPath(),this.ctx.moveTo(o,c),this.ctx.lineTo(v,m),this.ctx.stroke()}}this.ctx.restore()}dazzledFill(t,e){if(e<=0)return t.color;const i=/^#([0-9a-f]{6})$/i.exec(t.color.trim());if(!i)return t.color;const n=Number.parseInt(i[1],16),s=r=>Math.round(r+(255-r)*e);return`rgb(${s(n>>16&255)}, ${s(n>>8&255)}, ${s(n&255)})`}withAlpha(t,e){const i=Math.max(0,Math.min(1,e)),n=/^#([0-9a-f]{6})$/i.exec(t.trim());if(!n)return t;const s=Number.parseInt(n[1],16);return`rgba(${s>>16&255}, ${s>>8&255}, ${s&255}, ${i.toFixed(3)})`}paintBase(t){this.ctx.fillStyle=this.dazzledFill(t,t.brightness??0),this.tracePath(t),this.ctx.fill()}paintGhost(t,e){this.ctx.save(),this.tracePath(t),this.ctx.setLineDash([e*3,e*2]),this.ctx.lineWidth=e,this.ctx.strokeStyle=t.color,this.ctx.stroke(),this.ctx.restore()}tracePath(t){if(this.ctx.beginPath(),t.kind==="oval"){const{x:e,y:i,width:n,height:s}=t.bounds,r=n/2,o=s/2;this.ctx.ellipse(e+r,i+o,r,o,t.angle,0,2*Math.PI)}else{const{x:e,y:i,width:n,height:s}=t.bounds;this.ctx.save(),this.ctx.translate(e+n/2,i+s/2),this.ctx.rotate(t.angle),this.ctx.translate(-n/2,-s/2),t.points.forEach((r,o)=>{o===0?this.ctx.moveTo(r.x,r.y):this.ctx.lineTo(r.x,r.y)}),this.ctx.closePath(),this.ctx.restore()}}paintHalo(t){this.ctx.save(),this.ctx.shadowColor=t.color,this.ctx.shadowBlur=N0*t.haloScale,this.paintBase(t),this.ctx.restore()}paintSelectionHandles(t){this.paintHandleFrame(ji.handlePointsFor(t),{includeRotate:!0}),t.kind==="polygon"&&this.paintVertexHandles(t)}paintVertexHandles(t){this.ctx.fillStyle="#39f";for(const e of ji.vertexPointsFor(t))this.ctx.beginPath(),this.ctx.ellipse(e.x,e.y,Un,Un,0,0,2*Math.PI),this.ctx.fill()}paintMemberOutline(t){this.paintOutline(ji.handlePointsFor(t))}paintSelectionOnly(t){this.paintSelectionHandles(t)}paintPictureFrame(t,e,i){const n=this.ctx;if(n.save(),t&&t.length===4){n.strokeStyle="#39f",n.lineWidth=1.5,n.setLineDash([6,4]),n.beginPath(),n.moveTo(t[0].x,t[0].y);for(const s of t.slice(1))n.lineTo(s.x,s.y);n.closePath(),n.stroke(),n.setLineDash([])}for(const s of e){const r=xo.landmarkColour(s.residualDeg),o=s.selected?3:2;s.selected&&(n.strokeStyle="#fff",n.lineWidth=o+3,n.beginPath(),n.ellipse(s.picture.x,s.picture.y,Un+2,Un+2,0,0,2*Math.PI),n.stroke()),s.scene&&(n.strokeStyle=r,n.lineWidth=1,n.beginPath(),n.moveTo(s.picture.x,s.picture.y),n.lineTo(s.scene.x,s.scene.y),n.stroke(),n.fillStyle=r,n.beginPath(),n.ellipse(s.scene.x,s.scene.y,Un,Un,0,0,2*Math.PI),n.fill()),n.strokeStyle=r,n.lineWidth=o,n.beginPath(),n.ellipse(s.picture.x,s.picture.y,Un+2,Un+2,0,0,2*Math.PI),n.stroke(),this.paintLabel(s.label,s.picture.x+Un+5,s.picture.y-Un-2,r)}i&&this.paintLabel(i,8,8,"#fff",13),n.restore()}static landmarkColour(t){return t===void 0?"#ffb000":t<=1?"#3c3":t<=3?"#ffb000":"#f33"}paintLabel(t,e,i,n,s=11){const r=this.ctx;r.save(),r.font=`${s}px system-ui, sans-serif`,r.textBaseline="top";const o=r.measureText(t).width;r.fillStyle="rgba(0, 0, 0, 0.6)",r.fillRect(e-3,i-2,o+6,s+4),r.fillStyle=n,r.fillText(t,e,i),r.restore()}paintGroupHandles(t){this.paintHandleFrame(ji.handlePointsFor({bounds:t,angle:0}),{includeRotate:!0})}paintOutline(t){this.ctx.strokeStyle="lightgray",this.ctx.beginPath(),this.ctx.moveTo(t.nw.x,t.nw.y),this.ctx.lineTo(t.ne.x,t.ne.y),this.ctx.lineTo(t.se.x,t.se.y),this.ctx.lineTo(t.sw.x,t.sw.y),this.ctx.closePath(),this.ctx.stroke()}paintHandleFrame(t,{includeRotate:e}){this.paintOutline(t),this.ctx.fillStyle="lightgray";for(const i of km){const n=t[i];this.ctx.fillRect(n.x-zo,n.y-zo,ru,ru)}e&&(this.ctx.beginPath(),this.ctx.moveTo(t.n.x,t.n.y),this.ctx.lineTo(t.rotate.x,t.rotate.y),this.ctx.stroke(),this.ctx.beginPath(),this.ctx.ellipse(t.rotate.x,t.rotate.y,zo+1,zo+1,0,0,2*Math.PI),this.ctx.fill())}}const B0=.05,H0=.08,G0=2,V0=3,o2=14,c2=.02;class l2{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(t){console.warn("SightingAudio: Web Audio unavailable, the sighting stays silent:",t);return}}this.context.state==="suspended"&&this.context.resume()}setSound(t){if(this.requested=t,!this.context)return;const e=this.keyFor(t);if(!e){this.silence();return}if(this.voice?.key!==e){this.stopVoice();const i=++this.voiceToken;e.startsWith("src:")?this.buildRecordedVoice(t.src,e,i):this.voice=this.buildSynthesizedVoice(t,e)}this.applyTo(this.voice,t)}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(t){if(!(t.volume<=0))return t.src?`src:${t.src}`:t.kind==="none"?void 0:t.kind}applyTo(t,e){const i=this.context;if(!t||!i)return;const n=i.currentTime;t.volumeParam.setTargetAtTime(Math.max(0,Math.min(1,e.volume))*t.gainScale,n,B0);for(const{param:s,ratio:r}of t.pitch)s.setTargetAtTime(Math.min(e.pitchHz*r,i.sampleRate/2-1),n,B0)}buildSynthesizedVoice(t,e){const i=this.context;if(i)switch(t.kind){case"hum":return this.buildHum(i,e);case"whistle":return this.buildWhistle(i,e);case"rumble":return this.buildRumble(i,e);case"crackle":return this.buildCrackle(i,e);default:return}}buildHum(t,e){const i=t.createOscillator();i.type="sawtooth";const n=t.createOscillator();n.type="sawtooth";const s=t.createBiquadFilter();s.type="lowpass",s.Q.value=1;const r=t.createGain();return r.gain.value=0,i.connect(s),n.connect(s),s.connect(r).connect(t.destination),i.start(),n.start(),{key:e,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(t,e){const i=t.createOscillator();i.type="sine";const n=t.createOscillator();n.type="sine",n.frequency.value=5;const s=t.createGain(),r=t.createGain();return r.gain.value=0,n.connect(s).connect(i.frequency),i.connect(r).connect(t.destination),i.start(),n.start(),{key:e,nodes:[s,r],sources:[i,n],volumeParam:r.gain,gainScale:.22,pitch:[{param:i.frequency,ratio:1},{param:s.gain,ratio:.012}]}}buildRumble(t,e){const i=t.createBufferSource();i.buffer=this.brownNoise(t),i.loop=!0;const n=t.createBiquadFilter();n.type="lowpass",n.Q.value=.8;const s=t.createGain();return s.gain.value=0,i.connect(n).connect(s).connect(t.destination),i.start(),{key:e,nodes:[n,s],sources:[i],volumeParam:s.gain,gainScale:1.4,pitch:[{param:n.frequency,ratio:1}]}}buildCrackle(t,e){const i=t.createBufferSource();i.buffer=this.whiteNoise(t),i.loop=!0;const n=t.createBiquadFilter();n.type="bandpass",n.Q.value=1.2;const s=t.createGain();s.gain.value=0;const r=t.createBufferSource();r.buffer=this.crackleEnvelope(t),r.loop=!0;const o=t.createGain();return o.gain.value=0,r.connect(o).connect(s.gain),i.connect(n).connect(s).connect(t.destination),i.start(),r.start(),{key:e,nodes:[n,s,o],sources:[i,r],volumeParam:o.gain,gainScale:.9,pitch:[{param:n.frequency,ratio:4}]}}async buildRecordedVoice(t,e,i){const n=this.context;if(!n)return;let s;try{s=await this.getBuffer(t)}catch(c){console.warn("SightingAudio: the recorded sound failed to load, staying silent:",c);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:e,nodes:[o],sources:[r],volumeParam:o.gain,gainScale:1,pitch:[]},this.requested&&this.applyTo(this.voice,this.requested)}async getBuffer(t){const e=this.context;if(!e)throw new Error("SightingAudio: AudioContext not ready — resume() must be called first");let i=this.buffers.get(t);return i||(i=fetch(t).then(n=>{if(!n.ok)throw new Error(`Audio fetch failed (${n.status}): ${t}`);return n.arrayBuffer()}).then(n=>e.decodeAudioData(n)),this.buffers.set(t,i)),i}whiteNoise(t){if(!this.noiseBuffer){const e=t.createBuffer(1,Math.floor(t.sampleRate*G0),t.sampleRate),i=e.getChannelData(0);for(let n=0;n<i.length;n++)i[n]=Math.random()*2-1;this.noiseBuffer=e}return this.noiseBuffer}brownNoise(t){const e=t.createBuffer(1,Math.floor(t.sampleRate*G0),t.sampleRate),i=e.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 e}crackleEnvelope(t){if(!this.crackleBuffer){const e=t.createBuffer(1,Math.floor(t.sampleRate*V0),t.sampleRate),i=e.getChannelData(0),n=Math.max(1,Math.floor(c2*t.sampleRate)),s=Math.round(V0*o2);for(let r=0;r<s;r++){const o=Math.floor(Math.random()*i.length),c=.4+Math.random()*.6;for(let l=0;l<n&&o+l<i.length;l++)i[o+l]=Math.max(i[o+l],c*(1-l/n))}this.crackleBuffer=e}return this.crackleBuffer}stopVoice(){const t=this.voice,e=this.context;if(this.voice=void 0,!t||!e)return;const i=e.currentTime;t.volumeParam.cancelScheduledValues(i),t.volumeParam.setTargetAtTime(0,i,H0/3);const n=i+H0;for(const s of t.sources){s.onended=()=>{s.disconnect();for(const r of t.nodes)r.disconnect()};try{s.stop(n)}catch{s.disconnect();for(const r of t.nodes)r.disconnect()}}}}function Jc(a){return[...a].sort((t,e)=>t.t-e.t)}function W0(a,t){let e;for(const i of Jc(a)){if(i.t>t)break;e=i}return e}const zl=Math.PI/180,Bo=180/Math.PI;class ms{constructor(t,e,i){this.kind=t,this.canvasHeightPx=e,this.fovDeg=i;const n=i*zl/2;this.focalPx=t==="equidistant"?e/2/n:e/2/Math.tan(n)}focalPx;static of(t,e,i){return new ms(t.projection,e,i)}degToPx(t){const e=t*zl;return this.kind==="equidistant"?this.focalPx*e:2*this.focalPx*Math.tan(e/2)}pxToDeg(t){return this.kind==="equidistant"?t/this.focalPx*Bo:2*Math.atan(t/(2*this.focalPx))*Bo}angleDegToRadiusPx(t){const e=t*zl;return this.kind==="equidistant"?this.focalPx*e:this.focalPx*Math.tan(e)}halfWidthAngleDeg(t){return this.radiusPxToAngleDeg(this.canvasHeightPx*t/2)}radiusPxToAngleDeg(t){return this.kind==="equidistant"?t/this.focalPx*Bo:Math.atan(t/this.focalPx)*Bo}ofBounds(t){return{widthDeg:this.pxToDeg(t.width),heightDeg:this.pxToDeg(t.height)}}toBoundsSize(t){return{width:this.degToPx(t.widthDeg),height:this.degToPx(t.heightDeg)}}widthPx(t){return this.degToPx(Re.angularWidthDeg(t))}}class Wi{static fovOf(t,e){return ai(t,e)?.fovDeg??ri.fieldOfViewDeg(t.instrument)}static toAngular(t){this.eachKeyframe(t,(e,i)=>({...e,angular:i.ofBounds(e.bounds)}))}static toBounds(t){this.eachKeyframe(t,(e,i)=>{if(!e.angular)return e;const{width:n,height:s}=i.toBoundsSize(e.angular),r={x:e.bounds.x+(e.bounds.width-n)/2,y:e.bounds.y+(e.bounds.height-s)/2,width:n,height:s};if(e.kind!=="polygon")return{...e,bounds:r};const o=e.bounds.width===0?1:n/e.bounds.width,c=e.bounds.height===0?1:s/e.bounds.height;return{...e,bounds:r,points:e.points.map(l=>({x:l.x*o,y:l.y*c}))}})}static toAim(t){this.eachKeyframe(t,(e,i,n)=>{const s=e.aim&&this.positionOf(t,e.aim,e.bounds,i,n);if(s&&Math.abs(s.x-e.bounds.x)<Wi.UNMOVED_PX&&Math.abs(s.y-e.bounds.y)<Wi.UNMOVED_PX)return e;const r=this.aimFrom(t,i,n,e.bounds);return r?{...e,aim:r}:e})}static UNMOVED_PX=.01;static aimOf(t,e,i){const n=ms.of(t.instrument,Re.CANVAS_HEIGHT_PX,this.fovOf(t,e));return this.aimFrom(t,n,ai(t,e),i)}static aimFrom(t,e,i,n){if(i?.headingDeg===void 0)return;const s=this.frameCentre(t),r=e.radiusPxToAngleDeg(n.x+n.width/2-s.x),o=e.radiusPxToAngleDeg(s.y-(n.y+n.height/2));return{azimuthDeg:((i.headingDeg+r)%360+360)%360,altitudeDeg:i.pitchDeg+o}}static toPosition(t){this.eachKeyframe(t,(e,i,n)=>{const s=e.aim&&this.positionOf(t,e.aim,e.bounds,i,n);return s?{...e,bounds:{...e.bounds,...s}}:e})}static positionOf(t,e,i,n,s){if(s?.headingDeg===void 0)return;const r=this.frameCentre(t),o=this.shortestArc(e.azimuthDeg-s.headingDeg),c=e.altitudeDeg-s.pitchDeg;return{x:r.x+this.offAxisPx(n,o)-i.width/2,y:r.y-this.offAxisPx(n,c)-i.height/2}}static frameCentre(t){return{x:ri.frameWidthPx(t.instrument,Re.CANVAS_HEIGHT_PX)/2,y:Re.CANVAS_HEIGHT_PX/2}}static shortestArc(t){return(t%360+540)%360-180}static offAxisPx(t,e){return Math.abs(e)>=Wi.OFF_CANVAS_DEG?Math.sign(e)*Wi.OFF_CANVAS_PX:t.angleDegToRadiusPx(e)}static OFF_CANVAS_DEG=89;static OFF_CANVAS_PX=1e5;static reproject(t,e,i){const n=ri.frameWidthPx(e,Re.CANVAS_HEIGHT_PX)/2,s=ri.frameWidthPx(t.instrument,Re.CANVAS_HEIGHT_PX)/2,r=Re.CANVAS_HEIGHT_PX/2;for(const o of[...t.timeline.allKeyframes]){const c=this.fovOf(t,o.t),l=i?.get(o.t)??c,h=ms.of(e,Re.CANVAS_HEIGHT_PX,l),u=ms.of(t.instrument,Re.CANVAS_HEIGHT_PX,c);t.timeline.addKeyframe(o.t,o.shapes.map(d=>{const{bounds:f}=d.shape,p=f.x+f.width/2-n,v=f.y+f.height/2-r,m=Math.hypot(p,v),g=m===0?1:u.angleDegToRadiusPx(h.radiusPxToAngleDeg(m))/m,_={...f,x:s+p*g-f.width/2,y:r+v*g-f.height/2};return{...d,shape:{...d.shape,bounds:_}}}))}this.toBounds(t)}static eachKeyframe(t,e){const{timeline:i}=t;for(const n of[...i.allKeyframes]){const s=ai(t,n.t),r=this.fovOf(t,n.t),o=ms.of(t.instrument,Re.CANVAS_HEIGHT_PX,r);i.addKeyframe(n.t,n.shapes.map(c=>({...c,shape:e(c.shape,o,s)})))}}}function h2(a){return dn.restore(u2(a),a.provenance)}function u2(a){return Wi.toAngular(a),Wi.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,witness:a.witness,testimony:a.testimony,description:a.event.description,tags:a.event.tags,timeline:a.timeline.toJSON(),witnessTrack:a.witnessTrack.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,interpretation:a.interpretation}}function d2(a){const{recording:t,provenance:e}=dn.strip(a),i=f2(t);return i.provenance=e,i}function f2(a){const t=new Sl({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},_l.fromJSON(a.timeline),a.witnessTrack?go.fromJSON(a.witnessTrack):new go,a.weatherTrack?vo.fromJSON(a.weatherTrack):new vo,a.soundTrack?Mo.fromJSON(a.soundTrack):new Mo,a.witness&&{id:a.witness.id,title:a.witness.title,lastName:a.witness.lastName,firstNames:a.witness.firstNames},a.id,a.weather,a.decor??[],a.weatherSource,a.instrument,a.exposureSeconds??a.witnessTrack?.keyframes.map(e=>e.pose.exposureSeconds).find(e=>e!==void 0),Jc(a.milestones??[]),a.references??[],a.roads??[]);return t.testimony=a.testimony,t.interpretation=a.interpretation,Wi.toBounds(t),Wi.toPosition(t),t}const X0=2;function zm(a){return a==="building"||a==="vehicle"}function p2(a,t){const e=a.litKeyframes;if(!e||e.length===0)return a.lit??!1;let i=e[0];for(const n of e){if(n.t>t)break;i=n}return i.lit}function m2(a,t){return a.pattern.kind==="steady"?!0:Bm(a,t,t+1)>.5}function Bm(a,t,e){if(a.pattern.kind==="steady")return 1;const{perMinute:i,dutyCycle:n,phase:s=0}=a.pattern,r=Math.min(Math.max(n,0),1);if(r===0||i<=0)return 0;const o=6e4/i,c=t/o+s,l=e/o+s;if(l<=c)return Math.min(Math.max(c-Math.floor(c),0),r)<r?1:0;const h=u=>Math.floor(u)*r+Math.min(u-Math.floor(u),r);return(h(l)-h(c))/(l-c)}function Id(a,t){const e=a.track,i={eastM:a.eastM,northM:a.northM,altitudeM:0,headingDeg:a.headingDeg};if(!e||e.length===0)return i;if(e.length===1||t<=e[0].t)return q0(e[0],a);const n=e[e.length-1];if(t>=n.t)return q0(n,a);for(let s=0;s<e.length-1;s++){const r=e[s],o=e[s+1];if(t<r.t||t>o.t)continue;const c=o.t-r.t,l=c===0?0:(t-r.t)/c;return{eastM:r.eastM+(o.eastM-r.eastM)*l,northM:r.northM+(o.northM-r.northM)*l,altitudeM:(r.altitudeM??0)+((o.altitudeM??0)-(r.altitudeM??0))*l,headingDeg:r.headingDeg??a.headingDeg}}return i}function q0(a,t){return{eastM:a.eastM,northM:a.northM,altitudeM:a.altitudeM??0,headingDeg:a.headingDeg??t.headingDeg}}class En{static PIXELS_PER_INSTANT=2;static INSTANTS_PER_FLASH=2;static MAX_INSTANTS=512;static windowEndingAt(t,e){const i=Number.isFinite(e)?Math.max(0,e):0,n=Math.max(0,t-i*1e3),s=Math.max(0,t-n);return{fromMs:n,toMs:t,ms:s,seconds:s/1e3}}static instants(t,e,i,n,s){if(!(n>0))return 1;const r=s>0?En.travelDegOver(t,e,i,i+n*1e3)/s/En.PIXELS_PER_INSTANT:0,o=En.flashesOver(t,n)*En.INSTANTS_PER_FLASH,c=Math.ceil(Math.max(r,o));return c<2?1:Math.min(En.MAX_INSTANTS,c)}static travelDegOver(t,e,i,n){let s=0;for(const r of t){if(!r.track||r.track.length<2)continue;const o=En.directionAt(r,e,i),c=En.directionAt(r,e,n),l=Math.min(1,Math.max(-1,o.x*c.x+o.y*c.y+o.z*c.z));s=Math.max(s,Math.acos(l)*180/Math.PI)}return s}static flashesOver(t,e){let i=0;for(const n of t)for(const s of n.lights??[])s.pattern.kind==="flash"&&(i=Math.max(i,s.pattern.perMinute));return i/60*e}static directionAt(t,e,i){const n=Id(t,i),s=n.eastM,r=n.altitudeM-e,o=n.northM,c=Math.hypot(s,r,o);return c===0?{x:0,y:1,z:0}:{x:s/c,y:r/c,z:o/c}}}function jc(a,t){for(const e of a){const i=e.toLowerCase().split("-")[0];if(t.includes(i))return i}return"en"}class ao{static preferencesFor(t){const e=navigator.languages??[],i=this.declaredFor(t);return i?[i,...e]:e}static declaredFor(t){for(let e=t;e;){const i=e.closest("[lang]")?.getAttribute("lang")?.trim();if(i)return i;const n=e.getRootNode();e=n instanceof ShadowRoot?n.host:void 0}}}class zs{constructor(t){this.preferences=t}read(t){if(t===void 0||typeof t=="string")return t===""?void 0:t;for(const i of this.preferences){const n=t[i]??t[zs.base(i)];if(n)return n}const e=new Set(this.preferences.map(i=>zs.base(i)));for(const[i,n]of Object.entries(t))if(n&&e.has(zs.base(i)))return n;return Object.values(t).find(i=>i)??void 0}write(t,e,i){const n=e?.trim()?e.trim():void 0;if(t===void 0||typeof t=="string")return n;const s={...t},r=Object.keys(s).find(o=>o===i)??Object.keys(s).find(o=>zs.base(o)===zs.base(i))??i;return n===void 0?delete s[r]:s[r]=n,Object.keys(s).length===0?void 0:s}static base(t){return t.toLowerCase().split("-")[0]}}const g2=["en","fr"],v2={en:()=>Kc(()=>Promise.resolve().then(()=>x2),void 0,import.meta.url).then(a=>a.ufoMessages_en),fr:()=>Kc(()=>import("./UfoMessages_fr-CnenjNH2.js"),[],import.meta.url).then(a=>a.ufoMessages_fr)};function M2(a){return v2[a]()}const Hm={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",showWitnessMap:"Show where the witness was",hideWitnessMap:"Hide where the witness was",mapImageryUnavailable:"Aerial imagery unavailable",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",witnessHere:"The witness, here",decorHere:"Scenery"},x2=Object.freeze(Object.defineProperty({__proto__:null,ufoMessages_en:Hm},Symbol.toStringTag,{value:"Module"})),Gm=Math.PI/180,y2=180/Math.PI,_2=256,Vm=19,S2=1.25;function Wm(a,t){return 156543.03392*Math.cos(a*Gm)/2**t}function Xm(a,t){return Wm(a,t)*_2}function w2(a,t){let e=0;for(;e<Vm&&Xm(a,e+1)>=t;)e++;return e}function qm(a,t){return Xm(a,t)}function b2(a,t){const e=t*S2;let i=0;for(;i<Vm&&Wm(a,i)>e;)i++;return i}function kc(a){const t=a*Gm;return(1-Math.log(Math.tan(t)+1/Math.cos(t))/Math.PI)/2}function Ym(a,t,e){const i=2**e;return{x:(a+180)/360*i,y:kc(t)*i}}function Km(a,t,e){const i=kc(a.north),n=kc(a.south);return{x:(t-a.west)/(a.east-a.west),y:(kc(e)-i)/(n-i)}}function E2(a,t,e){const{x:i,y:n}=Ym(a,t,e);return{x:Math.floor(i),y:Math.floor(n),z:e}}function A2(a){const t=2**a.z,e=a.x/t*360-180,i=(a.x+1)/t*360-180,n=Y0(a.y,t);return{south:Y0(a.y+1,t),north:n,west:e,east:i}}function Y0(a,t){const e=a/t;return Math.atan(Math.sinh(Math.PI*(1-2*e)))*y2}function $m(a,t,e,i){const n=E2(a,t,e),s=Math.floor(i/2),r=[];for(let l=-s;l<=s;l++)for(let h=-s;h<=s;h++)r.push({x:n.x+h,y:n.y+l,z:e});const o=r.map(A2),c={south:Math.min(...o.map(l=>l.south)),north:Math.max(...o.map(l=>l.north)),west:Math.min(...o.map(l=>l.west)),east:Math.max(...o.map(l=>l.east))};return{tiles:r,bounds:c}}class oa{constructor(t){this.ctx=t}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(t,e){let i,n=1/0;for(const s of this.targets){const r=Math.hypot(s.x-t,s.y-e);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(t){const{ctx:e}=this;e.save(),this.targets=[],e.clearRect(0,0,this.width,this.height),this.paintGround(t),this.paintNight(t.nightFraction),this.paintPath(t),t.position?(this.paintCone(t,t.position),this.paintDecor(t),this.paintMarkers(t),this.paintWitness(t,t.position)):(this.paintDecor(t),this.paintMarkers(t)),this.paintNorth(),this.paintFooter(t.bounds,t.attribution),e.restore()}toCanvas(t,e,i){const n=Km(t,i,e);return{x:n.x*this.width,y:n.y*this.height}}paintGround(t){const{ctx:e}=this;e.fillStyle="#1d2321",e.fillRect(0,0,this.width,this.height);const i=t.imagery;if(!i)return;const n=this.toCanvas(t.bounds,i.bounds.north,i.bounds.west),s=this.toCanvas(t.bounds,i.bounds.south,i.bounds.east);e.drawImage(i.source,n.x,n.y,s.x-n.x,s.y-n.y)}paintNight(t=0){if(t<=0)return;const{ctx:e}=this;e.save(),e.fillStyle=`rgba(6, 12, 30, ${Math.min(t,1)*.78})`,e.fillRect(0,0,this.width,this.height),e.restore()}paintDecor(t){const{ctx:e}=this;for(const i of t.decor){const n=this.toCanvas(t.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}),e.beginPath(),e.rect(n.x-3.5,n.y-3.5,7,7),e.fillStyle="rgba(120, 220, 255, 0.85)",e.fill(),e.lineWidth=1.5,e.strokeStyle="rgba(0, 0, 0, 0.7)",e.stroke(),i.headingDeg===void 0)continue;const s=(i.headingDeg-90)*Math.PI/180;e.beginPath(),e.moveTo(n.x,n.y),e.lineTo(n.x+Math.cos(s)*10,n.y+Math.sin(s)*10),e.lineWidth=3,e.strokeStyle="rgba(0, 0, 0, 0.6)",e.stroke(),e.lineWidth=1.5,e.strokeStyle="rgba(120, 220, 255, 0.9)",e.stroke()}}paintPath(t){if(!t.path.moved)return;const{ctx:e}=this,i=t.path.points.map(n=>this.toCanvas(t.bounds,n.lat,n.lng));e.beginPath(),e.moveTo(i[0].x,i[0].y);for(const n of i.slice(1))e.lineTo(n.x,n.y);e.lineJoin="round",e.lineCap="round",e.strokeStyle="rgba(0, 0, 0, 0.65)",e.lineWidth=5,e.stroke(),e.strokeStyle="rgba(255, 255, 255, 0.9)",e.lineWidth=2,e.stroke()}paintCone(t,e){const{headingDeg:i,coneHalfAngleDeg:n}=t;if(i===void 0||n===void 0)return;const{ctx:s}=this,r=this.toCanvas(t.bounds,e.lat,e.lng),o=Math.hypot(this.width,this.height),c=(i-90)*Math.PI/180,l=n*Math.PI/180;s.save(),s.beginPath(),s.moveTo(r.x,r.y),s.arc(r.x,r.y,o,c-l,c+l),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(t){const{ctx:e}=this;e.textAlign="center",e.textBaseline="middle",e.font="bold 10px sans-serif";for(const i of[...t.markers].sort((n,s)=>Number(n.current)-Number(s.current))){const n=this.toCanvas(t.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:oa.MARKER_RADIUS_PX}),e.beginPath(),e.arc(n.x,n.y,oa.MARKER_RADIUS_PX,0,Math.PI*2),e.fillStyle=i.current?"rgba(255, 224, 130, 0.95)":"rgba(0, 0, 0, 0.55)",e.fill(),e.lineWidth=2,e.strokeStyle="rgba(255, 255, 255, 0.9)",e.stroke(),e.fillStyle=i.current?"#1d2321":"#fff",e.fillText(i.label,n.x,n.y)}}paintWitness(t,e){const{ctx:i}=this,n=this.toCanvas(t.bounds,e.lat,e.lng);t.witnessLabel&&this.targets.push({kind:"witness",label:t.witnessLabel,lat:e.lat,lng:e.lng,x:n.x,y:n.y,radius:8});const s=t.markers.some(r=>{if(!r.current)return!1;const o=li(r.lat,r.lng,e.lat,e.lng);return Math.hypot(o.x,o.z)<=oa.ON_MARKER_M});i.beginPath(),i.arc(n.x,n.y,s?oa.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:t}=this,e=this.width-14,i=16;t.beginPath(),t.moveTo(e,i-9),t.lineTo(e-4.5,i+5),t.lineTo(e,i+2),t.lineTo(e+4.5,i+5),t.closePath(),t.fillStyle="rgba(255, 255, 255, 0.92)",t.strokeStyle="rgba(0, 0, 0, 0.6)",t.lineWidth=1,t.fill(),t.stroke(),t.font="bold 9px sans-serif",t.textAlign="center",t.textBaseline="top",t.strokeText("N",e,i+6),t.fillText("N",e,i+6)}paintFooter(t,e){const{ctx:i}=this;i.font="9px sans-serif",i.textBaseline="bottom";const n=e?this.wrap(e,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=(t.south+t.north)/2,c=Math.abs(li(r,t.east,r,t.west).x)/this.width,l=oa.SCALE_STEPS_M.find(f=>f/c<=this.width/3);if(l===void 0)return;const h=l/c,u=8,d=s-3;i.lineWidth=3,i.strokeStyle="rgba(0, 0, 0, 0.6)",i.beginPath(),i.moveTo(u,d),i.lineTo(u+h,d),i.stroke(),i.lineWidth=1.5,i.strokeStyle="rgba(255, 255, 255, 0.95)",i.stroke(),i.textAlign="left",this.paintOutlinedText(l>=1e3?`${l/1e3} km`:`${l} m`,u,d-3)}paintOutlinedText(t,e,i){const{ctx:n}=this;n.lineWidth=3,n.strokeStyle="rgba(0, 0, 0, 0.75)",n.strokeText(t,e,i),n.fillStyle="#fff",n.fillText(t,e,i)}wrap(t,e){const i=[];let n="";for(const s of t.split(" ")){const r=n?`${n} ${s}`:s;n&&this.ctx.measureText(r).width>e?(i.push(n),n=s):n=r}return n&&i.push(n),i}}const on=256,K0=3,T2=32768;class R2{fetchImpl;tileUrlTemplate;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.tileUrlTemplate=t.tileUrlTemplate??"https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png"}async getElevationGrid(t,e){const i=(t.south+t.north)/2,n=(t.west+t.east)/2,s=Math.abs(li(i,t.east,i,t.west).x),r=Math.abs(li(t.north,n,t.south,n).z),o=w2(i,Math.max(s,r)),{tiles:c}=$m(n,i,o,K0),l=K0*on,h=new Float32Array(l*l),u=c[0];await Promise.all(c.map(f=>this.decodeTileInto(f,u,h,l)));const d=new Float32Array(e.width*e.height);for(let f=0;f<e.height;f++){const p=t.north+(t.south-t.north)*(f/(e.height-1));for(let v=0;v<e.width;v++){const m=t.west+(t.east-t.west)*(v/(e.width-1));d[f*e.width+v]=this.sampleAt(p,m,o,u,h,l)}}return{heights:d,width:e.width,height:e.height,bounds:t}}async decodeTileInto(t,e,i,n){const s=this.tileUrlTemplate.replace("{z}",String(t.z)).replace("{x}",String(t.x)).replace("{y}",String(t.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()),c=document.createElement("canvas");c.width=on,c.height=on;const l=c.getContext("2d");if(!l)throw new Error("2D canvas context unavailable");l.drawImage(o,0,0);const{data:h}=l.getImageData(0,0,on,on),u=(t.x-e.x)*on,d=(t.y-e.y)*on;for(let f=0;f<on;f++)for(let p=0;p<on;p++){const v=(f*on+p)*4,m=h[v]*256+h[v+1]+h[v+2]/256-T2,g=u+p,_=d+f;i[_*n+g]=m}}sampleAt(t,e,i,n,s,r){const{x:o,y:c}=Ym(e,t,i),l=(o-n.x)*on,h=(c-n.y)*on,u=Math.max(0,Math.min(r-1,Math.floor(l))),d=Math.max(0,Math.min(r-1,Math.floor(h))),f=Math.min(r-1,u+1),p=Math.min(r-1,d+1),v=l-u,m=h-d,g=s[d*r+u],_=s[d*r+f],w=s[p*r+u],M=s[p*r+f],S=g+(_-g)*v,b=w+(M-w)*v;return S+(b-S)*m}}const zc=256,D2=5;async function C2(a,t,e,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),c=Math.max(r,o),{zoom:l,gridSize:h}=I2(n,c,Math.max(t.width,t.height)),{tiles:u,bounds:d}=$m(s,n,l,h),f=h*zc,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=u[0];await Promise.all(u.map(async M=>{const S=e(M),b=await i(S);if(!b.ok)throw new Error(`Imagery tile fetch failed (${b.status}): ${S}`);const T=await createImageBitmap(await b.blob());v.drawImage(T,(M.x-m.x)*zc,(M.y-m.y)*zc)}));const g=Math.min(Math.max(t.width,t.height),f);if(g===f)return{source:p,width:f,height:f,bounds:d};const _=document.createElement("canvas");_.width=g,_.height=g;const w=_.getContext("2d");if(!w)throw new Error("2D canvas context unavailable");return w.drawImage(p,0,0,f,f,0,0,g,g),{source:_,width:g,height:g,bounds:d}}function I2(a,t,e){let i=b2(a,t/Math.max(1,e)),n=$0(a,i,t);for(;n>D2&&i>0;)i--,n=$0(a,i,t);return{zoom:i,gridSize:n,mPerPixel:qm(a,i)/zc}}function $0(a,t,e){const i=Math.ceil(e/2/qm(a,t));return Math.max(3,2*i+1)}class P2{attribution="Imagery © Esri, Maxar, Earthstar Geographics, and the GIS User Community";fetchImpl;tileUrlTemplate;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.tileUrlTemplate=t.tileUrlTemplate??"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"}async getImageryTexture(t,e){return C2(t,e,i=>this.tileUrlTemplate.replace("{z}",String(i.z)).replace("{y}",String(i.y)).replace("{x}",String(i.x)),this.fetchImpl)}}class Sn{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(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.endpoints=t.endpoints??Sn.ENDPOINTS}static queue=Promise.resolve();static RETRY_MS=4e3;async getRoads(t){const e=`${t.south},${t.west},${t.north},${t.east}`,i=`[out:json][timeout:30];way["highway"~"^(${Sn.DRIVABLE.join("|")})$"](${e});out geom;`;return this.waysFrom(await this.queued(()=>this.ask(i)))}waysFrom(t){const e=[];for(const i of t.elements??[]){const n=i.geometry,s=i.tags;!s||!n||n.length<2||e.push({id:`osm-${i.id??e.length}`,name:s.name,surface:Sn.surfaceOf(s),widthM:Sn.widthOf(s),points:n.map(r=>({lat:r.lat,lng:r.lon}))})}return e}queued(t){const e=Sn.queue.then(t,t);return Sn.queue=e.catch(()=>{}),e}async ask(t){let e;for(const i of this.endpoints)for(let n=0;n<2;n++){try{const s=await this.fetchImpl(`${i}?data=${encodeURIComponent(t)}`);if(s.ok)return await s.json();if(e=new Error(`${new URL(i).host} refused (${s.status})`),s.status!==429&&s.status!==504)break}catch(s){e=new Error(`${new URL(i).host} unreachable (${String(s)})`);break}await new Promise(s=>setTimeout(s,Sn.RETRY_MS))}throw e??new Error("No Overpass instance answered")}static widthOf(t){const e=Number.parseFloat(t.width??t.est_width??"");if(Number.isFinite(e)&&e>0)return e;const i=Number.parseInt(t.lanes??"",10);return Number.isFinite(i)&&i>0?i*3.5:Sn.WIDTH_M[t.highway]??Sn.DEFAULT_WIDTH_M}static surfaceOf(t){const e=t.surface;return e==="dirt"||e==="earth"||e==="mud"?"dirt":e==="gravel"||e==="fine_gravel"||e==="compacted"||e==="ground"||e==="sand"||e==="unpaved"?"gravel":e?"paved":t.highway==="track"?"gravel":"paved"}}const Bl="https://ufoathome.org/roads/index.json";class Pd{attributionRead;contemporaryRead;fetchImpl;indexUrls;fallback;index;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??Pd.defaultIndexUrls(),this.fallback=t.fallback}get attribution(){return this.attributionRead??this.fallback?.attribution??"Roads © OpenStreetMap contributors"}get contemporary(){return this.contemporaryRead??this.fallback?.contemporary??!0}async getRoads(t){const e=await this.held(t);if(e)return e;if(!this.fallback)return[];const i=await this.fallback.getRoads(t);return this.attributionRead=this.fallback.attribution,this.contemporaryRead=this.fallback.contemporary,i}async held(t){let e;try{e=await this.load()}catch{return}const i=e.find(({entry:n})=>n.north>=t.north&&n.south<=t.south&&n.east>=t.east&&n.west<=t.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 t of this.indexUrls)try{const e=await this.fetchImpl(t);if(!e.ok)continue;const i=await e.json();if(Array.isArray(i?.entries))return i.entries.map(n=>({entry:n,indexUrl:t}))}catch{}return[]}static defaultIndexUrls(){const t=`?v=${encodeURIComponent("0.65.4")}`,e=typeof location>"u"?void 0:new URL("/roads/index.json",location.href).href;return(e&&e!==Bl?[e,Bl]:[Bl]).map(i=>i+t)}}function L2(){return{elevation:new R2,imagery:Zm(),roads:N2()}}function Zm(){return new P2}function N2(){return new Pd({fallback:new Sn})}const O2=new Set,cr="show-witness-map",lr="hide-milestones";class Ki extends HTMLElement{static get observedAttributes(){return["src",cr,lr]}shadow;stageElement;canvas;canvasRenderer;tooltip;toolbar;playPauseButton;static WITNESS_MAP_MIN_SPAN_M=400;static WITNESS_MAP_MARGIN=.6;static WITNESS_MAP_IMAGERY_PX=768;fullscreenButton;witnessMapButton;referencesButton;referenceOpacityInput;referencesShownState=!0;referenceOpacityTouched=!1;milestonesButton;witnessMapPanel;witnessMapCanvas;witnessMapRenderer;seekInput;milestoneMarks;milestoneCaption;timeStartLabel;timeEndLabel;witnessPath;witnessMapBounds;witnessMapImagery;witnessMapImageryRequested=!1;witnessMapImageryCredit;witnessMapImageryFailed=!1;creditShownExternally=!1;lookYawDeg=0;lookPitchDeg=0;milestonesShown=!0;currentSighting=Sl.create();sightingAudio=new l2;soundPreview;player;loopEnabled=!1;playbackBeforeClick;highlightedSourceIds=new Set;paintsShapes=!0;selectionShown=!0;overlayPainter;enableClickToPlay=!0;fullscreenTarget;messages=Hm;realDurationMs;realStartMs;showClockTime=!0;handleFullscreenChange=()=>{this.updateFullscreenButton(),this.resizeWitnessMap()};witnessMapResizeObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>this.resizeWitnessMap());resizeWitnessMap(){this.witnessMapPanel.hidden||(this.sizeWitnessMapCanvas(),this.paintWitnessMap(this.currentTime))}simulatedFullscreen=!1;styleBeforeSimulatedFullscreen;bodyOverflowBeforeSimulatedFullscreen;handleSimulatedFullscreenKey=t=>{t.key==="Escape"&&this.exitSimulatedFullscreen()};handlePointerMove=t=>{const e=this.canvasPointFromEvent(t),i=e&&this.shapeAt(e.x,e.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=`${t.clientX-s.left+12}px`,this.tooltip.style.top=`${t.clientY-s.top+12}px`};handleWitnessMapPointerMove=t=>{const e=this.witnessMapTargetFrom(t);if(!e){this.tooltip.hidden=!0,this.witnessMapCanvas.style.cursor="default";return}this.witnessMapCanvas.style.cursor="pointer",this.tooltip.textContent=e.label,this.tooltip.hidden=!1;const i=this.stageElement.getBoundingClientRect();this.tooltip.style.left=`${t.clientX-i.left+12}px`,this.tooltip.style.top=`${t.clientY-i.top+12}px`};handleWitnessMapClick=t=>{const e=this.witnessMapTargetFrom(t);if(e){if(e.kind==="milestone"&&e.t!==void 0){this.player.seek(e.t);return}this.dispatchEvent(new CustomEvent("lookat",{detail:{lat:e.lat,lng:e.lng,kind:e.kind},bubbles:!0,composed:!0}))}};witnessMapTargetFrom(t){const e=this.witnessMapCanvas.getBoundingClientRect();if(!(e.width===0||e.height===0))return this.witnessMapRenderer.hitTest((t.clientX-e.left)/e.width*this.witnessMapCanvas.width,(t.clientY-e.top)/e.height*this.witnessMapCanvas.height)}handlePointerLeave=()=>{this.tooltip.hidden=!0};constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const t=document.createElement("template");t.innerHTML=`<style>${O1}</style>${N1}`,this.shadow.appendChild(t.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.canvas=this.shadow.getElementById("canvas"),this.canvasRenderer=new xo(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.witnessMapButton=this.shadow.getElementById("witness-map"),this.referencesButton=this.shadow.getElementById("references"),this.referenceOpacityInput=this.shadow.getElementById("reference-opacity"),this.milestonesButton=this.shadow.getElementById("milestones"),this.witnessMapPanel=this.shadow.getElementById("witness-map-panel"),this.witnessMapCanvas=this.shadow.getElementById("witness-map-canvas"),this.witnessMapRenderer=new oa(this.witnessMapCanvas.getContext("2d")),this.seekInput=this.shadow.getElementById("seek"),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 e of[this.timeStartLabel,this.timeEndLabel])e.addEventListener("click",()=>this.toggleTimeDisplay()),e.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.witnessMapButton.addEventListener("click",()=>this.toggleWitnessMap()),this.referencesButton.addEventListener("click",()=>this.toggleReferences()),this.referenceOpacityInput.addEventListener("input",()=>{this.referenceOpacityTouched=!0,this.dispatchReferenceView()}),this.milestonesButton.addEventListener("click",()=>this.toggleMilestones()),this.witnessMapCanvas.addEventListener("pointermove",this.handleWitnessMapPointerMove),this.witnessMapCanvas.addEventListener("pointerleave",this.handlePointerLeave),this.witnessMapCanvas.addEventListener("click",this.handleWitnessMapClick),this.seekInput.addEventListener("input",()=>this.player.seek(this.snapSeekToMark(Number(this.seekInput.value)))),this.seekInput.addEventListener("pointerdown",e=>{this.seekSnapArmed=!0,this.nameMarkUnder(e)}),this.seekInput.addEventListener("pointerup",()=>{this.seekSnapArmed=!1}),this.seekInput.addEventListener("pointermove",e=>this.nameMarkUnder(e)),this.seekInput.addEventListener("pointerleave",()=>this.seekInput.removeAttribute("title")),this.canvas.addEventListener("click",e=>{this.enableClickToPlay&&(e.detail<=1&&(this.playbackBeforeClick={state:this.playbackState,time:this.currentTime}),this.togglePlayPause())}),this.canvas.addEventListener("dblclick",e=>{this.enableClickToPlay&&(e.preventDefault(),this.restorePlayback(),this.toggleFullscreen())}),this.canvas.addEventListener("pointermove",this.handlePointerMove),this.canvas.addEventListener("pointerleave",this.handlePointerLeave),document.addEventListener("fullscreenchange",this.handleFullscreenChange),this.witnessMapResizeObserver?.observe(this.witnessMapPanel),this.hostControls(void 0),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateWitnessMapButton(),this.updateReferencesButton(),this.updateMilestonesButton(),this.refresh(),this.loadLocaleMessages()}connectedCallback(){this.saidTexts=void 0;const t=this.getAttribute("src");t&&this.loadFromSrc(t)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.handleFullscreenChange),this.witnessMapResizeObserver?.disconnect(),this.exitSimulatedFullscreen(),this.sightingAudio.dispose()}attributeChangedCallback(t,e,i){t==="src"&&i&&i!==e&&this.isConnected&&this.loadFromSrc(i),t===cr&&this.applyWitnessMapDefault(),t===lr&&this.setMilestonesShown(!this.hasAttribute(lr))}async loadFromSrc(t){this.sightingData=await Fm.json(t)}get sightingData(){return h2(this.currentSighting)}set sightingData(t){this.player.stop(),this.soundPreview=void 0,this.sightingAudio.silence(),this.currentSighting=d2(t),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.refresh(),this.applyWitnessMapDefault()}get sighting(){return this.currentSighting}previewSound(t){this.soundPreview=t,this.sightingAudio.resume(),this.sightingAudio.setSound(t)}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(t){this.player.seek(t)}get seekableDuration(){return this.player.seekableDuration}get autoReplayEnabled(){return this.loopEnabled}set autoReplayEnabled(t){t!==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(t){this.toolbar.classList.toggle("hidden",!t)}get playbackState(){return this.player.playbackState}get selectedSourceIds(){return this.highlightedSourceIds}get durationSeconds(){return this.currentSighting.event.durationSeconds}set durationSeconds(t){this.currentSighting.event.durationSeconds=t,this.updateTimeLabels(),this.refresh(),this.updatePlayPauseButton()}set selectedSourceIds(t){const e=new Set(t);e.size===this.highlightedSourceIds.size&&[...e].every(n=>this.highlightedSourceIds.has(n))||(this.highlightedSourceIds=e,this.refresh())}hasVisibleShapeAt(t,e){return this.shapeAt(t,e)!==void 0}refresh(){this.applyFrameFormat(),this.updateTimeLabels(),this.seekInput.max=String(this.player.seekableDuration),this.refreshMilestoneMarks(),this.updateMilestonesButton(),this.updateWitnessMap(),this.updateReferences(),this.player.seek(this.player.time)}hostControls(t){const e=[this.milestonesButton,this.referenceOpacityInput,this.referencesButton,this.witnessMapButton];if(t)for(const i of e)t.appendChild(i);else for(const i of e)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 t=this.currentSighting.references;!this.referenceOpacityTouched&&t.length>0&&(this.referenceOpacityInput.value=String(t[0].opacity)),this.updateReferencesButton()}updateReferencesButton(){const t=this.currentSighting.references.length>0;this.referencesButton.hidden=!t,this.referenceOpacityInput.hidden=!t||!this.referencesShownState,this.referencesButton.setAttribute("aria-pressed",String(this.referencesShownState));const e=this.referencesShownState?this.messages.hideReferences:this.messages.showReferences;this.referencesButton.title=e,this.referencesButton.setAttribute("aria-label",e),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 t=this.player.seekableDuration,e=t>0?Jc(this.sighting.milestones):[];this.milestoneMarks.replaceChildren(...e.map(i=>{const n=document.createElement("button");n.type="button",n.className="milestone-mark",n.style.left=`${Math.min(Math.max(i.t/t,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(t){const e=this.player.seekableDuration,i=this.seekInput.getBoundingClientRect().width;if(e<=0||i<=0)return;const n=Ki.MARK_SNAP_PX/i*e;let s;for(const r of this.milestoneMarks.children){const o=Number(r.dataset.t);Math.abs(o-t)>n||(!s||Math.abs(o-t)<Math.abs(s.t-t))&&(s={t:o,name:r.title})}return s}snapSeekToMark(t){return this.seekSnapArmed?(this.seekSnapArmed=!1,this.markNear(t)?.t??t):t}nameMarkUnder(t){const e=this.seekInput.getBoundingClientRect(),i=this.player.seekableDuration;if(e.width<=0||i<=0)return;const n=(t.clientX-e.left)/e.width*i,s=this.markNear(n);s?this.seekInput.title=s.name:this.seekInput.removeAttribute("title")}showMilestoneAt(t){const e=this.milestonesShown&&this.sighting.milestones.length>0?W0(this.sighting.milestones,t):void 0;if(this.milestoneCaption.hidden=e===void 0,!e)return;const i=document.createElement("b");i.textContent=this.said.read(e.label)??"";const n=this.said.read(e.note),s=n?` — ${n}`:"";this.milestoneCaption.replaceChildren(i,document.createTextNode(s))}exposureInstants(t){const e=this.exposureTimes(t),i=1/e.length;return e.map(n=>({shapes:this.shapesAt(n),share:i}))}exposureTimes(t=this.currentTime){const e=En.windowEndingAt(t,this.currentSighting.exposure??0);if(e.ms<Ki.SHORTEST_VISIBLE_EXPOSURE_MS)return[t];const i=Math.min(Ki.MAX_EXPOSURE_STEPS,Math.max(2,Math.round(e.ms/Ki.SHORTEST_VISIBLE_EXPOSURE_MS))),n=Math.ceil(this.travelPxOver(e.fromMs,e.ms)/Ki.EXPOSURE_STEP_PX),s=Math.min(Ki.MAX_TRAVEL_STEPS,Math.max(i,n)),r=[];for(let o=0;o<s;o++)r.push(e.fromMs+e.ms*o/(s-1));return r}travelPxOver(t,e){const i=this.shapesAt(t),n=this.shapesAt(t+e);let s=0;for(const[r,o]of i){const c=n.get(r);if(!c)continue;const l=c.bounds.x+c.bounds.width/2-(o.bounds.x+o.bounds.width/2),h=c.bounds.y+c.bounds.height/2-(o.bounds.y+o.bounds.height/2);s=Math.max(s,Math.hypot(l,h))}return s}shapeAt(t,e,i){for(const n of this.exposureTimes()){const s=this.currentSighting.timeline.hitTest(n,t,e,i);if(s)return s}}shapesAt(t){const e=new Map;for(const i of this.currentSighting.timeline.sourceIds){const n=this.currentSighting.timeline.getInterpolatedShapeAt(t,i);n&&e.set(i,n)}return e}static SHORTEST_VISIBLE_EXPOSURE_MS=20;static MAX_EXPOSURE_STEPS=48;static EXPOSURE_STEP_PX=2;static MAX_TRAVEL_STEPS=320;applyFrameFormat(){const t=ri.frameWidthPx(this.currentSighting.instrument,this.canvas.height);if(this.canvas.width===t)return;this.canvas.width=t,this.canvas.parentElement?.style.setProperty("--frame-aspect",`${t} / ${this.canvas.height}`)}canvasPointFromEvent(t){const e=this.canvas.getBoundingClientRect();if(!(e.width===0||e.height===0))return{x:(t.clientX-e.left)/e.width*this.canvas.width,y:(t.clientY-e.top)/e.height*this.canvas.height}}onFrame(t,e){this.canvasRenderer.clear(this.canvas.width,this.canvas.height);const i=this.playbackState!=="playing"?this.highlightedSourceIds:O2;this.canvasRenderer.setStarPoints(ri.starPointsOf(this.sighting.instrument));const n=(ai(this.sighting,t)?.rollDeg??0)+this.gaitAt(t).rollDeg;this.canvasRenderer.setRoll(n*Math.PI/180);const s=this.exposureInstants(t),r=this.frameShift;if(this.paintsShapes)for(const o of s)for(const[,c]of o.shapes){const l=o.share,h=l===1?c:{...c,transparency:1-(1-c.transparency)*l};this.canvasRenderer.paintShape(this.shifted(h,r))}for(const[o,c]of s[0].shapes)!this.selectionShown||!i.has(o)||(this.paintsShapes?i.size===1?this.canvasRenderer.paintShape({...c,selected:!0}):this.canvasRenderer.paintMemberOutline(c):this.canvasRenderer.paintSelectionOnly(this.shifted(c,r)));if(this.selectionShown&&i.size>1){const o=ji.groupBoundsFor([...e].filter(([c])=>i.has(c)).map(([,c])=>c.bounds));this.canvasRenderer.paintGroupHandles(o)}this.overlayPainter?.(this.canvasRenderer),this.mapShapeBounds=s.flatMap(o=>[...o.shapes.values()].filter(c=>c.transparency<1).map(c=>this.shifted(c,r).bounds)),this.keepWitnessMapClear(),this.seekInput.value=String(t),this.timeStartLabel.textContent=this.formatPosition(t),this.showMilestoneAt(t),this.paintWitnessMap(t),this.playbackState==="playing"?(this.soundPreview=void 0,this.sightingAudio.setSound(e2(this.currentSighting,t))):this.soundPreview?this.sightingAudio.setSound(this.soundPreview):this.sightingAudio.silence(),this.updatePlayPauseButton(),this.dispatchEvent(new CustomEvent("timeupdate",{detail:{time:t}}))}shifted(t,e){return e.x===0&&e.y===0?t:{...t,bounds:{...t.bounds,x:t.bounds.x+e.x,y:t.bounds.y+e.y}}}createPlayer(){const t=new i2(this.currentSighting.timeline,(e,i)=>this.onFrame(e,i));return t.loop=this.loopEnabled,t.onEnded=()=>{this.updatePlayPauseButton(),this.dispatchEvent(new CustomEvent("ended",{bubbles:!0,composed:!0}))},t}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())}updatePlayPauseButton(){const t=this.player.playbackState==="playing";this.playPauseButton.textContent=t?"⏸":"▶";const e=this.player.seekableDuration>0;this.playPauseButton.disabled=!e;const i=e?t?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 t=this.playbackBeforeClick;t&&(this.currentTime=t.time,t.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(t=>{console.error("<rr0-ufo>: requestFullscreen() failed —",t)})}enterSimulatedFullscreen(){const t=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen=t.getAttribute("style")??"",this.bodyOverflowBeforeSimulatedFullscreen=document.body.style.overflow;const e=t.style;e.setProperty("position","fixed"),e.setProperty("inset","0"),e.setProperty("margin","0"),e.setProperty("max-width","none"),e.setProperty("max-height","none"),e.setProperty("aspect-ratio","auto"),e.setProperty("z-index","2147483647"),e.setProperty("background","#000"),e.setProperty("width","100vw"),e.setProperty("width","100dvw"),e.setProperty("height","100vh"),e.setProperty("height","100dvh"),document.body.style.overflow="hidden",this.simulatedFullscreen=!0,document.addEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton()}exitSimulatedFullscreen(){if(!this.simulatedFullscreen)return;const t=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen?t.setAttribute("style",this.styleBeforeSimulatedFullscreen):t.removeAttribute("style"),document.body.style.overflow=this.bodyOverflowBeforeSimulatedFullscreen??"",this.simulatedFullscreen=!1,document.removeEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton()}toggleWitnessMap(){this.setWitnessMapOpen(this.witnessMapPanel.hidden)}applyWitnessMapDefault(){this.setWitnessMapOpen(this.hasAttribute(cr)&&this.witnessPath!==void 0)}setWitnessMapOpen(t){this.witnessMapPanel.hidden=!t,this.witnessMapPanel.removeAttribute("title"),this.witnessMapButton.setAttribute("aria-pressed",String(t)),this.updateWitnessMapButton(),t&&(this.sizeWitnessMapCanvas(),this.loadWitnessMapImagery(),this.paintWitnessMap(this.currentTime))}updateWitnessMapButton(){const e=!this.witnessMapPanel.hidden?this.messages.hideWitnessMap:this.messages.showWitnessMap;this.witnessMapButton.title=e,this.witnessMapButton.setAttribute("aria-label",e)}updateWitnessMap(){const t=this.witnessPath!==void 0;if(this.witnessPath=mo.of(this.currentSighting),this.witnessMapButton.hidden=this.witnessPath===void 0,!t&&this.witnessPath&&this.applyWitnessMapDefault(),!this.witnessPath){this.setWitnessMapOpen(!1),this.witnessMapBounds=void 0;return}const e=this.witnessPath.boundsAround(Ki.WITNESS_MAP_MIN_SPAN_M,Ki.WITNESS_MAP_MARGIN);(!this.witnessMapBounds||!this.sameGround(this.witnessMapBounds,e))&&(this.witnessMapBounds=e,this.witnessMapImagery=void 0,this.witnessMapImageryCredit=void 0,this.witnessMapImageryFailed=!1,this.witnessMapImageryRequested=!1,this.witnessMapPanel.hidden||this.loadWitnessMapImagery())}sameGround(t,e){const i=Math.abs(t.east-t.west)/20;return Math.abs(t.north-e.north)<i&&Math.abs(t.south-e.south)<i&&Math.abs(t.west-e.west)<i&&Math.abs(t.east-e.east)<i}async loadWitnessMapImagery(){if(this.witnessMapImageryRequested||!this.witnessMapBounds)return;this.witnessMapImageryRequested=!0;const t=Zm(),e=this.witnessMapBounds;try{const i=await t.getImageryTexture(e,{width:Ki.WITNESS_MAP_IMAGERY_PX,height:Ki.WITNESS_MAP_IMAGERY_PX});if(this.witnessMapBounds!==e)return;this.witnessMapImagery=i,this.witnessMapImageryCredit=t.attribution}catch{this.witnessMapImageryFailed=!0}this.paintWitnessMap(this.currentTime)}get witnessMapCredit(){return this.witnessMapImageryCredit}get witnessMapFooterLine(){return this.witnessMapImageryFailed?this.messages.mapImageryUnavailable:this.creditShownExternally?void 0:this.witnessMapImageryCredit}mapShapeBounds=[];mapSceneBounds=[];setMapSubjectBounds(t){this.mapSceneBounds=t.map(e=>({x:e.x*this.canvas.width,y:e.y*this.canvas.height,width:e.width*this.canvas.width,height:e.height*this.canvas.height})),this.keepWitnessMapClear()}keepWitnessMapClear(){if(this.witnessMapPanel.hidden)return;const t=this.witnessMapBoxPx;if(!t)return;const e=[...this.mapShapeBounds,...this.mapSceneBounds],i=(l,h,u)=>{for(const d of e)if(!(d.x+d.width<l-u||d.x>h+u)&&!(d.y>t.bottom+u||d.y+d.height<t.top-u))return!0;return!1},n=[this.canvas.width-t.width,this.canvas.width],s=[0,t.width],r=Ki.WITNESS_MAP_CLEARANCE_PX,o=i(...n,0),c=i(...s,0);if(this.witnessMapPanel.classList.toggle("subject-overlap",o&&c),this.witnessMapPanel.classList.contains("on-the-left")){!o&&(c||!i(n[0],n[1],r))&&this.witnessMapPanel.classList.remove("on-the-left");return}i(n[0],n[1],0)&&!i(s[0],s[1],0)&&this.witnessMapPanel.classList.add("on-the-left")}witnessMapBoxPx;static WITNESS_MAP_CLEARANCE_PX=24;sizeWitnessMapCanvas(){const t=this.witnessMapPanel.clientWidth;if(t===0)return;const e=Math.round(t*(globalThis.devicePixelRatio??1));this.measureWitnessMapBox(),this.witnessMapCanvas.width!==e&&(this.witnessMapCanvas.width=e,this.witnessMapCanvas.height=e)}measureWitnessMapBox(){const t=this.witnessMapPanel.getBoundingClientRect(),e=this.canvas.getBoundingClientRect();if(e.width===0||e.height===0)return;const i=this.canvas.width/e.width,n=this.canvas.height/e.height;this.witnessMapBoxPx={width:t.width*i,top:(t.top-e.top)*n,bottom:(t.bottom-e.top)*n}}paintWitnessMap(t){if(this.witnessMapPanel.hidden||!this.witnessPath||!this.witnessMapBounds)return;const e=ai(this.currentSighting,t),i=this.currentSighting.instrument,n=[],s=this.currentSighting.milestones.length>0?W0(this.currentSighting.milestones,t):void 0;for(const r of this.milestonesShown?Jc(this.currentSighting.milestones):[]){const o=ai(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.witnessMapRenderer.paint({bounds:this.witnessMapBounds,imagery:this.witnessMapImagery,path:this.witnessPath,position:e?.lat!==void 0&&e.lng!==void 0?{lat:e.lat,lng:e.lng}:void 0,headingDeg:e?.headingDeg===void 0?void 0:e.headingDeg+this.lookYawDeg,coneHalfAngleDeg:e?ms.of(i,this.canvas.height,e.fovDeg).halfWidthAngleDeg(ri.aspectOf(i)):void 0,markers:n,decor:this.witnessMapDecorAt(t),witnessLabel:this.said.read(this.currentSighting.witness?.title)??this.messages.witnessHere,nightFraction:this.witnessMapNightFraction,attribution:this.witnessMapFooterLine})}toggleMilestones(){this.setMilestonesShown(!this.milestonesShown)}setMilestonesShown(t){this.milestonesShown=t,this.milestoneMarks.hidden=!t,this.milestonesButton.setAttribute("aria-pressed",String(t)),this.updateMilestonesButton(),this.showMilestoneAt(this.currentTime),this.paintWitnessMap(this.currentTime)}updateMilestonesButton(){this.milestonesButton.hidden=this.currentSighting.milestones.length===0;const t=this.milestonesShown?this.messages.hideMilestones:this.messages.showMilestones;this.milestonesButton.title=t,this.milestonesButton.setAttribute("aria-label",t)}witnessMapDecorAt(t){const e=ai(this.currentSighting,0);return e?.lat===void 0||e.lng===void 0?[]:this.currentSighting.decor.filter(i=>i.kind!=="crop").map(i=>{const n=Id(i,t),{lat:s,lng:r}=ps(n.eastM,-n.northM,e.lat,e.lng);return{lat:s,lng:r,headingDeg:n.headingDeg,label:this.said.read(i.title)??this.messages.decorHere}})}witnessMapNightFraction;setSunAltitude(t){const e=t===void 0?void 0:Math.max(0,Math.min(1,-t/12));e!==this.witnessMapNightFraction&&(this.witnessMapNightFraction=e,this.paintWitnessMap(this.currentTime))}setLookOffset(t,e){t===this.lookYawDeg&&e===this.lookPitchDeg||(this.lookYawDeg=t,this.lookPitchDeg=e,this.refresh())}get frameShiftPx(){return this.frameShift}get frameShift(){const t=this.gaitAt(this.currentTime),e=this.lookYawDeg+t.yawDeg,i=this.lookPitchDeg+t.pitchDeg;if(e===0&&i===0)return{x:0,y:0};const n=ai(this.currentSighting,this.currentTime),s=ms.of(this.currentSighting.instrument,this.canvas.height,n?.fovDeg??60);return{x:-s.angleDegToRadiusPx(e),y:s.angleDegToRadiusPx(i)}}gaitAt(t){return si.of(this.currentSighting)?.offsetAt(t)??si.STILL}updateFullscreenButton(){const t=this.simulatedFullscreen||document.fullscreenElement===this.fullscreenTarget;this.fullscreenButton.title=t?this.messages.exitFullscreen:this.messages.fullscreen,this.fullscreenButton.setAttribute("aria-label",this.fullscreenButton.title)}get said(){return this.saidTexts??=new zs(ao.preferencesFor(this))}saidTexts;async loadLocaleMessages(){const t=jc(ao.preferencesFor(this),g2);t!=="en"&&this.applyMessages(await M2(t))}updateTimeLabelTitles(){const t=this.showClockTime?this.messages.switchToElapsed:this.messages.switchToClockTime,e=this.canSwitchTimeDisplay?` — ${t}`:"";this.timeStartLabel.title=this.messages.currentPosition+e,this.timeEndLabel.title=this.messages.duration+e;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(t){this.messages=t,this.updateTimeLabelTitles(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateWitnessMapButton(),this.updateReferencesButton(),this.updateMilestonesButton()}updateTimeLabels(){const t=this.currentSighting.event,e=j1(t);this.realDurationMs=e!==void 0&&e>0?e:void 0,this.realStartMs=t.time?au(t.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(t){if(this.realDurationMs===void 0)return Ho(t);const e=this.currentSighting.timeline.duration,i=e>0&&t<=e?t/e*this.realDurationMs:t;return this.canShowClockTime?J0(Z0(this.realStartMs+i)):Ho(i)}formatEndOfTimeline(){return this.realDurationMs===void 0?Ho(this.currentSighting.timeline.duration):this.canShowClockTime?J0(Z0(this.realStartMs+this.realDurationMs)):Ho(this.realDurationMs)}}function Z0(a){const t=new Date(a);return{hour:t.getUTCHours(),minute:t.getUTCMinutes(),second:t.getUTCSeconds()}}function J0(a){if(a.hour===void 0)return"0:00";const t=e=>String(e).padStart(2,"0");return a.second?`${t(a.hour)}:${t(a.minute??0)}:${t(a.second)}`:`${t(a.hour)}:${t(a.minute??0)}`}function Ho(a){const t=Math.round(a/1e3),e=Math.floor(t/60),i=t%60;return`${e}:${String(i).padStart(2,"0")}`}const ou="rr0-ufo";function Jm(){customElements.get(ou)||customElements.define(ou,Ki)}/**
|
|
697
697
|
* @license
|
|
698
698
|
* Copyright 2010-2026 Three.js Authors
|
|
699
699
|
* SPDX-License-Identifier: MIT
|
|
@@ -5238,12 +5238,13 @@ float densityAt(vec3 p) {
|
|
|
5238
5238
|
if (mask < 0.001) return 0.0;
|
|
5239
5239
|
float top = mix(0.45 + 0.55 * billow, 0.96, flatness);
|
|
5240
5240
|
float profile = smoothstep(0.0, 0.09, h) * (1.0 - smoothstep(top - 0.22, top, h));
|
|
5241
|
-
|
|
5242
|
-
//
|
|
5243
|
-
//
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5241
|
+
float erosion = mix(max(0.0, mask - (1.0 - billow) * 0.38 - (1.0 - detail) * 0.10), mask * 0.8, flatness);
|
|
5242
|
+
// A deck thins away with the distance rather than stopping where its averaged cover can no longer
|
|
5243
|
+
// pay for the billows' bite, which left a hard line of cloud at thirty kilometres (Valensole). A
|
|
5244
|
+
// deck closing up to overcast keeps its far part: that is a ceiling, and a ceiling reaches the
|
|
5245
|
+
// horizon.
|
|
5246
|
+
float fade = mix(1.0 - distant, 1.0, smoothstep(0.5, 0.92, coverage));
|
|
5247
|
+
return profile * erosion * density * carve * fade;
|
|
5247
5248
|
}
|
|
5248
5249
|
void main() {
|
|
5249
5250
|
vec3 dir = normalize(vCloudDirection);
|
|
@@ -5328,7 +5329,7 @@ float transmissionAt(vec3 dir, float distanceM) {
|
|
|
5328
5329
|
if (transmission < 0.015) break;
|
|
5329
5330
|
}
|
|
5330
5331
|
return transmission;
|
|
5331
|
-
}`,i=/\b(noiseMap|sunDir|sunColor|ambientColor|hazeColor|offsetM|seedOffset|localCenter|localSize|localRotation|baseM|thicknessM|eyeM|coverage|sizeM|density|darkness|flatness|SLICE|MAX_HOLES|holeCount|holeCenter|holeSize|holeRotation|R|roots|altitude|coverageThreshold|ellipsoidRadius|clipLocal|densityAt|transmissionAt)\b/g;return(t+e).replace(i,n=>a+n)}class dl{mesh;uniforms;constructor(t,e){this.uniforms={noiseMap:{value:t},sunDir:{value:new D(0,1,0)},sunColor:{value:new st(1,1,1)},ambientColor:{value:new st(.4,.45,.5)},hazeColor:{value:new st(.5,.6,.7)},offsetM:{value:new D},seedOffset:{value:new D},localCenter:{value:new D},localSize:{value:new D},localRotation:{value:0},holeCount:{value:0},holeCenter:{value:Array.from({length:Wr},()=>new D)},holeSize:{value:Array.from({length:Wr},()=>new D)},holeRotation:{value:new Array(Wr).fill(0)},baseM:{value:1e3},thicknessM:{value:650},eyeM:{value:1.6},coverage:{value:.5},sizeM:{value:1400},density:{value:1},darkness:{value:0},flatness:{value:0}};const i=new ae({uniforms:this.uniforms,vertexShader:ZS,fragmentShader:sd,transparent:!0,depthWrite:!1,depthTest:!0,side:Ue});this.mesh=new Dt(new Qe(e,32,16),i),this.mesh.frustumCulled=!1}update(t,e,i,n=[]){const s=this.uniforms;s.localSize.value.set(i?.widthM??0,i?.thicknessM??0,i?.depthM??0),s.localCenter.value.set(i?.eastM??0,i?i.baseM+i.thicknessM/2:0,-(i?.northM??0)),s.localRotation.value=(i?.rotationDeg??0)*Math.PI/180,s.holeCount.value=Math.min(Wr,n.length),n.slice(0,Wr).forEach((o,c)=>{s.holeCenter.value[c].set(o.eastM,o.baseM+o.thicknessM/2,-o.northM),s.holeSize.value[c].set(o.widthM,o.thicknessM,o.depthM),s.holeRotation.value[c]=o.rotationDeg*Math.PI/180}),s.baseM.value=Math.max(0,t.baseM),s.thicknessM.value=Math.max(10,t.thicknessM),s.coverage.value=Math.max(0,Math.min(1,t.coverage)),s.sizeM.value=Math.max(50,t.sizeM),s.density.value=Math.max(0,Math.min(2,t.density)),s.darkness.value=Math.max(0,Math.min(1,t.darkness??0)),s.eyeM.value=Math.max(.1,e),s.flatness.value=t.type==="stratus"?1:t.type==="stratocumulus"?.45:0;const r=nd(t);s.seedOffset.value.set(r%97/97,r%61/61,r%37/37),this.mesh.visible=s.density.value>0&&(i!==void 0||s.coverage.value>0)}static thresholdFor(t){const e=Math.min(.999,Math.max(.001,t));return .564-.2516*(Math.sqrt(3)/Math.PI)*Math.log(e/(1-e))}densityAt(t){const e=this.uniforms,i=(P,B,k)=>{const K=Math.max(0,Math.min(1,(k-P)/(B-P)));return K*K*(3-2*K)},n=(P,B,k)=>P+(B-P)*k,s=e.eyeM.value+t.y,r=2*Gs*s+t.x**2+s**2+t.z**2,o=r/(Math.sqrt(Gs**2+r)+Gs),c=(o-e.baseM.value)/e.thicknessM.value,l=e.localSize.value.x>0;if(c<=0||c>=1||e.coverage.value<=0&&!l)return 0;const h=(P,B,k)=>{const K=t.x+e.offsetM.value.x-P.x,tt=t.z+e.offsetM.value.z-P.z,J=Math.cos(k),it=Math.sin(k);return Math.hypot((J*K-it*tt)/(B.x*.5),(o-P.y)/(B.y*.5),(it*K+J*tt)/(B.z*.5))},u=l?h(e.localCenter.value,e.localSize.value,e.localRotation.value):0;if(u>1.3)return 0;const d=[t.x,t.y,t.z].map((P,B)=>(P+e.offsetM.value.getComponent(B))/(e.sizeM.value*4)+e.seedOffset.value.getComponent(B)),f=e.noiseMap.value.image.data,p=(P,B,k)=>{const K=[P,B,k].map(rt=>(rt%1+1)%1*Je-.5),tt=K.map(Math.floor),J=K.map((rt,Gt)=>rt-tt[Gt]);let it=0;for(let rt=0;rt<2;rt++)for(let Gt=0;Gt<2;Gt++)for(let Jt=0;Jt<2;Jt++){const qt=(tt[0]+Jt+Je)%Je,Y=(tt[1]+Gt+Je)%Je,at=(tt[2]+rt+Je)%Je;it+=f[qt+Je*(Y+Je*at)]/255*(Jt?J[0]:1-J[0])*(Gt?J[1]:1-J[1])*(rt?J[2]:1-J[2])}return it},v=[d[0]*.173,Ah,d[2]*.173];d[0]+=(p(v[0]+.13,v[1]+.27,v[2]+.41)-.5)*1.3,d[2]+=(p(v[0]+.67,v[1]+.53,v[2]+.19)-.5)*1.3;const m=(d[0]*.731+d[2]*.682)*1.371,g=(-d[0]*.682+d[2]*.731)*1.371;let _=i(.2,.8,p(d[0],Ah,d[2])*.65+p(m,Ah+.37,g)*.35);const w=i(8e3,4e4,Math.hypot(t.x,t.y,t.z)),M=n(p(d[0]*2,d[1]*3,d[2]*2),.5,w),S=n(p(d[0]*7,d[1]*7,d[2]*7),.5,w);let b=dl.thresholdFor(e.coverage.value),T=1,x=0;if(l){const P=u+(M-.5)*.18;x=1-i(.35,1,P),T=1-i(.85,1.15,P),_=n(_,1,x),b=Math.min(b,dl.thresholdFor(.5))}for(let P=0;P<e.holeCount.value;P++)T*=i(.85,1.15,h(e.holeCenter.value[P],e.holeSize.value[P],e.holeRotation.value[P])+(M-.5)*.18);if(T<.001)return 0;const A=(1-e.flatness.value)*.3*c*c;let I=i(b-.1+A,b+.1+A,_+(M-.5)*.12*c);if(I=n(I,1,i(.92,1,e.coverage.value)),I=n(I,Math.max(e.coverage.value,x),w),I<.001)return 0;const C=n(.45+.55*M,.96,e.flatness.value),L=i(0,.09,c)*(1-i(C-.22,C,c)),W=1-w,X=n(Math.max(0,I-((1-M)*.38+(1-S)*.1)*W),I*.8,e.flatness.value);return L*X*e.density.value*T}transmissionAt(t,e=1/0){const i=this.uniforms,n=$S(t.y,i.eyeM.value,i.baseM.value,i.thicknessM.value);if(!n)return 1;let[s,r]=n;if(i.localSize.value.x>0){const h=i.localCenter.value.clone().sub(i.offsetM.value);h.y-=i.eyeM.value+(h.x**2+h.z**2)/(2*Gs);const u=i.localSize.value.length()*.5+25,d=t.x*h.x+t.y*h.y+t.z*h.z,f=d*d-h.lengthSq()+u*u;if(f<0)return 1;s=Math.max(s,d-Math.sqrt(f)),r=Math.min(r,d+Math.sqrt(f))}const o=Math.min(r,e,s+18e3);if(o<=s)return 1;const c=(o-s)/48;let l=1;for(let h=0;h<48;h++){const u=s+(h+.5)*c;if(l*=Math.exp(-this.densityAt({x:t.x*u,y:t.y*u,z:t.z*u})*c*.006),l<.015)break}return l}dispose(){this.mesh.removeFromParent(),this.mesh.geometry.dispose(),this.mesh.material.dispose()}}class ci{static VIOLET_NM=400;static DEEP_RED_NM=700;static SAMPLES=ci.build(24);static build(t){const e=[];let i=0,n=0,s=0;for(let r=0;r<t;r++){const o=ci.VIOLET_NM+(r+.5)/t*(ci.DEEP_RED_NM-ci.VIOLET_NM),[c,l,h]=ci.colourMatching(o),u={wavelengthNm:o,r:Math.max(0,3.2406*c-1.5372*l-.4986*h),g:Math.max(0,-.9689*c+1.8758*l+.0415*h),b:Math.max(0,.0557*c-.204*l+1.057*h)};i+=u.r,n+=u.g,s+=u.b,e.push(u)}for(const r of e)r.r/=i,r.g/=n,r.b/=s;return e}static tristimulus(t,e,i){let n=0,s=0,r=0;for(let c=0;c<t.length;c++){const[l,h,u]=ci.colourMatching(t[c]);n+=l*e[c],s+=h*e[c],r+=u*e[c]}const o=683*i;return[n*o,s*o,r*o]}static scotopic(t){const e=t/1e3;return .992*Math.exp(-321.9*(e-.5)**2)}static linearSrgbOf([t,e,i]){return[3.2406*t-1.5372*e-.4986*i,-.9689*t+1.8758*e+.0415*i,.0557*t-.204*e+1.057*i]}static colourMatching(t){const e=(i,n,s)=>{const r=(t-i)/(t<i?n:s);return Math.exp(-.5*r*r)};return[1.056*e(599.8,37.9,31)+.362*e(442,16,26.7)-.065*e(501.1,20.4,26.2),.821*e(568.8,46.9,40.5)+.286*e(530.9,16.3,31.1),1.217*e(437,11.8,36)+.681*e(459,26,13.8)]}}class fl{static reflectance(t,e,i){const s=e/i*Math.sqrt(Math.max(0,1-t*t));if(s>=1)return 1;const r=Math.sqrt(Math.max(0,1-s*s)),o=(i*t-e*r)/(i*t+e*r),c=(e*t-i*r)/(e*t+i*r);return(o*o+c*c)/2}}class gi{static RED_NM=656.3;static BLUE_NM=435.8;static ANCHOR_RED=1.3312;static ANCHOR_BLUE=1.3404;static B=(gi.ANCHOR_BLUE-gi.ANCHOR_RED)/(1/(gi.BLUE_NM*gi.BLUE_NM)-1/(gi.RED_NM*gi.RED_NM));static A=gi.ANCHOR_RED-gi.B/(gi.RED_NM*gi.RED_NM);static indexAt(t){return gi.A+gi.B/(t*t)}}class dr{static MAX_CHORDS=4;index=1.333;set refractiveIndex(t){this.index=t}trace(t,e){const i=Math.min(1,Math.max(0,t)),n=Math.sqrt(Math.max(0,1-i*i)),s=i/this.index,r=Math.sqrt(Math.max(0,1-s*s)),o=Math.asin(i),c=Math.asin(s),l=fl.reflectance(n,1,this.index);let h=0;e[h].chords=0,e[h].scatteringAngle=dr.folded(Math.PI-2*o),e[h].weight=l,h++;const u=fl.reflectance(r,this.index,1);let d=1-l;for(let f=1;f<=dr.MAX_CHORDS&&h<e.length;f++){const p=2*(o-c)+(f-1)*(Math.PI-2*c);e[h].chords=f,e[h].scatteringAngle=dr.folded(p),e[h].weight=d*(1-u),h++,d*=u}return h}static folded(t){const e=2*Math.PI;let i=t%e;return i<0&&(i+=e),i>Math.PI?e-i:i}}class Ze{static BINS=1800;static SOURCE_RADIUS_DEG=.265;static FULL_UNTIL_DEG=60;static FADED_BY_DEG=90;static IMPACT_STEPS=4096;drop=new dr;previous=Ze.emergences();current=Ze.emergences();tally=new Float32Array(Ze.BINS*3);radiance=new Float32Array(Ze.BINS*3);scratch=new Float32Array(Ze.BINS*3);static emergences(){return Array.from({length:dr.MAX_CHORDS+1},()=>({chords:0,scatteringAngle:0,weight:0}))}compute(){this.tally.fill(0);for(const t of ci.SAMPLES)this.sweep(t);return this.toRadiance(),this.blurBySourceDisc(),{bins:Ze.BINS,data:this.radiance,binDeg:180/Ze.BINS}}sweep(t){this.drop.refractiveIndex=gi.indexAt(t.wavelengthNm);const e=Ze.IMPACT_STEPS;let i=this.drop.trace(0,this.previous);const n=1/e;for(let s=1;s<=e;s++){const r=this.drop.trace(Math.sqrt(s/e),this.current);for(let o=0;o<Math.min(r,i);o++){const c=this.previous[o],l=this.current[o];c.chords===l.chords&&this.deposit(c.scatteringAngle,l.scatteringAngle,(c.weight+l.weight)/2*n,t)}i=r,this.copyInto(this.current,this.previous)}}copyInto(t,e){for(let i=0;i<t.length;i++)e[i].chords=t[i].chords,e[i].scatteringAngle=t[i].scatteringAngle,e[i].weight=t[i].weight}deposit(t,e,i,n){if(i<=0)return;const s=Ze.BINS,r=Math.PI/s,o=Math.min(t,e),c=Math.max(t,e),l=c-o,h=Math.min(s-1,Math.max(0,Math.floor(o/r))),u=Math.min(s-1,Math.max(0,Math.floor(c/r)));if(l<=0||h===u){this.add(h,i,n);return}for(let d=h;d<=u;d++){const f=Math.min(c,(d+1)*r)-Math.max(o,d*r);f>0&&this.add(d,i*f/l,n)}}add(t,e,i){const n=t*3,s=e*ci.SAMPLES.length;this.tally[n]+=s*i.r,this.tally[n+1]+=s*i.g,this.tally[n+2]+=s*i.b}toRadiance(){const t=Ze.BINS,e=Math.PI/t;for(let i=0;i<t;i++){const n=2*Math.PI*(Math.cos(i*e)-Math.cos((i+1)*e)),s=n>0?this.backwardShare((i+.5)*(180/t))/n:0,r=i*3;this.radiance[r]=this.tally[r]*s,this.radiance[r+1]=this.tally[r+1]*s,this.radiance[r+2]=this.tally[r+2]*s}}backwardShare(t){const e=180-t;if(e<=Ze.FULL_UNTIL_DEG)return 1;if(e>=Ze.FADED_BY_DEG)return 0;const i=(e-Ze.FULL_UNTIL_DEG)/(Ze.FADED_BY_DEG-Ze.FULL_UNTIL_DEG);return Math.cos(i*Math.PI/2)**2}blurBySourceDisc(){const t=Ze.BINS,e=Ze.SOURCE_RADIUS_DEG*t/180,i=Math.max(1,Math.ceil(e)),n=[];let s=0;for(let r=-i;r<=i;r++){const o=Math.max(0,e*e-r*r),c=Math.sqrt(o);n.push(c),s+=c}if(!(s<=0)){this.scratch.set(this.radiance);for(let r=0;r<t;r++){let o=0,c=0,l=0;for(let u=-i;u<=i;u++){const d=Math.min(t-1,Math.max(0,r+u))*3,f=n[u+i];o+=this.scratch[d]*f,c+=this.scratch[d+1]*f,l+=this.scratch[d+2]*f}const h=r*3;this.radiance[h]=o/s,this.radiance[h+1]=c/s,this.radiance[h+2]=l/s}}}}class ga{static RADIUS=880;static RENDER_ORDER=5.5;static GAIN=.22;static MOON_SATURATION=.15;object;material;sky=new Ze;texture;texels;computed=!1;constructor(){this.texels=new Uint16Array(Ze.BINS*4),this.texture=new Js(this.texels,Ze.BINS,1,_i,ze),this.texture.minFilter=se,this.texture.magFilter=se,this.texture.wrapS=yi,this.texture.wrapT=yi,this.texture.needsUpdate=!0,this.material=new ae({uniforms:{uSource:{value:new D(0,1,0)},uStrength:{value:0},uTint:{value:new D(1,1,1)},uSaturation:{value:1},uProfile:{value:this.texture},uGain:{value:ga.GAIN}},vertexShader:`
|
|
5332
|
+
}`,i=/\b(noiseMap|sunDir|sunColor|ambientColor|hazeColor|offsetM|seedOffset|localCenter|localSize|localRotation|baseM|thicknessM|eyeM|coverage|sizeM|density|darkness|flatness|SLICE|MAX_HOLES|holeCount|holeCenter|holeSize|holeRotation|R|roots|altitude|coverageThreshold|ellipsoidRadius|clipLocal|densityAt|transmissionAt)\b/g;return(t+e).replace(i,n=>a+n)}class dl{mesh;uniforms;constructor(t,e){this.uniforms={noiseMap:{value:t},sunDir:{value:new D(0,1,0)},sunColor:{value:new st(1,1,1)},ambientColor:{value:new st(.4,.45,.5)},hazeColor:{value:new st(.5,.6,.7)},offsetM:{value:new D},seedOffset:{value:new D},localCenter:{value:new D},localSize:{value:new D},localRotation:{value:0},holeCount:{value:0},holeCenter:{value:Array.from({length:Wr},()=>new D)},holeSize:{value:Array.from({length:Wr},()=>new D)},holeRotation:{value:new Array(Wr).fill(0)},baseM:{value:1e3},thicknessM:{value:650},eyeM:{value:1.6},coverage:{value:.5},sizeM:{value:1400},density:{value:1},darkness:{value:0},flatness:{value:0}};const i=new ae({uniforms:this.uniforms,vertexShader:ZS,fragmentShader:sd,transparent:!0,depthWrite:!1,depthTest:!0,side:Ue});this.mesh=new Dt(new Qe(e,32,16),i),this.mesh.frustumCulled=!1}update(t,e,i,n=[]){const s=this.uniforms;s.localSize.value.set(i?.widthM??0,i?.thicknessM??0,i?.depthM??0),s.localCenter.value.set(i?.eastM??0,i?i.baseM+i.thicknessM/2:0,-(i?.northM??0)),s.localRotation.value=(i?.rotationDeg??0)*Math.PI/180,s.holeCount.value=Math.min(Wr,n.length),n.slice(0,Wr).forEach((o,c)=>{s.holeCenter.value[c].set(o.eastM,o.baseM+o.thicknessM/2,-o.northM),s.holeSize.value[c].set(o.widthM,o.thicknessM,o.depthM),s.holeRotation.value[c]=o.rotationDeg*Math.PI/180}),s.baseM.value=Math.max(0,t.baseM),s.thicknessM.value=Math.max(10,t.thicknessM),s.coverage.value=Math.max(0,Math.min(1,t.coverage)),s.sizeM.value=Math.max(50,t.sizeM),s.density.value=Math.max(0,Math.min(2,t.density)),s.darkness.value=Math.max(0,Math.min(1,t.darkness??0)),s.eyeM.value=Math.max(.1,e),s.flatness.value=t.type==="stratus"?1:t.type==="stratocumulus"?.45:0;const r=nd(t);s.seedOffset.value.set(r%97/97,r%61/61,r%37/37),this.mesh.visible=s.density.value>0&&(i!==void 0||s.coverage.value>0)}static thresholdFor(t){const e=Math.min(.999,Math.max(.001,t));return .564-.2516*(Math.sqrt(3)/Math.PI)*Math.log(e/(1-e))}densityAt(t){const e=this.uniforms,i=(P,B,k)=>{const K=Math.max(0,Math.min(1,(k-P)/(B-P)));return K*K*(3-2*K)},n=(P,B,k)=>P+(B-P)*k,s=e.eyeM.value+t.y,r=2*Gs*s+t.x**2+s**2+t.z**2,o=r/(Math.sqrt(Gs**2+r)+Gs),c=(o-e.baseM.value)/e.thicknessM.value,l=e.localSize.value.x>0;if(c<=0||c>=1||e.coverage.value<=0&&!l)return 0;const h=(P,B,k)=>{const K=t.x+e.offsetM.value.x-P.x,tt=t.z+e.offsetM.value.z-P.z,J=Math.cos(k),it=Math.sin(k);return Math.hypot((J*K-it*tt)/(B.x*.5),(o-P.y)/(B.y*.5),(it*K+J*tt)/(B.z*.5))},u=l?h(e.localCenter.value,e.localSize.value,e.localRotation.value):0;if(u>1.3)return 0;const d=[t.x,t.y,t.z].map((P,B)=>(P+e.offsetM.value.getComponent(B))/(e.sizeM.value*4)+e.seedOffset.value.getComponent(B)),f=e.noiseMap.value.image.data,p=(P,B,k)=>{const K=[P,B,k].map(rt=>(rt%1+1)%1*Je-.5),tt=K.map(Math.floor),J=K.map((rt,Gt)=>rt-tt[Gt]);let it=0;for(let rt=0;rt<2;rt++)for(let Gt=0;Gt<2;Gt++)for(let Jt=0;Jt<2;Jt++){const qt=(tt[0]+Jt+Je)%Je,Y=(tt[1]+Gt+Je)%Je,at=(tt[2]+rt+Je)%Je;it+=f[qt+Je*(Y+Je*at)]/255*(Jt?J[0]:1-J[0])*(Gt?J[1]:1-J[1])*(rt?J[2]:1-J[2])}return it},v=[d[0]*.173,Ah,d[2]*.173];d[0]+=(p(v[0]+.13,v[1]+.27,v[2]+.41)-.5)*1.3,d[2]+=(p(v[0]+.67,v[1]+.53,v[2]+.19)-.5)*1.3;const m=(d[0]*.731+d[2]*.682)*1.371,g=(-d[0]*.682+d[2]*.731)*1.371;let _=i(.2,.8,p(d[0],Ah,d[2])*.65+p(m,Ah+.37,g)*.35);const w=i(8e3,4e4,Math.hypot(t.x,t.y,t.z)),M=n(p(d[0]*2,d[1]*3,d[2]*2),.5,w),S=n(p(d[0]*7,d[1]*7,d[2]*7),.5,w);let b=dl.thresholdFor(e.coverage.value),T=1,x=0;if(l){const P=u+(M-.5)*.18;x=1-i(.35,1,P),T=1-i(.85,1.15,P),_=n(_,1,x),b=Math.min(b,dl.thresholdFor(.5))}for(let P=0;P<e.holeCount.value;P++)T*=i(.85,1.15,h(e.holeCenter.value[P],e.holeSize.value[P],e.holeRotation.value[P])+(M-.5)*.18);if(T<.001)return 0;const A=(1-e.flatness.value)*.3*c*c;let I=i(b-.1+A,b+.1+A,_+(M-.5)*.12*c);if(I=n(I,1,i(.92,1,e.coverage.value)),I=n(I,Math.max(e.coverage.value,x),w),I<.001)return 0;const C=n(.45+.55*M,.96,e.flatness.value),L=i(0,.09,c)*(1-i(C-.22,C,c)),W=n(Math.max(0,I-(1-M)*.38-(1-S)*.1),I*.8,e.flatness.value),X=n(1-w,1,i(.5,.92,e.coverage.value));return L*W*e.density.value*T*X}transmissionAt(t,e=1/0){const i=this.uniforms,n=$S(t.y,i.eyeM.value,i.baseM.value,i.thicknessM.value);if(!n)return 1;let[s,r]=n;if(i.localSize.value.x>0){const h=i.localCenter.value.clone().sub(i.offsetM.value);h.y-=i.eyeM.value+(h.x**2+h.z**2)/(2*Gs);const u=i.localSize.value.length()*.5+25,d=t.x*h.x+t.y*h.y+t.z*h.z,f=d*d-h.lengthSq()+u*u;if(f<0)return 1;s=Math.max(s,d-Math.sqrt(f)),r=Math.min(r,d+Math.sqrt(f))}const o=Math.min(r,e,s+18e3);if(o<=s)return 1;const c=(o-s)/48;let l=1;for(let h=0;h<48;h++){const u=s+(h+.5)*c;if(l*=Math.exp(-this.densityAt({x:t.x*u,y:t.y*u,z:t.z*u})*c*.006),l<.015)break}return l}dispose(){this.mesh.removeFromParent(),this.mesh.geometry.dispose(),this.mesh.material.dispose()}}class ci{static VIOLET_NM=400;static DEEP_RED_NM=700;static SAMPLES=ci.build(24);static build(t){const e=[];let i=0,n=0,s=0;for(let r=0;r<t;r++){const o=ci.VIOLET_NM+(r+.5)/t*(ci.DEEP_RED_NM-ci.VIOLET_NM),[c,l,h]=ci.colourMatching(o),u={wavelengthNm:o,r:Math.max(0,3.2406*c-1.5372*l-.4986*h),g:Math.max(0,-.9689*c+1.8758*l+.0415*h),b:Math.max(0,.0557*c-.204*l+1.057*h)};i+=u.r,n+=u.g,s+=u.b,e.push(u)}for(const r of e)r.r/=i,r.g/=n,r.b/=s;return e}static tristimulus(t,e,i){let n=0,s=0,r=0;for(let c=0;c<t.length;c++){const[l,h,u]=ci.colourMatching(t[c]);n+=l*e[c],s+=h*e[c],r+=u*e[c]}const o=683*i;return[n*o,s*o,r*o]}static scotopic(t){const e=t/1e3;return .992*Math.exp(-321.9*(e-.5)**2)}static linearSrgbOf([t,e,i]){return[3.2406*t-1.5372*e-.4986*i,-.9689*t+1.8758*e+.0415*i,.0557*t-.204*e+1.057*i]}static colourMatching(t){const e=(i,n,s)=>{const r=(t-i)/(t<i?n:s);return Math.exp(-.5*r*r)};return[1.056*e(599.8,37.9,31)+.362*e(442,16,26.7)-.065*e(501.1,20.4,26.2),.821*e(568.8,46.9,40.5)+.286*e(530.9,16.3,31.1),1.217*e(437,11.8,36)+.681*e(459,26,13.8)]}}class fl{static reflectance(t,e,i){const s=e/i*Math.sqrt(Math.max(0,1-t*t));if(s>=1)return 1;const r=Math.sqrt(Math.max(0,1-s*s)),o=(i*t-e*r)/(i*t+e*r),c=(e*t-i*r)/(e*t+i*r);return(o*o+c*c)/2}}class gi{static RED_NM=656.3;static BLUE_NM=435.8;static ANCHOR_RED=1.3312;static ANCHOR_BLUE=1.3404;static B=(gi.ANCHOR_BLUE-gi.ANCHOR_RED)/(1/(gi.BLUE_NM*gi.BLUE_NM)-1/(gi.RED_NM*gi.RED_NM));static A=gi.ANCHOR_RED-gi.B/(gi.RED_NM*gi.RED_NM);static indexAt(t){return gi.A+gi.B/(t*t)}}class dr{static MAX_CHORDS=4;index=1.333;set refractiveIndex(t){this.index=t}trace(t,e){const i=Math.min(1,Math.max(0,t)),n=Math.sqrt(Math.max(0,1-i*i)),s=i/this.index,r=Math.sqrt(Math.max(0,1-s*s)),o=Math.asin(i),c=Math.asin(s),l=fl.reflectance(n,1,this.index);let h=0;e[h].chords=0,e[h].scatteringAngle=dr.folded(Math.PI-2*o),e[h].weight=l,h++;const u=fl.reflectance(r,this.index,1);let d=1-l;for(let f=1;f<=dr.MAX_CHORDS&&h<e.length;f++){const p=2*(o-c)+(f-1)*(Math.PI-2*c);e[h].chords=f,e[h].scatteringAngle=dr.folded(p),e[h].weight=d*(1-u),h++,d*=u}return h}static folded(t){const e=2*Math.PI;let i=t%e;return i<0&&(i+=e),i>Math.PI?e-i:i}}class Ze{static BINS=1800;static SOURCE_RADIUS_DEG=.265;static FULL_UNTIL_DEG=60;static FADED_BY_DEG=90;static IMPACT_STEPS=4096;drop=new dr;previous=Ze.emergences();current=Ze.emergences();tally=new Float32Array(Ze.BINS*3);radiance=new Float32Array(Ze.BINS*3);scratch=new Float32Array(Ze.BINS*3);static emergences(){return Array.from({length:dr.MAX_CHORDS+1},()=>({chords:0,scatteringAngle:0,weight:0}))}compute(){this.tally.fill(0);for(const t of ci.SAMPLES)this.sweep(t);return this.toRadiance(),this.blurBySourceDisc(),{bins:Ze.BINS,data:this.radiance,binDeg:180/Ze.BINS}}sweep(t){this.drop.refractiveIndex=gi.indexAt(t.wavelengthNm);const e=Ze.IMPACT_STEPS;let i=this.drop.trace(0,this.previous);const n=1/e;for(let s=1;s<=e;s++){const r=this.drop.trace(Math.sqrt(s/e),this.current);for(let o=0;o<Math.min(r,i);o++){const c=this.previous[o],l=this.current[o];c.chords===l.chords&&this.deposit(c.scatteringAngle,l.scatteringAngle,(c.weight+l.weight)/2*n,t)}i=r,this.copyInto(this.current,this.previous)}}copyInto(t,e){for(let i=0;i<t.length;i++)e[i].chords=t[i].chords,e[i].scatteringAngle=t[i].scatteringAngle,e[i].weight=t[i].weight}deposit(t,e,i,n){if(i<=0)return;const s=Ze.BINS,r=Math.PI/s,o=Math.min(t,e),c=Math.max(t,e),l=c-o,h=Math.min(s-1,Math.max(0,Math.floor(o/r))),u=Math.min(s-1,Math.max(0,Math.floor(c/r)));if(l<=0||h===u){this.add(h,i,n);return}for(let d=h;d<=u;d++){const f=Math.min(c,(d+1)*r)-Math.max(o,d*r);f>0&&this.add(d,i*f/l,n)}}add(t,e,i){const n=t*3,s=e*ci.SAMPLES.length;this.tally[n]+=s*i.r,this.tally[n+1]+=s*i.g,this.tally[n+2]+=s*i.b}toRadiance(){const t=Ze.BINS,e=Math.PI/t;for(let i=0;i<t;i++){const n=2*Math.PI*(Math.cos(i*e)-Math.cos((i+1)*e)),s=n>0?this.backwardShare((i+.5)*(180/t))/n:0,r=i*3;this.radiance[r]=this.tally[r]*s,this.radiance[r+1]=this.tally[r+1]*s,this.radiance[r+2]=this.tally[r+2]*s}}backwardShare(t){const e=180-t;if(e<=Ze.FULL_UNTIL_DEG)return 1;if(e>=Ze.FADED_BY_DEG)return 0;const i=(e-Ze.FULL_UNTIL_DEG)/(Ze.FADED_BY_DEG-Ze.FULL_UNTIL_DEG);return Math.cos(i*Math.PI/2)**2}blurBySourceDisc(){const t=Ze.BINS,e=Ze.SOURCE_RADIUS_DEG*t/180,i=Math.max(1,Math.ceil(e)),n=[];let s=0;for(let r=-i;r<=i;r++){const o=Math.max(0,e*e-r*r),c=Math.sqrt(o);n.push(c),s+=c}if(!(s<=0)){this.scratch.set(this.radiance);for(let r=0;r<t;r++){let o=0,c=0,l=0;for(let u=-i;u<=i;u++){const d=Math.min(t-1,Math.max(0,r+u))*3,f=n[u+i];o+=this.scratch[d]*f,c+=this.scratch[d+1]*f,l+=this.scratch[d+2]*f}const h=r*3;this.radiance[h]=o/s,this.radiance[h+1]=c/s,this.radiance[h+2]=l/s}}}}class ga{static RADIUS=880;static RENDER_ORDER=5.5;static GAIN=.22;static MOON_SATURATION=.15;object;material;sky=new Ze;texture;texels;computed=!1;constructor(){this.texels=new Uint16Array(Ze.BINS*4),this.texture=new Js(this.texels,Ze.BINS,1,_i,ze),this.texture.minFilter=se,this.texture.magFilter=se,this.texture.wrapS=yi,this.texture.wrapT=yi,this.texture.needsUpdate=!0,this.material=new ae({uniforms:{uSource:{value:new D(0,1,0)},uStrength:{value:0},uTint:{value:new D(1,1,1)},uSaturation:{value:1},uProfile:{value:this.texture},uGain:{value:ga.GAIN}},vertexShader:`
|
|
5332
5333
|
varying vec3 vDirection;
|
|
5333
5334
|
void main() {
|
|
5334
5335
|
vDirection = normalize((modelMatrix * vec4(position, 1.0)).xyz - cameraPosition);
|
|
@@ -6454,7 +6455,7 @@ void main()
|
|
|
6454
6455
|
if (ice <= 0.0) discard;
|
|
6455
6456
|
gl_FragColor = vec4(iceHaloLight(dir, ice), 1.0);
|
|
6456
6457
|
}
|
|
6457
|
-
`,transparent:!0,blending:Ci,depthWrite:!1,side:Ue,fog:!1}),this.object=new Dt(new Qe(Ti.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(t){this.hostedByDeck=t,this.show(this.shown)}show(t){this.shown=t,this.object.visible=t&&!this.hostedByDeck,this.deckUniforms.uHaloShown.value=t?1:0}get awaitingFirstDisplay(){return this.tracing&&!this.everDisplayed}setUrgent(t){this.urgent=t}set onReady(t){this.onRepaint=t}update(t,e,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(t.x,t.y,t.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(e,r)}requestMap(t,e){if(!(!(Math.abs(t-this.mappedAltitudeDeg)<Ti.ALTITUDE_STEP_DEG)||!(Math.abs(e-this.mappedAlignment)<Ti.ALIGNMENT_STEP))){this.next=void 0;return}if(this.tracing){if(this.tracingFor(t,e)){this.next=void 0;return}if(!(!(Math.abs(t-this.pendingAltitudeDeg)<Ti.LEAP_ALTITUDE_DEG)||!(Math.abs(e-this.pendingAlignment)<Ti.LEAP_ALIGNMENT))){this.next={sourceAltitudeDeg:t,alignment:e};return}}this.next=void 0,this.pendingAltitudeDeg=t,this.pendingAlignment=e,this.sky.begin(t,e),this.tracing=!0,this.scheduleWork()}pendingAltitudeDeg=Number.NaN;pendingAlignment=Number.NaN;next;tracingFor(t,e){return this.tracing&&Math.abs(t-this.pendingAltitudeDeg)<Ti.ALTITUDE_STEP_DEG&&Math.abs(e-this.pendingAlignment)<Ti.ALIGNMENT_STEP}scheduleWork(){if(this.workHandle!==void 0)return;const t=()=>{if(this.workHandle=void 0,!this.tracing)return;const e=performance.now(),i=this.urgent?Ti.URGENT_BUDGET_MS:Ti.BUDGET_MS;do this.sky.trace(Ti.RAYS_PER_BATCH);while(this.sky.tracedRays<Ti.RAYS&&performance.now()-e<i);if(this.sky.tracedRays>=Ti.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(t)};this.workHandle=requestAnimationFrame(t)}stopWork(){this.workHandle!==void 0&&cancelAnimationFrame(this.workHandle),this.workHandle=void 0,this.tracing=!1,this.next=void 0}publish(){const e=this.sky.harvest().data;for(let i=0,n=0;n<e.length;i+=4,n+=3)this.texels[i]=Cn.toHalfFloat(e[n]),this.texels[i+1]=Cn.toHalfFloat(e[n+1]),this.texels[i+2]=Cn.toHalfFloat(e[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 pi{static MAX_CONCURRENT=24;static POINTS=8;static SEGMENTS=pi.POINTS-1;static ACROSS=3;static VERTICES_PER_SEGMENT=(pi.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 t=pi.MAX_CONCURRENT*pi.SEGMENTS*pi.VERTICES_PER_SEGMENT;this.positions=new Float32Array(t*3),this.colors=new Float32Array(t*3);const e=new ue;e.setAttribute("position",new te(this.positions,3)),e.setAttribute("color",new te(this.colors,3)),e.setDrawRange(0,0),this.object=new Dt(e,new gn({vertexColors:!0,transparent:!0,blending:Ci,depthWrite:!1,fog:!1,side:en})),this.object.frustumCulled=!1}get schedule(){return this.meteors}setShower(t,e,i){this.meteors=t,this.radiantAltitudeDeg=e,this.radiantAzimuthDeg=i}update(t){const e=this.object.geometry;if(this.meteors.length===0){e.setDrawRange(0,0);return}const i=xa.aliveAt(this.meteors,t).slice(0,pi.MAX_CONCURRENT);let n=0;for(const{meteor:s,progress:r}of i){const o=this.radiantOf(s);if(!o)continue;const c=ni(o.altitudeDeg,o.azimuthDeg,1),[l,h]=this.basisAround(c),u=s.fromRadiantDeg+r*s.lengthDeg,d=Math.max(s.fromRadiantDeg,u-s.lengthDeg*.6),f=Math.min(1,(1-r)*2.5),p=this.turn(l,h,s.bearingDeg),v=(.15+.85*s.brightness)*f,m=w=>v*w**1.6,g=w=>this.onSphere(c,p,d+(u-d)*w),_=w=>pi.RADIUS*((pi.MIN_HALF_WIDTH_DEG+pi.BRIGHT_HALF_WIDTH_DEG*s.brightness*w)*Math.PI/180);for(let w=1;w<pi.POINTS;w++){const M=(w-1)/pi.SEGMENTS,S=w/pi.SEGMENTS;n=this.pushRibbon(n,g(M),g(S),_(M),_(S),m(M),m(S))}}e.setDrawRange(0,n),e.getAttribute("position").needsUpdate=!0,e.getAttribute("color").needsUpdate=!0}midpointOf(t){const e=this.radiantOf(t);if(!e)return;const i=ni(e.altitudeDeg,e.azimuthDeg,1),[n,s]=this.basisAround(i),r=this.turn(n,s,t.bearingDeg),o=this.onSphere(i,r,t.fromRadiantDeg+t.lengthDeg/2),c=Math.hypot(o.x,o.y,o.z)||1;return{altitudeDeg:Math.asin(o.y/c)*180/Math.PI,azimuthDeg:(Math.atan2(o.x,-o.z)*180/Math.PI+360)%360}}radiantOf(t){return t.radiant?t.radiant:this.radiantAltitudeDeg>0?{altitudeDeg:this.radiantAltitudeDeg,azimuthDeg:this.radiantAzimuthDeg}:void 0}pushRibbon(t,e,i,n,s,r,o){const c=this.normalise(this.cross(this.normalise(e),this.normalise(this.subtract(i,e))));for(let l=0;l<pi.ACROSS-1;l++){const h=l-1,u=l,d=this.across(e,c,n,h),f=this.across(i,c,s,h),p=this.across(e,c,n,u),v=this.across(i,c,s,u),m=(g,_)=>g===0?_:0;t=this.push(t,d,m(h,r)),t=this.push(t,f,m(h,o)),t=this.push(t,p,m(u,r)),t=this.push(t,f,m(h,o)),t=this.push(t,v,m(u,o)),t=this.push(t,p,m(u,r))}return t}across(t,e,i,n){return{x:t.x+e.x*i*n,y:t.y+e.y*i*n,z:t.z+e.z*i*n}}push(t,e,i){const n=t*3;this.positions[n]=e.x,this.positions[n+1]=e.y,this.positions[n+2]=e.z;const s=Et.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,t+1}turn(t,e,i){const n=i*Math.PI/180,s=Math.cos(n),r=Math.sin(n);return{x:t.x*s+e.x*r,y:t.y*s+e.y*r,z:t.z*s+e.z*r}}onSphere(t,e,i){const n=i*Math.PI/180,s=Math.cos(n),r=Math.sin(n);return{x:(t.x*s+e.x*r)*pi.RADIUS,y:(t.y*s+e.y*r)*pi.RADIUS,z:(t.z*s+e.z*r)*pi.RADIUS}}basisAround(t){const e=Math.abs(t.y)<.9?{x:0,y:1,z:0}:{x:1,y:0,z:0},i=this.normalise(this.cross(t,e));return[i,this.normalise(this.cross(t,i))]}subtract(t,e){return{x:t.x-e.x,y:t.y-e.y,z:t.z-e.z}}cross(t,e){return{x:t.y*e.z-t.z*e.y,y:t.z*e.x-t.x*e.z,z:t.x*e.y-t.y*e.x}}normalise(t){const e=Math.hypot(t.x,t.y,t.z)||1;return{x:t.x/e,y:t.y/e,z:t.z/e}}dispose(){this.object.geometry.dispose(),this.object.material.dispose()}}const Lh=Math.PI/180;function Ye(a,t,e,i,n=!1){const s=n?new gn({color:new st(...e)}):new Er({color:new st(...e)}),r=new Dt(t,s);return r.position.y=i,r.userData={emissive:n},r.castShadow=!n,r.receiveShadow=!n,a.add(r),r}const Nh=.25,Uw=.002,Fw=100,kw=1500,zw=.25,Bw=1e3,Hw=.15;function Gw(a){const t=/^#([0-9a-f]{6})$/i.exec(a);if(!t)return[1,1,1];const e=parseInt(t[1],16);return[(e>>16&255)/255,(e>>8&255)/255,(e&255)/255]}const Vw=[.32,.32,.3],u1=[1,.85,.5],Ww=[.25,.25,.25],d1=[1,.97,.85],Xw=[.55,.68,.72],Xn=.03,qn=.05,f1={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 Oi(a,t){return a?.[t]}function Yn(a,t,e,i,n,s,r,o){if(o===void 0)return;const c=new Er({color:new st(...Xw),transparent:!0,opacity:o/100}),l=new Dt(new an(t,e,i),c);l.position.set(n,s,r),a.add(l)}const un=.05,Oh=[.6,.58,.53],Up=[.5,.5,.48];function rr(a,t,e,i,n,s,r,o){const c=new Er({color:new st(...o),side:Ue}),l=new Dt(new an(t,e,i),c);l.position.set(n,s,r),a.add(l)}function qw(a,t,e,i,n,s,r,o,c){const l=(i-s)/2,h=(p,v,m,g)=>{p<=0||(t?rr(a,p,v,un,m,o+g,r,c):rr(a,un,v,p,r,o+g,m,c))};h(e,l,0,i/2-l/2),h(e,l,0,-(i/2-l/2));const u=[...n].sort((p,v)=>p.center-v.center);let d=-e/2;for(const p of u){const m=p.center-p.main/2-d;h(m,s,d+m/2,0),d=p.center+p.main/2}const f=e/2-d;h(f,s,d+f/2,0)}function p1(a,t,e,i,n,s,r,o,c,l){const h=(i+n)/2,u=n-i,d=(f,p,v,m)=>{f.length===0?p?rr(a,v,u,un,0,h,m,Oh):rr(a,un,u,v,m,h,0,Oh):qw(a,p,v,u,f,s,m,h,Oh)};d(r,!0,t*2,-e+un),d(o,!0,t*2,e-un),d(c,!1,e*2,-t+un),d(l,!1,e*2,t-un),rr(a,t*2,un,e*2,0,i+un,0,Up),rr(a,t*2,un,e*2,0,n-un,0,Up)}function Ed(a,t,e,i){switch(a){case"front":return{x:0,z:-(e-i)};case"behind":return{x:0,z:e-i};case"left":return{x:-(t-i),z:0};case"right":return{x:t-i,z:0};case"front-left":return{x:-(t-i),z:-Kn};case"front-right":return{x:t-i,z:-Kn};case"behind-left":return{x:-(t-i),z:Kn};case"behind-right":return{x:t-i,z:Kn}}}function m1(a,t,e,i,n,s,r){const o=Rd();o.scale.setScalar(i),o.rotation.y=f1[t];const{x:c,z:l}=Ed(t,n,s,r);o.position.set(c,e,l),a.add(o)}const Ad=6,Td=6,ks=3,qr=1.4,Yr=ks*.5,g1=1.2,v1=.35,Yw=.75,Kw=1.6;function Fp(a,t,e,i){const n=new De,s=Math.max(1,a+1),r=s*ks;Ye(n,new an(Ad,r,Td),[.55,.54,.5],r/2);const o=Ad/2,c=Td/2;for(let l=0;l<s;l++){const h=l*ks+ks/2;Yn(n,qr,Yr,qn,0,h,-c-Xn,Oi(t,"front")),Yn(n,qr,Yr,qn,0,h,c+Xn,Oi(t,"behind")),Yn(n,qn,Yr,qr,-o-Xn,h,0,Oi(t,"left")),Yn(n,qn,Yr,qr,o+Xn,h,0,Oi(t,"right"))}if(e){const l=Math.min(Math.max(i??0,0),s-1);m1(n,e,l*ks,.72,o,c,g1);const h=u=>Oi(t,u)!==void 0?[{main:qr,center:0}]:[];p1(n,o,c,l*ks,(l+1)*ks,Yr,h("front"),h("behind"),h("left"),h("right"))}return n}function kp(){const a=new De,t=[[0,0,.55,.5],[.4,.1,.35,.4],[-.35,-.2,.4,.38],[.1,-.4,.35,.36],[-.15,.4,.3,.34]];for(const[e,i,n,s]of t){const r=new Qe(n,10,7);r.scale(1,.85,1),r.translate(e,0,i),Ye(a,r,[.26,.28,.17],s)}return a}function zp(){const a=new De;return Ye(a,new es(.15,.22,2,8),[.32,.22,.14],1),Ye(a,new br(1.4,3,8),[.16,.32,.14],3.5),a}const Bp=.275,$w=.35,Zw=.9,Jw=34,jw=8,Qw=1.4;function Hp(){const a=new De,t=new Qe(Bp,7,3,0,Math.PI*2,0,Math.PI/2);t.scale(1,$w/Bp,1);const e=vi.repeatOnGrid(t,Jw,Zw,jw,Qw),i=Ye(a,e,[.26,.28,.22],0);return i.castShadow=!0,i.userData.cropBasePositions=e.getAttribute("position").array.slice(),i.userData.cropVerticesPerClump=t.getAttribute("position").count,t.dispose(),a}function Gp(){const a=new De,t=new Qe(1,7,3,0,Math.PI*2,0,Math.PI/2);return Ye(a,t,[.38,.36,.32],0),a}function Vp(a){const t=new De;return Ye(t,new es(.05,.08,5,8),[.28,.28,.3],2.5),Ye(t,new Qe(.25,12,8),a?u1:Vw,5.1,!0),t}const tb=[.08,.08,.08],Os=.8,tr=1,Bn=1.7,Uh=.6,sa=.4,Tc=1.2,Ja=.7,Kn=.5,eb=Bn;function Wp(a,t,e){const i=new De;Ye(i,new an(1.8,1.4,4.2),[.45,.14,.14],.7),Ye(i,new an(Os*2,Uh,tr*2),[.4,.12,.12],Bn);for(const s of[-1.4,1.4])for(const r of[-.95,.95]){const o=Ye(i,new es(.4,.4,.3,12),tb,.4);o.rotation.z=Math.PI/2,o.position.x=r,o.position.z=s}const n=a?d1:Ww;for(const s of[-.7,.7])Ye(i,new Qe(.15,8,6),n,.7,!0).position.set(s,.7,-2.1);if(Yn(i,Tc,sa,qn,0,Bn,-tr-Xn,Oi(t,"front")),Yn(i,Tc,sa,qn,0,Bn,tr+Xn,Oi(t,"behind")),Yn(i,qn,sa,Ja,-Os-Xn,Bn,-Kn,Oi(t,"front-left")),Yn(i,qn,sa,Ja,-Os-Xn,Bn,Kn,Oi(t,"behind-left")),Yn(i,qn,sa,Ja,Os+Xn,Bn,-Kn,Oi(t,"front-right")),Yn(i,qn,sa,Ja,Os+Xn,Bn,Kn,Oi(t,"behind-right")),e){m1(i,e,Yw,.5,Os,tr,v1);const s=(c,l)=>{const h=[];return Oi(t,c)!==void 0&&h.push({main:Ja,center:-Kn}),Oi(t,l)!==void 0&&h.push({main:Ja,center:Kn}),h},r=Oi(t,"front")!==void 0?[{main:Tc,center:0}]:[],o=Oi(t,"behind")!==void 0?[{main:Tc,center:0}]:[];p1(i,Os,tr,Bn-Uh/2,Bn+Uh/2,sa,r,o,s("front-left","behind-left"),s("front-right","behind-right"))}return i}const Xp=new Map;function qp(a,t){if(!a)return;const e=[[a.lengthM,t.lengthM],[a.heightM,t.heightM],[a.widthM,t.widthM]];for(const[i,n]of e)if(i!==void 0&&n>1e-6)return i/n}function Fh(a,t){return t>1e-6?a/t:1}const M1=[.95,.9,.82],Yp=[.72,.74,.78];function Kp(){const a=new De;Ye(a,new es(.25,.3,1.5,10),Yp,.75),Ye(a,new Qe(.26,10,8),Yp,1.74);const t=Ye(a,new br(.07,.16,8),M1,1.74);return t.rotation.x=-Math.PI/2,t.position.z=-.22,a}function Rd(){const a=new De;Ye(a,new es(.25,.3,1.5,10),[.3,.3,.35],.75),Ye(a,new Qe(.22,10,8),[.62,.52,.46],1.72);const t=Ye(a,new br(.07,.16,8),M1,1.72);return t.rotation.x=-Math.PI/2,t.position.z=-.2,a}const ib=17,$p=18.5,kh=[.16,.16,.18];function Zp(){const a=new De,t=Ye(a,new es(1.8,1.8,$p*2,10),kh,0);t.rotation.x=Math.PI/2,Ye(a,new an(ib*2,.5,4.5),kh,0);const e=Ye(a,new an(.4,5.5,4),kh,3);return e.position.z=-$p+2,a}class vi{static groundUnderFootprint(t,e,i,n,s,r=0){const o=vi.sizeOf(t);if(r>o.heightM)return s(e,i);const c=(n??0)*Math.PI/180,l=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));let u=-1/0;for(let d=0;d<l;d++){const f=(d/(l-1)-.5)*o.lengthM;for(let p=0;p<h;p++){const v=(p/(h-1)-.5)*o.widthM,m=e+Math.sin(c)*f+Math.cos(c)*v,g=i-Math.cos(c)*f+Math.sin(c)*v;u=Math.max(u,s(m,g))}}return Number.isFinite(u)?u:s(e,i)}static occupantView(t){const e=t.witnessSide;if(!e)throw new Error("occupantView requires object.witnessSide to be set");const{x:i,z:n}=t.kind==="vehicle"?Ed(e,Os,tr,v1):Ed(e,Ad/2,Td/2,g1),s=t.kind==="vehicle"?eb:(t.occupiedFloor??0)*ks+Kw,r=(t.headingDeg??0)-f1[e]/Lh,o=this.scaleFor(t);return{x:i*o.x,z:n*o.z,eyeY:s*o.y,headingDeg:r}}static BODY_NAME="decor-body";static bodyOf(t){return t.getObjectByName(vi.BODY_NAME)??t}static repeatOnGrid(t,e,i,n,s){const r=t.getAttribute("position"),o=t.getAttribute("normal"),c=t.getIndex();if(!c)throw new Error("repeatOnGrid needs an indexed geometry");const l=r.count,h=e*n,u=new Float32Array(l*h*3),d=new Float32Array(l*h*3),f=new Uint32Array(c.count*h),p=-((e-1)*i)/2,v=-((n-1)*s)/2;let m=0;for(let _=0;_<n;_++)for(let w=0;w<e;w++,m++){const M=v+_*s,S=p+w*i;for(let b=0;b<l;b++){const T=(m*l+b)*3;u[T]=r.getX(b)+M,u[T+1]=r.getY(b),u[T+2]=r.getZ(b)+S,d[T]=o.getX(b),d[T+1]=o.getY(b),d[T+2]=o.getZ(b)}for(let b=0;b<c.count;b++)f[m*c.count+b]=c.getX(b)+m*l}const g=new ue;return g.setAttribute("position",new _e(u,3)),g.setAttribute("normal",new _e(d,3)),g.setIndex(new Kd(f,1)),g}static fitCropToGround(t,e){t.updateMatrixWorld(!0);const i=new D;t.traverse(n=>{const s=n,r=s.userData.cropBasePositions,o=s.userData.cropVerticesPerClump;if(!s.isMesh||!r||!o)return;const c=s.geometry.getAttribute("position"),l=new Zt().copy(s.matrixWorld).invert();for(let h=0;h<c.count;h+=o){i.set(r[h*3],0,r[h*3+2]).applyMatrix4(s.matrixWorld),i.y=e(i.x,i.z),i.applyMatrix4(l);for(let u=h;u<h+o;u++)c.setY(u,r[u*3+1]+i.y)}c.needsUpdate=!0,s.geometry.computeBoundingBox(),s.geometry.computeBoundingSphere()})}static paint(t,e){t.traverse(i=>{const n=i,s=n.userData;if(!n.isMesh||s?.emissive)return;const r=n.material;r?.color&&r.color.set(e)})}static build(t,e){const i=t.kind==="building"?Fp(t.floors??X0,t.windows,t.witnessSide,t.occupiedFloor):t.kind==="tree"?zp():t.kind==="shrub"?kp():t.kind==="crop"?Hp():t.kind==="mound"?Gp():t.kind==="streetlight"?Vp(e):t.kind==="vehicle"?Wp(e,t.windows,t.witnessSide):t.kind==="aircraft"?Zp():t.kind==="entity"?Kp():Rd();t.color&&this.paint(i,t.color);const n=this.scaleFor(t),s=new De;return i.name=vi.BODY_NAME,i.scale.copy(n),s.add(i),t.headingDeg!==void 0&&(s.rotation.y=-t.headingDeg*Lh),this.addLights(s,t.lights),s}static scaleFor(t){const e=t.sizeM;if(!e)return new D(1,1,1);const i=this.naturalSize(t.kind,t.floors);return new D(e.widthM===void 0?1:Fh(e.widthM,i.widthM),e.heightM===void 0?1:Fh(e.heightM,i.heightM),e.lengthM===void 0?1:Fh(e.lengthM,i.lengthM))}static naturalSize(t,e){const i=t==="building"?Math.max(1,(e??X0)+1):0,n=`${t}:${i}`,s=Xp.get(n);if(s)return s;const r=t==="building"?Fp(i-1,void 0,void 0,void 0):t==="tree"?zp():t==="shrub"?kp():t==="crop"?Hp():t==="mound"?Gp():t==="streetlight"?Vp(!1):t==="vehicle"?Wp(!1,void 0,void 0):t==="aircraft"?Zp():t==="entity"?Kp():Rd(),o=new Mn().setFromObject(r),c={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),Xp.set(n,c),c}static usesModel(t){return t.model!==void 0&&!(t.witnessSide!==void 0&&zm(t.kind))}static applyModel(t,e,i,n={}){const s=this.bodyOf(t),r=new De;r.name=vi.BODY_NAME,i.rotation.y=-(n.headingOffsetDeg??0)*Lh,i.updateMatrixWorld(!0);const o=new Mn().setFromObject(i),c={lengthM:o.max.z-o.min.z,heightM:o.max.y-o.min.y,widthM:o.max.x-o.min.x},l=qp(e.sizeM,c)??qp(n.depictedSizeM,c)??1;i.scale.multiplyScalar(l);const h=o.getCenter(new D).multiplyScalar(l);i.position.x-=h.x,i.position.z-=h.z,i.position.y-=e.kind==="aircraft"?h.y:o.min.y*l,i.traverse(u=>{u instanceof Dt&&(u.castShadow=!0,u.receiveShadow=!0)}),r.add(i),s.parent?(s.parent.add(r),s.removeFromParent()):t.add(r),this.dispose(s)}static sizeOf(t){const e=this.naturalSize(t.kind,t.floors);return{widthM:t.sizeM?.widthM??e.widthM,lengthM:t.sizeM?.lengthM??e.lengthM,heightM:t.sizeM?.heightM??e.heightM}}static addLights(t,e){for(const i of e??[]){const n=Gw(i.color),s=Ye(t,new Qe(Nh,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(t,e,i,n,s=0,r=1){if(!e||e.length===0)return;const o=new Map(e.map(u=>[u.id,u])),c=Math.max(1,n*Uw/Nh),l=Nh*c,h=r/(Math.PI*l*l);for(const u of t.children){if(!(u instanceof Dt))continue;const d=u.userData.lightId;if(!d)continue;const f=o.get(d);if(!f)continue;const p=s>0?Bm(f,i,i+s):m2(f,i)?1:0;u.visible=p>0;const v=u.material,m=u.userData.lightColor;if(m){const g=p*Fw*(f.intensity??1)*h;v.color.setRGB(m[0]*g,m[1]*g,m[2]*g)}u.scale.setScalar(c)}}static setLit(t,e,i,n=1){const[s,r,o]=e==="streetlight"?[kw,zw,u1]:[Bw,Hw,d1],c=i?s*n/(Math.PI*r*r):0,l=[o[0]*c,o[1]*c,o[2]*c];t.traverse(h=>{const u=h.userData;!(h instanceof Dt)||!u.emissive||u.lightId||h.material.color.setRGB(...l)})}static dispose(t){t.traverse(e=>{if(!(e instanceof Dt))return;e.geometry.dispose();const i=e.material;for(const n of Array.isArray(i)?i:[i])n.dispose()})}}const zh="https://ufoathome.org/models/index.json";class nb{attribution="3D models re-hosted by UFO@home, each under its own author's licence";fetchImpl;indexUrls;loading;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??sb()}async entries(t){const e=await this.load();return t?e.filter(i=>i.kind===t):e}async entry(t){return(await this.load()).find(e=>e.id===t)}load(){return this.loading??=this.fetchFirstAvailable(),this.loading}async fetchFirstAvailable(){for(const t of this.indexUrls){const e=await this.fetchIndex(t);if(e)return e}return[]}async fetchIndex(t){try{const e=await this.fetchImpl(t);if(!e.ok)return;const i=await e.json();return Array.isArray(i?.models)?i.models.map(({file:n,...s})=>({...s,url:new URL(n,t).href})):void 0}catch{return}}}function sb(){const a=`?v=${encodeURIComponent("0.65.3")}`,t=typeof location>"u"?void 0:new URL("/models/index.json",location.href).href;return(t&&t!==zh?[t,zh]:[zh]).map(e=>e+a)}const ab=[{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 nb}];async function Jp(a){const{GLTFLoader:t}=await Kc(async()=>{const{GLTFLoader:i}=await import("./GLTFLoader-BumifFuq.js");return{GLTFLoader:i}},[],import.meta.url),e=new t;return new Promise((i,n)=>{e.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 x1=["ellipsoid","sphere","disc","cylinder","cone","box","torus","figure"];class Qi{static MIN_ANGLE_RAD=.002;static FILL=(1-Math.exp(-4))/4;static MAX_SHARE=.3;mesh;constructor(t,e){this.mesh=new Dt(new ki(2,2),new ae({uniforms:{uColor:{value:new st(0,0,0)},uRadius:{value:1}},vertexShader:Qi.VERTEX,fragmentShader:Qi.FRAGMENT,transparent:!0,depthWrite:!1,blending:Ci,toneMapped:!1})),this.mesh.name=t,this.mesh.frustumCulled=!1,this.mesh.renderOrder=e,this.mesh.visible=!1}shine(t,e,i){this.mesh.visible=!0,this.mesh.position.set(t.x,t.y,t.z),this.mesh.material.uniforms.uRadius.value=e,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(t,e,i,n){const s=Math.max(t,n*Qi.MIN_ANGLE_RAD),r=Qi.FILL*Math.PI*s*s;return{radiusM:s,luminanceCdM2:i*Math.min(Qi.MAX_SHARE,e/r)}}static conserving(t){return Math.sqrt(t/(Qi.MAX_SHARE*Qi.FILL*Math.PI))}static VERTEX=`
|
|
6458
|
+
`,transparent:!0,blending:Ci,depthWrite:!1,side:Ue,fog:!1}),this.object=new Dt(new Qe(Ti.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(t){this.hostedByDeck=t,this.show(this.shown)}show(t){this.shown=t,this.object.visible=t&&!this.hostedByDeck,this.deckUniforms.uHaloShown.value=t?1:0}get awaitingFirstDisplay(){return this.tracing&&!this.everDisplayed}setUrgent(t){this.urgent=t}set onReady(t){this.onRepaint=t}update(t,e,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(t.x,t.y,t.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(e,r)}requestMap(t,e){if(!(!(Math.abs(t-this.mappedAltitudeDeg)<Ti.ALTITUDE_STEP_DEG)||!(Math.abs(e-this.mappedAlignment)<Ti.ALIGNMENT_STEP))){this.next=void 0;return}if(this.tracing){if(this.tracingFor(t,e)){this.next=void 0;return}if(!(!(Math.abs(t-this.pendingAltitudeDeg)<Ti.LEAP_ALTITUDE_DEG)||!(Math.abs(e-this.pendingAlignment)<Ti.LEAP_ALIGNMENT))){this.next={sourceAltitudeDeg:t,alignment:e};return}}this.next=void 0,this.pendingAltitudeDeg=t,this.pendingAlignment=e,this.sky.begin(t,e),this.tracing=!0,this.scheduleWork()}pendingAltitudeDeg=Number.NaN;pendingAlignment=Number.NaN;next;tracingFor(t,e){return this.tracing&&Math.abs(t-this.pendingAltitudeDeg)<Ti.ALTITUDE_STEP_DEG&&Math.abs(e-this.pendingAlignment)<Ti.ALIGNMENT_STEP}scheduleWork(){if(this.workHandle!==void 0)return;const t=()=>{if(this.workHandle=void 0,!this.tracing)return;const e=performance.now(),i=this.urgent?Ti.URGENT_BUDGET_MS:Ti.BUDGET_MS;do this.sky.trace(Ti.RAYS_PER_BATCH);while(this.sky.tracedRays<Ti.RAYS&&performance.now()-e<i);if(this.sky.tracedRays>=Ti.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(t)};this.workHandle=requestAnimationFrame(t)}stopWork(){this.workHandle!==void 0&&cancelAnimationFrame(this.workHandle),this.workHandle=void 0,this.tracing=!1,this.next=void 0}publish(){const e=this.sky.harvest().data;for(let i=0,n=0;n<e.length;i+=4,n+=3)this.texels[i]=Cn.toHalfFloat(e[n]),this.texels[i+1]=Cn.toHalfFloat(e[n+1]),this.texels[i+2]=Cn.toHalfFloat(e[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 pi{static MAX_CONCURRENT=24;static POINTS=8;static SEGMENTS=pi.POINTS-1;static ACROSS=3;static VERTICES_PER_SEGMENT=(pi.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 t=pi.MAX_CONCURRENT*pi.SEGMENTS*pi.VERTICES_PER_SEGMENT;this.positions=new Float32Array(t*3),this.colors=new Float32Array(t*3);const e=new ue;e.setAttribute("position",new te(this.positions,3)),e.setAttribute("color",new te(this.colors,3)),e.setDrawRange(0,0),this.object=new Dt(e,new gn({vertexColors:!0,transparent:!0,blending:Ci,depthWrite:!1,fog:!1,side:en})),this.object.frustumCulled=!1}get schedule(){return this.meteors}setShower(t,e,i){this.meteors=t,this.radiantAltitudeDeg=e,this.radiantAzimuthDeg=i}update(t){const e=this.object.geometry;if(this.meteors.length===0){e.setDrawRange(0,0);return}const i=xa.aliveAt(this.meteors,t).slice(0,pi.MAX_CONCURRENT);let n=0;for(const{meteor:s,progress:r}of i){const o=this.radiantOf(s);if(!o)continue;const c=ni(o.altitudeDeg,o.azimuthDeg,1),[l,h]=this.basisAround(c),u=s.fromRadiantDeg+r*s.lengthDeg,d=Math.max(s.fromRadiantDeg,u-s.lengthDeg*.6),f=Math.min(1,(1-r)*2.5),p=this.turn(l,h,s.bearingDeg),v=(.15+.85*s.brightness)*f,m=w=>v*w**1.6,g=w=>this.onSphere(c,p,d+(u-d)*w),_=w=>pi.RADIUS*((pi.MIN_HALF_WIDTH_DEG+pi.BRIGHT_HALF_WIDTH_DEG*s.brightness*w)*Math.PI/180);for(let w=1;w<pi.POINTS;w++){const M=(w-1)/pi.SEGMENTS,S=w/pi.SEGMENTS;n=this.pushRibbon(n,g(M),g(S),_(M),_(S),m(M),m(S))}}e.setDrawRange(0,n),e.getAttribute("position").needsUpdate=!0,e.getAttribute("color").needsUpdate=!0}midpointOf(t){const e=this.radiantOf(t);if(!e)return;const i=ni(e.altitudeDeg,e.azimuthDeg,1),[n,s]=this.basisAround(i),r=this.turn(n,s,t.bearingDeg),o=this.onSphere(i,r,t.fromRadiantDeg+t.lengthDeg/2),c=Math.hypot(o.x,o.y,o.z)||1;return{altitudeDeg:Math.asin(o.y/c)*180/Math.PI,azimuthDeg:(Math.atan2(o.x,-o.z)*180/Math.PI+360)%360}}radiantOf(t){return t.radiant?t.radiant:this.radiantAltitudeDeg>0?{altitudeDeg:this.radiantAltitudeDeg,azimuthDeg:this.radiantAzimuthDeg}:void 0}pushRibbon(t,e,i,n,s,r,o){const c=this.normalise(this.cross(this.normalise(e),this.normalise(this.subtract(i,e))));for(let l=0;l<pi.ACROSS-1;l++){const h=l-1,u=l,d=this.across(e,c,n,h),f=this.across(i,c,s,h),p=this.across(e,c,n,u),v=this.across(i,c,s,u),m=(g,_)=>g===0?_:0;t=this.push(t,d,m(h,r)),t=this.push(t,f,m(h,o)),t=this.push(t,p,m(u,r)),t=this.push(t,f,m(h,o)),t=this.push(t,v,m(u,o)),t=this.push(t,p,m(u,r))}return t}across(t,e,i,n){return{x:t.x+e.x*i*n,y:t.y+e.y*i*n,z:t.z+e.z*i*n}}push(t,e,i){const n=t*3;this.positions[n]=e.x,this.positions[n+1]=e.y,this.positions[n+2]=e.z;const s=Et.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,t+1}turn(t,e,i){const n=i*Math.PI/180,s=Math.cos(n),r=Math.sin(n);return{x:t.x*s+e.x*r,y:t.y*s+e.y*r,z:t.z*s+e.z*r}}onSphere(t,e,i){const n=i*Math.PI/180,s=Math.cos(n),r=Math.sin(n);return{x:(t.x*s+e.x*r)*pi.RADIUS,y:(t.y*s+e.y*r)*pi.RADIUS,z:(t.z*s+e.z*r)*pi.RADIUS}}basisAround(t){const e=Math.abs(t.y)<.9?{x:0,y:1,z:0}:{x:1,y:0,z:0},i=this.normalise(this.cross(t,e));return[i,this.normalise(this.cross(t,i))]}subtract(t,e){return{x:t.x-e.x,y:t.y-e.y,z:t.z-e.z}}cross(t,e){return{x:t.y*e.z-t.z*e.y,y:t.z*e.x-t.x*e.z,z:t.x*e.y-t.y*e.x}}normalise(t){const e=Math.hypot(t.x,t.y,t.z)||1;return{x:t.x/e,y:t.y/e,z:t.z/e}}dispose(){this.object.geometry.dispose(),this.object.material.dispose()}}const Lh=Math.PI/180;function Ye(a,t,e,i,n=!1){const s=n?new gn({color:new st(...e)}):new Er({color:new st(...e)}),r=new Dt(t,s);return r.position.y=i,r.userData={emissive:n},r.castShadow=!n,r.receiveShadow=!n,a.add(r),r}const Nh=.25,Uw=.002,Fw=100,kw=1500,zw=.25,Bw=1e3,Hw=.15;function Gw(a){const t=/^#([0-9a-f]{6})$/i.exec(a);if(!t)return[1,1,1];const e=parseInt(t[1],16);return[(e>>16&255)/255,(e>>8&255)/255,(e&255)/255]}const Vw=[.32,.32,.3],u1=[1,.85,.5],Ww=[.25,.25,.25],d1=[1,.97,.85],Xw=[.55,.68,.72],Xn=.03,qn=.05,f1={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 Oi(a,t){return a?.[t]}function Yn(a,t,e,i,n,s,r,o){if(o===void 0)return;const c=new Er({color:new st(...Xw),transparent:!0,opacity:o/100}),l=new Dt(new an(t,e,i),c);l.position.set(n,s,r),a.add(l)}const un=.05,Oh=[.6,.58,.53],Up=[.5,.5,.48];function rr(a,t,e,i,n,s,r,o){const c=new Er({color:new st(...o),side:Ue}),l=new Dt(new an(t,e,i),c);l.position.set(n,s,r),a.add(l)}function qw(a,t,e,i,n,s,r,o,c){const l=(i-s)/2,h=(p,v,m,g)=>{p<=0||(t?rr(a,p,v,un,m,o+g,r,c):rr(a,un,v,p,r,o+g,m,c))};h(e,l,0,i/2-l/2),h(e,l,0,-(i/2-l/2));const u=[...n].sort((p,v)=>p.center-v.center);let d=-e/2;for(const p of u){const m=p.center-p.main/2-d;h(m,s,d+m/2,0),d=p.center+p.main/2}const f=e/2-d;h(f,s,d+f/2,0)}function p1(a,t,e,i,n,s,r,o,c,l){const h=(i+n)/2,u=n-i,d=(f,p,v,m)=>{f.length===0?p?rr(a,v,u,un,0,h,m,Oh):rr(a,un,u,v,m,h,0,Oh):qw(a,p,v,u,f,s,m,h,Oh)};d(r,!0,t*2,-e+un),d(o,!0,t*2,e-un),d(c,!1,e*2,-t+un),d(l,!1,e*2,t-un),rr(a,t*2,un,e*2,0,i+un,0,Up),rr(a,t*2,un,e*2,0,n-un,0,Up)}function Ed(a,t,e,i){switch(a){case"front":return{x:0,z:-(e-i)};case"behind":return{x:0,z:e-i};case"left":return{x:-(t-i),z:0};case"right":return{x:t-i,z:0};case"front-left":return{x:-(t-i),z:-Kn};case"front-right":return{x:t-i,z:-Kn};case"behind-left":return{x:-(t-i),z:Kn};case"behind-right":return{x:t-i,z:Kn}}}function m1(a,t,e,i,n,s,r){const o=Rd();o.scale.setScalar(i),o.rotation.y=f1[t];const{x:c,z:l}=Ed(t,n,s,r);o.position.set(c,e,l),a.add(o)}const Ad=6,Td=6,ks=3,qr=1.4,Yr=ks*.5,g1=1.2,v1=.35,Yw=.75,Kw=1.6;function Fp(a,t,e,i){const n=new De,s=Math.max(1,a+1),r=s*ks;Ye(n,new an(Ad,r,Td),[.55,.54,.5],r/2);const o=Ad/2,c=Td/2;for(let l=0;l<s;l++){const h=l*ks+ks/2;Yn(n,qr,Yr,qn,0,h,-c-Xn,Oi(t,"front")),Yn(n,qr,Yr,qn,0,h,c+Xn,Oi(t,"behind")),Yn(n,qn,Yr,qr,-o-Xn,h,0,Oi(t,"left")),Yn(n,qn,Yr,qr,o+Xn,h,0,Oi(t,"right"))}if(e){const l=Math.min(Math.max(i??0,0),s-1);m1(n,e,l*ks,.72,o,c,g1);const h=u=>Oi(t,u)!==void 0?[{main:qr,center:0}]:[];p1(n,o,c,l*ks,(l+1)*ks,Yr,h("front"),h("behind"),h("left"),h("right"))}return n}function kp(){const a=new De,t=[[0,0,.55,.5],[.4,.1,.35,.4],[-.35,-.2,.4,.38],[.1,-.4,.35,.36],[-.15,.4,.3,.34]];for(const[e,i,n,s]of t){const r=new Qe(n,10,7);r.scale(1,.85,1),r.translate(e,0,i),Ye(a,r,[.26,.28,.17],s)}return a}function zp(){const a=new De;return Ye(a,new es(.15,.22,2,8),[.32,.22,.14],1),Ye(a,new br(1.4,3,8),[.16,.32,.14],3.5),a}const Bp=.275,$w=.35,Zw=.9,Jw=34,jw=8,Qw=1.4;function Hp(){const a=new De,t=new Qe(Bp,7,3,0,Math.PI*2,0,Math.PI/2);t.scale(1,$w/Bp,1);const e=vi.repeatOnGrid(t,Jw,Zw,jw,Qw),i=Ye(a,e,[.26,.28,.22],0);return i.castShadow=!0,i.userData.cropBasePositions=e.getAttribute("position").array.slice(),i.userData.cropVerticesPerClump=t.getAttribute("position").count,t.dispose(),a}function Gp(){const a=new De,t=new Qe(1,7,3,0,Math.PI*2,0,Math.PI/2);return Ye(a,t,[.38,.36,.32],0),a}function Vp(a){const t=new De;return Ye(t,new es(.05,.08,5,8),[.28,.28,.3],2.5),Ye(t,new Qe(.25,12,8),a?u1:Vw,5.1,!0),t}const tb=[.08,.08,.08],Os=.8,tr=1,Bn=1.7,Uh=.6,sa=.4,Tc=1.2,Ja=.7,Kn=.5,eb=Bn;function Wp(a,t,e){const i=new De;Ye(i,new an(1.8,1.4,4.2),[.45,.14,.14],.7),Ye(i,new an(Os*2,Uh,tr*2),[.4,.12,.12],Bn);for(const s of[-1.4,1.4])for(const r of[-.95,.95]){const o=Ye(i,new es(.4,.4,.3,12),tb,.4);o.rotation.z=Math.PI/2,o.position.x=r,o.position.z=s}const n=a?d1:Ww;for(const s of[-.7,.7])Ye(i,new Qe(.15,8,6),n,.7,!0).position.set(s,.7,-2.1);if(Yn(i,Tc,sa,qn,0,Bn,-tr-Xn,Oi(t,"front")),Yn(i,Tc,sa,qn,0,Bn,tr+Xn,Oi(t,"behind")),Yn(i,qn,sa,Ja,-Os-Xn,Bn,-Kn,Oi(t,"front-left")),Yn(i,qn,sa,Ja,-Os-Xn,Bn,Kn,Oi(t,"behind-left")),Yn(i,qn,sa,Ja,Os+Xn,Bn,-Kn,Oi(t,"front-right")),Yn(i,qn,sa,Ja,Os+Xn,Bn,Kn,Oi(t,"behind-right")),e){m1(i,e,Yw,.5,Os,tr,v1);const s=(c,l)=>{const h=[];return Oi(t,c)!==void 0&&h.push({main:Ja,center:-Kn}),Oi(t,l)!==void 0&&h.push({main:Ja,center:Kn}),h},r=Oi(t,"front")!==void 0?[{main:Tc,center:0}]:[],o=Oi(t,"behind")!==void 0?[{main:Tc,center:0}]:[];p1(i,Os,tr,Bn-Uh/2,Bn+Uh/2,sa,r,o,s("front-left","behind-left"),s("front-right","behind-right"))}return i}const Xp=new Map;function qp(a,t){if(!a)return;const e=[[a.lengthM,t.lengthM],[a.heightM,t.heightM],[a.widthM,t.widthM]];for(const[i,n]of e)if(i!==void 0&&n>1e-6)return i/n}function Fh(a,t){return t>1e-6?a/t:1}const M1=[.95,.9,.82],Yp=[.72,.74,.78];function Kp(){const a=new De;Ye(a,new es(.25,.3,1.5,10),Yp,.75),Ye(a,new Qe(.26,10,8),Yp,1.74);const t=Ye(a,new br(.07,.16,8),M1,1.74);return t.rotation.x=-Math.PI/2,t.position.z=-.22,a}function Rd(){const a=new De;Ye(a,new es(.25,.3,1.5,10),[.3,.3,.35],.75),Ye(a,new Qe(.22,10,8),[.62,.52,.46],1.72);const t=Ye(a,new br(.07,.16,8),M1,1.72);return t.rotation.x=-Math.PI/2,t.position.z=-.2,a}const ib=17,$p=18.5,kh=[.16,.16,.18];function Zp(){const a=new De,t=Ye(a,new es(1.8,1.8,$p*2,10),kh,0);t.rotation.x=Math.PI/2,Ye(a,new an(ib*2,.5,4.5),kh,0);const e=Ye(a,new an(.4,5.5,4),kh,3);return e.position.z=-$p+2,a}class vi{static groundUnderFootprint(t,e,i,n,s,r=0){const o=vi.sizeOf(t);if(r>o.heightM)return s(e,i);const c=(n??0)*Math.PI/180,l=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));let u=-1/0;for(let d=0;d<l;d++){const f=(d/(l-1)-.5)*o.lengthM;for(let p=0;p<h;p++){const v=(p/(h-1)-.5)*o.widthM,m=e+Math.sin(c)*f+Math.cos(c)*v,g=i-Math.cos(c)*f+Math.sin(c)*v;u=Math.max(u,s(m,g))}}return Number.isFinite(u)?u:s(e,i)}static occupantView(t){const e=t.witnessSide;if(!e)throw new Error("occupantView requires object.witnessSide to be set");const{x:i,z:n}=t.kind==="vehicle"?Ed(e,Os,tr,v1):Ed(e,Ad/2,Td/2,g1),s=t.kind==="vehicle"?eb:(t.occupiedFloor??0)*ks+Kw,r=(t.headingDeg??0)-f1[e]/Lh,o=this.scaleFor(t);return{x:i*o.x,z:n*o.z,eyeY:s*o.y,headingDeg:r}}static BODY_NAME="decor-body";static bodyOf(t){return t.getObjectByName(vi.BODY_NAME)??t}static repeatOnGrid(t,e,i,n,s){const r=t.getAttribute("position"),o=t.getAttribute("normal"),c=t.getIndex();if(!c)throw new Error("repeatOnGrid needs an indexed geometry");const l=r.count,h=e*n,u=new Float32Array(l*h*3),d=new Float32Array(l*h*3),f=new Uint32Array(c.count*h),p=-((e-1)*i)/2,v=-((n-1)*s)/2;let m=0;for(let _=0;_<n;_++)for(let w=0;w<e;w++,m++){const M=v+_*s,S=p+w*i;for(let b=0;b<l;b++){const T=(m*l+b)*3;u[T]=r.getX(b)+M,u[T+1]=r.getY(b),u[T+2]=r.getZ(b)+S,d[T]=o.getX(b),d[T+1]=o.getY(b),d[T+2]=o.getZ(b)}for(let b=0;b<c.count;b++)f[m*c.count+b]=c.getX(b)+m*l}const g=new ue;return g.setAttribute("position",new _e(u,3)),g.setAttribute("normal",new _e(d,3)),g.setIndex(new Kd(f,1)),g}static fitCropToGround(t,e){t.updateMatrixWorld(!0);const i=new D;t.traverse(n=>{const s=n,r=s.userData.cropBasePositions,o=s.userData.cropVerticesPerClump;if(!s.isMesh||!r||!o)return;const c=s.geometry.getAttribute("position"),l=new Zt().copy(s.matrixWorld).invert();for(let h=0;h<c.count;h+=o){i.set(r[h*3],0,r[h*3+2]).applyMatrix4(s.matrixWorld),i.y=e(i.x,i.z),i.applyMatrix4(l);for(let u=h;u<h+o;u++)c.setY(u,r[u*3+1]+i.y)}c.needsUpdate=!0,s.geometry.computeBoundingBox(),s.geometry.computeBoundingSphere()})}static paint(t,e){t.traverse(i=>{const n=i,s=n.userData;if(!n.isMesh||s?.emissive)return;const r=n.material;r?.color&&r.color.set(e)})}static build(t,e){const i=t.kind==="building"?Fp(t.floors??X0,t.windows,t.witnessSide,t.occupiedFloor):t.kind==="tree"?zp():t.kind==="shrub"?kp():t.kind==="crop"?Hp():t.kind==="mound"?Gp():t.kind==="streetlight"?Vp(e):t.kind==="vehicle"?Wp(e,t.windows,t.witnessSide):t.kind==="aircraft"?Zp():t.kind==="entity"?Kp():Rd();t.color&&this.paint(i,t.color);const n=this.scaleFor(t),s=new De;return i.name=vi.BODY_NAME,i.scale.copy(n),s.add(i),t.headingDeg!==void 0&&(s.rotation.y=-t.headingDeg*Lh),this.addLights(s,t.lights),s}static scaleFor(t){const e=t.sizeM;if(!e)return new D(1,1,1);const i=this.naturalSize(t.kind,t.floors);return new D(e.widthM===void 0?1:Fh(e.widthM,i.widthM),e.heightM===void 0?1:Fh(e.heightM,i.heightM),e.lengthM===void 0?1:Fh(e.lengthM,i.lengthM))}static naturalSize(t,e){const i=t==="building"?Math.max(1,(e??X0)+1):0,n=`${t}:${i}`,s=Xp.get(n);if(s)return s;const r=t==="building"?Fp(i-1,void 0,void 0,void 0):t==="tree"?zp():t==="shrub"?kp():t==="crop"?Hp():t==="mound"?Gp():t==="streetlight"?Vp(!1):t==="vehicle"?Wp(!1,void 0,void 0):t==="aircraft"?Zp():t==="entity"?Kp():Rd(),o=new Mn().setFromObject(r),c={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),Xp.set(n,c),c}static usesModel(t){return t.model!==void 0&&!(t.witnessSide!==void 0&&zm(t.kind))}static applyModel(t,e,i,n={}){const s=this.bodyOf(t),r=new De;r.name=vi.BODY_NAME,i.rotation.y=-(n.headingOffsetDeg??0)*Lh,i.updateMatrixWorld(!0);const o=new Mn().setFromObject(i),c={lengthM:o.max.z-o.min.z,heightM:o.max.y-o.min.y,widthM:o.max.x-o.min.x},l=qp(e.sizeM,c)??qp(n.depictedSizeM,c)??1;i.scale.multiplyScalar(l);const h=o.getCenter(new D).multiplyScalar(l);i.position.x-=h.x,i.position.z-=h.z,i.position.y-=e.kind==="aircraft"?h.y:o.min.y*l,i.traverse(u=>{u instanceof Dt&&(u.castShadow=!0,u.receiveShadow=!0)}),r.add(i),s.parent?(s.parent.add(r),s.removeFromParent()):t.add(r),this.dispose(s)}static sizeOf(t){const e=this.naturalSize(t.kind,t.floors);return{widthM:t.sizeM?.widthM??e.widthM,lengthM:t.sizeM?.lengthM??e.lengthM,heightM:t.sizeM?.heightM??e.heightM}}static addLights(t,e){for(const i of e??[]){const n=Gw(i.color),s=Ye(t,new Qe(Nh,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(t,e,i,n,s=0,r=1){if(!e||e.length===0)return;const o=new Map(e.map(u=>[u.id,u])),c=Math.max(1,n*Uw/Nh),l=Nh*c,h=r/(Math.PI*l*l);for(const u of t.children){if(!(u instanceof Dt))continue;const d=u.userData.lightId;if(!d)continue;const f=o.get(d);if(!f)continue;const p=s>0?Bm(f,i,i+s):m2(f,i)?1:0;u.visible=p>0;const v=u.material,m=u.userData.lightColor;if(m){const g=p*Fw*(f.intensity??1)*h;v.color.setRGB(m[0]*g,m[1]*g,m[2]*g)}u.scale.setScalar(c)}}static setLit(t,e,i,n=1){const[s,r,o]=e==="streetlight"?[kw,zw,u1]:[Bw,Hw,d1],c=i?s*n/(Math.PI*r*r):0,l=[o[0]*c,o[1]*c,o[2]*c];t.traverse(h=>{const u=h.userData;!(h instanceof Dt)||!u.emissive||u.lightId||h.material.color.setRGB(...l)})}static dispose(t){t.traverse(e=>{if(!(e instanceof Dt))return;e.geometry.dispose();const i=e.material;for(const n of Array.isArray(i)?i:[i])n.dispose()})}}const zh="https://ufoathome.org/models/index.json";class nb{attribution="3D models re-hosted by UFO@home, each under its own author's licence";fetchImpl;indexUrls;loading;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??sb()}async entries(t){const e=await this.load();return t?e.filter(i=>i.kind===t):e}async entry(t){return(await this.load()).find(e=>e.id===t)}load(){return this.loading??=this.fetchFirstAvailable(),this.loading}async fetchFirstAvailable(){for(const t of this.indexUrls){const e=await this.fetchIndex(t);if(e)return e}return[]}async fetchIndex(t){try{const e=await this.fetchImpl(t);if(!e.ok)return;const i=await e.json();return Array.isArray(i?.models)?i.models.map(({file:n,...s})=>({...s,url:new URL(n,t).href})):void 0}catch{return}}}function sb(){const a=`?v=${encodeURIComponent("0.65.4")}`,t=typeof location>"u"?void 0:new URL("/models/index.json",location.href).href;return(t&&t!==zh?[t,zh]:[zh]).map(e=>e+a)}const ab=[{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 nb}];async function Jp(a){const{GLTFLoader:t}=await Kc(async()=>{const{GLTFLoader:i}=await import("./GLTFLoader-BumifFuq.js");return{GLTFLoader:i}},[],import.meta.url),e=new t;return new Promise((i,n)=>{e.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 x1=["ellipsoid","sphere","disc","cylinder","cone","box","torus","figure"];class Qi{static MIN_ANGLE_RAD=.002;static FILL=(1-Math.exp(-4))/4;static MAX_SHARE=.3;mesh;constructor(t,e){this.mesh=new Dt(new ki(2,2),new ae({uniforms:{uColor:{value:new st(0,0,0)},uRadius:{value:1}},vertexShader:Qi.VERTEX,fragmentShader:Qi.FRAGMENT,transparent:!0,depthWrite:!1,blending:Ci,toneMapped:!1})),this.mesh.name=t,this.mesh.frustumCulled=!1,this.mesh.renderOrder=e,this.mesh.visible=!1}shine(t,e,i){this.mesh.visible=!0,this.mesh.position.set(t.x,t.y,t.z),this.mesh.material.uniforms.uRadius.value=e,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(t,e,i,n){const s=Math.max(t,n*Qi.MIN_ANGLE_RAD),r=Qi.FILL*Math.PI*s*s;return{radiusM:s,luminanceCdM2:i*Math.min(Qi.MAX_SHARE,e/r)}}static conserving(t){return Math.sqrt(t/(Qi.MAX_SHARE*Qi.FILL*Math.PI))}static VERTEX=`
|
|
6458
6459
|
uniform float uRadius;
|
|
6459
6460
|
varying vec2 vOffset;
|
|
6460
6461
|
void main() {
|
|
@@ -6954,11 +6955,9 @@ cloudPoint = (modelMatrix * vec4(transformed, 1.0)).xyz - cameraPosition;`);let
|
|
|
6954
6955
|
gl_FragColor = vec4(relativeOf(light.xyz, light.w), 1.0);
|
|
6955
6956
|
#include <colorspace_fragment>
|
|
6956
6957
|
}
|
|
6957
|
-
`})}get supported(){return this.tables.supported}get ready(){return this.hasViews}get ambient(){return this.ready?this.ambientColours:void 0}setInstrument(t,e){const i=t?10**(.4*e):1;i===this.exposureScale&&this.seenByEye===!t||(this.exposureScale=i,this.seenByEye=!t,this.material.uniforms.uExposureScale.value=i,this.applyAdaptation(this.adaptingLuminance),this.onChange())}setConditions(t){this.tables.setMedium(new Ot(t)),this.tables.ready||(this.drawnKey="")}advance(t){!this.supported||this.tables.ready||this.tables.advance(t)&&this.state&&this.draw(this.state)}invalidate(){this.tables.invalidate(),this.drawnKey="",this.hasViews=!1}update(t){this.state=t,this.tables.ready?this.draw(t):this.hasViews||this.applyAdaptation(ii.predictedZenithLuminance(t))}dispose(){this.tables.dispose(),this.material.dispose()}draw(t){const e=[t.altitudeM.toFixed(0),t.sun.altitudeDeg.toFixed(3),t.moon.altitudeDeg.toFixed(3)].join(":"),i=this.material.uniforms;if(i.uSunAzimuth.value.copy(ii.azimuthVector(t.sun.azimuthDeg)),i.uMoonAzimuth.value.copy(ii.azimuthVector(t.moon.azimuthDeg)),i.uMoonScale.value=10**(-.4*(t.moon.magnitude-ii.SUN_MAGNITUDE)),i.uObserverRadius.value=Ot.GROUND_RADIUS_M+Math.max(t.altitudeM,2),e!==this.drawnKey){this.tables.renderSkyViews(t.altitudeM,t.sun.altitudeDeg,t.moon.altitudeDeg);const n=!this.hasViews;this.hasViews=!0,this.drawnKey=e,n&&!this.ambientColours&&this.adaptFromViews(this.tables.readSkyViewNow("sun"),this.tables.readSkyViewNow("moon"),t),this.readBack()}this.onChange()}async readBack(){if(this.reading){this.readAgain=!0;return}this.reading=!0;try{const[t,e]=await Promise.all([this.tables.readSkyView("sun"),this.tables.readSkyView("moon")]),i=this.state;i&&this.adaptFromViews(t,e,i)}finally{this.reading=!1}this.readAgain&&(this.readAgain=!1,this.readBack())}adaptToSurroundings(t){if(!(t>0)||!(this.clearAdaptation>0))return!1;const e=t/this.clearAdaptation;return Math.abs(Math.log(e/this.surroundingsFactor))<.05?!1:(this.surroundingsFactor=e,this.views&&this.state?this.adaptFromViews(this.views.sun,this.views.moon,this.state):this.applyAdaptation(this.clearAdaptation*e),!0)}resetSurroundings(){this.surroundingsFactor=1}surroundingsFactor=1;clearAdaptation=0;views;adaptFromViews(t,e,i){this.views={sun:t,moon:e};const n=10**(-.4*(i.moon.magnitude-ii.SUN_MAGNITUDE)),s=ii.airglowXyzs(),r=(m,g,_=!0)=>{const w=(90-m)*Math.PI/180,M=Vt.skyViewUv(i.altitudeM,w,ii.azimuthBetween(g,i.sun.azimuthDeg)),S=Vt.skyViewUv(i.altitudeM,w,ii.azimuthBetween(g,i.moon.azimuthDeg)),b=ii.bilinear(t,M.u,M.v),T=ii.bilinear(e,S.u,S.v),x=_&&m>0?ii.airglowFactor(m):0;return[0,1,2,3].map(A=>b[A]+n*T[A]+s[A]*x)};let o=0,c=0;for(let m=5;m<90;m+=10){const g=Math.cos(m*Math.PI/180);for(let _=0;_<360;_+=30)o+=g*Math.log(Math.max(r(m,_)[1],1e-9)),c+=g}this.clearAdaptation=Math.exp(o/c),this.applyAdaptation(this.clearAdaptation*this.surroundingsFactor);const l=([m,g,_,w])=>{const M=this.exposureScale,S=this.adaptingLuminance*M;return Et.relativeOf([m*M,g*M,_*M],w*M,S,0)},h=(m,g,_=!0)=>l(r(m,g,_)),u=[0,0,0,0],d=5*Math.PI/180,f=20*Math.PI/180;for(let m=2.5;m<90;m+=5){const g=m*Math.PI/180,_=Math.sin(g)*Math.cos(g)*d*f;for(let w=10;w<360;w+=20){const M=r(m,w);for(let S=0;S<4;S++)u[S]+=M[S]*_}}const p=[0,0,0],v=[0,0,0];for(let m=0;m<360;m+=20){const g=h(2,m),_=h(2,m,!1);for(let w=0;w<3;w++)p[w]+=g[w]/18,v[w]+=_[w]/18}this.ambientColours={zenith:h(90,0),horizon:p,airlight:v,skyIrradiance:l(u),scale:this.relativeScale},this.onChange()}relativeOfLuminance(t,e){const[i,n,s]=t,r=.2126*i+.7152*n+.0722*s,o=r>0?e/r:0,c=[o*(.4124*i+.3576*n+.1805*s),e,o*(.0193*i+.1192*n+.9505*s)],l=this.exposureScale,h=this.adaptingLuminance*l;return Et.relativeOf([c[0]*l,c[1]*l,c[2]*l],c[1]*l,h,0)}get rodShare(){const t=this.adaptingLuminance*this.exposureScale;return this.seenByEye?Et.rodShare(t):0}get relativeScale(){const t=this.adaptingLuminance*this.exposureScale;return this.exposureScale/Et.semiSaturation(t)}applyAdaptation(t){this.adaptingLuminance=t;const e=t*this.exposureScale;this.material.uniforms.uRodShare.value=0,this.material.uniforms.uInverseSemiSaturation.value=1/Et.semiSaturation(e)}static predictedZenithLuminance(t){const e=n=>90-n.altitudeDeg,i=Yt.magPerArcsec2({altitudeDeg:t.sun.altitudeDeg,separationDeg:e(t.sun)},{phaseAngleDeg:t.moon.phaseAngleDeg,altitudeDeg:t.moon.altitudeDeg,separationDeg:e(t.moon)},90);return Yt.toNanolamberts(i)*ii.CANDELAS_PER_NANOLAMBERT}static CANDELAS_PER_NANOLAMBERT=1e-5/Math.PI;static airglowXyzs(){const t=Yt.toNanolamberts(Yt.AIRGLOW_MAG_PER_ARCSEC2)*ii.CANDELAS_PER_NANOLAMBERT;return[t*.3127/.329,t,t*(1-.3127-.329)/.329,t]}static airglowFactor(t){const e=Math.cos(t*Math.PI/180)**2,i=Ot.GROUND_RADIUS_M/(Ot.GROUND_RADIUS_M+ii.AIRGLOW_LAYER_ALTITUDE_M),n=1/Math.sqrt(Math.max(1-i*i*e,1e-4)),s=1/Math.sqrt(Math.max(1-.96*e,.001));return n*10**(-.4*Yt.EXTINCTION_PER_AIR_MASS*(s-1))}static azimuthVector(t){const e=t*Math.PI/180;return new Mt(Math.sin(e),-Math.cos(e))}static azimuthBetween(t,e){const i=Math.abs(t-e)%360;return(i>180?360-i:i)*Math.PI/180}static bilinear(t,e,i){const n=Vt.SKY_VIEW_WIDTH,s=Vt.SKY_VIEW_HEIGHT,r=Math.min(Math.max(e*n-.5,0),n-1),o=Math.min(Math.max(i*s-.5,0),s-1),c=Math.floor(r),l=Math.floor(o),h=Math.min(c+1,n-1),u=Math.min(l+1,s-1),d=r-c,f=o-l,p=(v,m,g)=>t[(v*n+m)*4+g];return[0,1,2,3].map(v=>(p(l,c,v)*(1-d)+p(l,h,v)*d)*(1-f)+(p(u,c,v)*(1-d)+p(u,h,v)*d)*f)}}class Ws{static DRY_OPTICAL_DEPTH=.08;static GROWTH_EXPONENT=.3;static MAX_RELATIVE_HUMIDITY=.95;static OPTICAL_DEPTH_STEP=.02;static relativeHumidity(t,e){const i=n=>Math.exp(17.625*n/(243.04+n));return Math.min(Math.max(i(e)/i(t),0),1)}static opticalDepth(t){const e=Math.min(Math.max(t,0),Ws.MAX_RELATIVE_HUMIDITY);return Ws.DRY_OPTICAL_DEPTH*(1-e)**-.3}static steppedOpticalDepth(t){const e=Ws.OPTICAL_DEPTH_STEP;return Math.round(Ws.opticalDepth(t)/e)*e}}class fn{static CHANNEL_WAVELENGTHS_NM=[680,550,440];static KOSCHMIEDER=-Math.log(.02);static PRECIPITATION_EXTINCTION_PER_KM={rain:{a:.365,b:.63},snow:{a:1.023,b:.72},hail:{a:.365,b:.63}};static FULL_INTENSITY_MM_PER_H=8;rayleigh;aerosol;constructor(t=Ot.DEFAULT_AEROSOL_OPTICAL_DEPTH,e=0){const[i,n,s]=fn.CHANNEL_WAVELENGTHS_NM;this.rayleigh=[Ot.rayleighAt(i),Ot.rayleighAt(n),Ot.rayleighAt(s)];const r=o=>t/Ot.AEROSOL_SCALE_HEIGHT_M*(o/550)**-1.3;this.aerosol=[r(i)+e,r(n)+e,r(s)+e],this.precipitationPerM=e}precipitationPerM;static of(t){const e=t.relativeHumidity===void 0?void 0:Ws.opticalDepth(t.relativeHumidity);return new fn(e,fn.precipitationExtinction(t))}static precipitationExtinction(t){if(t.precipitationType==="none"||!(t.precipitationIntensity>0))return 0;const e=fn.PRECIPITATION_EXTINCTION_PER_KM[t.precipitationType],i=t.precipitationIntensity*fn.FULL_INTENSITY_MM_PER_H;return e.a*i**e.b/1e3}transmittance(t,e,i){const n=fn.meanDensity(t,e,Ot.RAYLEIGH_SCALE_HEIGHT_M),s=fn.meanDensity(t,e,Ot.AEROSOL_SCALE_HEIGHT_M);return[0,1,2].map(r=>Math.exp(-(this.rayleigh[r]*n+this.aerosol[r]*s)*i))}transmittanceFromSpace(t,e){const i=Math.max(e,0),n=1/(Math.sin(i*Math.PI/180)+.50572*(i+6.07995)**-1.6364),s=Ot.RAYLEIGH_SCALE_HEIGHT_M*Ot.rayleighDensity(t),r=Ot.AEROSOL_SCALE_HEIGHT_M*Ot.aerosolDensity(t);return[0,1,2].map(o=>Math.exp(-(this.rayleigh[o]*s+(this.aerosol[o]-this.precipitationPerM)*r)*n))}extinctionAt(t){return{rayleigh:this.rayleigh[1]*Ot.rayleighDensity(t),aerosol:this.aerosol[1]*Ot.aerosolDensity(t)}}visibilityM(t){const{rayleigh:e,aerosol:i}=this.extinctionAt(t);return fn.KOSCHMIEDER/(e+i)}get rayleighRatios(){return[this.rayleigh[0]/this.rayleigh[1],1,this.rayleigh[2]/this.rayleigh[1]]}static meanDensity(t,e,i){const n=Math.max(t,0),s=Math.max(e,0),r=s-n;return Math.abs(r)<.01?Math.exp(-n/i):i*(Math.exp(-n/i)-Math.exp(-s/i))/r}}class ya extends Yd{constructor(){super(new st(0,0,0),0,0),ya.install()}setAir(t,e,i){const{rayleigh:n,aerosol:s}=t.extinctionAt(e);this.near=n,this.far=s,this.color.setRGB(i[0],i[1],i[2])}static fadeRim(t,e,i
|
|
6958
|
-
uniform vec3 aerialHorizon;`).replace("#include <fog_fragment>",`#include <fog_fragment>
|
|
6958
|
+
`})}get supported(){return this.tables.supported}get ready(){return this.hasViews}get ambient(){return this.ready?this.ambientColours:void 0}setInstrument(t,e){const i=t?10**(.4*e):1;i===this.exposureScale&&this.seenByEye===!t||(this.exposureScale=i,this.seenByEye=!t,this.material.uniforms.uExposureScale.value=i,this.applyAdaptation(this.adaptingLuminance),this.onChange())}setConditions(t){this.tables.setMedium(new Ot(t)),this.tables.ready||(this.drawnKey="")}advance(t){!this.supported||this.tables.ready||this.tables.advance(t)&&this.state&&this.draw(this.state)}invalidate(){this.tables.invalidate(),this.drawnKey="",this.hasViews=!1}update(t){this.state=t,this.tables.ready?this.draw(t):this.hasViews||this.applyAdaptation(ii.predictedZenithLuminance(t))}dispose(){this.tables.dispose(),this.material.dispose()}draw(t){const e=[t.altitudeM.toFixed(0),t.sun.altitudeDeg.toFixed(3),t.moon.altitudeDeg.toFixed(3)].join(":"),i=this.material.uniforms;if(i.uSunAzimuth.value.copy(ii.azimuthVector(t.sun.azimuthDeg)),i.uMoonAzimuth.value.copy(ii.azimuthVector(t.moon.azimuthDeg)),i.uMoonScale.value=10**(-.4*(t.moon.magnitude-ii.SUN_MAGNITUDE)),i.uObserverRadius.value=Ot.GROUND_RADIUS_M+Math.max(t.altitudeM,2),e!==this.drawnKey){this.tables.renderSkyViews(t.altitudeM,t.sun.altitudeDeg,t.moon.altitudeDeg);const n=!this.hasViews;this.hasViews=!0,this.drawnKey=e,n&&!this.ambientColours&&this.adaptFromViews(this.tables.readSkyViewNow("sun"),this.tables.readSkyViewNow("moon"),t),this.readBack()}this.onChange()}async readBack(){if(this.reading){this.readAgain=!0;return}this.reading=!0;try{const[t,e]=await Promise.all([this.tables.readSkyView("sun"),this.tables.readSkyView("moon")]),i=this.state;i&&this.adaptFromViews(t,e,i)}finally{this.reading=!1}this.readAgain&&(this.readAgain=!1,this.readBack())}adaptToSurroundings(t){if(!(t>0)||!(this.clearAdaptation>0))return!1;const e=t/this.clearAdaptation;return Math.abs(Math.log(e/this.surroundingsFactor))<.05?!1:(this.surroundingsFactor=e,this.views&&this.state?this.adaptFromViews(this.views.sun,this.views.moon,this.state):this.applyAdaptation(this.clearAdaptation*e),!0)}resetSurroundings(){this.surroundingsFactor=1}surroundingsFactor=1;clearAdaptation=0;views;adaptFromViews(t,e,i){this.views={sun:t,moon:e};const n=10**(-.4*(i.moon.magnitude-ii.SUN_MAGNITUDE)),s=ii.airglowXyzs(),r=(m,g,_=!0)=>{const w=(90-m)*Math.PI/180,M=Vt.skyViewUv(i.altitudeM,w,ii.azimuthBetween(g,i.sun.azimuthDeg)),S=Vt.skyViewUv(i.altitudeM,w,ii.azimuthBetween(g,i.moon.azimuthDeg)),b=ii.bilinear(t,M.u,M.v),T=ii.bilinear(e,S.u,S.v),x=_&&m>0?ii.airglowFactor(m):0;return[0,1,2,3].map(A=>b[A]+n*T[A]+s[A]*x)};let o=0,c=0;for(let m=5;m<90;m+=10){const g=Math.cos(m*Math.PI/180);for(let _=0;_<360;_+=30)o+=g*Math.log(Math.max(r(m,_)[1],1e-9)),c+=g}this.clearAdaptation=Math.exp(o/c),this.applyAdaptation(this.clearAdaptation*this.surroundingsFactor);const l=([m,g,_,w])=>{const M=this.exposureScale,S=this.adaptingLuminance*M;return Et.relativeOf([m*M,g*M,_*M],w*M,S,0)},h=(m,g,_=!0)=>l(r(m,g,_)),u=[0,0,0,0],d=5*Math.PI/180,f=20*Math.PI/180;for(let m=2.5;m<90;m+=5){const g=m*Math.PI/180,_=Math.sin(g)*Math.cos(g)*d*f;for(let w=10;w<360;w+=20){const M=r(m,w);for(let S=0;S<4;S++)u[S]+=M[S]*_}}const p=[0,0,0],v=[0,0,0];for(let m=0;m<360;m+=20){const g=h(2,m),_=h(2,m,!1);for(let w=0;w<3;w++)p[w]+=g[w]/18,v[w]+=_[w]/18}this.ambientColours={zenith:h(90,0),horizon:p,airlight:v,skyIrradiance:l(u),scale:this.relativeScale},this.onChange()}relativeOfLuminance(t,e){const[i,n,s]=t,r=.2126*i+.7152*n+.0722*s,o=r>0?e/r:0,c=[o*(.4124*i+.3576*n+.1805*s),e,o*(.0193*i+.1192*n+.9505*s)],l=this.exposureScale,h=this.adaptingLuminance*l;return Et.relativeOf([c[0]*l,c[1]*l,c[2]*l],c[1]*l,h,0)}get rodShare(){const t=this.adaptingLuminance*this.exposureScale;return this.seenByEye?Et.rodShare(t):0}get relativeScale(){const t=this.adaptingLuminance*this.exposureScale;return this.exposureScale/Et.semiSaturation(t)}applyAdaptation(t){this.adaptingLuminance=t;const e=t*this.exposureScale;this.material.uniforms.uRodShare.value=0,this.material.uniforms.uInverseSemiSaturation.value=1/Et.semiSaturation(e)}static predictedZenithLuminance(t){const e=n=>90-n.altitudeDeg,i=Yt.magPerArcsec2({altitudeDeg:t.sun.altitudeDeg,separationDeg:e(t.sun)},{phaseAngleDeg:t.moon.phaseAngleDeg,altitudeDeg:t.moon.altitudeDeg,separationDeg:e(t.moon)},90);return Yt.toNanolamberts(i)*ii.CANDELAS_PER_NANOLAMBERT}static CANDELAS_PER_NANOLAMBERT=1e-5/Math.PI;static airglowXyzs(){const t=Yt.toNanolamberts(Yt.AIRGLOW_MAG_PER_ARCSEC2)*ii.CANDELAS_PER_NANOLAMBERT;return[t*.3127/.329,t,t*(1-.3127-.329)/.329,t]}static airglowFactor(t){const e=Math.cos(t*Math.PI/180)**2,i=Ot.GROUND_RADIUS_M/(Ot.GROUND_RADIUS_M+ii.AIRGLOW_LAYER_ALTITUDE_M),n=1/Math.sqrt(Math.max(1-i*i*e,1e-4)),s=1/Math.sqrt(Math.max(1-.96*e,.001));return n*10**(-.4*Yt.EXTINCTION_PER_AIR_MASS*(s-1))}static azimuthVector(t){const e=t*Math.PI/180;return new Mt(Math.sin(e),-Math.cos(e))}static azimuthBetween(t,e){const i=Math.abs(t-e)%360;return(i>180?360-i:i)*Math.PI/180}static bilinear(t,e,i){const n=Vt.SKY_VIEW_WIDTH,s=Vt.SKY_VIEW_HEIGHT,r=Math.min(Math.max(e*n-.5,0),n-1),o=Math.min(Math.max(i*s-.5,0),s-1),c=Math.floor(r),l=Math.floor(o),h=Math.min(c+1,n-1),u=Math.min(l+1,s-1),d=r-c,f=o-l,p=(v,m,g)=>t[(v*n+m)*4+g];return[0,1,2,3].map(v=>(p(l,c,v)*(1-d)+p(l,h,v)*d)*(1-f)+(p(u,c,v)*(1-d)+p(u,h,v)*d)*f)}}class Ws{static DRY_OPTICAL_DEPTH=.08;static GROWTH_EXPONENT=.3;static MAX_RELATIVE_HUMIDITY=.95;static OPTICAL_DEPTH_STEP=.02;static relativeHumidity(t,e){const i=n=>Math.exp(17.625*n/(243.04+n));return Math.min(Math.max(i(e)/i(t),0),1)}static opticalDepth(t){const e=Math.min(Math.max(t,0),Ws.MAX_RELATIVE_HUMIDITY);return Ws.DRY_OPTICAL_DEPTH*(1-e)**-.3}static steppedOpticalDepth(t){const e=Ws.OPTICAL_DEPTH_STEP;return Math.round(Ws.opticalDepth(t)/e)*e}}class fn{static CHANNEL_WAVELENGTHS_NM=[680,550,440];static KOSCHMIEDER=-Math.log(.02);static PRECIPITATION_EXTINCTION_PER_KM={rain:{a:.365,b:.63},snow:{a:1.023,b:.72},hail:{a:.365,b:.63}};static FULL_INTENSITY_MM_PER_H=8;rayleigh;aerosol;constructor(t=Ot.DEFAULT_AEROSOL_OPTICAL_DEPTH,e=0){const[i,n,s]=fn.CHANNEL_WAVELENGTHS_NM;this.rayleigh=[Ot.rayleighAt(i),Ot.rayleighAt(n),Ot.rayleighAt(s)];const r=o=>t/Ot.AEROSOL_SCALE_HEIGHT_M*(o/550)**-1.3;this.aerosol=[r(i)+e,r(n)+e,r(s)+e],this.precipitationPerM=e}precipitationPerM;static of(t){const e=t.relativeHumidity===void 0?void 0:Ws.opticalDepth(t.relativeHumidity);return new fn(e,fn.precipitationExtinction(t))}static precipitationExtinction(t){if(t.precipitationType==="none"||!(t.precipitationIntensity>0))return 0;const e=fn.PRECIPITATION_EXTINCTION_PER_KM[t.precipitationType],i=t.precipitationIntensity*fn.FULL_INTENSITY_MM_PER_H;return e.a*i**e.b/1e3}transmittance(t,e,i){const n=fn.meanDensity(t,e,Ot.RAYLEIGH_SCALE_HEIGHT_M),s=fn.meanDensity(t,e,Ot.AEROSOL_SCALE_HEIGHT_M);return[0,1,2].map(r=>Math.exp(-(this.rayleigh[r]*n+this.aerosol[r]*s)*i))}transmittanceFromSpace(t,e){const i=Math.max(e,0),n=1/(Math.sin(i*Math.PI/180)+.50572*(i+6.07995)**-1.6364),s=Ot.RAYLEIGH_SCALE_HEIGHT_M*Ot.rayleighDensity(t),r=Ot.AEROSOL_SCALE_HEIGHT_M*Ot.aerosolDensity(t);return[0,1,2].map(o=>Math.exp(-(this.rayleigh[o]*s+(this.aerosol[o]-this.precipitationPerM)*r)*n))}extinctionAt(t){return{rayleigh:this.rayleigh[1]*Ot.rayleighDensity(t),aerosol:this.aerosol[1]*Ot.aerosolDensity(t)}}visibilityM(t){const{rayleigh:e,aerosol:i}=this.extinctionAt(t);return fn.KOSCHMIEDER/(e+i)}get rayleighRatios(){return[this.rayleigh[0]/this.rayleigh[1],1,this.rayleigh[2]/this.rayleigh[1]]}static meanDensity(t,e,i){const n=Math.max(t,0),s=Math.max(e,0),r=s-n;return Math.abs(r)<.01?Math.exp(-n/i):i*(Math.exp(-n/i)-Math.exp(-s/i))/r}}class ya extends Yd{constructor(){super(new st(0,0,0),0,0),ya.install()}setAir(t,e,i){const{rayleigh:n,aerosol:s}=t.extinctionAt(e);this.near=n,this.far=s,this.color.setRGB(i[0],i[1],i[2])}static fadeRim(t,e,i){t.transparent=!0,t.onBeforeCompile=n=>{n.fragmentShader=n.fragmentShader.replace("#include <fog_fragment>",`#include <fog_fragment>
|
|
6959
6959
|
#ifdef USE_FOG
|
|
6960
|
-
|
|
6961
|
-
gl_FragColor.rgb = mix(gl_FragColor.rgb, aerialHorizon, aerialRim);
|
|
6960
|
+
gl_FragColor.a *= 1.0 - smoothstep(${e.toFixed(1)}, ${i.toFixed(1)}, length(vAerialWorld.xz - cameraPosition.xz));
|
|
6962
6961
|
#endif`)},t.customProgramCacheKey=()=>`aerial-rim-${e.toFixed(1)}-${i.toFixed(1)}`,t.needsUpdate=!0}static installed=!1;static install(){if(ya.installed)return;ya.installed=!0;const t=new fn(1),e=t.rayleighRatios,i=[t.aerosol[0]/t.aerosol[1],1,t.aerosol[2]/t.aerosol[1]],n=o=>`vec3(${o.map(c=>c.toFixed(4)).join(", ")})`,s=Ot.RAYLEIGH_SCALE_HEIGHT_M.toFixed(1),r=Ot.AEROSOL_SCALE_HEIGHT_M.toFixed(1);Wt.fog_pars_vertex=`
|
|
6963
6962
|
#ifdef USE_FOG
|
|
6964
6963
|
varying vec3 vAerialWorld;
|
|
@@ -7015,7 +7014,7 @@ cloudPoint = (modelMatrix * vec4(transformed, 1.0)).xyz - cameraPosition;`);let
|
|
|
7015
7014
|
vec3 light = texture2D(uMap, vec2((along * (uSteps - 1.0) + 0.5) / uSteps, 0.5)).rgb;
|
|
7016
7015
|
gl_FragColor = vec4(light, 1.0);
|
|
7017
7016
|
}
|
|
7018
|
-
`,transparent:!0,blending:Ci,depthWrite:!1,side:Ue,fog:!1});this.object=new Dt(new Qe(M0.RADIUS,128,32,0,Math.PI*2,0,ce.MAX_ANGLE_RAD),e),this.object.renderOrder=-1,this.object.frustumCulled=!1,this.object.visible=!1}show(t,e){if(!t||!e){this.object.visible=!1;return}this.towards.set(t.x,t.y,t.z).normalize(),this.object.quaternion.setFromUnitVectors(this.up,this.towards),this.object.material.uniforms.uSource.value.copy(this.towards);for(let i=0;i<ce.STEPS;i++){for(let n=0;n<3;n++)this.texels[i*4+n]=Cn.toHalfFloat(Math.min(e[i*3+n],6e4));this.texels[i*4+3]=Cn.toHalfFloat(1)}this.texture.needsUpdate=!0,this.object.visible=!0}dispose(){this.object.geometry.dispose(),this.object.material.dispose(),this.texture.dispose()}}class xl{constructor(t){this.generator=t}static SIZE=128;target=new To(xl.SIZE,{type:ze,generateMipmaps:!1,minFilter:se,magFilter:se});camera=new e0(.1,2e5,this.target);filteredTarget;capturedAtMs=-1/0;capturedVersion;get sharp(){return this.target.texture}get filtered(){return this.filteredTarget?.texture}capture(t,e,i,n=[]){const s=t.shadowMap.autoUpdate;t.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(t,e),n.forEach((o,c)=>{o.visible=r[c]}),t.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 Ji{static REFRESH_MS=250;generator;eye;probes=new Map;constructor(t){Ji.install(),this.generator=new Ju(t),this.eye=new xl(this.generator)}static decor;refresh(t,e,i,n,s,r,o,c=[],l){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 xl(this.generator),this.probes.set(v.id,m)),h.push({probe:m,reflector:v})}const u=performance.now(),d=()=>h.filter(({probe:v})=>v.capturedVersion!==o),f=d().filter(({probe:v})=>u-v.capturedAtMs>=Ji.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(t,e,m,[v.reflector.holder,...s]),Ji.reflectOn(v.reflector.holder,v.probe)}else{v.probe.capture(t,e,i,[...s,...c]),l?.(v.probe.sharp),Ji.decor=v.probe.filtered;for(const m of r)Ji.reflectOn(m,v.probe);for(const m of n)m.shiny||Ji.reflectOn(m.holder,v.probe)}v.probe.capturedVersion=o}const p=d();if(p.length!==0)return Math.max(16,Math.min(...p.map(({probe:v})=>Ji.REFRESH_MS-(u-v.capturedAtMs))))}scratch=new D;static reflectOn(t,e={filtered:Ji.decor}){t.traverse(i=>{const n=i.material;for(const s of Array.isArray(n)?n:n?[n]:[])s instanceof Do?e.sharp&&s.setSurroundings(e.sharp):s instanceof la&&e.filtered&&s.envMap!==e.filtered&&(s.envMap=e.filtered,s.needsUpdate=!0)})}dispose(){this.eye.dispose();for(const t of this.probes.values())t.dispose();this.generator.dispose()}static installed=!1;static install(){if(Ji.installed)return;Ji.installed=!0;const t="iblIrradiance += getIBLIrradiance( geometryNormal );";if(!Wt.lights_fragment_maps.includes(t)){console.warn("Reflections: three's lights_fragment_maps changed; the environment will light diffusely too");return}Wt.lights_fragment_maps=Wt.lights_fragment_maps.replace(t,"// The sky's diffuse light is the hemisphere light's (see Reflections).")}}function cb(a,t){return JSON.stringify(a.cloudLayers)===JSON.stringify(t.cloudLayers)&&a.cloudCover===t.cloudCover&&a.cloudDarkness===t.cloudDarkness&&a.cloudBaseM===t.cloudBaseM&&a.highCloudCover===t.highCloudCover&&a.iceCrystalAlignment===t.iceCrystalAlignment&&a.lowerCloudCover===t.lowerCloudCover&&a.relativeHumidity===t.relativeHumidity&&a.precipitationType===t.precipitationType&&a.precipitationIntensity===t.precipitationIntensity&&a.windDirectionDeg===t.windDirectionDeg&&a.windSpeed===t.windSpeed&&a.storm===t.storm}const Cc=900,Bh=1,jp=4,Qp=5,tm=.5,so=900,lb=6371e3,hb=3e4;function em(a){const t=Math.sqrt(2*lb*Math.max(a,0));return Math.max(so,Math.min(t,hb))}const Hh=.5,Gh=850,im=.03,ln=850,Vh=300,ub=.04,$r=4,Wh=1.5,nm=-1,db=6,Dd=-4,fb=2,pb=20,Ic=2600,mb=.97,gb=.38,Pc=Dd,sm=1500,vb=400,Mb=[0,45,90,135,180,225,270,315],xb={en:["N","NE","E","SE","S","SW","W","NW"],fr:["N","NE","E","SE","S","SO","O","NO"]},yb=["en","fr"],_b=2,Sb=16,am=2500,rm=880,Lc=40,om=60,wb=10,bb=1,Eb=150,Ab=55,Tb=.5,Rb=17,cm=.265,lm=[[0,0],...Array.from({length:8},(a,t)=>{const e=t*Math.PI/4;return[Math.cos(e)*cm,Math.sin(e)*cm]})],Xh=700,qh=250/1e3,Db=12,hm=5,Yh=6,aa=[.92,.92,.95],Kh=[.15,.15,.19],um={snow:{fallSpeedMPerS:2,size:.3,color:new st(1,1,1),driftSensitivity:1,radiusM:25,topYM:20,opacity:.75,poolSize:2400},hail:{fallSpeedMPerS:14,size:.5,color:new st(.95,.98,1),driftSensitivity:.25,radiusM:25,topYM:10,opacity:.95,poolSize:1200}},er=0,$h=0,Cb=150,dm=3e3,Zr=20,Ib=15,fm=er,Pb=40,pm=1,Lb=9;function mm(a){return pm+(Lb-pm)*a}const gm=new st(.75,.82,.92),Nb=10,Ob=.5;function Ub(a){return or(a/Nb,Ob,1)}const ja=200,vm=.18,Mm=.32,Fb=.35,xm=new st(.85,.9,.98),ym=5,_m=.85,Sm=.01;function Zh(a,t){return Math.round(a*(Sm+(1-Sm)*t))}const wm=230,bm=.7,Em=.05,kb=.6,zb=.7,Bb=.15,Am=.35,Hb=3,Gb=1/12,Vb=.5,zn=new st(.82,.86,1),Wb=2500,Xb=1.6,Jh=15,qb={Venus:new st(1,.96,.85),Mars:new st(1,.55,.4),Jupiter:new st(.95,.87,.72),Saturn:new st(.92,.86,.68)};class Fe{renderer;scene=new ys;phenomena=new bn(this.scene);references=new fa(this.scene,()=>this.render());camera;celestialGroup=new De;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 hn;roadAttribution;roadWays;statedRoads=[];decorModelProvider=ab[0].create();decorModelToken=0;decorModelCredits=new Map;bodySystem=new oe(t=>this.loadBodyModel(t),()=>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 Xf(16777215,0);celestialLightTarget=new Pe;skyLight=new PM(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 xh;weather=Om;observerElevationM=0;siteElevationM=0;air=new fn;groundRadius=so;terrainRadius=so;cloudRendering="volume";layeredClouds;cloudLayerOffsetsM={};cloudOffsetM=new D;cloudFieldOffset=new D;cloudMesh;cirrusMesh;cirrusMaterial;cirrusUniforms;cloudMaterial;cloudUniforms;precipitationPoints;precipitationPositions;precipitationPhase;precipitationSpeedJitter;precipitationWobbleFreqJitter;precipitationWobbleAmpJitter;precipitationBounceRemaining;precipitationBounceHeight;precipitationBounceDuration;precipitationBounceVelX;precipitationBounceVelZ;precipitationUniforms;rainSystem;rainSplashSystem;rainCameraDirection=new D;rainLastVerticalFacing=-1;rainViewportSize=new Mt;lightningArmed=!1;lightningFlashes=[];lightningLevel=0;lightningBolt;lightningLight=new Xf(16777215,0);baseFogColor=[0,0,0];lastSunPosition;lensFlare;sunUnhiddenFraction=1;lensFlareArtifactIntensity=0;sunWorldPosition=new D;sunVisible=!1;lensFlareScratch=new D;sunOcclusionRaycaster=new xh;sunOcclusionDirectionScratch=new D;sunOcclusionRightScratch=new D;sunOcclusionUpScratch=new D;ufoOcclusionRaycaster=new xh;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(t){return Math.max(3,Math.round(6e6/Math.max(1,t)))}exposureFrameId=null;exposureInstantsDone=0;exposureInstantAt;restatingExposure=!1;lensOptics;instrumentMagnitudeGain=0;meteorSystem;cometTail;satelliteField;iceHalos;lunarDiffraction;lunarDiffractionKey="";rainbow;skyGlow;cometKey;novaKeys=new Set;constructor(t,e=L2()){this.renderer=new XS({canvas:t,antialias:!0}),this.resolution=new de(Math.min(window.devicePixelRatio||1,2),this.renderer.getContext()),this.renderer.setPixelRatio(this.resolution.pixelRatio),this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=ro,this.camera=new Vi(60,t.width/Math.max(t.height,1),.1,Cc*1.2),this.camera.position.set(0,1.6,0),this.terrainProviders=e,this.celestialLight.shadow.mapSize.set(1024,1024),this.celestialLight.shadow.camera.left=-120,this.celestialLight.shadow.camera.right=120,this.celestialLight.shadow.camera.top=120,this.celestialLight.shadow.camera.bottom=-120,this.celestialLight.shadow.camera.near=ln-Vh,this.celestialLight.shadow.camera.far=ln+Vh,this.celestialLight.shadow.bias=-.03/(2*Vh),this.celestialLight.shadow.normalBias=ub,this.celestialLight.target=this.celestialLightTarget,this.lightningLight.color.copy(zn),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 ii(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(t,e){this.cssSize.width=t,this.cssSize.height=e,this.renderer.setSize(t,e,!1),this.camera.aspect=t/Math.max(e,1),this.camera.updateProjectionMatrix(),this.render()}setCloudRendering(t){t!==this.cloudRendering&&(this.cloudTransmissionMemo.clear(),this.cloudRendering=t,this.layeredClouds?.dispose(),this.layeredClouds=void 0,this.buildClouds(),this.buildCirrus(),this.render())}setCloudOffset(t,e={}){this.cloudOffsetM.set(t.x,0,t.z),this.cloudLayerOffsetsM=e,this.layeredClouds?.setOffsets(t,e),this.cloudFieldOffset.set(t.x*qh,0,t.z*qh);for(const i of[this.cloudUniforms,this.cirrusUniforms])i?.fieldOffset.value.copy(this.cloudFieldOffset);this.iceHalos?.setCloudOffset(this.layeredClouds?.cirrusMask?.offset??this.cloudFieldOffset)}setObserverPose(t){const e=((t.rollDeg??0)+this.gaitOffset.rollDeg)*Bi,i=(t.pitchDeg+this.lookPitchDeg+this.gaitOffset.pitchDeg)*Bi;if(t.headingDeg!==void 0?this.camera.rotation.set(i,-(t.headingDeg+this.lookYawDeg+this.gaitOffset.yawDeg)*Bi,e,"YXZ"):this.camera.rotation.set(i,this.camera.rotation.y,e,"YXZ"),t.elevationM!==this.observerElevationM&&(this.observerElevationM=t.elevationM,this.syncCloudLayer(),Math.abs(em(t.elevationM)-this.groundRadius)>1&&(this.buildGround(),this.celestialGroup.scale.setScalar(this.groundRadius/so),this.camera.far=Math.max(Cc*1.2,this.groundRadius*2.5),this.camera.updateProjectionMatrix())),this.terrainMesh&&this.terrainOrigin&&t.lat!==void 0&&t.lng!==void 0){const n=li(this.terrainOrigin.lat,this.terrainOrigin.lng,t.lat,t.lng);this.terrainMesh.position.x=n.x,this.terrainMesh.position.z=n.z}this.poseCameraY=this.groundYUnder(0,0)+1.6+t.elevationM,this.camera.position.y=this.poseCameraY,this.celestialGroup.position.y=this.camera.position.y,this.camera.fov!==t.fovDeg&&(this.camera.fov=t.fovDeg,this.camera.updateProjectionMatrix(),this.updateCompassScale())}setTerrainProviders(t){this.terrainProviders=t,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(t,e,i){if(t===void 0||e===void 0)return;const n=this.groundRadius;if(this.terrainOrigin&&Math.abs(this.terrainRadius-n)<n*.1){const{x:c,z:l}=li(t,e,this.terrainOrigin.lat,this.terrainOrigin.lng);if(Math.sqrt(c*c+l*l)<Eb*(n/so))return}const s=this.terrainOrigin,r=this.terrainRadius;(!s||s.lat!==t||s.lng!==e)&&(this.roadSystem.clear(),this.roadAttribution=void 0),this.terrainOrigin={lat:t,lng:e},this.terrainRadius=n;const o=++this.terrainBuildToken;yw(t,e,this.terrainProviders,n).then(({mesh:c,attribution:l,originElevationM:h})=>{if(o!==this.terrainBuildToken)return;this.setSiteElevation(h??0);const u=this.terrainMesh,d=s?li(t,e,s.lat,s.lng):void 0;u&&d&&Math.hypot(d.x,d.z)<=r&&(c.position.y=u.position.y+this.groundYOfPatch(u,d.x,d.z)),this.disposeMesh(this.terrainMesh),c.renderOrder=bb,this.terrainMesh=c,this.compileNextFrameOffThread(),this.terrainAttribution=l,this.scene.add(c),this.applyGroundDepthWrite(),this.decorCurrentPose&&(this.setObserverPose(this.decorCurrentPose),this.updateDecorAnchoring(this.decorReferencePose,this.decorCurrentPose,this.decorTime)),this.buildRoads(t,e,n),this.drapeStatedRoads(),this.render(),i?.()}).catch(c=>{console.warn("Terrain build failed, keeping the flat ground fallback:",c),i?.()})}static ROADS_MAX_RADIUS_M=5e3;buildRoads(t,e,i){const n=this.terrainProviders.roads;if(!n||i>Fe.ROADS_MAX_RADIUS_M){this.roadSystem.clear(),this.roadAttribution=void 0;return}const s=this.roadWays;if(s&&s.lat===t&&s.lng===e&&s.radiusM===i){this.drapeRoads(s.ways,t,e,n.contemporary);return}n.getRoads(h1(t,e,i)).then(r=>{this.terrainOrigin?.lat!==t||this.terrainOrigin?.lng!==e||(this.roadWays={lat:t,lng:e,radiusM:i,ways:r},this.drapeRoads(r,t,e,n.contemporary))}).catch(r=>{console.warn("Roads unavailable, drawing none:",r)})}setStatedRoads(t){t!==this.statedRoads&&(this.statedRoads=t,this.drapeStatedRoads(),this.render())}drapeStatedRoads(){const t=this.terrainMesh;t&&(this.roadSystem.group.position.copy(t.position),this.roadSystem.setStated(this.statedRoads,(e,i)=>this.groundYOfPatch(t,e,i)))}drapeRoads(t,e,i,n){const s=this.terrainMesh;s&&(this.roadSystem.group.position.copy(s.position),this.roadSystem.set(t,e,i,(r,o)=>this.groundYOfPatch(s,r,o),n),this.roadAttribution=t.length>0?this.terrainProviders.roads?.attribution:void 0,this.compileNextFrameOffThread(),this.render())}setShowCompass(t){this.showCompass!==t&&(this.showCompass=t,this.disposeCompassLabels(),t&&this.buildCompassLabels(),this.render())}applyLensFlareTint(t){if(!this.lensFlare)return;const e=Ab*(this.sunArriving[1]/Rb);this.lensFlare.uniforms.uColorGain.value.setRGB(e*t[0],e*t[1],e*t[2]),this.applyDazzleStrength()}applyDazzleStrength(){if(!this.lensFlare)return;const[t,e,i]=this.sunArriving,n=Math.max(e,1e-30);this.lensFlare.uniforms.uDazzleColour.value.setRGB(t/n,1,i/n),this.lensFlare.uniforms.uVeilStrength.value=Ui.K*e*this.sunUnhiddenFraction}sunArriving=[0,0,0];setCompassHovered(t){this.compassHovered!==t&&(this.compassHovered=t,this.updateCompassVisibility())}setCompassForced(t){this.compassForced!==t&&(this.compassForced=t,this.updateCompassVisibility())}updateCompassVisibility(){const t=this.compassHovered||this.compassForced;if(this.compassSprites.some(e=>e.visible!==t)){for(const e of this.compassSprites)e.visible=t;this.developingExposure?this.exposureInstantsDone>0&&this.presentExposure():this.render()}}setWeather(t){this.cloudTransmissionMemo.clear(),!cb(this.weather,t)&&(this.weather=t,this.air=fn.of(t),this.applyAir(),this.scatteredSky?.setConditions({aerosolOpticalDepth:t.relativeHumidity===void 0?void 0:Ws.steppedOpticalDepth(t.relativeHumidity)}),this.pumpScatteredSky(),this.buildClouds(),this.buildCirrus(),this.buildPrecipitation(),this.lastAstronomy&&(this.buildIceHalos(this.lastAstronomy.sun,this.lastAstronomy.moon),this.buildRainbow(this.lastAstronomy.sun,this.lastAstronomy.moon),this.buildLunarDiffraction(this.lastAstronomy.moon)),this.lightningArmed=t.storm&&t.cloudDarkness>=Vb,this.syncAnimationLoop(),this.render())}setDecor(t){if(this.decorObjects!==t){this.decorObjects=t,this.decorModelToken++,this.decorModelCredits.clear();for(const e of this.decorGroups.values())e.removeFromParent(),vi.dispose(e);this.decorGroups.clear(),this.streetlightLights.clear();for(const e of t){const i=vi.build(e,e.lit??!1);this.scene.add(i),this.decorGroups.set(e.id,i),e.kind==="streetlight"&&this.addStreetlightLight(e.id,i),this.loadDecorModel(e,this.decorModelToken)}this.celestialLight.castShadow=this.decorGroups.size>0||this.bodySystem.any}}setDecorModelProvider(t){this.decorModelProvider=t;const e=this.decorObjects;this.decorObjects=[],this.setDecor(e)}get currentDecorModelCredits(){return[...this.decorModelCredits.values(),...this.bodySystem.modelCredits]}get bodyGround(){const{x:t,z:e}=this.bodyOrigin,i=this.groundYUnder(t,e);return{heightAt:(n,s)=>this.groundYUnder(t+n,e-s)-i}}setBodies(t,e=0,i=t.map(r=>r.id),n=[],s){const{x:r,z:o}=this.bodyOrigin,c=this.scatteredSky;this.bodySystem.set(t,{originX:r,originZ:o,originGroundY:this.groundYUnder(r,o),eye:this.camera.position,groundYAt:(h,u)=>this.groundYUnder(h,u),wind:s,light:this.plumeLight(),transmittance:(h,u,d)=>this.transmittanceTo(h,u,d)},e,c?(h,u)=>c.relativeOfLuminance(h,u):void 0,i),this.bodySystem.setSmoke(n,e),this.bodySystem.any&&(this.celestialLight.castShadow=!0);const l=this.bodySystem.furthestFrom(this.camera.position)*1.2;l>this.camera.far&&(this.camera.far=l,this.camera.updateProjectionMatrix())}plumeLight(){const t=this.celestialLight.color,e=this.celestialLight.intensity*.5,i=this.skyLight.color,n=this.skyLight.groundColor,s=this.skyLight.intensity,r=(o,c,l)=>(o*e+(c+l)/2*s)/Math.PI;return[r(t.r,i.r,n.r),r(t.g,i.g,n.g),r(t.b,i.b,n.b)]}bodyOutline(t,e){return this.bodySystem.outlineOf(t,e)}async loadBodyModel(t){const e=t.url?void 0:t.id?await this.decorModelProvider.entry(t.id):void 0,i=t.url??e?.url,n=t.credit??e?.credit;if(!(!i||!n))return{scene:await Jp(i),credit:n,headingOffsetDeg:t.headingOffsetDeg??e?.headingOffsetDeg}}async loadDecorModel(t,e){const i=t.model;if(!(!i||!vi.usesModel(t)))try{const n=i.url?void 0:i.id?await this.decorModelProvider.entry(i.id):void 0,s=i.url??n?.url,r=i.credit??n?.credit;if(!s||!r)return;const o=await Jp(s);if(e!==this.decorModelToken)return;const c=this.decorGroups.get(t.id);if(!c)return;Ji.reflectOn(o),vi.applyModel(c,t,o,{headingOffsetDeg:i.headingOffsetDeg??n?.headingOffsetDeg,depictedSizeM:n?.sizeM}),this.decorModelCredits.set(t.id,r),this.render()}catch(n){console.warn(`Keeping the built-in shape for decor "${t.id}":`,n)}}updateDecorAnchoring(t,e,i=0){this.decorReferencePose=t,this.decorCurrentPose=e,this.decorTime=i;const n=t?.lat!==void 0&&t.lng!==void 0&&e?.lat!==void 0&&e?.lng!==void 0?li(t.lat,t.lng,e.lat,e.lng):{x:0,z:0},s=this.decorObjects.find(l=>l.witnessSide!==void 0&&zm(l.kind));if(this.terrainMesh&&this.terrainOrigin&&e?.lat!==void 0&&e.lng!==void 0){const l=li(this.terrainOrigin.lat,this.terrainOrigin.lng,e.lat,e.lng);this.terrainMesh.position.x=l.x-(s?0:this.gaitOffset.eastM),this.terrainMesh.position.z=l.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 l=vi.occupantView(s),h=-(s.headingDeg??0)*Bi,u=l.x*Math.cos(h)+l.z*Math.sin(h),d=-l.x*Math.sin(h)+l.z*Math.cos(h),f=s.eastM+n.x,p=-s.northM+n.z;r.x=-(f+u),r.z=-(p+d),this.camera.position.y=this.groundYUnder(f,p)+l.eyeY,this.camera.rotation.set(this.indoorLookPitchDeg*Bi,-(l.headingDeg+this.indoorLookYawDeg)*Bi,0,"YXZ")}this.bodyOrigin={x:n.x+r.x,z:n.z+r.z},this.placeShadowFrustum();for(const l of this.decorObjects){const h=this.decorGroups.get(l.id);if(!h)continue;const u=Id(l,i),d=u.eastM+n.x+r.x,f=-u.northM+n.z+r.z,p=this.terrainMesh,v=`${p?.geometry.uuid}:${(d-(p?.position.x??0)).toFixed(3)}:${(f-(p?.position.z??0)).toFixed(3)}:${(p?.position.y??0).toFixed(3)}:${u.headingDeg}:${u.altitudeM}`;if(h.userData.footprintKey!==v&&(h.userData.footprintGroundY=this.groundUnderFootprint(l,d,f,u.headingDeg,u.altitudeM),h.userData.footprintKey=v),h.position.set(d,h.userData.footprintGroundY+u.altitudeM,f),l.kind==="crop"){const m=Math.hypot(d,f);h.visible=m<=Cb}if(u.headingDeg!==void 0&&(h.rotation.y=-u.headingDeg*Bi),l.kind==="crop"&&h.visible){const m=this.terrainMesh,g=[m?.geometry.uuid,d-(m?.position.x??0),f-(m?.position.z??0),h.position.y-(m?.position.y??0),u.headingDeg,u.altitudeM].map(_=>typeof _=="number"?_.toFixed(4):_).join(":");h.userData.cropGroundKey!==g&&(vi.fitCropToGround(h,(_,w)=>this.groundYUnder(_,w)+u.altitudeM),h.userData.cropGroundKey=g)}o=Math.max(o,h.position.distanceTo(this.camera.position))}const c=Math.max(Cc*1.2,this.groundRadius*2.5,o*1.2);Math.abs(this.camera.far-c)>1&&(this.camera.far=c,this.camera.updateProjectionMatrix())}groundYUnder(t,e){const i=this.terrainMesh;return i?i.position.y+this.groundYOfPatch(i,t-i.position.x,e-i.position.z):$h}groundYOfPatch(t,e,i){const n=t.geometry.getAttribute("position"),s=Math.round(Math.sqrt(n.count));if(s<2||s*s!==n.count)return $h;const r=n.getX(0),o=n.getX(s-1),c=n.getZ(0),l=n.getZ((s-1)*s),h=or((e-r)/(o-r)*(s-1),0,s-1),u=or((i-c)/(l-c)*(s-1),0,s-1);if(!Number.isFinite(h)||!Number.isFinite(u))return $h;const d=Math.min(Math.floor(h),s-2),f=Math.min(Math.floor(u),s-2),p=h-d,v=u-f,m=(S,b)=>n.getY(S*s+b),g=m(f,d),_=m(f,d+1),w=m(f+1,d),M=m(f+1,d+1);return p+v<=1?g+(_-g)*p+(w-g)*v:M+(w-M)*(1-p)+(_-M)*(1-v)}groundUnderFootprint(t,e,i,n,s=0){return vi.groundUnderFootprint(t,e,i,n,(r,o)=>this.groundYUnder(r,o),s)}lookYawDeg=0;lookPitchDeg=0;poseCameraY=1.6;setGait(t){this.gaitOffset=t}gaitOffset={eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0};setLookOffset(t,e){this.lookYawDeg=t,this.lookPitchDeg=e}indoorLookYawDeg=0;indoorLookPitchDeg=0;setIndoorLook(t,e){this.indoorLookYawDeg=t,this.indoorLookPitchDeg=e}updateDecorLitState(t,e=0){for(const i of this.decorObjects){const n=this.decorGroups.get(i.id);if(n&&i.lights?.length&&vi.setLights(n,i.lights,t,n.position.distanceTo(this.camera.position),e,this.relativeScale),i.kind!=="streetlight"&&i.kind!=="vehicle")continue;const s=this.decorGroups.get(i.id);if(!s)continue;const r=p2(i,t);vi.setLit(s,i.kind,r,this.relativeScale);const o=this.streetlightLights.get(i.id);o&&(o.visible=r)}}addStreetlightLight(t,e){const i=vi.bodyOf(e),n=i.children.find(r=>r.userData.emissive);if(!n)return;const s=new Cg(16764006,sm*this.relativeScale,vb);s.position.copy(n.position).multiply(i.scale),s.castShadow=!0,s.shadow.mapSize.set(512,512),s.shadow.bias=-.002,e.add(s),this.streetlightLights.set(t,s)}setAstronomy(t){(!this.lastAstronomy||Math.abs(this.lastAstronomy.sun.altitudeDeg-t.sun.altitudeDeg)>2)&&(this.surroundings=void 0,this.scatteredSky?.resetSurroundings()),this.lastAstronomy=t,this.scatteredSky?.update(this.scatteredSkyState(t)),this.skyHoldUntilMs===void 0&&(this.skyHoldUntilMs=performance.now()+am,this.onFirstFrameHold?.(!0),setTimeout(()=>this.render(),am+20)),this.pumpScatteredSky(),this.lastSunPosition=t.sun,this.buildSky(t.sun),this.buildGround();const e=qc(t.sun.altitudeDeg,this.instrumentMagnitudeGain);this.buildStars(t.stars,e),this.placeBodies(t,e),this.buildIceHalos(t.sun,t.moon),this.buildRainbow(t.sun,t.moon),this.applySkyColours(t),this.syncAnimationLoop(),this.render()}static relativeSkyOf(t,e){const i=r=>{const o=Rn.luminanceOf(r);if(!(o>0))return[0,0,0];const c=Et.relativeOfResponse(o)/o;return[r[0]*c,r[1]*c,r[2]*c]},n=i(t.zenith),s=i(t.horizon);return{zenith:n,horizon:s,airlight:s,skyIrradiance:[n[0]*Math.PI,n[1]*Math.PI,n[2]*Math.PI],scale:e}}placeBodies(t,e){this.bodiesScale=this.relativeScale,this.setBodyMesh("sun",t.sun,$r,new st(1,.96,.88),t.sun.magnitude),this.setMoonMesh(t.moon,e),this.buildPlanets(t.planets,e),this.buildComet(t.comet,e),this.buildNovae(t.novae??[],e)}bodiesScale=0;applySkyColours(t){this.skyColoursStale=!1,this.bodiesScale!==this.relativeScale&&(this.placeBodies(t,qc(t.sun.altitudeDeg,this.instrumentMagnitudeGain)),this.applyDazzleStrength(),this.buildIceHalos(t.sun,t.moon),this.buildRainbow(t.sun,t.moon));const e=this.scatteredSky?.ambient??Fe.relativeSkyOf(rd(t.sun.altitudeDeg),this.relativeScale),i=e,n=this.lightUnderClouds(t),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(t,e),this.updateCloudLighting(t.sun,this.baseFogColor),Oe.setEye(this.scatteredSky?.rodShare??0,this.relativeScale),this.updateTwinkle(this.twinkleSeconds);for(const r of this.streetlightLights.values())r.intensity=sm*this.relativeScale;this.buildSkyGlow(t,i.zenith),this.applyAir(),this.buildLunarDiffraction(t.moon)}reflections;sceneVersion=0;reflectionTimer;buildLunarDiffraction(t){const e=this.scatteredSky?.ready?this.scatteredSky:void 0;if(t.altitudeDeg<-.5||!e){this.lunarDiffraction?.show(void 0),this.lunarDiffractionKey="";return}const i=this.weather.relativeHumidity,n=(i===void 0?Ot.DEFAULT_AEROSOL_OPTICAL_DEPTH:Ws.opticalDepth(i))*Ot.aerosolDensity(this.siteElevationM+this.observerElevationM),s=this.cloudTransmission(t),r=-Math.log(Math.max(this.cloudTransmission(t,!0),1e-4)),o=ce.aureoleScale(n,ce.airMass(t.altitudeDeg))*s,c=ce.coronaScale(r),l=ce.illuminanceOf(t.magnitude),h=[t.altitudeDeg.toFixed(1),t.azimuthDeg.toFixed(1),t.magnitude.toFixed(2),o.toExponential(2),c.toExponential(2),Math.log10(Math.max(e.adaptation,1e-12)).toFixed(2)].join(":");if(h===this.lunarDiffractionKey)return;this.lunarDiffractionKey=h,this.lunarDiffraction||(this.lunarDiffraction=new M0,this.celestialGroup.add(this.lunarDiffraction.object));const u=ce.profile(ce.HAZE_COARSE_MODE),d=ce.profile(ce.CLOUD_DROPLETS),f=_p(t.altitudeDeg),p=new Float32Array(ce.STEPS*3);let v=0;for(let w=0;w<ce.STEPS;w++){const M=w*3,S=[0,1,2].map(T=>l*f[T]*(o*u[M+T]+c*d[M+T])),b=Rn.shown(S,Rn.luminanceOf(S),(T,x)=>e.relativeOfLuminance(T,x));p.set(b,M),v=Math.max(v,Rn.response(b))}const{x:m,y:g,z:_}=ni(t.altitudeDeg,t.azimuthDeg,1);this.lunarDiffraction.show(v>1/200?{x:m,y:g,z:_}:void 0,p)}applyAir(){this.scene.fog instanceof ya||(this.scene.fog=new ya),this.scene.fog.setAir(this.air,this.siteElevationM,this.airlight),this.horizonColour.setRGB(this.baseFogColor[0],this.baseFogColor[1],this.baseFogColor[2])}airlight=[0,0,0];horizonColour=new st(0,0,0);transmittanceTo(t,e,i){const n=this.camera.position;return this.air.transmittance(this.siteElevationM+n.y,this.siteElevationM+e,Math.hypot(t-n.x,e-n.y,i-n.z))}setSiteElevation(t){Math.abs(t-this.siteElevationM)<1||(this.siteElevationM=t,this.applyAir(),this.lastAstronomy&&this.scatteredSky?.update(this.scatteredSkyState(this.lastAstronomy)))}scatteredSkyState(t){return{altitudeM:this.siteElevationM+this.observerElevationM+1.6,sun:{altitudeDeg:t.sun.altitudeDeg,azimuthDeg:t.sun.azimuthDeg,magnitude:t.sun.magnitude},moon:{altitudeDeg:t.moon.altitudeDeg,azimuthDeg:t.moon.azimuthDeg,magnitude:t.moon.magnitude,phaseAngleDeg:Yt.phaseAngleOf(t.moon.phase.illuminatedFraction)}}}pumpScatteredSky(){const t=this.scatteredSky;!t||t.tables.ready||this.scatteredSkyFrameId!==null||this.contextReleased||(this.scatteredSkyFrameId=requestAnimationFrame(()=>{this.scatteredSkyFrameId=null,!this.contextReleased&&(t.advance(this.skyHoldUntilMs?Sb:_b),this.pumpScatteredSky())}))}cancelScatteredSkyPump(){this.scatteredSkyFrameId!==null&&(cancelAnimationFrame(this.scatteredSkyFrameId),this.scatteredSkyFrameId=null)}setSatellites(t){if(t.length===0&&!this.satelliteField?.count)return;this.satelliteField||(this.satelliteField=new Ow(Gh),this.celestialGroup.add(this.satelliteField.object));const e=qc(this.lastSunPosition?.altitudeDeg??-90,this.instrumentMagnitudeGain);this.satelliteField.set(t,e,i=>this.cloudTransmission(i),(i,n)=>this.arrivingIlluminance(i,n,1)),this.render()}pickSatelliteAt(t,e){if(!this.satelliteField?.count)return;this.aimAtScreenPoint(this.raycaster,t,e);const i=Math.cos(im*this.camera.fov*Math.PI/180),n=this.satelliteField.nearest(this.raycaster.ray.direction,i);return n&&this.groundHides(t,e)?void 0:n}updateCelestialLight(t,e){const i=this.relativeScale,n=t.sun.altitudeDeg>=Pc,s=!n&&t.moon.altitudeDeg>=Pc,r=n?t.sun:t.moon,o=[0,0,0],c=Math.max(0,Math.sin(Math.max(r.altitudeDeg,0)*Bi)),l=n||s?this.cloudTransmission(r):1,h=-Math.log(Math.max(l,1e-6)),u=Math.max(0,1/(1+.1125*h)-l),d=[0,0,0];if(n||s){const _=ce.illuminanceOf(r.magnitude)*i,w=this.air.transmittanceFromSpace(this.siteElevationM+this.observerElevationM,r.altitudeDeg);for(let T=0;T<3;T++)o[T]=_*w[T]*l,d[T]=_*w[T]*u*c,this.cloudBeam[T]=_*w[T];const{x:M,y:S,z:b}=ni(r.altitudeDeg,r.azimuthDeg,1);this.cloudBeamDirection.set(M,S,b)}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 _=this.skyCloudTransmission(),w=e.skyIrradiance,M=[0,1,2].map(b=>w[b]*_+d[b]);this.skyLight.color.setRGB(M[0],M[1],M[2]);const S=Vt.GROUND_ALBEDO;this.skyLight.groundColor.setRGB(S*(M[0]+o[0]*c),S*(M[1]+o[1]*c),S*(M[2]+o[2]*c))}if(this.skyLight.intensity=1,!n&&!s){this.celestialLight.intensity=0;return}const{x:p,y:v,z:m}=ni(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 D(0,1,0);placeShadowFrustum(){const t=this.lightDirection,e=this.celestialLight.shadow.camera,i=(e.right-e.left)/this.celestialLight.shadow.mapSize.x,n=this.shadowAxisX.crossVectors(this.shadowUp,t);n.lengthSq()<1e-8&&n.set(1,0,0),n.normalize();const s=this.shadowAxisY.crossVectors(t,n).normalize(),r=this.shadowWorld.set(this.bodyOrigin.x,0,this.bodyOrigin.z),o=l=>{const h=r.dot(l)/i;return(h-Math.round(h))*i},c=this.celestialLightTarget.position.set(0,0,0).addScaledVector(n,o(n)).addScaledVector(s,o(s));this.celestialLightTarget.updateMatrixWorld(),this.celestialLight.position.copy(c).addScaledVector(t,ln)}shadowUp=new D(0,1,0);shadowAxisX=new D;shadowAxisY=new D;shadowWorld=new D;skyCloudTransmission(){let t=this.cloudTransmission({altitudeDeg:90,azimuthDeg:0}),e=1;for(const i of[20,45,70]){const n=i*Bi,s=Math.sin(n)*Math.cos(n)*2;for(let r=0;r<360;r+=60)t+=s*this.cloudTransmission({altitudeDeg:i,azimuthDeg:r}),e+=s}return t/e}cloudBeam=[0,0,0];cloudBeamDirection=new D(0,1,0);get relativeScale(){return this.scatteredSky?.relativeScale??1/Et.semiSaturation(Et.DAYLIGHT_ANCHOR_CD_M2)}setMeteorShower(t,e,i){this.meteorSystem||(this.meteorSystem=new pi,this.celestialGroup.add(this.meteorSystem.object)),this.meteorSystem.setShower(t,e,i)}get meteorSchedule(){return this.meteorSystem?.schedule??[]}meteorMidpoint(t){return this.meteorSystem?.midpointOf(t)}updateMeteors(t){this.meteorSystem?.update(t)}setInstrument(t){this.projectionKind=t.projection;const e=ri.starPointsOf(t),i=ri.flareArtifactsOf(t);e===this.starPoints&&i===this.lensFlareArtifactIntensity||(this.starPoints=e,this.lensFlareArtifactIntensity=i,this.lensFlare&&(this.lensFlare.uniforms.uStarPoints.value=e,this.lensFlare.uniforms.uFlareIntensity.value=i),this.render())}setInstrumentGain(t,e=!1){this.instrumentMagnitudeGain=Number.isFinite(t)?t:0,this.scatteredSky?.setInstrument(e,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 t=this.compileOffThread().then(()=>{this.compiling===t&&(this.compiling=void 0,this.render())});this.compiling=t;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 t=this.renderer.compile(this.scene,this.camera);if(!this.renderer.extensions.get("KHR_parallel_shader_compile"))return Promise.resolve();const e=this.renderer.properties,i=performance.now()+Fe.COMPILE_WAIT_MS;return new Promise(n=>{const s=()=>{if(this.contextReleased)return n();for(const r of t){const o=e.get(r)?.currentProgram;(!o||o.isReady())&&t.delete(r)}t.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(t){if(this.animationsRunning){const e=this.lastFrameTimeMs===void 0?0:t-this.lastFrameTimeMs;this.lastFrameTimeMs=t,this.hasAnimations()&&this.animate(t,e);const i=this.resolution.ratioFor(t,e);i!==this.renderer.getPixelRatio()&&this.applyPixelRatio(i)}this.drawIfDirty()}refreshReflections(){this.reflections??=new Ji(this.renderer);const t=[...this.compassSprites,...this.lensFlare?[this.lensFlare.mesh]:[],...[...this.glareSprites.values()].map(s=>s.mesh)],e=[...this.starTiers.map(s=>s.points),...[...this.bodyMeshes.values()].filter(s=>s instanceof ds),...[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,t,[...this.decorGroups.values()],this.sceneVersion,e,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(t,e){const i=this.lastAstronomy;if(!i)return;this.probeIrradiance??=new uo;const n=[i.sun,i.moon].filter(s=>s.altitudeDeg>-2).map(s=>ni(s.altitudeDeg,s.azimuthDeg,1));this.probeIrradiance.measure(this.renderer,t,n,s=>{const r=d=>d.map(f=>f/e),o=this.surroundings,c={up:r(s.up),down:r(s.down)},l=(d,f)=>d.some((p,v)=>Math.abs(p-f[v])>.03*Math.max(Math.abs(p),Math.abs(f[v]),1e-12)),h=!o||l(o.up,c.up)||l(o.down,c.down);h&&(this.surroundings=c);const u=this.scatteredSky?.adaptToSurroundings(Math.exp(s.logAverage)/e)??!1;!h&&!u||(this.skyColoursStale=!0,this.render())})}lightUnderClouds(t){const e=this.surroundings;if(!e)return;const i=t.sun.altitudeDeg>=Pc?t.sun:t.moon.altitudeDeg>=Pc?t.moon:void 0;if(!i)return;const n=this.relativeScale/Math.PI;return{through:this.cloudTransmission(i),radiance:[e.up[0]*n,e.up[1]*n,e.up[2]*n]}}probeIrradiance;surroundings;animate(t,e){const i=Math.min(e/1e3,Gb);this.twinkleSeconds=t/1e3,this.updateTwinkle(this.twinkleSeconds),this.updatePrecipitation(t/1e3,i),this.updateRain(i),this.lensFlare&&(this.lensFlare.uniforms.uTime.value=t/1e3),this.developingExposure||(this.frameDirty=!0)}setMaxPixelRatio(t){this.resolution.maximum=t,this.renderer.getPixelRatio()>this.resolution.maximum&&this.applyPixelRatio(this.resolution.maximum)}applyPixelRatio(t){this.renderer.setPixelRatio(t),this.renderer.setSize(this.cssSize.width,this.cssSize.height,!1),this.frameDirty=!0}setExposure(t,e){const i=e?Math.max(1,Math.round(t)):1;if(i===this.exposureInstants&&(i===1||e===this.exposureInstantAt)){this.exposureInstantAt=e;return}this.exposureInstants=i,this.exposureInstantAt=e,i===1&&(this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0),this.render()}renderOnce(t){if(this.onMapSubjectBounds){const r=this.mapSubjectBounds();t?this.exposureSubjectBounds.push(...r):this.onMapSubjectBounds(r)}const e=this.usableEquidistantPass();this.phenomena.setCloudLayers(this.layeredClouds?.volumes??[]),this.phenomena.place(this.camera,(r,o,c)=>this.directionAtScreenPoint(r,o,c),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()),pn.uRodShare.value=this.scatteredSky?.rodShare??0,pn.uRelativeScale.value=this.relativeScale;const n=this.references.any||this.phenomena.any||this.compassSprites.some(r=>r.visible);pn.uHasOverlay.value=n?1:0;const s=n?r=>this.renderOverlayPasses(r):void 0;if(this.skyGlow?.setDestinationEncoded(!1),!e){this.updateLensFlarePosition();const r=this.usableDepthOfFieldPass();r?r.render(this.renderer,this.scene,this.camera,s,t):this.usableFinishPass().render(this.renderer,this.scene,this.camera,s,void 0,t);return}e.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(),t)}renderOverlayPasses(t=this.camera){this.renderReferencesPass(t),this.renderPhenomenaPass(t),this.renderHudPass(t)}renderHudPass(t){if(!this.compassSprites.some(n=>n.visible))return;const e=this.renderer.autoClear,i=this.renderer.shadowMap.autoUpdate;this.renderer.autoClear=!1,this.renderer.shadowMap.autoUpdate=!1,t.layers.set(Qp),this.renderer.render(this.scene,t),t.layers.set(0),this.renderer.autoClear=e,this.renderer.shadowMap.autoUpdate=i}renderReferencesPass(t){if(!this.references.any)return;const e=this.renderer.autoClear,i=this.renderer.shadowMap.autoUpdate;this.renderer.autoClear=!1,this.renderer.shadowMap.autoUpdate=!1,t.layers.set(_1),this.renderer.render(this.scene,t),t.layers.set(0),this.renderer.autoClear=e,this.renderer.shadowMap.autoUpdate=i}setReferences(t){this.references.set(t)}referenceAspect(t){return this.references.aspectOf(t)}directionAt(t,e){return this.directionAtScreenPoint(t,e,new D)}referenceFailedToLoad(t){return this.references.failedToLoad(t)}setReferencesShown(t){this.references.setShown(t),this.render()}setReferenceView(t,e){this.references.setView(t,e),this.render()}renderPhenomenaPass(t){if(!this.phenomena.any)return;const e=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&&Fe.markDecorDepth(s,n.kind!=="crop")}t.layers.set(Bh),this.scene.overrideMaterial=this.decorDepthMaterial,this.renderer.render(this.scene,t),this.scene.overrideMaterial=null,t.layers.set(y1),this.renderer.render(this.scene,t),t.layers.set(0),this.renderer.autoClear=e,this.renderer.shadowMap.autoUpdate=i}decorDepthMaterial=new gn({colorWrite:!1});static markDecorDepth(t,e){t.traverse(i=>{if(!(i instanceof Dt))return;const n=Array.isArray(i.material)?i.material[0]:i.material;e&&n.depthWrite!==!1&&n.blending!==Ci?i.layers.enable(Bh):i.layers.disable(Bh)})}startExposure(){this.cancelExposure(),this.exposureSubjectBounds=[];const t=this.renderer.getDrawingBufferSize(new Mt),e=Math.max(1,Math.round(t.x)),i=Math.max(1,Math.round(t.y));this.exposureAccumulation||(this.exposureAccumulation=new QS(e,i)),this.exposureAccumulation.resize(e,i),this.exposureAccumulation.open(this.renderer),this.exposureInstantsDone=0,this.exposureFrameId=requestAnimationFrame(()=>this.developExposure())}developExposure(){this.exposureFrameId=null;const t=this.exposureInstantAt,e=this.exposureAccumulation;if(!t||!e)return;const i=1/this.exposureInstants;this.resolution.beginDrawing();const n=performance.now()+Fe.EXPOSURE_BUDGET_MS,s=Fe.exposureInstantsPerFrame(e.instantTarget.scene.width*e.instantTarget.scene.height);let r=0;do{this.restateAt(t,this.exposureInstantsDone);const o=this.compassSprites.map(c=>c.visible);for(const c of this.compassSprites)c.visible=!1;try{this.renderOnce(e.instantTarget)}finally{this.compassSprites.forEach((c,l)=>{c.visible=o[l]})}e.add(this.renderer,i),this.exposureInstantsDone++,r++}while(this.exposureInstantsDone<this.exposureInstants&&performance.now()<n&&r<s);this.restateAt(t,0),this.presentExposure(),this.resolution.endDrawing(),this.exposureInstantsDone<this.exposureInstants&&(this.exposureFrameId=requestAnimationFrame(()=>this.developExposure()))}presentExposure(){if(pn.uRodShare.value=this.scatteredSky?.rodShare??0,pn.uHasOverlay.value=1,pn.uRelativeScale.value=this.relativeScale,this.exposureAccumulation?.develop(this.renderer,this.exposureInstants/this.exposureInstantsDone),this.onMapSubjectBounds?.(this.exposureSubjectBounds),!this.compassSprites.some(s=>s.visible))return;const t=new ys,e=new In(-1,1,1,-1,0,2),i=Lc/(rm*Math.tan(om*Bi/2));for(const s of this.compassSprites){if(!s.visible)continue;const r=s.getWorldPosition(new D).sub(this.camera.position).normalize(),o=this.screenPointOf(r);if(!o)continue;const c=new Fr(s.material);c.position.set(o.ndcX,o.ndcY,-1),c.scale.set(i/this.camera.aspect,i,1),t.add(c)}const n=this.renderer.autoClear;this.renderer.autoClear=!1;try{this.renderer.render(t,e)}finally{this.renderer.autoClear=n}}onMapSubjectBounds;exposureSubjectBounds=[];static MAP_SUBJECT_NEAREST_M=8;mapSubjectBounds(){const t=[],e=new Mn,i=new D,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||(e.setFromObject(r),e.isEmpty())||e.distanceToPoint(this.camera.position)<Fe.MAP_SUBJECT_NEAREST_M)continue;let o=1/0,c=-1/0,l=1/0,h=-1/0;for(const u of[e.min.x,e.max.x])for(const d of[e.min.y,e.max.y])for(const f of[e.min.z,e.max.z]){i.set(u,d,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),c=Math.max(c,v),l=Math.min(l,m),h=Math.max(h,m)}Number.isFinite(o)&&t.push({x:o,y:l,width:c-o,height:h-l})}return t}restateAt(t,e){this.restatingExposure=!0;try{t(e)}finally{this.restatingExposure=!1}}cancelExposure(){this.exposureFrameId!==null&&(cancelAnimationFrame(this.exposureFrameId),this.exposureFrameId=null)}setLensOptics(t){const e=this.lensOptics;this.lensOptics=t,(e===void 0!=(t===void 0)||e&&t&&(e.focalLengthMm!==t.focalLengthMm||e.fNumber!==t.fNumber||e.focusDistance!==t.focusDistance||e.frameHeightMm!==t.frameHeightMm))&&(t&&this.depthOfFieldPass&&this.depthOfFieldPass.setLens(t.focalLengthMm,t.fNumber,t.focusDistance,t.frameHeightMm),this.render())}usableDepthOfFieldPass(){const t=this.lensOptics;if(!t)return;const e=this.renderer.getDrawingBufferSize(new Mt),i=Math.max(1,Math.round(e.x)),n=Math.max(1,Math.round(e.y));return this.depthOfFieldPass||(this.depthOfFieldPass=new fo(i,n)),this.depthOfFieldPass.resize(i,n),this.depthOfFieldPass.setLens(t.focalLengthMm,t.fNumber,t.focusDistance,t.frameHeightMm),this.depthOfFieldPass}usableFinishPass(){const t=this.renderer.getDrawingBufferSize(new Mt);return this.finishPass?this.finishPass.resize(t.x,t.y):this.finishPass=new v0(t.x,t.y),this.finishPass}usableEquidistantPass(){if(this.projectionKind!=="equidistant")return;const t=this.renderer.getDrawingBufferSize(new Mt);return this.equidistantPass?this.equidistantPass.resize(t.x,t.y):this.equidistantPass=new mi(t.x,t.y),this.equidistantPass}aimAtScreenPoint(t,e,i){const n=this.projectionKind==="equidistant"?this.equidistantPass:void 0;if(!n){t.setFromCamera(new Mt(e,i),this.camera);return}const s=n.directionFor(e,i,this.camera.fov);this.camera.updateMatrixWorld(),t.ray.origin.setFromMatrixPosition(this.camera.matrixWorld),t.ray.direction.set(s.x,s.y,s.z).applyQuaternion(this.camera.quaternion).normalize(),t.camera=this.camera}pickCloudAt(t,e){return this.layeredClouds?.pickInstance(this.cloudDirectionAt(t,e))}cloudDirectionAt(t,e){return this.directionAtScreenPoint(t,e,new D)}directionAtScreenPoint(t,e,i){return this.aimAtScreenPoint(this.ufoOcclusionRaycaster,t,e),i.copy(this.ufoOcclusionRaycaster.ray.direction)}screenPointOf(t){this.camera.updateMatrixWorld();const e=this.screenPointScratch.copy(t).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 mi.ndcFor(e,this.camera.fov,n);if(e.z>=0)return;const s=Math.tan(this.camera.fov/2*Bi);return{ndcX:e.x/-e.z/(n*s),ndcY:e.y/-e.z/s}}screenPointScratch=new D;screenPointQuaternion=new sn;screenPointSize=new Mt;updateLensFlarePosition(){const t=this.lensFlare;if(!t)return;if(!this.sunVisible){t.mesh.visible=!1;return}if(this.camera.updateMatrixWorld(),this.lensFlareScratch.copy(this.sunWorldPosition).applyMatrix4(this.camera.matrixWorldInverse),this.lensFlareScratch.z>0){t.mesh.visible=!1;return}const e=this.sunVisibleFraction();if(e<=0){t.mesh.visible=!1;return}t.mesh.visible=!0,this.sunUnhiddenFraction=e,this.applyDazzleStrength();const i=this.lensFlareScratch.copy(this.sunWorldPosition).project(this.camera);t.uniforms.uLensPosition.value.set(i.x,i.y);const n=this.renderer.domElement.width,s=this.renderer.domElement.height;t.uniforms.uResolution.value.set(n,s),t.uniforms.uTanHalfFov.value=Math.tan(this.camera.fov*Math.PI/360)}renderDazzleOnResample(){const t=this.lensFlare;if(!t||!this.sunVisible)return;const e=this.sunVisibleFraction();if(e<=0)return;this.sunUnhiddenFraction=e,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);t.uniforms.uLensPosition.value.set(i.ndcX,i.ndcY),t.uniforms.uResolution.value.set(n.x,n.y),t.uniforms.uEquidistant.value=1,t.uniforms.uHalfFovRad.value=this.camera.fov*Math.PI/360;const s=this.renderer.autoClear;this.renderer.autoClear=!1,t.mesh.visible=!0,t.mesh.layers.enable(jp),this.camera.layers.set(jp),this.renderer.render(this.scene,this.camera),this.camera.layers.set(0),t.mesh.visible=!1,t.uniforms.uEquidistant.value=0,this.renderer.autoClear=s}sunVisibleFraction(){this.raycastableDecor().length>0&&this.scene.updateMatrixWorld();let t=0;for(const e of lm)this.isSunOccluded(e[0],e[1])||t++;return t/lm.length}raycastableDecor(){const t=[];for(const e of this.decorObjects){if(e.kind==="crop")continue;const i=this.decorGroups.get(e.id);i&&t.push(i)}return t}isSunOccluded(t=0,e=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(),t!==0||e!==0){const o=Math.PI/180,c=this.sunOcclusionRightScratch.set(n.z,0,-n.x);c.lengthSq()<1e-9&&c.set(1,0,0),c.normalize();const l=this.sunOcclusionUpScratch.crossVectors(c,n).normalize();n.addScaledVector(c,t*o).addScaledVector(l,e*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(t,e,i,n=0){const s=this.groundMesh;if(s&&e.y<0){const m=(s.position.y-t.y)/e.y;if(m>n&&m<i){const g=t.x+e.x*m-s.position.x,_=t.z+e.z*m-s.position.z;if(Math.hypot(g,_)<=this.groundRadius)return!0}}const r=this.terrainMesh;if(!r)return!1;const o=r.geometry.getAttribute("position"),c=Math.round(Math.sqrt(o.count));if(c<2||c*c!==o.count)return!1;const l=[r.position.x+o.getX(0),r.position.x+o.getX(c-1)],h=[r.position.z+o.getZ(0),r.position.z+o.getZ((c-1)*c)],u=Math.min(Math.abs(l[1]-l[0]),Math.abs(h[1]-h[0]))/(c-1);if(!(u>0))return!1;let d=n,f=i;for(const[m,g,_]of[[t.x,e.x,l],[t.z,e.z,h]]){const w=Math.min(_[0],_[1]),M=Math.max(_[0],_[1]);if(Math.abs(g)<1e-12){if(m<w||m>M)return!1;continue}const S=(w-m)/g,b=(M-m)/g;d=Math.max(d,Math.min(S,b)),f=Math.min(f,Math.max(S,b))}if(!(f>d))return!1;const p=Math.hypot(e.x,e.z),v=Math.min(4096,Math.max(8,Math.ceil((f-d)*p/(u/2))));for(let m=0;m<=v;m++){const g=d+(f-d)*m/v,_=t.x+e.x*g,w=t.y+e.y*g,M=t.z+e.z*g;if(w<=this.groundYUnder(_,M))return!0}return!1}setPhenomena(t,e){this.phenomena.set(t,e)}decorDistancesAt(t,e,i){this.aimAtScreenPoint(this.ufoOcclusionRaycaster,t,e),this.ufoOcclusionRaycaster.near=tm;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 c=this.ufoOcclusionRaycaster.intersectObject(o,!0)[0];c&&(r.occludesSourceIds?.includes(i)?n=n===void 0?c.distance:Math.max(n,c.distance):s=s===void 0?c.distance:Math.min(s,c.distance))}return{behindM:n,inFrontM:s}}pickBodyAt(t,e){this.aimAtScreenPoint(this.raycaster,t,e);const i=[...this.hitAreas.entries()],n=this.raycaster.intersectObjects(i.map(([,s])=>s))[0];if(n&&!this.groundHides(t,e))return i.find(([,s])=>s===n.object)?.[0]}pickStarAt(t,e){if(this.namedStars.length===0)return;this.aimAtScreenPoint(this.raycaster,t,e);const i=this.raycaster.ray.direction,n=Math.cos(im*this.camera.fov*Math.PI/180);let s,r=n;for(const o of this.namedStars){const c=o.direction.dot(i);c>r&&(r=c,s={star:o.star,altitudeDeg:o.altitudeDeg})}return s&&this.groundHides(t,e)?void 0:s}groundHides(t,e){if(!this.terrainMesh&&!this.groundMesh)return!1;this.aimAtScreenPoint(this.ufoOcclusionRaycaster,t,e);const i=this.ufoOcclusionRaycaster.ray;return this.groundBlocks(i.origin,i.direction,1/0,tm)}pickDecorAt(t,e){this.aimAtScreenPoint(this.raycaster,t,e);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.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 t of this.bodyMeshes.values())this.disposeMesh(t);this.bodyMeshes.clear(),this.novaKeys.clear();for(const t of[...this.hitAreas.keys()])this.disposeHitArea(t);for(const t of[...this.glareSprites.keys()])this.disposeGlare(t);this.disposeCompassLabels();for(const t of this.decorGroups.values())vi.dispose(t);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 t=e=>{this.frame(e),this.animationFrameId=requestAnimationFrame(t)};this.animationFrameId=requestAnimationFrame(t)}setAnimationsRunning(t,e=!1){const i=t&&e;if(t===this.animationsRunning&&i===this.framesDriven)return;const n=this.animationsRunning;this.animationsRunning=t,this.framesDriven=i,t&&!n&&(this.lastFrameTimeMs=void 0,this.resolution.reset()),!t&&this.renderer.getPixelRatio()!==this.resolution.maximum&&this.applyPixelRatio(this.resolution.maximum),this.syncAnimationLoop(),(!t||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(t){const e=this.skyMesh?.geometry??new Qe(Cc,32,16),i=e.attributes.position,n=e.getAttribute("color")??new _e(new Float32Array(i.count*3),3);for(let r=0;r<i.count;r++){const{altitudeDeg:o,azimuthDeg:c}=i5(i.getX(r),i.getY(r),i.getZ(r)),l=h5(o,c,t.azimuthDeg,t.altitudeDeg);n.setXYZ(r,l[0],l[1],l[2])}if(n.needsUpdate=!0,this.skyMesh)return;e.setAttribute("color",n);const s=new gn({vertexColors:!0,side:Ue,fog:!1,depthWrite:!1});this.skyGradientMaterial=s,this.skyMesh=new Dt(e,s),this.skyMesh.renderOrder=-1,this.celestialGroup.add(this.skyMesh)}buildGround(){const t=em(this.observerElevationM);if(this.groundMesh&&t===this.groundRadius)return;this.disposeMesh(this.groundMesh),this.groundRadius=t;const e=new Zd(this.groundRadius,48),i=new Er({color:new st(Hh,Hh,Hh),fog:!0});ya.fadeRim(i,this.groundRadius*.75,this.groundRadius,this.horizonColour),this.groundMesh=new Dt(e,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 t=this.groundMesh?.material;if(!t)return;const e=this.terrainMesh===void 0;t.depthWrite!==e&&(t.depthWrite=e,t.needsUpdate=!0)}cloudTransmission(t,e=!1){const i=`${t.altitudeDeg.toFixed(1)}:${t.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(";")+(e?":water":""),n=this.cloudTransmissionMemo.get(i);if(n!==void 0)return n;this.cloudTransmissionMemo.size>256&&this.cloudTransmissionMemo.clear();const s=this.computeCloudTransmission(t,e);return this.cloudTransmissionMemo.set(i,s),s}cloudTransmissionMemo=new Map;computeCloudTransmission(t,e=!1){const i=ni(t.altitudeDeg,t.azimuthDeg,1);if(this.layeredClouds)return this.layeredClouds.transmissionAt(i,e);let n=1;const s=this.lowerCloudCover();s>0&&(n*=1-he.alphaAt(i,Math.abs(this.cloudLayerOffset()),s,this.cloudFieldOffset)*mb);const r=e?0:this.weather.highCloudCover??0;return r>0&&(n*=1-he.iceAlphaAt(i,Ic,r,this.cloudFieldOffset)*gb),Math.max(0,Math.min(1,n))}setBodyMesh(t,e,i,n,s){if(e.altitudeDeg<Dd){this.disposeMesh(this.bodyMeshes.get(t)),this.bodyMeshes.delete(t),this.disposeHitArea(t),this.disposeGlare(t),t==="sun"&&(this.sunVisible=!1);return}const{x:r,y:o,z:c}=ni(e.altitudeDeg,e.azimuthDeg,ln),l=_p(e.altitudeDeg),h=this.cloudTransmission(e),u=this.arrivingIlluminance(e,s,h),d=Fe.unitLuminance(n);let f=this.bodyMeshes.get(t);if(t==="sun"){const p=Math.PI*(i/ln)**2,v=[0,1,2].map(m=>Math.min(Fe.BRIGHTEST_RELATIVE,d[m]*u[m]/p));f instanceof Dt||(this.disposeMesh(f),f=new Dt(new Qe(1,16,16),new gn({fog:!1})),this.celestialGroup.add(f),this.bodyMeshes.set(t,f)),f.material.color.setRGB(v[0],v[1],v[2]),f.scale.setScalar(i)}else{if(!(f instanceof ds)){this.disposeMesh(f);const m=new ue;m.setAttribute("position",new te(new Float32Array(3),3)),m.setAttribute("color",new te(new Float32Array(3),3)),f=new ds(m,Oe.material(ho[ho.length-1].size)),Oe.track(f),this.celestialGroup.add(f),this.bodyMeshes.set(t,f)}const p=f.geometry.getAttribute("color"),v=t.startsWith("comet:")?this.pointToPixel():1;p.setXYZ(0,d[0]*u[0]*v,d[1]*u[1]*v,d[2]*u[2]*v),p.needsUpdate=!0}if(f.position.set(r,o,c),this.setHitArea(t,r,o,c,i),t==="sun"&&(this.sunArriving=u),t.startsWith("comet:")?this.disposeGlare(t):t!=="sun"&&this.setGlare(t,r,o,c,u,i/ln*(180/Math.PI),Fe.POINT_VEIL_HOLD_DEG),t==="sun"){this.sunVisible=!0;const p=this.celestialGroup.scale.x;this.sunWorldPosition.set(r*p,o*p+this.celestialGroup.position.y,c*p),this.lensFlare||(this.lensFlare=Nw(),this.lensFlare.uniforms.uOpacity.value=Tb,this.lensFlare.uniforms.uFlareIntensity.value=this.lensFlareArtifactIntensity,this.lensFlare.uniforms.uStarPoints.value=this.starPoints,this.scene.add(this.lensFlare.mesh)),this.applyLensFlareTint(l)}}setMoonMesh(t,e){const i="moon";if(t.magnitude>e||t.altitudeDeg<Dd){this.disposeMesh(this.bodyMeshes.get(i)),this.bodyMeshes.delete(i),this.disposeHitArea(i),this.disposeGlare(i);return}const{x:n,y:s,z:r}=ni(t.altitudeDeg,t.azimuthDeg,ln),o=this.cloudTransmission(t),c=this.arrivingIlluminance(t,t.magnitude,o),l=Math.max(or(t.phase.illuminatedFraction,0,1),.01)*Math.PI*($r/ln)**2,h=new st(...c.map(f=>Math.min(Fe.BRIGHTEST_RELATIVE,f/l))),u=`${t.phase.phaseFraction<.5}:${Math.round(or(t.phase.illuminatedFraction,0,1)*500)}`;let d=this.bodyMeshes.get(i);if(d instanceof Fr)d.userData.phaseKey!==u&&(d.material.map?.dispose(),d.material.map=Rm(t.phase),d.userData.phaseKey=u),d.material.color.copy(h);else{this.disposeMesh(d),d=new Fr(new Wc({map:Rm(t.phase),color:h,fog:!1})),d.userData.phaseKey=u;const f=$r*2;d.scale.set(f,f,1),this.celestialGroup.add(d),this.bodyMeshes.set(i,d)}d.position.set(n,s,r),this.setHitArea(i,n,s,r,$r),this.setGlare(i,n,s,r,c,$r/ln*(180/Math.PI))}bentLight(t,e,i=fb){const[n,s,r]=this.arrivingIlluminance(t,e,1),o=Math.max(s,1e-30);return{scale:s/i,tint:[n/o,1,r/o]}}static litBySky(t,e){return Fe.litScratch.setRGB(t.r*e[0],t.g*e[1],t.b*e[2])}static litScratch=new st;pointToPixel(){const t=Math.max(1,this.renderer.getDrawingBufferSize(this.pointScratch).y),e=(this.camera.fov*Math.PI/180/t)**2;return Math.min(1,Oe.CONE_SOLID_ANGLE/e)}pointScratch=new Mt;static POINT_VEIL_HOLD_DEG=.25;static BRIGHTEST_RELATIVE=6e4;arrivingIlluminance(t,e,i){const n=this.air.transmittanceFromSpace(this.siteElevationM+this.observerElevationM,t.altitudeDeg),s=ce.illuminanceOf(e)*i*this.relativeScale;return[n[0]*s,n[1]*s,n[2]*s]}static unitLuminance(t){const e=Rn.luminanceOf([t.r,t.g,t.b]);return e>0?[t.r/e,t.g/e,t.b/e]:[1,1,1]}setHitArea(t,e,i,n,s){let r=this.hitAreas.get(t);if(!r){const c=new Wc({transparent:!0,opacity:0,depthTest:!1,depthWrite:!1,fog:!1});r=new Fr(c),this.celestialGroup.add(r),this.hitAreas.set(t,r)}r.position.set(e,i,n);const o=s*db;r.scale.set(o,o,1)}disposeHitArea(t){const e=this.hitAreas.get(t);e&&(e.removeFromParent(),e.material.dispose(),this.hitAreas.delete(t))}setGlare(t,e,i,n,s,r,o=0){if(Ui.radiusDeg(Ui.K*Math.max(...s))<=Math.max(r,o)){this.disposeGlare(t);return}let c=this.glareSprites.get(t);c||(c=new Ui(`veil:${t}`),this.celestialGroup.add(c.mesh),this.glareSprites.set(t,c)),c.shine({x:e,y:i,z:n},s,r,o)}disposeGlare(t){const e=this.glareSprites.get(t);e&&(e.mesh.removeFromParent(),e.dispose(),this.glareSprites.delete(t))}buildComet(t,e){const i=t&&`comet:${t.id}`;if(!t||!i||t.magnitude>e){this.disposeComet();return}this.cometKey&&this.cometKey!==i&&this.disposeComet();const n=eo(t.magnitude,e),s=Rh(n);this.cometKey=i,this.setBodyMesh(i,t.position,Wh*(.5+.5*n),new st(s,s,s),t.magnitude),this.cometTail||(this.cometTail=new Zi(ln),this.celestialGroup.add(this.cometTail.object)),this.cometTail.set(t.position,t.tailEnd,n)}buildIceHalos(t,e){this.iceHalos||(this.iceHalos=new Ti,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:Ic},0);return}const s=this.lowerCloudCover(),r=le.deckLitUntilDeg(le.DECK_HEIGHT_M),o=t.altitudeDeg>-r?t:e,c=this.bentLight(o,o===t?ii.SUN_MAGNITUDE:e.magnitude),l=le.strength(i,s,o.altitudeDeg,r)*c.scale,{x:h,y:u,z:d}=ni(o.altitudeDeg,o.azimuthDeg,1);this.iceHalos.update({x:h,y:u,z:d},o.altitudeDeg,l,c.tint,{cover:n?.cover??i,layerHeight:n?.layerHeight??Ic},n?.iceCrystalAlignment??this.weather.iceCrystalAlignment??.65)}buildRainbow(t,e){this.rainbow||(this.rainbow=new ga,this.celestialGroup.add(this.rainbow.object));const i=this.weather.precipitationType==="rain"?this.weather.precipitationIntensity:0,n=t.altitudeDeg>0,s=n?t:e,r=this.lowerCloudCover(),o=this.bentLight(s,n?ii.SUN_MAGNITUDE:e.magnitude,pb),c=$i.strength(i,r,s.altitudeDeg)*o.scale;if(c<=0){this.rainbow.update({x:0,y:1,z:0},0,[1,1,1],!0);return}const{x:l,y:h,z:u}=ni(s.altitudeDeg,s.azimuthDeg,1);this.rainbow.update({x:l,y:h,z:u},c,o.tint,n)}buildSkyGlow(t,e){if(!t.frame){this.skyGlow?.hide();return}this.skyGlow||(this.skyGlow=new Us,this.skyGlow.onReady=()=>this.render(),this.celestialGroup.add(this.skyGlow.object));const{date:i,observer:n}=t.frame,s=wn.galactic(i,n),r=Fe.directionOf(s.centre),o=Fe.directionOf(s.rotation),c=Fe.directionOf(s.pole),l=new Xt().set(r.x,r.y,r.z,o.x,o.y,o.z,c.x,c.y,c.z),h=Fe.directionOf(wn.eclipticPole(i,n)),u=Fe.directionOf(t.sun),d=u.clone().addScaledVector(h,-u.dot(h)).normalize();this.skyGlow.update({galactic:l,eclipticPole:h,sunLongitude:d,sunDirection:u,sunAltitudeDeg:t.sun.altitudeDeg,moon:{direction:Fe.directionOf(t.moon),altitudeDeg:t.moon.altitudeDeg,phaseAngleDeg:Yt.phaseAngleOf(t.moon.phase.illuminatedFraction)},skyColor:new D(e[0],e[1],e[2])})}static directionOf(t){const{x:e,y:i,z:n}=ni(t.altitudeDeg,t.azimuthDeg,1);return new D(e,i,n).normalize()}buildNovae(t,e){const i=new Set;for(const n of t){if(n.magnitude>e)continue;const s=`nova:${n.id}`;i.add(s);const r=eo(n.magnitude,e),o=Rh(r);this.setBodyMesh(s,n.position,Wh*(.5+.5*r),new st(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(t,e){const i=new Set(["sun","moon",...this.cometKey?[this.cometKey]:[],...this.novaKeys]);for(const n of t){if(n.magnitude>e)continue;i.add(n.body);const s=eo(n.magnitude,e),r=Rh(s),o=qb[n.body]??new st(1,1,1),c=new st(o.r*r,o.g*r,o.b*r),l=Wh*(.5+.5*s);this.setBodyMesh(n.body,n.position,l,c,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(t,e){if(this.namedStars=[],!t||t.catalog.count===0){this.disposeStarTiers(),this.syncAnimationLoop();return}const{catalog:i,date:n,observer:s}=t,r=new An(n,s),o=jh(1337),c=[],l=this.siteElevationM+this.observerElevationM;for(let h=0;h<i.count;h++){const u=i.mag[h];if(u>e)break;const{altitudeDeg:d,azimuthDeg:f}=r.position(i.ra[h],i.dec[h]);if(d<nm)continue;const{x:p,y:v,z:m}=ni(d,f,Gh);c.push({x:p,y:v,z:m,brightness:eo(u,e),illuminance:this.air.transmittanceFromSpace(l,d).map(g=>g*ce.illuminanceOf(u)),phase:o()*Math.PI*2,speedFactor:.7+o()*.6})}for(const h of mw){if(h.mag>e)continue;const{altitudeDeg:u,azimuthDeg:d}=r.position(h.raHours,h.decDeg);if(u<nm)continue;const{x:f,y:p,z:v}=ni(u,d,Gh);this.namedStars.push({star:h,direction:new D(f,p,v).normalize(),altitudeDeg:u})}this.starTiers=ho.map((h,u)=>{const d=c.filter(S=>Wg(S.brightness)===u),f=new Float32Array(d.length*3),p=new Float32Array(d.length),v=new Float32Array(d.length*3),m=new Float32Array(d.length),g=new Float32Array(d.length);d.forEach((S,b)=>{f[b*3]=S.x,f[b*3+1]=S.y,f[b*3+2]=S.z,p[b]=S.brightness,v.set(S.illuminance,b*3),m[b]=S.phase,g[b]=S.speedFactor});const _=new ue;_.setAttribute("position",new te(f,3));const w=new te(new Float32Array(d.length*3),3);_.setAttribute("color",w);let M=this.starTiers[u]?.points;return M?(M.geometry.dispose(),M.geometry=_):(M=new ds(_,Oe.material(h.size)),Oe.track(M),this.celestialGroup.add(M)),{points:M,colorAttribute:w,brightness:p,illuminance:v,phase:m,speedFactor:g}}),this.updateTwinkle(0),this.startTwinkle()}twinkleSeconds=0;updateTwinkle(t){const e=this.relativeScale;for(const i of this.starTiers){const n=i.colorAttribute.array;for(let s=0;s<i.brightness.length;s++){const r=m5(i.brightness[s],{phase:i.phase[s],speedFactor:i.speedFactor[s]},t),o=e*r;n[s*3]=i.illuminance[s*3]*o,n[s*3+1]=i.illuminance[s*3+1]*o,n[s*3+2]=i.illuminance[s*3+2]*o}i.colorAttribute.needsUpdate=!0}}buildClouds(){if(this.cloudRendering==="volume"||this.weather.cloudLayers!==void 0){this.layeredClouds||(this.disposeCloudSystem(),this.layeredClouds=new fr(this.celestialGroup,Xh,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 t=this.lowerCloudCover();if(t<=0){this.disposeCloudSystem();return}const e=this.weather.cloudDarkness,i=new st(aa[0]+(Kh[0]-aa[0])*e,aa[1]+(Kh[1]-aa[1])*e,aa[2]+(Kh[2]-aa[2])*e);if(this.cloudMesh&&this.cloudUniforms){this.cloudUniforms.coverage.value=t,this.cloudUniforms.baseColor.value.copy(i),this.syncCloudLayer(),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);return}this.disposeCloudSystem();const{material:n,uniforms:s}=ed(i,t,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=id(Xh);this.cloudMesh=new Dt(r,n),this.faceCloudDeck(this.cloudMesh,this.cloudLayerOffset()),this.celestialGroup.add(this.cloudMesh)}lowerCloudCover(){return this.weather.cloudLayers?1-this.weather.cloudLayers.filter(t=>t.type!=="cirrus").reduce((t,e)=>t*(1-e.coverage),1):this.weather.lowerCloudCover??this.weather.cloudCover}highCloudCover(){return this.weather.cloudLayers?1-this.weather.cloudLayers.filter(t=>t.type==="cirrus").reduce((t,e)=>t*(1-e.coverage),1):this.weather.highCloudCover}buildCirrus(){const t=this.weather.highCloudCover??0;if(this.layeredClouds||t<=0){this.disposeCirrus();return}if(this.cirrusMesh&&this.cirrusUniforms){this.cirrusUniforms.coverage.value=t,this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);return}const{material:e,uniforms:i}=ed(new st(...aa),t,Ic,1);this.cirrusMaterial=e,this.cirrusUniforms=i,i.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor),this.cirrusMesh=new Dt(id(Xh*1.04),e),this.cirrusMesh.renderOrder=hm-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 t=this.cloudLayerOffset();this.cloudUniforms&&(this.cloudUniforms.layerHeight.value=Math.abs(t)),this.cloudMesh&&this.faceCloudDeck(this.cloudMesh,t)}faceCloudDeck(t,e){const i=e<0;t.scale.y=i?-1:1,t.renderOrder=i?fr.deckOrder(!0,0,1):hm}cloudLayerOffset(){const e=((this.weather.cloudBaseM??1e3)-this.observerElevationM)*qh;return Math.sign(e||1)*Math.max(Math.abs(e),Db)}updateCloudLighting(t,e){const i=[this.cloudUniforms,this.cirrusUniforms].filter(u=>u!==void 0);if(i.length===0&&!this.layeredClouds)return;const n=this.cloudBeamDirection,[s,r,o]=this.cloudBeam.map(u=>u/Math.PI),c=this.lightningLevel*Jh*this.relativeScale/Math.PI,l=new st(e[0]+zn.r*c,e[1]+zn.g*c,e[2]+zn.b*c);this.layeredClouds?.setLighting(n.clone(),new st(s,r,o),l,l);const h=Math.max(0,n.y);for(const u of i)u.sunDir.value.copy(n),u.sunColor.value.setRGB(s*h,r*h,o*h),u.ambientColor.value.copy(l)}disposeCloudSystem(){this.layeredClouds?.dispose(),this.layeredClouds=void 0,this.cloudMesh&&(this.cloudMesh.removeFromParent(),this.cloudMesh.geometry.dispose()),this.cloudMaterial?.dispose(),this.cloudMesh=void 0,this.cloudMaterial=void 0,this.cloudUniforms=void 0}disposePrecipitationPoints(){this.precipitationPoints&&(this.precipitationPoints.removeFromParent(),this.precipitationPoints.geometry.dispose(),this.precipitationPoints.material.dispose()),this.precipitationPoints=void 0,this.precipitationPositions=void 0,this.precipitationPhase=void 0,this.precipitationSpeedJitter=void 0,this.precipitationWobbleFreqJitter=void 0,this.precipitationWobbleAmpJitter=void 0,this.precipitationBounceRemaining=void 0,this.precipitationBounceHeight=void 0,this.precipitationBounceDuration=void 0,this.precipitationBounceVelX=void 0,this.precipitationBounceVelZ=void 0,this.precipitationUniforms=void 0}buildPrecipitation(){this.disposePrecipitationPoints(),this.disposeRain();const t=this.weather.precipitationType;if(t==="none")return;if(t==="rain"){this.buildRain();return}const e=um[t],i=e.poolSize,n=jh(9001),s=new Float32Array(i*3),r=new Float32Array(i),o=new Float32Array(i),c=new Float32Array(i),l=new Float32Array(i),h=new Float32Array(i),u=new Float32Array(i),d=new Float32Array(i),f=new Float32Array(i),p=new Float32Array(i);for(let w=0;w<i;w++){const M=n()*Math.PI*2,S=n()*e.radiusM;s[w*3]=Math.cos(M)*S,s[w*3+1]=er+n()*(e.topYM-er),s[w*3+2]=Math.sin(M)*S,r[w]=n()*Math.PI*2,o[w]=.7+n()*.6,c[w]=.6+n()*.8,l[w]=.4+n()*1.2}const v=new ue;v.setAttribute("position",new te(s,3)),v.setDrawRange(0,Zh(i,this.weather.precipitationIntensity));const m={uSize:{value:e.size},uScale:{value:.5*this.renderer.domElement.height},uOpacity:{value:e.opacity},uColor:{value:e.color.clone()},uHazeColor:{value:new st(...this.baseFogColor)},uTexture:{value:Yb(t)},uNearFocusDistance:{value:ym},uHazeDistance:{value:e.radiusM*_m}},g=new ae({uniforms:m,vertexShader:Qb,fragmentShader:tE,transparent:!0,depthWrite:!1});this.precipitationUniforms=m;const _=new ds(v,g);_.renderOrder=Yh,this.scene.add(_),this.precipitationPoints=_,this.precipitationPositions=s,this.precipitationPhase=r,this.precipitationSpeedJitter=o,this.precipitationWobbleFreqJitter=c,this.precipitationWobbleAmpJitter=l,this.precipitationBounceRemaining=h,this.precipitationBounceHeight=u,this.precipitationBounceDuration=d,this.precipitationBounceVelX=f,this.precipitationBounceVelZ=p}updatePrecipitation(t,e){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=um[i];if(this.precipitationUniforms?.uColor.value.copy(Fe.litBySky(n.color,this.baseFogColor)),e<=0)return;const s=this.weather.windDirectionDeg*Bi,r=Math.sin(s)*this.weather.windSpeed*n.driftSensitivity,o=-Math.cos(s)*this.weather.windSpeed*n.driftSensitivity,c=this.precipitationPositions,l=this.precipitationPhase,h=this.precipitationSpeedJitter,u=this.precipitationWobbleFreqJitter,d=this.precipitationWobbleAmpJitter,f=this.precipitationBounceRemaining,p=this.precipitationBounceHeight,v=this.precipitationBounceDuration,m=this.precipitationBounceVelX,g=this.precipitationBounceVelZ,_=i==="snow"&&u&&d,w=i==="hail"&&f&&p&&v&&m&&g;for(let M=0,S=0;M<c.length;M+=3,S++){if(w&&f[S]>0){if(f[S]-=e,f[S]<=0){const x=Math.random()*Math.PI*2,A=Math.sqrt(Math.random())*n.radiusM;c[M]=Math.cos(x)*A,c[M+1]=n.topYM,c[M+2]=Math.sin(x)*A,f[S]=0}else{const x=1-f[S]/v[S];c[M+1]=er+Math.sin(Math.PI*x)*p[S],c[M]=Nc(c[M]+(r+m[S])*e,n.radiusM),c[M+2]=Nc(c[M+2]+(o+g[S])*e,n.radiusM)}continue}let b=0,T=0;if(_){const x=kb*u[S],A=zb*d[S];b=Math.sin(t*x*Math.PI*2+l[S])*A,T=Math.sin(t*x*Math.PI*2+l[S]+Math.PI/2)*A}if(c[M]+=(r+b)*e,c[M+1]-=n.fallSpeedMPerS*h[S]*e,c[M+2]+=(o+T)*e,c[M]=Nc(c[M],n.radiusM),c[M+2]=Nc(c[M+2],n.radiusM),c[M+1]<er){if(w){p[S]=Am*(.2+Math.random()*1.6),v[S]=Bb*(.5+Math.random()),f[S]=v[S];const I=Math.random()*Math.PI*2,C=Hb*(p[S]/Am);m[S]=Math.cos(I)*C,g[S]=Math.sin(I)*C,c[M+1]=er;continue}const x=Math.random()*Math.PI*2,A=Math.sqrt(Math.random())*n.radiusM;c[M]=Math.cos(x)*A,c[M+1]=n.topYM,c[M+2]=Math.sin(x)*A}}this.precipitationPoints.geometry.attributes.position.needsUpdate=!0}buildRain(){const t=mm(this.weather.precipitationIntensity);this.rainSystem=Cw({count:dm,radiusM:Zr,heightM:Ib,bottomYM:fm,overallSpeed:Pb,color:gm.clone(),opacity:.85,visibleCount:Zh(dm,this.weather.precipitationIntensity),speedStreak:Ub(t),pixelSize:wm,seed:9001,nearFocusDistanceM:ym,hazeDistanceM:Zr*_m,hazeColor:new st(...this.baseFogColor)}),this.rainLastVerticalFacing=-1,this.syncRainSlant(),this.rainSystem.points.renderOrder=Yh,this.scene.add(this.rainSystem.points),this.buildRainSplashes()}buildRainSplashes(){const t=jh(4242),e=new Float32Array(ja*3),i=new Float32Array(ja),n=new Float32Array(ja),s=new Float32Array(ja);for(let h=0;h<ja;h++){const u=t()*Math.PI*2,d=Math.sqrt(t())*Zr;e[h*3]=Math.cos(u)*d,e[h*3+1]=fm,e[h*3+2]=Math.sin(u)*d,n[h]=Tm(vm,Mm),i[h]=t()*n[h],s[h]=i[h]/n[h]}const r=new ue;r.setAttribute("position",new te(e,3));const o=new te(s,1);r.setAttribute("aLife",o),r.setDrawRange(0,Zh(ja,this.weather.precipitationIntensity));const c=new ae({uniforms:{uMaxSize:{value:Fb},uScale:{value:.5*this.renderer.domElement.height},uColor:{value:xm.clone()},uTexture:{value:Zb()}},vertexShader:Jb,fragmentShader:jb,transparent:!0,depthWrite:!1}),l=new ds(r,c);l.renderOrder=Yh,this.scene.add(l),this.rainSplashSystem={points:l,positions:e,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 t=this.rainSystem;if(!t)return;const e=this.weather.windDirectionDeg*Bi;t.uniforms.uDropVelocity.value.set(Math.sin(e)*this.weather.windSpeed,-mm(this.weather.precipitationIntensity),-Math.cos(e)*this.weather.windSpeed);const i=this.renderer.getSize(this.rainViewportSize);t.uniforms.uAspect.value=i.x/Math.max(i.y,1)}updateRain(t){const e=this.rainSystem;if(!e)return;e.uniforms.uTime.value+=t,e.uniforms.uHazeColor.value.setRGB(...this.baseFogColor),e.uniforms.uColor.value.copy(Fe.litBySky(gm,this.baseFogColor));const i=this.rainSplashSystem?.points.material?.uniforms?.uColor;i&&i.value.copy(Fe.litBySky(xm,this.baseFogColor));const n=this.weather.windDirectionDeg*Bi,s=Math.sin(n)*this.weather.windSpeed,r=-Math.cos(n)*this.weather.windSpeed,o=Zr,c=h=>(h%(o*2)+o*3)%(o*2)-o;e.uniforms.uWindOffset.value.set(c(e.uniforms.uWindOffset.value.x+s*t),c(e.uniforms.uWindOffset.value.y+r*t)),this.syncRainSlant(),this.camera.getWorldDirection(this.rainCameraDirection);const l=Math.abs(this.rainCameraDirection.y);if(Math.abs(l-this.rainLastVerticalFacing)>.001){this.rainLastVerticalFacing=l;const h=bm+(1-bm)*(1-l),u=Em+(1-Em)*(1-l);e.uniforms.uUvSquash.value=u,e.uniforms.uPixelSize.value=wm*h*(.5+.5*u)}this.updateRainSplashes(t)}updateRainSplashes(t){const e=this.rainSplashSystem;if(!e||t<=0)return;const{positions:i,life:n,duration:s,lifeAttribute:r}=e,o=r.array;for(let c=0,l=0;c<i.length;c+=3,l++){if(n[l]+=t,n[l]>=s[l]){const h=Math.random()*Math.PI*2,u=Math.sqrt(Math.random())*Zr;i[c]=Math.cos(h)*u,i[c+2]=Math.sin(h)*u,s[l]=Tm(vm,Mm),n[l]=0}o[l]=n[l]/s[l]}e.points.geometry.attributes.position.needsUpdate=!0,r.needsUpdate=!0}setLightning(t){this.lightningFlashes=t}updateLightning(t){let e,i=0;if(this.lightningArmed)for(const c of this.lightningFlashes){if(c.t>t)break;const l=oi.brightnessAt(c,t);l>i&&(e=c,i=l)}const n=e?Math.min(1,Math.max(.1,(Wb/e.distanceM)**2)):0,s=i*n*(e?.cloudToGround?1:.6);if(s===this.lightningLevel&&!e?.cloudToGround)return;if(this.lightningLevel=s,this.scene.fog){const c=this.scene.fog,l=s*Jh*this.relativeScale/Math.PI;c.color.setRGB(this.airlight[0]+zn.r*l,this.airlight[1]+zn.g*l,this.airlight[2]+zn.b*l)}const r=this.skyMesh?.material?.color;if(r){const c=s*Xb;r.setRGB(1+c*zn.r,1+c*zn.g,1+c*zn.b)}if(this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor),this.lightningLight.intensity=s*Jh*this.relativeScale,e){const{x:c,y:l,z:h}=ni(25,e.azimuthDeg,ln);this.lightningLight.position.set(c,l,h)}this.lightningBolt||(this.lightningBolt=new Fs(ln*.95),this.celestialGroup.add(this.lightningBolt.object));const o=this.weather.cloudBaseM??1500;this.lightningBolt.set(e,i,o),this.render()}buildCompassLabels(){const t=jc(navigator.languages,yb),e=xb[t];this.compassSprites=Mb.map((i,n)=>{const s=e[n],r=new Wc({map:eE(s),depthTest:!1,fog:!1}),o=new Fr(r),{x:c,y:l,z:h}=ni(0,i,rm);return o.position.set(c,l,h),o.scale.set(Lc,Lc,1),o.renderOrder=wb,o.layers.set(Qp),o.visible=this.compassHovered||this.compassForced,this.celestialGroup.add(o),o}),this.updateCompassScale()}updateCompassScale(){const t=this.camera.fov*Math.PI/360,e=om*Math.PI/360,i=Lc*Math.tan(t)/Math.tan(e);for(const n of this.compassSprites)n.scale.set(i,i,1)}disposeCompassLabels(){for(const t of this.compassSprites)t.removeFromParent(),t.material.map?.dispose(),t.material.dispose();this.compassSprites=[]}disposeStarTiers(){for(const t of this.starTiers)this.disposeMesh(t.points);this.starTiers=[]}disposeMesh(t){if(!t)return;t.removeFromParent(),"geometry"in t&&t.geometry.dispose();const e=t.material;for(const i of Array.isArray(e)?e:[e]){const n=i.map;n&&n.dispose(),i.dispose()}}}const Bi=Math.PI/180;function or(a,t,e){return Math.max(t,Math.min(e,a))}function Tm(a,t){return a+Math.random()*(t-a)}function Nc(a,t){return(a%(t*2)+t*3)%(t*2)-t}let Oc,Uc;function Yb(a){switch(a){case"snow":return Kb();case"hail":return $b()}}function Kb(){if(Oc)return Oc;const a=64,t=document.createElement("canvas");t.width=a,t.height=a;const e=t.getContext("2d"),i=e.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)"),e.fillStyle=i,e.fillRect(0,0,a,a),Oc=new ws(t),Oc}function $b(){if(Uc)return Uc;const a=64,t=document.createElement("canvas");t.width=a,t.height=a;const e=t.getContext("2d"),i=e.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)"),e.fillStyle=i,e.fillRect(0,0,a,a),Uc=new ws(t),Uc}let Fc;function Zb(){if(Fc)return Fc;const a=64,t=document.createElement("canvas");t.width=a,t.height=a;const e=t.getContext("2d"),i=e.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)"),e.fillStyle=i,e.fillRect(0,0,a,a),Fc=new ws(t),Fc}const Jb=`
|
|
7017
|
+
`,transparent:!0,blending:Ci,depthWrite:!1,side:Ue,fog:!1});this.object=new Dt(new Qe(M0.RADIUS,128,32,0,Math.PI*2,0,ce.MAX_ANGLE_RAD),e),this.object.renderOrder=-1,this.object.frustumCulled=!1,this.object.visible=!1}show(t,e){if(!t||!e){this.object.visible=!1;return}this.towards.set(t.x,t.y,t.z).normalize(),this.object.quaternion.setFromUnitVectors(this.up,this.towards),this.object.material.uniforms.uSource.value.copy(this.towards);for(let i=0;i<ce.STEPS;i++){for(let n=0;n<3;n++)this.texels[i*4+n]=Cn.toHalfFloat(Math.min(e[i*3+n],6e4));this.texels[i*4+3]=Cn.toHalfFloat(1)}this.texture.needsUpdate=!0,this.object.visible=!0}dispose(){this.object.geometry.dispose(),this.object.material.dispose(),this.texture.dispose()}}class xl{constructor(t){this.generator=t}static SIZE=128;target=new To(xl.SIZE,{type:ze,generateMipmaps:!1,minFilter:se,magFilter:se});camera=new e0(.1,2e5,this.target);filteredTarget;capturedAtMs=-1/0;capturedVersion;get sharp(){return this.target.texture}get filtered(){return this.filteredTarget?.texture}capture(t,e,i,n=[]){const s=t.shadowMap.autoUpdate;t.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(t,e),n.forEach((o,c)=>{o.visible=r[c]}),t.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 Ji{static REFRESH_MS=250;generator;eye;probes=new Map;constructor(t){Ji.install(),this.generator=new Ju(t),this.eye=new xl(this.generator)}static decor;refresh(t,e,i,n,s,r,o,c=[],l){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 xl(this.generator),this.probes.set(v.id,m)),h.push({probe:m,reflector:v})}const u=performance.now(),d=()=>h.filter(({probe:v})=>v.capturedVersion!==o),f=d().filter(({probe:v})=>u-v.capturedAtMs>=Ji.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(t,e,m,[v.reflector.holder,...s]),Ji.reflectOn(v.reflector.holder,v.probe)}else{v.probe.capture(t,e,i,[...s,...c]),l?.(v.probe.sharp),Ji.decor=v.probe.filtered;for(const m of r)Ji.reflectOn(m,v.probe);for(const m of n)m.shiny||Ji.reflectOn(m.holder,v.probe)}v.probe.capturedVersion=o}const p=d();if(p.length!==0)return Math.max(16,Math.min(...p.map(({probe:v})=>Ji.REFRESH_MS-(u-v.capturedAtMs))))}scratch=new D;static reflectOn(t,e={filtered:Ji.decor}){t.traverse(i=>{const n=i.material;for(const s of Array.isArray(n)?n:n?[n]:[])s instanceof Do?e.sharp&&s.setSurroundings(e.sharp):s instanceof la&&e.filtered&&s.envMap!==e.filtered&&(s.envMap=e.filtered,s.needsUpdate=!0)})}dispose(){this.eye.dispose();for(const t of this.probes.values())t.dispose();this.generator.dispose()}static installed=!1;static install(){if(Ji.installed)return;Ji.installed=!0;const t="iblIrradiance += getIBLIrradiance( geometryNormal );";if(!Wt.lights_fragment_maps.includes(t)){console.warn("Reflections: three's lights_fragment_maps changed; the environment will light diffusely too");return}Wt.lights_fragment_maps=Wt.lights_fragment_maps.replace(t,"// The sky's diffuse light is the hemisphere light's (see Reflections).")}}function cb(a,t){return JSON.stringify(a.cloudLayers)===JSON.stringify(t.cloudLayers)&&a.cloudCover===t.cloudCover&&a.cloudDarkness===t.cloudDarkness&&a.cloudBaseM===t.cloudBaseM&&a.highCloudCover===t.highCloudCover&&a.iceCrystalAlignment===t.iceCrystalAlignment&&a.lowerCloudCover===t.lowerCloudCover&&a.relativeHumidity===t.relativeHumidity&&a.precipitationType===t.precipitationType&&a.precipitationIntensity===t.precipitationIntensity&&a.windDirectionDeg===t.windDirectionDeg&&a.windSpeed===t.windSpeed&&a.storm===t.storm}const Cc=900,Bh=1,jp=4,Qp=5,tm=.5,so=900,lb=6371e3,hb=3e4;function em(a){const t=Math.sqrt(2*lb*Math.max(a,0));return Math.max(so,Math.min(t,hb))}const Hh=.5,Gh=850,im=.03,ln=850,Vh=300,ub=.04,$r=4,Wh=1.5,nm=-1,db=6,Dd=-4,fb=2,pb=20,Ic=2600,mb=.97,gb=.38,Pc=Dd,sm=1500,vb=400,Mb=[0,45,90,135,180,225,270,315],xb={en:["N","NE","E","SE","S","SW","W","NW"],fr:["N","NE","E","SE","S","SO","O","NO"]},yb=["en","fr"],_b=2,Sb=16,am=2500,rm=880,Lc=40,om=60,wb=10,bb=1,Eb=150,Ab=55,Tb=.5,Rb=17,cm=.265,lm=[[0,0],...Array.from({length:8},(a,t)=>{const e=t*Math.PI/4;return[Math.cos(e)*cm,Math.sin(e)*cm]})],Xh=700,qh=250/1e3,Db=12,hm=5,Yh=6,aa=[.92,.92,.95],Kh=[.15,.15,.19],um={snow:{fallSpeedMPerS:2,size:.3,color:new st(1,1,1),driftSensitivity:1,radiusM:25,topYM:20,opacity:.75,poolSize:2400},hail:{fallSpeedMPerS:14,size:.5,color:new st(.95,.98,1),driftSensitivity:.25,radiusM:25,topYM:10,opacity:.95,poolSize:1200}},er=0,$h=0,Cb=150,dm=3e3,Zr=20,Ib=15,fm=er,Pb=40,pm=1,Lb=9;function mm(a){return pm+(Lb-pm)*a}const gm=new st(.75,.82,.92),Nb=10,Ob=.5;function Ub(a){return or(a/Nb,Ob,1)}const ja=200,vm=.18,Mm=.32,Fb=.35,xm=new st(.85,.9,.98),ym=5,_m=.85,Sm=.01;function Zh(a,t){return Math.round(a*(Sm+(1-Sm)*t))}const wm=230,bm=.7,Em=.05,kb=.6,zb=.7,Bb=.15,Am=.35,Hb=3,Gb=1/12,Vb=.5,zn=new st(.82,.86,1),Wb=2500,Xb=1.6,Jh=15,qb={Venus:new st(1,.96,.85),Mars:new st(1,.55,.4),Jupiter:new st(.95,.87,.72),Saturn:new st(.92,.86,.68)};class Fe{renderer;scene=new ys;phenomena=new bn(this.scene);references=new fa(this.scene,()=>this.render());camera;celestialGroup=new De;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 hn;roadAttribution;roadWays;statedRoads=[];decorModelProvider=ab[0].create();decorModelToken=0;decorModelCredits=new Map;bodySystem=new oe(t=>this.loadBodyModel(t),()=>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 Xf(16777215,0);celestialLightTarget=new Pe;skyLight=new PM(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 xh;weather=Om;observerElevationM=0;siteElevationM=0;air=new fn;groundRadius=so;terrainRadius=so;cloudRendering="volume";layeredClouds;cloudLayerOffsetsM={};cloudOffsetM=new D;cloudFieldOffset=new D;cloudMesh;cirrusMesh;cirrusMaterial;cirrusUniforms;cloudMaterial;cloudUniforms;precipitationPoints;precipitationPositions;precipitationPhase;precipitationSpeedJitter;precipitationWobbleFreqJitter;precipitationWobbleAmpJitter;precipitationBounceRemaining;precipitationBounceHeight;precipitationBounceDuration;precipitationBounceVelX;precipitationBounceVelZ;precipitationUniforms;rainSystem;rainSplashSystem;rainCameraDirection=new D;rainLastVerticalFacing=-1;rainViewportSize=new Mt;lightningArmed=!1;lightningFlashes=[];lightningLevel=0;lightningBolt;lightningLight=new Xf(16777215,0);baseFogColor=[0,0,0];lastSunPosition;lensFlare;sunUnhiddenFraction=1;lensFlareArtifactIntensity=0;sunWorldPosition=new D;sunVisible=!1;lensFlareScratch=new D;sunOcclusionRaycaster=new xh;sunOcclusionDirectionScratch=new D;sunOcclusionRightScratch=new D;sunOcclusionUpScratch=new D;ufoOcclusionRaycaster=new xh;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(t){return Math.max(3,Math.round(6e6/Math.max(1,t)))}exposureFrameId=null;exposureInstantsDone=0;exposureInstantAt;restatingExposure=!1;lensOptics;instrumentMagnitudeGain=0;meteorSystem;cometTail;satelliteField;iceHalos;lunarDiffraction;lunarDiffractionKey="";rainbow;skyGlow;cometKey;novaKeys=new Set;constructor(t,e=L2()){this.renderer=new XS({canvas:t,antialias:!0}),this.resolution=new de(Math.min(window.devicePixelRatio||1,2),this.renderer.getContext()),this.renderer.setPixelRatio(this.resolution.pixelRatio),this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=ro,this.camera=new Vi(60,t.width/Math.max(t.height,1),.1,Cc*1.2),this.camera.position.set(0,1.6,0),this.terrainProviders=e,this.celestialLight.shadow.mapSize.set(1024,1024),this.celestialLight.shadow.camera.left=-120,this.celestialLight.shadow.camera.right=120,this.celestialLight.shadow.camera.top=120,this.celestialLight.shadow.camera.bottom=-120,this.celestialLight.shadow.camera.near=ln-Vh,this.celestialLight.shadow.camera.far=ln+Vh,this.celestialLight.shadow.bias=-.03/(2*Vh),this.celestialLight.shadow.normalBias=ub,this.celestialLight.target=this.celestialLightTarget,this.lightningLight.color.copy(zn),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 ii(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(t,e){this.cssSize.width=t,this.cssSize.height=e,this.renderer.setSize(t,e,!1),this.camera.aspect=t/Math.max(e,1),this.camera.updateProjectionMatrix(),this.render()}setCloudRendering(t){t!==this.cloudRendering&&(this.cloudTransmissionMemo.clear(),this.cloudRendering=t,this.layeredClouds?.dispose(),this.layeredClouds=void 0,this.buildClouds(),this.buildCirrus(),this.render())}setCloudOffset(t,e={}){this.cloudOffsetM.set(t.x,0,t.z),this.cloudLayerOffsetsM=e,this.layeredClouds?.setOffsets(t,e),this.cloudFieldOffset.set(t.x*qh,0,t.z*qh);for(const i of[this.cloudUniforms,this.cirrusUniforms])i?.fieldOffset.value.copy(this.cloudFieldOffset);this.iceHalos?.setCloudOffset(this.layeredClouds?.cirrusMask?.offset??this.cloudFieldOffset)}setObserverPose(t){const e=((t.rollDeg??0)+this.gaitOffset.rollDeg)*Bi,i=(t.pitchDeg+this.lookPitchDeg+this.gaitOffset.pitchDeg)*Bi;if(t.headingDeg!==void 0?this.camera.rotation.set(i,-(t.headingDeg+this.lookYawDeg+this.gaitOffset.yawDeg)*Bi,e,"YXZ"):this.camera.rotation.set(i,this.camera.rotation.y,e,"YXZ"),t.elevationM!==this.observerElevationM&&(this.observerElevationM=t.elevationM,this.syncCloudLayer(),Math.abs(em(t.elevationM)-this.groundRadius)>1&&(this.buildGround(),this.celestialGroup.scale.setScalar(this.groundRadius/so),this.camera.far=Math.max(Cc*1.2,this.groundRadius*2.5),this.camera.updateProjectionMatrix())),this.terrainMesh&&this.terrainOrigin&&t.lat!==void 0&&t.lng!==void 0){const n=li(this.terrainOrigin.lat,this.terrainOrigin.lng,t.lat,t.lng);this.terrainMesh.position.x=n.x,this.terrainMesh.position.z=n.z}this.poseCameraY=this.groundYUnder(0,0)+1.6+t.elevationM,this.camera.position.y=this.poseCameraY,this.celestialGroup.position.y=this.camera.position.y,this.camera.fov!==t.fovDeg&&(this.camera.fov=t.fovDeg,this.camera.updateProjectionMatrix(),this.updateCompassScale())}setTerrainProviders(t){this.terrainProviders=t,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(t,e,i){if(t===void 0||e===void 0)return;const n=this.groundRadius;if(this.terrainOrigin&&Math.abs(this.terrainRadius-n)<n*.1){const{x:c,z:l}=li(t,e,this.terrainOrigin.lat,this.terrainOrigin.lng);if(Math.sqrt(c*c+l*l)<Eb*(n/so))return}const s=this.terrainOrigin,r=this.terrainRadius;(!s||s.lat!==t||s.lng!==e)&&(this.roadSystem.clear(),this.roadAttribution=void 0),this.terrainOrigin={lat:t,lng:e},this.terrainRadius=n;const o=++this.terrainBuildToken;yw(t,e,this.terrainProviders,n).then(({mesh:c,attribution:l,originElevationM:h})=>{if(o!==this.terrainBuildToken)return;this.setSiteElevation(h??0);const u=this.terrainMesh,d=s?li(t,e,s.lat,s.lng):void 0;u&&d&&Math.hypot(d.x,d.z)<=r&&(c.position.y=u.position.y+this.groundYOfPatch(u,d.x,d.z)),this.disposeMesh(this.terrainMesh),c.renderOrder=bb,this.terrainMesh=c,this.compileNextFrameOffThread(),this.terrainAttribution=l,this.scene.add(c),this.applyGroundDepthWrite(),this.decorCurrentPose&&(this.setObserverPose(this.decorCurrentPose),this.updateDecorAnchoring(this.decorReferencePose,this.decorCurrentPose,this.decorTime)),this.buildRoads(t,e,n),this.drapeStatedRoads(),this.render(),i?.()}).catch(c=>{console.warn("Terrain build failed, keeping the flat ground fallback:",c),i?.()})}static ROADS_MAX_RADIUS_M=5e3;buildRoads(t,e,i){const n=this.terrainProviders.roads;if(!n||i>Fe.ROADS_MAX_RADIUS_M){this.roadSystem.clear(),this.roadAttribution=void 0;return}const s=this.roadWays;if(s&&s.lat===t&&s.lng===e&&s.radiusM===i){this.drapeRoads(s.ways,t,e,n.contemporary);return}n.getRoads(h1(t,e,i)).then(r=>{this.terrainOrigin?.lat!==t||this.terrainOrigin?.lng!==e||(this.roadWays={lat:t,lng:e,radiusM:i,ways:r},this.drapeRoads(r,t,e,n.contemporary))}).catch(r=>{console.warn("Roads unavailable, drawing none:",r)})}setStatedRoads(t){t!==this.statedRoads&&(this.statedRoads=t,this.drapeStatedRoads(),this.render())}drapeStatedRoads(){const t=this.terrainMesh;t&&(this.roadSystem.group.position.copy(t.position),this.roadSystem.setStated(this.statedRoads,(e,i)=>this.groundYOfPatch(t,e,i)))}drapeRoads(t,e,i,n){const s=this.terrainMesh;s&&(this.roadSystem.group.position.copy(s.position),this.roadSystem.set(t,e,i,(r,o)=>this.groundYOfPatch(s,r,o),n),this.roadAttribution=t.length>0?this.terrainProviders.roads?.attribution:void 0,this.compileNextFrameOffThread(),this.render())}setShowCompass(t){this.showCompass!==t&&(this.showCompass=t,this.disposeCompassLabels(),t&&this.buildCompassLabels(),this.render())}applyLensFlareTint(t){if(!this.lensFlare)return;const e=Ab*(this.sunArriving[1]/Rb);this.lensFlare.uniforms.uColorGain.value.setRGB(e*t[0],e*t[1],e*t[2]),this.applyDazzleStrength()}applyDazzleStrength(){if(!this.lensFlare)return;const[t,e,i]=this.sunArriving,n=Math.max(e,1e-30);this.lensFlare.uniforms.uDazzleColour.value.setRGB(t/n,1,i/n),this.lensFlare.uniforms.uVeilStrength.value=Ui.K*e*this.sunUnhiddenFraction}sunArriving=[0,0,0];setCompassHovered(t){this.compassHovered!==t&&(this.compassHovered=t,this.updateCompassVisibility())}setCompassForced(t){this.compassForced!==t&&(this.compassForced=t,this.updateCompassVisibility())}updateCompassVisibility(){const t=this.compassHovered||this.compassForced;if(this.compassSprites.some(e=>e.visible!==t)){for(const e of this.compassSprites)e.visible=t;this.developingExposure?this.exposureInstantsDone>0&&this.presentExposure():this.render()}}setWeather(t){this.cloudTransmissionMemo.clear(),!cb(this.weather,t)&&(this.weather=t,this.air=fn.of(t),this.applyAir(),this.scatteredSky?.setConditions({aerosolOpticalDepth:t.relativeHumidity===void 0?void 0:Ws.steppedOpticalDepth(t.relativeHumidity)}),this.pumpScatteredSky(),this.buildClouds(),this.buildCirrus(),this.buildPrecipitation(),this.lastAstronomy&&(this.buildIceHalos(this.lastAstronomy.sun,this.lastAstronomy.moon),this.buildRainbow(this.lastAstronomy.sun,this.lastAstronomy.moon),this.buildLunarDiffraction(this.lastAstronomy.moon)),this.lightningArmed=t.storm&&t.cloudDarkness>=Vb,this.syncAnimationLoop(),this.render())}setDecor(t){if(this.decorObjects!==t){this.decorObjects=t,this.decorModelToken++,this.decorModelCredits.clear();for(const e of this.decorGroups.values())e.removeFromParent(),vi.dispose(e);this.decorGroups.clear(),this.streetlightLights.clear();for(const e of t){const i=vi.build(e,e.lit??!1);this.scene.add(i),this.decorGroups.set(e.id,i),e.kind==="streetlight"&&this.addStreetlightLight(e.id,i),this.loadDecorModel(e,this.decorModelToken)}this.celestialLight.castShadow=this.decorGroups.size>0||this.bodySystem.any}}setDecorModelProvider(t){this.decorModelProvider=t;const e=this.decorObjects;this.decorObjects=[],this.setDecor(e)}get currentDecorModelCredits(){return[...this.decorModelCredits.values(),...this.bodySystem.modelCredits]}get bodyGround(){const{x:t,z:e}=this.bodyOrigin,i=this.groundYUnder(t,e);return{heightAt:(n,s)=>this.groundYUnder(t+n,e-s)-i}}setBodies(t,e=0,i=t.map(r=>r.id),n=[],s){const{x:r,z:o}=this.bodyOrigin,c=this.scatteredSky;this.bodySystem.set(t,{originX:r,originZ:o,originGroundY:this.groundYUnder(r,o),eye:this.camera.position,groundYAt:(h,u)=>this.groundYUnder(h,u),wind:s,light:this.plumeLight(),transmittance:(h,u,d)=>this.transmittanceTo(h,u,d)},e,c?(h,u)=>c.relativeOfLuminance(h,u):void 0,i),this.bodySystem.setSmoke(n,e),this.bodySystem.any&&(this.celestialLight.castShadow=!0);const l=this.bodySystem.furthestFrom(this.camera.position)*1.2;l>this.camera.far&&(this.camera.far=l,this.camera.updateProjectionMatrix())}plumeLight(){const t=this.celestialLight.color,e=this.celestialLight.intensity*.5,i=this.skyLight.color,n=this.skyLight.groundColor,s=this.skyLight.intensity,r=(o,c,l)=>(o*e+(c+l)/2*s)/Math.PI;return[r(t.r,i.r,n.r),r(t.g,i.g,n.g),r(t.b,i.b,n.b)]}bodyOutline(t,e){return this.bodySystem.outlineOf(t,e)}async loadBodyModel(t){const e=t.url?void 0:t.id?await this.decorModelProvider.entry(t.id):void 0,i=t.url??e?.url,n=t.credit??e?.credit;if(!(!i||!n))return{scene:await Jp(i),credit:n,headingOffsetDeg:t.headingOffsetDeg??e?.headingOffsetDeg}}async loadDecorModel(t,e){const i=t.model;if(!(!i||!vi.usesModel(t)))try{const n=i.url?void 0:i.id?await this.decorModelProvider.entry(i.id):void 0,s=i.url??n?.url,r=i.credit??n?.credit;if(!s||!r)return;const o=await Jp(s);if(e!==this.decorModelToken)return;const c=this.decorGroups.get(t.id);if(!c)return;Ji.reflectOn(o),vi.applyModel(c,t,o,{headingOffsetDeg:i.headingOffsetDeg??n?.headingOffsetDeg,depictedSizeM:n?.sizeM}),this.decorModelCredits.set(t.id,r),this.render()}catch(n){console.warn(`Keeping the built-in shape for decor "${t.id}":`,n)}}updateDecorAnchoring(t,e,i=0){this.decorReferencePose=t,this.decorCurrentPose=e,this.decorTime=i;const n=t?.lat!==void 0&&t.lng!==void 0&&e?.lat!==void 0&&e?.lng!==void 0?li(t.lat,t.lng,e.lat,e.lng):{x:0,z:0},s=this.decorObjects.find(l=>l.witnessSide!==void 0&&zm(l.kind));if(this.terrainMesh&&this.terrainOrigin&&e?.lat!==void 0&&e.lng!==void 0){const l=li(this.terrainOrigin.lat,this.terrainOrigin.lng,e.lat,e.lng);this.terrainMesh.position.x=l.x-(s?0:this.gaitOffset.eastM),this.terrainMesh.position.z=l.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 l=vi.occupantView(s),h=-(s.headingDeg??0)*Bi,u=l.x*Math.cos(h)+l.z*Math.sin(h),d=-l.x*Math.sin(h)+l.z*Math.cos(h),f=s.eastM+n.x,p=-s.northM+n.z;r.x=-(f+u),r.z=-(p+d),this.camera.position.y=this.groundYUnder(f,p)+l.eyeY,this.camera.rotation.set(this.indoorLookPitchDeg*Bi,-(l.headingDeg+this.indoorLookYawDeg)*Bi,0,"YXZ")}this.bodyOrigin={x:n.x+r.x,z:n.z+r.z},this.placeShadowFrustum();for(const l of this.decorObjects){const h=this.decorGroups.get(l.id);if(!h)continue;const u=Id(l,i),d=u.eastM+n.x+r.x,f=-u.northM+n.z+r.z,p=this.terrainMesh,v=`${p?.geometry.uuid}:${(d-(p?.position.x??0)).toFixed(3)}:${(f-(p?.position.z??0)).toFixed(3)}:${(p?.position.y??0).toFixed(3)}:${u.headingDeg}:${u.altitudeM}`;if(h.userData.footprintKey!==v&&(h.userData.footprintGroundY=this.groundUnderFootprint(l,d,f,u.headingDeg,u.altitudeM),h.userData.footprintKey=v),h.position.set(d,h.userData.footprintGroundY+u.altitudeM,f),l.kind==="crop"){const m=Math.hypot(d,f);h.visible=m<=Cb}if(u.headingDeg!==void 0&&(h.rotation.y=-u.headingDeg*Bi),l.kind==="crop"&&h.visible){const m=this.terrainMesh,g=[m?.geometry.uuid,d-(m?.position.x??0),f-(m?.position.z??0),h.position.y-(m?.position.y??0),u.headingDeg,u.altitudeM].map(_=>typeof _=="number"?_.toFixed(4):_).join(":");h.userData.cropGroundKey!==g&&(vi.fitCropToGround(h,(_,w)=>this.groundYUnder(_,w)+u.altitudeM),h.userData.cropGroundKey=g)}o=Math.max(o,h.position.distanceTo(this.camera.position))}const c=Math.max(Cc*1.2,this.groundRadius*2.5,o*1.2);Math.abs(this.camera.far-c)>1&&(this.camera.far=c,this.camera.updateProjectionMatrix())}groundYUnder(t,e){const i=this.terrainMesh;return i?i.position.y+this.groundYOfPatch(i,t-i.position.x,e-i.position.z):$h}groundYOfPatch(t,e,i){const n=t.geometry.getAttribute("position"),s=Math.round(Math.sqrt(n.count));if(s<2||s*s!==n.count)return $h;const r=n.getX(0),o=n.getX(s-1),c=n.getZ(0),l=n.getZ((s-1)*s),h=or((e-r)/(o-r)*(s-1),0,s-1),u=or((i-c)/(l-c)*(s-1),0,s-1);if(!Number.isFinite(h)||!Number.isFinite(u))return $h;const d=Math.min(Math.floor(h),s-2),f=Math.min(Math.floor(u),s-2),p=h-d,v=u-f,m=(S,b)=>n.getY(S*s+b),g=m(f,d),_=m(f,d+1),w=m(f+1,d),M=m(f+1,d+1);return p+v<=1?g+(_-g)*p+(w-g)*v:M+(w-M)*(1-p)+(_-M)*(1-v)}groundUnderFootprint(t,e,i,n,s=0){return vi.groundUnderFootprint(t,e,i,n,(r,o)=>this.groundYUnder(r,o),s)}lookYawDeg=0;lookPitchDeg=0;poseCameraY=1.6;setGait(t){this.gaitOffset=t}gaitOffset={eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0};setLookOffset(t,e){this.lookYawDeg=t,this.lookPitchDeg=e}indoorLookYawDeg=0;indoorLookPitchDeg=0;setIndoorLook(t,e){this.indoorLookYawDeg=t,this.indoorLookPitchDeg=e}updateDecorLitState(t,e=0){for(const i of this.decorObjects){const n=this.decorGroups.get(i.id);if(n&&i.lights?.length&&vi.setLights(n,i.lights,t,n.position.distanceTo(this.camera.position),e,this.relativeScale),i.kind!=="streetlight"&&i.kind!=="vehicle")continue;const s=this.decorGroups.get(i.id);if(!s)continue;const r=p2(i,t);vi.setLit(s,i.kind,r,this.relativeScale);const o=this.streetlightLights.get(i.id);o&&(o.visible=r)}}addStreetlightLight(t,e){const i=vi.bodyOf(e),n=i.children.find(r=>r.userData.emissive);if(!n)return;const s=new Cg(16764006,sm*this.relativeScale,vb);s.position.copy(n.position).multiply(i.scale),s.castShadow=!0,s.shadow.mapSize.set(512,512),s.shadow.bias=-.002,e.add(s),this.streetlightLights.set(t,s)}setAstronomy(t){(!this.lastAstronomy||Math.abs(this.lastAstronomy.sun.altitudeDeg-t.sun.altitudeDeg)>2)&&(this.surroundings=void 0,this.scatteredSky?.resetSurroundings()),this.lastAstronomy=t,this.scatteredSky?.update(this.scatteredSkyState(t)),this.skyHoldUntilMs===void 0&&(this.skyHoldUntilMs=performance.now()+am,this.onFirstFrameHold?.(!0),setTimeout(()=>this.render(),am+20)),this.pumpScatteredSky(),this.lastSunPosition=t.sun,this.buildSky(t.sun),this.buildGround();const e=qc(t.sun.altitudeDeg,this.instrumentMagnitudeGain);this.buildStars(t.stars,e),this.placeBodies(t,e),this.buildIceHalos(t.sun,t.moon),this.buildRainbow(t.sun,t.moon),this.applySkyColours(t),this.syncAnimationLoop(),this.render()}static relativeSkyOf(t,e){const i=r=>{const o=Rn.luminanceOf(r);if(!(o>0))return[0,0,0];const c=Et.relativeOfResponse(o)/o;return[r[0]*c,r[1]*c,r[2]*c]},n=i(t.zenith),s=i(t.horizon);return{zenith:n,horizon:s,airlight:s,skyIrradiance:[n[0]*Math.PI,n[1]*Math.PI,n[2]*Math.PI],scale:e}}placeBodies(t,e){this.bodiesScale=this.relativeScale,this.setBodyMesh("sun",t.sun,$r,new st(1,.96,.88),t.sun.magnitude),this.setMoonMesh(t.moon,e),this.buildPlanets(t.planets,e),this.buildComet(t.comet,e),this.buildNovae(t.novae??[],e)}bodiesScale=0;applySkyColours(t){this.skyColoursStale=!1,this.bodiesScale!==this.relativeScale&&(this.placeBodies(t,qc(t.sun.altitudeDeg,this.instrumentMagnitudeGain)),this.applyDazzleStrength(),this.buildIceHalos(t.sun,t.moon),this.buildRainbow(t.sun,t.moon));const e=this.scatteredSky?.ambient??Fe.relativeSkyOf(rd(t.sun.altitudeDeg),this.relativeScale),i=e,n=this.lightUnderClouds(t),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(t,e),this.updateCloudLighting(t.sun,this.baseFogColor),Oe.setEye(this.scatteredSky?.rodShare??0,this.relativeScale),this.updateTwinkle(this.twinkleSeconds);for(const r of this.streetlightLights.values())r.intensity=sm*this.relativeScale;this.buildSkyGlow(t,i.zenith),this.applyAir(),this.buildLunarDiffraction(t.moon)}reflections;sceneVersion=0;reflectionTimer;buildLunarDiffraction(t){const e=this.scatteredSky?.ready?this.scatteredSky:void 0;if(t.altitudeDeg<-.5||!e){this.lunarDiffraction?.show(void 0),this.lunarDiffractionKey="";return}const i=this.weather.relativeHumidity,n=(i===void 0?Ot.DEFAULT_AEROSOL_OPTICAL_DEPTH:Ws.opticalDepth(i))*Ot.aerosolDensity(this.siteElevationM+this.observerElevationM),s=this.cloudTransmission(t),r=-Math.log(Math.max(this.cloudTransmission(t,!0),1e-4)),o=ce.aureoleScale(n,ce.airMass(t.altitudeDeg))*s,c=ce.coronaScale(r),l=ce.illuminanceOf(t.magnitude),h=[t.altitudeDeg.toFixed(1),t.azimuthDeg.toFixed(1),t.magnitude.toFixed(2),o.toExponential(2),c.toExponential(2),Math.log10(Math.max(e.adaptation,1e-12)).toFixed(2)].join(":");if(h===this.lunarDiffractionKey)return;this.lunarDiffractionKey=h,this.lunarDiffraction||(this.lunarDiffraction=new M0,this.celestialGroup.add(this.lunarDiffraction.object));const u=ce.profile(ce.HAZE_COARSE_MODE),d=ce.profile(ce.CLOUD_DROPLETS),f=_p(t.altitudeDeg),p=new Float32Array(ce.STEPS*3);let v=0;for(let w=0;w<ce.STEPS;w++){const M=w*3,S=[0,1,2].map(T=>l*f[T]*(o*u[M+T]+c*d[M+T])),b=Rn.shown(S,Rn.luminanceOf(S),(T,x)=>e.relativeOfLuminance(T,x));p.set(b,M),v=Math.max(v,Rn.response(b))}const{x:m,y:g,z:_}=ni(t.altitudeDeg,t.azimuthDeg,1);this.lunarDiffraction.show(v>1/200?{x:m,y:g,z:_}:void 0,p)}applyAir(){this.scene.fog instanceof ya||(this.scene.fog=new ya),this.scene.fog.setAir(this.air,this.siteElevationM,this.airlight)}airlight=[0,0,0];transmittanceTo(t,e,i){const n=this.camera.position;return this.air.transmittance(this.siteElevationM+n.y,this.siteElevationM+e,Math.hypot(t-n.x,e-n.y,i-n.z))}setSiteElevation(t){Math.abs(t-this.siteElevationM)<1||(this.siteElevationM=t,this.applyAir(),this.lastAstronomy&&this.scatteredSky?.update(this.scatteredSkyState(this.lastAstronomy)))}scatteredSkyState(t){return{altitudeM:this.siteElevationM+this.observerElevationM+1.6,sun:{altitudeDeg:t.sun.altitudeDeg,azimuthDeg:t.sun.azimuthDeg,magnitude:t.sun.magnitude},moon:{altitudeDeg:t.moon.altitudeDeg,azimuthDeg:t.moon.azimuthDeg,magnitude:t.moon.magnitude,phaseAngleDeg:Yt.phaseAngleOf(t.moon.phase.illuminatedFraction)}}}pumpScatteredSky(){const t=this.scatteredSky;!t||t.tables.ready||this.scatteredSkyFrameId!==null||this.contextReleased||(this.scatteredSkyFrameId=requestAnimationFrame(()=>{this.scatteredSkyFrameId=null,!this.contextReleased&&(t.advance(this.skyHoldUntilMs?Sb:_b),this.pumpScatteredSky())}))}cancelScatteredSkyPump(){this.scatteredSkyFrameId!==null&&(cancelAnimationFrame(this.scatteredSkyFrameId),this.scatteredSkyFrameId=null)}setSatellites(t){if(t.length===0&&!this.satelliteField?.count)return;this.satelliteField||(this.satelliteField=new Ow(Gh),this.celestialGroup.add(this.satelliteField.object));const e=qc(this.lastSunPosition?.altitudeDeg??-90,this.instrumentMagnitudeGain);this.satelliteField.set(t,e,i=>this.cloudTransmission(i),(i,n)=>this.arrivingIlluminance(i,n,1)),this.render()}pickSatelliteAt(t,e){if(!this.satelliteField?.count)return;this.aimAtScreenPoint(this.raycaster,t,e);const i=Math.cos(im*this.camera.fov*Math.PI/180),n=this.satelliteField.nearest(this.raycaster.ray.direction,i);return n&&this.groundHides(t,e)?void 0:n}updateCelestialLight(t,e){const i=this.relativeScale,n=t.sun.altitudeDeg>=Pc,s=!n&&t.moon.altitudeDeg>=Pc,r=n?t.sun:t.moon,o=[0,0,0],c=Math.max(0,Math.sin(Math.max(r.altitudeDeg,0)*Bi)),l=n||s?this.cloudTransmission(r):1,h=-Math.log(Math.max(l,1e-6)),u=Math.max(0,1/(1+.1125*h)-l),d=[0,0,0];if(n||s){const _=ce.illuminanceOf(r.magnitude)*i,w=this.air.transmittanceFromSpace(this.siteElevationM+this.observerElevationM,r.altitudeDeg);for(let T=0;T<3;T++)o[T]=_*w[T]*l,d[T]=_*w[T]*u*c,this.cloudBeam[T]=_*w[T];const{x:M,y:S,z:b}=ni(r.altitudeDeg,r.azimuthDeg,1);this.cloudBeamDirection.set(M,S,b)}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 _=this.skyCloudTransmission(),w=e.skyIrradiance,M=[0,1,2].map(b=>w[b]*_+d[b]);this.skyLight.color.setRGB(M[0],M[1],M[2]);const S=Vt.GROUND_ALBEDO;this.skyLight.groundColor.setRGB(S*(M[0]+o[0]*c),S*(M[1]+o[1]*c),S*(M[2]+o[2]*c))}if(this.skyLight.intensity=1,!n&&!s){this.celestialLight.intensity=0;return}const{x:p,y:v,z:m}=ni(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 D(0,1,0);placeShadowFrustum(){const t=this.lightDirection,e=this.celestialLight.shadow.camera,i=(e.right-e.left)/this.celestialLight.shadow.mapSize.x,n=this.shadowAxisX.crossVectors(this.shadowUp,t);n.lengthSq()<1e-8&&n.set(1,0,0),n.normalize();const s=this.shadowAxisY.crossVectors(t,n).normalize(),r=this.shadowWorld.set(this.bodyOrigin.x,0,this.bodyOrigin.z),o=l=>{const h=r.dot(l)/i;return(h-Math.round(h))*i},c=this.celestialLightTarget.position.set(0,0,0).addScaledVector(n,o(n)).addScaledVector(s,o(s));this.celestialLightTarget.updateMatrixWorld(),this.celestialLight.position.copy(c).addScaledVector(t,ln)}shadowUp=new D(0,1,0);shadowAxisX=new D;shadowAxisY=new D;shadowWorld=new D;skyCloudTransmission(){let t=this.cloudTransmission({altitudeDeg:90,azimuthDeg:0}),e=1;for(const i of[20,45,70]){const n=i*Bi,s=Math.sin(n)*Math.cos(n)*2;for(let r=0;r<360;r+=60)t+=s*this.cloudTransmission({altitudeDeg:i,azimuthDeg:r}),e+=s}return t/e}cloudBeam=[0,0,0];cloudBeamDirection=new D(0,1,0);get relativeScale(){return this.scatteredSky?.relativeScale??1/Et.semiSaturation(Et.DAYLIGHT_ANCHOR_CD_M2)}setMeteorShower(t,e,i){this.meteorSystem||(this.meteorSystem=new pi,this.celestialGroup.add(this.meteorSystem.object)),this.meteorSystem.setShower(t,e,i)}get meteorSchedule(){return this.meteorSystem?.schedule??[]}meteorMidpoint(t){return this.meteorSystem?.midpointOf(t)}updateMeteors(t){this.meteorSystem?.update(t)}setInstrument(t){this.projectionKind=t.projection;const e=ri.starPointsOf(t),i=ri.flareArtifactsOf(t);e===this.starPoints&&i===this.lensFlareArtifactIntensity||(this.starPoints=e,this.lensFlareArtifactIntensity=i,this.lensFlare&&(this.lensFlare.uniforms.uStarPoints.value=e,this.lensFlare.uniforms.uFlareIntensity.value=i),this.render())}setInstrumentGain(t,e=!1){this.instrumentMagnitudeGain=Number.isFinite(t)?t:0,this.scatteredSky?.setInstrument(e,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 t=this.compileOffThread().then(()=>{this.compiling===t&&(this.compiling=void 0,this.render())});this.compiling=t;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 t=this.renderer.compile(this.scene,this.camera);if(!this.renderer.extensions.get("KHR_parallel_shader_compile"))return Promise.resolve();const e=this.renderer.properties,i=performance.now()+Fe.COMPILE_WAIT_MS;return new Promise(n=>{const s=()=>{if(this.contextReleased)return n();for(const r of t){const o=e.get(r)?.currentProgram;(!o||o.isReady())&&t.delete(r)}t.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(t){if(this.animationsRunning){const e=this.lastFrameTimeMs===void 0?0:t-this.lastFrameTimeMs;this.lastFrameTimeMs=t,this.hasAnimations()&&this.animate(t,e);const i=this.resolution.ratioFor(t,e);i!==this.renderer.getPixelRatio()&&this.applyPixelRatio(i)}this.drawIfDirty()}refreshReflections(){this.reflections??=new Ji(this.renderer);const t=[...this.compassSprites,...this.lensFlare?[this.lensFlare.mesh]:[],...[...this.glareSprites.values()].map(s=>s.mesh)],e=[...this.starTiers.map(s=>s.points),...[...this.bodyMeshes.values()].filter(s=>s instanceof ds),...[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,t,[...this.decorGroups.values()],this.sceneVersion,e,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(t,e){const i=this.lastAstronomy;if(!i)return;this.probeIrradiance??=new uo;const n=[i.sun,i.moon].filter(s=>s.altitudeDeg>-2).map(s=>ni(s.altitudeDeg,s.azimuthDeg,1));this.probeIrradiance.measure(this.renderer,t,n,s=>{const r=d=>d.map(f=>f/e),o=this.surroundings,c={up:r(s.up),down:r(s.down)},l=(d,f)=>d.some((p,v)=>Math.abs(p-f[v])>.03*Math.max(Math.abs(p),Math.abs(f[v]),1e-12)),h=!o||l(o.up,c.up)||l(o.down,c.down);h&&(this.surroundings=c);const u=this.scatteredSky?.adaptToSurroundings(Math.exp(s.logAverage)/e)??!1;!h&&!u||(this.skyColoursStale=!0,this.render())})}lightUnderClouds(t){const e=this.surroundings;if(!e)return;const i=t.sun.altitudeDeg>=Pc?t.sun:t.moon.altitudeDeg>=Pc?t.moon:void 0;if(!i)return;const n=this.relativeScale/Math.PI;return{through:this.cloudTransmission(i),radiance:[e.up[0]*n,e.up[1]*n,e.up[2]*n]}}probeIrradiance;surroundings;animate(t,e){const i=Math.min(e/1e3,Gb);this.twinkleSeconds=t/1e3,this.updateTwinkle(this.twinkleSeconds),this.updatePrecipitation(t/1e3,i),this.updateRain(i),this.lensFlare&&(this.lensFlare.uniforms.uTime.value=t/1e3),this.developingExposure||(this.frameDirty=!0)}setMaxPixelRatio(t){this.resolution.maximum=t,this.renderer.getPixelRatio()>this.resolution.maximum&&this.applyPixelRatio(this.resolution.maximum)}applyPixelRatio(t){this.renderer.setPixelRatio(t),this.renderer.setSize(this.cssSize.width,this.cssSize.height,!1),this.frameDirty=!0}setExposure(t,e){const i=e?Math.max(1,Math.round(t)):1;if(i===this.exposureInstants&&(i===1||e===this.exposureInstantAt)){this.exposureInstantAt=e;return}this.exposureInstants=i,this.exposureInstantAt=e,i===1&&(this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0),this.render()}renderOnce(t){if(this.onMapSubjectBounds){const r=this.mapSubjectBounds();t?this.exposureSubjectBounds.push(...r):this.onMapSubjectBounds(r)}const e=this.usableEquidistantPass();this.phenomena.setCloudLayers(this.layeredClouds?.volumes??[]),this.phenomena.place(this.camera,(r,o,c)=>this.directionAtScreenPoint(r,o,c),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()),pn.uRodShare.value=this.scatteredSky?.rodShare??0,pn.uRelativeScale.value=this.relativeScale;const n=this.references.any||this.phenomena.any||this.compassSprites.some(r=>r.visible);pn.uHasOverlay.value=n?1:0;const s=n?r=>this.renderOverlayPasses(r):void 0;if(this.skyGlow?.setDestinationEncoded(!1),!e){this.updateLensFlarePosition();const r=this.usableDepthOfFieldPass();r?r.render(this.renderer,this.scene,this.camera,s,t):this.usableFinishPass().render(this.renderer,this.scene,this.camera,s,void 0,t);return}e.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(),t)}renderOverlayPasses(t=this.camera){this.renderReferencesPass(t),this.renderPhenomenaPass(t),this.renderHudPass(t)}renderHudPass(t){if(!this.compassSprites.some(n=>n.visible))return;const e=this.renderer.autoClear,i=this.renderer.shadowMap.autoUpdate;this.renderer.autoClear=!1,this.renderer.shadowMap.autoUpdate=!1,t.layers.set(Qp),this.renderer.render(this.scene,t),t.layers.set(0),this.renderer.autoClear=e,this.renderer.shadowMap.autoUpdate=i}renderReferencesPass(t){if(!this.references.any)return;const e=this.renderer.autoClear,i=this.renderer.shadowMap.autoUpdate;this.renderer.autoClear=!1,this.renderer.shadowMap.autoUpdate=!1,t.layers.set(_1),this.renderer.render(this.scene,t),t.layers.set(0),this.renderer.autoClear=e,this.renderer.shadowMap.autoUpdate=i}setReferences(t){this.references.set(t)}referenceAspect(t){return this.references.aspectOf(t)}directionAt(t,e){return this.directionAtScreenPoint(t,e,new D)}referenceFailedToLoad(t){return this.references.failedToLoad(t)}setReferencesShown(t){this.references.setShown(t),this.render()}setReferenceView(t,e){this.references.setView(t,e),this.render()}renderPhenomenaPass(t){if(!this.phenomena.any)return;const e=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&&Fe.markDecorDepth(s,n.kind!=="crop")}t.layers.set(Bh),this.scene.overrideMaterial=this.decorDepthMaterial,this.renderer.render(this.scene,t),this.scene.overrideMaterial=null,t.layers.set(y1),this.renderer.render(this.scene,t),t.layers.set(0),this.renderer.autoClear=e,this.renderer.shadowMap.autoUpdate=i}decorDepthMaterial=new gn({colorWrite:!1});static markDecorDepth(t,e){t.traverse(i=>{if(!(i instanceof Dt))return;const n=Array.isArray(i.material)?i.material[0]:i.material;e&&n.depthWrite!==!1&&n.blending!==Ci?i.layers.enable(Bh):i.layers.disable(Bh)})}startExposure(){this.cancelExposure(),this.exposureSubjectBounds=[];const t=this.renderer.getDrawingBufferSize(new Mt),e=Math.max(1,Math.round(t.x)),i=Math.max(1,Math.round(t.y));this.exposureAccumulation||(this.exposureAccumulation=new QS(e,i)),this.exposureAccumulation.resize(e,i),this.exposureAccumulation.open(this.renderer),this.exposureInstantsDone=0,this.exposureFrameId=requestAnimationFrame(()=>this.developExposure())}developExposure(){this.exposureFrameId=null;const t=this.exposureInstantAt,e=this.exposureAccumulation;if(!t||!e)return;const i=1/this.exposureInstants;this.resolution.beginDrawing();const n=performance.now()+Fe.EXPOSURE_BUDGET_MS,s=Fe.exposureInstantsPerFrame(e.instantTarget.scene.width*e.instantTarget.scene.height);let r=0;do{this.restateAt(t,this.exposureInstantsDone);const o=this.compassSprites.map(c=>c.visible);for(const c of this.compassSprites)c.visible=!1;try{this.renderOnce(e.instantTarget)}finally{this.compassSprites.forEach((c,l)=>{c.visible=o[l]})}e.add(this.renderer,i),this.exposureInstantsDone++,r++}while(this.exposureInstantsDone<this.exposureInstants&&performance.now()<n&&r<s);this.restateAt(t,0),this.presentExposure(),this.resolution.endDrawing(),this.exposureInstantsDone<this.exposureInstants&&(this.exposureFrameId=requestAnimationFrame(()=>this.developExposure()))}presentExposure(){if(pn.uRodShare.value=this.scatteredSky?.rodShare??0,pn.uHasOverlay.value=1,pn.uRelativeScale.value=this.relativeScale,this.exposureAccumulation?.develop(this.renderer,this.exposureInstants/this.exposureInstantsDone),this.onMapSubjectBounds?.(this.exposureSubjectBounds),!this.compassSprites.some(s=>s.visible))return;const t=new ys,e=new In(-1,1,1,-1,0,2),i=Lc/(rm*Math.tan(om*Bi/2));for(const s of this.compassSprites){if(!s.visible)continue;const r=s.getWorldPosition(new D).sub(this.camera.position).normalize(),o=this.screenPointOf(r);if(!o)continue;const c=new Fr(s.material);c.position.set(o.ndcX,o.ndcY,-1),c.scale.set(i/this.camera.aspect,i,1),t.add(c)}const n=this.renderer.autoClear;this.renderer.autoClear=!1;try{this.renderer.render(t,e)}finally{this.renderer.autoClear=n}}onMapSubjectBounds;exposureSubjectBounds=[];static MAP_SUBJECT_NEAREST_M=8;mapSubjectBounds(){const t=[],e=new Mn,i=new D,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||(e.setFromObject(r),e.isEmpty())||e.distanceToPoint(this.camera.position)<Fe.MAP_SUBJECT_NEAREST_M)continue;let o=1/0,c=-1/0,l=1/0,h=-1/0;for(const u of[e.min.x,e.max.x])for(const d of[e.min.y,e.max.y])for(const f of[e.min.z,e.max.z]){i.set(u,d,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),c=Math.max(c,v),l=Math.min(l,m),h=Math.max(h,m)}Number.isFinite(o)&&t.push({x:o,y:l,width:c-o,height:h-l})}return t}restateAt(t,e){this.restatingExposure=!0;try{t(e)}finally{this.restatingExposure=!1}}cancelExposure(){this.exposureFrameId!==null&&(cancelAnimationFrame(this.exposureFrameId),this.exposureFrameId=null)}setLensOptics(t){const e=this.lensOptics;this.lensOptics=t,(e===void 0!=(t===void 0)||e&&t&&(e.focalLengthMm!==t.focalLengthMm||e.fNumber!==t.fNumber||e.focusDistance!==t.focusDistance||e.frameHeightMm!==t.frameHeightMm))&&(t&&this.depthOfFieldPass&&this.depthOfFieldPass.setLens(t.focalLengthMm,t.fNumber,t.focusDistance,t.frameHeightMm),this.render())}usableDepthOfFieldPass(){const t=this.lensOptics;if(!t)return;const e=this.renderer.getDrawingBufferSize(new Mt),i=Math.max(1,Math.round(e.x)),n=Math.max(1,Math.round(e.y));return this.depthOfFieldPass||(this.depthOfFieldPass=new fo(i,n)),this.depthOfFieldPass.resize(i,n),this.depthOfFieldPass.setLens(t.focalLengthMm,t.fNumber,t.focusDistance,t.frameHeightMm),this.depthOfFieldPass}usableFinishPass(){const t=this.renderer.getDrawingBufferSize(new Mt);return this.finishPass?this.finishPass.resize(t.x,t.y):this.finishPass=new v0(t.x,t.y),this.finishPass}usableEquidistantPass(){if(this.projectionKind!=="equidistant")return;const t=this.renderer.getDrawingBufferSize(new Mt);return this.equidistantPass?this.equidistantPass.resize(t.x,t.y):this.equidistantPass=new mi(t.x,t.y),this.equidistantPass}aimAtScreenPoint(t,e,i){const n=this.projectionKind==="equidistant"?this.equidistantPass:void 0;if(!n){t.setFromCamera(new Mt(e,i),this.camera);return}const s=n.directionFor(e,i,this.camera.fov);this.camera.updateMatrixWorld(),t.ray.origin.setFromMatrixPosition(this.camera.matrixWorld),t.ray.direction.set(s.x,s.y,s.z).applyQuaternion(this.camera.quaternion).normalize(),t.camera=this.camera}pickCloudAt(t,e){return this.layeredClouds?.pickInstance(this.cloudDirectionAt(t,e))}cloudDirectionAt(t,e){return this.directionAtScreenPoint(t,e,new D)}directionAtScreenPoint(t,e,i){return this.aimAtScreenPoint(this.ufoOcclusionRaycaster,t,e),i.copy(this.ufoOcclusionRaycaster.ray.direction)}screenPointOf(t){this.camera.updateMatrixWorld();const e=this.screenPointScratch.copy(t).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 mi.ndcFor(e,this.camera.fov,n);if(e.z>=0)return;const s=Math.tan(this.camera.fov/2*Bi);return{ndcX:e.x/-e.z/(n*s),ndcY:e.y/-e.z/s}}screenPointScratch=new D;screenPointQuaternion=new sn;screenPointSize=new Mt;updateLensFlarePosition(){const t=this.lensFlare;if(!t)return;if(!this.sunVisible){t.mesh.visible=!1;return}if(this.camera.updateMatrixWorld(),this.lensFlareScratch.copy(this.sunWorldPosition).applyMatrix4(this.camera.matrixWorldInverse),this.lensFlareScratch.z>0){t.mesh.visible=!1;return}const e=this.sunVisibleFraction();if(e<=0){t.mesh.visible=!1;return}t.mesh.visible=!0,this.sunUnhiddenFraction=e,this.applyDazzleStrength();const i=this.lensFlareScratch.copy(this.sunWorldPosition).project(this.camera);t.uniforms.uLensPosition.value.set(i.x,i.y);const n=this.renderer.domElement.width,s=this.renderer.domElement.height;t.uniforms.uResolution.value.set(n,s),t.uniforms.uTanHalfFov.value=Math.tan(this.camera.fov*Math.PI/360)}renderDazzleOnResample(){const t=this.lensFlare;if(!t||!this.sunVisible)return;const e=this.sunVisibleFraction();if(e<=0)return;this.sunUnhiddenFraction=e,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);t.uniforms.uLensPosition.value.set(i.ndcX,i.ndcY),t.uniforms.uResolution.value.set(n.x,n.y),t.uniforms.uEquidistant.value=1,t.uniforms.uHalfFovRad.value=this.camera.fov*Math.PI/360;const s=this.renderer.autoClear;this.renderer.autoClear=!1,t.mesh.visible=!0,t.mesh.layers.enable(jp),this.camera.layers.set(jp),this.renderer.render(this.scene,this.camera),this.camera.layers.set(0),t.mesh.visible=!1,t.uniforms.uEquidistant.value=0,this.renderer.autoClear=s}sunVisibleFraction(){this.raycastableDecor().length>0&&this.scene.updateMatrixWorld();let t=0;for(const e of lm)this.isSunOccluded(e[0],e[1])||t++;return t/lm.length}raycastableDecor(){const t=[];for(const e of this.decorObjects){if(e.kind==="crop")continue;const i=this.decorGroups.get(e.id);i&&t.push(i)}return t}isSunOccluded(t=0,e=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(),t!==0||e!==0){const o=Math.PI/180,c=this.sunOcclusionRightScratch.set(n.z,0,-n.x);c.lengthSq()<1e-9&&c.set(1,0,0),c.normalize();const l=this.sunOcclusionUpScratch.crossVectors(c,n).normalize();n.addScaledVector(c,t*o).addScaledVector(l,e*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(t,e,i,n=0){const s=this.groundMesh;if(s&&e.y<0){const m=(s.position.y-t.y)/e.y;if(m>n&&m<i){const g=t.x+e.x*m-s.position.x,_=t.z+e.z*m-s.position.z;if(Math.hypot(g,_)<=this.groundRadius)return!0}}const r=this.terrainMesh;if(!r)return!1;const o=r.geometry.getAttribute("position"),c=Math.round(Math.sqrt(o.count));if(c<2||c*c!==o.count)return!1;const l=[r.position.x+o.getX(0),r.position.x+o.getX(c-1)],h=[r.position.z+o.getZ(0),r.position.z+o.getZ((c-1)*c)],u=Math.min(Math.abs(l[1]-l[0]),Math.abs(h[1]-h[0]))/(c-1);if(!(u>0))return!1;let d=n,f=i;for(const[m,g,_]of[[t.x,e.x,l],[t.z,e.z,h]]){const w=Math.min(_[0],_[1]),M=Math.max(_[0],_[1]);if(Math.abs(g)<1e-12){if(m<w||m>M)return!1;continue}const S=(w-m)/g,b=(M-m)/g;d=Math.max(d,Math.min(S,b)),f=Math.min(f,Math.max(S,b))}if(!(f>d))return!1;const p=Math.hypot(e.x,e.z),v=Math.min(4096,Math.max(8,Math.ceil((f-d)*p/(u/2))));for(let m=0;m<=v;m++){const g=d+(f-d)*m/v,_=t.x+e.x*g,w=t.y+e.y*g,M=t.z+e.z*g;if(w<=this.groundYUnder(_,M))return!0}return!1}setPhenomena(t,e){this.phenomena.set(t,e)}decorDistancesAt(t,e,i){this.aimAtScreenPoint(this.ufoOcclusionRaycaster,t,e),this.ufoOcclusionRaycaster.near=tm;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 c=this.ufoOcclusionRaycaster.intersectObject(o,!0)[0];c&&(r.occludesSourceIds?.includes(i)?n=n===void 0?c.distance:Math.max(n,c.distance):s=s===void 0?c.distance:Math.min(s,c.distance))}return{behindM:n,inFrontM:s}}pickBodyAt(t,e){this.aimAtScreenPoint(this.raycaster,t,e);const i=[...this.hitAreas.entries()],n=this.raycaster.intersectObjects(i.map(([,s])=>s))[0];if(n&&!this.groundHides(t,e))return i.find(([,s])=>s===n.object)?.[0]}pickStarAt(t,e){if(this.namedStars.length===0)return;this.aimAtScreenPoint(this.raycaster,t,e);const i=this.raycaster.ray.direction,n=Math.cos(im*this.camera.fov*Math.PI/180);let s,r=n;for(const o of this.namedStars){const c=o.direction.dot(i);c>r&&(r=c,s={star:o.star,altitudeDeg:o.altitudeDeg})}return s&&this.groundHides(t,e)?void 0:s}groundHides(t,e){if(!this.terrainMesh&&!this.groundMesh)return!1;this.aimAtScreenPoint(this.ufoOcclusionRaycaster,t,e);const i=this.ufoOcclusionRaycaster.ray;return this.groundBlocks(i.origin,i.direction,1/0,tm)}pickDecorAt(t,e){this.aimAtScreenPoint(this.raycaster,t,e);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.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 t of this.bodyMeshes.values())this.disposeMesh(t);this.bodyMeshes.clear(),this.novaKeys.clear();for(const t of[...this.hitAreas.keys()])this.disposeHitArea(t);for(const t of[...this.glareSprites.keys()])this.disposeGlare(t);this.disposeCompassLabels();for(const t of this.decorGroups.values())vi.dispose(t);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 t=e=>{this.frame(e),this.animationFrameId=requestAnimationFrame(t)};this.animationFrameId=requestAnimationFrame(t)}setAnimationsRunning(t,e=!1){const i=t&&e;if(t===this.animationsRunning&&i===this.framesDriven)return;const n=this.animationsRunning;this.animationsRunning=t,this.framesDriven=i,t&&!n&&(this.lastFrameTimeMs=void 0,this.resolution.reset()),!t&&this.renderer.getPixelRatio()!==this.resolution.maximum&&this.applyPixelRatio(this.resolution.maximum),this.syncAnimationLoop(),(!t||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(t){const e=this.skyMesh?.geometry??new Qe(Cc,32,16),i=e.attributes.position,n=e.getAttribute("color")??new _e(new Float32Array(i.count*3),3);for(let r=0;r<i.count;r++){const{altitudeDeg:o,azimuthDeg:c}=i5(i.getX(r),i.getY(r),i.getZ(r)),l=h5(o,c,t.azimuthDeg,t.altitudeDeg);n.setXYZ(r,l[0],l[1],l[2])}if(n.needsUpdate=!0,this.skyMesh)return;e.setAttribute("color",n);const s=new gn({vertexColors:!0,side:Ue,fog:!1,depthWrite:!1});this.skyGradientMaterial=s,this.skyMesh=new Dt(e,s),this.skyMesh.renderOrder=-1,this.celestialGroup.add(this.skyMesh)}buildGround(){const t=em(this.observerElevationM);if(this.groundMesh&&t===this.groundRadius)return;this.disposeMesh(this.groundMesh),this.groundRadius=t;const e=new Zd(this.groundRadius,48),i=new Er({color:new st(Hh,Hh,Hh),fog:!0});ya.fadeRim(i,this.groundRadius*.75,this.groundRadius),this.groundMesh=new Dt(e,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 t=this.groundMesh?.material;if(!t)return;const e=this.terrainMesh===void 0;t.depthWrite!==e&&(t.depthWrite=e,t.needsUpdate=!0)}cloudTransmission(t,e=!1){const i=`${t.altitudeDeg.toFixed(1)}:${t.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(";")+(e?":water":""),n=this.cloudTransmissionMemo.get(i);if(n!==void 0)return n;this.cloudTransmissionMemo.size>256&&this.cloudTransmissionMemo.clear();const s=this.computeCloudTransmission(t,e);return this.cloudTransmissionMemo.set(i,s),s}cloudTransmissionMemo=new Map;computeCloudTransmission(t,e=!1){const i=ni(t.altitudeDeg,t.azimuthDeg,1);if(this.layeredClouds)return this.layeredClouds.transmissionAt(i,e);let n=1;const s=this.lowerCloudCover();s>0&&(n*=1-he.alphaAt(i,Math.abs(this.cloudLayerOffset()),s,this.cloudFieldOffset)*mb);const r=e?0:this.weather.highCloudCover??0;return r>0&&(n*=1-he.iceAlphaAt(i,Ic,r,this.cloudFieldOffset)*gb),Math.max(0,Math.min(1,n))}setBodyMesh(t,e,i,n,s){if(e.altitudeDeg<Dd){this.disposeMesh(this.bodyMeshes.get(t)),this.bodyMeshes.delete(t),this.disposeHitArea(t),this.disposeGlare(t),t==="sun"&&(this.sunVisible=!1);return}const{x:r,y:o,z:c}=ni(e.altitudeDeg,e.azimuthDeg,ln),l=_p(e.altitudeDeg),h=this.cloudTransmission(e),u=this.arrivingIlluminance(e,s,h),d=Fe.unitLuminance(n);let f=this.bodyMeshes.get(t);if(t==="sun"){const p=Math.PI*(i/ln)**2,v=[0,1,2].map(m=>Math.min(Fe.BRIGHTEST_RELATIVE,d[m]*u[m]/p));f instanceof Dt||(this.disposeMesh(f),f=new Dt(new Qe(1,16,16),new gn({fog:!1})),this.celestialGroup.add(f),this.bodyMeshes.set(t,f)),f.material.color.setRGB(v[0],v[1],v[2]),f.scale.setScalar(i)}else{if(!(f instanceof ds)){this.disposeMesh(f);const m=new ue;m.setAttribute("position",new te(new Float32Array(3),3)),m.setAttribute("color",new te(new Float32Array(3),3)),f=new ds(m,Oe.material(ho[ho.length-1].size)),Oe.track(f),this.celestialGroup.add(f),this.bodyMeshes.set(t,f)}const p=f.geometry.getAttribute("color"),v=t.startsWith("comet:")?this.pointToPixel():1;p.setXYZ(0,d[0]*u[0]*v,d[1]*u[1]*v,d[2]*u[2]*v),p.needsUpdate=!0}if(f.position.set(r,o,c),this.setHitArea(t,r,o,c,i),t==="sun"&&(this.sunArriving=u),t.startsWith("comet:")?this.disposeGlare(t):t!=="sun"&&this.setGlare(t,r,o,c,u,i/ln*(180/Math.PI),Fe.POINT_VEIL_HOLD_DEG),t==="sun"){this.sunVisible=!0;const p=this.celestialGroup.scale.x;this.sunWorldPosition.set(r*p,o*p+this.celestialGroup.position.y,c*p),this.lensFlare||(this.lensFlare=Nw(),this.lensFlare.uniforms.uOpacity.value=Tb,this.lensFlare.uniforms.uFlareIntensity.value=this.lensFlareArtifactIntensity,this.lensFlare.uniforms.uStarPoints.value=this.starPoints,this.scene.add(this.lensFlare.mesh)),this.applyLensFlareTint(l)}}setMoonMesh(t,e){const i="moon";if(t.magnitude>e||t.altitudeDeg<Dd){this.disposeMesh(this.bodyMeshes.get(i)),this.bodyMeshes.delete(i),this.disposeHitArea(i),this.disposeGlare(i);return}const{x:n,y:s,z:r}=ni(t.altitudeDeg,t.azimuthDeg,ln),o=this.cloudTransmission(t),c=this.arrivingIlluminance(t,t.magnitude,o),l=Math.max(or(t.phase.illuminatedFraction,0,1),.01)*Math.PI*($r/ln)**2,h=new st(...c.map(f=>Math.min(Fe.BRIGHTEST_RELATIVE,f/l))),u=`${t.phase.phaseFraction<.5}:${Math.round(or(t.phase.illuminatedFraction,0,1)*500)}`;let d=this.bodyMeshes.get(i);if(d instanceof Fr)d.userData.phaseKey!==u&&(d.material.map?.dispose(),d.material.map=Rm(t.phase),d.userData.phaseKey=u),d.material.color.copy(h);else{this.disposeMesh(d),d=new Fr(new Wc({map:Rm(t.phase),color:h,fog:!1})),d.userData.phaseKey=u;const f=$r*2;d.scale.set(f,f,1),this.celestialGroup.add(d),this.bodyMeshes.set(i,d)}d.position.set(n,s,r),this.setHitArea(i,n,s,r,$r),this.setGlare(i,n,s,r,c,$r/ln*(180/Math.PI))}bentLight(t,e,i=fb){const[n,s,r]=this.arrivingIlluminance(t,e,1),o=Math.max(s,1e-30);return{scale:s/i,tint:[n/o,1,r/o]}}static litBySky(t,e){return Fe.litScratch.setRGB(t.r*e[0],t.g*e[1],t.b*e[2])}static litScratch=new st;pointToPixel(){const t=Math.max(1,this.renderer.getDrawingBufferSize(this.pointScratch).y),e=(this.camera.fov*Math.PI/180/t)**2;return Math.min(1,Oe.CONE_SOLID_ANGLE/e)}pointScratch=new Mt;static POINT_VEIL_HOLD_DEG=.25;static BRIGHTEST_RELATIVE=6e4;arrivingIlluminance(t,e,i){const n=this.air.transmittanceFromSpace(this.siteElevationM+this.observerElevationM,t.altitudeDeg),s=ce.illuminanceOf(e)*i*this.relativeScale;return[n[0]*s,n[1]*s,n[2]*s]}static unitLuminance(t){const e=Rn.luminanceOf([t.r,t.g,t.b]);return e>0?[t.r/e,t.g/e,t.b/e]:[1,1,1]}setHitArea(t,e,i,n,s){let r=this.hitAreas.get(t);if(!r){const c=new Wc({transparent:!0,opacity:0,depthTest:!1,depthWrite:!1,fog:!1});r=new Fr(c),this.celestialGroup.add(r),this.hitAreas.set(t,r)}r.position.set(e,i,n);const o=s*db;r.scale.set(o,o,1)}disposeHitArea(t){const e=this.hitAreas.get(t);e&&(e.removeFromParent(),e.material.dispose(),this.hitAreas.delete(t))}setGlare(t,e,i,n,s,r,o=0){if(Ui.radiusDeg(Ui.K*Math.max(...s))<=Math.max(r,o)){this.disposeGlare(t);return}let c=this.glareSprites.get(t);c||(c=new Ui(`veil:${t}`),this.celestialGroup.add(c.mesh),this.glareSprites.set(t,c)),c.shine({x:e,y:i,z:n},s,r,o)}disposeGlare(t){const e=this.glareSprites.get(t);e&&(e.mesh.removeFromParent(),e.dispose(),this.glareSprites.delete(t))}buildComet(t,e){const i=t&&`comet:${t.id}`;if(!t||!i||t.magnitude>e){this.disposeComet();return}this.cometKey&&this.cometKey!==i&&this.disposeComet();const n=eo(t.magnitude,e),s=Rh(n);this.cometKey=i,this.setBodyMesh(i,t.position,Wh*(.5+.5*n),new st(s,s,s),t.magnitude),this.cometTail||(this.cometTail=new Zi(ln),this.celestialGroup.add(this.cometTail.object)),this.cometTail.set(t.position,t.tailEnd,n)}buildIceHalos(t,e){this.iceHalos||(this.iceHalos=new Ti,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:Ic},0);return}const s=this.lowerCloudCover(),r=le.deckLitUntilDeg(le.DECK_HEIGHT_M),o=t.altitudeDeg>-r?t:e,c=this.bentLight(o,o===t?ii.SUN_MAGNITUDE:e.magnitude),l=le.strength(i,s,o.altitudeDeg,r)*c.scale,{x:h,y:u,z:d}=ni(o.altitudeDeg,o.azimuthDeg,1);this.iceHalos.update({x:h,y:u,z:d},o.altitudeDeg,l,c.tint,{cover:n?.cover??i,layerHeight:n?.layerHeight??Ic},n?.iceCrystalAlignment??this.weather.iceCrystalAlignment??.65)}buildRainbow(t,e){this.rainbow||(this.rainbow=new ga,this.celestialGroup.add(this.rainbow.object));const i=this.weather.precipitationType==="rain"?this.weather.precipitationIntensity:0,n=t.altitudeDeg>0,s=n?t:e,r=this.lowerCloudCover(),o=this.bentLight(s,n?ii.SUN_MAGNITUDE:e.magnitude,pb),c=$i.strength(i,r,s.altitudeDeg)*o.scale;if(c<=0){this.rainbow.update({x:0,y:1,z:0},0,[1,1,1],!0);return}const{x:l,y:h,z:u}=ni(s.altitudeDeg,s.azimuthDeg,1);this.rainbow.update({x:l,y:h,z:u},c,o.tint,n)}buildSkyGlow(t,e){if(!t.frame){this.skyGlow?.hide();return}this.skyGlow||(this.skyGlow=new Us,this.skyGlow.onReady=()=>this.render(),this.celestialGroup.add(this.skyGlow.object));const{date:i,observer:n}=t.frame,s=wn.galactic(i,n),r=Fe.directionOf(s.centre),o=Fe.directionOf(s.rotation),c=Fe.directionOf(s.pole),l=new Xt().set(r.x,r.y,r.z,o.x,o.y,o.z,c.x,c.y,c.z),h=Fe.directionOf(wn.eclipticPole(i,n)),u=Fe.directionOf(t.sun),d=u.clone().addScaledVector(h,-u.dot(h)).normalize();this.skyGlow.update({galactic:l,eclipticPole:h,sunLongitude:d,sunDirection:u,sunAltitudeDeg:t.sun.altitudeDeg,moon:{direction:Fe.directionOf(t.moon),altitudeDeg:t.moon.altitudeDeg,phaseAngleDeg:Yt.phaseAngleOf(t.moon.phase.illuminatedFraction)},skyColor:new D(e[0],e[1],e[2])})}static directionOf(t){const{x:e,y:i,z:n}=ni(t.altitudeDeg,t.azimuthDeg,1);return new D(e,i,n).normalize()}buildNovae(t,e){const i=new Set;for(const n of t){if(n.magnitude>e)continue;const s=`nova:${n.id}`;i.add(s);const r=eo(n.magnitude,e),o=Rh(r);this.setBodyMesh(s,n.position,Wh*(.5+.5*r),new st(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(t,e){const i=new Set(["sun","moon",...this.cometKey?[this.cometKey]:[],...this.novaKeys]);for(const n of t){if(n.magnitude>e)continue;i.add(n.body);const s=eo(n.magnitude,e),r=Rh(s),o=qb[n.body]??new st(1,1,1),c=new st(o.r*r,o.g*r,o.b*r),l=Wh*(.5+.5*s);this.setBodyMesh(n.body,n.position,l,c,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(t,e){if(this.namedStars=[],!t||t.catalog.count===0){this.disposeStarTiers(),this.syncAnimationLoop();return}const{catalog:i,date:n,observer:s}=t,r=new An(n,s),o=jh(1337),c=[],l=this.siteElevationM+this.observerElevationM;for(let h=0;h<i.count;h++){const u=i.mag[h];if(u>e)break;const{altitudeDeg:d,azimuthDeg:f}=r.position(i.ra[h],i.dec[h]);if(d<nm)continue;const{x:p,y:v,z:m}=ni(d,f,Gh);c.push({x:p,y:v,z:m,brightness:eo(u,e),illuminance:this.air.transmittanceFromSpace(l,d).map(g=>g*ce.illuminanceOf(u)),phase:o()*Math.PI*2,speedFactor:.7+o()*.6})}for(const h of mw){if(h.mag>e)continue;const{altitudeDeg:u,azimuthDeg:d}=r.position(h.raHours,h.decDeg);if(u<nm)continue;const{x:f,y:p,z:v}=ni(u,d,Gh);this.namedStars.push({star:h,direction:new D(f,p,v).normalize(),altitudeDeg:u})}this.starTiers=ho.map((h,u)=>{const d=c.filter(S=>Wg(S.brightness)===u),f=new Float32Array(d.length*3),p=new Float32Array(d.length),v=new Float32Array(d.length*3),m=new Float32Array(d.length),g=new Float32Array(d.length);d.forEach((S,b)=>{f[b*3]=S.x,f[b*3+1]=S.y,f[b*3+2]=S.z,p[b]=S.brightness,v.set(S.illuminance,b*3),m[b]=S.phase,g[b]=S.speedFactor});const _=new ue;_.setAttribute("position",new te(f,3));const w=new te(new Float32Array(d.length*3),3);_.setAttribute("color",w);let M=this.starTiers[u]?.points;return M?(M.geometry.dispose(),M.geometry=_):(M=new ds(_,Oe.material(h.size)),Oe.track(M),this.celestialGroup.add(M)),{points:M,colorAttribute:w,brightness:p,illuminance:v,phase:m,speedFactor:g}}),this.updateTwinkle(0),this.startTwinkle()}twinkleSeconds=0;updateTwinkle(t){const e=this.relativeScale;for(const i of this.starTiers){const n=i.colorAttribute.array;for(let s=0;s<i.brightness.length;s++){const r=m5(i.brightness[s],{phase:i.phase[s],speedFactor:i.speedFactor[s]},t),o=e*r;n[s*3]=i.illuminance[s*3]*o,n[s*3+1]=i.illuminance[s*3+1]*o,n[s*3+2]=i.illuminance[s*3+2]*o}i.colorAttribute.needsUpdate=!0}}buildClouds(){if(this.cloudRendering==="volume"||this.weather.cloudLayers!==void 0){this.layeredClouds||(this.disposeCloudSystem(),this.layeredClouds=new fr(this.celestialGroup,Xh,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 t=this.lowerCloudCover();if(t<=0){this.disposeCloudSystem();return}const e=this.weather.cloudDarkness,i=new st(aa[0]+(Kh[0]-aa[0])*e,aa[1]+(Kh[1]-aa[1])*e,aa[2]+(Kh[2]-aa[2])*e);if(this.cloudMesh&&this.cloudUniforms){this.cloudUniforms.coverage.value=t,this.cloudUniforms.baseColor.value.copy(i),this.syncCloudLayer(),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);return}this.disposeCloudSystem();const{material:n,uniforms:s}=ed(i,t,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=id(Xh);this.cloudMesh=new Dt(r,n),this.faceCloudDeck(this.cloudMesh,this.cloudLayerOffset()),this.celestialGroup.add(this.cloudMesh)}lowerCloudCover(){return this.weather.cloudLayers?1-this.weather.cloudLayers.filter(t=>t.type!=="cirrus").reduce((t,e)=>t*(1-e.coverage),1):this.weather.lowerCloudCover??this.weather.cloudCover}highCloudCover(){return this.weather.cloudLayers?1-this.weather.cloudLayers.filter(t=>t.type==="cirrus").reduce((t,e)=>t*(1-e.coverage),1):this.weather.highCloudCover}buildCirrus(){const t=this.weather.highCloudCover??0;if(this.layeredClouds||t<=0){this.disposeCirrus();return}if(this.cirrusMesh&&this.cirrusUniforms){this.cirrusUniforms.coverage.value=t,this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor);return}const{material:e,uniforms:i}=ed(new st(...aa),t,Ic,1);this.cirrusMaterial=e,this.cirrusUniforms=i,i.fieldOffset.value.copy(this.cloudFieldOffset),this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor),this.cirrusMesh=new Dt(id(Xh*1.04),e),this.cirrusMesh.renderOrder=hm-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 t=this.cloudLayerOffset();this.cloudUniforms&&(this.cloudUniforms.layerHeight.value=Math.abs(t)),this.cloudMesh&&this.faceCloudDeck(this.cloudMesh,t)}faceCloudDeck(t,e){const i=e<0;t.scale.y=i?-1:1,t.renderOrder=i?fr.deckOrder(!0,0,1):hm}cloudLayerOffset(){const e=((this.weather.cloudBaseM??1e3)-this.observerElevationM)*qh;return Math.sign(e||1)*Math.max(Math.abs(e),Db)}updateCloudLighting(t,e){const i=[this.cloudUniforms,this.cirrusUniforms].filter(u=>u!==void 0);if(i.length===0&&!this.layeredClouds)return;const n=this.cloudBeamDirection,[s,r,o]=this.cloudBeam.map(u=>u/Math.PI),c=this.lightningLevel*Jh*this.relativeScale/Math.PI,l=new st(e[0]+zn.r*c,e[1]+zn.g*c,e[2]+zn.b*c);this.layeredClouds?.setLighting(n.clone(),new st(s,r,o),l,l);const h=Math.max(0,n.y);for(const u of i)u.sunDir.value.copy(n),u.sunColor.value.setRGB(s*h,r*h,o*h),u.ambientColor.value.copy(l)}disposeCloudSystem(){this.layeredClouds?.dispose(),this.layeredClouds=void 0,this.cloudMesh&&(this.cloudMesh.removeFromParent(),this.cloudMesh.geometry.dispose()),this.cloudMaterial?.dispose(),this.cloudMesh=void 0,this.cloudMaterial=void 0,this.cloudUniforms=void 0}disposePrecipitationPoints(){this.precipitationPoints&&(this.precipitationPoints.removeFromParent(),this.precipitationPoints.geometry.dispose(),this.precipitationPoints.material.dispose()),this.precipitationPoints=void 0,this.precipitationPositions=void 0,this.precipitationPhase=void 0,this.precipitationSpeedJitter=void 0,this.precipitationWobbleFreqJitter=void 0,this.precipitationWobbleAmpJitter=void 0,this.precipitationBounceRemaining=void 0,this.precipitationBounceHeight=void 0,this.precipitationBounceDuration=void 0,this.precipitationBounceVelX=void 0,this.precipitationBounceVelZ=void 0,this.precipitationUniforms=void 0}buildPrecipitation(){this.disposePrecipitationPoints(),this.disposeRain();const t=this.weather.precipitationType;if(t==="none")return;if(t==="rain"){this.buildRain();return}const e=um[t],i=e.poolSize,n=jh(9001),s=new Float32Array(i*3),r=new Float32Array(i),o=new Float32Array(i),c=new Float32Array(i),l=new Float32Array(i),h=new Float32Array(i),u=new Float32Array(i),d=new Float32Array(i),f=new Float32Array(i),p=new Float32Array(i);for(let w=0;w<i;w++){const M=n()*Math.PI*2,S=n()*e.radiusM;s[w*3]=Math.cos(M)*S,s[w*3+1]=er+n()*(e.topYM-er),s[w*3+2]=Math.sin(M)*S,r[w]=n()*Math.PI*2,o[w]=.7+n()*.6,c[w]=.6+n()*.8,l[w]=.4+n()*1.2}const v=new ue;v.setAttribute("position",new te(s,3)),v.setDrawRange(0,Zh(i,this.weather.precipitationIntensity));const m={uSize:{value:e.size},uScale:{value:.5*this.renderer.domElement.height},uOpacity:{value:e.opacity},uColor:{value:e.color.clone()},uHazeColor:{value:new st(...this.baseFogColor)},uTexture:{value:Yb(t)},uNearFocusDistance:{value:ym},uHazeDistance:{value:e.radiusM*_m}},g=new ae({uniforms:m,vertexShader:Qb,fragmentShader:tE,transparent:!0,depthWrite:!1});this.precipitationUniforms=m;const _=new ds(v,g);_.renderOrder=Yh,this.scene.add(_),this.precipitationPoints=_,this.precipitationPositions=s,this.precipitationPhase=r,this.precipitationSpeedJitter=o,this.precipitationWobbleFreqJitter=c,this.precipitationWobbleAmpJitter=l,this.precipitationBounceRemaining=h,this.precipitationBounceHeight=u,this.precipitationBounceDuration=d,this.precipitationBounceVelX=f,this.precipitationBounceVelZ=p}updatePrecipitation(t,e){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=um[i];if(this.precipitationUniforms?.uColor.value.copy(Fe.litBySky(n.color,this.baseFogColor)),e<=0)return;const s=this.weather.windDirectionDeg*Bi,r=Math.sin(s)*this.weather.windSpeed*n.driftSensitivity,o=-Math.cos(s)*this.weather.windSpeed*n.driftSensitivity,c=this.precipitationPositions,l=this.precipitationPhase,h=this.precipitationSpeedJitter,u=this.precipitationWobbleFreqJitter,d=this.precipitationWobbleAmpJitter,f=this.precipitationBounceRemaining,p=this.precipitationBounceHeight,v=this.precipitationBounceDuration,m=this.precipitationBounceVelX,g=this.precipitationBounceVelZ,_=i==="snow"&&u&&d,w=i==="hail"&&f&&p&&v&&m&&g;for(let M=0,S=0;M<c.length;M+=3,S++){if(w&&f[S]>0){if(f[S]-=e,f[S]<=0){const x=Math.random()*Math.PI*2,A=Math.sqrt(Math.random())*n.radiusM;c[M]=Math.cos(x)*A,c[M+1]=n.topYM,c[M+2]=Math.sin(x)*A,f[S]=0}else{const x=1-f[S]/v[S];c[M+1]=er+Math.sin(Math.PI*x)*p[S],c[M]=Nc(c[M]+(r+m[S])*e,n.radiusM),c[M+2]=Nc(c[M+2]+(o+g[S])*e,n.radiusM)}continue}let b=0,T=0;if(_){const x=kb*u[S],A=zb*d[S];b=Math.sin(t*x*Math.PI*2+l[S])*A,T=Math.sin(t*x*Math.PI*2+l[S]+Math.PI/2)*A}if(c[M]+=(r+b)*e,c[M+1]-=n.fallSpeedMPerS*h[S]*e,c[M+2]+=(o+T)*e,c[M]=Nc(c[M],n.radiusM),c[M+2]=Nc(c[M+2],n.radiusM),c[M+1]<er){if(w){p[S]=Am*(.2+Math.random()*1.6),v[S]=Bb*(.5+Math.random()),f[S]=v[S];const I=Math.random()*Math.PI*2,C=Hb*(p[S]/Am);m[S]=Math.cos(I)*C,g[S]=Math.sin(I)*C,c[M+1]=er;continue}const x=Math.random()*Math.PI*2,A=Math.sqrt(Math.random())*n.radiusM;c[M]=Math.cos(x)*A,c[M+1]=n.topYM,c[M+2]=Math.sin(x)*A}}this.precipitationPoints.geometry.attributes.position.needsUpdate=!0}buildRain(){const t=mm(this.weather.precipitationIntensity);this.rainSystem=Cw({count:dm,radiusM:Zr,heightM:Ib,bottomYM:fm,overallSpeed:Pb,color:gm.clone(),opacity:.85,visibleCount:Zh(dm,this.weather.precipitationIntensity),speedStreak:Ub(t),pixelSize:wm,seed:9001,nearFocusDistanceM:ym,hazeDistanceM:Zr*_m,hazeColor:new st(...this.baseFogColor)}),this.rainLastVerticalFacing=-1,this.syncRainSlant(),this.rainSystem.points.renderOrder=Yh,this.scene.add(this.rainSystem.points),this.buildRainSplashes()}buildRainSplashes(){const t=jh(4242),e=new Float32Array(ja*3),i=new Float32Array(ja),n=new Float32Array(ja),s=new Float32Array(ja);for(let h=0;h<ja;h++){const u=t()*Math.PI*2,d=Math.sqrt(t())*Zr;e[h*3]=Math.cos(u)*d,e[h*3+1]=fm,e[h*3+2]=Math.sin(u)*d,n[h]=Tm(vm,Mm),i[h]=t()*n[h],s[h]=i[h]/n[h]}const r=new ue;r.setAttribute("position",new te(e,3));const o=new te(s,1);r.setAttribute("aLife",o),r.setDrawRange(0,Zh(ja,this.weather.precipitationIntensity));const c=new ae({uniforms:{uMaxSize:{value:Fb},uScale:{value:.5*this.renderer.domElement.height},uColor:{value:xm.clone()},uTexture:{value:Zb()}},vertexShader:Jb,fragmentShader:jb,transparent:!0,depthWrite:!1}),l=new ds(r,c);l.renderOrder=Yh,this.scene.add(l),this.rainSplashSystem={points:l,positions:e,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 t=this.rainSystem;if(!t)return;const e=this.weather.windDirectionDeg*Bi;t.uniforms.uDropVelocity.value.set(Math.sin(e)*this.weather.windSpeed,-mm(this.weather.precipitationIntensity),-Math.cos(e)*this.weather.windSpeed);const i=this.renderer.getSize(this.rainViewportSize);t.uniforms.uAspect.value=i.x/Math.max(i.y,1)}updateRain(t){const e=this.rainSystem;if(!e)return;e.uniforms.uTime.value+=t,e.uniforms.uHazeColor.value.setRGB(...this.baseFogColor),e.uniforms.uColor.value.copy(Fe.litBySky(gm,this.baseFogColor));const i=this.rainSplashSystem?.points.material?.uniforms?.uColor;i&&i.value.copy(Fe.litBySky(xm,this.baseFogColor));const n=this.weather.windDirectionDeg*Bi,s=Math.sin(n)*this.weather.windSpeed,r=-Math.cos(n)*this.weather.windSpeed,o=Zr,c=h=>(h%(o*2)+o*3)%(o*2)-o;e.uniforms.uWindOffset.value.set(c(e.uniforms.uWindOffset.value.x+s*t),c(e.uniforms.uWindOffset.value.y+r*t)),this.syncRainSlant(),this.camera.getWorldDirection(this.rainCameraDirection);const l=Math.abs(this.rainCameraDirection.y);if(Math.abs(l-this.rainLastVerticalFacing)>.001){this.rainLastVerticalFacing=l;const h=bm+(1-bm)*(1-l),u=Em+(1-Em)*(1-l);e.uniforms.uUvSquash.value=u,e.uniforms.uPixelSize.value=wm*h*(.5+.5*u)}this.updateRainSplashes(t)}updateRainSplashes(t){const e=this.rainSplashSystem;if(!e||t<=0)return;const{positions:i,life:n,duration:s,lifeAttribute:r}=e,o=r.array;for(let c=0,l=0;c<i.length;c+=3,l++){if(n[l]+=t,n[l]>=s[l]){const h=Math.random()*Math.PI*2,u=Math.sqrt(Math.random())*Zr;i[c]=Math.cos(h)*u,i[c+2]=Math.sin(h)*u,s[l]=Tm(vm,Mm),n[l]=0}o[l]=n[l]/s[l]}e.points.geometry.attributes.position.needsUpdate=!0,r.needsUpdate=!0}setLightning(t){this.lightningFlashes=t}updateLightning(t){let e,i=0;if(this.lightningArmed)for(const c of this.lightningFlashes){if(c.t>t)break;const l=oi.brightnessAt(c,t);l>i&&(e=c,i=l)}const n=e?Math.min(1,Math.max(.1,(Wb/e.distanceM)**2)):0,s=i*n*(e?.cloudToGround?1:.6);if(s===this.lightningLevel&&!e?.cloudToGround)return;if(this.lightningLevel=s,this.scene.fog){const c=this.scene.fog,l=s*Jh*this.relativeScale/Math.PI;c.color.setRGB(this.airlight[0]+zn.r*l,this.airlight[1]+zn.g*l,this.airlight[2]+zn.b*l)}const r=this.skyMesh?.material?.color;if(r){const c=s*Xb;r.setRGB(1+c*zn.r,1+c*zn.g,1+c*zn.b)}if(this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor),this.lightningLight.intensity=s*Jh*this.relativeScale,e){const{x:c,y:l,z:h}=ni(25,e.azimuthDeg,ln);this.lightningLight.position.set(c,l,h)}this.lightningBolt||(this.lightningBolt=new Fs(ln*.95),this.celestialGroup.add(this.lightningBolt.object));const o=this.weather.cloudBaseM??1500;this.lightningBolt.set(e,i,o),this.render()}buildCompassLabels(){const t=jc(navigator.languages,yb),e=xb[t];this.compassSprites=Mb.map((i,n)=>{const s=e[n],r=new Wc({map:eE(s),depthTest:!1,fog:!1}),o=new Fr(r),{x:c,y:l,z:h}=ni(0,i,rm);return o.position.set(c,l,h),o.scale.set(Lc,Lc,1),o.renderOrder=wb,o.layers.set(Qp),o.visible=this.compassHovered||this.compassForced,this.celestialGroup.add(o),o}),this.updateCompassScale()}updateCompassScale(){const t=this.camera.fov*Math.PI/360,e=om*Math.PI/360,i=Lc*Math.tan(t)/Math.tan(e);for(const n of this.compassSprites)n.scale.set(i,i,1)}disposeCompassLabels(){for(const t of this.compassSprites)t.removeFromParent(),t.material.map?.dispose(),t.material.dispose();this.compassSprites=[]}disposeStarTiers(){for(const t of this.starTiers)this.disposeMesh(t.points);this.starTiers=[]}disposeMesh(t){if(!t)return;t.removeFromParent(),"geometry"in t&&t.geometry.dispose();const e=t.material;for(const i of Array.isArray(e)?e:[e]){const n=i.map;n&&n.dispose(),i.dispose()}}}const Bi=Math.PI/180;function or(a,t,e){return Math.max(t,Math.min(e,a))}function Tm(a,t){return a+Math.random()*(t-a)}function Nc(a,t){return(a%(t*2)+t*3)%(t*2)-t}let Oc,Uc;function Yb(a){switch(a){case"snow":return Kb();case"hail":return $b()}}function Kb(){if(Oc)return Oc;const a=64,t=document.createElement("canvas");t.width=a,t.height=a;const e=t.getContext("2d"),i=e.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)"),e.fillStyle=i,e.fillRect(0,0,a,a),Oc=new ws(t),Oc}function $b(){if(Uc)return Uc;const a=64,t=document.createElement("canvas");t.width=a,t.height=a;const e=t.getContext("2d"),i=e.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)"),e.fillStyle=i,e.fillRect(0,0,a,a),Uc=new ws(t),Uc}let Fc;function Zb(){if(Fc)return Fc;const a=64,t=document.createElement("canvas");t.width=a,t.height=a;const e=t.getContext("2d"),i=e.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)"),e.fillStyle=i,e.fillRect(0,0,a,a),Fc=new ws(t),Fc}const Jb=`
|
|
7019
7018
|
uniform float uMaxSize;
|
|
7020
7019
|
uniform float uScale;
|
|
7021
7020
|
attribute float aLife;
|