@rr0/ufoathome 0.81.4 → 0.81.5
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.
|
@@ -1340,7 +1340,7 @@ canvas[data-cursor="rotate"] {
|
|
|
1340
1340
|
}
|
|
1341
1341
|
`,Qo=[{id:"eye",name:"Naked eye",flare:0,projection:"equidistant",stabilization:.97},{id:"rectilinear-lens",name:"Camera, unknown device",projection:"rectilinear",fNumber:8,fNumberRange:{min:2,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:8},apertureBlades:6},{id:"instamatic-126",name:"Instamatic, 126 film",projection:"rectilinear",frame:{widthMm:28,heightMm:28,focalLengthMm:43},fNumber:11,exposureSeconds:1/90,years:{from:1963,to:1988},apertureBlades:5,detailUm:20,medium:{kind:"negative",iso:64}},{id:"slr-35mm-50",name:"35 mm SLR, 50 mm lens",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,medium:{kind:"negative",iso:100}},{id:"slr-35mm-zoom",name:"35 mm SLR, 70-210 mm zoom",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,medium:{kind:"negative",iso:100}},{id:"phone-landscape",name:"Phone, held sideways",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,medium:{kind:"sensor",iso:100,autoExposure:!0}},{id:"phone-portrait",name:"Phone, held upright",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,medium:{kind:"sensor",iso:100,autoExposure:!0}}];class fi{static get default(){return Qo[0]}static byId(t){return Qo.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:fi.UNAIDED_FIELD_DEG}static aspectOf(t){const e=t.frame;return e?e.widthMm/e.heightMm:fi.UNAIDED_ASPECT}static frameWidthPx(t,e){return Math.round(e*fi.aspectOf(t))}static availableAt(t){return t===void 0?Qo:Qo.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??fi.LENS_FLARE_ARTIFACTS}static starPointsOf(t){const e=t.apertureBlades;return e===void 0||e<3?0:e%2===0?e:e*2}}class yr{constructor(t){this.points=t}static STATIONARY_M=5;static of(t){const e=[];for(const i of t.observerTrack.allKeyframes){const{lat:n,lng:s,headingDeg:a}=i.pose;n===void 0||s===void 0||e.push({t:i.t,lat:n,lng:s,headingDeg:a})}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 yr(e)}static TRAVEL_M=50;get travels(){return this.spanM>yr.TRAVEL_M}get moved(){return this.spanM>yr.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(ai(e,t.east,e,t.west).x),Math.abs(ai(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:_s(0,-s,i,n).lat,south:_s(0,s,i,n).lat,east:_s(s,0,i,n).lng,west:_s(-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 mn{constructor(t,e){this.rotationPassed=t,this.scale=e}static SWAY_M=.012;static BREATH_M=.003;static DRIFT_YAW_DEG=.5;static DRIFT_PITCH_DEG=.4;static DRIFT_ROLL_DEG=.3;static GAZE_DRIFT_SHARE=.35;static HAND_HELD_S=.5;static HZ=[.11,.23,.17,.29,.37,.07];static of(t){const e=t.event.tags?.includes("paralysis")||(t.exposure??0)>mn.HAND_HELD_S,i=t.sway??(e?0:1);if(i>0)return new mn(Math.max(1-(t.instrument.stabilization??0),mn.GAZE_DRIFT_SHARE),i)}offsetAt(t){const e=t/1e3,i=this.scale,n=(u,d)=>Math.sin(2*Math.PI*u*e+d),[s,a,o,c,l,h]=mn.HZ;return{eastM:i*mn.SWAY_M*(.7*n(s,.3)+.3*n(c,1.9)),northM:i*mn.SWAY_M*(.6*n(o,2.2)+.4*n(l,.8)),upM:i*mn.BREATH_M*n(a,0),yawDeg:i*this.rotationPassed*mn.DRIFT_YAW_DEG*(.6*n(h,1.1)+.4*n(c,2.7)),pitchDeg:i*this.rotationPassed*mn.DRIFT_PITCH_DEG*(.5*n(a,1.6)+.5*n(o,.4)),rollDeg:i*this.rotationPassed*mn.DRIFT_ROLL_DEG*n(s,2.9)}}}class _e{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 STOP_LURCH_M=.035;static STOP_PITCH_DEG=3;static START_LURCH_M=.015;static START_PITCH_DEG=1.2;static JOLT_HZ=1.4;static JOLT_DECAY_S=.35;static JOLT_LASTS_MS=1500;static STILL=Object.freeze({eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0});static of(t){const e=yr.of(t);if(!e||e.points.length<2)return;const i=[];let n=0;for(let s=1;s<e.points.length;s++){const a=e.points[s-1],o=e.points[s],c=(o.t-a.t)/1e3;if(c<=0)continue;const l=ai(o.lat,o.lng,a.lat,a.lng),h=l.x,u=-l.z,d=Math.hypot(h,u),f=d/c,p=_e.stepHzFor(f);i.push({startMs:a.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 a=i[s-1],o=i[s+1];i[s].rampsIn=a===void 0||a.stepHz===0,i[s].rampsOut=o===void 0||o.stepHz===0}if(i.some(s=>s.stepHz>0))return new _e(i,1-(t.instrument.stabilization??0))}static bodyAt(t,e,i=!1){const n=_e.of(t)?.offsetAt(e)??_e.STILL;return i?n:_e.add(n,mn.of(t)?.offsetAt(e))}static stepHzFor(t){return t<_e.SLOWEST_WALK_M_PER_S||t>_e.FASTEST_WALK_M_PER_S?0:_e.REFERENCE_STEP_HZ*Math.pow(t/_e.REFERENCE_SPEED_M_PER_S,_e.CADENCE_EXPONENT)}offsetAt(t){return _e.add(this.cycleAt(t),this.joltAt(t))}joltAt(t){for(const e of this.stretches){if(e.stepHz===0)continue;const i=e.speedMPerS/_e.REFERENCE_SPEED_M_PER_S,n=(o,c,l,h)=>{if(o<0||o>_e.JOLT_LASTS_MS)return;const u=o/1e3,d=Math.exp(-u/_e.JOLT_DECAY_S)*Math.sin(2*Math.PI*_e.JOLT_HZ*u),f=h*c*i*d;return{eastM:f*e.eastUnit,northM:f*e.northUnit,upM:-Math.abs(f)*.3,rollDeg:0,pitchDeg:-h*l*i*d*this.rotationPassed,yawDeg:0}},s=e.rampsOut?n(t-e.endMs,_e.STOP_LURCH_M,_e.STOP_PITCH_DEG,1):void 0;if(s)return s;const a=e.rampsIn?n(t-e.startMs,_e.START_LURCH_M,_e.START_PITCH_DEG,-1):void 0;if(a)return a}}static add(t,e){return e?{eastM:t.eastM+e.eastM,northM:t.northM+e.northM,upM:t.upM+e.upM,rollDeg:t.rollDeg+e.rollDeg,pitchDeg:t.pitchDeg+e.pitchDeg,yawDeg:t.yawDeg+e.yawDeg}:t}cycleAt(t){const e=this.stretches.find(c=>t>=c.startMs&&t<=c.endMs);if(!e||e.stepHz===0)return _e.STILL;const i=e.stepsBefore+e.stepHz*(t-e.startMs)/1e3,n=2*Math.PI*i,s=this.amplitudeAt(e,t),a=_e.SWAY_M*s*Math.cos(n/2),o=s*this.rotationPassed*e.speedMPerS/_e.REFERENCE_SPEED_M_PER_S;return{eastM:a*e.northUnit,northM:-a*e.eastUnit,upM:_e.RISE_M_PER_M_PER_S*e.speedMPerS*s*Math.cos(n),rollDeg:_e.HEAD_ROLL_DEG*o*Math.cos(n/2),pitchDeg:-1.25*o*Math.cos(n),yawDeg:_e.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,a=t.endMs-e,o=Math.min(t.rampsIn?s/n:1,t.rampsOut?a/n:1,1);return(1-Math.cos(Math.PI*Math.max(o,0)))/2}}class Te{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/Te.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 uv(r,t,e){if(!r||!t)return e<1?r:t;const i=((t.azimuthDeg-r.azimuthDeg)%360+540)%360-180;return{azimuthDeg:((r.azimuthDeg+i*e)%360+360)%360,altitudeDeg:r.altitudeDeg+(t.altitudeDeg-r.altitudeDeg)*e}}function dv(r,t,e){const{bounds:i}=r;return t>=i.x&&t<=i.x+i.width&&e>=i.y&&e<=i.y+i.height}function Ki(r,t,e){return r+(t-r)*e}function sf(r){const t=/^#([0-9a-f]{6})$/i.exec(r);if(!t)return;const e=parseInt(t[1],16);return[e>>16&255,e>>8&255,e&255]}function fv(r){return`#${r.map(t=>Math.round(t).toString(16).padStart(2,"0")).join("")}`}function pv(r,t,e){const i=sf(r),n=sf(t);return!i||!n?e<1?r:t:fv([Ki(i[0],n[0],e),Ki(i[1],n[1],e),Ki(i[2],n[2],e)])}function mv(r,t,e){const i={x:Ki(r.bounds.x,t.bounds.x,e),y:Ki(r.bounds.y,t.bounds.y,e),width:Ki(r.bounds.width,t.bounds.width,e),height:Ki(r.bounds.height,t.bounds.height,e)},n=Ki(r.angle,t.angle,e),s=Ki(r.transparency,t.transparency,e),a=Ki(r.haloScale,t.haloScale,e),o=Ki(r.blur??0,t.blur??0,e),c=Ki(r.brightness??0,t.brightness??0,e),l=pv(r.color,t.color,e),h=Te.lerpAngular(r.angular,t.angular,e),u=uv(r.aim,t.aim,e);return r.kind==="polygon"&&t.kind==="polygon"&&r.points.length===t.points.length?{...r,bounds:i,angle:n,transparency:s,haloScale:a,blur:o,brightness:c,color:l,angular:h,aim:u,points:r.points.map((d,f)=>({x:Ki(d.x,t.points[f].x,e),y:Ki(d.y,t.points[f].y,e)}))}:{...e<1?r:t,bounds:i,angle:n,transparency:s,haloScale:a,blur:o,brightness:c,color:l,angular:h,aim:u}}class va{static DEFAULT_COLOR="#e8e6df";static complete(t,e=[]){const i=new Map;return t.map((n,s)=>({keyframe:n,index:s})).sort((n,s)=>n.keyframe.t-s.keyframe.t).map(({keyframe:n,index:s})=>({t:n.t,shapes:(n.shapes??[]).map((a,o)=>{const c=`timeline.keyframes.${s}.shapes.${o}.shape`,l=va.completed(a,i.get(a.sourceId),c,e);return i.set(a.sourceId,l),{sourceId:a.sourceId,shape:l}})}))}static completed(t,e,i,n){const s=t.shape??{},a=e??va.firstAppearance(s,i,n),o={...a};s.bounds&&e&&(e.aim||e.angular)&&!s.aim&&!s.angular&&n.push({kind:"pixels-over-angles",path:i}),s.bounds&&(s.aim||delete o.aim,s.angular||delete o.angular);const c=s.kind??a.kind??"oval",l={...o,...s,kind:c};if(c==="polygon"&&!l.points){n.push({kind:"defaulted",path:`${i}.points`,expected:"rectangle"});const{width:h,height:u}=l.bounds;return{...l,points:[{x:0,y:0},{x:h,y:0},{x:h,y:u},{x:0,y:u}]}}return l}static firstAppearance(t,e,i){return t.kind||i.push({kind:"defaulted",path:`${e}.kind`,expected:'"oval"'}),t.color||i.push({kind:"defaulted",path:`${e}.color`,expected:`"${va.DEFAULT_COLOR}"`}),!t.bounds&&!t.aim&&i.push({kind:"unplaced",path:e}),!t.bounds&&!t.angular&&i.push({kind:"unsized",path:e}),{kind:t.kind??"oval",bounds:{...va.NEUTRAL_BOUNDS},color:va.DEFAULT_COLOR,angle:0,transparency:0,haloScale:0,selected:!1}}static NEUTRAL_BOUNDS={x:Te.CANVAS_WIDTH_PX/2,y:Te.CANVAS_HEIGHT_PX/2,width:1,height:1}}class kl{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?mv(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 a=s.length-1;a>=0;a--){if(n?.has(s[a]))continue;const o=this.getInterpolatedShapeAt(t,s[a]);if(o&&dv(o,e,i))return{sourceId:s[a],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,e){const i=new kl;for(const n of va.complete(t.keyframes??[],e))i.addKeyframe(n.t,n.shapes);if(t.order){const n=i.order.filter(s=>!t.order.includes(s));i.order=[...t.order,...n]}return t.groups&&(i.groups=t.groups.map(n=>n.filter(s=>i.order.includes(s))).filter(n=>n.length>=2)),i}}function gv(r,t,e){return Math.max(t,Math.min(e,r))}function vv(r,t,e){const i=((t-r)%360+540)%360-180;return((r+i*e)%360+360)%360}function Ga(r,t,e){return r+(t-r)*e}function Mv(r,t,e){return{lat:r.lat===void 0||t.lat===void 0?void 0:Ga(r.lat,t.lat,e),lng:r.lng===void 0||t.lng===void 0?void 0:Ga(r.lng,t.lng,e),elevationM:Ga(r.elevationM,t.elevationM,e),headingDeg:r.headingDeg===void 0||t.headingDeg===void 0?void 0:vv(r.headingDeg,t.headingDeg,e),pitchDeg:Ga(r.pitchDeg,t.pitchDeg,e),rollDeg:Ga(r.rollDeg??0,t.rollDeg??0,e),fovDeg:Ga(r.fovDeg,t.fovDeg,e),fNumber:r.fNumber,focusDistanceM:r.focusDistanceM}}class Ia{static at(t,e,i,n,s){const a=t[i],c=t[i+1]-a;if(c<=0)return e[i];const l=Ia.tangent(t,e,i,s),h=Ia.tangent(t,e,i+1,s),u=(n-a)/c,d=u*u,f=d*u;return(2*f-3*d+1)*e[i]+(f-2*d+u)*c*l+(-2*f+3*d)*e[i+1]+(f-d)*c*h}static BRAKE_S=.8;static paced(t,e,i,n){if(!i&&!n)return t;const s=e>0?Math.min(.5,Ia.BRAKE_S/e):.5;if(i&&n){const o=1/(1-s);return t<=s?o*t*t/(2*s):t>=1-s?1-o*(1-t)*(1-t)/(2*s):o*(t-s/2)}const a=o=>{const c=1/(1-s/2);if(o<=1-s)return c*o;const l=o-(1-s);return c*(1-s)+c*(l-l*l/(2*s))};return n?a(t):1-a(1-t)}static tangent(t,e,i,n){const s=t.length-1,a=f=>(e[f+1]-e[f])/(t[f+1]-t[f]||1);if(i===0)return n?0:a(0);if(i===s)return n?0:a(s-1);const o=a(i-1),c=a(i);if(o*c<=0)return 0;const l=t[i]-t[i-1],h=t[i+1]-t[i],u=2*h+l,d=h+2*l;return(u+d)/(u/o+d/c)}}class Lo{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];if(!i)return n?.pose;if(!n)return i.pose;const s=Mv(i.pose,n.pose,gv((t-i.t)/(n.t-i.t),0,1));return this.humanly(e-1,t,s)}humanly(t,e,i){const n=Math.max(0,t-1),s=Math.min(this.keyframes.length-1,t+2),a=this.keyframes.slice(n,s+1),o=t-n,c=a.map(y=>y.t),l=(y,M)=>{const b=a.map(w=>y(w.pose));if(!b.some(w=>w===void 0))return Ia.at(c,b,o,e,M)},h=a.map(y=>y.pose.headingDeg);let u;if(h.every(y=>y!==void 0)){const y=[h[0]];for(let M=1;M<h.length;M++)y.push(y[M-1]+((h[M]-h[M-1])%360+540)%360-180);u=(Ia.at(c,y,o,e,!0)%360+360)%360}const d=this.keyframes[t],f=this.keyframes[t+1],p=(y,M)=>y.lat===M.lat&&y.lng===M.lng&&y.elevationM===M.elevationM,v=!p(d.pose,f.pose),m=v&&t>0&&p(this.keyframes[t-1].pose,d.pose),g=v&&t+2<this.keyframes.length&&p(f.pose,this.keyframes[t+2].pose);let S;if(m||g){const y=Ia.paced((e-d.t)/(f.t-d.t),(f.t-d.t)/1e3,m,g),M=(b,w)=>b===void 0||w===void 0?void 0:b+(w-b)*y;S={lat:M(d.pose.lat,f.pose.lat),lng:M(d.pose.lng,f.pose.lng),elevationM:M(d.pose.elevationM,f.pose.elevationM)}}return{...i,lat:S?S.lat:l(y=>y.lat,!1)??i.lat,lng:S?S.lng:l(y=>y.lng,!1)??i.lng,elevationM:S?S.elevationM:l(y=>y.elevationM,!1)??i.elevationM,headingDeg:u??i.headingDeg,pitchDeg:l(y=>y.pitchDeg,!0)??i.pitchDeg,rollDeg:l(y=>y.rollDeg??0,!0)??i.rollDeg,fovDeg:l(y=>y.fovDeg,!0)??i.fovDeg}}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 Lo;for(const i of t.keyframes)e.addKeyframe(i.t,i.pose);return e}}class Ws{static MAX_CHANGE_PER_S=.05;points;followed;constructor(t){let e="none",i=0;this.points=t.map(({t:n,weather:s})=>(s.precipitationType!=="none"&&(e=s.precipitationType,i=s.precipitationIntensity),{t:n,lastFalling:e,lastFallingIntensity:i,intensity:s.precipitationType==="none"?0:s.precipitationIntensity,type:s.precipitationType})),this.followed=[];for(let n=0;n<this.points.length;n++){if(n===0){this.followed.push(this.points[0].intensity);continue}const s=this.points[n-1],a=this.points[n];this.followed.push(Ws.follow(this.followed[n-1],s.intensity,a.intensity,(a.t-s.t)/1e3,(a.t-s.t)/1e3))}}at(t){if(this.points.length===0||t<this.points[0].t)return;let e=this.points.length-1;for(;e>0&&this.points[e].t>t;)e--;const i=this.points[e],n=this.points[e+1],s=n?Ws.follow(this.followed[e],i.intensity,n.intensity,(n.t-i.t)/1e3,(t-i.t)/1e3):Ws.follow(this.followed[e],i.intensity,i.intensity,1,(t-i.t)/1e3);return{type:Ws.typeBetween(i,n,t,s),intensity:s,character:Ws.characterBetween(i,n,t)}}static characterBetween(t,e,i){return t.type==="none"?e&&e.type!=="none"?e.intensity:t.lastFallingIntensity:!e||e.type==="none"?t.intensity:t.intensity+(e.intensity-t.intensity)*(i-t.t)/(e.t-t.t||1)}static typeBetween(t,e,i,n){return t.type==="none"?e&&e.type!=="none"&&i>t.t?e.type:n>0?t.lastFalling:"none":e&&e.type==="none"&&n<=0?"none":t.type}static follow(t,e,i,n,s){const a=Ws.MAX_CHANGE_PER_S,o=n>0?(i-e)/n:0,c=u=>e+o*Math.min(Math.max(u,0),n);let l=t,h=0;for(let u=0;u<8&&h<s;u++){const d=c(h)-l;if(Math.abs(d)<1e-9){const y=h<n?o:0;if(Math.abs(y)<=a){const b=h<n?Math.min(s,n):s;l=c(b),h=b;continue}const M=Math.min(s,n);l+=Math.sign(y)*a*(M-h),h=M;continue}const f=Math.sign(d),p=h<n?o:0,v=a-f*p,m=v>0?h+Math.abs(d)/v:1/0,g=h<n?n:1/0,S=Math.min(s,m,g);l+=f*a*(S-h),h=S,S===m&&(l=c(h))}return Math.min(1,Math.max(0,l))}}function ze(r,t,e){return r+(t-r)*e}function Qd(r,t,e){const i=((t-r)%360+540)%360-180;return((r+i*e)%360+360)%360}function xv(r,t,e){return Math.max(t,Math.min(e,r))}function yv(r=[],t=[],e){if(!(!r.length&&!t.length))return[...new Set([...r.map(i=>i.id),...t.map(i=>i.id)])].map(i=>{const n=r.find(c=>c.id===i),s=t.find(c=>c.id===i),a=n??{...s,density:0},o=s??{...n,density:0};return{...a,eastM:ze(a.eastM,o.eastM,e),northM:ze(a.northM,o.northM,e),baseM:ze(a.baseM,o.baseM,e),thicknessM:ze(a.thicknessM,o.thicknessM,e),widthM:ze(a.widthM,o.widthM,e),depthM:ze(a.depthM,o.depthM,e),rotationDeg:Qd(a.rotationDeg,o.rotationDeg,e),density:ze(a.density,o.density,e),darkness:ze(a.darkness??0,o.darkness??0,e)}})}function _v(r,t,e){if(r.cloudLayers===void 0&&t.cloudLayers===void 0)return;const i=fl(r),n=fl(t);return e>=1?n.map(a=>({...a})):[...new Set([...i.map(a=>a.id),...n.map(a=>a.id)])].map(a=>{const o=i.find(u=>u.id===a),c=n.find(u=>u.id===a),l=o??{...c,coverage:0},h=c??{...o,coverage:0};return{...l,instances:yv(o?.instances,c?.instances,e),baseM:ze(l.baseM,h.baseM,e),thicknessM:ze(l.thicknessM,h.thicknessM,e),coverage:ze(l.coverage,h.coverage,e),sizeM:ze(l.sizeM,h.sizeM,e),density:ze(l.density,h.density,e),darkness:ze(l.darkness??r.cloudDarkness,h.darkness??t.cloudDarkness,e),iceCrystalAlignment:l.iceCrystalAlignment===void 0||h.iceCrystalAlignment===void 0?void 0:ze(l.iceCrystalAlignment,h.iceCrystalAlignment,e),windSpeed:l.windSpeed===void 0&&h.windSpeed===void 0?void 0:ze(l.windSpeed??r.windSpeed,h.windSpeed??t.windSpeed,e),windDirectionDeg:l.windDirectionDeg===void 0&&h.windDirectionDeg===void 0?void 0:Qd(l.windDirectionDeg??r.windDirectionDeg,h.windDirectionDeg??t.windDirectionDeg,e)}})}function Sv(r,t,e){return{cloudLayers:_v(r,t,e),cloudCover:ze(r.cloudCover,t.cloudCover,e),cloudDarkness:ze(r.cloudDarkness,t.cloudDarkness,e),highCloudCover:r.highCloudCover===void 0||t.highCloudCover===void 0?void 0:ze(r.highCloudCover,t.highCloudCover,e),iceCrystalAlignment:r.iceCrystalAlignment===void 0||t.iceCrystalAlignment===void 0?void 0:ze(r.iceCrystalAlignment,t.iceCrystalAlignment,e),lowerCloudCover:r.lowerCloudCover===void 0||t.lowerCloudCover===void 0?void 0:ze(r.lowerCloudCover,t.lowerCloudCover,e),cloudBaseM:r.cloudBaseM===void 0||t.cloudBaseM===void 0?void 0:ze(r.cloudBaseM,t.cloudBaseM,e),relativeHumidity:r.relativeHumidity===void 0||t.relativeHumidity===void 0?void 0:ze(r.relativeHumidity,t.relativeHumidity,e),precipitationType:e<1?r.precipitationType:t.precipitationType,precipitationIntensity:ze(r.precipitationIntensity,t.precipitationIntensity,e),windDirectionDeg:Qd(r.windDirectionDeg,t.windDirectionDeg,e),windSpeed:ze(r.windSpeed,t.windSpeed,e),storm:e<1?r.storm:t.storm}}class Oo{keyframes=[];ramp;addKeyframe(t,e){this.ramp=void 0;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.ramp=void 0,this.keyframes.length=0}removeKeyframeAt(t){this.ramp=void 0;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?Sv(i.weather,n.weather,xv((t-i.t)/(n.t-i.t),0,1)):i.weather:n?.weather}getActualWeatherAt(t){const e=this.getInterpolatedWeatherAt(t);if(!e)return;const i=(this.ramp??=new Ws(this.keyframes)).at(t);if(!i)return e;const{type:n,intensity:s,character:a}=i,o=a>0?Math.min(1,s/a):n==="none"?0:1;return{...e,precipitationType:n,precipitationIntensity:a,precipitationAmount:o}}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 Oo;for(const i of t.keyframes)e.addKeyframe(i.t,i.weather);return e}}class No{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 No;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 bv=100,wv={kind:"none",volume:0,pitchHz:bv};class Mn{constructor(t){this.entries=t}static empty(){return new Mn(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 Mn(new Map);return{recording:Mn.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),a=n.split("."),o=Mn.holderOf(i,a);if(!o)continue;const c=a[a.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 Mn.isWrapper(t)?(i.set(e.join("."),{basis:t.basis??"stated",...t.rationale===void 0?{}:{rationale:t.rationale},of:t.value}),Mn.stripValue(t.value,e,i)):Array.isArray(t)?t.map((n,s)=>Mn.stripValue(n,[...e,String(s)],i)):typeof t=="object"&&t!==null?Object.fromEntries(Object.entries(t).map(([n,s])=>[n,Mn.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 wu(r){if(r.year!==void 0)return Date.UTC(r.year,(r.month??1)-1,r.day??1,r.hour??0,r.minute??0,r.second??0)}function af(r){return(((r.day??0)*24+(r.hour??0))*60+(r.minute??0))*6e4+(r.second??0)*1e3}const Ev=["year","month","day","hour","minute"],Av=["day","hour","minute"];function rf(r,t){return t.filter(e=>r[e]!==void 0).join(",")}function Tv(r){if(r.durationSeconds!==void 0)return r.durationSeconds*1e3;if(!r.time||!r.endTime)return;const t=r.time.year!==void 0&&r.endTime.year!==void 0,e=t?Ev:Av,i=rf(r.time,e);if(!(i===""||i!==rf(r.endTime,e)))return t?wu(r.endTime)-wu(r.time):af(r.endTime)-af(r.time)}class zl{constructor(t,e,i,n,s,a,o,c,l=[],h,u,d,f=[],p=[],v=[]){this.event=t,this.timeline=e,this.observerTrack=i,this.weatherTrack=n,this.soundTrack=s,this.observer=a,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=Mn.empty();loadIssues=[];account;sources;interpretation;sway;lightPollution;iso;vehicle;get observerCount(){return 1+this.decor.filter(t=>t.kind==="observer").length}get exposure(){return this.exposureSeconds??this.instrument.exposureSeconds}get instrument(){return fi.byId(this.instrumentId)}static create(t,e,i){return new zl({eventType:"sighting",time:t,place:e},new kl,new Lo,new Oo,new No,i)}}const Rv=0,Dv=0;function di(r,t){const e=r.observerTrack.getInterpolatedPoseAt(t);if(e)return e;const i=r.event.place?.[0];if(i)return{lat:i.lat,lng:i.lng,elevationM:Rv,headingDeg:void 0,pitchDeg:Dv,fovDeg:fi.fieldOfViewDeg(r.instrument)}}function Vr(r,t){return r.weatherTrack.getInterpolatedWeatherAt(t)??r.weather??jd}function of(r,t){return r.weatherTrack.getActualWeatherAt(t)??r.weather??jd}function Iv(r,t){return r.soundTrack.getInterpolatedSoundAt(t)??wv}class Cv{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 og=["nw","n","ne","e","se","s","sw","w"],Pv=24,tc=8,Lv=3,Ov=8;function ec(r,t,e){const i=r.x-t.x,n=r.y-t.y,s=Math.cos(e),a=Math.sin(e);return{x:t.x+i*s-n*a,y:t.y+i*a+n*s}}function Wr(r){return{x:r.x+r.width/2,y:r.y+r.height/2}}const Nv={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 cn{static handlePointsFor(t){const{x:e,y:i,width:n,height:s}=t.bounds,a={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-Pv}},o=Wr(t.bounds),c={};for(const l of Object.keys(a))c[l]=ec(a[l],o,t.angle);return c}static hitTestHandle(t,e,i=8,n=[...og,"rotate"]){const s=cn.handlePointsFor(t);for(const a of n)if(Math.hypot(e.x-s[a].x,e.y-s[a].y)<=i)return a}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=((cn.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=Wr(t),a=ec(n,s,-e),{x:o,y:c,width:l,height:h}=t,u=Nv[i];let d=o,f=c,p=o+l,v=c+h;return u.left&&(d=Math.min(a.x,p-tc)),u.right&&(p=Math.max(a.x,d+tc)),u.top&&(f=Math.min(a.y,v-tc)),u.bottom&&(v=Math.max(a.y,f+tc)),{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,a=cn.resizeBounds(t.bounds,t.angle,e,i);if(t.kind==="oval")return{...t,bounds:a};const o=n===0?1:a.width/n,c=s===0?1:a.height/s;return{...t,bounds:a,points:t.points.map(l=>({x:l.x*o,y:l.y*c}))}}static rotateShape(t,e){const i=Wr(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(a=>a.x)),i=Math.min(...t.map(a=>a.y)),n=Math.max(...t.map(a=>a.x+a.width)),s=Math.max(...t.map(a=>a.y+a.height));return{x:e,y:i,width:n-e,height:s-i}}static vertexPointsFor(t){const e=Wr(t.bounds);return t.points.map(i=>ec({x:t.bounds.x+i.x,y:t.bounds.y+i.y},e,t.angle))}static hitTestVertex(t,e,i=Ov){const n=cn.vertexPointsFor(t);let s,a=i;return n.forEach((o,c)=>{const l=Math.hypot(e.x-o.x,e.y-o.y);l<=a&&(a=l,s=c)}),s}static toLocalPoint(t,e){const i=Wr(t.bounds),n=ec(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?cn.toLocalPoint(t,i):u),s=Math.min(...n.map(u=>u.x)),a=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+a,width:o-s,height:c-a},h=n.map(u=>({x:u.x-s,y:u.y-a}));return{...t,bounds:l,points:h}}static insertVertexNear(t,e){const i=cn.toLocalPoint(t,e),{points:n}=t;let s=n.length-1,a=1/0;for(let c=0;c<n.length;c++){const l=n[c],h=n[(c+1)%n.length],u=cn.distanceToSegment(i,l,h);u<a&&(a=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,a=n*n+s*s,o=a===0?0:Math.max(0,Math.min(1,((t.x-e.x)*n+(t.y-e.y)*s)/a)),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<=Lv?t:{...t,points:t.points.filter((i,n)=>n!==e)}}}const Eu=6,ic=Eu/2,cf=20,lf=24,hf=9,uf=6,df=7,ff=6,Gn=4;class Fo{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,a=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+hf*f),ff*f)-d:0,v=f>0?d*(1+df*f)-d:0,m=3*lf*(t.blur??0)+1.5*cf*t.haloScale,g=Math.max(p,v,0)+m+2;return{x:a-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(${(lf*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:a}=t.bounds,o=i+s/2,c=n+a/2,l=Math.max(s,a)/2,h=Math.max(l*(1+hf*e),ff*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<=uf;d++){const f=d/uf,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+df*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=a=>Math.round(a+(255-a)*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,a=n/2,o=s/2;this.ctx.ellipse(e+a,i+o,a,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((a,o)=>{o===0?this.ctx.moveTo(a.x,a.y):this.ctx.lineTo(a.x,a.y)}),this.ctx.closePath(),this.ctx.restore()}}paintHalo(t){this.ctx.save(),this.ctx.shadowColor=t.color,this.ctx.shadowBlur=cf*t.haloScale,this.paintBase(t),this.ctx.restore()}paintSelectionHandles(t){this.paintHandleFrame(cn.handlePointsFor(t),{includeRotate:!0}),t.kind==="polygon"&&this.paintVertexHandles(t)}paintVertexHandles(t){this.ctx.fillStyle="#39f";for(const e of cn.vertexPointsFor(t))this.ctx.beginPath(),this.ctx.ellipse(e.x,e.y,Gn,Gn,0,0,2*Math.PI),this.ctx.fill()}paintMemberOutline(t){this.paintOutline(cn.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 a=Fo.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,Gn+2,Gn+2,0,0,2*Math.PI),n.stroke()),s.scene&&(n.strokeStyle=a,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=a,n.beginPath(),n.ellipse(s.scene.x,s.scene.y,Gn,Gn,0,0,2*Math.PI),n.fill()),n.strokeStyle=a,n.lineWidth=o,n.beginPath(),n.ellipse(s.picture.x,s.picture.y,Gn+2,Gn+2,0,0,2*Math.PI),n.stroke(),this.paintLabel(s.label,s.picture.x+Gn+5,s.picture.y-Gn-2,a)}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 a=this.ctx;a.save(),a.font=`${s}px system-ui, sans-serif`,a.textBaseline="top";const o=a.measureText(t).width;a.fillStyle="rgba(0, 0, 0, 0.6)",a.fillRect(e-3,i-2,o+6,s+4),a.fillStyle=n,a.fillText(t,e,i),a.restore()}paintGroupHandles(t){this.paintHandleFrame(cn.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 og){const n=t[i];this.ctx.fillRect(n.x-ic,n.y-ic,Eu,Eu)}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,ic+1,ic+1,0,0,2*Math.PI),this.ctx.fill())}}const pf=.05,mf=.08,gf=2,vf=3,Fv=14,Uv=.02;class kv{context;voice;voiceToken=0;buffers=new Map;noiseBuffer;crackleBuffer;requested;level=1;master;output(t){return this.master||(this.master=t.createGain(),this.master.gain.value=this.level,this.master.connect(t.destination)),this.master}setLevel(t){this.level=t,this.master&&(this.master.gain.value=t)}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}}Da.unlock(this.context)}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.master=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,pf);for(const{param:s,ratio:a}of t.pitch)s.setTargetAtTime(Math.min(e.pitchHz*a,i.sampleRate/2-1),n,pf)}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 a=t.createGain();return a.gain.value=0,i.connect(s),n.connect(s),s.connect(a).connect(this.output(t)),i.start(),n.start(),{key:e,nodes:[s,a],sources:[i,n],volumeParam:a.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(),a=t.createGain();return a.gain.value=0,n.connect(s).connect(i.frequency),i.connect(a).connect(this.output(t)),i.start(),n.start(),{key:e,nodes:[s,a],sources:[i,n],volumeParam:a.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(this.output(t)),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 a=t.createBufferSource();a.buffer=this.crackleEnvelope(t),a.loop=!0;const o=t.createGain();return o.gain.value=0,a.connect(o).connect(s.gain),i.connect(n).connect(s).connect(this.output(t)),i.start(),a.start(),{key:e,nodes:[n,s,o],sources:[i,a],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 a=n.createBufferSource();a.buffer=s,a.loop=!0;const o=n.createGain();o.gain.value=0,a.connect(o).connect(this.output(n)),a.start(),this.voice={key:e,nodes:[o],sources:[a],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*gf),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*gf),t.sampleRate),i=e.getChannelData(0);let n=0,s=0;for(let a=0;a<i.length;a++)n=(n+.02*(Math.random()*2-1))/1.02,i[a]=n,s=Math.max(s,Math.abs(n));if(s>0)for(let a=0;a<i.length;a++)i[a]/=s;return e}crackleEnvelope(t){if(!this.crackleBuffer){const e=t.createBuffer(1,Math.floor(t.sampleRate*vf),t.sampleRate),i=e.getChannelData(0),n=Math.max(1,Math.floor(Uv*t.sampleRate)),s=Math.round(vf*Fv);for(let a=0;a<s;a++){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,mf/3);const n=i+mf;for(const s of t.sources){s.onended=()=>{s.disconnect();for(const a of t.nodes)a.disconnect()};try{s.stop(n)}catch{s.disconnect();for(const a of t.nodes)a.disconnect()}}}}class Zt{static svg(t){return`<svg viewBox="0 0 24 24" width="1.5em" height="1.5em" aria-hidden="true" focusable="false"><path d="${t}" fill="currentColor"/></svg>`}static outline(t){return`<svg viewBox="0 0 24 24" width="1.5em" height="1.5em" aria-hidden="true" focusable="false"><path d="${t}" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round" stroke-linecap="round"/></svg>`}static solid(t){return`<svg viewBox="0 0 24 24" width="1.5em" height="1.5em" aria-hidden="true" focusable="false"><path d="${t}" fill="currentColor" fill-rule="evenodd"/></svg>`}static BOOKMARK="M6 3.5h12a.5.5 0 0 1 .5.5v16.5L12 16.8l-6.5 3.7V4a.5.5 0 0 1 .5-.5z";static PICTURE="M5 4h14a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z";static PICTURE_HILLS="M4.5 17.5l4.5-6 3 4 2.5-3 5 5z";static PIN="M12 21.5s-6.5-5.7-6.5-10.8a6.5 6.5 0 0 1 13 0c0 5.1-6.5 10.8-6.5 10.8z";static PIN_HOLE="M12 8.4a2.4 2.4 0 1 0 0 4.8 2.4 2.4 0 0 0 0-4.8z";static MILESTONES_OFF=Zt.outline(Zt.BOOKMARK);static MILESTONES_ON=Zt.solid(Zt.BOOKMARK);static PICTURES_OFF=Zt.outline(`${Zt.PICTURE}${Zt.PICTURE_HILLS}`);static PICTURES_ON=Zt.solid(`${Zt.PICTURE}${Zt.PICTURE_HILLS}`);static MAP_OFF=Zt.outline(`${Zt.PIN}${Zt.PIN_HOLE}`);static MAP_ON=Zt.solid(`${Zt.PIN}${Zt.PIN_HOLE}`);static SHARE=Zt.outline("M14 4l7 7-7 7v-4.2C8.6 13.8 5.4 15.6 3.5 19c.6-5.6 3.4-9.6 10.5-10.8V4z");static FOLDED=Zt.svg("M15.4 7.4 14 6l-6 6 6 6 1.4-1.4L10.8 12z");static UNFOLDED=Zt.svg("M8.6 16.6 10 18l6-6-6-6-1.4 1.4 4.6 4.6z");static PLAY=Zt.svg("M7.4 5v14l11-7z");static PAUSE=Zt.svg("M6 5h4v14H6zM14 5h4v14h-4z");static VOLUME=Zt.svg("M2 9.5v5h3.5l4.5 4.5V5L5.5 9.5H2zm12.5 2.5A4 4 0 0 0 12.5 8.5v7A4 4 0 0 0 14.5 12zM12.5 4.2v2.1a6.5 6.5 0 0 1 0 11.4v2.1a8.6 8.6 0 0 0 0-15.6z");static MUTED=Zt.svg("M2 9.5v5h3.5l4.5 4.5V5L5.5 9.5H2zM15 9.8l1.4-1.4 2.6 2.6 2.6-2.6 1.4 1.4-2.6 2.6 2.6 2.6-1.4 1.4-2.6-2.6-2.6 2.6-1.4-1.4 2.6-2.6z");static ENTER_FULLSCREEN=Zt.svg("M5 5h5v2H7v3H5V5zm9 0h5v5h-2V7h-3V5zM5 14h2v3h3v2H5v-5zm12 0h2v5h-5v-2h3v-3z");static EXIT_FULLSCREEN=Zt.svg("M8 5h2v5H5V8h3V5zm6 0h2v3h3v2h-5V5zM5 14h5v5H8v-3H5v-2zm9 0h5v2h-3v3h-2v-5z")}function So(r){return[...r].sort((t,e)=>t.t-e.t)}function ih(r,t){let e;for(const i of So(r)){if(i.t>t)break;e=i}return e}const nh=Math.PI/180,nc=180/Math.PI;class Ss{constructor(t,e,i){this.kind=t,this.canvasHeightPx=e,this.fovDeg=i;const n=i*nh/2;this.focalPx=t==="equidistant"?e/2/n:e/2/Math.tan(n)}focalPx;static of(t,e,i){return new Ss(t.projection,e,i)}degToPx(t){const e=t*nh;return this.kind==="equidistant"?this.focalPx*e:2*this.focalPx*Math.tan(e/2)}pxToDeg(t){return this.kind==="equidistant"?t/this.focalPx*nc:2*Math.atan(t/(2*this.focalPx))*nc}angleDegToRadiusPx(t){const e=t*nh;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*nc:Math.atan(t/this.focalPx)*nc}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(Te.angularWidthDeg(t))}}class Ji{static fovOf(t,e){return di(t,e)?.fovDeg??fi.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),a={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:a};const o=e.bounds.width===0?1:n/e.bounds.width,c=e.bounds.height===0?1:s/e.bounds.height;return{...e,bounds:a,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)<Ji.UNMOVED_PX&&Math.abs(s.y-e.bounds.y)<Ji.UNMOVED_PX)return e;const a=this.aimFrom(t,i,n,e.bounds);return a?{...e,aim:a}:e})}static UNMOVED_PX=.01;static aimOf(t,e,i){const n=Ss.of(t.instrument,Te.CANVAS_HEIGHT_PX,this.fovOf(t,e));return this.aimFrom(t,n,di(t,e),i)}static aimFrom(t,e,i,n){if(i?.headingDeg===void 0)return;const s=this.frameCentre(t),a=e.radiusPxToAngleDeg(n.x+n.width/2-s.x),o=e.radiusPxToAngleDeg(s.y-(n.y+n.height/2));return{azimuthDeg:((i.headingDeg+a)%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 a=this.frameCentre(t),o=this.shortestArc(e.azimuthDeg-s.headingDeg),c=e.altitudeDeg-s.pitchDeg;return{x:a.x+this.offAxisPx(n,o)-i.width/2,y:a.y-this.offAxisPx(n,c)-i.height/2}}static frameCentre(t){return{x:fi.frameWidthPx(t.instrument,Te.CANVAS_HEIGHT_PX)/2,y:Te.CANVAS_HEIGHT_PX/2}}static shortestArc(t){return(t%360+540)%360-180}static offAxisPx(t,e){return Math.abs(e)>=Ji.OFF_CANVAS_DEG?Math.sign(e)*Ji.OFF_CANVAS_PX:t.angleDegToRadiusPx(e)}static OFF_CANVAS_DEG=89;static OFF_CANVAS_PX=1e5;static reproject(t,e,i){const n=fi.frameWidthPx(e,Te.CANVAS_HEIGHT_PX)/2,s=fi.frameWidthPx(t.instrument,Te.CANVAS_HEIGHT_PX)/2,a=Te.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=Ss.of(e,Te.CANVAS_HEIGHT_PX,l),u=Ss.of(t.instrument,Te.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-a,m=Math.hypot(p,v),g=m===0?1:u.angleDegToRadiusPx(h.radiusPxToAngleDeg(m))/m,S={...f,x:s+p*g-f.width/2,y:a+v*g-f.height/2};return{...d,shape:{...d.shape,bounds:S}}}))}this.toBounds(t)}static eachKeyframe(t,e){const{timeline:i}=t;for(const n of[...i.allKeyframes]){const s=di(t,n.t),a=this.fovOf(t,n.t),o=Ss.of(t.instrument,Te.CANVAS_HEIGHT_PX,a);i.addKeyframe(n.t,n.shapes.map(c=>({...c,shape:e(c.shape,o,s)})))}}}function zv(r){return Mn.restore(Bv(r),r.provenance)}function Bv(r){return Ji.toAngular(r),Ji.toAim(r),{version:1,id:r.id,time:r.event.time,endTime:r.event.endTime,durationSeconds:r.event.durationSeconds,utcOffsetHours:r.event.utcOffsetHours,timeZone:r.event.timeZone,place:r.event.place,observer:r.observer,account:r.account,sources:r.sources?.length?r.sources:void 0,sway:r.sway,vehicle:r.vehicle,description:r.event.description,tags:r.event.tags,timeline:r.timeline.toJSON(),observerTrack:r.observerTrack.toJSON(),weatherTrack:r.weatherTrack.toJSON(),soundTrack:r.soundTrack.toJSON(),weather:r.weather,decor:r.decor,milestones:r.milestones.length>0?r.milestones:void 0,references:r.references.length>0?r.references:void 0,roads:r.roads.length>0?r.roads:void 0,weatherSource:r.weatherSource,instrument:r.instrumentId,exposureSeconds:r.exposureSeconds,iso:r.iso,lightPollution:r.lightPollution,interpretation:r.interpretation}}function Hv(r){const{recording:t,provenance:e}=Mn.strip(r),i=Gv(t);return i.provenance=e,i}function Gv(r){const t=[],e=new zl({eventType:"sighting",time:r.time,endTime:r.endTime,durationSeconds:r.durationSeconds,utcOffsetHours:r.utcOffsetHours,timeZone:r.timeZone,place:r.place,description:r.description,tags:r.tags},kl.fromJSON(r.timeline,t),r.observerTrack?Lo.fromJSON(r.observerTrack):new Lo,r.weatherTrack?Oo.fromJSON(r.weatherTrack):new Oo,r.soundTrack?No.fromJSON(r.soundTrack):new No,r.observer&&{id:r.observer.id,title:r.observer.title,lastName:r.observer.lastName,firstNames:r.observer.firstNames},r.id,r.weather,r.decor??[],r.weatherSource,r.instrument,r.exposureSeconds??r.observerTrack?.keyframes.map(i=>i.pose.exposureSeconds).find(i=>i!==void 0),So(r.milestones??[]),r.references??[],r.roads??[]);return e.account=r.account,e.sources=r.sources,e.sway=r.sway,e.iso=r.iso,e.lightPollution=r.lightPollution,e.vehicle=r.vehicle,e.interpretation=r.interpretation,e.loadIssues=t,Ji.toBounds(e),Ji.toPosition(e),e}class Pr{static EN={"unknown-key":"{path}: unknown key, ignored","wrong-type":"{path}: expected {expected}, found {found}","not-in-list":"{path}: {found} is not one of {expected}",defaulted:"{path}: missing, {expected} used",unplaced:"{path}: no aim (and no bounds), drawn at the middle of the view",unsized:"{path}: no angular size (and no bounds), drawn one pixel wide","pixels-over-angles":"{path}: bounds restated without aim or angular, so the shape follows the pixels"};static text(t,e=Pr.EN){return e[t.kind].replace("{path}",t.path).replace("{expected}",t.expected??"").replace("{found}",t.found??"")}static warn(t,e){if(t.length===0)return;const i=t.map(n=>` ${Pr.text(n)}`);console.warn(`UFO@home: ${t.length} problem(s) in ${e??"this recording"}:
|
|
1342
1342
|
${i.join(`
|
|
1343
|
-
`)}`)}}class An{constructor(t){this.format=t}issues(t){const e=[];return this.object(t,this.format,"",e),e}object(t,e,i,n){if(!An.isObject(t)){n.push({kind:"wrong-type",path:i||"(the file)",expected:"object",found:An.typeOf(t)});return}for(const[s,a]of Object.entries(t)){const o=i?`${i}.${s}`:s,c=e[s];c?this.field(a,c,o,n):n.push({kind:"unknown-key",path:o})}}field(t,e,i,n){if(An.isStated(t)){this.field(t.value,e,i,n);return}if(!(e.loose||t===void 0||t===null))switch(e.type){case"enum":(typeof t!="string"||!e.values?.includes(t))&&n.push({kind:"not-in-list",path:i,expected:(e.values??[]).map(s=>`"${s}"`).join(", "),found:JSON.stringify(t)});return;case"object":e.fields?this.object(t,e.fields,i,n):An.isObject(t)||n.push({kind:"wrong-type",path:i,expected:"object",found:An.typeOf(t)});return;case"array":Array.isArray(t)?e.fields&&t.forEach((s,a)=>{const o=An.isStated(s)?s.value:s;this.object(o,e.fields,`${i}.${a}`,n)}):n.push({kind:"wrong-type",path:i,expected:"array",found:An.typeOf(t)});return;default:typeof t!==e.type&&n.push({kind:"wrong-type",path:i,expected:e.type,found:An.typeOf(t)})}}static isObject(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}static isStated(t){return An.isObject(t)&&"value"in t&&Object.keys(t).every(e=>e==="value"||e==="basis"||e==="rationale")}static typeOf(t){return Array.isArray(t)?"array":t===null?"null":typeof t}}class Cn{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 a=s>0?Cn.travelDegOver(t,e,i,i+n*1e3)/s/Cn.PIXELS_PER_INSTANT:0,o=Cn.flashesOver(t,n)*Cn.INSTANTS_PER_FLASH,c=Math.ceil(Math.max(a,o));return c<2?1:Math.min(Cn.MAX_INSTANTS,c)}static travelDegOver(t,e,i,n){let s=0;for(const a of t){if(!a.track||a.track.length<2)continue;const o=Cn.directionAt(a,e,i),c=Cn.directionAt(a,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=Co(t,i),s=n.eastM,a=n.altitudeM-e,o=n.northM,c=Math.hypot(s,a,o);return c===0?{x:0,y:1,z:0}:{x:s/c,y:a/c,z:o/c}}}function cg(r,t){for(const e of r){const i=e.toLowerCase().split("-")[0];if(t.includes(i))return i}return"en"}class pl{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 Ks{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[Ks.base(i)];if(n)return n}const e=new Set(this.preferences.map(i=>Ks.base(i)));for(const[i,n]of Object.entries(t))if(n&&e.has(Ks.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},a=Object.keys(s).find(o=>o===i)??Object.keys(s).find(o=>Ks.base(o)===Ks.base(i))??i;return n===void 0?delete s[a]:s[a]=n,Object.keys(s).length===0?void 0:s}static base(t){return t.toLowerCase().split("-")[0]}}const lg=["en","fr","es","it"],Vv={en:()=>is(()=>Promise.resolve().then(()=>Yv),void 0,import.meta.url).then(r=>r.ufoMessages_en),fr:()=>is(()=>import("./UfoMessages_fr-BnjRvJ7U.js"),[],import.meta.url).then(r=>r.ufoMessages_fr),es:()=>is(()=>import("./UfoMessages_es-Cm0EH1RY.js"),[],import.meta.url).then(r=>r.ufoMessages_es),it:()=>is(()=>import("./UfoMessages_it-BsE5MTYw.js"),[],import.meta.url).then(r=>r.ufoMessages_it)};function Wv(r){return Vv[r]()}function Xv(r){switch(r){case"fr":return is(()=>import("./SceneNames_fr-BbDQV822.js"),[],import.meta.url).then(t=>t.sceneNames_fr);case"es":return is(()=>import("./SceneNames_es-D17SooUd.js"),[],import.meta.url).then(t=>t.sceneNames_es);case"it":return is(()=>import("./SceneNames_it-DLcaIKpK.js"),[],import.meta.url).then(t=>t.sceneNames_it);default:return Promise.resolve(void 0)}}const hg={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",mute:"Mute",unmute:"Unmute",moments:"Moments",moreControls:"More controls",fewerControls:"Fewer controls",showObserverMap:"Show where the observer was",hideObserverMap:"Hide where the observer was",mapImageryUnavailable:"Aerial imagery unavailable",zoomMapIn:"Zoom in",zoomMapOut:"Zoom out",fitMap:"Back to the whole path",placeObserverHere:"Put the observer here",showReferences:"Show the pictures of the place",hideReferences:"Hide the pictures of the place",referenceOpacity:"Picture opacity",showMilestones:"Show the account's moments",hideMilestones:"Hide the account's moments",observerHere:"The observer, here",decorHere:"Scenery",recordingIssues:"{count} problem(s) in this recording: it may not play as its author meant",issueTemplates:Pr.EN},Yv=Object.freeze(Object.defineProperty({__proto__:null,ufoMessages_en:hg},Symbol.toStringTag,{value:"Module"})),ug=Math.PI/180,qv=180/Math.PI,$v=256,dg=19,Kv=1.25;function fg(r,t){return 156543.03392*Math.cos(r*ug)/2**t}function pg(r,t){return fg(r,t)*$v}function Zv(r,t){let e=0;for(;e<dg&&pg(r,e+1)>=t;)e++;return e}function mg(r,t){return pg(r,t)}function Jv(r,t){const e=t*Kv;let i=0;for(;i<dg&&fg(r,i)>e;)i++;return i}function el(r){const t=r*ug;return(1-Math.log(Math.tan(t)+1/Math.cos(t))/Math.PI)/2}function gg(r,t,e){const i=2**e;return{x:(r+180)/360*i,y:el(t)*i}}function vg(r,t,e){const i=el(r.north),n=el(r.south);return{x:(t-r.west)/(r.east-r.west),y:(el(e)-i)/(n-i)}}function jv(r,t,e){const{x:i,y:n}=gg(r,t,e);return{x:Math.floor(i),y:Math.floor(n),z:e}}function Qv(r){const t=2**r.z,e=r.x/t*360-180,i=(r.x+1)/t*360-180,n=Mf(r.y,t);return{south:Mf(r.y+1,t),north:n,west:e,east:i}}function Mf(r,t){const e=r/t;return Math.atan(Math.sinh(Math.PI*(1-2*e)))*qv}function Mg(r,t,e,i){const n=jv(r,t,e),s=Math.floor(i/2),a=[];for(let l=-s;l<=s;l++)for(let h=-s;h<=s;h++)a.push({x:n.x+h,y:n.y+l,z:e});const o=a.map(Qv),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:a,bounds:c}}class Ma{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 a=Math.hypot(s.x-t,s.y-e);a>s.radius||a>n||(i=s,n=a)}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.paintObserver(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=vg(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,a=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(a.x,a.y),s.arc(a.x,a.y,o,c-l,c+l),s.closePath();const h=s.createRadialGradient(a.x,a.y,0,a.x,a.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:Ma.MARKER_RADIUS_PX}),e.beginPath(),e.arc(n.x,n.y,Ma.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)}}paintObserver(t,e){const{ctx:i}=this,n=this.toCanvas(t.bounds,e.lat,e.lng);t.observerLabel&&this.targets.push({kind:"observer",label:t.observerLabel,lat:e.lat,lng:e.lng,x:n.x,y:n.y,radius:8});const s=t.markers.some(a=>{if(!a.current)return!1;const o=ai(a.lat,a.lng,e.lat,e.lng);return Math.hypot(o.x,o.z)<=Ma.ON_MARKER_M});i.beginPath(),i.arc(n.x,n.y,s?Ma.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 a=(t.south+t.north)/2,c=Math.abs(ai(a,t.east,a,t.west).x)/this.width,l=Ma.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 a=n?`${n} ${s}`:s;n&&this.ctx.measureText(a).width>e?(i.push(n),n=s):n=a}return n&&i.push(n),i}}class Ye{static MIN_ZOOM=.25;static MAX_ZOOM=64;zoom=1;centerX=.5;centerY=.5;get changed(){return this.zoom!==1||this.centerX!==.5||this.centerY!==.5}get zoomFactor(){return this.zoom}reset(){this.zoom=1,this.centerX=.5,this.centerY=.5}zoomAt(t,e,i){const n=Math.min(Ye.MAX_ZOOM,Math.max(Ye.MIN_ZOOM,this.zoom*i)),s=this.centerX+(t-.5)/this.zoom,a=this.centerY+(e-.5)/this.zoom;this.centerX=s-(t-.5)/n,this.centerY=a-(e-.5)/n,this.zoom=n}panBy(t,e){this.centerX-=t/this.zoom,this.centerY-=e/this.zoom}refit(t,e){if(!this.changed)return;const i=this.boundsWithin(t),n=Ye.mercatorY01(e.north),s=Ye.mercatorY01(e.south),a=Ye.mercatorY01(i.north),o=Ye.mercatorY01(i.south);this.zoom=(e.east-e.west)/(i.east-i.west),this.centerX=((i.west+i.east)/2-e.west)/(e.east-e.west),this.centerY=((a+o)/2-n)/(s-n)}keepInView(t,e,i){if(!this.changed)return!1;const n=this.boundsWithin(t),s=Ye.mercatorY01(n.north),a=Ye.mercatorY01(n.south),o=(e.lng-n.west)/(n.east-n.west),c=(Ye.mercatorY01(e.lat)-s)/(a-s);return o>=i&&o<=1-i&&c>=i&&c<=1-i?!1:(this.panBy(.5-o,.5-c),!0)}boundsWithin(t){if(!this.changed)return t;const e=.5/this.zoom,i=Ye.mercatorY01(t.north),n=Ye.mercatorY01(t.south),s=t.east-t.west;return{west:t.west+(this.centerX-e)*s,east:t.west+(this.centerX+e)*s,north:Ye.latitudeAt(i+(this.centerY-e)*(n-i)),south:Ye.latitudeAt(i+(this.centerY+e)*(n-i))}}static expand(t,e){const i=t.east-t.west,n=t.north-t.south;return{west:t.west-i*e,east:t.east+i*e,south:t.south-n*e,north:t.north+n*e}}static pointAt(t,e,i){const n=Ye.mercatorY01(t.north),s=Ye.mercatorY01(t.south);return{lat:Ye.latitudeAt(n+i*(s-n)),lng:t.west+e*(t.east-t.west)}}static mercatorY01(t){const e=t*Math.PI/180;return(1-Math.log(Math.tan(e)+1/Math.cos(e))/Math.PI)/2}static latitudeAt(t){return Math.atan(Math.sinh(Math.PI*(1-2*t)))*180/Math.PI}}const fn=256,xf=3,t2=32768;class e2{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(ai(i,t.east,i,t.west).x),a=Math.abs(ai(t.north,n,t.south,n).z),o=Zv(i,Math.max(s,a)),{tiles:c}=Mg(n,i,o,xf),l=xf*fn,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)),a=await this.fetchImpl(s);if(!a.ok)throw new Error(`Elevation tile fetch failed (${a.status}): ${s}`);const o=await createImageBitmap(await a.blob()),c=document.createElement("canvas");c.width=fn,c.height=fn;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,fn,fn),u=(t.x-e.x)*fn,d=(t.y-e.y)*fn;for(let f=0;f<fn;f++)for(let p=0;p<fn;p++){const v=(f*fn+p)*4,m=h[v]*256+h[v+1]+h[v+2]/256-t2,g=u+p,S=d+f;i[S*n+g]=m}}sampleAt(t,e,i,n,s,a){const{x:o,y:c}=gg(e,t,i),l=(o-n.x)*fn,h=(c-n.y)*fn,u=Math.max(0,Math.min(a-1,Math.floor(l))),d=Math.max(0,Math.min(a-1,Math.floor(h))),f=Math.min(a-1,u+1),p=Math.min(a-1,d+1),v=l-u,m=h-d,g=s[d*a+u],S=s[d*a+f],y=s[p*a+u],M=s[p*a+f],b=g+(S-g)*v,w=y+(M-y)*v;return b+(w-b)*m}}const il=256,i2=5;async function n2(r,t,e,i){const n=(r.south+r.north)/2,s=(r.west+r.east)/2,a=Math.abs(ai(n,r.east,n,r.west).x),o=Math.abs(ai(r.north,s,r.south,s).z),c=Math.max(a,o),{zoom:l,gridSize:h}=s2(n,c,Math.max(t.width,t.height)),{tiles:u,bounds:d}=Mg(s,n,l,h),f=h*il,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 b=e(M),w=await i(b);if(!w.ok)throw new Error(`Imagery tile fetch failed (${w.status}): ${b}`);const T=await createImageBitmap(await w.blob());v.drawImage(T,(M.x-m.x)*il,(M.y-m.y)*il)}));const g=Math.min(Math.max(t.width,t.height),f);if(g===f)return{source:p,width:f,height:f,bounds:d};const S=document.createElement("canvas");S.width=g,S.height=g;const y=S.getContext("2d");if(!y)throw new Error("2D canvas context unavailable");return y.drawImage(p,0,0,f,f,0,0,g,g),{source:S,width:g,height:g,bounds:d}}function s2(r,t,e){let i=Jv(r,t/Math.max(1,e)),n=yf(r,i,t);for(;n>i2&&i>0;)i--,n=yf(r,i,t);return{zoom:i,gridSize:n,mPerPixel:mg(r,i)/il}}function yf(r,t,e){const i=Math.ceil(e/2/mg(r,t));return Math.max(3,2*i+1)}class a2{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 n2(t,e,i=>this.tileUrlTemplate.replace("{z}",String(i.z)).replace("{y}",String(i.y)).replace("{x}",String(i.x)),this.fetchImpl)}}class Tn{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??Tn.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"~"^(${Tn.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:Tn.surfaceOf(s),widthM:Tn.widthOf(s),points:n.map(a=>({lat:a.lat,lng:a.lon}))})}return e}queued(t){const e=Tn.queue.then(t,t);return Tn.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,Tn.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:Tn.WIDTH_M[t.highway]??Tn.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 sh="https://ufoathome.org/roads/index.json";class t0{attributionRead;contemporaryRead;fetchImpl;indexUrls;fallback;index;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??t0.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.81.4")}`,e=typeof location>"u"?void 0:new URL("/roads/index.json",location.href).href;return(e&&e!==sh?[e,sh]:[sh]).map(i=>i+t)}}function r2(){return{elevation:new e2,imagery:xg(),roads:o2()}}function xg(){return new a2}function o2(){return new t0({fallback:new Tn})}const c2=new Set,_r="show-observer-map",Sr="hide-milestones";class fe extends HTMLElement{static get observedAttributes(){return["src",_r,Sr]}shadow;stageElement;canvas;canvasRenderer;tooltip;toolbar;issuesBox;issuesButton;issuesPanel;playPauseButton;static OBSERVER_MAP_MIN_SPAN_M=400;static OBSERVER_MAP_MARGIN=.6;static OBSERVER_MAP_IMAGERY_PX=768;fullscreenButton;cornerButtons;observerMapButton;referencesButton;referenceOpacityInput;referencesShownState=!0;referenceOpacityTouched=!1;milestonesButton;observerMapPanel;observerMapCanvas;observerMapRenderer;mapZoomInButton;mapZoomOutButton;mapFitButton;observerMapView=new Ye;observerMapDrag;suppressObserverMapClick=!1;observerMapImageryTimer;observerPlacing=!1;seekInput;playbackFlash;milestoneMarks;milestoneCaption;timeStartLabel;timeEndLabel;timePill;muteButton;volumeInput;controlsRow;momentsBox;momentsButton;momentsCurrent;momentsMenu;moreButton;controlsRight;seekSegments;seekDot;seekPreview;seekPreviewCanvas;seekPreviewTitle;seekPreviewTime;observerPath;observerMapBounds;observerMapImagery;observerMapImageryBounds;observerMapImageryViewWidth=0;observerMapImageryLoading=!1;observerMapImageryCredit;observerMapImageryFailed=!1;creditShownExternally=!1;lookYawDeg=0;lookPitchDeg=0;milestonesShown=!0;currentSighting=zl.create();issues=[];issueCheck=0;sightingAudio=new kv;soundPreview;player;loopEnabled=!1;playbackBeforeClick;highlightedSourceIds=new Set;paintsShapes=!0;steadyObserver=!1;selectionShown=!0;overlayPainter;enableClickToPlay=!0;fullscreenTarget;messages=hg;realDurationMs;realStartMs;showClockTime=!0;handleFullscreenChange=()=>{this.updateFullscreenButton(),this.updateMuteButton(),this.resizeObserverMap()};controlsFitObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>this.fitControls());controlsMutations;fitControls(){const t=this.controlsRow,e=t.classList.contains("more-open"),i=()=>t.scrollWidth>t.clientWidth+1,n=!this.momentsMenu.hidden;if(this.momentsMenu.hidden=!0,t.classList.remove("narrow","more-open","nomoments","compact","tiny"),t.clientWidth>0&&i()){t.classList.add("narrow");for(const s of["nomoments","compact","tiny"]){if(!i())break;t.classList.add(s)}e&&t.classList.add("more-open")}this.momentsMenu.hidden=!n,this.updateMoreButton()}setControlsFolded(t){this.controlsRow.classList.toggle("more-open",!t),this.updateMoreButton()}updateMoreButton(){const t=this.controlsRow.classList.contains("more-open");fe.setIcon(this.moreButton,t?Zt.UNFOLDED:Zt.FOLDED);const e=t?this.messages.fewerControls:this.messages.moreControls;this.moreButton.title=e,this.moreButton.setAttribute("aria-label",e),this.moreButton.setAttribute("aria-expanded",String(t))}addControl(t){this.controlsRight.insertBefore(t,this.fullscreenButton.parentElement===this.controlsRight?this.fullscreenButton:null),this.fitControls()}observerMapResizeObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>this.resizeObserverMap());resizeObserverMap(){this.observerMapPanel.hidden||(this.sizeObserverMapCanvas(),this.paintObserverMap(this.currentTime))}simulatedFullscreen=!1;styleBeforeSimulatedFullscreen;bodyOverflowBeforeSimulatedFullscreen;handleSimulatedFullscreenKey=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`};handleObserverMapPointerMove=t=>{if(this.dragObserverMap(t))return;const e=this.observerMapTargetFrom(t);if(!e){if(!this.observerPlacing){this.tooltip.hidden=!0,this.observerMapCanvas.style.cursor="grab";return}this.observerMapCanvas.style.cursor="crosshair",this.showObserverMapTooltip(t,this.messages.placeObserverHere);return}this.observerMapCanvas.style.cursor="pointer",this.showObserverMapTooltip(t,e.label)};showObserverMapTooltip(t,e){this.tooltip.textContent=e,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`}handleObserverMapClick=t=>{if(this.suppressObserverMapClick){this.suppressObserverMapClick=!1;return}const e=this.observerMapTargetFrom(t);if(!e){this.observerPlacing&&this.placeObserverFrom(t);return}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}))};observerMapTargetFrom(t){const e=this.observerMapCanvas.getBoundingClientRect();if(!(e.width===0||e.height===0))return this.observerMapRenderer.hitTest((t.clientX-e.left)/e.width*this.observerMapCanvas.width,(t.clientY-e.top)/e.height*this.observerMapCanvas.height)}handlePointerLeave=()=>{this.tooltip.hidden=!0};handleObserverMapPointerDown=t=>{t.button===0&&(this.suppressObserverMapClick=!1,this.observerMapDrag={pointerId:t.pointerId,startX:t.clientX,startY:t.clientY,lastX:t.clientX,lastY:t.clientY,moved:!1})};handleObserverMapPointerUp=t=>{const e=this.observerMapDrag;!e||e.pointerId!==t.pointerId||(this.observerMapDrag=void 0,this.observerMapCanvas.classList.remove("dragging"),e.moved&&(this.suppressObserverMapClick=!0,this.paintObserverMap(this.currentTime),this.observerMapCanvas.hasPointerCapture?.(t.pointerId)&&this.observerMapCanvas.releasePointerCapture(t.pointerId)))};dragObserverMap(t){const e=this.observerMapDrag;if(!e||e.pointerId!==t.pointerId)return!1;if(!e.moved){if(Math.hypot(t.clientX-e.startX,t.clientY-e.startY)<fe.OBSERVER_MAP_DRAG_PX)return!1;e.moved=!0,this.tooltip.hidden=!0,this.observerMapCanvas.classList.add("dragging"),this.observerMapCanvas.setPointerCapture?.(t.pointerId)}const i=this.observerMapCanvas.getBoundingClientRect();return i.width>0&&i.height>0&&(this.observerMapView.panBy((t.clientX-e.lastX)/i.width,(t.clientY-e.lastY)/i.height),this.observerMapViewChanged()),e.lastX=t.clientX,e.lastY=t.clientY,!0}static OBSERVER_MAP_DRAG_PX=4;handleObserverMapWheel=t=>{t.preventDefault();const e=this.observerMapCanvas.getBoundingClientRect();if(e.width===0||e.height===0)return;const i=t.deltaMode===0?t.deltaY:t.deltaY*40;this.zoomObserverMap((t.clientX-e.left)/e.width,(t.clientY-e.top)/e.height,Math.exp(-i*.002))};zoomObserverMap(t,e,i){this.observerMapView.zoomAt(t,e,i),this.observerMapViewChanged()}observerMapViewChanged(){this.mapFitButton.hidden=!this.observerMapView.changed,this.mapZoomInButton.disabled=this.observerMapView.zoomFactor>=Ye.MAX_ZOOM,this.mapZoomOutButton.disabled=this.observerMapView.zoomFactor<=Ye.MIN_ZOOM,this.paintObserverMap(this.currentTime),this.scheduleObserverMapImagery()}scheduleObserverMapImagery(){this.observerMapImageryTimer===void 0&&(this.observerMapImageryTimer=setTimeout(()=>{this.observerMapImageryTimer=void 0,this.loadObserverMapImagery()},fe.OBSERVER_MAP_IMAGERY_DELAY_MS))}static OBSERVER_MAP_FOLLOW_MARGIN=.1;static OBSERVER_MAP_IMAGERY_DELAY_MS=300;get observerMapViewBounds(){return this.observerMapBounds&&this.observerMapView.boundsWithin(this.observerMapBounds)}placeObserverFrom(t){const e=this.observerMapViewBounds,i=this.observerMapCanvas.getBoundingClientRect();if(!e||i.width===0||i.height===0)return;const n=Ye.pointAt(e,(t.clientX-i.left)/i.width,(t.clientY-i.top)/i.height);this.dispatchEvent(new CustomEvent("observerplace",{detail:n,bubbles:!0,composed:!0}))}constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const t=document.createElement("template");t.innerHTML=`<style>${hv}</style>${lv}`,this.shadow.appendChild(t.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.canvas=this.shadow.getElementById("canvas"),this.canvasRenderer=new Fo(this.canvas.getContext("2d")),this.tooltip=this.shadow.getElementById("tooltip"),this.toolbar=this.shadow.getElementById("toolbar"),this.issuesBox=this.shadow.getElementById("issues"),this.issuesButton=this.shadow.getElementById("issues-button"),this.issuesPanel=this.shadow.getElementById("issues-panel"),this.issuesButton.addEventListener("click",e=>{e.stopPropagation(),this.issuesPanel.hidden=!this.issuesPanel.hidden,this.issuesButton.setAttribute("aria-expanded",String(!this.issuesPanel.hidden))}),this.playPauseButton=this.shadow.getElementById("play-pause"),this.fullscreenButton=this.shadow.getElementById("fullscreen"),this.cornerButtons=this.shadow.getElementById("corner-buttons"),this.observerMapButton=this.shadow.getElementById("observer-map"),this.referencesButton=this.shadow.getElementById("references"),this.referenceOpacityInput=this.shadow.getElementById("reference-opacity"),this.milestonesButton=this.shadow.getElementById("milestones"),this.observerMapPanel=this.shadow.getElementById("observer-map-panel"),this.observerMapCanvas=this.shadow.getElementById("observer-map-canvas"),this.observerMapRenderer=new Ma(this.observerMapCanvas.getContext("2d")),this.mapZoomInButton=this.shadow.getElementById("map-zoom-in"),this.mapZoomOutButton=this.shadow.getElementById("map-zoom-out"),this.mapFitButton=this.shadow.getElementById("map-fit"),this.seekInput=this.shadow.getElementById("seek"),this.playbackFlash=this.shadow.getElementById("playback-flash"),this.milestoneMarks=this.shadow.getElementById("milestone-marks"),this.milestoneCaption=this.shadow.getElementById("milestone-caption"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end"),this.timePill=this.shadow.getElementById("time"),this.muteButton=this.shadow.getElementById("mute"),this.controlsRight=this.shadow.getElementById("controls-right"),this.seekSegments=this.shadow.getElementById("seek-segments"),this.seekDot=this.shadow.getElementById("seek-dot"),this.seekPreview=this.shadow.getElementById("seek-preview"),this.seekPreviewCanvas=this.shadow.getElementById("seek-preview-canvas"),this.seekPreviewTitle=this.shadow.getElementById("seek-preview-title"),this.seekPreviewTime=this.shadow.getElementById("seek-preview-time"),this.timePill.addEventListener("click",()=>this.toggleTimeDisplay()),this.timePill.addEventListener("keydown",e=>{e.key!=="Enter"&&e.key!==" "||(e.preventDefault(),this.toggleTimeDisplay())}),this.volumeInput=this.shadow.getElementById("volume"),this.controlsRow=this.shadow.querySelector(".controls"),this.momentsBox=this.shadow.getElementById("moments"),this.momentsButton=this.shadow.getElementById("moments-button"),this.momentsCurrent=this.shadow.getElementById("moments-current"),this.momentsMenu=this.shadow.getElementById("moments-menu"),this.momentsButton.addEventListener("click",()=>this.toggleMomentsMenu()),this.moreButton=this.shadow.getElementById("controls-more"),this.moreButton.addEventListener("click",()=>this.setControlsFolded(this.controlsRow.classList.contains("more-open"))),this.muteButton.addEventListener("click",()=>this.toggleMuted()),this.volumeInput.addEventListener("input",()=>{this.setVolume(Number(this.volumeInput.value))}),this.fullscreenTarget=this.stageElement,this.playPauseButton.addEventListener("click",()=>this.togglePlayPause()),this.fullscreenButton.addEventListener("click",()=>this.toggleFullscreen()),this.addEventListener("keydown",this.handleFullscreenKey),this.observerMapButton.addEventListener("click",()=>this.toggleObserverMap()),this.referencesButton.addEventListener("click",()=>this.toggleReferences()),this.referenceOpacityInput.addEventListener("input",()=>{this.referenceOpacityTouched=!0,this.dispatchReferenceView()}),this.milestonesButton.addEventListener("click",()=>this.toggleMilestones()),this.observerMapCanvas.addEventListener("pointermove",this.handleObserverMapPointerMove),this.observerMapCanvas.addEventListener("pointerleave",this.handlePointerLeave),this.observerMapCanvas.addEventListener("click",this.handleObserverMapClick),this.observerMapCanvas.addEventListener("pointerdown",this.handleObserverMapPointerDown),this.observerMapCanvas.addEventListener("pointerup",this.handleObserverMapPointerUp),this.observerMapCanvas.addEventListener("pointercancel",this.handleObserverMapPointerUp),this.observerMapCanvas.addEventListener("wheel",this.handleObserverMapWheel,{passive:!1}),this.mapZoomInButton.addEventListener("click",()=>this.zoomObserverMap(.5,.5,2)),this.mapZoomOutButton.addEventListener("click",()=>this.zoomObserverMap(.5,.5,.5)),this.mapFitButton.addEventListener("click",()=>{this.observerMapView.reset(),this.observerMapViewChanged()}),this.seekInput.addEventListener("input",()=>this.player.seek(this.snapSeekToMark(Number(this.seekInput.value)))),this.seekInput.addEventListener("pointerdown",e=>{this.suspendForScrub(),this.seekSnapArmed=!0,this.nameMarkUnder(e),this.beginTouchScrub(e)}),this.seekInput.addEventListener("pointerup",e=>{this.seekSnapArmed=!1,this.endTouchScrub(e)}),this.seekInput.addEventListener("pointercancel",e=>this.endTouchScrub(e)),this.seekInput.addEventListener("pointermove",e=>{this.nameMarkUnder(e),this.hoverSeek(e),this.touchScrub(e)}),this.seekInput.addEventListener("pointerleave",()=>{this.seekInput.removeAttribute("title"),this.leaveSeek()}),this.seekInput.addEventListener("keydown",this.handleSeekKey),this.stageElement.addEventListener("pointerdown",()=>{this.handlePointerDown(),this.touchedStage()},!0);for(const e of["touchend","click"])this.stageElement.addEventListener(e,()=>this.sightingAudio.resume(),!0);this.stageElement.addEventListener("pointermove",()=>this.touchedStage()),this.canvas.addEventListener("click",e=>{if(this.enableClickToPlay){if(this.tapRevealedOnly){this.tapRevealedOnly=!1;return}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),document.addEventListener("pointerdown",this.handleMomentsDismiss,!0),document.addEventListener("keydown",this.handleMomentsDismiss,!0),document.addEventListener("visibilitychange",this.handleVisibility),window.addEventListener("pagehide",this.handleHidden),document.addEventListener("pointerup",this.handlePointerRelease,!0),document.addEventListener("pointercancel",this.handlePointerRelease,!0),this.observerMapResizeObserver?.observe(this.observerMapPanel),this.controlsFitObserver?.observe(this.controlsRow),this.controlsFitObserver?.observe(this.controlsRow.querySelector(".controls-left")),typeof MutationObserver<"u"&&(this.controlsMutations=new MutationObserver(()=>this.fitControls()),this.controlsMutations.observe(this.controlsRight,{attributes:!0,attributeFilter:["hidden"],childList:!0,subtree:!0})),this.hostControls(void 0),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateMuteButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateMilestonesButton(),this.refresh()}connectedCallback(){this.saidTexts=void 0,this.loadLocaleMessages();const t=this.getAttribute("src");t&&this.loadFromSrc(t)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.handleFullscreenChange),document.removeEventListener("pointerdown",this.handleMomentsDismiss,!0),document.removeEventListener("keydown",this.handleMomentsDismiss,!0),document.removeEventListener("visibilitychange",this.handleVisibility),window.removeEventListener("pagehide",this.handleHidden),document.removeEventListener("pointerup",this.handlePointerRelease,!0),document.removeEventListener("pointercancel",this.handlePointerRelease,!0),window.clearTimeout(this.controlsIdleTimer),this.observerMapResizeObserver?.disconnect(),this.controlsFitObserver?.disconnect(),this.controlsMutations?.disconnect(),this.exitSimulatedFullscreen(),this.sightingAudio.dispose()}attributeChangedCallback(t,e,i){t==="src"&&i&&i!==e&&this.isConnected&&this.loadFromSrc(i),t===_r&&this.applyObserverMapDefault(),t===Sr&&this.setMilestonesShown(!this.hasAttribute(Sr))}async loadFromSrc(t){this.sightingData=await rg.json(t)}get sightingData(){return zv(this.currentSighting)}set sightingData(t){this.player.stop(),this.soundPreview=void 0,this.sightingAudio.silence(),this.currentSighting=Hv(t),this.issuesPanel.hidden=!0,this.issuesButton.setAttribute("aria-expanded","false"),this.reportIssues(t,this.currentSighting),this.observerMapView.reset(),this.mapFitButton.hidden=!0,this.observerMapAsked=!1,this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.refresh(),this.applyObserverMapDefault()}get recordingIssues(){return this.issues}async reportIssues(t,e){const i=++this.issueCheck;let n=[];try{const{default:s}=await is(async()=>{const{default:a}=await import("./sightingSchema-DOOSOVWK.js");return{default:a}},[],import.meta.url);n=new An(s).issues(t)}catch{}i===this.issueCheck&&(this.issues=[...n,...e.loadIssues],Pr.warn(this.issues,e.id),this.renderIssues(),this.dispatchEvent(new CustomEvent(l2,{detail:{issues:this.issues},bubbles:!0,composed:!0})))}renderIssues(){const t=this.issues.length;this.issuesBox.hidden=t===0,this.shadow.getElementById("issues-count").textContent=String(t);const e=this.messages.recordingIssues.replace("{count}",String(t));this.issuesButton.title=e,this.issuesButton.setAttribute("aria-label",e),this.shadow.getElementById("issues-title").textContent=e,this.shadow.getElementById("issues-list").replaceChildren(...this.issues.map(i=>{const n=document.createElement("li");return n.textContent=Pr.text(i,this.messages.issueTemplates),n}))}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),t?this.controlsRight.appendChild(this.fullscreenButton):this.cornerButtons.appendChild(this.fullscreenButton)}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.updateObserverMap(),this.updateReferences(),this.player.seek(this.player.time)}hostControls(t){const e=[this.milestonesButton,this.referencesButton,this.referenceOpacityInput,this.observerMapButton];if(t)for(const i of e)t.appendChild(i);else{const i=this.fullscreenButton.parentElement===this.controlsRight?this.fullscreenButton:null;for(const n of e)this.controlsRight.insertBefore(n,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)),fe.setIcon(this.referencesButton,this.referencesShownState?Zt.PICTURES_ON:Zt.PICTURES_OFF);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?So(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)??"",a=this.said.read(i.note),o=a?`${s} — ${a}`: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})),this.refreshSeekSegments(t,e.map(i=>i.t)),this.refreshMomentsPicker(e)}refreshMomentsPicker(t){const e=this.milestonesShown&&t.length>0;this.momentsBox.hidden=!e,this.closeMomentsMenu(),this.momentsMenu.replaceChildren(...t.map(i=>{const n=document.createElement("li"),s=document.createElement("button");s.type="button",s.dataset.t=String(i.t);const a=this.said.read(i.label)??"",o=this.said.read(i.note);return s.textContent=o?`${a} — ${o}`:a,s.addEventListener("click",()=>{this.player.seek(i.t),this.closeMomentsMenu()}),n.appendChild(s),n})),this.momentsButton.title=this.messages.moments,this.showCurrentMoment(void 0)}showCurrentMoment(t){const i=(t?this.said.read(t.label)??"":"")||this.messages.moments;this.momentsCurrent.textContent!==i&&(this.momentsCurrent.textContent=i);for(const n of this.momentsMenu.querySelectorAll("button")){const s=t!==void 0&&Number(n.dataset.t)===t.t;n.getAttribute("aria-current")==="true"!==s&&n.setAttribute("aria-current",String(s))}}toggleMomentsMenu(){this.momentsMenu.hidden?(this.momentsMenu.hidden=!1,this.momentsButton.setAttribute("aria-expanded","true")):this.closeMomentsMenu()}closeMomentsMenu(){this.momentsMenu.hidden=!0,this.momentsButton.setAttribute("aria-expanded","false")}handleMomentsDismiss=t=>{if(!this.momentsMenu.hidden){if(t instanceof KeyboardEvent){t.key==="Escape"&&this.closeMomentsMenu();return}t.composedPath().some(e=>e===this.momentsMenu||e===this.momentsButton)||this.closeMomentsMenu()}};seekSegmentList=[];refreshSeekSegments(t,e){const n=[0,...this.milestonesShown&&t>0?[...new Set(e.filter(a=>a>0&&a<t))].sort((a,o)=>a-o):[],Math.max(t,0)];this.seekSegmentList=[];const s=[];for(let a=0;a<n.length-1;a++){const o=document.createElement("div");o.className="seek-segment",o.style.flexGrow=String(Math.max(n[a+1]-n[a],1));const c=document.createElement("i");c.className="seek-hover";const l=document.createElement("i");l.className="seek-played",o.append(c,l),s.push(o),this.seekSegmentList.push({start:n[a],end:n[a+1],element:o,played:l,hover:c})}this.seekSegments.replaceChildren(...s),this.paintSeekProgress(this.player.time)}static fillOf(t,e){const i=t.end-t.start,n=i>0?(e-t.start)/i:e>=t.end?1:0;return`${Math.min(Math.max(n,0),1)*100}%`}paintSeekProgress(t){for(const i of this.seekSegmentList)i.played.style.width=fe.fillOf(i,t);const e=this.player.seekableDuration;this.seekDot.style.left=`${e>0?Math.min(Math.max(t/e,0),1)*100:0}%`}hoverSeek(t){const e=this.seekInput.getBoundingClientRect(),i=this.player.seekableDuration;if(e.width<=0||i<=0)return;const n=Math.min(Math.max((t.clientX-e.left)/e.width,0),1),s=n*i,a=this.seekSegmentList.length-1;this.seekSegmentList.forEach((f,p)=>{f.hover.style.width=fe.fillOf(f,s),f.element.classList.toggle("hovered",s>=f.start&&(s<f.end||p===a))});const o=this.milestonesShown?this.sighting.milestones:[],c=o.length>0?ih(o,s):void 0,l=c?this.said.read(c.label)??"":"",h=c?this.said.read(c.note):void 0,u=h?`${l} — ${h}`:l;this.seekPreviewTitle.textContent=u,this.seekPreviewTime.textContent=this.formatPosition(s),this.seekPreview.hidden=!1;const d=this.seekPreview.offsetWidth;this.seekPreview.style.left=`${Math.min(Math.max(n*e.width-d/2,0),Math.max(e.width-d,0))}px`,this.paintSeekPreview(s)}leaveSeek(){for(const t of this.seekSegmentList)t.hover.style.width="0",t.element.classList.remove("hovered");this.seekPreview.hidden=!0}seekPreviewPainter;paintSeekPreview(t){const e=this.seekPreviewPainter;this.seekPreviewCanvas.hidden=e===void 0,e?.(t,this.seekPreviewCanvas)}scrubbingPointer;beginTouchScrub(t){if(t.pointerType!=="mouse"){this.scrubbingPointer=t.pointerId;try{this.seekInput.setPointerCapture(t.pointerId)}catch{}this.seekToPointer(t)}}touchScrub(t){t.pointerId===this.scrubbingPointer&&this.seekToPointer(t)}endTouchScrub(t){t.pointerId===this.scrubbingPointer&&(this.scrubbingPointer=void 0,this.seekToPointer(t))}seekToPointer(t){const e=this.seekInput.getBoundingClientRect(),i=this.player.seekableDuration;if(e.width<=0||i<=0)return;const n=Math.min(Math.max((t.clientX-e.left)/e.width,0),1);this.player.seek(this.snapSeekToMark(n*i))}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=fe.MARK_SNAP_PX/i*e;let s;for(const a of this.milestoneMarks.children){const o=Number(a.dataset.t);Math.abs(o-t)>n||(!s||Math.abs(o-t)<Math.abs(s.t-t))&&(s={t:o,name:a.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?ih(this.sighting.milestones,t):void 0;if(this.milestoneCaption.hidden=e===void 0,this.showCurrentMoment(e),!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=Cn.windowEndingAt(t,this.currentSighting.exposure??0);if(e.ms<fe.SHORTEST_VISIBLE_EXPOSURE_MS)return[t];const i=Math.min(fe.MAX_EXPOSURE_STEPS,Math.max(2,Math.round(e.ms/fe.SHORTEST_VISIBLE_EXPOSURE_MS))),n=Math.ceil(this.travelPxOver(e.fromMs,e.ms)/fe.EXPOSURE_STEP_PX),s=Math.min(fe.MAX_TRAVEL_STEPS,Math.max(i,n)),a=[];for(let o=0;o<s;o++)a.push(e.fromMs+e.ms*o/(s-1));return a}travelPxOver(t,e){const i=this.shapesAt(t),n=this.shapesAt(t+e);let s=0;for(const[a,o]of i){const c=n.get(a);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=fi.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:c2;this.canvasRenderer.setStarPoints(fi.starPointsOf(this.sighting.instrument));const n=(di(this.sighting,t)?.rollDeg??0)+this.gaitAt(t).rollDeg;this.canvasRenderer.setRoll(n*Math.PI/180);const s=this.exposureInstants(t),a=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,a))}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,a)));if(this.selectionShown&&i.size>1){const o=cn.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,a).bounds)),this.keepObserverMapClear(),this.seekInput.value=String(t),this.paintSeekProgress(t),this.timeStartLabel.textContent=this.formatPosition(t),this.showMilestoneAt(t),this.paintObserverMap(t),this.playbackState==="playing"?(this.soundPreview=void 0,this.sightingAudio.setSound(Iv(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 Cv(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}static SEEK_KEY_STEP_MS=5e3;handleFullscreenKey=t=>{t.key.toLowerCase()!=="f"||t.altKey||t.ctrlKey||t.metaKey||!this.enableClickToPlay||t.composedPath().some(i=>i instanceof HTMLElement&&(i.isContentEditable||["INPUT","TEXTAREA","SELECT"].includes(i.tagName)&&i.type!=="range"))||(t.preventDefault(),this.toggleFullscreen())};handleSeekKey=t=>{if(t.altKey||t.ctrlKey||t.metaKey)return;const e=t.key==="ArrowLeft"?-1:t.key==="ArrowRight"?1:0;if(e){t.preventDefault();const i=this.player.seekableDuration;this.player.seek(Math.min(i,Math.max(0,this.player.time+e*fe.SEEK_KEY_STEP_MS)))}else t.key===" "&&(t.preventDefault(),this.togglePlayPause())};togglePlayPause(){this.player.seekableDuration<=0||(this.player.playbackState==="playing"?(this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh()):(this.sightingAudio.resume(),this.player.play()),this.updatePlayPauseButton(),this.flashPlayback())}flashPlayback(){const t=this.playbackFlash;t.innerHTML=this.player.playbackState==="playing"?Zt.PLAY:Zt.PAUSE,t.classList.remove("flashing"),t.offsetWidth,t.classList.add("flashing")}static icons=new WeakMap;static setIcon(t,e){fe.icons.get(t)!==e&&(fe.icons.set(t,e),t.innerHTML=e)}set captionHeld(t){this.stageElement.classList.toggle("caption-held",t)}static CONTROLS_IDLE_MS=3e3;controlsIdleTimer;wasPlaying=!1;tapRevealedOnly=!1;get hoverless(){return typeof matchMedia=="function"&&matchMedia("(hover: none)").matches}touchedStage(){if(!this.hoverless)return;this.player.playbackState==="playing"&&!this.stageElement.classList.contains("touched")&&(this.tapRevealedOnly=!0),this.revealControls()}pointerHeld=!1;handlePointerDown=()=>{this.pointerHeld=!0};resumeAfterScrub=!1;suspendForScrub(){this.player.playbackState==="playing"&&(this.resumeAfterScrub=!0,this.stopPlaying())}stopPlaying(){this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh(),this.updatePlayPauseButton()}resumeFromScrub(){this.resumeAfterScrub&&(this.resumeAfterScrub=!1,this.sightingAudio.resume(),this.player.play(),this.updatePlayPauseButton())}handleHidden=()=>{this.player.playbackState==="playing"&&this.stopPlaying(),this.resumeAfterScrub=!1};handleVisibility=()=>{document.visibilityState==="hidden"&&this.handleHidden()};handlePointerRelease=()=>{this.resumeAfterScrub&&window.setTimeout(()=>this.resumeFromScrub(),0),this.pointerHeld&&(this.pointerHeld=!1,this.hoverless&&this.stageElement.classList.contains("touched")&&this.revealControls())};revealControls(){this.stageElement.classList.add("touched"),window.clearTimeout(this.controlsIdleTimer),this.player.playbackState==="playing"&&(this.pointerHeld||!this.momentsMenu.hidden||(this.controlsIdleTimer=window.setTimeout(()=>{this.stageElement.classList.remove("touched"),this.tapRevealedOnly=!1},fe.CONTROLS_IDLE_MS)))}updatePlayPauseButton(){const t=this.player.playbackState==="playing";this.stageElement.classList.toggle("paused",!t),t!==this.wasPlaying&&t&&this.hoverless&&this.revealControls(),this.wasPlaying=t,fe.setIcon(this.playPauseButton,t?Zt.PAUSE:Zt.PLAY);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(),this.updateMuteButton()}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(),this.updateMuteButton()}toggleObserverMap(){const t=this.observerMapPanel.hidden;this.observerMapAsked=t,this.setObserverMapOpen(t),this.keepObserverMapClear()}observerMapAsked=!1;applyObserverMapDefault(){const t=this.getAttribute(_r),e=t===null?this.observerPath?.travels===!0:t!=="false";this.setObserverMapOpen(e&&this.observerPath!==void 0)}setObserverMapOpen(t){this.observerMapPanel.hidden=!t,this.observerMapPanel.removeAttribute("title"),this.observerMapButton.setAttribute("aria-pressed",String(t)),this.updateObserverMapButton(),t&&(this.sizeObserverMapCanvas(),this.loadObserverMapImagery(),this.paintObserverMap(this.currentTime))}updateObserverMapButton(){const t=!this.observerMapPanel.hidden;fe.setIcon(this.observerMapButton,t?Zt.MAP_ON:Zt.MAP_OFF);const e=t?this.messages.hideObserverMap:this.messages.showObserverMap;this.observerMapButton.title=e,this.observerMapButton.setAttribute("aria-label",e);const i=[[this.mapZoomInButton,this.messages.zoomMapIn],[this.mapZoomOutButton,this.messages.zoomMapOut],[this.mapFitButton,this.messages.fitMap]];for(const[n,s]of i)n.title=s,n.setAttribute("aria-label",s)}updateObserverMap(){const t=this.observerPath!==void 0;if(this.observerPath=yr.of(this.currentSighting),this.observerMapButton.hidden=this.observerPath===void 0,!t&&this.observerPath&&this.applyObserverMapDefault(),!this.observerPath){this.setObserverMapOpen(!1),this.observerMapBounds=void 0;return}const e=this.observerPath.boundsAround(fe.OBSERVER_MAP_MIN_SPAN_M,fe.OBSERVER_MAP_MARGIN);(!this.observerMapBounds||!this.sameGround(this.observerMapBounds,e))&&(this.observerMapBounds&&this.observerMapView.refit(this.observerMapBounds,e),this.observerMapBounds=e,this.observerMapImagery=void 0,this.observerMapImageryCredit=void 0,this.observerMapImageryFailed=!1,this.observerMapImageryBounds=void 0,this.observerMapImageryLoading=!1,this.observerMapPanel.hidden||this.loadObserverMapImagery())}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 loadObserverMapImagery(){const t=this.observerMapViewBounds;if(!t||this.observerMapPanel.hidden||this.observerMapImageryLoading||!this.observerMapImageryNeededFor(t))return;const e=this.observerMapView.changed,i=e?Ye.expand(t,fe.OBSERVER_MAP_IMAGERY_AHEAD):t,n=fe.OBSERVER_MAP_IMAGERY_PX*(e?1+2*fe.OBSERVER_MAP_IMAGERY_AHEAD:1);this.observerMapImageryBounds=i,this.observerMapImageryViewWidth=t.east-t.west,this.observerMapImageryLoading=!0;const s=xg();try{const a=await s.getImageryTexture(i,{width:n,height:n});if(this.observerMapImageryBounds!==i)return;this.observerMapImagery=a,this.observerMapImageryCredit=s.attribution,this.observerMapImageryFailed=!1}catch{if(this.observerMapImageryBounds!==i)return;this.observerMapImageryFailed=this.observerMapImagery===void 0}finally{this.observerMapImageryBounds===i&&(this.observerMapImageryLoading=!1)}this.paintObserverMap(this.currentTime),this.scheduleObserverMapImagery()}static OBSERVER_MAP_IMAGERY_AHEAD=.5;static OBSERVER_MAP_IMAGERY_LOOKAHEAD=.25;observerMapImageryNeededFor(t){const e=this.observerMapImageryBounds;if(!e)return!0;const i=this.observerMapImagery?.bounds??e,n=this.observerMapView.changed?Ye.expand(t,fe.OBSERVER_MAP_IMAGERY_LOOKAHEAD):t,s=n.west>=i.west&&n.east<=i.east&&n.south>=i.south&&n.north<=i.north,a=t.east-t.west>this.observerMapImageryViewWidth/2;return!s||!a}get observerMapCredit(){return this.observerMapImageryCredit}get observerMapFooterLine(){return this.observerMapImageryFailed?this.messages.mapImageryUnavailable:this.creditShownExternally?void 0:this.observerMapImageryCredit}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.keepObserverMapClear()}keepObserverMapClear(){if(this.observerMapPanel.hidden)return;const t=this.observerMapBoxPx;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],a=fe.OBSERVER_MAP_CLEARANCE_PX,o=i(...n,0),c=i(...s,0);if(this.observerMapPanel.classList.toggle("subject-overlap",o&&c&&!this.observerMapAsked),this.observerMapPanel.classList.contains("on-the-left")){!o&&(c||!i(n[0],n[1],a))&&this.observerMapPanel.classList.remove("on-the-left");return}i(n[0],n[1],0)&&!i(s[0],s[1],0)&&this.observerMapPanel.classList.add("on-the-left")}observerMapBoxPx;static OBSERVER_MAP_CLEARANCE_PX=24;sizeObserverMapCanvas(){const t=this.observerMapPanel.clientWidth;if(t===0)return;const e=Math.round(t*(globalThis.devicePixelRatio??1));this.measureObserverMapBox(),this.observerMapCanvas.width!==e&&(this.observerMapCanvas.width=e,this.observerMapCanvas.height=e)}measureObserverMapBox(){const t=this.observerMapPanel.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.observerMapBoxPx={width:t.width*i,top:(t.top-e.top)*n,bottom:(t.bottom-e.top)*n}}paintObserverMap(t){if(this.observerMapPanel.hidden||!this.observerPath||!this.observerMapBounds)return;const e=di(this.currentSighting,t);e?.lat!==void 0&&e.lng!==void 0&&!this.observerMapDrag?.moved&&this.observerMapView.keepInView(this.observerMapBounds,{lat:e.lat,lng:e.lng},fe.OBSERVER_MAP_FOLLOW_MARGIN)&&this.scheduleObserverMapImagery();const i=this.currentSighting.instrument,n=[],s=this.currentSighting.milestones.length>0?ih(this.currentSighting.milestones,t):void 0;for(const a of this.milestonesShown?So(this.currentSighting.milestones):[]){const o=di(this.currentSighting,a.t);o?.lat===void 0||o.lng===void 0||n.push({label:this.said.read(a.label)??"",note:this.said.read(a.note),t:a.t,lat:o.lat,lng:o.lng,current:a===s})}this.observerMapRenderer.paint({bounds:this.observerMapViewBounds,imagery:this.observerMapImagery,path:this.observerPath,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?Ss.of(i,this.canvas.height,e.fovDeg).halfWidthAngleDeg(fi.aspectOf(i)):void 0,markers:n,decor:this.observerMapDecorAt(t),observerLabel:this.said.read(this.currentSighting.observer?.title)??this.messages.observerHere,nightFraction:this.observerMapNightFraction,attribution:this.observerMapFooterLine})}toggleMilestones(){this.setMilestonesShown(!this.milestonesShown)}setMilestonesShown(t){this.milestonesShown=t,this.milestoneMarks.hidden=!t,this.momentsBox.hidden=!t||this.sighting.milestones.length===0,this.refreshSeekSegments(this.player.seekableDuration,So(this.sighting.milestones).map(e=>e.t)),this.milestonesButton.setAttribute("aria-pressed",String(t)),this.updateMilestonesButton(),this.showMilestoneAt(this.currentTime),this.paintObserverMap(this.currentTime)}updateMilestonesButton(){this.milestonesButton.hidden=this.currentSighting.milestones.length===0,this.momentsButton.title=this.messages.moments,fe.setIcon(this.milestonesButton,this.milestonesShown?Zt.MILESTONES_ON:Zt.MILESTONES_OFF);const t=this.milestonesShown?this.messages.hideMilestones:this.messages.showMilestones;this.milestonesButton.title=t,this.milestonesButton.setAttribute("aria-label",t)}observerMapDecorAt(t){const e=di(this.currentSighting,0);return e?.lat===void 0||e.lng===void 0?[]:this.currentSighting.decor.filter(i=>i.kind!=="crop").map(i=>{const n=Co(i,t),{lat:s,lng:a}=_s(n.eastM,-n.northM,e.lat,e.lng);return{lat:s,lng:a,headingDeg:n.headingDeg,label:this.said.read(i.title)??this.messages.decorHere}})}observerMapNightFraction;setSunAltitude(t){const e=t===void 0?void 0:Math.max(0,Math.min(1,-t/12));e!==this.observerMapNightFraction&&(this.observerMapNightFraction=e,this.paintObserverMap(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=di(this.currentSighting,this.currentTime),s=Ss.of(this.currentSighting.instrument,this.canvas.height,n?.fovDeg??60);return{x:-s.angleDegToRadiusPx(e),y:s.angleDegToRadiusPx(i)}}gaitAt(t){return _e.bodyAt(this.currentSighting,t,this.steadyObserver)}mutedState=!1;get muted(){return this.mutedState}set muted(t){t!==this.mutedState&&(this.mutedState=t,!t&&this.volumeState===0&&(this.volumeState=fe.RESTORED_VOLUME),this.applyLevel())}volumeState=1;static RESTORED_VOLUME=.5;get volume(){return this.volumeState}set volume(t){this.setVolume(t)}setVolume(t){this.volumeState=Math.min(Math.max(t,0),1),this.mutedState=this.volumeState===0,this.applyLevel()}get level(){return this.mutedState?0:this.volumeState}applyLevel(){this.sightingAudio.setLevel(this.level),this.updateMuteButton(),this.dispatchEvent(new CustomEvent("mutedchange",{bubbles:!0,composed:!0,detail:{muted:this.mutedState,volume:this.volumeState}}))}toggleMuted(){this.muted=!this.mutedState}updateMuteButton(){fe.setIcon(this.muteButton,this.mutedState?Zt.MUTED:Zt.VOLUME);const t=this.mutedState?this.messages.unmute:this.messages.mute;this.muteButton.title=t,this.muteButton.setAttribute("aria-label",t),this.muteButton.setAttribute("aria-pressed",String(this.mutedState)),this.volumeInput.value=String(this.level)}updateFullscreenButton(){const t=this.simulatedFullscreen||document.fullscreenElement===this.fullscreenTarget;fe.setIcon(this.fullscreenButton,t?Zt.EXIT_FULLSCREEN:Zt.ENTER_FULLSCREEN),this.fullscreenButton.title=t?this.messages.exitFullscreen:this.messages.fullscreen,this.fullscreenButton.setAttribute("aria-label",this.fullscreenButton.title)}get said(){return this.saidTexts??=new Ks(pl.preferencesFor(this))}saidTexts;async loadLocaleMessages(){const t=cg(pl.preferencesFor(this),lg);if(t===this.messagesLanguage||t==="en"&&this.messagesLanguage===void 0)return;this.messagesLanguage=t;const e=await Wv(t);this.messagesLanguage===t&&this.applyMessages(e)}messagesLanguage;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,this.timePill.classList.toggle("switchable",this.canSwitchTimeDisplay),this.canSwitchTimeDisplay?(this.timePill.setAttribute("role","button"),this.timePill.setAttribute("tabindex","0")):(this.timePill.removeAttribute("role"),this.timePill.removeAttribute("tabindex"))}applyMessages(t){this.messages=t,this.updateTimeLabelTitles(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateMuteButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateMilestonesButton(),this.renderIssues()}updateTimeLabels(){const t=this.currentSighting.event,e=Tv(t);this.realDurationMs=e!==void 0&&e>0?e:void 0,this.realStartMs=t.time?wu(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 sc(t);const e=this.currentSighting.timeline.duration,i=e>0&&t<=e?t/e*this.realDurationMs:t;return this.canShowClockTime?Sf(_f(this.realStartMs+i)):sc(i)}formatEndOfTimeline(){return this.realDurationMs===void 0?sc(this.currentSighting.timeline.duration):this.canShowClockTime?Sf(_f(this.realStartMs+this.realDurationMs)):sc(this.realDurationMs)}}function _f(r){const t=new Date(r);return{hour:t.getUTCHours(),minute:t.getUTCMinutes(),second:t.getUTCSeconds()}}function Sf(r){if(r.hour===void 0)return"0:00";const t=e=>String(e).padStart(2,"0");return r.second?`${t(r.hour)}:${t(r.minute??0)}:${t(r.second)}`:`${t(r.hour)}:${t(r.minute??0)}`}function sc(r){const t=Math.round(r/1e3),e=Math.floor(t/60),i=t%60;return`${e}:${String(i).padStart(2,"0")}`}const Au="rr0-ufo";function yg(){customElements.get(Au)||customElements.define(Au,fe)}const l2="recordingissues";/**
|
|
1343
|
+
`)}`)}}class An{constructor(t){this.format=t}issues(t){const e=[];return this.object(t,this.format,"",e),e}object(t,e,i,n){if(!An.isObject(t)){n.push({kind:"wrong-type",path:i||"(the file)",expected:"object",found:An.typeOf(t)});return}for(const[s,a]of Object.entries(t)){const o=i?`${i}.${s}`:s,c=e[s];c?this.field(a,c,o,n):n.push({kind:"unknown-key",path:o})}}field(t,e,i,n){if(An.isStated(t)){this.field(t.value,e,i,n);return}if(!(e.loose||t===void 0||t===null))switch(e.type){case"enum":(typeof t!="string"||!e.values?.includes(t))&&n.push({kind:"not-in-list",path:i,expected:(e.values??[]).map(s=>`"${s}"`).join(", "),found:JSON.stringify(t)});return;case"object":e.fields?this.object(t,e.fields,i,n):An.isObject(t)||n.push({kind:"wrong-type",path:i,expected:"object",found:An.typeOf(t)});return;case"array":Array.isArray(t)?e.fields&&t.forEach((s,a)=>{const o=An.isStated(s)?s.value:s;this.object(o,e.fields,`${i}.${a}`,n)}):n.push({kind:"wrong-type",path:i,expected:"array",found:An.typeOf(t)});return;default:typeof t!==e.type&&n.push({kind:"wrong-type",path:i,expected:e.type,found:An.typeOf(t)})}}static isObject(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}static isStated(t){return An.isObject(t)&&"value"in t&&Object.keys(t).every(e=>e==="value"||e==="basis"||e==="rationale")}static typeOf(t){return Array.isArray(t)?"array":t===null?"null":typeof t}}class Cn{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 a=s>0?Cn.travelDegOver(t,e,i,i+n*1e3)/s/Cn.PIXELS_PER_INSTANT:0,o=Cn.flashesOver(t,n)*Cn.INSTANTS_PER_FLASH,c=Math.ceil(Math.max(a,o));return c<2?1:Math.min(Cn.MAX_INSTANTS,c)}static travelDegOver(t,e,i,n){let s=0;for(const a of t){if(!a.track||a.track.length<2)continue;const o=Cn.directionAt(a,e,i),c=Cn.directionAt(a,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=Co(t,i),s=n.eastM,a=n.altitudeM-e,o=n.northM,c=Math.hypot(s,a,o);return c===0?{x:0,y:1,z:0}:{x:s/c,y:a/c,z:o/c}}}function cg(r,t){for(const e of r){const i=e.toLowerCase().split("-")[0];if(t.includes(i))return i}return"en"}class pl{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 Ks{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[Ks.base(i)];if(n)return n}const e=new Set(this.preferences.map(i=>Ks.base(i)));for(const[i,n]of Object.entries(t))if(n&&e.has(Ks.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},a=Object.keys(s).find(o=>o===i)??Object.keys(s).find(o=>Ks.base(o)===Ks.base(i))??i;return n===void 0?delete s[a]:s[a]=n,Object.keys(s).length===0?void 0:s}static base(t){return t.toLowerCase().split("-")[0]}}const lg=["en","fr","es","it"],Vv={en:()=>is(()=>Promise.resolve().then(()=>Yv),void 0,import.meta.url).then(r=>r.ufoMessages_en),fr:()=>is(()=>import("./UfoMessages_fr-BnjRvJ7U.js"),[],import.meta.url).then(r=>r.ufoMessages_fr),es:()=>is(()=>import("./UfoMessages_es-Cm0EH1RY.js"),[],import.meta.url).then(r=>r.ufoMessages_es),it:()=>is(()=>import("./UfoMessages_it-BsE5MTYw.js"),[],import.meta.url).then(r=>r.ufoMessages_it)};function Wv(r){return Vv[r]()}function Xv(r){switch(r){case"fr":return is(()=>import("./SceneNames_fr-BbDQV822.js"),[],import.meta.url).then(t=>t.sceneNames_fr);case"es":return is(()=>import("./SceneNames_es-D17SooUd.js"),[],import.meta.url).then(t=>t.sceneNames_es);case"it":return is(()=>import("./SceneNames_it-DLcaIKpK.js"),[],import.meta.url).then(t=>t.sceneNames_it);default:return Promise.resolve(void 0)}}const hg={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",mute:"Mute",unmute:"Unmute",moments:"Moments",moreControls:"More controls",fewerControls:"Fewer controls",showObserverMap:"Show where the observer was",hideObserverMap:"Hide where the observer was",mapImageryUnavailable:"Aerial imagery unavailable",zoomMapIn:"Zoom in",zoomMapOut:"Zoom out",fitMap:"Back to the whole path",placeObserverHere:"Put the observer here",showReferences:"Show the pictures of the place",hideReferences:"Hide the pictures of the place",referenceOpacity:"Picture opacity",showMilestones:"Show the account's moments",hideMilestones:"Hide the account's moments",observerHere:"The observer, here",decorHere:"Scenery",recordingIssues:"{count} problem(s) in this recording: it may not play as its author meant",issueTemplates:Pr.EN},Yv=Object.freeze(Object.defineProperty({__proto__:null,ufoMessages_en:hg},Symbol.toStringTag,{value:"Module"})),ug=Math.PI/180,qv=180/Math.PI,$v=256,dg=19,Kv=1.25;function fg(r,t){return 156543.03392*Math.cos(r*ug)/2**t}function pg(r,t){return fg(r,t)*$v}function Zv(r,t){let e=0;for(;e<dg&&pg(r,e+1)>=t;)e++;return e}function mg(r,t){return pg(r,t)}function Jv(r,t){const e=t*Kv;let i=0;for(;i<dg&&fg(r,i)>e;)i++;return i}function el(r){const t=r*ug;return(1-Math.log(Math.tan(t)+1/Math.cos(t))/Math.PI)/2}function gg(r,t,e){const i=2**e;return{x:(r+180)/360*i,y:el(t)*i}}function vg(r,t,e){const i=el(r.north),n=el(r.south);return{x:(t-r.west)/(r.east-r.west),y:(el(e)-i)/(n-i)}}function jv(r,t,e){const{x:i,y:n}=gg(r,t,e);return{x:Math.floor(i),y:Math.floor(n),z:e}}function Qv(r){const t=2**r.z,e=r.x/t*360-180,i=(r.x+1)/t*360-180,n=Mf(r.y,t);return{south:Mf(r.y+1,t),north:n,west:e,east:i}}function Mf(r,t){const e=r/t;return Math.atan(Math.sinh(Math.PI*(1-2*e)))*qv}function Mg(r,t,e,i){const n=jv(r,t,e),s=Math.floor(i/2),a=[];for(let l=-s;l<=s;l++)for(let h=-s;h<=s;h++)a.push({x:n.x+h,y:n.y+l,z:e});const o=a.map(Qv),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:a,bounds:c}}class Ma{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 a=Math.hypot(s.x-t,s.y-e);a>s.radius||a>n||(i=s,n=a)}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.paintObserver(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=vg(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,a=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(a.x,a.y),s.arc(a.x,a.y,o,c-l,c+l),s.closePath();const h=s.createRadialGradient(a.x,a.y,0,a.x,a.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:Ma.MARKER_RADIUS_PX}),e.beginPath(),e.arc(n.x,n.y,Ma.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)}}paintObserver(t,e){const{ctx:i}=this,n=this.toCanvas(t.bounds,e.lat,e.lng);t.observerLabel&&this.targets.push({kind:"observer",label:t.observerLabel,lat:e.lat,lng:e.lng,x:n.x,y:n.y,radius:8});const s=t.markers.some(a=>{if(!a.current)return!1;const o=ai(a.lat,a.lng,e.lat,e.lng);return Math.hypot(o.x,o.z)<=Ma.ON_MARKER_M});i.beginPath(),i.arc(n.x,n.y,s?Ma.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 a=(t.south+t.north)/2,c=Math.abs(ai(a,t.east,a,t.west).x)/this.width,l=Ma.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 a=n?`${n} ${s}`:s;n&&this.ctx.measureText(a).width>e?(i.push(n),n=s):n=a}return n&&i.push(n),i}}class Ye{static MIN_ZOOM=.25;static MAX_ZOOM=64;zoom=1;centerX=.5;centerY=.5;get changed(){return this.zoom!==1||this.centerX!==.5||this.centerY!==.5}get zoomFactor(){return this.zoom}reset(){this.zoom=1,this.centerX=.5,this.centerY=.5}zoomAt(t,e,i){const n=Math.min(Ye.MAX_ZOOM,Math.max(Ye.MIN_ZOOM,this.zoom*i)),s=this.centerX+(t-.5)/this.zoom,a=this.centerY+(e-.5)/this.zoom;this.centerX=s-(t-.5)/n,this.centerY=a-(e-.5)/n,this.zoom=n}panBy(t,e){this.centerX-=t/this.zoom,this.centerY-=e/this.zoom}refit(t,e){if(!this.changed)return;const i=this.boundsWithin(t),n=Ye.mercatorY01(e.north),s=Ye.mercatorY01(e.south),a=Ye.mercatorY01(i.north),o=Ye.mercatorY01(i.south);this.zoom=(e.east-e.west)/(i.east-i.west),this.centerX=((i.west+i.east)/2-e.west)/(e.east-e.west),this.centerY=((a+o)/2-n)/(s-n)}keepInView(t,e,i){if(!this.changed)return!1;const n=this.boundsWithin(t),s=Ye.mercatorY01(n.north),a=Ye.mercatorY01(n.south),o=(e.lng-n.west)/(n.east-n.west),c=(Ye.mercatorY01(e.lat)-s)/(a-s);return o>=i&&o<=1-i&&c>=i&&c<=1-i?!1:(this.panBy(.5-o,.5-c),!0)}boundsWithin(t){if(!this.changed)return t;const e=.5/this.zoom,i=Ye.mercatorY01(t.north),n=Ye.mercatorY01(t.south),s=t.east-t.west;return{west:t.west+(this.centerX-e)*s,east:t.west+(this.centerX+e)*s,north:Ye.latitudeAt(i+(this.centerY-e)*(n-i)),south:Ye.latitudeAt(i+(this.centerY+e)*(n-i))}}static expand(t,e){const i=t.east-t.west,n=t.north-t.south;return{west:t.west-i*e,east:t.east+i*e,south:t.south-n*e,north:t.north+n*e}}static pointAt(t,e,i){const n=Ye.mercatorY01(t.north),s=Ye.mercatorY01(t.south);return{lat:Ye.latitudeAt(n+i*(s-n)),lng:t.west+e*(t.east-t.west)}}static mercatorY01(t){const e=t*Math.PI/180;return(1-Math.log(Math.tan(e)+1/Math.cos(e))/Math.PI)/2}static latitudeAt(t){return Math.atan(Math.sinh(Math.PI*(1-2*t)))*180/Math.PI}}const fn=256,xf=3,t2=32768;class e2{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(ai(i,t.east,i,t.west).x),a=Math.abs(ai(t.north,n,t.south,n).z),o=Zv(i,Math.max(s,a)),{tiles:c}=Mg(n,i,o,xf),l=xf*fn,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)),a=await this.fetchImpl(s);if(!a.ok)throw new Error(`Elevation tile fetch failed (${a.status}): ${s}`);const o=await createImageBitmap(await a.blob()),c=document.createElement("canvas");c.width=fn,c.height=fn;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,fn,fn),u=(t.x-e.x)*fn,d=(t.y-e.y)*fn;for(let f=0;f<fn;f++)for(let p=0;p<fn;p++){const v=(f*fn+p)*4,m=h[v]*256+h[v+1]+h[v+2]/256-t2,g=u+p,S=d+f;i[S*n+g]=m}}sampleAt(t,e,i,n,s,a){const{x:o,y:c}=gg(e,t,i),l=(o-n.x)*fn,h=(c-n.y)*fn,u=Math.max(0,Math.min(a-1,Math.floor(l))),d=Math.max(0,Math.min(a-1,Math.floor(h))),f=Math.min(a-1,u+1),p=Math.min(a-1,d+1),v=l-u,m=h-d,g=s[d*a+u],S=s[d*a+f],y=s[p*a+u],M=s[p*a+f],b=g+(S-g)*v,w=y+(M-y)*v;return b+(w-b)*m}}const il=256,i2=5;async function n2(r,t,e,i){const n=(r.south+r.north)/2,s=(r.west+r.east)/2,a=Math.abs(ai(n,r.east,n,r.west).x),o=Math.abs(ai(r.north,s,r.south,s).z),c=Math.max(a,o),{zoom:l,gridSize:h}=s2(n,c,Math.max(t.width,t.height)),{tiles:u,bounds:d}=Mg(s,n,l,h),f=h*il,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 b=e(M),w=await i(b);if(!w.ok)throw new Error(`Imagery tile fetch failed (${w.status}): ${b}`);const T=await createImageBitmap(await w.blob());v.drawImage(T,(M.x-m.x)*il,(M.y-m.y)*il)}));const g=Math.min(Math.max(t.width,t.height),f);if(g===f)return{source:p,width:f,height:f,bounds:d};const S=document.createElement("canvas");S.width=g,S.height=g;const y=S.getContext("2d");if(!y)throw new Error("2D canvas context unavailable");return y.drawImage(p,0,0,f,f,0,0,g,g),{source:S,width:g,height:g,bounds:d}}function s2(r,t,e){let i=Jv(r,t/Math.max(1,e)),n=yf(r,i,t);for(;n>i2&&i>0;)i--,n=yf(r,i,t);return{zoom:i,gridSize:n,mPerPixel:mg(r,i)/il}}function yf(r,t,e){const i=Math.ceil(e/2/mg(r,t));return Math.max(3,2*i+1)}class a2{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 n2(t,e,i=>this.tileUrlTemplate.replace("{z}",String(i.z)).replace("{y}",String(i.y)).replace("{x}",String(i.x)),this.fetchImpl)}}class Tn{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??Tn.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"~"^(${Tn.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:Tn.surfaceOf(s),widthM:Tn.widthOf(s),points:n.map(a=>({lat:a.lat,lng:a.lon}))})}return e}queued(t){const e=Tn.queue.then(t,t);return Tn.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,Tn.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:Tn.WIDTH_M[t.highway]??Tn.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 sh="https://ufoathome.org/roads/index.json";class t0{attributionRead;contemporaryRead;fetchImpl;indexUrls;fallback;index;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??t0.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.81.5")}`,e=typeof location>"u"?void 0:new URL("/roads/index.json",location.href).href;return(e&&e!==sh?[e,sh]:[sh]).map(i=>i+t)}}function r2(){return{elevation:new e2,imagery:xg(),roads:o2()}}function xg(){return new a2}function o2(){return new t0({fallback:new Tn})}const c2=new Set,_r="show-observer-map",Sr="hide-milestones";class fe extends HTMLElement{static get observedAttributes(){return["src",_r,Sr]}shadow;stageElement;canvas;canvasRenderer;tooltip;toolbar;issuesBox;issuesButton;issuesPanel;playPauseButton;static OBSERVER_MAP_MIN_SPAN_M=400;static OBSERVER_MAP_MARGIN=.6;static OBSERVER_MAP_IMAGERY_PX=768;fullscreenButton;cornerButtons;observerMapButton;referencesButton;referenceOpacityInput;referencesShownState=!0;referenceOpacityTouched=!1;milestonesButton;observerMapPanel;observerMapCanvas;observerMapRenderer;mapZoomInButton;mapZoomOutButton;mapFitButton;observerMapView=new Ye;observerMapDrag;suppressObserverMapClick=!1;observerMapImageryTimer;observerPlacing=!1;seekInput;playbackFlash;milestoneMarks;milestoneCaption;timeStartLabel;timeEndLabel;timePill;muteButton;volumeInput;controlsRow;momentsBox;momentsButton;momentsCurrent;momentsMenu;moreButton;controlsRight;seekSegments;seekDot;seekPreview;seekPreviewCanvas;seekPreviewTitle;seekPreviewTime;observerPath;observerMapBounds;observerMapImagery;observerMapImageryBounds;observerMapImageryViewWidth=0;observerMapImageryLoading=!1;observerMapImageryCredit;observerMapImageryFailed=!1;creditShownExternally=!1;lookYawDeg=0;lookPitchDeg=0;milestonesShown=!0;currentSighting=zl.create();issues=[];issueCheck=0;sightingAudio=new kv;soundPreview;player;loopEnabled=!1;playbackBeforeClick;highlightedSourceIds=new Set;paintsShapes=!0;steadyObserver=!1;selectionShown=!0;overlayPainter;enableClickToPlay=!0;fullscreenTarget;messages=hg;realDurationMs;realStartMs;showClockTime=!0;handleFullscreenChange=()=>{this.updateFullscreenButton(),this.updateMuteButton(),this.resizeObserverMap()};controlsFitObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>this.fitControls());controlsMutations;fitControls(){const t=this.controlsRow,e=t.classList.contains("more-open"),i=()=>t.scrollWidth>t.clientWidth+1,n=!this.momentsMenu.hidden;if(this.momentsMenu.hidden=!0,t.classList.remove("narrow","more-open","nomoments","compact","tiny"),t.clientWidth>0&&i()){t.classList.add("narrow");for(const s of["nomoments","compact","tiny"]){if(!i())break;t.classList.add(s)}e&&t.classList.add("more-open")}this.momentsMenu.hidden=!n,this.updateMoreButton()}setControlsFolded(t){this.controlsRow.classList.toggle("more-open",!t),this.updateMoreButton()}updateMoreButton(){const t=this.controlsRow.classList.contains("more-open");fe.setIcon(this.moreButton,t?Zt.UNFOLDED:Zt.FOLDED);const e=t?this.messages.fewerControls:this.messages.moreControls;this.moreButton.title=e,this.moreButton.setAttribute("aria-label",e),this.moreButton.setAttribute("aria-expanded",String(t))}addControl(t){this.controlsRight.insertBefore(t,this.fullscreenButton.parentElement===this.controlsRight?this.fullscreenButton:null),this.fitControls()}observerMapResizeObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>this.resizeObserverMap());resizeObserverMap(){this.observerMapPanel.hidden||(this.sizeObserverMapCanvas(),this.paintObserverMap(this.currentTime))}simulatedFullscreen=!1;styleBeforeSimulatedFullscreen;bodyOverflowBeforeSimulatedFullscreen;handleSimulatedFullscreenKey=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`};handleObserverMapPointerMove=t=>{if(this.dragObserverMap(t))return;const e=this.observerMapTargetFrom(t);if(!e){if(!this.observerPlacing){this.tooltip.hidden=!0,this.observerMapCanvas.style.cursor="grab";return}this.observerMapCanvas.style.cursor="crosshair",this.showObserverMapTooltip(t,this.messages.placeObserverHere);return}this.observerMapCanvas.style.cursor="pointer",this.showObserverMapTooltip(t,e.label)};showObserverMapTooltip(t,e){this.tooltip.textContent=e,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`}handleObserverMapClick=t=>{if(this.suppressObserverMapClick){this.suppressObserverMapClick=!1;return}const e=this.observerMapTargetFrom(t);if(!e){this.observerPlacing&&this.placeObserverFrom(t);return}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}))};observerMapTargetFrom(t){const e=this.observerMapCanvas.getBoundingClientRect();if(!(e.width===0||e.height===0))return this.observerMapRenderer.hitTest((t.clientX-e.left)/e.width*this.observerMapCanvas.width,(t.clientY-e.top)/e.height*this.observerMapCanvas.height)}handlePointerLeave=()=>{this.tooltip.hidden=!0};handleObserverMapPointerDown=t=>{t.button===0&&(this.suppressObserverMapClick=!1,this.observerMapDrag={pointerId:t.pointerId,startX:t.clientX,startY:t.clientY,lastX:t.clientX,lastY:t.clientY,moved:!1})};handleObserverMapPointerUp=t=>{const e=this.observerMapDrag;!e||e.pointerId!==t.pointerId||(this.observerMapDrag=void 0,this.observerMapCanvas.classList.remove("dragging"),e.moved&&(this.suppressObserverMapClick=!0,this.paintObserverMap(this.currentTime),this.observerMapCanvas.hasPointerCapture?.(t.pointerId)&&this.observerMapCanvas.releasePointerCapture(t.pointerId)))};dragObserverMap(t){const e=this.observerMapDrag;if(!e||e.pointerId!==t.pointerId)return!1;if(!e.moved){if(Math.hypot(t.clientX-e.startX,t.clientY-e.startY)<fe.OBSERVER_MAP_DRAG_PX)return!1;e.moved=!0,this.tooltip.hidden=!0,this.observerMapCanvas.classList.add("dragging"),this.observerMapCanvas.setPointerCapture?.(t.pointerId)}const i=this.observerMapCanvas.getBoundingClientRect();return i.width>0&&i.height>0&&(this.observerMapView.panBy((t.clientX-e.lastX)/i.width,(t.clientY-e.lastY)/i.height),this.observerMapViewChanged()),e.lastX=t.clientX,e.lastY=t.clientY,!0}static OBSERVER_MAP_DRAG_PX=4;handleObserverMapWheel=t=>{t.preventDefault();const e=this.observerMapCanvas.getBoundingClientRect();if(e.width===0||e.height===0)return;const i=t.deltaMode===0?t.deltaY:t.deltaY*40;this.zoomObserverMap((t.clientX-e.left)/e.width,(t.clientY-e.top)/e.height,Math.exp(-i*.002))};zoomObserverMap(t,e,i){this.observerMapView.zoomAt(t,e,i),this.observerMapViewChanged()}observerMapViewChanged(){this.mapFitButton.hidden=!this.observerMapView.changed,this.mapZoomInButton.disabled=this.observerMapView.zoomFactor>=Ye.MAX_ZOOM,this.mapZoomOutButton.disabled=this.observerMapView.zoomFactor<=Ye.MIN_ZOOM,this.paintObserverMap(this.currentTime),this.scheduleObserverMapImagery()}scheduleObserverMapImagery(){this.observerMapImageryTimer===void 0&&(this.observerMapImageryTimer=setTimeout(()=>{this.observerMapImageryTimer=void 0,this.loadObserverMapImagery()},fe.OBSERVER_MAP_IMAGERY_DELAY_MS))}static OBSERVER_MAP_FOLLOW_MARGIN=.1;static OBSERVER_MAP_IMAGERY_DELAY_MS=300;get observerMapViewBounds(){return this.observerMapBounds&&this.observerMapView.boundsWithin(this.observerMapBounds)}placeObserverFrom(t){const e=this.observerMapViewBounds,i=this.observerMapCanvas.getBoundingClientRect();if(!e||i.width===0||i.height===0)return;const n=Ye.pointAt(e,(t.clientX-i.left)/i.width,(t.clientY-i.top)/i.height);this.dispatchEvent(new CustomEvent("observerplace",{detail:n,bubbles:!0,composed:!0}))}constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const t=document.createElement("template");t.innerHTML=`<style>${hv}</style>${lv}`,this.shadow.appendChild(t.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.canvas=this.shadow.getElementById("canvas"),this.canvasRenderer=new Fo(this.canvas.getContext("2d")),this.tooltip=this.shadow.getElementById("tooltip"),this.toolbar=this.shadow.getElementById("toolbar"),this.issuesBox=this.shadow.getElementById("issues"),this.issuesButton=this.shadow.getElementById("issues-button"),this.issuesPanel=this.shadow.getElementById("issues-panel"),this.issuesButton.addEventListener("click",e=>{e.stopPropagation(),this.issuesPanel.hidden=!this.issuesPanel.hidden,this.issuesButton.setAttribute("aria-expanded",String(!this.issuesPanel.hidden))}),this.playPauseButton=this.shadow.getElementById("play-pause"),this.fullscreenButton=this.shadow.getElementById("fullscreen"),this.cornerButtons=this.shadow.getElementById("corner-buttons"),this.observerMapButton=this.shadow.getElementById("observer-map"),this.referencesButton=this.shadow.getElementById("references"),this.referenceOpacityInput=this.shadow.getElementById("reference-opacity"),this.milestonesButton=this.shadow.getElementById("milestones"),this.observerMapPanel=this.shadow.getElementById("observer-map-panel"),this.observerMapCanvas=this.shadow.getElementById("observer-map-canvas"),this.observerMapRenderer=new Ma(this.observerMapCanvas.getContext("2d")),this.mapZoomInButton=this.shadow.getElementById("map-zoom-in"),this.mapZoomOutButton=this.shadow.getElementById("map-zoom-out"),this.mapFitButton=this.shadow.getElementById("map-fit"),this.seekInput=this.shadow.getElementById("seek"),this.playbackFlash=this.shadow.getElementById("playback-flash"),this.milestoneMarks=this.shadow.getElementById("milestone-marks"),this.milestoneCaption=this.shadow.getElementById("milestone-caption"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end"),this.timePill=this.shadow.getElementById("time"),this.muteButton=this.shadow.getElementById("mute"),this.controlsRight=this.shadow.getElementById("controls-right"),this.seekSegments=this.shadow.getElementById("seek-segments"),this.seekDot=this.shadow.getElementById("seek-dot"),this.seekPreview=this.shadow.getElementById("seek-preview"),this.seekPreviewCanvas=this.shadow.getElementById("seek-preview-canvas"),this.seekPreviewTitle=this.shadow.getElementById("seek-preview-title"),this.seekPreviewTime=this.shadow.getElementById("seek-preview-time"),this.timePill.addEventListener("click",()=>this.toggleTimeDisplay()),this.timePill.addEventListener("keydown",e=>{e.key!=="Enter"&&e.key!==" "||(e.preventDefault(),this.toggleTimeDisplay())}),this.volumeInput=this.shadow.getElementById("volume"),this.controlsRow=this.shadow.querySelector(".controls"),this.momentsBox=this.shadow.getElementById("moments"),this.momentsButton=this.shadow.getElementById("moments-button"),this.momentsCurrent=this.shadow.getElementById("moments-current"),this.momentsMenu=this.shadow.getElementById("moments-menu"),this.momentsButton.addEventListener("click",()=>this.toggleMomentsMenu()),this.moreButton=this.shadow.getElementById("controls-more"),this.moreButton.addEventListener("click",()=>this.setControlsFolded(this.controlsRow.classList.contains("more-open"))),this.muteButton.addEventListener("click",()=>this.toggleMuted()),this.volumeInput.addEventListener("input",()=>{this.setVolume(Number(this.volumeInput.value))}),this.fullscreenTarget=this.stageElement,this.playPauseButton.addEventListener("click",()=>this.togglePlayPause()),this.fullscreenButton.addEventListener("click",()=>this.toggleFullscreen()),this.addEventListener("keydown",this.handleFullscreenKey),this.observerMapButton.addEventListener("click",()=>this.toggleObserverMap()),this.referencesButton.addEventListener("click",()=>this.toggleReferences()),this.referenceOpacityInput.addEventListener("input",()=>{this.referenceOpacityTouched=!0,this.dispatchReferenceView()}),this.milestonesButton.addEventListener("click",()=>this.toggleMilestones()),this.observerMapCanvas.addEventListener("pointermove",this.handleObserverMapPointerMove),this.observerMapCanvas.addEventListener("pointerleave",this.handlePointerLeave),this.observerMapCanvas.addEventListener("click",this.handleObserverMapClick),this.observerMapCanvas.addEventListener("pointerdown",this.handleObserverMapPointerDown),this.observerMapCanvas.addEventListener("pointerup",this.handleObserverMapPointerUp),this.observerMapCanvas.addEventListener("pointercancel",this.handleObserverMapPointerUp),this.observerMapCanvas.addEventListener("wheel",this.handleObserverMapWheel,{passive:!1}),this.mapZoomInButton.addEventListener("click",()=>this.zoomObserverMap(.5,.5,2)),this.mapZoomOutButton.addEventListener("click",()=>this.zoomObserverMap(.5,.5,.5)),this.mapFitButton.addEventListener("click",()=>{this.observerMapView.reset(),this.observerMapViewChanged()}),this.seekInput.addEventListener("input",()=>this.player.seek(this.snapSeekToMark(Number(this.seekInput.value)))),this.seekInput.addEventListener("pointerdown",e=>{this.suspendForScrub(),this.seekSnapArmed=!0,this.nameMarkUnder(e),this.beginTouchScrub(e)}),this.seekInput.addEventListener("pointerup",e=>{this.seekSnapArmed=!1,this.endTouchScrub(e)}),this.seekInput.addEventListener("pointercancel",e=>this.endTouchScrub(e)),this.seekInput.addEventListener("pointermove",e=>{this.nameMarkUnder(e),this.hoverSeek(e),this.touchScrub(e)}),this.seekInput.addEventListener("pointerleave",()=>{this.seekInput.removeAttribute("title"),this.leaveSeek()}),this.seekInput.addEventListener("keydown",this.handleSeekKey),this.stageElement.addEventListener("pointerdown",()=>{this.handlePointerDown(),this.touchedStage()},!0);for(const e of["touchend","click"])this.stageElement.addEventListener(e,()=>this.sightingAudio.resume(),!0);this.stageElement.addEventListener("pointermove",()=>this.touchedStage()),this.canvas.addEventListener("click",e=>{if(this.enableClickToPlay){if(this.tapRevealedOnly){this.tapRevealedOnly=!1;return}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),document.addEventListener("pointerdown",this.handleMomentsDismiss,!0),document.addEventListener("keydown",this.handleMomentsDismiss,!0),document.addEventListener("visibilitychange",this.handleVisibility),window.addEventListener("pagehide",this.handleHidden),document.addEventListener("pointerup",this.handlePointerRelease,!0),document.addEventListener("pointercancel",this.handlePointerRelease,!0),this.observerMapResizeObserver?.observe(this.observerMapPanel),this.controlsFitObserver?.observe(this.controlsRow),this.controlsFitObserver?.observe(this.controlsRow.querySelector(".controls-left")),typeof MutationObserver<"u"&&(this.controlsMutations=new MutationObserver(()=>this.fitControls()),this.controlsMutations.observe(this.controlsRight,{attributes:!0,attributeFilter:["hidden"],childList:!0,subtree:!0})),this.hostControls(void 0),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateMuteButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateMilestonesButton(),this.refresh()}connectedCallback(){this.saidTexts=void 0,this.loadLocaleMessages();const t=this.getAttribute("src");t&&this.loadFromSrc(t)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.handleFullscreenChange),document.removeEventListener("pointerdown",this.handleMomentsDismiss,!0),document.removeEventListener("keydown",this.handleMomentsDismiss,!0),document.removeEventListener("visibilitychange",this.handleVisibility),window.removeEventListener("pagehide",this.handleHidden),document.removeEventListener("pointerup",this.handlePointerRelease,!0),document.removeEventListener("pointercancel",this.handlePointerRelease,!0),window.clearTimeout(this.controlsIdleTimer),this.observerMapResizeObserver?.disconnect(),this.controlsFitObserver?.disconnect(),this.controlsMutations?.disconnect(),this.exitSimulatedFullscreen(),this.sightingAudio.dispose()}attributeChangedCallback(t,e,i){t==="src"&&i&&i!==e&&this.isConnected&&this.loadFromSrc(i),t===_r&&this.applyObserverMapDefault(),t===Sr&&this.setMilestonesShown(!this.hasAttribute(Sr))}async loadFromSrc(t){this.sightingData=await rg.json(t)}get sightingData(){return zv(this.currentSighting)}set sightingData(t){this.player.stop(),this.soundPreview=void 0,this.sightingAudio.silence(),this.currentSighting=Hv(t),this.issuesPanel.hidden=!0,this.issuesButton.setAttribute("aria-expanded","false"),this.reportIssues(t,this.currentSighting),this.observerMapView.reset(),this.mapFitButton.hidden=!0,this.observerMapAsked=!1,this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.refresh(),this.applyObserverMapDefault()}get recordingIssues(){return this.issues}async reportIssues(t,e){const i=++this.issueCheck;let n=[];try{const{default:s}=await is(async()=>{const{default:a}=await import("./sightingSchema-DOOSOVWK.js");return{default:a}},[],import.meta.url);n=new An(s).issues(t)}catch{}i===this.issueCheck&&(this.issues=[...n,...e.loadIssues],Pr.warn(this.issues,e.id),this.renderIssues(),this.dispatchEvent(new CustomEvent(l2,{detail:{issues:this.issues},bubbles:!0,composed:!0})))}renderIssues(){const t=this.issues.length;this.issuesBox.hidden=t===0,this.shadow.getElementById("issues-count").textContent=String(t);const e=this.messages.recordingIssues.replace("{count}",String(t));this.issuesButton.title=e,this.issuesButton.setAttribute("aria-label",e),this.shadow.getElementById("issues-title").textContent=e,this.shadow.getElementById("issues-list").replaceChildren(...this.issues.map(i=>{const n=document.createElement("li");return n.textContent=Pr.text(i,this.messages.issueTemplates),n}))}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),t?this.controlsRight.appendChild(this.fullscreenButton):this.cornerButtons.appendChild(this.fullscreenButton)}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.updateObserverMap(),this.updateReferences(),this.player.seek(this.player.time)}hostControls(t){const e=[this.milestonesButton,this.referencesButton,this.referenceOpacityInput,this.observerMapButton];if(t)for(const i of e)t.appendChild(i);else{const i=this.fullscreenButton.parentElement===this.controlsRight?this.fullscreenButton:null;for(const n of e)this.controlsRight.insertBefore(n,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)),fe.setIcon(this.referencesButton,this.referencesShownState?Zt.PICTURES_ON:Zt.PICTURES_OFF);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?So(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)??"",a=this.said.read(i.note),o=a?`${s} — ${a}`: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})),this.refreshSeekSegments(t,e.map(i=>i.t)),this.refreshMomentsPicker(e)}refreshMomentsPicker(t){const e=this.milestonesShown&&t.length>0;this.momentsBox.hidden=!e,this.closeMomentsMenu(),this.momentsMenu.replaceChildren(...t.map(i=>{const n=document.createElement("li"),s=document.createElement("button");s.type="button",s.dataset.t=String(i.t);const a=this.said.read(i.label)??"",o=this.said.read(i.note);return s.textContent=o?`${a} — ${o}`:a,s.addEventListener("click",()=>{this.player.seek(i.t),this.closeMomentsMenu()}),n.appendChild(s),n})),this.momentsButton.title=this.messages.moments,this.showCurrentMoment(void 0)}showCurrentMoment(t){const i=(t?this.said.read(t.label)??"":"")||this.messages.moments;this.momentsCurrent.textContent!==i&&(this.momentsCurrent.textContent=i);for(const n of this.momentsMenu.querySelectorAll("button")){const s=t!==void 0&&Number(n.dataset.t)===t.t;n.getAttribute("aria-current")==="true"!==s&&n.setAttribute("aria-current",String(s))}}toggleMomentsMenu(){this.momentsMenu.hidden?(this.momentsMenu.hidden=!1,this.momentsButton.setAttribute("aria-expanded","true")):this.closeMomentsMenu()}closeMomentsMenu(){this.momentsMenu.hidden=!0,this.momentsButton.setAttribute("aria-expanded","false")}handleMomentsDismiss=t=>{if(!this.momentsMenu.hidden){if(t instanceof KeyboardEvent){t.key==="Escape"&&this.closeMomentsMenu();return}t.composedPath().some(e=>e===this.momentsMenu||e===this.momentsButton)||this.closeMomentsMenu()}};seekSegmentList=[];refreshSeekSegments(t,e){const n=[0,...this.milestonesShown&&t>0?[...new Set(e.filter(a=>a>0&&a<t))].sort((a,o)=>a-o):[],Math.max(t,0)];this.seekSegmentList=[];const s=[];for(let a=0;a<n.length-1;a++){const o=document.createElement("div");o.className="seek-segment",o.style.flexGrow=String(Math.max(n[a+1]-n[a],1));const c=document.createElement("i");c.className="seek-hover";const l=document.createElement("i");l.className="seek-played",o.append(c,l),s.push(o),this.seekSegmentList.push({start:n[a],end:n[a+1],element:o,played:l,hover:c})}this.seekSegments.replaceChildren(...s),this.paintSeekProgress(this.player.time)}static fillOf(t,e){const i=t.end-t.start,n=i>0?(e-t.start)/i:e>=t.end?1:0;return`${Math.min(Math.max(n,0),1)*100}%`}paintSeekProgress(t){for(const i of this.seekSegmentList)i.played.style.width=fe.fillOf(i,t);const e=this.player.seekableDuration;this.seekDot.style.left=`${e>0?Math.min(Math.max(t/e,0),1)*100:0}%`}hoverSeek(t){const e=this.seekInput.getBoundingClientRect(),i=this.player.seekableDuration;if(e.width<=0||i<=0)return;const n=Math.min(Math.max((t.clientX-e.left)/e.width,0),1),s=n*i,a=this.seekSegmentList.length-1;this.seekSegmentList.forEach((f,p)=>{f.hover.style.width=fe.fillOf(f,s),f.element.classList.toggle("hovered",s>=f.start&&(s<f.end||p===a))});const o=this.milestonesShown?this.sighting.milestones:[],c=o.length>0?ih(o,s):void 0,l=c?this.said.read(c.label)??"":"",h=c?this.said.read(c.note):void 0,u=h?`${l} — ${h}`:l;this.seekPreviewTitle.textContent=u,this.seekPreviewTime.textContent=this.formatPosition(s),this.seekPreview.hidden=!1;const d=this.seekPreview.offsetWidth;this.seekPreview.style.left=`${Math.min(Math.max(n*e.width-d/2,0),Math.max(e.width-d,0))}px`,this.paintSeekPreview(s)}leaveSeek(){for(const t of this.seekSegmentList)t.hover.style.width="0",t.element.classList.remove("hovered");this.seekPreview.hidden=!0}seekPreviewPainter;paintSeekPreview(t){const e=this.seekPreviewPainter;this.seekPreviewCanvas.hidden=e===void 0,e?.(t,this.seekPreviewCanvas)}scrubbingPointer;beginTouchScrub(t){if(t.pointerType!=="mouse"){this.scrubbingPointer=t.pointerId;try{this.seekInput.setPointerCapture(t.pointerId)}catch{}this.seekToPointer(t)}}touchScrub(t){t.pointerId===this.scrubbingPointer&&this.seekToPointer(t)}endTouchScrub(t){t.pointerId===this.scrubbingPointer&&(this.scrubbingPointer=void 0,this.seekToPointer(t))}seekToPointer(t){const e=this.seekInput.getBoundingClientRect(),i=this.player.seekableDuration;if(e.width<=0||i<=0)return;const n=Math.min(Math.max((t.clientX-e.left)/e.width,0),1);this.player.seek(this.snapSeekToMark(n*i))}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=fe.MARK_SNAP_PX/i*e;let s;for(const a of this.milestoneMarks.children){const o=Number(a.dataset.t);Math.abs(o-t)>n||(!s||Math.abs(o-t)<Math.abs(s.t-t))&&(s={t:o,name:a.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?ih(this.sighting.milestones,t):void 0;if(this.milestoneCaption.hidden=e===void 0,this.showCurrentMoment(e),!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=Cn.windowEndingAt(t,this.currentSighting.exposure??0);if(e.ms<fe.SHORTEST_VISIBLE_EXPOSURE_MS)return[t];const i=Math.min(fe.MAX_EXPOSURE_STEPS,Math.max(2,Math.round(e.ms/fe.SHORTEST_VISIBLE_EXPOSURE_MS))),n=Math.ceil(this.travelPxOver(e.fromMs,e.ms)/fe.EXPOSURE_STEP_PX),s=Math.min(fe.MAX_TRAVEL_STEPS,Math.max(i,n)),a=[];for(let o=0;o<s;o++)a.push(e.fromMs+e.ms*o/(s-1));return a}travelPxOver(t,e){const i=this.shapesAt(t),n=this.shapesAt(t+e);let s=0;for(const[a,o]of i){const c=n.get(a);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=fi.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:c2;this.canvasRenderer.setStarPoints(fi.starPointsOf(this.sighting.instrument));const n=(di(this.sighting,t)?.rollDeg??0)+this.gaitAt(t).rollDeg;this.canvasRenderer.setRoll(n*Math.PI/180);const s=this.exposureInstants(t),a=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,a))}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,a)));if(this.selectionShown&&i.size>1){const o=cn.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,a).bounds)),this.keepObserverMapClear(),this.seekInput.value=String(t),this.paintSeekProgress(t),this.timeStartLabel.textContent=this.formatPosition(t),this.showMilestoneAt(t),this.paintObserverMap(t),this.playbackState==="playing"?(this.soundPreview=void 0,this.sightingAudio.setSound(Iv(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 Cv(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}static SEEK_KEY_STEP_MS=5e3;handleFullscreenKey=t=>{t.key.toLowerCase()!=="f"||t.altKey||t.ctrlKey||t.metaKey||!this.enableClickToPlay||t.composedPath().some(i=>i instanceof HTMLElement&&(i.isContentEditable||["INPUT","TEXTAREA","SELECT"].includes(i.tagName)&&i.type!=="range"))||(t.preventDefault(),this.toggleFullscreen())};handleSeekKey=t=>{if(t.altKey||t.ctrlKey||t.metaKey)return;const e=t.key==="ArrowLeft"?-1:t.key==="ArrowRight"?1:0;if(e){t.preventDefault();const i=this.player.seekableDuration;this.player.seek(Math.min(i,Math.max(0,this.player.time+e*fe.SEEK_KEY_STEP_MS)))}else t.key===" "&&(t.preventDefault(),this.togglePlayPause())};togglePlayPause(){this.player.seekableDuration<=0||(this.player.playbackState==="playing"?(this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh()):(this.sightingAudio.resume(),this.player.play()),this.updatePlayPauseButton(),this.flashPlayback())}flashPlayback(){const t=this.playbackFlash;t.innerHTML=this.player.playbackState==="playing"?Zt.PLAY:Zt.PAUSE,t.classList.remove("flashing"),t.offsetWidth,t.classList.add("flashing")}static icons=new WeakMap;static setIcon(t,e){fe.icons.get(t)!==e&&(fe.icons.set(t,e),t.innerHTML=e)}set captionHeld(t){this.stageElement.classList.toggle("caption-held",t)}static CONTROLS_IDLE_MS=3e3;controlsIdleTimer;wasPlaying=!1;tapRevealedOnly=!1;get hoverless(){return typeof matchMedia=="function"&&matchMedia("(hover: none)").matches}touchedStage(){if(!this.hoverless)return;this.player.playbackState==="playing"&&!this.stageElement.classList.contains("touched")&&(this.tapRevealedOnly=!0),this.revealControls()}pointerHeld=!1;handlePointerDown=()=>{this.pointerHeld=!0};resumeAfterScrub=!1;suspendForScrub(){this.player.playbackState==="playing"&&(this.resumeAfterScrub=!0,this.stopPlaying())}stopPlaying(){this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh(),this.updatePlayPauseButton()}resumeFromScrub(){this.resumeAfterScrub&&(this.resumeAfterScrub=!1,this.sightingAudio.resume(),this.player.play(),this.updatePlayPauseButton())}handleHidden=()=>{this.player.playbackState==="playing"&&this.stopPlaying(),this.resumeAfterScrub=!1};handleVisibility=()=>{document.visibilityState==="hidden"&&this.handleHidden()};handlePointerRelease=()=>{this.resumeAfterScrub&&window.setTimeout(()=>this.resumeFromScrub(),0),this.pointerHeld&&(this.pointerHeld=!1,this.hoverless&&this.stageElement.classList.contains("touched")&&this.revealControls())};revealControls(){this.stageElement.classList.add("touched"),window.clearTimeout(this.controlsIdleTimer),this.player.playbackState==="playing"&&(this.pointerHeld||!this.momentsMenu.hidden||(this.controlsIdleTimer=window.setTimeout(()=>{this.stageElement.classList.remove("touched"),this.tapRevealedOnly=!1},fe.CONTROLS_IDLE_MS)))}updatePlayPauseButton(){const t=this.player.playbackState==="playing";this.stageElement.classList.toggle("paused",!t),t!==this.wasPlaying&&t&&this.hoverless&&this.revealControls(),this.wasPlaying=t,fe.setIcon(this.playPauseButton,t?Zt.PAUSE:Zt.PLAY);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(),this.updateMuteButton()}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(),this.updateMuteButton()}toggleObserverMap(){const t=this.observerMapPanel.hidden;this.observerMapAsked=t,this.setObserverMapOpen(t),this.keepObserverMapClear()}observerMapAsked=!1;applyObserverMapDefault(){const t=this.getAttribute(_r),e=t===null?this.observerPath?.travels===!0:t!=="false";this.setObserverMapOpen(e&&this.observerPath!==void 0)}setObserverMapOpen(t){this.observerMapPanel.hidden=!t,this.observerMapPanel.removeAttribute("title"),this.observerMapButton.setAttribute("aria-pressed",String(t)),this.updateObserverMapButton(),t&&(this.sizeObserverMapCanvas(),this.loadObserverMapImagery(),this.paintObserverMap(this.currentTime))}updateObserverMapButton(){const t=!this.observerMapPanel.hidden;fe.setIcon(this.observerMapButton,t?Zt.MAP_ON:Zt.MAP_OFF);const e=t?this.messages.hideObserverMap:this.messages.showObserverMap;this.observerMapButton.title=e,this.observerMapButton.setAttribute("aria-label",e);const i=[[this.mapZoomInButton,this.messages.zoomMapIn],[this.mapZoomOutButton,this.messages.zoomMapOut],[this.mapFitButton,this.messages.fitMap]];for(const[n,s]of i)n.title=s,n.setAttribute("aria-label",s)}updateObserverMap(){const t=this.observerPath!==void 0;if(this.observerPath=yr.of(this.currentSighting),this.observerMapButton.hidden=this.observerPath===void 0,!t&&this.observerPath&&this.applyObserverMapDefault(),!this.observerPath){this.setObserverMapOpen(!1),this.observerMapBounds=void 0;return}const e=this.observerPath.boundsAround(fe.OBSERVER_MAP_MIN_SPAN_M,fe.OBSERVER_MAP_MARGIN);(!this.observerMapBounds||!this.sameGround(this.observerMapBounds,e))&&(this.observerMapBounds&&this.observerMapView.refit(this.observerMapBounds,e),this.observerMapBounds=e,this.observerMapImagery=void 0,this.observerMapImageryCredit=void 0,this.observerMapImageryFailed=!1,this.observerMapImageryBounds=void 0,this.observerMapImageryLoading=!1,this.observerMapPanel.hidden||this.loadObserverMapImagery())}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 loadObserverMapImagery(){const t=this.observerMapViewBounds;if(!t||this.observerMapPanel.hidden||this.observerMapImageryLoading||!this.observerMapImageryNeededFor(t))return;const e=this.observerMapView.changed,i=e?Ye.expand(t,fe.OBSERVER_MAP_IMAGERY_AHEAD):t,n=fe.OBSERVER_MAP_IMAGERY_PX*(e?1+2*fe.OBSERVER_MAP_IMAGERY_AHEAD:1);this.observerMapImageryBounds=i,this.observerMapImageryViewWidth=t.east-t.west,this.observerMapImageryLoading=!0;const s=xg();try{const a=await s.getImageryTexture(i,{width:n,height:n});if(this.observerMapImageryBounds!==i)return;this.observerMapImagery=a,this.observerMapImageryCredit=s.attribution,this.observerMapImageryFailed=!1}catch{if(this.observerMapImageryBounds!==i)return;this.observerMapImageryFailed=this.observerMapImagery===void 0}finally{this.observerMapImageryBounds===i&&(this.observerMapImageryLoading=!1)}this.paintObserverMap(this.currentTime),this.scheduleObserverMapImagery()}static OBSERVER_MAP_IMAGERY_AHEAD=.5;static OBSERVER_MAP_IMAGERY_LOOKAHEAD=.25;observerMapImageryNeededFor(t){const e=this.observerMapImageryBounds;if(!e)return!0;const i=this.observerMapImagery?.bounds??e,n=this.observerMapView.changed?Ye.expand(t,fe.OBSERVER_MAP_IMAGERY_LOOKAHEAD):t,s=n.west>=i.west&&n.east<=i.east&&n.south>=i.south&&n.north<=i.north,a=t.east-t.west>this.observerMapImageryViewWidth/2;return!s||!a}get observerMapCredit(){return this.observerMapImageryCredit}get observerMapFooterLine(){return this.observerMapImageryFailed?this.messages.mapImageryUnavailable:this.creditShownExternally?void 0:this.observerMapImageryCredit}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.keepObserverMapClear()}keepObserverMapClear(){if(this.observerMapPanel.hidden)return;const t=this.observerMapBoxPx;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],a=fe.OBSERVER_MAP_CLEARANCE_PX,o=i(...n,0),c=i(...s,0);if(this.observerMapPanel.classList.toggle("subject-overlap",o&&c&&!this.observerMapAsked),this.observerMapPanel.classList.contains("on-the-left")){!o&&(c||!i(n[0],n[1],a))&&this.observerMapPanel.classList.remove("on-the-left");return}i(n[0],n[1],0)&&!i(s[0],s[1],0)&&this.observerMapPanel.classList.add("on-the-left")}observerMapBoxPx;static OBSERVER_MAP_CLEARANCE_PX=24;sizeObserverMapCanvas(){const t=this.observerMapPanel.clientWidth;if(t===0)return;const e=Math.round(t*(globalThis.devicePixelRatio??1));this.measureObserverMapBox(),this.observerMapCanvas.width!==e&&(this.observerMapCanvas.width=e,this.observerMapCanvas.height=e)}measureObserverMapBox(){const t=this.observerMapPanel.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.observerMapBoxPx={width:t.width*i,top:(t.top-e.top)*n,bottom:(t.bottom-e.top)*n}}paintObserverMap(t){if(this.observerMapPanel.hidden||!this.observerPath||!this.observerMapBounds)return;const e=di(this.currentSighting,t);e?.lat!==void 0&&e.lng!==void 0&&!this.observerMapDrag?.moved&&this.observerMapView.keepInView(this.observerMapBounds,{lat:e.lat,lng:e.lng},fe.OBSERVER_MAP_FOLLOW_MARGIN)&&this.scheduleObserverMapImagery();const i=this.currentSighting.instrument,n=[],s=this.currentSighting.milestones.length>0?ih(this.currentSighting.milestones,t):void 0;for(const a of this.milestonesShown?So(this.currentSighting.milestones):[]){const o=di(this.currentSighting,a.t);o?.lat===void 0||o.lng===void 0||n.push({label:this.said.read(a.label)??"",note:this.said.read(a.note),t:a.t,lat:o.lat,lng:o.lng,current:a===s})}this.observerMapRenderer.paint({bounds:this.observerMapViewBounds,imagery:this.observerMapImagery,path:this.observerPath,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?Ss.of(i,this.canvas.height,e.fovDeg).halfWidthAngleDeg(fi.aspectOf(i)):void 0,markers:n,decor:this.observerMapDecorAt(t),observerLabel:this.said.read(this.currentSighting.observer?.title)??this.messages.observerHere,nightFraction:this.observerMapNightFraction,attribution:this.observerMapFooterLine})}toggleMilestones(){this.setMilestonesShown(!this.milestonesShown)}setMilestonesShown(t){this.milestonesShown=t,this.milestoneMarks.hidden=!t,this.momentsBox.hidden=!t||this.sighting.milestones.length===0,this.refreshSeekSegments(this.player.seekableDuration,So(this.sighting.milestones).map(e=>e.t)),this.milestonesButton.setAttribute("aria-pressed",String(t)),this.updateMilestonesButton(),this.showMilestoneAt(this.currentTime),this.paintObserverMap(this.currentTime)}updateMilestonesButton(){this.milestonesButton.hidden=this.currentSighting.milestones.length===0,this.momentsButton.title=this.messages.moments,fe.setIcon(this.milestonesButton,this.milestonesShown?Zt.MILESTONES_ON:Zt.MILESTONES_OFF);const t=this.milestonesShown?this.messages.hideMilestones:this.messages.showMilestones;this.milestonesButton.title=t,this.milestonesButton.setAttribute("aria-label",t)}observerMapDecorAt(t){const e=di(this.currentSighting,0);return e?.lat===void 0||e.lng===void 0?[]:this.currentSighting.decor.filter(i=>i.kind!=="crop").map(i=>{const n=Co(i,t),{lat:s,lng:a}=_s(n.eastM,-n.northM,e.lat,e.lng);return{lat:s,lng:a,headingDeg:n.headingDeg,label:this.said.read(i.title)??this.messages.decorHere}})}observerMapNightFraction;setSunAltitude(t){const e=t===void 0?void 0:Math.max(0,Math.min(1,-t/12));e!==this.observerMapNightFraction&&(this.observerMapNightFraction=e,this.paintObserverMap(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=di(this.currentSighting,this.currentTime),s=Ss.of(this.currentSighting.instrument,this.canvas.height,n?.fovDeg??60);return{x:-s.angleDegToRadiusPx(e),y:s.angleDegToRadiusPx(i)}}gaitAt(t){return _e.bodyAt(this.currentSighting,t,this.steadyObserver)}mutedState=!1;get muted(){return this.mutedState}set muted(t){t!==this.mutedState&&(this.mutedState=t,!t&&this.volumeState===0&&(this.volumeState=fe.RESTORED_VOLUME),this.applyLevel())}volumeState=1;static RESTORED_VOLUME=.5;get volume(){return this.volumeState}set volume(t){this.setVolume(t)}setVolume(t){this.volumeState=Math.min(Math.max(t,0),1),this.mutedState=this.volumeState===0,this.applyLevel()}get level(){return this.mutedState?0:this.volumeState}applyLevel(){this.sightingAudio.setLevel(this.level),this.updateMuteButton(),this.dispatchEvent(new CustomEvent("mutedchange",{bubbles:!0,composed:!0,detail:{muted:this.mutedState,volume:this.volumeState}}))}toggleMuted(){this.muted=!this.mutedState}updateMuteButton(){fe.setIcon(this.muteButton,this.mutedState?Zt.MUTED:Zt.VOLUME);const t=this.mutedState?this.messages.unmute:this.messages.mute;this.muteButton.title=t,this.muteButton.setAttribute("aria-label",t),this.muteButton.setAttribute("aria-pressed",String(this.mutedState)),this.volumeInput.value=String(this.level)}updateFullscreenButton(){const t=this.simulatedFullscreen||document.fullscreenElement===this.fullscreenTarget;fe.setIcon(this.fullscreenButton,t?Zt.EXIT_FULLSCREEN:Zt.ENTER_FULLSCREEN),this.fullscreenButton.title=t?this.messages.exitFullscreen:this.messages.fullscreen,this.fullscreenButton.setAttribute("aria-label",this.fullscreenButton.title)}get said(){return this.saidTexts??=new Ks(pl.preferencesFor(this))}saidTexts;async loadLocaleMessages(){const t=cg(pl.preferencesFor(this),lg);if(t===this.messagesLanguage||t==="en"&&this.messagesLanguage===void 0)return;this.messagesLanguage=t;const e=await Wv(t);this.messagesLanguage===t&&this.applyMessages(e)}messagesLanguage;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,this.timePill.classList.toggle("switchable",this.canSwitchTimeDisplay),this.canSwitchTimeDisplay?(this.timePill.setAttribute("role","button"),this.timePill.setAttribute("tabindex","0")):(this.timePill.removeAttribute("role"),this.timePill.removeAttribute("tabindex"))}applyMessages(t){this.messages=t,this.updateTimeLabelTitles(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateMuteButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateMilestonesButton(),this.renderIssues()}updateTimeLabels(){const t=this.currentSighting.event,e=Tv(t);this.realDurationMs=e!==void 0&&e>0?e:void 0,this.realStartMs=t.time?wu(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 sc(t);const e=this.currentSighting.timeline.duration,i=e>0&&t<=e?t/e*this.realDurationMs:t;return this.canShowClockTime?Sf(_f(this.realStartMs+i)):sc(i)}formatEndOfTimeline(){return this.realDurationMs===void 0?sc(this.currentSighting.timeline.duration):this.canShowClockTime?Sf(_f(this.realStartMs+this.realDurationMs)):sc(this.realDurationMs)}}function _f(r){const t=new Date(r);return{hour:t.getUTCHours(),minute:t.getUTCMinutes(),second:t.getUTCSeconds()}}function Sf(r){if(r.hour===void 0)return"0:00";const t=e=>String(e).padStart(2,"0");return r.second?`${t(r.hour)}:${t(r.minute??0)}:${t(r.second)}`:`${t(r.hour)}:${t(r.minute??0)}`}function sc(r){const t=Math.round(r/1e3),e=Math.floor(t/60),i=t%60;return`${e}:${String(i).padStart(2,"0")}`}const Au="rr0-ufo";function yg(){customElements.get(Au)||customElements.define(Au,fe)}const l2="recordingissues";/**
|
|
1344
1344
|
* @license
|
|
1345
1345
|
* Copyright 2010-2026 Three.js Authors
|
|
1346
1346
|
* SPDX-License-Identifier: MIT
|
|
@@ -7190,7 +7190,7 @@ void main()
|
|
|
7190
7190
|
if (ice <= 0.0) discard;
|
|
7191
7191
|
gl_FragColor = vec4(iceHaloLight(dir, ice), 1.0);
|
|
7192
7192
|
}
|
|
7193
|
-
`,transparent:!0,blending:Ni,depthWrite:!1,side:Ve,fog:!1}),this.object=new Dt(new oi(Ci.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,a){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,a)}requestMap(t,e){if(!(!(Math.abs(t-this.mappedAltitudeDeg)<Ci.ALTITUDE_STEP_DEG)||!(Math.abs(e-this.mappedAlignment)<Ci.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)<Ci.LEAP_ALTITUDE_DEG)||!(Math.abs(e-this.pendingAlignment)<Ci.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)<Ci.ALTITUDE_STEP_DEG&&Math.abs(e-this.pendingAlignment)<Ci.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?Ci.URGENT_BUDGET_MS:Ci.BUDGET_MS;do this.sky.trace(Ci.RAYS_PER_BATCH);while(this.sky.tracedRays<Ci.RAYS&&performance.now()-e<i);if(this.sky.tracedRays>=Ci.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]=Fn.toHalfFloat(e[n]),this.texels[i+1]=Fn.toHalfFloat(e[n+1]),this.texels[i+2]=Fn.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 yi{static MAX_CONCURRENT=24;static POINTS=8;static SEGMENTS=yi.POINTS-1;static ACROSS=3;static VERTICES_PER_SEGMENT=(yi.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=yi.MAX_CONCURRENT*yi.SEGMENTS*yi.VERTICES_PER_SEGMENT;this.positions=new Float32Array(t*3),this.colors=new Float32Array(t*3);const e=new ce;e.setAttribute("position",new ie(this.positions,3)),e.setAttribute("color",new ie(this.colors,3)),e.setDrawRange(0,0),this.object=new Dt(e,new _n({vertexColors:!0,transparent:!0,blending:Ni,depthWrite:!1,fog:!1,side:ji})),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=Pa.aliveAt(this.meteors,t).slice(0,yi.MAX_CONCURRENT);let n=0;for(const{meteor:s,progress:a}of i){const o=this.radiantOf(s);if(!o)continue;const c=hi(o.altitudeDeg,o.azimuthDeg,1),[l,h]=this.basisAround(c),u=s.fromRadiantDeg+a*s.lengthDeg,d=Math.max(s.fromRadiantDeg,u-s.lengthDeg*.6),f=Math.min(1,(1-a)*2.5),p=this.turn(l,h,s.bearingDeg),v=(.15+.85*s.brightness)*f,m=y=>v*y**1.6,g=y=>this.onSphere(c,p,d+(u-d)*y),S=y=>yi.RADIUS*((yi.MIN_HALF_WIDTH_DEG+yi.BRIGHT_HALF_WIDTH_DEG*s.brightness*y)*Math.PI/180);for(let y=1;y<yi.POINTS;y++){const M=(y-1)/yi.SEGMENTS,b=y/yi.SEGMENTS;n=this.pushRibbon(n,g(M),g(b),S(M),S(b),m(M),m(b))}}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=hi(e.altitudeDeg,e.azimuthDeg,1),[n,s]=this.basisAround(i),a=this.turn(n,s,t.bearingDeg),o=this.onSphere(i,a,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,a,o){const c=this.normalise(this.cross(this.normalise(e),this.normalise(this.subtract(i,e))));for(let l=0;l<yi.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,S)=>g===0?S:0;t=this.push(t,d,m(h,a)),t=this.push(t,f,m(h,o)),t=this.push(t,p,m(u,a)),t=this.push(t,f,m(h,o)),t=this.push(t,v,m(u,o)),t=this.push(t,p,m(u,a))}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=At.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),a=Math.sin(n);return{x:t.x*s+e.x*a,y:t.y*s+e.y*a,z:t.z*s+e.z*a}}onSphere(t,e,i){const n=i*Math.PI/180,s=Math.cos(n),a=Math.sin(n);return{x:(t.x*s+e.x*a)*yi.RADIUS,y:(t.y*s+e.y*a)*yi.RADIUS,z:(t.z*s+e.z*a)*yi.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()}}class Oe{constructor(t,e={}){this.size=t,this.span=Math.min(t.lengthM,Math.max(0,e.spanM??t.lengthM)),this.bank=(t.lengthM-this.span)/2,this.deck=Math.min(t.heightM,e.deckThicknessM??Oe.DEFAULT_DECK_THICKNESS_M),this.railHeight=e.railing?.heightM??Oe.DEFAULT_RAILING_HEIGHT_M,this.postSpacing=Math.max(.3,e.railing?.postSpacingM??Oe.DEFAULT_POST_SPACING_M),this.rails=Math.max(0,Math.round(e.railing?.rails??Oe.DEFAULT_RAILS))}static DEFAULT_DECK_THICKNESS_M=1.2;static DEFAULT_RAILING_HEIGHT_M=1.05;static DEFAULT_POST_SPACING_M=1.5;static DEFAULT_RAILS=2;static BANK_SLOPE=1.5;static ABUTMENT_THICKNESS_M=1;static POST_SIDE_M=.08;static RAIL_HEIGHT_M=.08;static RAIL_DEPTH_M=.06;static BANK_STATIONS=12;static NATURAL_SIZE=Object.freeze({widthM:9,lengthM:40,heightM:6.5});span;bank;deck;railHeight;postSpacing;rails;roadAt(t){const e=Math.abs(t)-this.span/2;return e<=0?this.size.heightM:this.bank<=0?0:Math.max(0,this.size.heightM*(1-e/this.bank))}build(){const{widthM:t,heightM:e}=this.size,i=this.span/2,n=[];if(this.span>0){n.push(Oe.box(t,this.deck,this.span,0,e-this.deck/2,0));for(const c of[-1,1]){const l=e-this.deck;l>0&&this.bank>0&&n.push(Oe.box(t+1,l,Oe.ABUTMENT_THICKNESS_M,0,l/2,c*(i-Oe.ABUTMENT_THICKNESS_M/2)))}}const s=[];this.span>0&&s.push(Oe.box(t,.04,this.span,0,e+.02,0));const a=[];for(const c of[-1,1])this.bank<=0||(a.push(this.embankment(c)),s.push(this.bankRoad(c)));const o=[];for(const c of[-1,1])o.push(...this.railing(c*(t/2-Oe.POST_SIDE_M)));return{concrete:Oe.merge(n),road:Oe.merge(s),earth:Oe.merge(a),railing:Oe.merge(o)}}embankment(t){const e=this.size.widthM/2,i=this.stations(t),n=[],s=(l,h,u,d)=>{n.push(l.x,l.y,l.z,h.x,h.y,h.z,u.x,u.y,u.z,l.x,l.y,l.z,u.x,u.y,u.z,d.x,d.y,d.z)},a=l=>{const h=this.roadAt(l),u=e+Oe.BANK_SLOPE*h;return{leftFoot:new R(-u,0,l),leftTop:new R(-e,h,l),rightTop:new R(e,h,l),rightFoot:new R(u,0,l)}};for(let l=1;l<i.length;l++){const h=a(i[l-1]),u=a(i[l]),d=t>0,f=(p,v,m,g)=>d?s(p,v,m,g):s(g,m,v,p);f(h.leftFoot,h.leftTop,u.leftTop,u.leftFoot),f(h.leftTop,h.rightTop,u.rightTop,u.leftTop),f(h.rightTop,h.rightFoot,u.rightFoot,u.rightTop)}const o=a(i[0]);t>0?s(o.leftFoot,o.rightFoot,o.rightTop,o.leftTop):s(o.leftTop,o.rightTop,o.rightFoot,o.leftFoot);const c=new ce;return c.setAttribute("position",new de(n,3)),c.computeVertexNormals(),c}bankRoad(t){const e=this.size.widthM/2,i=this.stations(t),n=[];for(let a=1;a<i.length;a++){const o=i[a-1],c=i[a],l=this.roadAt(o)+.02,h=this.roadAt(c)+.02,u=t>0?[[-e,l,o],[e,l,o],[e,h,c],[-e,h,c]]:[[-e,h,c],[e,h,c],[e,l,o],[-e,l,o]];for(const d of[0,2,1,0,3,2])n.push(...u[d])}const s=new ce;return s.setAttribute("position",new de(n,3)),s.computeVertexNormals(),s}stations(t){const e=[];for(let i=0;i<=Oe.BANK_STATIONS;i++)e.push(t*(this.span/2+this.bank*i/Oe.BANK_STATIONS));return e}railing(t){const e=this.size.lengthM/2,i=Math.max(1,Math.round(this.size.lengthM/this.postSpacing)),n=[];for(let o=0;o<=i;o++)n.push(-e+this.size.lengthM*o/i);const s=[],a=Oe.POST_SIDE_M;for(const o of n)s.push(Oe.box(a,this.railHeight,a,t,this.roadAt(o)+this.railHeight/2,o));for(let o=1;o<=this.rails;o++){const c=this.railHeight*o/this.rails-Oe.RAIL_HEIGHT_M/2;for(let l=1;l<n.length;l++){const h=new R(t,this.roadAt(n[l-1])+c,n[l-1]),u=new R(t,this.roadAt(n[l])+c,n[l]);s.push(Oe.beam(h,u))}}return s}static box(t,e,i,n,s,a){return new Wi(t,e,i).translate(n,s,a)}static beam(t,e){const i=new R().subVectors(e,t),n=new Wi(Oe.RAIL_DEPTH_M,Oe.RAIL_HEIGHT_M,i.length()),s=new Qi().setFromUnitVectors(new R(0,0,1),i.clone().normalize()),a=new R().addVectors(t,e).multiplyScalar(.5);return n.applyMatrix4(new Jt().compose(a,s,new R(1,1,1)))}static merge(t){const e=t.map(c=>c.getIndex()?c.toNonIndexed():c),i=e.reduce((c,l)=>c+l.getAttribute("position").count,0),n=new Float32Array(i*3),s=new Float32Array(i*3);let a=0;for(const c of e){const l=c.getAttribute("position"),h=c.getAttribute("normal");n.set(l.array,a*3),h&&s.set(h.array,a*3),a+=l.count}const o=new ce;o.setAttribute("position",new de(n,3)),o.setAttribute("normal",new de(s,3));for(const c of t)c.dispose();for(const c of e)c.dispose();return o}}const Zh=Math.PI/180;function Ue(r,t,e,i,n=!1){const s=n?new _n({color:new st(...e)}):new zr({color:new st(...e)}),a=new Dt(t,s);return a.position.y=i,a.userData={emissive:n},a.castShadow=!n,a.receiveShadow=!n,r.add(a),a}const Jh=.25,l5=.002,h5=100,u5=1500,d5=.25,f5=1e3,p5=.15;function m5(r){const t=/^#([0-9a-f]{6})$/i.exec(r);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 g5=[.32,.32,.3],O1=[1,.85,.5],v5=[.25,.25,.25],N1=[1,.97,.85],M5=[.55,.68,.72],Jn=.03,jn=.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 Bi(r,t){return r?.[t]}function Qn(r,t,e,i,n,s,a,o){if(o===void 0)return;const c=new zr({color:new st(...M5),transparent:!0,opacity:o/100}),l=new Dt(new Wi(t,e,i),c);l.position.set(n,s,a),r.add(l)}const vn=.05,jh=[.6,.58,.53],rm=[.5,.5,.48];function Mr(r,t,e,i,n,s,a,o){const c=new zr({color:new st(...o),side:Ve}),l=new Dt(new Wi(t,e,i),c);l.position.set(n,s,a),r.add(l)}function x5(r,t,e,i,n,s,a,o,c){const l=(i-s)/2,h=(p,v,m,g)=>{p<=0||(t?Mr(r,p,v,vn,m,o+g,a,c):Mr(r,vn,v,p,a,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 U1(r,t,e,i,n,s,a,o,c,l){const h=(i+n)/2,u=n-i,d=(f,p,v,m)=>{f.length===0?p?Mr(r,v,u,vn,0,h,m,jh):Mr(r,vn,u,v,m,h,0,jh):x5(r,p,v,u,f,s,m,h,jh)};d(a,!0,t*2,-e+vn),d(o,!0,t*2,e-vn),d(c,!1,e*2,-t+vn),d(l,!1,e*2,t-vn),Mr(r,t*2,vn,e*2,0,i+vn,0,rm),Mr(r,t*2,vn,e*2,0,n-vn,0,rm)}function Xd(r,t,e,i){switch(r){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:-ts};case"front-right":return{x:t-i,z:-ts};case"behind-left":return{x:-(t-i),z:ts};case"behind-right":return{x:t-i,z:ts}}}function k1(r,t,e,i,n,s,a){const o=$d();o.scale.setScalar(i),o.rotation.y=F1[t];const{x:c,z:l}=Xd(t,n,s,a);o.position.set(c,e,l),r.add(o)}const Yd=6,qd=6,$s=3,oo=1.4,co=$s*.5,z1=1.2,B1=.35,y5=.75,_5=1.6;function om(r,t,e,i){const n=new Ce,s=Math.max(1,r+1),a=s*$s;Ue(n,new Wi(Yd,a,qd),[.55,.54,.5],a/2);const o=Yd/2,c=qd/2;for(let l=0;l<s;l++){const h=l*$s+$s/2;Qn(n,oo,co,jn,0,h,-c-Jn,Bi(t,"front")),Qn(n,oo,co,jn,0,h,c+Jn,Bi(t,"behind")),Qn(n,jn,co,oo,-o-Jn,h,0,Bi(t,"left")),Qn(n,jn,co,oo,o+Jn,h,0,Bi(t,"right"))}if(e){const l=Math.min(Math.max(i??0,0),s-1);k1(n,e,l*$s,.72,o,c,z1);const h=u=>Bi(t,u)!==void 0?[{main:oo,center:0}]:[];U1(n,o,c,l*$s,(l+1)*$s,co,h("front"),h("behind"),h("left"),h("right"))}return n}function cm(){const r=new Ce,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 a=new oi(n,10,7);a.scale(1,.85,1),a.translate(e,0,i),Ue(r,a,[.26,.28,.17],s)}return r}function S5(r){const t=new Ce,e=new Oe(ui.sizeOf(r),r.bridge).build();Ue(t,e.concrete,[.6,.6,.58],0);const i=Ue(t,e.road,[.2,.2,.21],0),n=Ue(t,e.earth,[.3,.36,.22],0);for(const s of[i,n])s.material.side=ji;return Ue(t,e.railing,[.5,.52,.55],0),t}function lm(){const r=new Ce;return Ue(r,new cs(.15,.22,2,8),[.32,.22,.14],1),Ue(r,new kr(1.4,3,8),[.16,.32,.14],3.5),r}const hm=.275,b5=.35,w5=.9,E5=34,A5=8,T5=1.4;function um(){const r=new Ce,t=new oi(hm,7,3,0,Math.PI*2,0,Math.PI/2);t.scale(1,b5/hm,1);const e=ui.repeatOnGrid(t,E5,w5,A5,T5),i=Ue(r,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(),r}function dm(){const r=new Ce,t=new oi(1,7,3,0,Math.PI*2,0,Math.PI/2);return Ue(r,t,[.38,.36,.32],0),r}function fm(r){const t=new Ce;return Ue(t,new cs(.05,.08,5,8),[.28,.28,.3],2.5),Ue(t,new oi(.25,12,8),r?O1:g5,5.1,!0),t}const R5=[.08,.08,.08],Vs=.8,dr=1,Yn=1.7,Qh=.6,fa=.4,Wc=1.2,hr=.7,ts=.5,D5=Yn;function pm(r,t,e){const i=new Ce;Ue(i,new Wi(1.8,1.4,4.2),[.45,.14,.14],.7),Ue(i,new Wi(Vs*2,Qh,dr*2),[.4,.12,.12],Yn);for(const s of[-1.4,1.4])for(const a of[-.95,.95]){const o=Ue(i,new cs(.4,.4,.3,12),R5,.4);o.rotation.z=Math.PI/2,o.position.x=a,o.position.z=s}const n=r?N1:v5;for(const s of[-.7,.7])Ue(i,new oi(.15,8,6),n,.7,!0).position.set(s,.7,-2.1);if(Qn(i,Wc,fa,jn,0,Yn,-dr-Jn,Bi(t,"front")),Qn(i,Wc,fa,jn,0,Yn,dr+Jn,Bi(t,"behind")),Qn(i,jn,fa,hr,-Vs-Jn,Yn,-ts,Bi(t,"front-left")),Qn(i,jn,fa,hr,-Vs-Jn,Yn,ts,Bi(t,"behind-left")),Qn(i,jn,fa,hr,Vs+Jn,Yn,-ts,Bi(t,"front-right")),Qn(i,jn,fa,hr,Vs+Jn,Yn,ts,Bi(t,"behind-right")),e){k1(i,e,y5,.5,Vs,dr,B1);const s=(c,l)=>{const h=[];return Bi(t,c)!==void 0&&h.push({main:hr,center:-ts}),Bi(t,l)!==void 0&&h.push({main:hr,center:ts}),h},a=Bi(t,"front")!==void 0?[{main:Wc,center:0}]:[],o=Bi(t,"behind")!==void 0?[{main:Wc,center:0}]:[];U1(i,Vs,dr,Yn-Qh/2,Yn+Qh/2,fa,a,o,s("front-left","behind-left"),s("front-right","behind-right"))}return i}const mm=new Map;function gm(r,t){if(!r)return;const e=[[r.lengthM,t.lengthM],[r.heightM,t.heightM],[r.widthM,t.widthM]];for(const[i,n]of e)if(i!==void 0&&n>1e-6)return i/n}function tu(r,t){return t>1e-6?r/t:1}const H1=[.95,.9,.82],vm=[.72,.74,.78];function Mm(){const r=new Ce;Ue(r,new cs(.25,.3,1.5,10),vm,.75),Ue(r,new oi(.26,10,8),vm,1.74);const t=Ue(r,new kr(.07,.16,8),H1,1.74);return t.rotation.x=-Math.PI/2,t.position.z=-.22,r}function $d(){const r=new Ce;Ue(r,new cs(.25,.3,1.5,10),[.3,.3,.35],.75),Ue(r,new oi(.22,10,8),[.62,.52,.46],1.72);const t=Ue(r,new kr(.07,.16,8),H1,1.72);return t.rotation.x=-Math.PI/2,t.position.z=-.2,r}const I5=17,xm=18.5,eu=[.16,.16,.18];function ym(){const r=new Ce,t=Ue(r,new cs(1.8,1.8,xm*2,10),eu,0);t.rotation.x=Math.PI/2,Ue(r,new Wi(I5*2,.5,4.5),eu,0);const e=Ue(r,new Wi(.4,5.5,4),eu,3);return e.position.z=-xm+2,r}class ui{static GROWS_FROM_GROUND=new Set(["tree","shrub","crop","mound"]);static groundUnderFootprint(t,e,i,n,s,a=0){const o=ui.sizeOf(t);if(a>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)),u=ui.GROWS_FROM_GROUND.has(t.kind);let d=u?1/0:-1/0;for(let f=0;f<l;f++){const p=(f/(l-1)-.5)*o.lengthM;for(let v=0;v<h;v++){const m=(v/(h-1)-.5)*o.widthM,g=e+Math.sin(c)*p+Math.cos(c)*m,S=i-Math.cos(c)*p+Math.sin(c)*m;d=u?Math.min(d,s(g,S)):Math.max(d,s(g,S))}}return Number.isFinite(d)?d:s(e,i)}static occupantView(t){const e=t.observerSide;if(!e)throw new Error("occupantView requires object.observerSide to be set");const{x:i,z:n}=t.kind==="vehicle"?Xd(e,Vs,dr,B1):Xd(e,Yd/2,qd/2,z1),s=t.kind==="vehicle"?D5:(t.occupiedFloor??0)*$s+_5,a=(t.headingDeg??0)-F1[e]/Zh,o=this.scaleFor(t);return{x:i*o.x,z:n*o.z,eyeY:s*o.y,headingDeg:a}}static BODY_NAME="decor-body";static bodyOf(t){return t.getObjectByName(ui.BODY_NAME)??t}static repeatOnGrid(t,e,i,n,s){const a=t.getAttribute("position"),o=t.getAttribute("normal"),c=t.getIndex();if(!c)throw new Error("repeatOnGrid needs an indexed geometry");const l=a.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 S=0;S<n;S++)for(let y=0;y<e;y++,m++){const M=v+S*s,b=p+y*i;for(let w=0;w<l;w++){const T=(m*l+w)*3;u[T]=a.getX(w)+M,u[T+1]=a.getY(w),u[T+2]=a.getZ(w)+b,d[T]=o.getX(w),d[T+1]=o.getY(w),d[T+2]=o.getZ(w)}for(let w=0;w<c.count;w++)f[m*c.count+w]=c.getX(w)+m*l}const g=new ce;return g.setAttribute("position",new de(u,3)),g.setAttribute("normal",new de(d,3)),g.setIndex(new g0(f,1)),g}static fitCropToGround(t,e){t.updateMatrixWorld(!0);const i=new R;t.traverse(n=>{const s=n,a=s.userData.cropBasePositions,o=s.userData.cropVerticesPerClump;if(!s.isMesh||!a||!o)return;const c=s.geometry.getAttribute("position"),l=new Jt().copy(s.matrixWorld).invert();for(let h=0;h<c.count;h+=o){i.set(a[h*3],0,a[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,a[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 a=n.material;a?.color&&a.color.set(e)})}static build(t,e){const i=t.kind==="building"?om(t.floors??tf,t.windows,t.observerSide,t.occupiedFloor):t.kind==="tree"?lm():t.kind==="shrub"?cm():t.kind==="bridge"?S5(t):t.kind==="crop"?um():t.kind==="mound"?dm():t.kind==="streetlight"?fm(e):t.kind==="vehicle"?pm(e,t.windows,t.observerSide):t.kind==="aircraft"?ym():t.kind==="entity"?Mm():$d();t.color&&this.paint(i,t.color);const n=this.scaleFor(t),s=new Ce;return i.name=ui.BODY_NAME,i.scale.copy(n),s.add(i),t.headingDeg!==void 0&&(s.rotation.y=-t.headingDeg*Zh),this.addLights(s,t.lights),s}static scaleFor(t){const e=t.sizeM;if(!e||t.kind==="bridge")return new R(1,1,1);const i=this.naturalSize(t.kind,t.floors);return new R(e.widthM===void 0?1:tu(e.widthM,i.widthM),e.heightM===void 0?1:tu(e.heightM,i.heightM),e.lengthM===void 0?1:tu(e.lengthM,i.lengthM))}static naturalSize(t,e){const i=t==="building"?Math.max(1,(e??tf)+1):0;if(t==="bridge")return Oe.NATURAL_SIZE;const n=`${t}:${i}`,s=mm.get(n);if(s)return s;const a=t==="building"?om(i-1,void 0,void 0,void 0):t==="tree"?lm():t==="shrub"?cm():t==="crop"?um():t==="mound"?dm():t==="streetlight"?fm(!1):t==="vehicle"?pm(!1,void 0,void 0):t==="aircraft"?ym():t==="entity"?Mm():$d(),o=new Vi().setFromObject(a),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(a),mm.set(n,c),c}static usesModel(t){return t.model!==void 0&&!(t.observerSide!==void 0&&ng(t.kind))}static applyModel(t,e,i,n={}){const s=this.bodyOf(t),a=new Ce;a.name=ui.BODY_NAME,i.rotation.y=-(n.headingOffsetDeg??0)*Zh,i.updateMatrixWorld(!0);const o=new Vi().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=gm(e.sizeM,c)??gm(n.depictedSizeM,c)??1;i.scale.multiplyScalar(l);const h=o.getCenter(new R).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)}),a.add(i),s.parent?(s.parent.add(a),s.removeFromParent()):t.add(a),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=m5(i.color),s=Ue(t,new oi(Jh,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,a=1,o=l5){if(!e||e.length===0)return;const c=new Map(e.map(d=>[d.id,d])),l=Math.max(1,n*o/Jh),h=Jh*l,u=a/(Math.PI*h*h);for(const d of t.children){if(!(d instanceof Dt))continue;const f=d.userData.lightId;if(!f)continue;const p=c.get(f);if(!p)continue;const v=s>0?sg(p,i,i+s):av(p,i)?1:0;d.visible=v>0;const m=d.material,g=d.userData.lightColor;if(g){const S=v*h5*(p.intensity??1)*u;m.color.setRGB(g[0]*S,g[1]*S,g[2]*S)}d.scale.setScalar(l)}}static setLit(t,e,i,n=1){const[s,a,o]=e==="streetlight"?[u5,d5,O1]:[f5,p5,N1],c=i?s*n/(Math.PI*a*a):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 iu="https://ufoathome.org/models/index.json";class C5{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??P5()}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 P5(){const r=`?v=${encodeURIComponent("0.81.4")}`,t=typeof location>"u"?void 0:new URL("/models/index.json",location.href).href;return(t&&t!==iu?[t,iu]:[iu]).map(e=>e+r)}const L5=[{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 C5}];async function _m(r){const{GLTFLoader:t}=await is(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(r,s=>i(Object.assign(s.scene,{animations:s.animations})),void 0,s=>n(new Error(`Could not load 3D model ${r}: ${s instanceof Error?s.message:String(s)}`)))})}const G1=["ellipsoid","sphere","disc","cylinder","cone","box","torus","figure"];class ln{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 Xi(2,2),new le({uniforms:{uColor:{value:new st(0,0,0)},uRadius:{value:1}},vertexShader:ln.VERTEX,fragmentShader:ln.FRAGMENT,transparent:!0,depthWrite:!1,blending:Ni,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*ln.MIN_ANGLE_RAD),a=ln.FILL*Math.PI*s*s;return{radiusM:s,luminanceCdM2:i*Math.min(ln.MAX_SHARE,e/a)}}static conserving(t){return Math.sqrt(t/(ln.MAX_SHARE*ln.FILL*Math.PI))}static VERTEX=`
|
|
7193
|
+
`,transparent:!0,blending:Ni,depthWrite:!1,side:Ve,fog:!1}),this.object=new Dt(new oi(Ci.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,a){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,a)}requestMap(t,e){if(!(!(Math.abs(t-this.mappedAltitudeDeg)<Ci.ALTITUDE_STEP_DEG)||!(Math.abs(e-this.mappedAlignment)<Ci.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)<Ci.LEAP_ALTITUDE_DEG)||!(Math.abs(e-this.pendingAlignment)<Ci.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)<Ci.ALTITUDE_STEP_DEG&&Math.abs(e-this.pendingAlignment)<Ci.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?Ci.URGENT_BUDGET_MS:Ci.BUDGET_MS;do this.sky.trace(Ci.RAYS_PER_BATCH);while(this.sky.tracedRays<Ci.RAYS&&performance.now()-e<i);if(this.sky.tracedRays>=Ci.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]=Fn.toHalfFloat(e[n]),this.texels[i+1]=Fn.toHalfFloat(e[n+1]),this.texels[i+2]=Fn.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 yi{static MAX_CONCURRENT=24;static POINTS=8;static SEGMENTS=yi.POINTS-1;static ACROSS=3;static VERTICES_PER_SEGMENT=(yi.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=yi.MAX_CONCURRENT*yi.SEGMENTS*yi.VERTICES_PER_SEGMENT;this.positions=new Float32Array(t*3),this.colors=new Float32Array(t*3);const e=new ce;e.setAttribute("position",new ie(this.positions,3)),e.setAttribute("color",new ie(this.colors,3)),e.setDrawRange(0,0),this.object=new Dt(e,new _n({vertexColors:!0,transparent:!0,blending:Ni,depthWrite:!1,fog:!1,side:ji})),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=Pa.aliveAt(this.meteors,t).slice(0,yi.MAX_CONCURRENT);let n=0;for(const{meteor:s,progress:a}of i){const o=this.radiantOf(s);if(!o)continue;const c=hi(o.altitudeDeg,o.azimuthDeg,1),[l,h]=this.basisAround(c),u=s.fromRadiantDeg+a*s.lengthDeg,d=Math.max(s.fromRadiantDeg,u-s.lengthDeg*.6),f=Math.min(1,(1-a)*2.5),p=this.turn(l,h,s.bearingDeg),v=(.15+.85*s.brightness)*f,m=y=>v*y**1.6,g=y=>this.onSphere(c,p,d+(u-d)*y),S=y=>yi.RADIUS*((yi.MIN_HALF_WIDTH_DEG+yi.BRIGHT_HALF_WIDTH_DEG*s.brightness*y)*Math.PI/180);for(let y=1;y<yi.POINTS;y++){const M=(y-1)/yi.SEGMENTS,b=y/yi.SEGMENTS;n=this.pushRibbon(n,g(M),g(b),S(M),S(b),m(M),m(b))}}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=hi(e.altitudeDeg,e.azimuthDeg,1),[n,s]=this.basisAround(i),a=this.turn(n,s,t.bearingDeg),o=this.onSphere(i,a,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,a,o){const c=this.normalise(this.cross(this.normalise(e),this.normalise(this.subtract(i,e))));for(let l=0;l<yi.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,S)=>g===0?S:0;t=this.push(t,d,m(h,a)),t=this.push(t,f,m(h,o)),t=this.push(t,p,m(u,a)),t=this.push(t,f,m(h,o)),t=this.push(t,v,m(u,o)),t=this.push(t,p,m(u,a))}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=At.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),a=Math.sin(n);return{x:t.x*s+e.x*a,y:t.y*s+e.y*a,z:t.z*s+e.z*a}}onSphere(t,e,i){const n=i*Math.PI/180,s=Math.cos(n),a=Math.sin(n);return{x:(t.x*s+e.x*a)*yi.RADIUS,y:(t.y*s+e.y*a)*yi.RADIUS,z:(t.z*s+e.z*a)*yi.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()}}class Oe{constructor(t,e={}){this.size=t,this.span=Math.min(t.lengthM,Math.max(0,e.spanM??t.lengthM)),this.bank=(t.lengthM-this.span)/2,this.deck=Math.min(t.heightM,e.deckThicknessM??Oe.DEFAULT_DECK_THICKNESS_M),this.railHeight=e.railing?.heightM??Oe.DEFAULT_RAILING_HEIGHT_M,this.postSpacing=Math.max(.3,e.railing?.postSpacingM??Oe.DEFAULT_POST_SPACING_M),this.rails=Math.max(0,Math.round(e.railing?.rails??Oe.DEFAULT_RAILS))}static DEFAULT_DECK_THICKNESS_M=1.2;static DEFAULT_RAILING_HEIGHT_M=1.05;static DEFAULT_POST_SPACING_M=1.5;static DEFAULT_RAILS=2;static BANK_SLOPE=1.5;static ABUTMENT_THICKNESS_M=1;static POST_SIDE_M=.08;static RAIL_HEIGHT_M=.08;static RAIL_DEPTH_M=.06;static BANK_STATIONS=12;static NATURAL_SIZE=Object.freeze({widthM:9,lengthM:40,heightM:6.5});span;bank;deck;railHeight;postSpacing;rails;roadAt(t){const e=Math.abs(t)-this.span/2;return e<=0?this.size.heightM:this.bank<=0?0:Math.max(0,this.size.heightM*(1-e/this.bank))}build(){const{widthM:t,heightM:e}=this.size,i=this.span/2,n=[];if(this.span>0){n.push(Oe.box(t,this.deck,this.span,0,e-this.deck/2,0));for(const c of[-1,1]){const l=e-this.deck;l>0&&this.bank>0&&n.push(Oe.box(t+1,l,Oe.ABUTMENT_THICKNESS_M,0,l/2,c*(i-Oe.ABUTMENT_THICKNESS_M/2)))}}const s=[];this.span>0&&s.push(Oe.box(t,.04,this.span,0,e+.02,0));const a=[];for(const c of[-1,1])this.bank<=0||(a.push(this.embankment(c)),s.push(this.bankRoad(c)));const o=[];for(const c of[-1,1])o.push(...this.railing(c*(t/2-Oe.POST_SIDE_M)));return{concrete:Oe.merge(n),road:Oe.merge(s),earth:Oe.merge(a),railing:Oe.merge(o)}}embankment(t){const e=this.size.widthM/2,i=this.stations(t),n=[],s=(l,h,u,d)=>{n.push(l.x,l.y,l.z,h.x,h.y,h.z,u.x,u.y,u.z,l.x,l.y,l.z,u.x,u.y,u.z,d.x,d.y,d.z)},a=l=>{const h=this.roadAt(l),u=e+Oe.BANK_SLOPE*h;return{leftFoot:new R(-u,0,l),leftTop:new R(-e,h,l),rightTop:new R(e,h,l),rightFoot:new R(u,0,l)}};for(let l=1;l<i.length;l++){const h=a(i[l-1]),u=a(i[l]),d=t>0,f=(p,v,m,g)=>d?s(p,v,m,g):s(g,m,v,p);f(h.leftFoot,h.leftTop,u.leftTop,u.leftFoot),f(h.leftTop,h.rightTop,u.rightTop,u.leftTop),f(h.rightTop,h.rightFoot,u.rightFoot,u.rightTop)}const o=a(i[0]);t>0?s(o.leftFoot,o.rightFoot,o.rightTop,o.leftTop):s(o.leftTop,o.rightTop,o.rightFoot,o.leftFoot);const c=new ce;return c.setAttribute("position",new de(n,3)),c.computeVertexNormals(),c}bankRoad(t){const e=this.size.widthM/2,i=this.stations(t),n=[];for(let a=1;a<i.length;a++){const o=i[a-1],c=i[a],l=this.roadAt(o)+.02,h=this.roadAt(c)+.02,u=t>0?[[-e,l,o],[e,l,o],[e,h,c],[-e,h,c]]:[[-e,h,c],[e,h,c],[e,l,o],[-e,l,o]];for(const d of[0,2,1,0,3,2])n.push(...u[d])}const s=new ce;return s.setAttribute("position",new de(n,3)),s.computeVertexNormals(),s}stations(t){const e=[];for(let i=0;i<=Oe.BANK_STATIONS;i++)e.push(t*(this.span/2+this.bank*i/Oe.BANK_STATIONS));return e}railing(t){const e=this.size.lengthM/2,i=Math.max(1,Math.round(this.size.lengthM/this.postSpacing)),n=[];for(let o=0;o<=i;o++)n.push(-e+this.size.lengthM*o/i);const s=[],a=Oe.POST_SIDE_M;for(const o of n)s.push(Oe.box(a,this.railHeight,a,t,this.roadAt(o)+this.railHeight/2,o));for(let o=1;o<=this.rails;o++){const c=this.railHeight*o/this.rails-Oe.RAIL_HEIGHT_M/2;for(let l=1;l<n.length;l++){const h=new R(t,this.roadAt(n[l-1])+c,n[l-1]),u=new R(t,this.roadAt(n[l])+c,n[l]);s.push(Oe.beam(h,u))}}return s}static box(t,e,i,n,s,a){return new Wi(t,e,i).translate(n,s,a)}static beam(t,e){const i=new R().subVectors(e,t),n=new Wi(Oe.RAIL_DEPTH_M,Oe.RAIL_HEIGHT_M,i.length()),s=new Qi().setFromUnitVectors(new R(0,0,1),i.clone().normalize()),a=new R().addVectors(t,e).multiplyScalar(.5);return n.applyMatrix4(new Jt().compose(a,s,new R(1,1,1)))}static merge(t){const e=t.map(c=>c.getIndex()?c.toNonIndexed():c),i=e.reduce((c,l)=>c+l.getAttribute("position").count,0),n=new Float32Array(i*3),s=new Float32Array(i*3);let a=0;for(const c of e){const l=c.getAttribute("position"),h=c.getAttribute("normal");n.set(l.array,a*3),h&&s.set(h.array,a*3),a+=l.count}const o=new ce;o.setAttribute("position",new de(n,3)),o.setAttribute("normal",new de(s,3));for(const c of t)c.dispose();for(const c of e)c.dispose();return o}}const Zh=Math.PI/180;function Ue(r,t,e,i,n=!1){const s=n?new _n({color:new st(...e)}):new zr({color:new st(...e)}),a=new Dt(t,s);return a.position.y=i,a.userData={emissive:n},a.castShadow=!n,a.receiveShadow=!n,r.add(a),a}const Jh=.25,l5=.002,h5=100,u5=1500,d5=.25,f5=1e3,p5=.15;function m5(r){const t=/^#([0-9a-f]{6})$/i.exec(r);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 g5=[.32,.32,.3],O1=[1,.85,.5],v5=[.25,.25,.25],N1=[1,.97,.85],M5=[.55,.68,.72],Jn=.03,jn=.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 Bi(r,t){return r?.[t]}function Qn(r,t,e,i,n,s,a,o){if(o===void 0)return;const c=new zr({color:new st(...M5),transparent:!0,opacity:o/100}),l=new Dt(new Wi(t,e,i),c);l.position.set(n,s,a),r.add(l)}const vn=.05,jh=[.6,.58,.53],rm=[.5,.5,.48];function Mr(r,t,e,i,n,s,a,o){const c=new zr({color:new st(...o),side:Ve}),l=new Dt(new Wi(t,e,i),c);l.position.set(n,s,a),r.add(l)}function x5(r,t,e,i,n,s,a,o,c){const l=(i-s)/2,h=(p,v,m,g)=>{p<=0||(t?Mr(r,p,v,vn,m,o+g,a,c):Mr(r,vn,v,p,a,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 U1(r,t,e,i,n,s,a,o,c,l){const h=(i+n)/2,u=n-i,d=(f,p,v,m)=>{f.length===0?p?Mr(r,v,u,vn,0,h,m,jh):Mr(r,vn,u,v,m,h,0,jh):x5(r,p,v,u,f,s,m,h,jh)};d(a,!0,t*2,-e+vn),d(o,!0,t*2,e-vn),d(c,!1,e*2,-t+vn),d(l,!1,e*2,t-vn),Mr(r,t*2,vn,e*2,0,i+vn,0,rm),Mr(r,t*2,vn,e*2,0,n-vn,0,rm)}function Xd(r,t,e,i){switch(r){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:-ts};case"front-right":return{x:t-i,z:-ts};case"behind-left":return{x:-(t-i),z:ts};case"behind-right":return{x:t-i,z:ts}}}function k1(r,t,e,i,n,s,a){const o=$d();o.scale.setScalar(i),o.rotation.y=F1[t];const{x:c,z:l}=Xd(t,n,s,a);o.position.set(c,e,l),r.add(o)}const Yd=6,qd=6,$s=3,oo=1.4,co=$s*.5,z1=1.2,B1=.35,y5=.75,_5=1.6;function om(r,t,e,i){const n=new Ce,s=Math.max(1,r+1),a=s*$s;Ue(n,new Wi(Yd,a,qd),[.55,.54,.5],a/2);const o=Yd/2,c=qd/2;for(let l=0;l<s;l++){const h=l*$s+$s/2;Qn(n,oo,co,jn,0,h,-c-Jn,Bi(t,"front")),Qn(n,oo,co,jn,0,h,c+Jn,Bi(t,"behind")),Qn(n,jn,co,oo,-o-Jn,h,0,Bi(t,"left")),Qn(n,jn,co,oo,o+Jn,h,0,Bi(t,"right"))}if(e){const l=Math.min(Math.max(i??0,0),s-1);k1(n,e,l*$s,.72,o,c,z1);const h=u=>Bi(t,u)!==void 0?[{main:oo,center:0}]:[];U1(n,o,c,l*$s,(l+1)*$s,co,h("front"),h("behind"),h("left"),h("right"))}return n}function cm(){const r=new Ce,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 a=new oi(n,10,7);a.scale(1,.85,1),a.translate(e,0,i),Ue(r,a,[.26,.28,.17],s)}return r}function S5(r){const t=new Ce,e=new Oe(ui.sizeOf(r),r.bridge).build();Ue(t,e.concrete,[.6,.6,.58],0);const i=Ue(t,e.road,[.2,.2,.21],0),n=Ue(t,e.earth,[.3,.36,.22],0);for(const s of[i,n])s.material.side=ji;return Ue(t,e.railing,[.5,.52,.55],0),t}function lm(){const r=new Ce;return Ue(r,new cs(.15,.22,2,8),[.32,.22,.14],1),Ue(r,new kr(1.4,3,8),[.16,.32,.14],3.5),r}const hm=.275,b5=.35,w5=.9,E5=34,A5=8,T5=1.4;function um(){const r=new Ce,t=new oi(hm,7,3,0,Math.PI*2,0,Math.PI/2);t.scale(1,b5/hm,1);const e=ui.repeatOnGrid(t,E5,w5,A5,T5),i=Ue(r,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(),r}function dm(){const r=new Ce,t=new oi(1,7,3,0,Math.PI*2,0,Math.PI/2);return Ue(r,t,[.38,.36,.32],0),r}function fm(r){const t=new Ce;return Ue(t,new cs(.05,.08,5,8),[.28,.28,.3],2.5),Ue(t,new oi(.25,12,8),r?O1:g5,5.1,!0),t}const R5=[.08,.08,.08],Vs=.8,dr=1,Yn=1.7,Qh=.6,fa=.4,Wc=1.2,hr=.7,ts=.5,D5=Yn;function pm(r,t,e){const i=new Ce;Ue(i,new Wi(1.8,1.4,4.2),[.45,.14,.14],.7),Ue(i,new Wi(Vs*2,Qh,dr*2),[.4,.12,.12],Yn);for(const s of[-1.4,1.4])for(const a of[-.95,.95]){const o=Ue(i,new cs(.4,.4,.3,12),R5,.4);o.rotation.z=Math.PI/2,o.position.x=a,o.position.z=s}const n=r?N1:v5;for(const s of[-.7,.7])Ue(i,new oi(.15,8,6),n,.7,!0).position.set(s,.7,-2.1);if(Qn(i,Wc,fa,jn,0,Yn,-dr-Jn,Bi(t,"front")),Qn(i,Wc,fa,jn,0,Yn,dr+Jn,Bi(t,"behind")),Qn(i,jn,fa,hr,-Vs-Jn,Yn,-ts,Bi(t,"front-left")),Qn(i,jn,fa,hr,-Vs-Jn,Yn,ts,Bi(t,"behind-left")),Qn(i,jn,fa,hr,Vs+Jn,Yn,-ts,Bi(t,"front-right")),Qn(i,jn,fa,hr,Vs+Jn,Yn,ts,Bi(t,"behind-right")),e){k1(i,e,y5,.5,Vs,dr,B1);const s=(c,l)=>{const h=[];return Bi(t,c)!==void 0&&h.push({main:hr,center:-ts}),Bi(t,l)!==void 0&&h.push({main:hr,center:ts}),h},a=Bi(t,"front")!==void 0?[{main:Wc,center:0}]:[],o=Bi(t,"behind")!==void 0?[{main:Wc,center:0}]:[];U1(i,Vs,dr,Yn-Qh/2,Yn+Qh/2,fa,a,o,s("front-left","behind-left"),s("front-right","behind-right"))}return i}const mm=new Map;function gm(r,t){if(!r)return;const e=[[r.lengthM,t.lengthM],[r.heightM,t.heightM],[r.widthM,t.widthM]];for(const[i,n]of e)if(i!==void 0&&n>1e-6)return i/n}function tu(r,t){return t>1e-6?r/t:1}const H1=[.95,.9,.82],vm=[.72,.74,.78];function Mm(){const r=new Ce;Ue(r,new cs(.25,.3,1.5,10),vm,.75),Ue(r,new oi(.26,10,8),vm,1.74);const t=Ue(r,new kr(.07,.16,8),H1,1.74);return t.rotation.x=-Math.PI/2,t.position.z=-.22,r}function $d(){const r=new Ce;Ue(r,new cs(.25,.3,1.5,10),[.3,.3,.35],.75),Ue(r,new oi(.22,10,8),[.62,.52,.46],1.72);const t=Ue(r,new kr(.07,.16,8),H1,1.72);return t.rotation.x=-Math.PI/2,t.position.z=-.2,r}const I5=17,xm=18.5,eu=[.16,.16,.18];function ym(){const r=new Ce,t=Ue(r,new cs(1.8,1.8,xm*2,10),eu,0);t.rotation.x=Math.PI/2,Ue(r,new Wi(I5*2,.5,4.5),eu,0);const e=Ue(r,new Wi(.4,5.5,4),eu,3);return e.position.z=-xm+2,r}class ui{static GROWS_FROM_GROUND=new Set(["tree","shrub","crop","mound"]);static groundUnderFootprint(t,e,i,n,s,a=0){const o=ui.sizeOf(t);if(a>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)),u=ui.GROWS_FROM_GROUND.has(t.kind);let d=u?1/0:-1/0;for(let f=0;f<l;f++){const p=(f/(l-1)-.5)*o.lengthM;for(let v=0;v<h;v++){const m=(v/(h-1)-.5)*o.widthM,g=e+Math.sin(c)*p+Math.cos(c)*m,S=i-Math.cos(c)*p+Math.sin(c)*m;d=u?Math.min(d,s(g,S)):Math.max(d,s(g,S))}}return Number.isFinite(d)?d:s(e,i)}static occupantView(t){const e=t.observerSide;if(!e)throw new Error("occupantView requires object.observerSide to be set");const{x:i,z:n}=t.kind==="vehicle"?Xd(e,Vs,dr,B1):Xd(e,Yd/2,qd/2,z1),s=t.kind==="vehicle"?D5:(t.occupiedFloor??0)*$s+_5,a=(t.headingDeg??0)-F1[e]/Zh,o=this.scaleFor(t);return{x:i*o.x,z:n*o.z,eyeY:s*o.y,headingDeg:a}}static BODY_NAME="decor-body";static bodyOf(t){return t.getObjectByName(ui.BODY_NAME)??t}static repeatOnGrid(t,e,i,n,s){const a=t.getAttribute("position"),o=t.getAttribute("normal"),c=t.getIndex();if(!c)throw new Error("repeatOnGrid needs an indexed geometry");const l=a.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 S=0;S<n;S++)for(let y=0;y<e;y++,m++){const M=v+S*s,b=p+y*i;for(let w=0;w<l;w++){const T=(m*l+w)*3;u[T]=a.getX(w)+M,u[T+1]=a.getY(w),u[T+2]=a.getZ(w)+b,d[T]=o.getX(w),d[T+1]=o.getY(w),d[T+2]=o.getZ(w)}for(let w=0;w<c.count;w++)f[m*c.count+w]=c.getX(w)+m*l}const g=new ce;return g.setAttribute("position",new de(u,3)),g.setAttribute("normal",new de(d,3)),g.setIndex(new g0(f,1)),g}static fitCropToGround(t,e){t.updateMatrixWorld(!0);const i=new R;t.traverse(n=>{const s=n,a=s.userData.cropBasePositions,o=s.userData.cropVerticesPerClump;if(!s.isMesh||!a||!o)return;const c=s.geometry.getAttribute("position"),l=new Jt().copy(s.matrixWorld).invert();for(let h=0;h<c.count;h+=o){i.set(a[h*3],0,a[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,a[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 a=n.material;a?.color&&a.color.set(e)})}static build(t,e){const i=t.kind==="building"?om(t.floors??tf,t.windows,t.observerSide,t.occupiedFloor):t.kind==="tree"?lm():t.kind==="shrub"?cm():t.kind==="bridge"?S5(t):t.kind==="crop"?um():t.kind==="mound"?dm():t.kind==="streetlight"?fm(e):t.kind==="vehicle"?pm(e,t.windows,t.observerSide):t.kind==="aircraft"?ym():t.kind==="entity"?Mm():$d();t.color&&this.paint(i,t.color);const n=this.scaleFor(t),s=new Ce;return i.name=ui.BODY_NAME,i.scale.copy(n),s.add(i),t.headingDeg!==void 0&&(s.rotation.y=-t.headingDeg*Zh),this.addLights(s,t.lights),s}static scaleFor(t){const e=t.sizeM;if(!e||t.kind==="bridge")return new R(1,1,1);const i=this.naturalSize(t.kind,t.floors);return new R(e.widthM===void 0?1:tu(e.widthM,i.widthM),e.heightM===void 0?1:tu(e.heightM,i.heightM),e.lengthM===void 0?1:tu(e.lengthM,i.lengthM))}static naturalSize(t,e){const i=t==="building"?Math.max(1,(e??tf)+1):0;if(t==="bridge")return Oe.NATURAL_SIZE;const n=`${t}:${i}`,s=mm.get(n);if(s)return s;const a=t==="building"?om(i-1,void 0,void 0,void 0):t==="tree"?lm():t==="shrub"?cm():t==="crop"?um():t==="mound"?dm():t==="streetlight"?fm(!1):t==="vehicle"?pm(!1,void 0,void 0):t==="aircraft"?ym():t==="entity"?Mm():$d(),o=new Vi().setFromObject(a),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(a),mm.set(n,c),c}static usesModel(t){return t.model!==void 0&&!(t.observerSide!==void 0&&ng(t.kind))}static applyModel(t,e,i,n={}){const s=this.bodyOf(t),a=new Ce;a.name=ui.BODY_NAME,i.rotation.y=-(n.headingOffsetDeg??0)*Zh,i.updateMatrixWorld(!0);const o=new Vi().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=gm(e.sizeM,c)??gm(n.depictedSizeM,c)??1;i.scale.multiplyScalar(l);const h=o.getCenter(new R).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)}),a.add(i),s.parent?(s.parent.add(a),s.removeFromParent()):t.add(a),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=m5(i.color),s=Ue(t,new oi(Jh,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,a=1,o=l5){if(!e||e.length===0)return;const c=new Map(e.map(d=>[d.id,d])),l=Math.max(1,n*o/Jh),h=Jh*l,u=a/(Math.PI*h*h);for(const d of t.children){if(!(d instanceof Dt))continue;const f=d.userData.lightId;if(!f)continue;const p=c.get(f);if(!p)continue;const v=s>0?sg(p,i,i+s):av(p,i)?1:0;d.visible=v>0;const m=d.material,g=d.userData.lightColor;if(g){const S=v*h5*(p.intensity??1)*u;m.color.setRGB(g[0]*S,g[1]*S,g[2]*S)}d.scale.setScalar(l)}}static setLit(t,e,i,n=1){const[s,a,o]=e==="streetlight"?[u5,d5,O1]:[f5,p5,N1],c=i?s*n/(Math.PI*a*a):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 iu="https://ufoathome.org/models/index.json";class C5{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??P5()}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 P5(){const r=`?v=${encodeURIComponent("0.81.5")}`,t=typeof location>"u"?void 0:new URL("/models/index.json",location.href).href;return(t&&t!==iu?[t,iu]:[iu]).map(e=>e+r)}const L5=[{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 C5}];async function _m(r){const{GLTFLoader:t}=await is(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(r,s=>i(Object.assign(s.scene,{animations:s.animations})),void 0,s=>n(new Error(`Could not load 3D model ${r}: ${s instanceof Error?s.message:String(s)}`)))})}const G1=["ellipsoid","sphere","disc","cylinder","cone","box","torus","figure"];class ln{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 Xi(2,2),new le({uniforms:{uColor:{value:new st(0,0,0)},uRadius:{value:1}},vertexShader:ln.VERTEX,fragmentShader:ln.FRAGMENT,transparent:!0,depthWrite:!1,blending:Ni,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*ln.MIN_ANGLE_RAD),a=ln.FILL*Math.PI*s*s;return{radiusM:s,luminanceCdM2:i*Math.min(ln.MAX_SHARE,e/a)}}static conserving(t){return Math.sqrt(t/(ln.MAX_SHARE*ln.FILL*Math.PI))}static VERTEX=`
|
|
7194
7194
|
uniform float uRadius;
|
|
7195
7195
|
varying vec2 vOffset;
|
|
7196
7196
|
void main() {
|
|
@@ -7753,7 +7753,7 @@ cloudPoint = (modelMatrix * vec4(transformed, 1.0)).xyz - cameraPosition;`);let
|
|
|
7753
7753
|
vec3 light = texture2D(uMap, vec2((along * (uSteps - 1.0) + 0.5) / uSteps, 0.5)).rgb;
|
|
7754
7754
|
gl_FragColor = vec4(light, 1.0);
|
|
7755
7755
|
}
|
|
7756
|
-
`,transparent:!0,blending:Ni,depthWrite:!1,side:Ve,fog:!1});this.object=new Dt(new oi(B0.RADIUS,128,32,0,Math.PI*2,0,pe.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<pe.STEPS;i++){for(let n=0;n<3;n++)this.texels[i*4+n]=Fn.toHalfFloat(Math.min(e[i*3+n],6e4));this.texels[i*4+3]=Fn.toHalfFloat(1)}this.texture.needsUpdate=!0,this.object.visible=!0}dispose(){this.object.geometry.dispose(),this.object.material.dispose(),this.texture.dispose()}}class Nl{constructor(t){this.generator=t}static SIZE=128;target=new Wo(Nl.SIZE,{type:qe,generateMipmaps:!1,minFilter:oe,magFilter:oe});camera=new b0(.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 a=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=a[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 on{static REFRESH_MS=250;generator;eye;probes=new Map;constructor(t){on.install(),this.generator=new gd(t),this.eye=new Nl(this.generator)}static decor;refresh(t,e,i,n,s,a,o,c=[],l,h=on.REFRESH_MS){for(const m of[...this.probes.keys()])n.some(g=>g.id===m&&g.shiny)||(this.probes.get(m).dispose(),this.probes.delete(m));const u=[{probe:this.eye}];for(const m of n){if(!m.shiny)continue;let g=this.probes.get(m.id);g||(g=new Nl(this.generator),this.probes.set(m.id,g)),u.push({probe:g,reflector:m})}const d=performance.now(),f=()=>u.filter(({probe:m})=>m.capturedVersion!==o),p=f().filter(({probe:m})=>d-m.capturedAtMs>=h);if(p.length>0){const m=p.reduce((g,S)=>S.probe.capturedAtMs<g.probe.capturedAtMs?S:g);if(m.reflector){const g=m.reflector.holder.getWorldPosition(this.scratch);m.probe.capture(t,e,g,[m.reflector.holder,...s]),on.reflectOn(m.reflector.holder,m.probe)}else{m.probe.capture(t,e,i,[...s,...c]),l?.(m.probe.sharp),on.decor=m.probe.filtered;for(const g of a)on.reflectOn(g,m.probe);for(const g of n)g.shiny||on.reflectOn(g.holder,m.probe)}m.probe.capturedVersion=o}const v=f();if(v.length!==0)return Math.max(16,Math.min(...v.map(({probe:m})=>h-(d-m.capturedAtMs))))}scratch=new R;static reflectOn(t,e={filtered:on.decor}){t.traverse(i=>{const n=i.material;for(const s of Array.isArray(n)?n:n?[n]:[])s instanceof Yo?e.sharp&&s.setSurroundings(e.sharp):s instanceof ya&&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(on.installed)return;on.installed=!0;const t="iblIrradiance += getIBLIrradiance( geometryNormal );";if(!Xt.lights_fragment_maps.includes(t)){console.warn("Reflections: three's lights_fragment_maps changed; the environment will light diffusely too");return}Xt.lights_fragment_maps=Xt.lights_fragment_maps.replace(t,"// The sky's diffuse light is the hemisphere light's (see Reflections).")}}function F5(r,t){return JSON.stringify(r.cloudLayers)===JSON.stringify(t.cloudLayers)&&r.cloudCover===t.cloudCover&&r.cloudDarkness===t.cloudDarkness&&r.cloudBaseM===t.cloudBaseM&&r.highCloudCover===t.highCloudCover&&r.iceCrystalAlignment===t.iceCrystalAlignment&&r.lowerCloudCover===t.lowerCloudCover&&r.relativeHumidity===t.relativeHumidity&&r.precipitationType===t.precipitationType&&r.precipitationIntensity===t.precipitationIntensity&&r.precipitationAmount===t.precipitationAmount&&r.windDirectionDeg===t.windDirectionDeg&&r.windSpeed===t.windSpeed&&r.storm===t.storm}const qc=900,nu=1,Sm=4,bm=5,wm=.5,_o=900,U5=6371e3,k5=3e4;function Em(r){const t=Math.sqrt(2*U5*Math.max(r,0));return Math.max(_o,Math.min(t,k5))}const su=.5,au=850,Am=.03,sn=850,ho=300,Gs=120,z5=700,B5=.04,uo=4,ru=1.5,Tm=-1,H5=6,Kd=-4,G5=2,V5=20,$c=2600,W5=.97,X5=.38,Kc=Kd,Rm=1500,Y5=400,q5=[0,45,90,135,180,225,270,315],$5=2,K5=16,Dm=4e3,Im=880,Zc=40,Cm=60,Z5=10,J5=1,j5=150,Q5=55,tE=.5,eE=17,Pm=.265,Lm=[[0,0],...Array.from({length:8},(r,t)=>{const e=t*Math.PI/4;return[Math.cos(e)*Pm,Math.sin(e)*Pm]})],ou=700,cu=250/Jd,iE=12,Om=5,lu=6,pa=[.92,.92,.95],hu=[.15,.15,.19],uu={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}},fr=0,du=0,nE=150,fu=3e3,fo=20,sE=15,Nm=fr,aE=40,Fm=1,rE=9;function pu(r){return Fm+(rE-Fm)*r}const Um=new st(.75,.82,.92),oE=10,cE=.5;function km(r){return xr(r/oE,cE,1)}const ma=200,zm=.18,Bm=.32,lE=.35,Hm=new st(.85,.9,.98),Gm=5,Vm=.85,Wm=.01;function hE(r,t,e=1){return Math.round(r*(Wm+(1-Wm)*t)*e)}function uE(r,t){return JSON.stringify(r.cloudLayers)===JSON.stringify(t.cloudLayers)&&r.cloudCover===t.cloudCover&&r.cloudDarkness===t.cloudDarkness&&r.cloudBaseM===t.cloudBaseM&&r.highCloudCover===t.highCloudCover&&r.iceCrystalAlignment===t.iceCrystalAlignment&&r.lowerCloudCover===t.lowerCloudCover}const Xm=230,Ym=.7,qm=.05,dE=.6,fE=.7,pE=.15,$m=.35,mE=3,gE=1/12,vE=.5,Xn=new st(.82,.86,1),ME=2500,xE=1.6,mu=15,yE={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 ke{renderer;scene=new Ts;phenomena=new In(this.scene);references=new Rn(this.scene,()=>this.render());camera;celestialGroup=new Ce;skyMesh;skyGradientMaterial;scatteredSky;lastAstronomy;skyColoursStale=!1;scatteredSkyFrameId=null;skyHoldUntilMs=void 0;onFirstFrameHold;firstFrameReady(){return(!this.scatteredSky||this.scatteredSky.ambient!==void 0)&&!this.iceHalos?.awaitingFirstDisplay}sceneSettled(){return this.firstFrameReady()&&this.arrivalsPending===0&&this.eyeSettledVersion>=this.lastArrivalVersion}arrivalsPending=0;eyeSettledVersion=-1;lastArrivalVersion=0;awaitArrival(t,e){if(this.skyHoldUntilMs===null)return t;this.arrivalsPending++;let i=!0;const n=()=>{i&&(i=!1,this.arrivalsPending--,this.lastArrivalVersion=this.sceneVersion,this.skyHoldUntilMs&&this.redrawHeld())},s=e===void 0?void 0:setTimeout(n,e);return t.finally(()=>{clearTimeout(s),n()})}static ROADS_PATIENCE_MS=1500;redrawHeld(){this.frameDirty=!0,!(this.animationFrameId!==null||this.framesDriven||this.flushFrameId!==null)&&(this.flushFrameId=requestAnimationFrame(()=>{this.flushFrameId=null,this.drawIfDirty()}))}holdForNewScene(t){this.surroundings=void 0,this.scatteredSky?.resetSurroundings(),this.startHold(),t&&this.awaitArrival(t).catch(()=>{})}startHold(){this.skyHoldUntilMs=performance.now()+Dm,this.eyeSettledVersion=-1,this.lastArrivalVersion=this.sceneVersion+1,this.iceHalos?.setUrgent(!0),this.onFirstFrameHold?.(!0),setTimeout(()=>this.render(),Dm+20)}groundMesh;terrainMesh;terrainProviders;terrainOrigin;terrainBuildToken=0;terrainAttribution;roadSystem=new gn;roadAttribution;roadWays;statedRoads=[];decorModelProvider=L5[0].create();decorModelToken=0;decorModelCredits=new Map;bodySystem=new ue(t=>this.awaitArrival(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 mp(16777215,0);celestialLightTarget=new Be;skyLight=new rx(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 cl;weather=jd;observerElevationM=0;siteElevationM=0;air=new xn;groundRadius=_o;terrainRadius=_o;cloudRendering="volume";layeredClouds;cloudLayerOffsetsM={};cloudOffsetM=new R;cloudFieldOffset=new R;cloudMesh;cirrusMesh;cirrusMaterial;cirrusUniforms;cloudMaterial;cloudUniforms;precipitationPoints;precipitationPositions;precipitationPhase;precipitationSpeedJitter;precipitationWobbleFreqJitter;precipitationWobbleAmpJitter;precipitationBounceRemaining;precipitationBounceHeight;precipitationBounceDuration;precipitationBounceVelX;precipitationBounceVelZ;precipitationUniforms;rainSystem;rainSplashSystem;rainCameraDirection=new R;rainLastVerticalFacing=-1;rainViewportSize=new xt;lightningArmed=!1;lightningFlashes=[];lightningLevel=0;lightningBolt;lightningLight=new mp(16777215,0);baseFogColor=[0,0,0];lastSunPosition;lensFlare;sunUnhiddenFraction=1;lensFlareArtifactIntensity=0;sunWorldPosition=new R;sunVisible=!1;lensFlareScratch=new R;sunOcclusionRaycaster=new cl;sunOcclusionDirectionScratch=new R;sunOcclusionRightScratch=new R;sunOcclusionUpScratch=new R;ufoOcclusionRaycaster=new cl;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;lightPollution;meteorSystem;cometTail;satelliteField;iceHalos;lunarDiffraction;lunarDiffractionKey="";rainbow;skyGlow;cometKey;novaKeys=new Set;constructor(t,e=r2()){this.renderer=new xb({canvas:t,antialias:!0}),this.resolution=new ve(Math.min(window.devicePixelRatio||1,2),this.renderer.getContext()),this.renderer.setPixelRatio(this.resolution.pixelRatio),this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=bo,this.camera=new Zi(60,t.width/Math.max(t.height,1),.1,qc*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=-Gs,this.celestialLight.shadow.camera.right=Gs,this.celestialLight.shadow.camera.top=Gs,this.celestialLight.shadow.camera.bottom=-Gs,this.celestialLight.shadow.camera.near=sn-ho,this.celestialLight.shadow.camera.far=sn+ho,this.celestialLight.shadow.bias=-.03/(2*ho),this.celestialLight.shadow.normalBias=B5,this.celestialLight.target=this.celestialLightTarget,this.lightningLight.color.copy(Xn),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 Ne(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*cu,0,t.z*cu);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)*qi,i=(t.pitchDeg+this.lookPitchDeg+this.gaitOffset.pitchDeg)*qi;if(t.headingDeg!==void 0?this.camera.rotation.set(i,-(t.headingDeg+this.lookYawDeg+this.gaitOffset.yawDeg)*qi,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/_o),this.camera.far=Math.max(qc*1.2,this.groundRadius*2.5),this.camera.updateProjectionMatrix())),this.terrainMesh&&this.terrainOrigin&&t.lat!==void 0&&t.lng!==void 0){const n=ai(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.stopTerrainFade(),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}=ai(t,e,this.terrainOrigin.lat,this.terrainOrigin.lng);if(Math.sqrt(c*c+l*l)<j5*(n/_o))return}const s=this.terrainOrigin,a=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;this.awaitArrival(Xw(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?ai(t,e,s.lat,s.lng):void 0;u&&d&&Math.hypot(d.x,d.z)<=a&&(c.position.y=u.position.y+this.groundYOfPatch(u,d.x,d.z)),u&&d&&Math.hypot(d.x,d.z)<=a?this.crossfadeTerrain(c,u):this.disposeMesh(this.terrainMesh),c.renderOrder=J5,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 TERRAIN_CROSSFADE_MS=1200;fadingTerrain;crossfadeTerrain(t,e){this.stopTerrainFade();const i=t.material;i.opacity=0,i.polygonOffset=!0,i.polygonOffsetFactor=-1,i.polygonOffsetUnits=-4;const n=performance.now(),s=()=>{const a=Math.min(1,(performance.now()-n)/ke.TERRAIN_CROSSFADE_MS);if(i.opacity=a*a*(3-2*a),this.render(),a<1&&this.fadingTerrain){this.fadingTerrain.frameId=requestAnimationFrame(s);return}i.polygonOffset=!1,i.opacity=1,this.fadingTerrain&&this.disposeMesh(this.fadingTerrain.mesh),this.fadingTerrain=void 0,this.render()};this.fadingTerrain={mesh:e,frameId:requestAnimationFrame(s)}}stopTerrainFade(){if(!this.fadingTerrain)return;cancelAnimationFrame(this.fadingTerrain.frameId),this.disposeMesh(this.fadingTerrain.mesh),this.fadingTerrain=void 0;const t=this.terrainMesh?.material;t&&(t.opacity=1,t.polygonOffset=!1)}static ROADS_MAX_RADIUS_M=5e3;buildRoads(t,e,i){const n=this.terrainProviders.roads;if(!n||i>ke.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}this.awaitArrival(n.getRoads(L1(t,e,i)),ke.ROADS_PATIENCE_MS).then(a=>{this.terrainOrigin?.lat!==t||this.terrainOrigin?.lng!==e||(this.roadWays={lat:t,lng:e,radiusM:i,ways:a},this.drapeRoads(a,t,e,n.contemporary))}).catch(a=>{console.warn("Roads unavailable, drawing none:",a)})}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,(a,o)=>this.groundYOfPatch(s,a,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())}setCompassPoints(t){this.compassPoints!==t&&(this.compassPoints=t,this.showCompass&&(this.disposeCompassLabels(),this.buildCompassLabels(),this.render()))}compassPoints;applyLensFlareTint(t){if(!this.lensFlare)return;const e=Q5*(this.sunArriving[1]/eE);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=Pi.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){if(F5(this.weather,t))return;this.cloudTransmissionMemo.clear();const e=this.weather;this.weather=t;const i=!uE(e,t),n=e.precipitationType!==t.precipitationType,s=e.precipitationIntensity!==t.precipitationIntensity||e.precipitationAmount!==t.precipitationAmount;(e.relativeHumidity!==t.relativeHumidity||n||s)&&(this.air=xn.of(t),this.applyAir(),this.scatteredSky?.setConditions({aerosolOpticalDepth:t.relativeHumidity===void 0?void 0:ta.steppedOpticalDepth(t.relativeHumidity)}),this.pumpScatteredSky()),i&&(this.buildClouds(),this.buildCirrus()),n?this.buildPrecipitation():s&&this.updatePrecipitationDensity(),this.lastAstronomy&&(i&&(this.buildIceHalos(this.lastAstronomy.sun,this.lastAstronomy.moon),this.buildLunarDiffraction(this.lastAstronomy.moon)),(i||n||s)&&this.buildRainbow(this.lastAstronomy.sun,this.lastAstronomy.moon)),this.lightningArmed=t.storm&&t.cloudDarkness>=vE,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(),ui.dispose(e);this.decorGroups.clear(),this.streetlightLights.clear();for(const e of t){const i=ui.build(e,e.lit??!1);this.scene.add(i),this.decorGroups.set(e.id,i),e.kind==="streetlight"&&this.addStreetlightLight(e.id,i),this.awaitArrival(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(a=>a.id),n=[],s){const{x:a,z:o}=this.bodyOrigin,c=this.scatteredSky;this.bodySystem.set(t,{originX:a,originZ:o,originGroundY:this.groundYUnder(a,o),eye:this.camera.position,groundYAt:(h,u)=>this.groundYUnder(h,u),wind:s,light:this.plumeLight(),occluders:[...this.decorGroups.values()],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),this.fitShadowToBodies();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,a=(o,c,l)=>(o*e+(c+l)/2*s)/Math.PI;return[a(t.r,i.r,n.r),a(t.g,i.g,n.g),a(t.b,i.b,n.b)]}bodyOutline(t,e){return this.bodySystem.outlineOf(t,e)}documentUrl;modelUrl(t){return t.url?this.documentRelative(t.url):void 0}documentRelative(t){if(t.startsWith("data:"))return t;const e=this.documentUrl??(typeof location>"u"?void 0:location.href);return e?new URL(t,e).href:t}async loadBodyModel(t){const e=t.url?void 0:t.id?await this.decorModelProvider.entry(t.id):void 0,i=this.modelUrl(t)??e?.url,n=t.credit??e?.credit;if(!(!i||!n))return{scene:await _m(i),credit:n,headingOffsetDeg:t.headingOffsetDeg??e?.headingOffsetDeg}}async loadDecorModel(t,e){const i=t.model;if(!(!i||!ui.usesModel(t)))try{const n=i.url?void 0:i.id?await this.decorModelProvider.entry(i.id):void 0,s=this.modelUrl(i)??n?.url,a=i.credit??n?.credit;if(!s||!a)return;const o=await _m(s);if(e!==this.decorModelToken)return;const c=this.decorGroups.get(t.id);if(!c)return;on.reflectOn(o),ui.applyModel(c,t,o,{headingOffsetDeg:i.headingOffsetDeg??n?.headingOffsetDeg,depictedSizeM:n?.sizeM}),this.decorModelCredits.set(t.id,a),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?ai(t.lat,t.lng,e.lat,e.lng):{x:0,z:0},s=this.decorObjects.find(l=>l.observerSide!==void 0&&ng(l.kind));if(this.terrainMesh&&this.terrainOrigin&&e?.lat!==void 0&&e.lng!==void 0){const l=ai(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 a={x:0,z:0};let o=0;if(s){const l=ui.occupantView(s),h=-(s.headingDeg??0)*qi,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;a.x=-(f+u),a.z=-(p+d),this.camera.position.y=this.groundYUnder(f,p)+l.eyeY,this.camera.rotation.set(this.indoorLookPitchDeg*qi,-(l.headingDeg+this.indoorLookYawDeg)*qi,0,"YXZ")}this.bodyOrigin={x:n.x+a.x,z:n.z+a.z},this.placeShadowFrustum();for(const l of this.decorObjects){const h=this.decorGroups.get(l.id);if(!h)continue;const u=Co(l,i),d=u.eastM+n.x+a.x,f=-u.northM+n.z+a.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<=nE}if(u.headingDeg!==void 0&&(h.rotation.y=-u.headingDeg*qi),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(S=>typeof S=="number"?S.toFixed(4):S).join(":");h.userData.cropGroundKey!==g&&(ui.fitCropToGround(h,(S,y)=>this.groundYUnder(S,y)+u.altitudeM),h.userData.cropGroundKey=g)}o=Math.max(o,h.position.distanceTo(this.camera.position))}const c=Math.max(qc*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):du}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 du;const a=n.getX(0),o=n.getX(s-1),c=n.getZ(0),l=n.getZ((s-1)*s),h=xr((e-a)/(o-a)*(s-1),0,s-1),u=xr((i-c)/(l-c)*(s-1),0,s-1);if(!Number.isFinite(h)||!Number.isFinite(u))return du;const d=Math.min(Math.floor(h),s-2),f=Math.min(Math.floor(u),s-2),p=h-d,v=u-f,m=(b,w)=>n.getY(b*s+w),g=m(f,d),S=m(f,d+1),y=m(f+1,d),M=m(f+1,d+1);return p+v<=1?g+(S-g)*p+(y-g)*v:M+(y-M)*(1-p)+(S-M)*(1-v)}groundUnderFootprint(t,e,i,n,s=0){return ui.groundUnderFootprint(t,e,i,n,(a,o)=>this.groundYUnder(a,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}medium;setMedium(t,e,i,n){const s=t&&e!==void 0&&e>0&&i!==void 0&&i>0?{kind:t.kind,iso:n??t.iso,autoExposure:t.autoExposure===!0,exposureSeconds:e,fNumber:i}:void 0;JSON.stringify(s)!==JSON.stringify(this.medium)&&(this.medium=s,this.render())}applyMedium(){const t=this.medium,e=Math.max(this.relativeScale,1e-30);if(!t){Hi.uMedium.value=0;return}Hi.uMedium.value=t.kind==="negative"?1:t.kind==="slide"?2:3;const i=t.autoExposure?this.scatteredSky?.sceneAdaptation:void 0;Hi.uMediumExposure.value=i!==void 0&&i>0?1/(e*i):.065*t.exposureSeconds*t.iso/(t.fNumber*t.fNumber*e)}grain;lampBloomRadiusRad(){if(!this.grain)return;const t=this.camera.fov*Math.PI/180,e=this.grain.frameHeightMm/(2*Math.tan(t/2)),i=Math.max(1,this.renderer.getDrawingBufferSize(this.bloomSize).y);return Math.max(this.grain.detailUm*.001/e,t/i)}bloomSize=new xt;updateDecorLitState(t,e=0){const i=this.lampBloomRadiusRad();for(const n of this.decorObjects){const s=this.decorGroups.get(n.id);if(s&&n.lights?.length&&ui.setLights(s,n.lights,t,s.position.distanceTo(this.camera.position),e,this.relativeScale,i),n.kind!=="streetlight"&&n.kind!=="vehicle")continue;const a=this.decorGroups.get(n.id);if(!a)continue;const o=sv(n,t);ui.setLit(a,n.kind,o,this.relativeScale);const c=this.streetlightLights.get(n.id);c&&(c.visible=o)}}addStreetlightLight(t,e){const i=ui.bodyOf(e),n=i.children.find(a=>a.userData.emissive);if(!n)return;const s=new Qg(16764006,Rm*this.relativeScale,Y5);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.startHold(),this.pumpScatteredSky(),this.lastSunPosition=t.sun,this.buildSky(t.sun),this.buildGround();const e=this.magnitudeLimitOf(t);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=a=>{const o=On.luminanceOf(a);if(!(o>0))return[0,0,0];const c=At.relativeOfResponse(o)/o;return[a[0]*c,a[1]*c,a[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,uo,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,this.magnitudeLimitOf(t)),this.applyDazzleStrength(),this.buildIceHalos(t.sun,t.moon),this.buildRainbow(t.sun,t.moon));const e=this.scatteredSky?.ambient??ke.relativeSkyOf(Ed(t.sun.altitudeDeg),this.relativeScale),i=e,n=this.lightUnderClouds(t),s=a=>n?[0,1,2].map(o=>a[o]*n.through+n.radiance[o]*(1-n.through)):[a[0],a[1],a[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),ae.setEye(this.scatteredSky?.rodShare??0,this.relativeScale),this.updateTwinkle(this.twinkleSeconds);for(const a of this.streetlightLights.values())a.intensity=Rm*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?Ft.DEFAULT_AEROSOL_OPTICAL_DEPTH:ta.opticalDepth(i))*Ft.aerosolDensity(this.siteElevationM+this.observerElevationM),s=this.cloudTransmission(t),a=-Math.log(Math.max(this.cloudTransmission(t,!0),1e-4)),o=pe.aureoleScale(n,pe.airMass(t.altitudeDeg))*s,c=pe.coronaScale(a),l=pe.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 B0,this.celestialGroup.add(this.lunarDiffraction.object));const u=pe.profile(pe.HAZE_COARSE_MODE),d=pe.profile(pe.CLOUD_DROPLETS),f=Xp(t.altitudeDeg),p=new Float32Array(pe.STEPS*3);let v=0;for(let y=0;y<pe.STEPS;y++){const M=y*3,b=[0,1,2].map(T=>l*f[T]*(o*u[M+T]+c*d[M+T])),w=On.shown(b,On.luminanceOf(b),(T,x)=>e.relativeOfLuminance(T,x));p.set(w,M),v=Math.max(v,On.response(w))}const{x:m,y:g,z:S}=hi(t.altitudeDeg,t.azimuthDeg,1);this.lunarDiffraction.show(v>1/200?{x:m,y:g,z:S}:void 0,p)}applyAir(){this.scene.fog instanceof La||(this.scene.fog=new La),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,lightPollution:this.lightPollution,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:Mt.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?K5:$5),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 c5(au),this.celestialGroup.add(this.satelliteField.object));const e=this.lastAstronomy?this.magnitudeLimitOf(this.lastAstronomy):Ad(-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(Am*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>=Kc,s=!n&&t.moon.altitudeDeg>=Kc,a=n?t.sun:t.moon,o=[0,0,0],c=Math.max(0,Math.sin(Math.max(a.altitudeDeg,0)*qi)),l=n||s?this.cloudTransmission(a):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 S=pe.illuminanceOf(a.magnitude)*i,y=this.air.transmittanceFromSpace(this.siteElevationM+this.observerElevationM,a.altitudeDeg);for(let T=0;T<3;T++)o[T]=S*y[T]*l,d[T]=S*y[T]*u*c,this.cloudBeam[T]=S*y[T];const{x:M,y:b,z:w}=hi(a.altitudeDeg,a.azimuthDeg,1);this.cloudBeamDirection.set(M,b,w)}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 S=this.skyCloudTransmission(),y=e.skyIrradiance,M=[0,1,2].map(w=>y[w]*S+d[w]);this.skyLight.color.setRGB(M[0],M[1],M[2]);const b=Wt.GROUND_ALBEDO;this.skyLight.groundColor.setRGB(b*(M[0]+o[0]*c),b*(M[1]+o[1]*c),b*(M[2]+o[2]*c))}if(this.skyLight.intensity=1,!n&&!s){this.celestialLight.intensity=0;return}const{x:p,y:v,z:m}=hi(a.altitudeDeg,a.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 R(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(),a=this.shadowWorld.set(this.bodyOrigin.x,0,this.bodyOrigin.z),o=l=>{const h=a.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,this.shadowLightDistanceM)}fitShadowToBodies(){const t=this.bodySystem.reachFrom(this.camera.position),e=Math.min(z5,Math.max(Gs,Math.ceil(t*1.25/20)*20));if(e===this.shadowHalfExtentM)return;this.shadowHalfExtentM=e;const i=this.celestialLight.shadow,n=i.camera;n.left=-e,n.right=e,n.top=e,n.bottom=-e;const s=Math.max(ho,e*(ho/Gs));this.shadowLightDistanceM=Math.max(sn,s+10),n.near=this.shadowLightDistanceM-s,n.far=this.shadowLightDistanceM+s,n.updateProjectionMatrix(),i.bias=-.03/(2*s);const a=e>2*Gs?2048:1024;i.mapSize.x!==a&&(i.mapSize.set(a,a),i.map?.dispose(),i.map=null),this.placeShadowFrustum()}shadowHalfExtentM=Gs;shadowLightDistanceM=sn;shadowUp=new R(0,1,0);shadowAxisX=new R;shadowAxisY=new R;shadowWorld=new R;skyCloudTransmission(){let t=this.cloudTransmission({altitudeDeg:90,azimuthDeg:0}),e=1;for(const i of[20,45,70]){const n=i*qi,s=Math.sin(n)*Math.cos(n)*2;for(let a=0;a<360;a+=60)t+=s*this.cloudTransmission({altitudeDeg:i,azimuthDeg:a}),e+=s}return t/e}cloudBeam=[0,0,0];cloudBeamDirection=new R(0,1,0);get relativeScale(){return this.scatteredSky?.relativeScale??1/At.semiSaturation(At.DAYLIGHT_ANCHOR_CD_M2)}setMeteorShower(t,e,i){this.meteorSystem||(this.meteorSystem=new yi,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,this.grain=t.detailUm!==void 0&&t.frame?{detailUm:t.detailUm,frameHeightMm:t.frame.heightMm}:void 0;const e=fi.starPointsOf(t),i=fi.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())}magnitudeLimitOf(t){const e=Mt.starLossMagnitudes(t.sun.altitudeDeg,{phaseAngleDeg:Mt.phaseAngleOf(t.moon.phase.illuminatedFraction),altitudeDeg:t.moon.altitudeDeg},this.lightPollution);return Ad(t.sun.altitudeDeg,this.instrumentMagnitudeGain,e)}setLightPollution(t){t!==this.lightPollution&&(this.lightPollution=t,this.lastAstronomy&&this.scatteredSky?.update(this.scatteredSkyState(this.lastAstronomy)))}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.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){if(this.skyHoldUntilMs){if(!this.sceneSettled()&&performance.now()<this.skyHoldUntilMs){this.firstFrameReady()&&this.refreshReflections(!0);return}this.skyHoldUntilMs=null,this.iceHalos?.setUrgent(!1),this.onFirstFrameHold?.(!1),this.skyColoursStale&&this.lastAstronomy&&this.applySkyColours(this.lastAstronomy)}this.frameDirty=!1,this.refreshReflections(),this.resolution.beginDrawing();try{this.renderOnce(),this.drawn++}finally{this.resolution.endDrawing()}this.developingExposure&&this.startExposure()}}}drawn=0;get framesDrawn(){return this.drawn}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()+ke.COMPILE_WAIT_MS;return new Promise(n=>{const s=()=>{if(this.contextReleased)return n();for(const a of t){const o=e.get(a)?.currentProgram;(!o||o.isReady())&&t.delete(a)}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(t=!1){this.reflections??=new on(this.renderer);const e=[...this.compassSprites,...this.lensFlare?[this.lensFlare.mesh]:[],...[...this.glareSprites.values()].map(o=>o.mesh)],i=[...this.starTiers.map(o=>o.points),...[...this.bodyMeshes.values()].filter(o=>o instanceof xs),...[this.rainSystem?.points,this.precipitationPoints,this.rainSplashSystem?.points].filter(o=>o!==void 0)],n=this.relativeScale,s=this.sceneVersion,a=this.reflections.refresh(this.renderer,this.scene,this.camera.position,this.bodySystem.reflectors,e,[...this.decorGroups.values()],s,i,o=>this.measureSurroundings(o,n,s),t?0:on.REFRESH_MS);a===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()}))},a))}measureSurroundings(t,e,i){const n=this.lastAstronomy;if(!n)return;this.probeIrradiance??=new Ro;const s=[n.sun,n.moon].filter(a=>a.altitudeDeg>-2).map(a=>hi(a.altitudeDeg,a.azimuthDeg,1));this.probeIrradiance.measure(this.renderer,t,s,a=>{const o=f=>f.map(p=>p/e),c=this.surroundings,l={up:o(a.up),down:o(a.down)},h=(f,p)=>f.some((v,m)=>Math.abs(v-p[m])>.03*Math.max(Math.abs(v),Math.abs(p[m]),1e-12)),u=!c||h(c.up,l.up)||h(c.down,l.down);u&&(this.surroundings=l),this.eyeSettledVersion=-1;const d=this.scatteredSky?.adaptToSurroundings(Math.exp(a.logAverage)/e)??!1;if(!u&&!d){this.eyeSettledVersion=i,this.skyHoldUntilMs&&this.redrawHeld();return}this.skyColoursStale=!0,this.render()})}lightUnderClouds(t){const e=this.surroundings;if(!e)return;const i=t.sun.altitudeDeg>=Kc?t.sun:t.moon.altitudeDeg>=Kc?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,gE);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 a=this.mapSubjectBounds();t?this.exposureSubjectBounds.push(...a):this.onMapSubjectBounds(a)}const e=this.usableEquidistantPass();this.phenomena.setCloudLayers(this.layeredClouds?.volumes??[]),this.phenomena.place(this.camera,(a,o,c)=>this.directionAtScreenPoint(a,o,c),a=>this.screenPointOf(a)),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()),Hi.uRodShare.value=this.scatteredSky?.rodShare??0,Hi.uRelativeScale.value=this.relativeScale,this.applyMedium();const n=this.references.any||this.phenomena.any||this.compassSprites.some(a=>a.visible);Hi.uHasOverlay.value=n?1:0;const s=n?a=>this.renderOverlayPasses(a):void 0;if(this.skyGlow?.setDestinationEncoded(!1),!e){this.updateLensFlarePosition();const a=this.usableDepthOfFieldPass();a?a.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,a=>{this.lensFlare&&(this.lensFlare.mesh.visible=a?!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(bm),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(W1),this.renderer.render(this.scene,t),t.layers.set(0),this.renderer.autoClear=e,this.renderer.shadowMap.autoUpdate=i}setReferences(t,e){this.references.set(t.map(i=>{const n=this.documentRelative(i.src);return n===i.src?i:{...i,src:n}}),void 0,e)}referenceAspect(t){return this.references.aspectOf(t)}directionAt(t,e){return this.directionAtScreenPoint(t,e,new R)}referenceFailedToLoad(t){return this.references.failedToLoad(this.documentRelative(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&&ke.markDecorDepth(s,n.kind!=="crop")}t.layers.set(nu),this.scene.overrideMaterial=this.decorDepthMaterial,this.renderer.render(this.scene,t),this.scene.overrideMaterial=null,t.layers.set(V1),this.renderer.render(this.scene,t),t.layers.set(0),this.renderer.autoClear=e,this.renderer.shadowMap.autoUpdate=i}decorDepthMaterial=new _n({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!==Ni?i.layers.enable(nu):i.layers.disable(nu)})}startExposure(){this.cancelExposure(),this.exposureSubjectBounds=[];const t=this.renderer.getDrawingBufferSize(new xt),e=Math.max(1,Math.round(t.x)),i=Math.max(1,Math.round(t.y));this.exposureAccumulation||(this.exposureAccumulation=new Tb(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()+ke.EXPOSURE_BUDGET_MS,s=ke.exposureInstantsPerFrame(e.instantTarget.scene.width*e.instantTarget.scene.height);let a=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++,a++}while(this.exposureInstantsDone<this.exposureInstants&&performance.now()<n&&a<s);this.restateAt(t,0),this.presentExposure(),this.resolution.endDrawing(),this.exposureInstantsDone<this.exposureInstants&&(this.exposureFrameId=requestAnimationFrame(()=>this.developExposure()))}presentExposure(){if(Hi.uRodShare.value=this.scatteredSky?.rodShare??0,Hi.uHasOverlay.value=1,Hi.uRelativeScale.value=this.relativeScale,this.applyMedium(),this.exposureAccumulation?.develop(this.renderer,this.exposureInstants/this.exposureInstantsDone),this.onMapSubjectBounds?.(this.exposureSubjectBounds),!this.compassSprites.some(s=>s.visible))return;const t=new Ts,e=new Un(-1,1,1,-1,0,2),i=Zc/(Im*Math.tan(Cm*qi/2));for(const s of this.compassSprites){if(!s.visible)continue;const a=s.getWorldPosition(new R).sub(this.camera.position).normalize(),o=this.screenPointOf(a);if(!o)continue;const c=new jr(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 Vi,i=new R,n=this.camera.getWorldDirection(new R),s=this.decorObjects.filter(o=>o.track?.length||o.kind==="aircraft"||o.kind==="vehicle").map(o=>this.decorGroups.get(o.id)),a=this.bodySystem.reflectors.map(o=>o.holder);for(const o of[...s,...a]){if(!o?.visible||(e.setFromObject(o),e.isEmpty())||e.distanceToPoint(this.camera.position)<ke.MAP_SUBJECT_NEAREST_M)continue;let c=1/0,l=-1/0,h=1/0,u=-1/0;for(const d of[e.min.x,e.max.x])for(const f of[e.min.y,e.max.y])for(const p of[e.min.z,e.max.z]){if(i.set(d,f,p).sub(this.camera.position).normalize(),i.dot(n)<=0)continue;const v=this.screenPointOf(i);if(!v)continue;const m=(v.ndcX+1)/2,g=(1-v.ndcY)/2;c=Math.min(c,m),l=Math.max(l,m),h=Math.min(h,g),u=Math.max(u,g)}c=Math.max(c,0),l=Math.min(l,1),h=Math.max(h,0),u=Math.min(u,1),l>=c&&u>=h&&t.push({x:c,y:h,width:l-c,height:u-h})}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 xt),i=Math.max(1,Math.round(e.x)),n=Math.max(1,Math.round(e.y));return this.depthOfFieldPass||(this.depthOfFieldPass=new Do(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 xt);return this.finishPass?this.finishPass.resize(t.x,t.y):this.finishPass=new z0(t.x,t.y),this.finishPass}usableEquidistantPass(){if(this.projectionKind!=="equidistant")return;const t=this.renderer.getDrawingBufferSize(new xt);return this.equidistantPass?this.equidistantPass.resize(t.x,t.y):this.equidistantPass=new We(t.x,t.y),this.equidistantPass}aimAtScreenPoint(t,e,i){const n=this.projectionKind==="equidistant"?this.equidistantPass:void 0;if(!n){t.setFromCamera(new xt(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 R)}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 We.ndcFor(e,this.camera.fov,n);if(e.z>=0)return;const s=Math.tan(this.camera.fov/2*qi);return{ndcX:e.x/-e.z/(n*s),ndcY:e.y/-e.z/s}}screenPointScratch=new R;screenPointQuaternion=new Qi;screenPointSize=new xt;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(Sm),this.camera.layers.set(Sm),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 a=this.sunOcclusionRaycaster.intersectObjects(i,!0)[0];return a!==void 0&&a.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,S=t.z+e.z*m-s.position.z;if(Math.hypot(g,S)<=this.groundRadius)return!0}}const a=this.terrainMesh;if(!a)return!1;const o=a.geometry.getAttribute("position"),c=Math.round(Math.sqrt(o.count));if(c<2||c*c!==o.count)return!1;const l=[a.position.x+o.getX(0),a.position.x+o.getX(c-1)],h=[a.position.z+o.getZ(0),a.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,S]of[[t.x,e.x,l],[t.z,e.z,h]]){const y=Math.min(S[0],S[1]),M=Math.max(S[0],S[1]);if(Math.abs(g)<1e-12){if(m<y||m>M)return!1;continue}const b=(y-m)/g,w=(M-m)/g;d=Math.max(d,Math.min(b,w)),f=Math.min(f,Math.max(b,w))}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,S=t.x+e.x*g,y=t.y+e.y*g,M=t.z+e.z*g;if(y<=this.groundYUnder(S,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=wm;let n,s;for(const a of this.decorObjects){if(a.kind==="crop")continue;const o=this.decorGroups.get(a.id);if(!o)continue;const c=this.ufoOcclusionRaycaster.intersectObject(o,!0)[0];c&&(a.occludesSourceIds?.includes(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(Am*this.camera.fov*Math.PI/180);let s,a=n;for(const o of this.namedStars){const c=o.direction.dot(i);c>a&&(a=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,wm)}bodyScreenBox(t){const e=this.bodySystem.boxOf(t,this.bodyBoxScratch);if(!e)return;let i=1/0,n=1/0,s=-1/0,a=-1/0;for(let o=0;o<8;o++){const c=this.bodyCornerScratch.set(o&1?e.max.x:e.min.x,o&2?e.max.y:e.min.y,o&4?e.max.z:e.min.z),l=this.screenPointOf(c.sub(this.camera.position).normalize());if(!l)return;i=Math.min(i,l.ndcX),s=Math.max(s,l.ndcX),n=Math.min(n,l.ndcY),a=Math.max(a,l.ndcY)}return{minX:i,minY:n,maxX:s,maxY:a}}bodyBoxScratch=new Vi;bodyCornerScratch=new R;pickPlacedBodyAt(t,e){return this.aimAtScreenPoint(this.raycaster,t,e),this.bodySystem.pick(this.raycaster)}pickDecorAt(t,e){this.aimAtScreenPoint(this.raycaster,t,e);const i=[...this.decorGroups.entries()],n=this.raycaster.intersectObjects(i.map(([,a])=>a),!0)[0];if(!n)return;let s=n.object;for(;s&&!i.some(([,a])=>a===s);)s=s.parent;return i.find(([,a])=>a===s)?.[0]}dispose(){this.stopTerrainFade(),this.stopTwinkle(),this.cancelFlush(),this.phenomena.clear(),this.references.disposeAll(),this.terrainBuildToken++,this.cancelScatteredSkyPump(),this.skyMesh&&this.skyGradientMaterial&&(this.skyMesh.material=this.skyGradientMaterial),this.scatteredSky?.dispose(),this.scatteredSky=void 0,this.disposeMesh(this.skyMesh),this.disposeMesh(this.groundMesh),this.disposeMesh(this.terrainMesh),this.roadSystem.dispose(),this.disposeCloudSystem(),this.disposeCirrus(),this.disposePrecipitationPoints(),this.disposeRain(),this.disposeStarTiers(),this.meteorSystem?.dispose(),this.meteorSystem=void 0,this.iceHalos?.dispose(),this.iceHalos=void 0,this.rainbow?.dispose(),this.rainbow=void 0,this.skyGlow?.dispose(),this.skyGlow=void 0,this.depthOfFieldPass?.dispose(),this.finishPass?.dispose(),this.depthOfFieldPass=void 0,this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0,this.cometTail?.dispose(),this.cometTail=void 0,this.satelliteField?.dispose(),this.satelliteField=void 0,this.lightningBolt?.dispose(),this.lightningBolt=void 0;for(const 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())ui.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());const s=!t&&this.renderer.getPixelRatio()!==this.resolution.maximum;s&&this.applyPixelRatio(this.resolution.maximum),this.syncAnimationLoop(),(!t||this.frameDirty)&&this.render(),s&&this.drawIfDirty()}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 oi(qc,32,16),i=e.attributes.position,n=e.getAttribute("color")??new de(new Float32Array(i.count*3),3);for(let a=0;a<i.count;a++){const{altitudeDeg:o,azimuthDeg:c}=Ib(i.getX(a),i.getY(a),i.getZ(a)),l=kb(o,c,t.azimuthDeg,t.altitudeDeg);n.setXYZ(a,l[0],l[1],l[2])}if(n.needsUpdate=!0,this.skyMesh)return;e.setAttribute("color",n);const s=new _n({vertexColors:!0,side:Ve,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 M0(this.groundRadius,48),i=new zr({color:new st(su,su,su),fog:!0});La.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(([a,o])=>`${a}=${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=hi(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-ge.alphaAt(i,Math.abs(this.cloudLayerOffset()),s,this.cloudFieldOffset)*W5);const a=e?0:this.weather.highCloudCover??0;return a>0&&(n*=1-ge.iceAlphaAt(i,$c,a,this.cloudFieldOffset)*X5),Math.max(0,Math.min(1,n))}setBodyMesh(t,e,i,n,s){if(e.altitudeDeg<Kd){this.disposeMesh(this.bodyMeshes.get(t)),this.bodyMeshes.delete(t),this.disposeHitArea(t),this.disposeGlare(t),t==="sun"&&(this.sunVisible=!1);return}const{x:a,y:o,z:c}=hi(e.altitudeDeg,e.azimuthDeg,sn),l=Xp(e.altitudeDeg),h=this.cloudTransmission(e),u=this.arrivingIlluminance(e,s,h),d=ke.unitLuminance(n);let f=this.bodyMeshes.get(t);if(t==="sun"){const p=Math.PI*(i/sn)**2,v=[0,1,2].map(m=>Math.min(ke.BRIGHTEST_RELATIVE,d[m]*u[m]/p));f instanceof Dt||(this.disposeMesh(f),f=new Dt(new oi(1,16,16),new _n({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 xs)){this.disposeMesh(f);const m=new ce;m.setAttribute("position",new ie(new Float32Array(3),3)),m.setAttribute("color",new ie(new Float32Array(3),3)),f=new xs(m,ae.material(To[To.length-1].size,!1)),ae.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(a,o,c),this.setHitArea(t,a,o,c,i),t==="sun"&&(this.sunArriving=u),t.startsWith("comet:")?this.disposeGlare(t):t!=="sun"&&this.setGlare(t,a,o,c,u,i/sn*(180/Math.PI),ke.POINT_VEIL_HOLD_DEG),t==="sun"){this.sunVisible=!0;const p=this.celestialGroup.scale.x;this.sunWorldPosition.set(a*p,o*p+this.celestialGroup.position.y,c*p),this.lensFlare||(this.lensFlare=o5(),this.lensFlare.uniforms.uOpacity.value=tE,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<Kd){this.disposeMesh(this.bodyMeshes.get(i)),this.bodyMeshes.delete(i),this.disposeHitArea(i),this.disposeGlare(i);return}const{x:n,y:s,z:a}=hi(t.altitudeDeg,t.azimuthDeg,sn),o=this.cloudTransmission(t),c=this.arrivingIlluminance(t,t.magnitude,o),l=Math.max(xr(t.phase.illuminatedFraction,0,1),.01)*Math.PI*(uo/sn)**2,h=new st(...c.map(f=>Math.min(ke.BRIGHTEST_RELATIVE,f/l))),u=`${t.phase.phaseFraction<.5}:${Math.round(xr(t.phase.illuminatedFraction,0,1)*500)}`;let d=this.bodyMeshes.get(i);if(d instanceof jr)d.userData.phaseKey!==u&&(d.material.map?.dispose(),d.material.map=Zm(t.phase),d.userData.phaseKey=u),d.material.color.copy(h);else{this.disposeMesh(d),d=new jr(new ol({map:Zm(t.phase),color:h,fog:!1})),d.userData.phaseKey=u;const f=uo*2;d.scale.set(f,f,1),this.celestialGroup.add(d),this.bodyMeshes.set(i,d)}d.position.set(n,s,a),this.setHitArea(i,n,s,a,uo),this.setGlare(i,n,s,a,c,uo/sn*(180/Math.PI))}bentLight(t,e,i=G5){const[n,s,a]=this.arrivingIlluminance(t,e,1),o=Math.max(s,1e-30);return{scale:s/i,tint:[n/o,1,a/o]}}static litBySky(t,e){return ke.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,ae.CONE_SOLID_ANGLE/e)}pointScratch=new xt;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=pe.illuminanceOf(e)*i*this.relativeScale;return[n[0]*s,n[1]*s,n[2]*s]}static unitLuminance(t){const e=On.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 a=this.hitAreas.get(t);if(!a){const c=new ol({transparent:!0,opacity:0,depthTest:!1,depthWrite:!1,fog:!1});a=new jr(c),this.celestialGroup.add(a),this.hitAreas.set(t,a)}a.position.set(e,i,n);const o=s*H5;a.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,a,o=0){if(Pi.radiusDeg(Pi.K*Math.max(...s))<=Math.max(a,o)){this.disposeGlare(t);return}let c=this.glareSprites.get(t);c||(c=new Pi(`veil:${t}`),this.celestialGroup.add(c.mesh),this.glareSprites.set(t,c)),c.shine({x:e,y:i,z:n},s,a,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=Mo(t.magnitude,e),s=Xh(n);this.cometKey=i,this.setBodyMesh(i,t.position,ru*(.5+.5*n),new st(s,s,s),t.magnitude),this.cometTail||(this.cometTail=new rn(sn),this.celestialGroup.add(this.cometTail.object)),this.cometTail.set(t.position,t.tailEnd,n)}buildIceHalos(t,e){this.iceHalos||(this.iceHalos=new Ci,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:$c},0);return}const s=this.lowerCloudCover(),a=me.deckLitUntilDeg(me.DECK_HEIGHT_M),o=t.altitudeDeg>-a?t:e,c=this.bentLight(o,o===t?Ne.SUN_MAGNITUDE:e.magnitude),l=me.strength(i,s,o.altitudeDeg,a)*c.scale,{x:h,y:u,z:d}=hi(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??$c},n?.iceCrystalAlignment??this.weather.iceCrystalAlignment??rv)}buildRainbow(t,e){this.rainbow||(this.rainbow=new Aa,this.celestialGroup.add(this.rainbow.object));const i=this.weather.precipitationType==="rain"?this.weather.precipitationIntensity*(this.weather.precipitationAmount??1):0,n=t.altitudeDeg>0,s=n?t:e,a=this.lowerCloudCover(),o=this.bentLight(s,n?Ne.SUN_MAGNITUDE:e.magnitude,V5),c=an.strength(i,a,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}=hi(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 Xs,this.skyGlow.onReady=()=>this.render(),this.celestialGroup.add(this.skyGlow.object));const{date:i,observer:n}=t.frame,s=Dn.galactic(i,n),a=ke.directionOf(s.centre),o=ke.directionOf(s.rotation),c=ke.directionOf(s.pole),l=new Yt().set(a.x,a.y,a.z,o.x,o.y,o.z,c.x,c.y,c.z),h=ke.directionOf(Dn.eclipticPole(i,n)),u=ke.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:ke.directionOf(t.moon),altitudeDeg:t.moon.altitudeDeg,phaseAngleDeg:Mt.phaseAngleOf(t.moon.phase.illuminatedFraction)},lightPollution:this.lightPollution,skyColor:new R(e[0],e[1],e[2])})}static directionOf(t){const{x:e,y:i,z:n}=hi(t.altitudeDeg,t.azimuthDeg,1);return new R(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 a=Mo(n.magnitude,e),o=Xh(a);this.setBodyMesh(s,n.position,ru*(.5+.5*a),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=Mo(n.magnitude,e),a=Xh(s),o=yE[n.body]??new st(1,1,1),c=new st(o.r*a,o.g*a,o.b*a),l=ru*(.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,a=new Pn(n,s),o=gu(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}=a.position(i.ra[h],i.dec[h]);if(d<Tm)continue;const{x:p,y:v,z:m}=hi(d,f,au);c.push({x:p,y:v,z:m,brightness:Mo(u,e),illuminance:this.air.transmittanceFromSpace(l,d).map(g=>g*pe.illuminanceOf(u)),phase:o()*Math.PI*2,speedFactor:.7+o()*.6})}for(const h of Bw){if(h.mag>e)continue;const{altitudeDeg:u,azimuthDeg:d}=a.position(h.raHours,h.decDeg);if(u<Tm)continue;const{x:f,y:p,z:v}=hi(u,d,au);this.namedStars.push({star:h,direction:new R(f,p,v).normalize(),altitudeDeg:u})}this.starTiers=To.map((h,u)=>{const d=c.filter(b=>f1(b.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((b,w)=>{f[w*3]=b.x,f[w*3+1]=b.y,f[w*3+2]=b.z,p[w]=b.brightness,v.set(b.illuminance,w*3),m[w]=b.phase,g[w]=b.speedFactor});const S=new ce;S.setAttribute("position",new ie(f,3)),S.setAttribute("seed",new ie(m.map(b=>b/(2*Math.PI)),1));const y=new ie(new Float32Array(d.length*3),3);S.setAttribute("color",y);let M=this.starTiers[u]?.points;return M?(M.geometry.dispose(),M.geometry=S):(M=new xs(S,ae.material(h.size)),ae.track(M),this.celestialGroup.add(M)),{points:M,colorAttribute:y,brightness:p,illuminance:v,phase:m,speedFactor:g}}),this.starColoursRelative=Number.NaN,this.updateTwinkle(this.twinkleSeconds),this.startTwinkle()}twinkleSeconds=0;starColoursRelative=Number.NaN;updateTwinkle(t){ae.setTime(t);const e=this.relativeScale;if(e!==this.starColoursRelative){this.starColoursRelative=e;for(const i of this.starTiers){const n=i.colorAttribute.array;for(let s=0;s<i.brightness.length;s++)n[s*3]=i.illuminance[s*3]*e,n[s*3+1]=i.illuminance[s*3+1]*e,n[s*3+2]=i.illuminance[s*3+2]*e;i.colorAttribute.needsUpdate=!0}}}buildClouds(){if(this.cloudRendering==="volume"||this.weather.cloudLayers!==void 0){this.layeredClouds||(this.disposeCloudSystem(),this.layeredClouds=new Ar(this.celestialGroup,ou,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(pa[0]+(hu[0]-pa[0])*e,pa[1]+(hu[1]-pa[1])*e,pa[2]+(hu[2]-pa[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}=yd(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 a=_d(ou);this.cloudMesh=new Dt(a,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}=yd(new st(...pa),t,$c,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(_d(ou*1.04),e),this.cirrusMesh.renderOrder=Om-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?Ar.deckOrder(!0,0,1):Om}cloudLayerOffset(){const e=((this.weather.cloudBaseM??Jd)-this.observerElevationM)*cu;return Math.sign(e||1)*Math.max(Math.abs(e),iE)}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,a,o]=this.cloudBeam.map(u=>u/Math.PI),c=this.lightningLevel*mu*this.relativeScale/Math.PI,l=new st(e[0]+Xn.r*c,e[1]+Xn.g*c,e[2]+Xn.b*c);this.layeredClouds?.setLighting(n.clone(),new st(s,a,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,a*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}precipitationCount(t){return hE(t,this.weather.precipitationIntensity,this.weather.precipitationAmount??1)}updatePrecipitationDensity(){const t=[[this.rainSystem?.points,fu],[this.rainSplashSystem?.points,ma],[this.precipitationPoints,this.weather.precipitationType==="none"||this.weather.precipitationType==="rain"?void 0:uu[this.weather.precipitationType].poolSize]];for(const[e,i]of t)e&&i!==void 0&&e.geometry.setDrawRange(0,this.precipitationCount(i));this.rainSystem&&(this.rainSystem.uniforms.uSpeedStreak.value=km(pu(this.weather.precipitationIntensity)))}buildPrecipitation(){this.disposePrecipitationPoints(),this.disposeRain();const t=this.weather.precipitationType;if(t==="none")return;if(t==="rain"){this.buildRain();return}const e=uu[t],i=e.poolSize,n=gu(9001),s=new Float32Array(i*3),a=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 y=0;y<i;y++){const M=n()*Math.PI*2,b=n()*e.radiusM;s[y*3]=Math.cos(M)*b,s[y*3+1]=fr+n()*(e.topYM-fr),s[y*3+2]=Math.sin(M)*b,a[y]=n()*Math.PI*2,o[y]=.7+n()*.6,c[y]=.6+n()*.8,l[y]=.4+n()*1.2}const v=new ce;v.setAttribute("position",new ie(s,3)),v.setDrawRange(0,this.precipitationCount(i));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:_E(t)},uNearFocusDistance:{value:Gm},uHazeDistance:{value:e.radiusM*Vm}},g=new le({uniforms:m,vertexShader:TE,fragmentShader:RE,transparent:!0,depthWrite:!1});this.precipitationUniforms=m;const S=new xs(v,g);S.renderOrder=lu,this.scene.add(S),this.precipitationPoints=S,this.precipitationPositions=s,this.precipitationPhase=a,this.precipitationSpeedJitter=o,this.precipitationWobbleFreqJitter=c,this.precipitationWobbleAmpJitter=l,this.precipitationBounceRemaining=h,this.precipitationBounceHeight=u,this.precipitationBounceDuration=d,this.precipitationBounceVelX=f,this.precipitationBounceVelZ=p}updatePrecipitation(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=uu[i];if(this.precipitationUniforms?.uColor.value.copy(ke.litBySky(n.color,this.baseFogColor)),e<=0)return;const s=this.weather.windDirectionDeg*qi,a=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,S=i==="snow"&&u&&d,y=i==="hail"&&f&&p&&v&&m&&g;for(let M=0,b=0;M<c.length;M+=3,b++){if(y&&f[b]>0){if(f[b]-=e,f[b]<=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[b]=0}else{const x=1-f[b]/v[b];c[M+1]=fr+Math.sin(Math.PI*x)*p[b],c[M]=Jc(c[M]+(a+m[b])*e,n.radiusM),c[M+2]=Jc(c[M+2]+(o+g[b])*e,n.radiusM)}continue}let w=0,T=0;if(S){const x=dE*u[b],A=fE*d[b];w=Math.sin(t*x*Math.PI*2+l[b])*A,T=Math.sin(t*x*Math.PI*2+l[b]+Math.PI/2)*A}if(c[M]+=(a+w)*e,c[M+1]-=n.fallSpeedMPerS*h[b]*e,c[M+2]+=(o+T)*e,c[M]=Jc(c[M],n.radiusM),c[M+2]=Jc(c[M+2],n.radiusM),c[M+1]<fr){if(y){p[b]=$m*(.2+Math.random()*1.6),v[b]=pE*(.5+Math.random()),f[b]=v[b];const C=Math.random()*Math.PI*2,I=mE*(p[b]/$m);m[b]=Math.cos(C)*I,g[b]=Math.sin(C)*I,c[M+1]=fr;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=pu(this.weather.precipitationIntensity);this.rainSystem=n5({count:fu,radiusM:fo,heightM:sE,bottomYM:Nm,overallSpeed:aE,color:Um.clone(),opacity:.85,visibleCount:this.precipitationCount(fu),speedStreak:km(t),pixelSize:Xm,seed:9001,nearFocusDistanceM:Gm,hazeDistanceM:fo*Vm,hazeColor:new st(...this.baseFogColor)}),this.rainLastVerticalFacing=-1,this.syncRainSlant(),this.rainSystem.points.renderOrder=lu,this.scene.add(this.rainSystem.points),this.buildRainSplashes()}buildRainSplashes(){const t=gu(4242),e=new Float32Array(ma*3),i=new Float32Array(ma),n=new Float32Array(ma),s=new Float32Array(ma);for(let h=0;h<ma;h++){const u=t()*Math.PI*2,d=Math.sqrt(t())*fo;e[h*3]=Math.cos(u)*d,e[h*3+1]=Nm,e[h*3+2]=Math.sin(u)*d,n[h]=Km(zm,Bm),i[h]=t()*n[h],s[h]=i[h]/n[h]}const a=new ce;a.setAttribute("position",new ie(e,3));const o=new ie(s,1);a.setAttribute("aLife",o),a.setDrawRange(0,this.precipitationCount(ma));const c=new le({uniforms:{uMaxSize:{value:lE},uScale:{value:.5*this.renderer.domElement.height},uColor:{value:Hm.clone()},uTexture:{value:wE()}},vertexShader:EE,fragmentShader:AE,transparent:!0,depthWrite:!1}),l=new xs(a,c);l.renderOrder=lu,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*qi;t.uniforms.uDropVelocity.value.set(Math.sin(e)*this.weather.windSpeed,-pu(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(ke.litBySky(Um,this.baseFogColor));const i=this.rainSplashSystem?.points.material?.uniforms?.uColor;i&&i.value.copy(ke.litBySky(Hm,this.baseFogColor));const n=this.weather.windDirectionDeg*qi,s=Math.sin(n)*this.weather.windSpeed,a=-Math.cos(n)*this.weather.windSpeed,o=fo,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+a*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=Ym+(1-Ym)*(1-l),u=qm+(1-qm)*(1-l);e.uniforms.uUvSquash.value=u,e.uniforms.uPixelSize.value=Xm*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:a}=e,o=a.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())*fo;i[c]=Math.cos(h)*u,i[c+2]=Math.sin(h)*u,s[l]=Km(zm,Bm),n[l]=0}o[l]=n[l]/s[l]}e.points.geometry.attributes.position.needsUpdate=!0,a.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=pi.brightnessAt(c,t);l>i&&(e=c,i=l)}const n=e?Math.min(1,Math.max(.1,(ME/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*mu*this.relativeScale/Math.PI;c.color.setRGB(this.airlight[0]+Xn.r*l,this.airlight[1]+Xn.g*l,this.airlight[2]+Xn.b*l)}const a=this.skyMesh?.material?.color;if(a){const c=s*xE;a.setRGB(1+c*Xn.r,1+c*Xn.g,1+c*Xn.b)}if(this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor),this.lightningLight.intensity=s*mu*this.relativeScale,e){const{x:c,y:l,z:h}=hi(25,e.azimuthDeg,sn);this.lightningLight.position.set(c,l,h)}this.lightningBolt||(this.lightningBolt=new qs(sn*.95),this.celestialGroup.add(this.lightningBolt.object));const o=this.weather.cloudBaseM??1500;this.lightningBolt.set(e,i,o),this.render()}buildCompassLabels(){this.compassSprites=q5.map(t=>{const e=Ca.point(t,this.compassPoints),i=new ol({map:DE(e),depthTest:!1,fog:!1}),n=new jr(i),{x:s,y:a,z:o}=hi(0,t,Im);return n.position.set(s,a,o),n.scale.set(Zc,Zc,1),n.renderOrder=Z5,n.layers.set(bm),n.visible=this.compassHovered||this.compassForced,this.celestialGroup.add(n),n}),this.updateCompassScale()}updateCompassScale(){const t=this.camera.fov*Math.PI/360,e=Cm*Math.PI/360,i=Zc*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 qi=Math.PI/180;function xr(r,t,e){return Math.max(t,Math.min(e,r))}function Km(r,t){return r+Math.random()*(t-r)}function Jc(r,t){return(r%(t*2)+t*3)%(t*2)-t}let jc,Qc;function _E(r){switch(r){case"snow":return SE();case"hail":return bE()}}function SE(){if(jc)return jc;const r=64,t=document.createElement("canvas");t.width=r,t.height=r;const e=t.getContext("2d"),i=e.createRadialGradient(r/2,r/2,0,r/2,r/2,r/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,r,r),jc=new Is(t),jc}function bE(){if(Qc)return Qc;const r=64,t=document.createElement("canvas");t.width=r,t.height=r;const e=t.getContext("2d"),i=e.createRadialGradient(r/2,r/2,0,r/2,r/2,r/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,r,r),Qc=new Is(t),Qc}let tl;function wE(){if(tl)return tl;const r=64,t=document.createElement("canvas");t.width=r,t.height=r;const e=t.getContext("2d"),i=e.createRadialGradient(r/2,r/2,0,r/2,r/2,r/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,r,r),tl=new Is(t),tl}const EE=`
|
|
7756
|
+
`,transparent:!0,blending:Ni,depthWrite:!1,side:Ve,fog:!1});this.object=new Dt(new oi(B0.RADIUS,128,32,0,Math.PI*2,0,pe.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<pe.STEPS;i++){for(let n=0;n<3;n++)this.texels[i*4+n]=Fn.toHalfFloat(Math.min(e[i*3+n],6e4));this.texels[i*4+3]=Fn.toHalfFloat(1)}this.texture.needsUpdate=!0,this.object.visible=!0}dispose(){this.object.geometry.dispose(),this.object.material.dispose(),this.texture.dispose()}}class Nl{constructor(t){this.generator=t}static SIZE=128;target=new Wo(Nl.SIZE,{type:qe,generateMipmaps:!1,minFilter:oe,magFilter:oe});camera=new b0(.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;let a=!1;e.traverse(c=>{const l=c;l.isLight&&l.castShadow&&l.shadow&&!l.shadow.map&&(a=!0)}),t.shadowMap.autoUpdate=a?s:!1;const o=n.map(c=>c.visible);for(const c of n)c.visible=!1;this.camera.position.copy(i),this.camera.update(t,e),n.forEach((c,l)=>{c.visible=o[l]}),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 on{static REFRESH_MS=250;generator;eye;probes=new Map;constructor(t){on.install(),this.generator=new gd(t),this.eye=new Nl(this.generator)}static decor;refresh(t,e,i,n,s,a,o,c=[],l,h=on.REFRESH_MS){for(const m of[...this.probes.keys()])n.some(g=>g.id===m&&g.shiny)||(this.probes.get(m).dispose(),this.probes.delete(m));const u=[{probe:this.eye}];for(const m of n){if(!m.shiny)continue;let g=this.probes.get(m.id);g||(g=new Nl(this.generator),this.probes.set(m.id,g)),u.push({probe:g,reflector:m})}const d=performance.now(),f=()=>u.filter(({probe:m})=>m.capturedVersion!==o),p=f().filter(({probe:m})=>d-m.capturedAtMs>=h);if(p.length>0){const m=p.reduce((g,S)=>S.probe.capturedAtMs<g.probe.capturedAtMs?S:g);if(m.reflector){const g=m.reflector.holder.getWorldPosition(this.scratch);m.probe.capture(t,e,g,[m.reflector.holder,...s]),on.reflectOn(m.reflector.holder,m.probe)}else{m.probe.capture(t,e,i,[...s,...c]),l?.(m.probe.sharp),on.decor=m.probe.filtered;for(const g of a)on.reflectOn(g,m.probe);for(const g of n)g.shiny||on.reflectOn(g.holder,m.probe)}m.probe.capturedVersion=o}const v=f();if(v.length!==0)return Math.max(16,Math.min(...v.map(({probe:m})=>h-(d-m.capturedAtMs))))}scratch=new R;static reflectOn(t,e={filtered:on.decor}){t.traverse(i=>{const n=i.material;for(const s of Array.isArray(n)?n:n?[n]:[])s instanceof Yo?e.sharp&&s.setSurroundings(e.sharp):s instanceof ya&&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(on.installed)return;on.installed=!0;const t="iblIrradiance += getIBLIrradiance( geometryNormal );";if(!Xt.lights_fragment_maps.includes(t)){console.warn("Reflections: three's lights_fragment_maps changed; the environment will light diffusely too");return}Xt.lights_fragment_maps=Xt.lights_fragment_maps.replace(t,"// The sky's diffuse light is the hemisphere light's (see Reflections).")}}function F5(r,t){return JSON.stringify(r.cloudLayers)===JSON.stringify(t.cloudLayers)&&r.cloudCover===t.cloudCover&&r.cloudDarkness===t.cloudDarkness&&r.cloudBaseM===t.cloudBaseM&&r.highCloudCover===t.highCloudCover&&r.iceCrystalAlignment===t.iceCrystalAlignment&&r.lowerCloudCover===t.lowerCloudCover&&r.relativeHumidity===t.relativeHumidity&&r.precipitationType===t.precipitationType&&r.precipitationIntensity===t.precipitationIntensity&&r.precipitationAmount===t.precipitationAmount&&r.windDirectionDeg===t.windDirectionDeg&&r.windSpeed===t.windSpeed&&r.storm===t.storm}const qc=900,nu=1,Sm=4,bm=5,wm=.5,_o=900,U5=6371e3,k5=3e4;function Em(r){const t=Math.sqrt(2*U5*Math.max(r,0));return Math.max(_o,Math.min(t,k5))}const su=.5,au=850,Am=.03,sn=850,ho=300,Gs=120,z5=700,B5=.04,uo=4,ru=1.5,Tm=-1,H5=6,Kd=-4,G5=2,V5=20,$c=2600,W5=.97,X5=.38,Kc=Kd,Rm=1500,Y5=400,q5=[0,45,90,135,180,225,270,315],$5=2,K5=16,Dm=4e3,Im=880,Zc=40,Cm=60,Z5=10,J5=1,j5=150,Q5=55,tE=.5,eE=17,Pm=.265,Lm=[[0,0],...Array.from({length:8},(r,t)=>{const e=t*Math.PI/4;return[Math.cos(e)*Pm,Math.sin(e)*Pm]})],ou=700,cu=250/Jd,iE=12,Om=5,lu=6,pa=[.92,.92,.95],hu=[.15,.15,.19],uu={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}},fr=0,du=0,nE=150,fu=3e3,fo=20,sE=15,Nm=fr,aE=40,Fm=1,rE=9;function pu(r){return Fm+(rE-Fm)*r}const Um=new st(.75,.82,.92),oE=10,cE=.5;function km(r){return xr(r/oE,cE,1)}const ma=200,zm=.18,Bm=.32,lE=.35,Hm=new st(.85,.9,.98),Gm=5,Vm=.85,Wm=.01;function hE(r,t,e=1){return Math.round(r*(Wm+(1-Wm)*t)*e)}function uE(r,t){return JSON.stringify(r.cloudLayers)===JSON.stringify(t.cloudLayers)&&r.cloudCover===t.cloudCover&&r.cloudDarkness===t.cloudDarkness&&r.cloudBaseM===t.cloudBaseM&&r.highCloudCover===t.highCloudCover&&r.iceCrystalAlignment===t.iceCrystalAlignment&&r.lowerCloudCover===t.lowerCloudCover}const Xm=230,Ym=.7,qm=.05,dE=.6,fE=.7,pE=.15,$m=.35,mE=3,gE=1/12,vE=.5,Xn=new st(.82,.86,1),ME=2500,xE=1.6,mu=15,yE={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 ke{renderer;scene=new Ts;phenomena=new In(this.scene);references=new Rn(this.scene,()=>this.render());camera;celestialGroup=new Ce;skyMesh;skyGradientMaterial;scatteredSky;lastAstronomy;skyColoursStale=!1;scatteredSkyFrameId=null;skyHoldUntilMs=void 0;onFirstFrameHold;firstFrameReady(){return(!this.scatteredSky||this.scatteredSky.ambient!==void 0)&&!this.iceHalos?.awaitingFirstDisplay}sceneSettled(){return this.firstFrameReady()&&this.arrivalsPending===0&&this.eyeSettledVersion>=this.lastArrivalVersion}arrivalsPending=0;eyeSettledVersion=-1;lastArrivalVersion=0;awaitArrival(t,e){if(this.skyHoldUntilMs===null)return t;this.arrivalsPending++;let i=!0;const n=()=>{i&&(i=!1,this.arrivalsPending--,this.lastArrivalVersion=this.sceneVersion,this.skyHoldUntilMs&&this.redrawHeld())},s=e===void 0?void 0:setTimeout(n,e);return t.finally(()=>{clearTimeout(s),n()})}static ROADS_PATIENCE_MS=1500;redrawHeld(){this.frameDirty=!0,!(this.animationFrameId!==null||this.framesDriven||this.flushFrameId!==null)&&(this.flushFrameId=requestAnimationFrame(()=>{this.flushFrameId=null,this.drawIfDirty()}))}holdForNewScene(t){this.surroundings=void 0,this.scatteredSky?.resetSurroundings(),this.startHold(),t&&this.awaitArrival(t).catch(()=>{})}startHold(){this.skyHoldUntilMs=performance.now()+Dm,this.eyeSettledVersion=-1,this.lastArrivalVersion=this.sceneVersion+1,this.iceHalos?.setUrgent(!0),this.onFirstFrameHold?.(!0),setTimeout(()=>this.render(),Dm+20)}groundMesh;terrainMesh;terrainProviders;terrainOrigin;terrainBuildToken=0;terrainAttribution;roadSystem=new gn;roadAttribution;roadWays;statedRoads=[];decorModelProvider=L5[0].create();decorModelToken=0;decorModelCredits=new Map;bodySystem=new ue(t=>this.awaitArrival(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 mp(16777215,0);celestialLightTarget=new Be;skyLight=new rx(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 cl;weather=jd;observerElevationM=0;siteElevationM=0;air=new xn;groundRadius=_o;terrainRadius=_o;cloudRendering="volume";layeredClouds;cloudLayerOffsetsM={};cloudOffsetM=new R;cloudFieldOffset=new R;cloudMesh;cirrusMesh;cirrusMaterial;cirrusUniforms;cloudMaterial;cloudUniforms;precipitationPoints;precipitationPositions;precipitationPhase;precipitationSpeedJitter;precipitationWobbleFreqJitter;precipitationWobbleAmpJitter;precipitationBounceRemaining;precipitationBounceHeight;precipitationBounceDuration;precipitationBounceVelX;precipitationBounceVelZ;precipitationUniforms;rainSystem;rainSplashSystem;rainCameraDirection=new R;rainLastVerticalFacing=-1;rainViewportSize=new xt;lightningArmed=!1;lightningFlashes=[];lightningLevel=0;lightningBolt;lightningLight=new mp(16777215,0);baseFogColor=[0,0,0];lastSunPosition;lensFlare;sunUnhiddenFraction=1;lensFlareArtifactIntensity=0;sunWorldPosition=new R;sunVisible=!1;lensFlareScratch=new R;sunOcclusionRaycaster=new cl;sunOcclusionDirectionScratch=new R;sunOcclusionRightScratch=new R;sunOcclusionUpScratch=new R;ufoOcclusionRaycaster=new cl;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;lightPollution;meteorSystem;cometTail;satelliteField;iceHalos;lunarDiffraction;lunarDiffractionKey="";rainbow;skyGlow;cometKey;novaKeys=new Set;constructor(t,e=r2()){this.renderer=new xb({canvas:t,antialias:!0}),this.resolution=new ve(Math.min(window.devicePixelRatio||1,2),this.renderer.getContext()),this.renderer.setPixelRatio(this.resolution.pixelRatio),this.renderer.shadowMap.enabled=!0,this.renderer.shadowMap.type=bo,this.camera=new Zi(60,t.width/Math.max(t.height,1),.1,qc*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=-Gs,this.celestialLight.shadow.camera.right=Gs,this.celestialLight.shadow.camera.top=Gs,this.celestialLight.shadow.camera.bottom=-Gs,this.celestialLight.shadow.camera.near=sn-ho,this.celestialLight.shadow.camera.far=sn+ho,this.celestialLight.shadow.bias=-.03/(2*ho),this.celestialLight.shadow.normalBias=B5,this.celestialLight.target=this.celestialLightTarget,this.lightningLight.color.copy(Xn),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 Ne(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*cu,0,t.z*cu);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)*qi,i=(t.pitchDeg+this.lookPitchDeg+this.gaitOffset.pitchDeg)*qi;if(t.headingDeg!==void 0?this.camera.rotation.set(i,-(t.headingDeg+this.lookYawDeg+this.gaitOffset.yawDeg)*qi,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/_o),this.camera.far=Math.max(qc*1.2,this.groundRadius*2.5),this.camera.updateProjectionMatrix())),this.terrainMesh&&this.terrainOrigin&&t.lat!==void 0&&t.lng!==void 0){const n=ai(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.stopTerrainFade(),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}=ai(t,e,this.terrainOrigin.lat,this.terrainOrigin.lng);if(Math.sqrt(c*c+l*l)<j5*(n/_o))return}const s=this.terrainOrigin,a=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;this.awaitArrival(Xw(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?ai(t,e,s.lat,s.lng):void 0;u&&d&&Math.hypot(d.x,d.z)<=a&&(c.position.y=u.position.y+this.groundYOfPatch(u,d.x,d.z)),u&&d&&Math.hypot(d.x,d.z)<=a?this.crossfadeTerrain(c,u):this.disposeMesh(this.terrainMesh),c.renderOrder=J5,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 TERRAIN_CROSSFADE_MS=1200;fadingTerrain;crossfadeTerrain(t,e){this.stopTerrainFade();const i=t.material;i.opacity=0,i.polygonOffset=!0,i.polygonOffsetFactor=-1,i.polygonOffsetUnits=-4;const n=performance.now(),s=()=>{const a=Math.min(1,(performance.now()-n)/ke.TERRAIN_CROSSFADE_MS);if(i.opacity=a*a*(3-2*a),this.render(),a<1&&this.fadingTerrain){this.fadingTerrain.frameId=requestAnimationFrame(s);return}i.polygonOffset=!1,i.opacity=1,this.fadingTerrain&&this.disposeMesh(this.fadingTerrain.mesh),this.fadingTerrain=void 0,this.render()};this.fadingTerrain={mesh:e,frameId:requestAnimationFrame(s)}}stopTerrainFade(){if(!this.fadingTerrain)return;cancelAnimationFrame(this.fadingTerrain.frameId),this.disposeMesh(this.fadingTerrain.mesh),this.fadingTerrain=void 0;const t=this.terrainMesh?.material;t&&(t.opacity=1,t.polygonOffset=!1)}static ROADS_MAX_RADIUS_M=5e3;buildRoads(t,e,i){const n=this.terrainProviders.roads;if(!n||i>ke.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}this.awaitArrival(n.getRoads(L1(t,e,i)),ke.ROADS_PATIENCE_MS).then(a=>{this.terrainOrigin?.lat!==t||this.terrainOrigin?.lng!==e||(this.roadWays={lat:t,lng:e,radiusM:i,ways:a},this.drapeRoads(a,t,e,n.contemporary))}).catch(a=>{console.warn("Roads unavailable, drawing none:",a)})}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,(a,o)=>this.groundYOfPatch(s,a,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())}setCompassPoints(t){this.compassPoints!==t&&(this.compassPoints=t,this.showCompass&&(this.disposeCompassLabels(),this.buildCompassLabels(),this.render()))}compassPoints;applyLensFlareTint(t){if(!this.lensFlare)return;const e=Q5*(this.sunArriving[1]/eE);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=Pi.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){if(F5(this.weather,t))return;this.cloudTransmissionMemo.clear();const e=this.weather;this.weather=t;const i=!uE(e,t),n=e.precipitationType!==t.precipitationType,s=e.precipitationIntensity!==t.precipitationIntensity||e.precipitationAmount!==t.precipitationAmount;(e.relativeHumidity!==t.relativeHumidity||n||s)&&(this.air=xn.of(t),this.applyAir(),this.scatteredSky?.setConditions({aerosolOpticalDepth:t.relativeHumidity===void 0?void 0:ta.steppedOpticalDepth(t.relativeHumidity)}),this.pumpScatteredSky()),i&&(this.buildClouds(),this.buildCirrus()),n?this.buildPrecipitation():s&&this.updatePrecipitationDensity(),this.lastAstronomy&&(i&&(this.buildIceHalos(this.lastAstronomy.sun,this.lastAstronomy.moon),this.buildLunarDiffraction(this.lastAstronomy.moon)),(i||n||s)&&this.buildRainbow(this.lastAstronomy.sun,this.lastAstronomy.moon)),this.lightningArmed=t.storm&&t.cloudDarkness>=vE,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(),ui.dispose(e);this.decorGroups.clear(),this.streetlightLights.clear();for(const e of t){const i=ui.build(e,e.lit??!1);this.scene.add(i),this.decorGroups.set(e.id,i),e.kind==="streetlight"&&this.addStreetlightLight(e.id,i),this.awaitArrival(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(a=>a.id),n=[],s){const{x:a,z:o}=this.bodyOrigin,c=this.scatteredSky;this.bodySystem.set(t,{originX:a,originZ:o,originGroundY:this.groundYUnder(a,o),eye:this.camera.position,groundYAt:(h,u)=>this.groundYUnder(h,u),wind:s,light:this.plumeLight(),occluders:[...this.decorGroups.values()],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),this.fitShadowToBodies();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,a=(o,c,l)=>(o*e+(c+l)/2*s)/Math.PI;return[a(t.r,i.r,n.r),a(t.g,i.g,n.g),a(t.b,i.b,n.b)]}bodyOutline(t,e){return this.bodySystem.outlineOf(t,e)}documentUrl;modelUrl(t){return t.url?this.documentRelative(t.url):void 0}documentRelative(t){if(t.startsWith("data:"))return t;const e=this.documentUrl??(typeof location>"u"?void 0:location.href);return e?new URL(t,e).href:t}async loadBodyModel(t){const e=t.url?void 0:t.id?await this.decorModelProvider.entry(t.id):void 0,i=this.modelUrl(t)??e?.url,n=t.credit??e?.credit;if(!(!i||!n))return{scene:await _m(i),credit:n,headingOffsetDeg:t.headingOffsetDeg??e?.headingOffsetDeg}}async loadDecorModel(t,e){const i=t.model;if(!(!i||!ui.usesModel(t)))try{const n=i.url?void 0:i.id?await this.decorModelProvider.entry(i.id):void 0,s=this.modelUrl(i)??n?.url,a=i.credit??n?.credit;if(!s||!a)return;const o=await _m(s);if(e!==this.decorModelToken)return;const c=this.decorGroups.get(t.id);if(!c)return;on.reflectOn(o),ui.applyModel(c,t,o,{headingOffsetDeg:i.headingOffsetDeg??n?.headingOffsetDeg,depictedSizeM:n?.sizeM}),this.decorModelCredits.set(t.id,a),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?ai(t.lat,t.lng,e.lat,e.lng):{x:0,z:0},s=this.decorObjects.find(l=>l.observerSide!==void 0&&ng(l.kind));if(this.terrainMesh&&this.terrainOrigin&&e?.lat!==void 0&&e.lng!==void 0){const l=ai(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 a={x:0,z:0};let o=0;if(s){const l=ui.occupantView(s),h=-(s.headingDeg??0)*qi,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;a.x=-(f+u),a.z=-(p+d),this.camera.position.y=this.groundYUnder(f,p)+l.eyeY,this.camera.rotation.set(this.indoorLookPitchDeg*qi,-(l.headingDeg+this.indoorLookYawDeg)*qi,0,"YXZ")}this.bodyOrigin={x:n.x+a.x,z:n.z+a.z},this.placeShadowFrustum();for(const l of this.decorObjects){const h=this.decorGroups.get(l.id);if(!h)continue;const u=Co(l,i),d=u.eastM+n.x+a.x,f=-u.northM+n.z+a.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<=nE}if(u.headingDeg!==void 0&&(h.rotation.y=-u.headingDeg*qi),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(S=>typeof S=="number"?S.toFixed(4):S).join(":");h.userData.cropGroundKey!==g&&(ui.fitCropToGround(h,(S,y)=>this.groundYUnder(S,y)+u.altitudeM),h.userData.cropGroundKey=g)}o=Math.max(o,h.position.distanceTo(this.camera.position))}const c=Math.max(qc*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):du}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 du;const a=n.getX(0),o=n.getX(s-1),c=n.getZ(0),l=n.getZ((s-1)*s),h=xr((e-a)/(o-a)*(s-1),0,s-1),u=xr((i-c)/(l-c)*(s-1),0,s-1);if(!Number.isFinite(h)||!Number.isFinite(u))return du;const d=Math.min(Math.floor(h),s-2),f=Math.min(Math.floor(u),s-2),p=h-d,v=u-f,m=(b,w)=>n.getY(b*s+w),g=m(f,d),S=m(f,d+1),y=m(f+1,d),M=m(f+1,d+1);return p+v<=1?g+(S-g)*p+(y-g)*v:M+(y-M)*(1-p)+(S-M)*(1-v)}groundUnderFootprint(t,e,i,n,s=0){return ui.groundUnderFootprint(t,e,i,n,(a,o)=>this.groundYUnder(a,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}medium;setMedium(t,e,i,n){const s=t&&e!==void 0&&e>0&&i!==void 0&&i>0?{kind:t.kind,iso:n??t.iso,autoExposure:t.autoExposure===!0,exposureSeconds:e,fNumber:i}:void 0;JSON.stringify(s)!==JSON.stringify(this.medium)&&(this.medium=s,this.render())}applyMedium(){const t=this.medium,e=Math.max(this.relativeScale,1e-30);if(!t){Hi.uMedium.value=0;return}Hi.uMedium.value=t.kind==="negative"?1:t.kind==="slide"?2:3;const i=t.autoExposure?this.scatteredSky?.sceneAdaptation:void 0;Hi.uMediumExposure.value=i!==void 0&&i>0?1/(e*i):.065*t.exposureSeconds*t.iso/(t.fNumber*t.fNumber*e)}grain;lampBloomRadiusRad(){if(!this.grain)return;const t=this.camera.fov*Math.PI/180,e=this.grain.frameHeightMm/(2*Math.tan(t/2)),i=Math.max(1,this.renderer.getDrawingBufferSize(this.bloomSize).y);return Math.max(this.grain.detailUm*.001/e,t/i)}bloomSize=new xt;updateDecorLitState(t,e=0){const i=this.lampBloomRadiusRad();for(const n of this.decorObjects){const s=this.decorGroups.get(n.id);if(s&&n.lights?.length&&ui.setLights(s,n.lights,t,s.position.distanceTo(this.camera.position),e,this.relativeScale,i),n.kind!=="streetlight"&&n.kind!=="vehicle")continue;const a=this.decorGroups.get(n.id);if(!a)continue;const o=sv(n,t);ui.setLit(a,n.kind,o,this.relativeScale);const c=this.streetlightLights.get(n.id);c&&(c.visible=o)}}addStreetlightLight(t,e){const i=ui.bodyOf(e),n=i.children.find(a=>a.userData.emissive);if(!n)return;const s=new Qg(16764006,Rm*this.relativeScale,Y5);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.startHold(),this.pumpScatteredSky(),this.lastSunPosition=t.sun,this.buildSky(t.sun),this.buildGround();const e=this.magnitudeLimitOf(t);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=a=>{const o=On.luminanceOf(a);if(!(o>0))return[0,0,0];const c=At.relativeOfResponse(o)/o;return[a[0]*c,a[1]*c,a[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,uo,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,this.magnitudeLimitOf(t)),this.applyDazzleStrength(),this.buildIceHalos(t.sun,t.moon),this.buildRainbow(t.sun,t.moon));const e=this.scatteredSky?.ambient??ke.relativeSkyOf(Ed(t.sun.altitudeDeg),this.relativeScale),i=e,n=this.lightUnderClouds(t),s=a=>n?[0,1,2].map(o=>a[o]*n.through+n.radiance[o]*(1-n.through)):[a[0],a[1],a[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),ae.setEye(this.scatteredSky?.rodShare??0,this.relativeScale),this.updateTwinkle(this.twinkleSeconds);for(const a of this.streetlightLights.values())a.intensity=Rm*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?Ft.DEFAULT_AEROSOL_OPTICAL_DEPTH:ta.opticalDepth(i))*Ft.aerosolDensity(this.siteElevationM+this.observerElevationM),s=this.cloudTransmission(t),a=-Math.log(Math.max(this.cloudTransmission(t,!0),1e-4)),o=pe.aureoleScale(n,pe.airMass(t.altitudeDeg))*s,c=pe.coronaScale(a),l=pe.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 B0,this.celestialGroup.add(this.lunarDiffraction.object));const u=pe.profile(pe.HAZE_COARSE_MODE),d=pe.profile(pe.CLOUD_DROPLETS),f=Xp(t.altitudeDeg),p=new Float32Array(pe.STEPS*3);let v=0;for(let y=0;y<pe.STEPS;y++){const M=y*3,b=[0,1,2].map(T=>l*f[T]*(o*u[M+T]+c*d[M+T])),w=On.shown(b,On.luminanceOf(b),(T,x)=>e.relativeOfLuminance(T,x));p.set(w,M),v=Math.max(v,On.response(w))}const{x:m,y:g,z:S}=hi(t.altitudeDeg,t.azimuthDeg,1);this.lunarDiffraction.show(v>1/200?{x:m,y:g,z:S}:void 0,p)}applyAir(){this.scene.fog instanceof La||(this.scene.fog=new La),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,lightPollution:this.lightPollution,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:Mt.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?K5:$5),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 c5(au),this.celestialGroup.add(this.satelliteField.object));const e=this.lastAstronomy?this.magnitudeLimitOf(this.lastAstronomy):Ad(-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(Am*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>=Kc,s=!n&&t.moon.altitudeDeg>=Kc,a=n?t.sun:t.moon,o=[0,0,0],c=Math.max(0,Math.sin(Math.max(a.altitudeDeg,0)*qi)),l=n||s?this.cloudTransmission(a):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 S=pe.illuminanceOf(a.magnitude)*i,y=this.air.transmittanceFromSpace(this.siteElevationM+this.observerElevationM,a.altitudeDeg);for(let T=0;T<3;T++)o[T]=S*y[T]*l,d[T]=S*y[T]*u*c,this.cloudBeam[T]=S*y[T];const{x:M,y:b,z:w}=hi(a.altitudeDeg,a.azimuthDeg,1);this.cloudBeamDirection.set(M,b,w)}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 S=this.skyCloudTransmission(),y=e.skyIrradiance,M=[0,1,2].map(w=>y[w]*S+d[w]);this.skyLight.color.setRGB(M[0],M[1],M[2]);const b=Wt.GROUND_ALBEDO;this.skyLight.groundColor.setRGB(b*(M[0]+o[0]*c),b*(M[1]+o[1]*c),b*(M[2]+o[2]*c))}if(this.skyLight.intensity=1,!n&&!s){this.celestialLight.intensity=0;return}const{x:p,y:v,z:m}=hi(a.altitudeDeg,a.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 R(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(),a=this.shadowWorld.set(this.bodyOrigin.x,0,this.bodyOrigin.z),o=l=>{const h=a.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,this.shadowLightDistanceM)}fitShadowToBodies(){const t=this.bodySystem.reachFrom(this.camera.position),e=Math.min(z5,Math.max(Gs,Math.ceil(t*1.25/20)*20));if(e===this.shadowHalfExtentM)return;this.shadowHalfExtentM=e;const i=this.celestialLight.shadow,n=i.camera;n.left=-e,n.right=e,n.top=e,n.bottom=-e;const s=Math.max(ho,e*(ho/Gs));this.shadowLightDistanceM=Math.max(sn,s+10),n.near=this.shadowLightDistanceM-s,n.far=this.shadowLightDistanceM+s,n.updateProjectionMatrix(),i.bias=-.03/(2*s);const a=e>2*Gs?2048:1024;i.mapSize.x!==a&&(i.mapSize.set(a,a),i.map?.dispose(),i.map=null),this.placeShadowFrustum()}shadowHalfExtentM=Gs;shadowLightDistanceM=sn;shadowUp=new R(0,1,0);shadowAxisX=new R;shadowAxisY=new R;shadowWorld=new R;skyCloudTransmission(){let t=this.cloudTransmission({altitudeDeg:90,azimuthDeg:0}),e=1;for(const i of[20,45,70]){const n=i*qi,s=Math.sin(n)*Math.cos(n)*2;for(let a=0;a<360;a+=60)t+=s*this.cloudTransmission({altitudeDeg:i,azimuthDeg:a}),e+=s}return t/e}cloudBeam=[0,0,0];cloudBeamDirection=new R(0,1,0);get relativeScale(){return this.scatteredSky?.relativeScale??1/At.semiSaturation(At.DAYLIGHT_ANCHOR_CD_M2)}setMeteorShower(t,e,i){this.meteorSystem||(this.meteorSystem=new yi,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,this.grain=t.detailUm!==void 0&&t.frame?{detailUm:t.detailUm,frameHeightMm:t.frame.heightMm}:void 0;const e=fi.starPointsOf(t),i=fi.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())}magnitudeLimitOf(t){const e=Mt.starLossMagnitudes(t.sun.altitudeDeg,{phaseAngleDeg:Mt.phaseAngleOf(t.moon.phase.illuminatedFraction),altitudeDeg:t.moon.altitudeDeg},this.lightPollution);return Ad(t.sun.altitudeDeg,this.instrumentMagnitudeGain,e)}setLightPollution(t){t!==this.lightPollution&&(this.lightPollution=t,this.lastAstronomy&&this.scatteredSky?.update(this.scatteredSkyState(this.lastAstronomy)))}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.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){if(this.skyHoldUntilMs){if(!this.sceneSettled()&&performance.now()<this.skyHoldUntilMs){this.firstFrameReady()&&this.refreshReflections(!0);return}this.skyHoldUntilMs=null,this.iceHalos?.setUrgent(!1),this.onFirstFrameHold?.(!1),this.skyColoursStale&&this.lastAstronomy&&this.applySkyColours(this.lastAstronomy)}this.frameDirty=!1,this.refreshReflections(),this.resolution.beginDrawing();try{this.renderOnce(),this.drawn++}finally{this.resolution.endDrawing()}this.developingExposure&&this.startExposure()}}}drawn=0;get framesDrawn(){return this.drawn}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()+ke.COMPILE_WAIT_MS;return new Promise(n=>{const s=()=>{if(this.contextReleased)return n();for(const a of t){const o=e.get(a)?.currentProgram;(!o||o.isReady())&&t.delete(a)}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(t=!1){this.reflections??=new on(this.renderer);const e=[...this.compassSprites,...this.lensFlare?[this.lensFlare.mesh]:[],...[...this.glareSprites.values()].map(o=>o.mesh)],i=[...this.starTiers.map(o=>o.points),...[...this.bodyMeshes.values()].filter(o=>o instanceof xs),...[this.rainSystem?.points,this.precipitationPoints,this.rainSplashSystem?.points].filter(o=>o!==void 0)],n=this.relativeScale,s=this.sceneVersion,a=this.reflections.refresh(this.renderer,this.scene,this.camera.position,this.bodySystem.reflectors,e,[...this.decorGroups.values()],s,i,o=>this.measureSurroundings(o,n,s),t?0:on.REFRESH_MS);a===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()}))},a))}measureSurroundings(t,e,i){const n=this.lastAstronomy;if(!n)return;this.probeIrradiance??=new Ro;const s=[n.sun,n.moon].filter(a=>a.altitudeDeg>-2).map(a=>hi(a.altitudeDeg,a.azimuthDeg,1));this.probeIrradiance.measure(this.renderer,t,s,a=>{const o=f=>f.map(p=>p/e),c=this.surroundings,l={up:o(a.up),down:o(a.down)},h=(f,p)=>f.some((v,m)=>Math.abs(v-p[m])>.03*Math.max(Math.abs(v),Math.abs(p[m]),1e-12)),u=!c||h(c.up,l.up)||h(c.down,l.down);u&&(this.surroundings=l),this.eyeSettledVersion=-1;const d=this.scatteredSky?.adaptToSurroundings(Math.exp(a.logAverage)/e)??!1;if(!u&&!d){this.eyeSettledVersion=i,this.skyHoldUntilMs&&this.redrawHeld();return}this.skyColoursStale=!0,this.render()})}lightUnderClouds(t){const e=this.surroundings;if(!e)return;const i=t.sun.altitudeDeg>=Kc?t.sun:t.moon.altitudeDeg>=Kc?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,gE);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 a=this.mapSubjectBounds();t?this.exposureSubjectBounds.push(...a):this.onMapSubjectBounds(a)}const e=this.usableEquidistantPass();this.phenomena.setCloudLayers(this.layeredClouds?.volumes??[]),this.phenomena.place(this.camera,(a,o,c)=>this.directionAtScreenPoint(a,o,c),a=>this.screenPointOf(a)),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()),Hi.uRodShare.value=this.scatteredSky?.rodShare??0,Hi.uRelativeScale.value=this.relativeScale,this.applyMedium();const n=this.references.any||this.phenomena.any||this.compassSprites.some(a=>a.visible);Hi.uHasOverlay.value=n?1:0;const s=n?a=>this.renderOverlayPasses(a):void 0;if(this.skyGlow?.setDestinationEncoded(!1),!e){this.updateLensFlarePosition();const a=this.usableDepthOfFieldPass();a?a.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,a=>{this.lensFlare&&(this.lensFlare.mesh.visible=a?!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(bm),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(W1),this.renderer.render(this.scene,t),t.layers.set(0),this.renderer.autoClear=e,this.renderer.shadowMap.autoUpdate=i}setReferences(t,e){this.references.set(t.map(i=>{const n=this.documentRelative(i.src);return n===i.src?i:{...i,src:n}}),void 0,e)}referenceAspect(t){return this.references.aspectOf(t)}directionAt(t,e){return this.directionAtScreenPoint(t,e,new R)}referenceFailedToLoad(t){return this.references.failedToLoad(this.documentRelative(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&&ke.markDecorDepth(s,n.kind!=="crop")}t.layers.set(nu),this.scene.overrideMaterial=this.decorDepthMaterial,this.renderer.render(this.scene,t),this.scene.overrideMaterial=null,t.layers.set(V1),this.renderer.render(this.scene,t),t.layers.set(0),this.renderer.autoClear=e,this.renderer.shadowMap.autoUpdate=i}decorDepthMaterial=new _n({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!==Ni?i.layers.enable(nu):i.layers.disable(nu)})}startExposure(){this.cancelExposure(),this.exposureSubjectBounds=[];const t=this.renderer.getDrawingBufferSize(new xt),e=Math.max(1,Math.round(t.x)),i=Math.max(1,Math.round(t.y));this.exposureAccumulation||(this.exposureAccumulation=new Tb(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()+ke.EXPOSURE_BUDGET_MS,s=ke.exposureInstantsPerFrame(e.instantTarget.scene.width*e.instantTarget.scene.height);let a=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++,a++}while(this.exposureInstantsDone<this.exposureInstants&&performance.now()<n&&a<s);this.restateAt(t,0),this.presentExposure(),this.resolution.endDrawing(),this.exposureInstantsDone<this.exposureInstants&&(this.exposureFrameId=requestAnimationFrame(()=>this.developExposure()))}presentExposure(){if(Hi.uRodShare.value=this.scatteredSky?.rodShare??0,Hi.uHasOverlay.value=1,Hi.uRelativeScale.value=this.relativeScale,this.applyMedium(),this.exposureAccumulation?.develop(this.renderer,this.exposureInstants/this.exposureInstantsDone),this.onMapSubjectBounds?.(this.exposureSubjectBounds),!this.compassSprites.some(s=>s.visible))return;const t=new Ts,e=new Un(-1,1,1,-1,0,2),i=Zc/(Im*Math.tan(Cm*qi/2));for(const s of this.compassSprites){if(!s.visible)continue;const a=s.getWorldPosition(new R).sub(this.camera.position).normalize(),o=this.screenPointOf(a);if(!o)continue;const c=new jr(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 Vi,i=new R,n=this.camera.getWorldDirection(new R),s=this.decorObjects.filter(o=>o.track?.length||o.kind==="aircraft"||o.kind==="vehicle").map(o=>this.decorGroups.get(o.id)),a=this.bodySystem.reflectors.map(o=>o.holder);for(const o of[...s,...a]){if(!o?.visible||(e.setFromObject(o),e.isEmpty())||e.distanceToPoint(this.camera.position)<ke.MAP_SUBJECT_NEAREST_M)continue;let c=1/0,l=-1/0,h=1/0,u=-1/0;for(const d of[e.min.x,e.max.x])for(const f of[e.min.y,e.max.y])for(const p of[e.min.z,e.max.z]){if(i.set(d,f,p).sub(this.camera.position).normalize(),i.dot(n)<=0)continue;const v=this.screenPointOf(i);if(!v)continue;const m=(v.ndcX+1)/2,g=(1-v.ndcY)/2;c=Math.min(c,m),l=Math.max(l,m),h=Math.min(h,g),u=Math.max(u,g)}c=Math.max(c,0),l=Math.min(l,1),h=Math.max(h,0),u=Math.min(u,1),l>=c&&u>=h&&t.push({x:c,y:h,width:l-c,height:u-h})}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 xt),i=Math.max(1,Math.round(e.x)),n=Math.max(1,Math.round(e.y));return this.depthOfFieldPass||(this.depthOfFieldPass=new Do(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 xt);return this.finishPass?this.finishPass.resize(t.x,t.y):this.finishPass=new z0(t.x,t.y),this.finishPass}usableEquidistantPass(){if(this.projectionKind!=="equidistant")return;const t=this.renderer.getDrawingBufferSize(new xt);return this.equidistantPass?this.equidistantPass.resize(t.x,t.y):this.equidistantPass=new We(t.x,t.y),this.equidistantPass}aimAtScreenPoint(t,e,i){const n=this.projectionKind==="equidistant"?this.equidistantPass:void 0;if(!n){t.setFromCamera(new xt(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 R)}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 We.ndcFor(e,this.camera.fov,n);if(e.z>=0)return;const s=Math.tan(this.camera.fov/2*qi);return{ndcX:e.x/-e.z/(n*s),ndcY:e.y/-e.z/s}}screenPointScratch=new R;screenPointQuaternion=new Qi;screenPointSize=new xt;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(Sm),this.camera.layers.set(Sm),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 a=this.sunOcclusionRaycaster.intersectObjects(i,!0)[0];return a!==void 0&&a.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,S=t.z+e.z*m-s.position.z;if(Math.hypot(g,S)<=this.groundRadius)return!0}}const a=this.terrainMesh;if(!a)return!1;const o=a.geometry.getAttribute("position"),c=Math.round(Math.sqrt(o.count));if(c<2||c*c!==o.count)return!1;const l=[a.position.x+o.getX(0),a.position.x+o.getX(c-1)],h=[a.position.z+o.getZ(0),a.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,S]of[[t.x,e.x,l],[t.z,e.z,h]]){const y=Math.min(S[0],S[1]),M=Math.max(S[0],S[1]);if(Math.abs(g)<1e-12){if(m<y||m>M)return!1;continue}const b=(y-m)/g,w=(M-m)/g;d=Math.max(d,Math.min(b,w)),f=Math.min(f,Math.max(b,w))}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,S=t.x+e.x*g,y=t.y+e.y*g,M=t.z+e.z*g;if(y<=this.groundYUnder(S,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=wm;let n,s;for(const a of this.decorObjects){if(a.kind==="crop")continue;const o=this.decorGroups.get(a.id);if(!o)continue;const c=this.ufoOcclusionRaycaster.intersectObject(o,!0)[0];c&&(a.occludesSourceIds?.includes(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(Am*this.camera.fov*Math.PI/180);let s,a=n;for(const o of this.namedStars){const c=o.direction.dot(i);c>a&&(a=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,wm)}bodyScreenBox(t){const e=this.bodySystem.boxOf(t,this.bodyBoxScratch);if(!e)return;let i=1/0,n=1/0,s=-1/0,a=-1/0;for(let o=0;o<8;o++){const c=this.bodyCornerScratch.set(o&1?e.max.x:e.min.x,o&2?e.max.y:e.min.y,o&4?e.max.z:e.min.z),l=this.screenPointOf(c.sub(this.camera.position).normalize());if(!l)return;i=Math.min(i,l.ndcX),s=Math.max(s,l.ndcX),n=Math.min(n,l.ndcY),a=Math.max(a,l.ndcY)}return{minX:i,minY:n,maxX:s,maxY:a}}bodyBoxScratch=new Vi;bodyCornerScratch=new R;pickPlacedBodyAt(t,e){return this.aimAtScreenPoint(this.raycaster,t,e),this.bodySystem.pick(this.raycaster)}pickDecorAt(t,e){this.aimAtScreenPoint(this.raycaster,t,e);const i=[...this.decorGroups.entries()],n=this.raycaster.intersectObjects(i.map(([,a])=>a),!0)[0];if(!n)return;let s=n.object;for(;s&&!i.some(([,a])=>a===s);)s=s.parent;return i.find(([,a])=>a===s)?.[0]}dispose(){this.stopTerrainFade(),this.stopTwinkle(),this.cancelFlush(),this.phenomena.clear(),this.references.disposeAll(),this.terrainBuildToken++,this.cancelScatteredSkyPump(),this.skyMesh&&this.skyGradientMaterial&&(this.skyMesh.material=this.skyGradientMaterial),this.scatteredSky?.dispose(),this.scatteredSky=void 0,this.disposeMesh(this.skyMesh),this.disposeMesh(this.groundMesh),this.disposeMesh(this.terrainMesh),this.roadSystem.dispose(),this.disposeCloudSystem(),this.disposeCirrus(),this.disposePrecipitationPoints(),this.disposeRain(),this.disposeStarTiers(),this.meteorSystem?.dispose(),this.meteorSystem=void 0,this.iceHalos?.dispose(),this.iceHalos=void 0,this.rainbow?.dispose(),this.rainbow=void 0,this.skyGlow?.dispose(),this.skyGlow=void 0,this.depthOfFieldPass?.dispose(),this.finishPass?.dispose(),this.depthOfFieldPass=void 0,this.cancelExposure(),this.exposureAccumulation?.dispose(),this.exposureAccumulation=void 0,this.cometTail?.dispose(),this.cometTail=void 0,this.satelliteField?.dispose(),this.satelliteField=void 0,this.lightningBolt?.dispose(),this.lightningBolt=void 0;for(const 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())ui.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());const s=!t&&this.renderer.getPixelRatio()!==this.resolution.maximum;s&&this.applyPixelRatio(this.resolution.maximum),this.syncAnimationLoop(),(!t||this.frameDirty)&&this.render(),s&&this.drawIfDirty()}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 oi(qc,32,16),i=e.attributes.position,n=e.getAttribute("color")??new de(new Float32Array(i.count*3),3);for(let a=0;a<i.count;a++){const{altitudeDeg:o,azimuthDeg:c}=Ib(i.getX(a),i.getY(a),i.getZ(a)),l=kb(o,c,t.azimuthDeg,t.altitudeDeg);n.setXYZ(a,l[0],l[1],l[2])}if(n.needsUpdate=!0,this.skyMesh)return;e.setAttribute("color",n);const s=new _n({vertexColors:!0,side:Ve,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 M0(this.groundRadius,48),i=new zr({color:new st(su,su,su),fog:!0});La.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(([a,o])=>`${a}=${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=hi(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-ge.alphaAt(i,Math.abs(this.cloudLayerOffset()),s,this.cloudFieldOffset)*W5);const a=e?0:this.weather.highCloudCover??0;return a>0&&(n*=1-ge.iceAlphaAt(i,$c,a,this.cloudFieldOffset)*X5),Math.max(0,Math.min(1,n))}setBodyMesh(t,e,i,n,s){if(e.altitudeDeg<Kd){this.disposeMesh(this.bodyMeshes.get(t)),this.bodyMeshes.delete(t),this.disposeHitArea(t),this.disposeGlare(t),t==="sun"&&(this.sunVisible=!1);return}const{x:a,y:o,z:c}=hi(e.altitudeDeg,e.azimuthDeg,sn),l=Xp(e.altitudeDeg),h=this.cloudTransmission(e),u=this.arrivingIlluminance(e,s,h),d=ke.unitLuminance(n);let f=this.bodyMeshes.get(t);if(t==="sun"){const p=Math.PI*(i/sn)**2,v=[0,1,2].map(m=>Math.min(ke.BRIGHTEST_RELATIVE,d[m]*u[m]/p));f instanceof Dt||(this.disposeMesh(f),f=new Dt(new oi(1,16,16),new _n({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 xs)){this.disposeMesh(f);const m=new ce;m.setAttribute("position",new ie(new Float32Array(3),3)),m.setAttribute("color",new ie(new Float32Array(3),3)),f=new xs(m,ae.material(To[To.length-1].size,!1)),ae.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(a,o,c),this.setHitArea(t,a,o,c,i),t==="sun"&&(this.sunArriving=u),t.startsWith("comet:")?this.disposeGlare(t):t!=="sun"&&this.setGlare(t,a,o,c,u,i/sn*(180/Math.PI),ke.POINT_VEIL_HOLD_DEG),t==="sun"){this.sunVisible=!0;const p=this.celestialGroup.scale.x;this.sunWorldPosition.set(a*p,o*p+this.celestialGroup.position.y,c*p),this.lensFlare||(this.lensFlare=o5(),this.lensFlare.uniforms.uOpacity.value=tE,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<Kd){this.disposeMesh(this.bodyMeshes.get(i)),this.bodyMeshes.delete(i),this.disposeHitArea(i),this.disposeGlare(i);return}const{x:n,y:s,z:a}=hi(t.altitudeDeg,t.azimuthDeg,sn),o=this.cloudTransmission(t),c=this.arrivingIlluminance(t,t.magnitude,o),l=Math.max(xr(t.phase.illuminatedFraction,0,1),.01)*Math.PI*(uo/sn)**2,h=new st(...c.map(f=>Math.min(ke.BRIGHTEST_RELATIVE,f/l))),u=`${t.phase.phaseFraction<.5}:${Math.round(xr(t.phase.illuminatedFraction,0,1)*500)}`;let d=this.bodyMeshes.get(i);if(d instanceof jr)d.userData.phaseKey!==u&&(d.material.map?.dispose(),d.material.map=Zm(t.phase),d.userData.phaseKey=u),d.material.color.copy(h);else{this.disposeMesh(d),d=new jr(new ol({map:Zm(t.phase),color:h,fog:!1})),d.userData.phaseKey=u;const f=uo*2;d.scale.set(f,f,1),this.celestialGroup.add(d),this.bodyMeshes.set(i,d)}d.position.set(n,s,a),this.setHitArea(i,n,s,a,uo),this.setGlare(i,n,s,a,c,uo/sn*(180/Math.PI))}bentLight(t,e,i=G5){const[n,s,a]=this.arrivingIlluminance(t,e,1),o=Math.max(s,1e-30);return{scale:s/i,tint:[n/o,1,a/o]}}static litBySky(t,e){return ke.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,ae.CONE_SOLID_ANGLE/e)}pointScratch=new xt;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=pe.illuminanceOf(e)*i*this.relativeScale;return[n[0]*s,n[1]*s,n[2]*s]}static unitLuminance(t){const e=On.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 a=this.hitAreas.get(t);if(!a){const c=new ol({transparent:!0,opacity:0,depthTest:!1,depthWrite:!1,fog:!1});a=new jr(c),this.celestialGroup.add(a),this.hitAreas.set(t,a)}a.position.set(e,i,n);const o=s*H5;a.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,a,o=0){if(Pi.radiusDeg(Pi.K*Math.max(...s))<=Math.max(a,o)){this.disposeGlare(t);return}let c=this.glareSprites.get(t);c||(c=new Pi(`veil:${t}`),this.celestialGroup.add(c.mesh),this.glareSprites.set(t,c)),c.shine({x:e,y:i,z:n},s,a,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=Mo(t.magnitude,e),s=Xh(n);this.cometKey=i,this.setBodyMesh(i,t.position,ru*(.5+.5*n),new st(s,s,s),t.magnitude),this.cometTail||(this.cometTail=new rn(sn),this.celestialGroup.add(this.cometTail.object)),this.cometTail.set(t.position,t.tailEnd,n)}buildIceHalos(t,e){this.iceHalos||(this.iceHalos=new Ci,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:$c},0);return}const s=this.lowerCloudCover(),a=me.deckLitUntilDeg(me.DECK_HEIGHT_M),o=t.altitudeDeg>-a?t:e,c=this.bentLight(o,o===t?Ne.SUN_MAGNITUDE:e.magnitude),l=me.strength(i,s,o.altitudeDeg,a)*c.scale,{x:h,y:u,z:d}=hi(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??$c},n?.iceCrystalAlignment??this.weather.iceCrystalAlignment??rv)}buildRainbow(t,e){this.rainbow||(this.rainbow=new Aa,this.celestialGroup.add(this.rainbow.object));const i=this.weather.precipitationType==="rain"?this.weather.precipitationIntensity*(this.weather.precipitationAmount??1):0,n=t.altitudeDeg>0,s=n?t:e,a=this.lowerCloudCover(),o=this.bentLight(s,n?Ne.SUN_MAGNITUDE:e.magnitude,V5),c=an.strength(i,a,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}=hi(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 Xs,this.skyGlow.onReady=()=>this.render(),this.celestialGroup.add(this.skyGlow.object));const{date:i,observer:n}=t.frame,s=Dn.galactic(i,n),a=ke.directionOf(s.centre),o=ke.directionOf(s.rotation),c=ke.directionOf(s.pole),l=new Yt().set(a.x,a.y,a.z,o.x,o.y,o.z,c.x,c.y,c.z),h=ke.directionOf(Dn.eclipticPole(i,n)),u=ke.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:ke.directionOf(t.moon),altitudeDeg:t.moon.altitudeDeg,phaseAngleDeg:Mt.phaseAngleOf(t.moon.phase.illuminatedFraction)},lightPollution:this.lightPollution,skyColor:new R(e[0],e[1],e[2])})}static directionOf(t){const{x:e,y:i,z:n}=hi(t.altitudeDeg,t.azimuthDeg,1);return new R(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 a=Mo(n.magnitude,e),o=Xh(a);this.setBodyMesh(s,n.position,ru*(.5+.5*a),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=Mo(n.magnitude,e),a=Xh(s),o=yE[n.body]??new st(1,1,1),c=new st(o.r*a,o.g*a,o.b*a),l=ru*(.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,a=new Pn(n,s),o=gu(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}=a.position(i.ra[h],i.dec[h]);if(d<Tm)continue;const{x:p,y:v,z:m}=hi(d,f,au);c.push({x:p,y:v,z:m,brightness:Mo(u,e),illuminance:this.air.transmittanceFromSpace(l,d).map(g=>g*pe.illuminanceOf(u)),phase:o()*Math.PI*2,speedFactor:.7+o()*.6})}for(const h of Bw){if(h.mag>e)continue;const{altitudeDeg:u,azimuthDeg:d}=a.position(h.raHours,h.decDeg);if(u<Tm)continue;const{x:f,y:p,z:v}=hi(u,d,au);this.namedStars.push({star:h,direction:new R(f,p,v).normalize(),altitudeDeg:u})}this.starTiers=To.map((h,u)=>{const d=c.filter(b=>f1(b.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((b,w)=>{f[w*3]=b.x,f[w*3+1]=b.y,f[w*3+2]=b.z,p[w]=b.brightness,v.set(b.illuminance,w*3),m[w]=b.phase,g[w]=b.speedFactor});const S=new ce;S.setAttribute("position",new ie(f,3)),S.setAttribute("seed",new ie(m.map(b=>b/(2*Math.PI)),1));const y=new ie(new Float32Array(d.length*3),3);S.setAttribute("color",y);let M=this.starTiers[u]?.points;return M?(M.geometry.dispose(),M.geometry=S):(M=new xs(S,ae.material(h.size)),ae.track(M),this.celestialGroup.add(M)),{points:M,colorAttribute:y,brightness:p,illuminance:v,phase:m,speedFactor:g}}),this.starColoursRelative=Number.NaN,this.updateTwinkle(this.twinkleSeconds),this.startTwinkle()}twinkleSeconds=0;starColoursRelative=Number.NaN;updateTwinkle(t){ae.setTime(t);const e=this.relativeScale;if(e!==this.starColoursRelative){this.starColoursRelative=e;for(const i of this.starTiers){const n=i.colorAttribute.array;for(let s=0;s<i.brightness.length;s++)n[s*3]=i.illuminance[s*3]*e,n[s*3+1]=i.illuminance[s*3+1]*e,n[s*3+2]=i.illuminance[s*3+2]*e;i.colorAttribute.needsUpdate=!0}}}buildClouds(){if(this.cloudRendering==="volume"||this.weather.cloudLayers!==void 0){this.layeredClouds||(this.disposeCloudSystem(),this.layeredClouds=new Ar(this.celestialGroup,ou,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(pa[0]+(hu[0]-pa[0])*e,pa[1]+(hu[1]-pa[1])*e,pa[2]+(hu[2]-pa[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}=yd(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 a=_d(ou);this.cloudMesh=new Dt(a,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}=yd(new st(...pa),t,$c,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(_d(ou*1.04),e),this.cirrusMesh.renderOrder=Om-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?Ar.deckOrder(!0,0,1):Om}cloudLayerOffset(){const e=((this.weather.cloudBaseM??Jd)-this.observerElevationM)*cu;return Math.sign(e||1)*Math.max(Math.abs(e),iE)}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,a,o]=this.cloudBeam.map(u=>u/Math.PI),c=this.lightningLevel*mu*this.relativeScale/Math.PI,l=new st(e[0]+Xn.r*c,e[1]+Xn.g*c,e[2]+Xn.b*c);this.layeredClouds?.setLighting(n.clone(),new st(s,a,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,a*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}precipitationCount(t){return hE(t,this.weather.precipitationIntensity,this.weather.precipitationAmount??1)}updatePrecipitationDensity(){const t=[[this.rainSystem?.points,fu],[this.rainSplashSystem?.points,ma],[this.precipitationPoints,this.weather.precipitationType==="none"||this.weather.precipitationType==="rain"?void 0:uu[this.weather.precipitationType].poolSize]];for(const[e,i]of t)e&&i!==void 0&&e.geometry.setDrawRange(0,this.precipitationCount(i));this.rainSystem&&(this.rainSystem.uniforms.uSpeedStreak.value=km(pu(this.weather.precipitationIntensity)))}buildPrecipitation(){this.disposePrecipitationPoints(),this.disposeRain();const t=this.weather.precipitationType;if(t==="none")return;if(t==="rain"){this.buildRain();return}const e=uu[t],i=e.poolSize,n=gu(9001),s=new Float32Array(i*3),a=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 y=0;y<i;y++){const M=n()*Math.PI*2,b=n()*e.radiusM;s[y*3]=Math.cos(M)*b,s[y*3+1]=fr+n()*(e.topYM-fr),s[y*3+2]=Math.sin(M)*b,a[y]=n()*Math.PI*2,o[y]=.7+n()*.6,c[y]=.6+n()*.8,l[y]=.4+n()*1.2}const v=new ce;v.setAttribute("position",new ie(s,3)),v.setDrawRange(0,this.precipitationCount(i));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:_E(t)},uNearFocusDistance:{value:Gm},uHazeDistance:{value:e.radiusM*Vm}},g=new le({uniforms:m,vertexShader:TE,fragmentShader:RE,transparent:!0,depthWrite:!1});this.precipitationUniforms=m;const S=new xs(v,g);S.renderOrder=lu,this.scene.add(S),this.precipitationPoints=S,this.precipitationPositions=s,this.precipitationPhase=a,this.precipitationSpeedJitter=o,this.precipitationWobbleFreqJitter=c,this.precipitationWobbleAmpJitter=l,this.precipitationBounceRemaining=h,this.precipitationBounceHeight=u,this.precipitationBounceDuration=d,this.precipitationBounceVelX=f,this.precipitationBounceVelZ=p}updatePrecipitation(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=uu[i];if(this.precipitationUniforms?.uColor.value.copy(ke.litBySky(n.color,this.baseFogColor)),e<=0)return;const s=this.weather.windDirectionDeg*qi,a=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,S=i==="snow"&&u&&d,y=i==="hail"&&f&&p&&v&&m&&g;for(let M=0,b=0;M<c.length;M+=3,b++){if(y&&f[b]>0){if(f[b]-=e,f[b]<=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[b]=0}else{const x=1-f[b]/v[b];c[M+1]=fr+Math.sin(Math.PI*x)*p[b],c[M]=Jc(c[M]+(a+m[b])*e,n.radiusM),c[M+2]=Jc(c[M+2]+(o+g[b])*e,n.radiusM)}continue}let w=0,T=0;if(S){const x=dE*u[b],A=fE*d[b];w=Math.sin(t*x*Math.PI*2+l[b])*A,T=Math.sin(t*x*Math.PI*2+l[b]+Math.PI/2)*A}if(c[M]+=(a+w)*e,c[M+1]-=n.fallSpeedMPerS*h[b]*e,c[M+2]+=(o+T)*e,c[M]=Jc(c[M],n.radiusM),c[M+2]=Jc(c[M+2],n.radiusM),c[M+1]<fr){if(y){p[b]=$m*(.2+Math.random()*1.6),v[b]=pE*(.5+Math.random()),f[b]=v[b];const C=Math.random()*Math.PI*2,I=mE*(p[b]/$m);m[b]=Math.cos(C)*I,g[b]=Math.sin(C)*I,c[M+1]=fr;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=pu(this.weather.precipitationIntensity);this.rainSystem=n5({count:fu,radiusM:fo,heightM:sE,bottomYM:Nm,overallSpeed:aE,color:Um.clone(),opacity:.85,visibleCount:this.precipitationCount(fu),speedStreak:km(t),pixelSize:Xm,seed:9001,nearFocusDistanceM:Gm,hazeDistanceM:fo*Vm,hazeColor:new st(...this.baseFogColor)}),this.rainLastVerticalFacing=-1,this.syncRainSlant(),this.rainSystem.points.renderOrder=lu,this.scene.add(this.rainSystem.points),this.buildRainSplashes()}buildRainSplashes(){const t=gu(4242),e=new Float32Array(ma*3),i=new Float32Array(ma),n=new Float32Array(ma),s=new Float32Array(ma);for(let h=0;h<ma;h++){const u=t()*Math.PI*2,d=Math.sqrt(t())*fo;e[h*3]=Math.cos(u)*d,e[h*3+1]=Nm,e[h*3+2]=Math.sin(u)*d,n[h]=Km(zm,Bm),i[h]=t()*n[h],s[h]=i[h]/n[h]}const a=new ce;a.setAttribute("position",new ie(e,3));const o=new ie(s,1);a.setAttribute("aLife",o),a.setDrawRange(0,this.precipitationCount(ma));const c=new le({uniforms:{uMaxSize:{value:lE},uScale:{value:.5*this.renderer.domElement.height},uColor:{value:Hm.clone()},uTexture:{value:wE()}},vertexShader:EE,fragmentShader:AE,transparent:!0,depthWrite:!1}),l=new xs(a,c);l.renderOrder=lu,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*qi;t.uniforms.uDropVelocity.value.set(Math.sin(e)*this.weather.windSpeed,-pu(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(ke.litBySky(Um,this.baseFogColor));const i=this.rainSplashSystem?.points.material?.uniforms?.uColor;i&&i.value.copy(ke.litBySky(Hm,this.baseFogColor));const n=this.weather.windDirectionDeg*qi,s=Math.sin(n)*this.weather.windSpeed,a=-Math.cos(n)*this.weather.windSpeed,o=fo,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+a*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=Ym+(1-Ym)*(1-l),u=qm+(1-qm)*(1-l);e.uniforms.uUvSquash.value=u,e.uniforms.uPixelSize.value=Xm*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:a}=e,o=a.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())*fo;i[c]=Math.cos(h)*u,i[c+2]=Math.sin(h)*u,s[l]=Km(zm,Bm),n[l]=0}o[l]=n[l]/s[l]}e.points.geometry.attributes.position.needsUpdate=!0,a.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=pi.brightnessAt(c,t);l>i&&(e=c,i=l)}const n=e?Math.min(1,Math.max(.1,(ME/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*mu*this.relativeScale/Math.PI;c.color.setRGB(this.airlight[0]+Xn.r*l,this.airlight[1]+Xn.g*l,this.airlight[2]+Xn.b*l)}const a=this.skyMesh?.material?.color;if(a){const c=s*xE;a.setRGB(1+c*Xn.r,1+c*Xn.g,1+c*Xn.b)}if(this.lastSunPosition&&this.updateCloudLighting(this.lastSunPosition,this.baseFogColor),this.lightningLight.intensity=s*mu*this.relativeScale,e){const{x:c,y:l,z:h}=hi(25,e.azimuthDeg,sn);this.lightningLight.position.set(c,l,h)}this.lightningBolt||(this.lightningBolt=new qs(sn*.95),this.celestialGroup.add(this.lightningBolt.object));const o=this.weather.cloudBaseM??1500;this.lightningBolt.set(e,i,o),this.render()}buildCompassLabels(){this.compassSprites=q5.map(t=>{const e=Ca.point(t,this.compassPoints),i=new ol({map:DE(e),depthTest:!1,fog:!1}),n=new jr(i),{x:s,y:a,z:o}=hi(0,t,Im);return n.position.set(s,a,o),n.scale.set(Zc,Zc,1),n.renderOrder=Z5,n.layers.set(bm),n.visible=this.compassHovered||this.compassForced,this.celestialGroup.add(n),n}),this.updateCompassScale()}updateCompassScale(){const t=this.camera.fov*Math.PI/360,e=Cm*Math.PI/360,i=Zc*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 qi=Math.PI/180;function xr(r,t,e){return Math.max(t,Math.min(e,r))}function Km(r,t){return r+Math.random()*(t-r)}function Jc(r,t){return(r%(t*2)+t*3)%(t*2)-t}let jc,Qc;function _E(r){switch(r){case"snow":return SE();case"hail":return bE()}}function SE(){if(jc)return jc;const r=64,t=document.createElement("canvas");t.width=r,t.height=r;const e=t.getContext("2d"),i=e.createRadialGradient(r/2,r/2,0,r/2,r/2,r/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,r,r),jc=new Is(t),jc}function bE(){if(Qc)return Qc;const r=64,t=document.createElement("canvas");t.width=r,t.height=r;const e=t.getContext("2d"),i=e.createRadialGradient(r/2,r/2,0,r/2,r/2,r/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,r,r),Qc=new Is(t),Qc}let tl;function wE(){if(tl)return tl;const r=64,t=document.createElement("canvas");t.width=r,t.height=r;const e=t.getContext("2d"),i=e.createRadialGradient(r/2,r/2,0,r/2,r/2,r/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,r,r),tl=new Is(t),tl}const EE=`
|
|
7757
7757
|
uniform float uMaxSize;
|
|
7758
7758
|
uniform float uScale;
|
|
7759
7759
|
attribute float aLife;
|