@rr0/ufoathome 0.75.1 → 0.75.2
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.
|
@@ -828,7 +828,7 @@ input[type=range] {
|
|
|
828
828
|
}
|
|
829
829
|
`,Zo=[{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 hi{static get default(){return Zo[0]}static byId(t){return Zo.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:hi.UNAIDED_FIELD_DEG}static aspectOf(t){const e=t.frame;return e?e.widthMm/e.heightMm:hi.UNAIDED_ASPECT}static frameWidthPx(t,e){return Math.round(e*hi.aspectOf(t))}static availableAt(t){return t===void 0?Zo:Zo.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??hi.LENS_FLARE_ARTIFACTS}static starPointsOf(t){const e=t.apertureBlades;return e===void 0||e<3?0:e%2===0?e:e*2}}class Mr{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 Mr(e)}static TRAVEL_M=50;get travels(){return this.spanM>Mr.TRAVEL_M}get moved(){return this.spanM>Mr.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(ii(e,t.east,e,t.west).x),Math.abs(ii(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:ys(0,-s,i,n).lat,south:ys(0,s,i,n).lat,east:ys(s,0,i,n).lng,west:ys(-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 pn{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)>pn.HAND_HELD_S,i=t.sway??(e?0:1);if(i>0)return new pn(Math.max(1-(t.instrument.stabilization??0),pn.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]=pn.HZ;return{eastM:i*pn.SWAY_M*(.7*n(s,.3)+.3*n(c,1.9)),northM:i*pn.SWAY_M*(.6*n(o,2.2)+.4*n(l,.8)),upM:i*pn.BREATH_M*n(a,0),yawDeg:i*this.rotationPassed*pn.DRIFT_YAW_DEG*(.6*n(h,1.1)+.4*n(c,2.7)),pitchDeg:i*this.rotationPassed*pn.DRIFT_PITCH_DEG*(.5*n(a,1.6)+.5*n(o,.4)),rollDeg:i*this.rotationPassed*pn.DRIFT_ROLL_DEG*n(s,2.9)}}}class xe{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=Mr.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=ii(o.lat,o.lng,a.lat,a.lng),h=l.x,u=-l.z,d=Math.hypot(h,u),f=d/c,p=xe.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 xe(i,1-(t.instrument.stabilization??0))}static bodyAt(t,e,i=!1){const n=xe.of(t)?.offsetAt(e)??xe.STILL;return i?n:xe.add(n,pn.of(t)?.offsetAt(e))}static stepHzFor(t){return t<xe.SLOWEST_WALK_M_PER_S||t>xe.FASTEST_WALK_M_PER_S?0:xe.REFERENCE_STEP_HZ*Math.pow(t/xe.REFERENCE_SPEED_M_PER_S,xe.CADENCE_EXPONENT)}offsetAt(t){return xe.add(this.cycleAt(t),this.joltAt(t))}joltAt(t){for(const e of this.stretches){if(e.stepHz===0)continue;const i=e.speedMPerS/xe.REFERENCE_SPEED_M_PER_S,n=(o,c,l,h)=>{if(o<0||o>xe.JOLT_LASTS_MS)return;const u=o/1e3,d=Math.exp(-u/xe.JOLT_DECAY_S)*Math.sin(2*Math.PI*xe.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,xe.STOP_LURCH_M,xe.STOP_PITCH_DEG,1):void 0;if(s)return s;const a=e.rampsIn?n(t-e.startMs,xe.START_LURCH_M,xe.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 xe.STILL;const i=e.stepsBefore+e.stepHz*(t-e.startMs)/1e3,n=2*Math.PI*i,s=this.amplitudeAt(e,t),a=xe.SWAY_M*s*Math.cos(n/2),o=s*this.rotationPassed*e.speedMPerS/xe.REFERENCE_SPEED_M_PER_S;return{eastM:a*e.northUnit,northM:-a*e.eastUnit,upM:xe.RISE_M_PER_M_PER_S*e.speedMPerS*s*Math.cos(n),rollDeg:xe.HEAD_ROLL_DEG*o*Math.cos(n/2),pitchDeg:-1.25*o*Math.cos(n),yawDeg:xe.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 Ee{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/Ee.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 sv(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 av(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 $i(r,t,e){return r+(t-r)*e}function Z0(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 rv(r){return`#${r.map(t=>Math.round(t).toString(16).padStart(2,"0")).join("")}`}function ov(r,t,e){const i=Z0(r),n=Z0(t);return!i||!n?e<1?r:t:rv([$i(i[0],n[0],e),$i(i[1],n[1],e),$i(i[2],n[2],e)])}function cv(r,t,e){const i={x:$i(r.bounds.x,t.bounds.x,e),y:$i(r.bounds.y,t.bounds.y,e),width:$i(r.bounds.width,t.bounds.width,e),height:$i(r.bounds.height,t.bounds.height,e)},n=$i(r.angle,t.angle,e),s=$i(r.transparency,t.transparency,e),a=$i(r.haloScale,t.haloScale,e),o=$i(r.blur??0,t.blur??0,e),c=$i(r.brightness??0,t.brightness??0,e),l=ov(r.color,t.color,e),h=Ee.lerpAngular(r.angular,t.angular,e),u=sv(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:$i(d.x,t.points[f].x,e),y:$i(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 ma{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=ma.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??ma.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:`"${ma.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:{...ma.NEUTRAL_BOUNDS},color:ma.DEFAULT_COLOR,angle:0,transparency:0,haloScale:0,selected:!1}}static NEUTRAL_BOUNDS={x:Ee.CANVAS_WIDTH_PX/2,y:Ee.CANVAS_HEIGHT_PX/2,width:1,height:1}}class Nl{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?cv(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&&av(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 Nl;for(const n of ma.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 lv(r,t,e){return Math.max(t,Math.min(e,r))}function hv(r,t,e){const i=((t-r)%360+540)%360-180;return((r+i*e)%360+360)%360}function Ba(r,t,e){return r+(t-r)*e}function uv(r,t,e){return{lat:r.lat===void 0||t.lat===void 0?void 0:Ba(r.lat,t.lat,e),lng:r.lng===void 0||t.lng===void 0?void 0:Ba(r.lng,t.lng,e),elevationM:Ba(r.elevationM,t.elevationM,e),headingDeg:r.headingDeg===void 0||t.headingDeg===void 0?void 0:hv(r.headingDeg,t.headingDeg,e),pitchDeg:Ba(r.pitchDeg,t.pitchDeg,e),rollDeg:Ba(r.rollDeg??0,t.rollDeg??0,e),fovDeg:Ba(r.fovDeg,t.fovDeg,e),fNumber:r.fNumber,focusDistanceM:r.focusDistanceM}}class Ra{static at(t,e,i,n,s){const a=t[i],c=t[i+1]-a;if(c<=0)return e[i];const l=Ra.tangent(t,e,i,s),h=Ra.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,Ra.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 Io{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=uv(i.pose,n.pose,lv((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(_=>_.t),l=(_,M)=>{const b=a.map(w=>_(w.pose));if(!b.some(w=>w===void 0))return Ra.at(c,b,o,e,M)},h=a.map(_=>_.pose.headingDeg);let u;if(h.every(_=>_!==void 0)){const _=[h[0]];for(let M=1;M<h.length;M++)_.push(_[M-1]+((h[M]-h[M-1])%360+540)%360-180);u=(Ra.at(c,_,o,e,!0)%360+360)%360}const d=this.keyframes[t],f=this.keyframes[t+1],p=(_,M)=>_.lat===M.lat&&_.lng===M.lng&&_.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 _=Ra.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)*_;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(_=>_.lat,!1)??i.lat,lng:S?S.lng:l(_=>_.lng,!1)??i.lng,elevationM:S?S.elevationM:l(_=>_.elevationM,!1)??i.elevationM,headingDeg:u??i.headingDeg,pitchDeg:l(_=>_.pitchDeg,!0)??i.pitchDeg,rollDeg:l(_=>_.rollDeg??0,!0)??i.rollDeg,fovDeg:l(_=>_.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 Io;for(const i of t.keyframes)e.addKeyframe(i.t,i.pose);return e}}class Vs{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(Vs.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?Vs.follow(this.followed[e],i.intensity,n.intensity,(n.t-i.t)/1e3,(t-i.t)/1e3):Vs.follow(this.followed[e],i.intensity,i.intensity,1,(t-i.t)/1e3);return{type:Vs.typeBetween(i,n,t,s),intensity:s,character:Vs.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=Vs.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 _=h<n?o:0;if(Math.abs(_)<=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(_)*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 Ue(r,t,e){return r+(t-r)*e}function $d(r,t,e){const i=((t-r)%360+540)%360-180;return((r+i*e)%360+360)%360}function dv(r,t,e){return Math.max(t,Math.min(e,r))}function fv(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:Ue(a.eastM,o.eastM,e),northM:Ue(a.northM,o.northM,e),baseM:Ue(a.baseM,o.baseM,e),thicknessM:Ue(a.thicknessM,o.thicknessM,e),widthM:Ue(a.widthM,o.widthM,e),depthM:Ue(a.depthM,o.depthM,e),rotationDeg:$d(a.rotationDeg,o.rotationDeg,e),density:Ue(a.density,o.density,e),darkness:Ue(a.darkness??0,o.darkness??0,e)}})}function pv(r,t,e){if(r.cloudLayers===void 0&&t.cloudLayers===void 0)return;const i=hl(r),n=hl(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:fv(o?.instances,c?.instances,e),baseM:Ue(l.baseM,h.baseM,e),thicknessM:Ue(l.thicknessM,h.thicknessM,e),coverage:Ue(l.coverage,h.coverage,e),sizeM:Ue(l.sizeM,h.sizeM,e),density:Ue(l.density,h.density,e),darkness:Ue(l.darkness??r.cloudDarkness,h.darkness??t.cloudDarkness,e),iceCrystalAlignment:l.iceCrystalAlignment===void 0||h.iceCrystalAlignment===void 0?void 0:Ue(l.iceCrystalAlignment,h.iceCrystalAlignment,e),windSpeed:l.windSpeed===void 0&&h.windSpeed===void 0?void 0:Ue(l.windSpeed??r.windSpeed,h.windSpeed??t.windSpeed,e),windDirectionDeg:l.windDirectionDeg===void 0&&h.windDirectionDeg===void 0?void 0:$d(l.windDirectionDeg??r.windDirectionDeg,h.windDirectionDeg??t.windDirectionDeg,e)}})}function mv(r,t,e){return{cloudLayers:pv(r,t,e),cloudCover:Ue(r.cloudCover,t.cloudCover,e),cloudDarkness:Ue(r.cloudDarkness,t.cloudDarkness,e),highCloudCover:r.highCloudCover===void 0||t.highCloudCover===void 0?void 0:Ue(r.highCloudCover,t.highCloudCover,e),iceCrystalAlignment:r.iceCrystalAlignment===void 0||t.iceCrystalAlignment===void 0?void 0:Ue(r.iceCrystalAlignment,t.iceCrystalAlignment,e),lowerCloudCover:r.lowerCloudCover===void 0||t.lowerCloudCover===void 0?void 0:Ue(r.lowerCloudCover,t.lowerCloudCover,e),cloudBaseM:r.cloudBaseM===void 0||t.cloudBaseM===void 0?void 0:Ue(r.cloudBaseM,t.cloudBaseM,e),relativeHumidity:r.relativeHumidity===void 0||t.relativeHumidity===void 0?void 0:Ue(r.relativeHumidity,t.relativeHumidity,e),precipitationType:e<1?r.precipitationType:t.precipitationType,precipitationIntensity:Ue(r.precipitationIntensity,t.precipitationIntensity,e),windDirectionDeg:$d(r.windDirectionDeg,t.windDirectionDeg,e),windSpeed:Ue(r.windSpeed,t.windSpeed,e),storm:e<1?r.storm:t.storm}}class Co{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?mv(i.weather,n.weather,dv((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 Vs(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 Co;for(const i of t.keyframes)e.addKeyframe(i.t,i.weather);return e}}class Po{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 Po;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 gv=100,vv={kind:"none",volume:0,pitchHz:gv};class vn{constructor(t){this.entries=t}static empty(){return new vn(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 vn(new Map);return{recording:vn.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=vn.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 vn.isWrapper(t)?(i.set(e.join("."),{basis:t.basis??"stated",...t.rationale===void 0?{}:{rationale:t.rationale},of:t.value}),vn.stripValue(t.value,e,i)):Array.isArray(t)?t.map((n,s)=>vn.stripValue(n,[...e,String(s)],i)):typeof t=="object"&&t!==null?Object.fromEntries(Object.entries(t).map(([n,s])=>[n,vn.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 yu(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 J0(r){return(((r.day??0)*24+(r.hour??0))*60+(r.minute??0))*6e4+(r.second??0)*1e3}const Mv=["year","month","day","hour","minute"],xv=["day","hour","minute"];function j0(r,t){return t.filter(e=>r[e]!==void 0).join(",")}function yv(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?Mv:xv,i=j0(r.time,e);if(!(i===""||i!==j0(r.endTime,e)))return t?yu(r.endTime)-yu(r.time):J0(r.endTime)-J0(r.time)}class Fl{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=vn.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 hi.byId(this.instrumentId)}static create(t,e,i){return new Fl({eventType:"sighting",time:t,place:e},new Nl,new Io,new Co,new Po,i)}}const _v=0,Sv=0;function li(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:_v,headingDeg:void 0,pitchDeg:Sv,fovDeg:hi.fieldOfViewDeg(r.instrument)}}function Hr(r,t){return r.weatherTrack.getInterpolatedWeatherAt(t)??r.weather??qd}function Q0(r,t){return r.weatherTrack.getActualWeatherAt(t)??r.weather??qd}function bv(r,t){return r.soundTrack.getInterpolatedSoundAt(t)??vv}class wv{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 ig=["nw","n","ne","e","se","s","sw","w"],Ev=24,Jo=8,Av=3,Tv=8;function jo(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 Gr(r){return{x:r.x+r.width/2,y:r.y+r.height/2}}const Rv={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 on{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-Ev}},o=Gr(t.bounds),c={};for(const l of Object.keys(a))c[l]=jo(a[l],o,t.angle);return c}static hitTestHandle(t,e,i=8,n=[...ig,"rotate"]){const s=on.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=((on.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=Gr(t),a=jo(n,s,-e),{x:o,y:c,width:l,height:h}=t,u=Rv[i];let d=o,f=c,p=o+l,v=c+h;return u.left&&(d=Math.min(a.x,p-Jo)),u.right&&(p=Math.max(a.x,d+Jo)),u.top&&(f=Math.min(a.y,v-Jo)),u.bottom&&(v=Math.max(a.y,f+Jo)),{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=on.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=Gr(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=Gr(t.bounds);return t.points.map(i=>jo({x:t.bounds.x+i.x,y:t.bounds.y+i.y},e,t.angle))}static hitTestVertex(t,e,i=Tv){const n=on.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=Gr(t.bounds),n=jo(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?on.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=on.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=on.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<=Av?t:{...t,points:t.points.filter((i,n)=>n!==e)}}}const _u=6,Qo=_u/2,tf=20,ef=24,nf=9,sf=6,af=7,rf=6,Hn=4;class Lo{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+nf*f),rf*f)-d:0,v=f>0?d*(1+af*f)-d:0,m=3*ef*(t.blur??0)+1.5*tf*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(${(ef*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+nf*e),rf*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<=sf;d++){const f=d/sf,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+af*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=tf*t.haloScale,this.paintBase(t),this.ctx.restore()}paintSelectionHandles(t){this.paintHandleFrame(on.handlePointsFor(t),{includeRotate:!0}),t.kind==="polygon"&&this.paintVertexHandles(t)}paintVertexHandles(t){this.ctx.fillStyle="#39f";for(const e of on.vertexPointsFor(t))this.ctx.beginPath(),this.ctx.ellipse(e.x,e.y,Hn,Hn,0,0,2*Math.PI),this.ctx.fill()}paintMemberOutline(t){this.paintOutline(on.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=Lo.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,Hn+2,Hn+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,Hn,Hn,0,0,2*Math.PI),n.fill()),n.strokeStyle=a,n.lineWidth=o,n.beginPath(),n.ellipse(s.picture.x,s.picture.y,Hn+2,Hn+2,0,0,2*Math.PI),n.stroke(),this.paintLabel(s.label,s.picture.x+Hn+5,s.picture.y-Hn-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(on.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 ig){const n=t[i];this.ctx.fillRect(n.x-Qo,n.y-Qo,_u,_u)}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,Qo+1,Qo+1,0,0,2*Math.PI),this.ctx.fill())}}const of=.05,cf=.08,lf=2,hf=3,Dv=14,Iv=.02;class Cv{context;voice;voiceToken=0;buffers=new Map;noiseBuffer;crackleBuffer;requested;resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(t){console.warn("SightingAudio: Web Audio unavailable, the sighting stays silent:",t);return}}this.context.state==="suspended"&&this.context.resume()}setSound(t){if(this.requested=t,!this.context)return;const e=this.keyFor(t);if(!e){this.silence();return}if(this.voice?.key!==e){this.stopVoice();const i=++this.voiceToken;e.startsWith("src:")?this.buildRecordedVoice(t.src,e,i):this.voice=this.buildSynthesizedVoice(t,e)}this.applyTo(this.voice,t)}silence(){this.voiceToken++,this.stopVoice()}dispose(){this.silence(),this.context?.close(),this.context=void 0,this.buffers.clear(),this.noiseBuffer=void 0,this.crackleBuffer=void 0}keyFor(t){if(!(t.volume<=0))return t.src?`src:${t.src}`:t.kind==="none"?void 0:t.kind}applyTo(t,e){const i=this.context;if(!t||!i)return;const n=i.currentTime;t.volumeParam.setTargetAtTime(Math.max(0,Math.min(1,e.volume))*t.gainScale,n,of);for(const{param:s,ratio:a}of t.pitch)s.setTargetAtTime(Math.min(e.pitchHz*a,i.sampleRate/2-1),n,of)}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(t.destination),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(t.destination),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(t.destination),i.start(),{key:e,nodes:[n,s],sources:[i],volumeParam:s.gain,gainScale:1.4,pitch:[{param:n.frequency,ratio:1}]}}buildCrackle(t,e){const i=t.createBufferSource();i.buffer=this.whiteNoise(t),i.loop=!0;const n=t.createBiquadFilter();n.type="bandpass",n.Q.value=1.2;const s=t.createGain();s.gain.value=0;const 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(t.destination),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(n.destination),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*lf),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*lf),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*hf),t.sampleRate),i=e.getChannelData(0),n=Math.max(1,Math.floor(Iv*t.sampleRate)),s=Math.round(hf*Dv);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,cf/3);const n=i+cf;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()}}}}function ul(r){return[...r].sort((t,e)=>t.t-e.t)}function uf(r,t){let e;for(const i of ul(r)){if(i.t>t)break;e=i}return e}const Ql=Math.PI/180,tc=180/Math.PI;class _s{constructor(t,e,i){this.kind=t,this.canvasHeightPx=e,this.fovDeg=i;const n=i*Ql/2;this.focalPx=t==="equidistant"?e/2/n:e/2/Math.tan(n)}focalPx;static of(t,e,i){return new _s(t.projection,e,i)}degToPx(t){const e=t*Ql;return this.kind==="equidistant"?this.focalPx*e:2*this.focalPx*Math.tan(e/2)}pxToDeg(t){return this.kind==="equidistant"?t/this.focalPx*tc:2*Math.atan(t/(2*this.focalPx))*tc}angleDegToRadiusPx(t){const e=t*Ql;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*tc:Math.atan(t/this.focalPx)*tc}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(Ee.angularWidthDeg(t))}}class Zi{static fovOf(t,e){return li(t,e)?.fovDeg??hi.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)<Zi.UNMOVED_PX&&Math.abs(s.y-e.bounds.y)<Zi.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=_s.of(t.instrument,Ee.CANVAS_HEIGHT_PX,this.fovOf(t,e));return this.aimFrom(t,n,li(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:hi.frameWidthPx(t.instrument,Ee.CANVAS_HEIGHT_PX)/2,y:Ee.CANVAS_HEIGHT_PX/2}}static shortestArc(t){return(t%360+540)%360-180}static offAxisPx(t,e){return Math.abs(e)>=Zi.OFF_CANVAS_DEG?Math.sign(e)*Zi.OFF_CANVAS_PX:t.angleDegToRadiusPx(e)}static OFF_CANVAS_DEG=89;static OFF_CANVAS_PX=1e5;static reproject(t,e,i){const n=hi.frameWidthPx(e,Ee.CANVAS_HEIGHT_PX)/2,s=hi.frameWidthPx(t.instrument,Ee.CANVAS_HEIGHT_PX)/2,a=Ee.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=_s.of(e,Ee.CANVAS_HEIGHT_PX,l),u=_s.of(t.instrument,Ee.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=li(t,n.t),a=this.fovOf(t,n.t),o=_s.of(t.instrument,Ee.CANVAS_HEIGHT_PX,a);i.addKeyframe(n.t,n.shapes.map(c=>({...c,shape:e(c.shape,o,s)})))}}}function Pv(r){return vn.restore(Lv(r),r.provenance)}function Lv(r){return Zi.toAngular(r),Zi.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 Ov(r){const{recording:t,provenance:e}=vn.strip(r),i=Nv(t);return i.provenance=e,i}function Nv(r){const t=[],e=new Fl({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},Nl.fromJSON(r.timeline,t),r.observerTrack?Io.fromJSON(r.observerTrack):new Io,r.weatherTrack?Co.fromJSON(r.weatherTrack):new Co,r.soundTrack?Po.fromJSON(r.soundTrack):new Po,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),ul(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,Zi.toBounds(e),Zi.toPosition(e),e}class Ir{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=Ir.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=>` ${Ir.text(n)}`);console.warn(`UFO@home: ${t.length} problem(s) in ${e??"this recording"}:
|
|
830
830
|
${i.join(`
|
|
831
|
-
`)}`)}}class En{constructor(t){this.format=t}issues(t){const e=[];return this.object(t,this.format,"",e),e}object(t,e,i,n){if(!En.isObject(t)){n.push({kind:"wrong-type",path:i||"(the file)",expected:"object",found:En.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(En.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):En.isObject(t)||n.push({kind:"wrong-type",path:i,expected:"object",found:En.typeOf(t)});return;case"array":Array.isArray(t)?e.fields&&t.forEach((s,a)=>{const o=En.isStated(s)?s.value:s;this.object(o,e.fields,`${i}.${a}`,n)}):n.push({kind:"wrong-type",path:i,expected:"array",found:En.typeOf(t)});return;default:typeof t!==e.type&&n.push({kind:"wrong-type",path:i,expected:e.type,found:En.typeOf(t)})}}static isObject(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}static isStated(t){return En.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 In{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?In.travelDegOver(t,e,i,i+n*1e3)/s/In.PIXELS_PER_INSTANT:0,o=In.flashesOver(t,n)*In.INSTANTS_PER_FLASH,c=Math.ceil(Math.max(a,o));return c<2?1:Math.min(In.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=In.directionAt(a,e,i),c=In.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=Ro(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 ng(r,t){for(const e of r){const i=e.toLowerCase().split("-")[0];if(t.includes(i))return i}return"en"}class dl{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 qs{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[qs.base(i)];if(n)return n}const e=new Set(this.preferences.map(i=>qs.base(i)));for(const[i,n]of Object.entries(t))if(n&&e.has(qs.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=>qs.base(o)===qs.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 sg=["en","fr","es","it"],Fv={en:()=>es(()=>Promise.resolve().then(()=>zv),void 0,import.meta.url).then(r=>r.ufoMessages_en),fr:()=>es(()=>import("./UfoMessages_fr-DDeCjNS8.js"),[],import.meta.url).then(r=>r.ufoMessages_fr),es:()=>es(()=>import("./UfoMessages_es-CzuRdJdo.js"),[],import.meta.url).then(r=>r.ufoMessages_es),it:()=>es(()=>import("./UfoMessages_it-C2dUwy6T.js"),[],import.meta.url).then(r=>r.ufoMessages_it)};function Uv(r){return Fv[r]()}function kv(r){switch(r){case"fr":return es(()=>import("./SceneNames_fr-0Wzm8zKy.js"),[],import.meta.url).then(t=>t.sceneNames_fr);case"es":return es(()=>import("./SceneNames_es-C1QdYSKO.js"),[],import.meta.url).then(t=>t.sceneNames_es);case"it":return es(()=>import("./SceneNames_it-C5oOps-9.js"),[],import.meta.url).then(t=>t.sceneNames_it);default:return Promise.resolve(void 0)}}const ag={play:"Play",pause:"Pause",noDuration:"No observation duration",currentPosition:"Current position",duration:"Duration",switchToElapsed:"click to show elapsed time",switchToClockTime:"click to show the time of day",fullscreen:"Fullscreen",exitFullscreen:"Exit fullscreen",showObserverMap:"Show where the observer was",hideObserverMap:"Hide where the observer was",mapImageryUnavailable:"Aerial imagery unavailable",zoomMapIn:"Zoom in",zoomMapOut:"Zoom out",fitMap:"Back to the whole path",placeObserverHere:"Put the observer here",showReferences:"Show the pictures of the place",hideReferences:"Hide the pictures of the place",referenceOpacity:"Picture opacity",showMilestones:"Show the account's moments",hideMilestones:"Hide the account's moments",observerHere:"The observer, here",decorHere:"Scenery",recordingIssues:"{count} problem(s) in this recording: it may not play as its author meant",issueTemplates:Ir.EN},zv=Object.freeze(Object.defineProperty({__proto__:null,ufoMessages_en:ag},Symbol.toStringTag,{value:"Module"})),rg=Math.PI/180,Bv=180/Math.PI,Hv=256,og=19,Gv=1.25;function cg(r,t){return 156543.03392*Math.cos(r*rg)/2**t}function lg(r,t){return cg(r,t)*Hv}function Vv(r,t){let e=0;for(;e<og&&lg(r,e+1)>=t;)e++;return e}function hg(r,t){return lg(r,t)}function Wv(r,t){const e=t*Gv;let i=0;for(;i<og&&cg(r,i)>e;)i++;return i}function jc(r){const t=r*rg;return(1-Math.log(Math.tan(t)+1/Math.cos(t))/Math.PI)/2}function ug(r,t,e){const i=2**e;return{x:(r+180)/360*i,y:jc(t)*i}}function dg(r,t,e){const i=jc(r.north),n=jc(r.south);return{x:(t-r.west)/(r.east-r.west),y:(jc(e)-i)/(n-i)}}function Xv(r,t,e){const{x:i,y:n}=ug(r,t,e);return{x:Math.floor(i),y:Math.floor(n),z:e}}function Yv(r){const t=2**r.z,e=r.x/t*360-180,i=(r.x+1)/t*360-180,n=df(r.y,t);return{south:df(r.y+1,t),north:n,west:e,east:i}}function df(r,t){const e=r/t;return Math.atan(Math.sinh(Math.PI*(1-2*e)))*Bv}function fg(r,t,e,i){const n=Xv(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(Yv),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 ga{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=dg(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:ga.MARKER_RADIUS_PX}),e.beginPath(),e.arc(n.x,n.y,ga.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=ii(a.lat,a.lng,e.lat,e.lng);return Math.hypot(o.x,o.z)<=ga.ON_MARKER_M});i.beginPath(),i.arc(n.x,n.y,s?ga.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(ii(a,t.east,a,t.west).x)/this.width,l=ga.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 Ve{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(Ve.MAX_ZOOM,Math.max(Ve.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=Ve.mercatorY01(e.north),s=Ve.mercatorY01(e.south),a=Ve.mercatorY01(i.north),o=Ve.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=Ve.mercatorY01(n.north),a=Ve.mercatorY01(n.south),o=(e.lng-n.west)/(n.east-n.west),c=(Ve.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=Ve.mercatorY01(t.north),n=Ve.mercatorY01(t.south),s=t.east-t.west;return{west:t.west+(this.centerX-e)*s,east:t.west+(this.centerX+e)*s,north:Ve.latitudeAt(i+(this.centerY-e)*(n-i)),south:Ve.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=Ve.mercatorY01(t.north),s=Ve.mercatorY01(t.south);return{lat:Ve.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 dn=256,ff=3,qv=32768;class $v{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(ii(i,t.east,i,t.west).x),a=Math.abs(ii(t.north,n,t.south,n).z),o=Vv(i,Math.max(s,a)),{tiles:c}=fg(n,i,o,ff),l=ff*dn,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=dn,c.height=dn;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,dn,dn),u=(t.x-e.x)*dn,d=(t.y-e.y)*dn;for(let f=0;f<dn;f++)for(let p=0;p<dn;p++){const v=(f*dn+p)*4,m=h[v]*256+h[v+1]+h[v+2]/256-qv,g=u+p,S=d+f;i[S*n+g]=m}}sampleAt(t,e,i,n,s,a){const{x:o,y:c}=ug(e,t,i),l=(o-n.x)*dn,h=(c-n.y)*dn,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],_=s[p*a+u],M=s[p*a+f],b=g+(S-g)*v,w=_+(M-_)*v;return b+(w-b)*m}}const Qc=256,Kv=5;async function Zv(r,t,e,i){const n=(r.south+r.north)/2,s=(r.west+r.east)/2,a=Math.abs(ii(n,r.east,n,r.west).x),o=Math.abs(ii(r.north,s,r.south,s).z),c=Math.max(a,o),{zoom:l,gridSize:h}=Jv(n,c,Math.max(t.width,t.height)),{tiles:u,bounds:d}=fg(s,n,l,h),f=h*Qc,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)*Qc,(M.y-m.y)*Qc)}));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 _=S.getContext("2d");if(!_)throw new Error("2D canvas context unavailable");return _.drawImage(p,0,0,f,f,0,0,g,g),{source:S,width:g,height:g,bounds:d}}function Jv(r,t,e){let i=Wv(r,t/Math.max(1,e)),n=pf(r,i,t);for(;n>Kv&&i>0;)i--,n=pf(r,i,t);return{zoom:i,gridSize:n,mPerPixel:hg(r,i)/Qc}}function pf(r,t,e){const i=Math.ceil(e/2/hg(r,t));return Math.max(3,2*i+1)}class jv{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 Zv(t,e,i=>this.tileUrlTemplate.replace("{z}",String(i.z)).replace("{y}",String(i.y)).replace("{x}",String(i.x)),this.fetchImpl)}}class An{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??An.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"~"^(${An.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:An.surfaceOf(s),widthM:An.widthOf(s),points:n.map(a=>({lat:a.lat,lng:a.lon}))})}return e}queued(t){const e=An.queue.then(t,t);return An.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,An.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:An.WIDTH_M[t.highway]??An.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 th="https://ufoathome.org/roads/index.json";class Kd{attributionRead;contemporaryRead;fetchImpl;indexUrls;fallback;index;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??Kd.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.75.1")}`,e=typeof location>"u"?void 0:new URL("/roads/index.json",location.href).href;return(e&&e!==th?[e,th]:[th]).map(i=>i+t)}}function Qv(){return{elevation:new $v,imagery:pg(),roads:t2()}}function pg(){return new jv}function t2(){return new Kd({fallback:new An})}const e2=new Set,xr="show-observer-map",yr="hide-milestones";class ui extends HTMLElement{static get observedAttributes(){return["src",xr,yr]}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;observerMapButton;referencesButton;referenceOpacityInput;referencesShownState=!0;referenceOpacityTouched=!1;milestonesButton;observerMapPanel;observerMapCanvas;observerMapRenderer;mapZoomInButton;mapZoomOutButton;mapFitButton;observerMapView=new Ve;observerMapDrag;suppressObserverMapClick=!1;observerMapImageryTimer;observerPlacing=!1;seekInput;playbackFlash;milestoneMarks;milestoneCaption;timeStartLabel;timeEndLabel;observerPath;observerMapBounds;observerMapImagery;observerMapImageryBounds;observerMapImageryViewWidth=0;observerMapImageryLoading=!1;observerMapImageryCredit;observerMapImageryFailed=!1;creditShownExternally=!1;lookYawDeg=0;lookPitchDeg=0;milestonesShown=!0;currentSighting=Fl.create();issues=[];issueCheck=0;sightingAudio=new Cv;soundPreview;player;loopEnabled=!1;playbackBeforeClick;highlightedSourceIds=new Set;paintsShapes=!0;steadyObserver=!1;selectionShown=!0;overlayPainter;enableClickToPlay=!0;fullscreenTarget;messages=ag;realDurationMs;realStartMs;showClockTime=!0;handleFullscreenChange=()=>{this.updateFullscreenButton(),this.resizeObserverMap()};observerMapResizeObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>this.resizeObserverMap());resizeObserverMap(){this.observerMapPanel.hidden||(this.sizeObserverMapCanvas(),this.paintObserverMap(this.currentTime))}simulatedFullscreen=!1;styleBeforeSimulatedFullscreen;bodyOverflowBeforeSimulatedFullscreen;handleSimulatedFullscreenKey=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)<ui.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>=Ve.MAX_ZOOM,this.mapZoomOutButton.disabled=this.observerMapView.zoomFactor<=Ve.MIN_ZOOM,this.paintObserverMap(this.currentTime),this.scheduleObserverMapImagery()}scheduleObserverMapImagery(){this.observerMapImageryTimer===void 0&&(this.observerMapImageryTimer=setTimeout(()=>{this.observerMapImageryTimer=void 0,this.loadObserverMapImagery()},ui.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=Ve.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>${nv}</style>${iv}`,this.shadow.appendChild(t.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.canvas=this.shadow.getElementById("canvas"),this.canvasRenderer=new Lo(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.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 ga(this.observerMapCanvas.getContext("2d")),this.mapZoomInButton=this.shadow.getElementById("map-zoom-in"),this.mapZoomOutButton=this.shadow.getElementById("map-zoom-out"),this.mapFitButton=this.shadow.getElementById("map-fit"),this.seekInput=this.shadow.getElementById("seek"),this.playbackFlash=this.shadow.getElementById("playback-flash"),this.milestoneMarks=this.shadow.getElementById("milestone-marks"),this.milestoneCaption=this.shadow.getElementById("milestone-caption"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end");for(const e of[this.timeStartLabel,this.timeEndLabel])e.addEventListener("click",()=>this.toggleTimeDisplay()),e.addEventListener("keydown",i=>{i.key!=="Enter"&&i.key!==" "||(i.preventDefault(),this.toggleTimeDisplay())});this.fullscreenTarget=this.stageElement,this.playPauseButton.addEventListener("click",()=>this.togglePlayPause()),this.fullscreenButton.addEventListener("click",()=>this.toggleFullscreen()),this.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.seekSnapArmed=!0,this.nameMarkUnder(e)}),this.seekInput.addEventListener("pointerup",()=>{this.seekSnapArmed=!1}),this.seekInput.addEventListener("pointermove",e=>this.nameMarkUnder(e)),this.seekInput.addEventListener("pointerleave",()=>this.seekInput.removeAttribute("title")),this.seekInput.addEventListener("keydown",this.handleSeekKey),this.canvas.addEventListener("click",e=>{this.enableClickToPlay&&(e.detail<=1&&(this.playbackBeforeClick={state:this.playbackState,time:this.currentTime}),this.togglePlayPause())}),this.canvas.addEventListener("dblclick",e=>{this.enableClickToPlay&&(e.preventDefault(),this.restorePlayback(),this.toggleFullscreen())}),this.canvas.addEventListener("pointermove",this.handlePointerMove),this.canvas.addEventListener("pointerleave",this.handlePointerLeave),document.addEventListener("fullscreenchange",this.handleFullscreenChange),this.observerMapResizeObserver?.observe(this.observerMapPanel),this.hostControls(void 0),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateMilestonesButton(),this.refresh()}connectedCallback(){this.saidTexts=void 0,this.loadLocaleMessages();const t=this.getAttribute("src");t&&this.loadFromSrc(t)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.handleFullscreenChange),this.observerMapResizeObserver?.disconnect(),this.exitSimulatedFullscreen(),this.sightingAudio.dispose()}attributeChangedCallback(t,e,i){t==="src"&&i&&i!==e&&this.isConnected&&this.loadFromSrc(i),t===xr&&this.applyObserverMapDefault(),t===yr&&this.setMilestonesShown(!this.hasAttribute(yr))}async loadFromSrc(t){this.sightingData=await eg.json(t)}get sightingData(){return Pv(this.currentSighting)}set sightingData(t){this.player.stop(),this.soundPreview=void 0,this.sightingAudio.silence(),this.currentSighting=Ov(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 es(async()=>{const{default:a}=await import("./sightingSchema-DOOSOVWK.js");return{default:a}},[],import.meta.url);n=new En(s).issues(t)}catch{}i===this.issueCheck&&(this.issues=[...n,...e.loadIssues],Ir.warn(this.issues,e.id),this.renderIssues(),this.dispatchEvent(new CustomEvent(i2,{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=Ir.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)}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.referenceOpacityInput,this.referencesButton,this.observerMapButton];if(t)for(const i of e)t.appendChild(i);else for(const i of e)this.toolbar.appendChild(i)}get referencesShown(){return this.referencesShownState}get referenceOpacity(){return Number(this.referenceOpacityInput.value)}toggleReferences(){this.referencesShownState=!this.referencesShownState,this.updateReferencesButton(),this.dispatchReferenceView()}updateReferences(){const t=this.currentSighting.references;!this.referenceOpacityTouched&&t.length>0&&(this.referenceOpacityInput.value=String(t[0].opacity)),this.updateReferencesButton()}updateReferencesButton(){const t=this.currentSighting.references.length>0;this.referencesButton.hidden=!t,this.referenceOpacityInput.hidden=!t||!this.referencesShownState,this.referencesButton.setAttribute("aria-pressed",String(this.referencesShownState));const e=this.referencesShownState?this.messages.hideReferences:this.messages.showReferences;this.referencesButton.title=e,this.referencesButton.setAttribute("aria-label",e),this.referenceOpacityInput.title=this.messages.referenceOpacity,this.referenceOpacityInput.setAttribute("aria-label",this.messages.referenceOpacity)}dispatchReferenceView(){this.dispatchEvent(new CustomEvent("referenceview",{detail:{shown:this.referencesShown,opacity:this.referenceOpacity}}))}refreshMilestoneMarks(){const t=this.player.seekableDuration,e=t>0?ul(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}))}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=ui.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?uf(this.sighting.milestones,t):void 0;if(this.milestoneCaption.hidden=e===void 0,!e)return;const i=document.createElement("b");i.textContent=this.said.read(e.label)??"";const n=this.said.read(e.note),s=n?` — ${n}`:"";this.milestoneCaption.replaceChildren(i,document.createTextNode(s))}exposureInstants(t){const e=this.exposureTimes(t),i=1/e.length;return e.map(n=>({shapes:this.shapesAt(n),share:i}))}exposureTimes(t=this.currentTime){const e=In.windowEndingAt(t,this.currentSighting.exposure??0);if(e.ms<ui.SHORTEST_VISIBLE_EXPOSURE_MS)return[t];const i=Math.min(ui.MAX_EXPOSURE_STEPS,Math.max(2,Math.round(e.ms/ui.SHORTEST_VISIBLE_EXPOSURE_MS))),n=Math.ceil(this.travelPxOver(e.fromMs,e.ms)/ui.EXPOSURE_STEP_PX),s=Math.min(ui.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=hi.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:e2;this.canvasRenderer.setStarPoints(hi.starPointsOf(this.sighting.instrument));const n=(li(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=on.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.timeStartLabel.textContent=this.formatPosition(t),this.showMilestoneAt(t),this.paintObserverMap(t),this.playbackState==="playing"?(this.soundPreview=void 0,this.sightingAudio.setSound(bv(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 wv(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;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*ui.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.textContent=this.player.playbackState==="playing"?"▶":"⏸",t.classList.remove("flashing"),t.offsetWidth,t.classList.add("flashing")}updatePlayPauseButton(){const t=this.player.playbackState==="playing";this.playPauseButton.textContent=t?"⏸":"▶";const e=this.player.seekableDuration>0;this.playPauseButton.disabled=!e;const i=e?t?this.messages.pause:this.messages.play:this.messages.noDuration;this.playPauseButton.title=i,this.playPauseButton.setAttribute("aria-label",i)}toggleLoop(){this.loopEnabled=!this.loopEnabled,this.player.loop=this.loopEnabled}restorePlayback(){const t=this.playbackBeforeClick;t&&(this.currentTime=t.time,t.state==="playing"?this.play():this.pause())}get canUseNativeFullscreen(){return typeof this.fullscreenTarget.requestFullscreen=="function"&&document.fullscreenEnabled}toggleFullscreen(){if(!this.canUseNativeFullscreen){this.simulatedFullscreen?this.exitSimulatedFullscreen():this.enterSimulatedFullscreen();return}document.fullscreenElement?document.exitFullscreen():this.fullscreenTarget.requestFullscreen().catch(t=>{console.error("<rr0-ufo>: requestFullscreen() failed —",t)})}enterSimulatedFullscreen(){const t=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen=t.getAttribute("style")??"",this.bodyOverflowBeforeSimulatedFullscreen=document.body.style.overflow;const e=t.style;e.setProperty("position","fixed"),e.setProperty("inset","0"),e.setProperty("margin","0"),e.setProperty("max-width","none"),e.setProperty("max-height","none"),e.setProperty("aspect-ratio","auto"),e.setProperty("z-index","2147483647"),e.setProperty("background","#000"),e.setProperty("width","100vw"),e.setProperty("width","100dvw"),e.setProperty("height","100vh"),e.setProperty("height","100dvh"),document.body.style.overflow="hidden",this.simulatedFullscreen=!0,document.addEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton()}exitSimulatedFullscreen(){if(!this.simulatedFullscreen)return;const t=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen?t.setAttribute("style",this.styleBeforeSimulatedFullscreen):t.removeAttribute("style"),document.body.style.overflow=this.bodyOverflowBeforeSimulatedFullscreen??"",this.simulatedFullscreen=!1,document.removeEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton()}toggleObserverMap(){const t=this.observerMapPanel.hidden;this.observerMapAsked=t,this.setObserverMapOpen(t),this.keepObserverMapClear()}observerMapAsked=!1;applyObserverMapDefault(){const t=this.getAttribute(xr),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 e=!this.observerMapPanel.hidden?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=Mr.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(ui.OBSERVER_MAP_MIN_SPAN_M,ui.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?Ve.expand(t,ui.OBSERVER_MAP_IMAGERY_AHEAD):t,n=ui.OBSERVER_MAP_IMAGERY_PX*(e?1+2*ui.OBSERVER_MAP_IMAGERY_AHEAD:1);this.observerMapImageryBounds=i,this.observerMapImageryViewWidth=t.east-t.west,this.observerMapImageryLoading=!0;const s=pg();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?Ve.expand(t,ui.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=ui.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=li(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},ui.OBSERVER_MAP_FOLLOW_MARGIN)&&this.scheduleObserverMapImagery();const i=this.currentSighting.instrument,n=[],s=this.currentSighting.milestones.length>0?uf(this.currentSighting.milestones,t):void 0;for(const a of this.milestonesShown?ul(this.currentSighting.milestones):[]){const o=li(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?_s.of(i,this.canvas.height,e.fovDeg).halfWidthAngleDeg(hi.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.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;const t=this.milestonesShown?this.messages.hideMilestones:this.messages.showMilestones;this.milestonesButton.title=t,this.milestonesButton.setAttribute("aria-label",t)}observerMapDecorAt(t){const e=li(this.currentSighting,0);return e?.lat===void 0||e.lng===void 0?[]:this.currentSighting.decor.filter(i=>i.kind!=="crop").map(i=>{const n=Ro(i,t),{lat:s,lng:a}=ys(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=li(this.currentSighting,this.currentTime),s=_s.of(this.currentSighting.instrument,this.canvas.height,n?.fovDeg??60);return{x:-s.angleDegToRadiusPx(e),y:s.angleDegToRadiusPx(i)}}gaitAt(t){return xe.bodyAt(this.currentSighting,t,this.steadyObserver)}updateFullscreenButton(){const t=this.simulatedFullscreen||document.fullscreenElement===this.fullscreenTarget;this.fullscreenButton.title=t?this.messages.exitFullscreen:this.messages.fullscreen,this.fullscreenButton.setAttribute("aria-label",this.fullscreenButton.title)}get said(){return this.saidTexts??=new qs(dl.preferencesFor(this))}saidTexts;async loadLocaleMessages(){const t=ng(dl.preferencesFor(this),sg);if(t===this.messagesLanguage||t==="en"&&this.messagesLanguage===void 0)return;this.messagesLanguage=t;const e=await Uv(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;for(const i of[this.timeStartLabel,this.timeEndLabel])i.classList.toggle("switchable",this.canSwitchTimeDisplay),this.canSwitchTimeDisplay?(i.setAttribute("role","button"),i.setAttribute("tabindex","0")):(i.removeAttribute("role"),i.removeAttribute("tabindex"))}applyMessages(t){this.messages=t,this.updateTimeLabelTitles(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateMilestonesButton(),this.renderIssues()}updateTimeLabels(){const t=this.currentSighting.event,e=yv(t);this.realDurationMs=e!==void 0&&e>0?e:void 0,this.realStartMs=t.time?yu(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 ec(t);const e=this.currentSighting.timeline.duration,i=e>0&&t<=e?t/e*this.realDurationMs:t;return this.canShowClockTime?gf(mf(this.realStartMs+i)):ec(i)}formatEndOfTimeline(){return this.realDurationMs===void 0?ec(this.currentSighting.timeline.duration):this.canShowClockTime?gf(mf(this.realStartMs+this.realDurationMs)):ec(this.realDurationMs)}}function mf(r){const t=new Date(r);return{hour:t.getUTCHours(),minute:t.getUTCMinutes(),second:t.getUTCSeconds()}}function gf(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 ec(r){const t=Math.round(r/1e3),e=Math.floor(t/60),i=t%60;return`${e}:${String(i).padStart(2,"0")}`}const Su="rr0-ufo";function mg(){customElements.get(Su)||customElements.define(Su,ui)}const i2="recordingissues";/**
|
|
831
|
+
`)}`)}}class En{constructor(t){this.format=t}issues(t){const e=[];return this.object(t,this.format,"",e),e}object(t,e,i,n){if(!En.isObject(t)){n.push({kind:"wrong-type",path:i||"(the file)",expected:"object",found:En.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(En.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):En.isObject(t)||n.push({kind:"wrong-type",path:i,expected:"object",found:En.typeOf(t)});return;case"array":Array.isArray(t)?e.fields&&t.forEach((s,a)=>{const o=En.isStated(s)?s.value:s;this.object(o,e.fields,`${i}.${a}`,n)}):n.push({kind:"wrong-type",path:i,expected:"array",found:En.typeOf(t)});return;default:typeof t!==e.type&&n.push({kind:"wrong-type",path:i,expected:e.type,found:En.typeOf(t)})}}static isObject(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}static isStated(t){return En.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 In{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?In.travelDegOver(t,e,i,i+n*1e3)/s/In.PIXELS_PER_INSTANT:0,o=In.flashesOver(t,n)*In.INSTANTS_PER_FLASH,c=Math.ceil(Math.max(a,o));return c<2?1:Math.min(In.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=In.directionAt(a,e,i),c=In.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=Ro(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 ng(r,t){for(const e of r){const i=e.toLowerCase().split("-")[0];if(t.includes(i))return i}return"en"}class dl{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 qs{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[qs.base(i)];if(n)return n}const e=new Set(this.preferences.map(i=>qs.base(i)));for(const[i,n]of Object.entries(t))if(n&&e.has(qs.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=>qs.base(o)===qs.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 sg=["en","fr","es","it"],Fv={en:()=>es(()=>Promise.resolve().then(()=>zv),void 0,import.meta.url).then(r=>r.ufoMessages_en),fr:()=>es(()=>import("./UfoMessages_fr-DDeCjNS8.js"),[],import.meta.url).then(r=>r.ufoMessages_fr),es:()=>es(()=>import("./UfoMessages_es-CzuRdJdo.js"),[],import.meta.url).then(r=>r.ufoMessages_es),it:()=>es(()=>import("./UfoMessages_it-C2dUwy6T.js"),[],import.meta.url).then(r=>r.ufoMessages_it)};function Uv(r){return Fv[r]()}function kv(r){switch(r){case"fr":return es(()=>import("./SceneNames_fr-0Wzm8zKy.js"),[],import.meta.url).then(t=>t.sceneNames_fr);case"es":return es(()=>import("./SceneNames_es-C1QdYSKO.js"),[],import.meta.url).then(t=>t.sceneNames_es);case"it":return es(()=>import("./SceneNames_it-C5oOps-9.js"),[],import.meta.url).then(t=>t.sceneNames_it);default:return Promise.resolve(void 0)}}const ag={play:"Play",pause:"Pause",noDuration:"No observation duration",currentPosition:"Current position",duration:"Duration",switchToElapsed:"click to show elapsed time",switchToClockTime:"click to show the time of day",fullscreen:"Fullscreen",exitFullscreen:"Exit fullscreen",showObserverMap:"Show where the observer was",hideObserverMap:"Hide where the observer was",mapImageryUnavailable:"Aerial imagery unavailable",zoomMapIn:"Zoom in",zoomMapOut:"Zoom out",fitMap:"Back to the whole path",placeObserverHere:"Put the observer here",showReferences:"Show the pictures of the place",hideReferences:"Hide the pictures of the place",referenceOpacity:"Picture opacity",showMilestones:"Show the account's moments",hideMilestones:"Hide the account's moments",observerHere:"The observer, here",decorHere:"Scenery",recordingIssues:"{count} problem(s) in this recording: it may not play as its author meant",issueTemplates:Ir.EN},zv=Object.freeze(Object.defineProperty({__proto__:null,ufoMessages_en:ag},Symbol.toStringTag,{value:"Module"})),rg=Math.PI/180,Bv=180/Math.PI,Hv=256,og=19,Gv=1.25;function cg(r,t){return 156543.03392*Math.cos(r*rg)/2**t}function lg(r,t){return cg(r,t)*Hv}function Vv(r,t){let e=0;for(;e<og&&lg(r,e+1)>=t;)e++;return e}function hg(r,t){return lg(r,t)}function Wv(r,t){const e=t*Gv;let i=0;for(;i<og&&cg(r,i)>e;)i++;return i}function jc(r){const t=r*rg;return(1-Math.log(Math.tan(t)+1/Math.cos(t))/Math.PI)/2}function ug(r,t,e){const i=2**e;return{x:(r+180)/360*i,y:jc(t)*i}}function dg(r,t,e){const i=jc(r.north),n=jc(r.south);return{x:(t-r.west)/(r.east-r.west),y:(jc(e)-i)/(n-i)}}function Xv(r,t,e){const{x:i,y:n}=ug(r,t,e);return{x:Math.floor(i),y:Math.floor(n),z:e}}function Yv(r){const t=2**r.z,e=r.x/t*360-180,i=(r.x+1)/t*360-180,n=df(r.y,t);return{south:df(r.y+1,t),north:n,west:e,east:i}}function df(r,t){const e=r/t;return Math.atan(Math.sinh(Math.PI*(1-2*e)))*Bv}function fg(r,t,e,i){const n=Xv(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(Yv),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 ga{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=dg(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:ga.MARKER_RADIUS_PX}),e.beginPath(),e.arc(n.x,n.y,ga.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=ii(a.lat,a.lng,e.lat,e.lng);return Math.hypot(o.x,o.z)<=ga.ON_MARKER_M});i.beginPath(),i.arc(n.x,n.y,s?ga.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(ii(a,t.east,a,t.west).x)/this.width,l=ga.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 Ve{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(Ve.MAX_ZOOM,Math.max(Ve.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=Ve.mercatorY01(e.north),s=Ve.mercatorY01(e.south),a=Ve.mercatorY01(i.north),o=Ve.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=Ve.mercatorY01(n.north),a=Ve.mercatorY01(n.south),o=(e.lng-n.west)/(n.east-n.west),c=(Ve.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=Ve.mercatorY01(t.north),n=Ve.mercatorY01(t.south),s=t.east-t.west;return{west:t.west+(this.centerX-e)*s,east:t.west+(this.centerX+e)*s,north:Ve.latitudeAt(i+(this.centerY-e)*(n-i)),south:Ve.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=Ve.mercatorY01(t.north),s=Ve.mercatorY01(t.south);return{lat:Ve.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 dn=256,ff=3,qv=32768;class $v{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(ii(i,t.east,i,t.west).x),a=Math.abs(ii(t.north,n,t.south,n).z),o=Vv(i,Math.max(s,a)),{tiles:c}=fg(n,i,o,ff),l=ff*dn,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=dn,c.height=dn;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,dn,dn),u=(t.x-e.x)*dn,d=(t.y-e.y)*dn;for(let f=0;f<dn;f++)for(let p=0;p<dn;p++){const v=(f*dn+p)*4,m=h[v]*256+h[v+1]+h[v+2]/256-qv,g=u+p,S=d+f;i[S*n+g]=m}}sampleAt(t,e,i,n,s,a){const{x:o,y:c}=ug(e,t,i),l=(o-n.x)*dn,h=(c-n.y)*dn,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],_=s[p*a+u],M=s[p*a+f],b=g+(S-g)*v,w=_+(M-_)*v;return b+(w-b)*m}}const Qc=256,Kv=5;async function Zv(r,t,e,i){const n=(r.south+r.north)/2,s=(r.west+r.east)/2,a=Math.abs(ii(n,r.east,n,r.west).x),o=Math.abs(ii(r.north,s,r.south,s).z),c=Math.max(a,o),{zoom:l,gridSize:h}=Jv(n,c,Math.max(t.width,t.height)),{tiles:u,bounds:d}=fg(s,n,l,h),f=h*Qc,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)*Qc,(M.y-m.y)*Qc)}));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 _=S.getContext("2d");if(!_)throw new Error("2D canvas context unavailable");return _.drawImage(p,0,0,f,f,0,0,g,g),{source:S,width:g,height:g,bounds:d}}function Jv(r,t,e){let i=Wv(r,t/Math.max(1,e)),n=pf(r,i,t);for(;n>Kv&&i>0;)i--,n=pf(r,i,t);return{zoom:i,gridSize:n,mPerPixel:hg(r,i)/Qc}}function pf(r,t,e){const i=Math.ceil(e/2/hg(r,t));return Math.max(3,2*i+1)}class jv{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 Zv(t,e,i=>this.tileUrlTemplate.replace("{z}",String(i.z)).replace("{y}",String(i.y)).replace("{x}",String(i.x)),this.fetchImpl)}}class An{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??An.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"~"^(${An.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:An.surfaceOf(s),widthM:An.widthOf(s),points:n.map(a=>({lat:a.lat,lng:a.lon}))})}return e}queued(t){const e=An.queue.then(t,t);return An.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,An.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:An.WIDTH_M[t.highway]??An.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 th="https://ufoathome.org/roads/index.json";class Kd{attributionRead;contemporaryRead;fetchImpl;indexUrls;fallback;index;constructor(t={}){this.fetchImpl=t.fetchImpl??fetch.bind(globalThis),this.indexUrls=t.indexUrls??Kd.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.75.2")}`,e=typeof location>"u"?void 0:new URL("/roads/index.json",location.href).href;return(e&&e!==th?[e,th]:[th]).map(i=>i+t)}}function Qv(){return{elevation:new $v,imagery:pg(),roads:t2()}}function pg(){return new jv}function t2(){return new Kd({fallback:new An})}const e2=new Set,xr="show-observer-map",yr="hide-milestones";class ui extends HTMLElement{static get observedAttributes(){return["src",xr,yr]}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;observerMapButton;referencesButton;referenceOpacityInput;referencesShownState=!0;referenceOpacityTouched=!1;milestonesButton;observerMapPanel;observerMapCanvas;observerMapRenderer;mapZoomInButton;mapZoomOutButton;mapFitButton;observerMapView=new Ve;observerMapDrag;suppressObserverMapClick=!1;observerMapImageryTimer;observerPlacing=!1;seekInput;playbackFlash;milestoneMarks;milestoneCaption;timeStartLabel;timeEndLabel;observerPath;observerMapBounds;observerMapImagery;observerMapImageryBounds;observerMapImageryViewWidth=0;observerMapImageryLoading=!1;observerMapImageryCredit;observerMapImageryFailed=!1;creditShownExternally=!1;lookYawDeg=0;lookPitchDeg=0;milestonesShown=!0;currentSighting=Fl.create();issues=[];issueCheck=0;sightingAudio=new Cv;soundPreview;player;loopEnabled=!1;playbackBeforeClick;highlightedSourceIds=new Set;paintsShapes=!0;steadyObserver=!1;selectionShown=!0;overlayPainter;enableClickToPlay=!0;fullscreenTarget;messages=ag;realDurationMs;realStartMs;showClockTime=!0;handleFullscreenChange=()=>{this.updateFullscreenButton(),this.resizeObserverMap()};observerMapResizeObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>this.resizeObserverMap());resizeObserverMap(){this.observerMapPanel.hidden||(this.sizeObserverMapCanvas(),this.paintObserverMap(this.currentTime))}simulatedFullscreen=!1;styleBeforeSimulatedFullscreen;bodyOverflowBeforeSimulatedFullscreen;handleSimulatedFullscreenKey=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)<ui.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>=Ve.MAX_ZOOM,this.mapZoomOutButton.disabled=this.observerMapView.zoomFactor<=Ve.MIN_ZOOM,this.paintObserverMap(this.currentTime),this.scheduleObserverMapImagery()}scheduleObserverMapImagery(){this.observerMapImageryTimer===void 0&&(this.observerMapImageryTimer=setTimeout(()=>{this.observerMapImageryTimer=void 0,this.loadObserverMapImagery()},ui.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=Ve.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>${nv}</style>${iv}`,this.shadow.appendChild(t.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.canvas=this.shadow.getElementById("canvas"),this.canvasRenderer=new Lo(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.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 ga(this.observerMapCanvas.getContext("2d")),this.mapZoomInButton=this.shadow.getElementById("map-zoom-in"),this.mapZoomOutButton=this.shadow.getElementById("map-zoom-out"),this.mapFitButton=this.shadow.getElementById("map-fit"),this.seekInput=this.shadow.getElementById("seek"),this.playbackFlash=this.shadow.getElementById("playback-flash"),this.milestoneMarks=this.shadow.getElementById("milestone-marks"),this.milestoneCaption=this.shadow.getElementById("milestone-caption"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end");for(const e of[this.timeStartLabel,this.timeEndLabel])e.addEventListener("click",()=>this.toggleTimeDisplay()),e.addEventListener("keydown",i=>{i.key!=="Enter"&&i.key!==" "||(i.preventDefault(),this.toggleTimeDisplay())});this.fullscreenTarget=this.stageElement,this.playPauseButton.addEventListener("click",()=>this.togglePlayPause()),this.fullscreenButton.addEventListener("click",()=>this.toggleFullscreen()),this.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.seekSnapArmed=!0,this.nameMarkUnder(e)}),this.seekInput.addEventListener("pointerup",()=>{this.seekSnapArmed=!1}),this.seekInput.addEventListener("pointermove",e=>this.nameMarkUnder(e)),this.seekInput.addEventListener("pointerleave",()=>this.seekInput.removeAttribute("title")),this.seekInput.addEventListener("keydown",this.handleSeekKey),this.canvas.addEventListener("click",e=>{this.enableClickToPlay&&(e.detail<=1&&(this.playbackBeforeClick={state:this.playbackState,time:this.currentTime}),this.togglePlayPause())}),this.canvas.addEventListener("dblclick",e=>{this.enableClickToPlay&&(e.preventDefault(),this.restorePlayback(),this.toggleFullscreen())}),this.canvas.addEventListener("pointermove",this.handlePointerMove),this.canvas.addEventListener("pointerleave",this.handlePointerLeave),document.addEventListener("fullscreenchange",this.handleFullscreenChange),this.observerMapResizeObserver?.observe(this.observerMapPanel),this.hostControls(void 0),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateMilestonesButton(),this.refresh()}connectedCallback(){this.saidTexts=void 0,this.loadLocaleMessages();const t=this.getAttribute("src");t&&this.loadFromSrc(t)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.handleFullscreenChange),this.observerMapResizeObserver?.disconnect(),this.exitSimulatedFullscreen(),this.sightingAudio.dispose()}attributeChangedCallback(t,e,i){t==="src"&&i&&i!==e&&this.isConnected&&this.loadFromSrc(i),t===xr&&this.applyObserverMapDefault(),t===yr&&this.setMilestonesShown(!this.hasAttribute(yr))}async loadFromSrc(t){this.sightingData=await eg.json(t)}get sightingData(){return Pv(this.currentSighting)}set sightingData(t){this.player.stop(),this.soundPreview=void 0,this.sightingAudio.silence(),this.currentSighting=Ov(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 es(async()=>{const{default:a}=await import("./sightingSchema-DOOSOVWK.js");return{default:a}},[],import.meta.url);n=new En(s).issues(t)}catch{}i===this.issueCheck&&(this.issues=[...n,...e.loadIssues],Ir.warn(this.issues,e.id),this.renderIssues(),this.dispatchEvent(new CustomEvent(i2,{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=Ir.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)}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.referenceOpacityInput,this.referencesButton,this.observerMapButton];if(t)for(const i of e)t.appendChild(i);else for(const i of e)this.toolbar.appendChild(i)}get referencesShown(){return this.referencesShownState}get referenceOpacity(){return Number(this.referenceOpacityInput.value)}toggleReferences(){this.referencesShownState=!this.referencesShownState,this.updateReferencesButton(),this.dispatchReferenceView()}updateReferences(){const t=this.currentSighting.references;!this.referenceOpacityTouched&&t.length>0&&(this.referenceOpacityInput.value=String(t[0].opacity)),this.updateReferencesButton()}updateReferencesButton(){const t=this.currentSighting.references.length>0;this.referencesButton.hidden=!t,this.referenceOpacityInput.hidden=!t||!this.referencesShownState,this.referencesButton.setAttribute("aria-pressed",String(this.referencesShownState));const e=this.referencesShownState?this.messages.hideReferences:this.messages.showReferences;this.referencesButton.title=e,this.referencesButton.setAttribute("aria-label",e),this.referenceOpacityInput.title=this.messages.referenceOpacity,this.referenceOpacityInput.setAttribute("aria-label",this.messages.referenceOpacity)}dispatchReferenceView(){this.dispatchEvent(new CustomEvent("referenceview",{detail:{shown:this.referencesShown,opacity:this.referenceOpacity}}))}refreshMilestoneMarks(){const t=this.player.seekableDuration,e=t>0?ul(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}))}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=ui.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?uf(this.sighting.milestones,t):void 0;if(this.milestoneCaption.hidden=e===void 0,!e)return;const i=document.createElement("b");i.textContent=this.said.read(e.label)??"";const n=this.said.read(e.note),s=n?` — ${n}`:"";this.milestoneCaption.replaceChildren(i,document.createTextNode(s))}exposureInstants(t){const e=this.exposureTimes(t),i=1/e.length;return e.map(n=>({shapes:this.shapesAt(n),share:i}))}exposureTimes(t=this.currentTime){const e=In.windowEndingAt(t,this.currentSighting.exposure??0);if(e.ms<ui.SHORTEST_VISIBLE_EXPOSURE_MS)return[t];const i=Math.min(ui.MAX_EXPOSURE_STEPS,Math.max(2,Math.round(e.ms/ui.SHORTEST_VISIBLE_EXPOSURE_MS))),n=Math.ceil(this.travelPxOver(e.fromMs,e.ms)/ui.EXPOSURE_STEP_PX),s=Math.min(ui.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=hi.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:e2;this.canvasRenderer.setStarPoints(hi.starPointsOf(this.sighting.instrument));const n=(li(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=on.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.timeStartLabel.textContent=this.formatPosition(t),this.showMilestoneAt(t),this.paintObserverMap(t),this.playbackState==="playing"?(this.soundPreview=void 0,this.sightingAudio.setSound(bv(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 wv(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;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*ui.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.textContent=this.player.playbackState==="playing"?"▶":"⏸",t.classList.remove("flashing"),t.offsetWidth,t.classList.add("flashing")}updatePlayPauseButton(){const t=this.player.playbackState==="playing";this.playPauseButton.textContent=t?"⏸":"▶";const e=this.player.seekableDuration>0;this.playPauseButton.disabled=!e;const i=e?t?this.messages.pause:this.messages.play:this.messages.noDuration;this.playPauseButton.title=i,this.playPauseButton.setAttribute("aria-label",i)}toggleLoop(){this.loopEnabled=!this.loopEnabled,this.player.loop=this.loopEnabled}restorePlayback(){const t=this.playbackBeforeClick;t&&(this.currentTime=t.time,t.state==="playing"?this.play():this.pause())}get canUseNativeFullscreen(){return typeof this.fullscreenTarget.requestFullscreen=="function"&&document.fullscreenEnabled}toggleFullscreen(){if(!this.canUseNativeFullscreen){this.simulatedFullscreen?this.exitSimulatedFullscreen():this.enterSimulatedFullscreen();return}document.fullscreenElement?document.exitFullscreen():this.fullscreenTarget.requestFullscreen().catch(t=>{console.error("<rr0-ufo>: requestFullscreen() failed —",t)})}enterSimulatedFullscreen(){const t=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen=t.getAttribute("style")??"",this.bodyOverflowBeforeSimulatedFullscreen=document.body.style.overflow;const e=t.style;e.setProperty("position","fixed"),e.setProperty("inset","0"),e.setProperty("margin","0"),e.setProperty("max-width","none"),e.setProperty("max-height","none"),e.setProperty("aspect-ratio","auto"),e.setProperty("z-index","2147483647"),e.setProperty("background","#000"),e.setProperty("width","100vw"),e.setProperty("width","100dvw"),e.setProperty("height","100vh"),e.setProperty("height","100dvh"),document.body.style.overflow="hidden",this.simulatedFullscreen=!0,document.addEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton()}exitSimulatedFullscreen(){if(!this.simulatedFullscreen)return;const t=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen?t.setAttribute("style",this.styleBeforeSimulatedFullscreen):t.removeAttribute("style"),document.body.style.overflow=this.bodyOverflowBeforeSimulatedFullscreen??"",this.simulatedFullscreen=!1,document.removeEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton()}toggleObserverMap(){const t=this.observerMapPanel.hidden;this.observerMapAsked=t,this.setObserverMapOpen(t),this.keepObserverMapClear()}observerMapAsked=!1;applyObserverMapDefault(){const t=this.getAttribute(xr),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 e=!this.observerMapPanel.hidden?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=Mr.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(ui.OBSERVER_MAP_MIN_SPAN_M,ui.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?Ve.expand(t,ui.OBSERVER_MAP_IMAGERY_AHEAD):t,n=ui.OBSERVER_MAP_IMAGERY_PX*(e?1+2*ui.OBSERVER_MAP_IMAGERY_AHEAD:1);this.observerMapImageryBounds=i,this.observerMapImageryViewWidth=t.east-t.west,this.observerMapImageryLoading=!0;const s=pg();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?Ve.expand(t,ui.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=ui.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=li(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},ui.OBSERVER_MAP_FOLLOW_MARGIN)&&this.scheduleObserverMapImagery();const i=this.currentSighting.instrument,n=[],s=this.currentSighting.milestones.length>0?uf(this.currentSighting.milestones,t):void 0;for(const a of this.milestonesShown?ul(this.currentSighting.milestones):[]){const o=li(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?_s.of(i,this.canvas.height,e.fovDeg).halfWidthAngleDeg(hi.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.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;const t=this.milestonesShown?this.messages.hideMilestones:this.messages.showMilestones;this.milestonesButton.title=t,this.milestonesButton.setAttribute("aria-label",t)}observerMapDecorAt(t){const e=li(this.currentSighting,0);return e?.lat===void 0||e.lng===void 0?[]:this.currentSighting.decor.filter(i=>i.kind!=="crop").map(i=>{const n=Ro(i,t),{lat:s,lng:a}=ys(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=li(this.currentSighting,this.currentTime),s=_s.of(this.currentSighting.instrument,this.canvas.height,n?.fovDeg??60);return{x:-s.angleDegToRadiusPx(e),y:s.angleDegToRadiusPx(i)}}gaitAt(t){return xe.bodyAt(this.currentSighting,t,this.steadyObserver)}updateFullscreenButton(){const t=this.simulatedFullscreen||document.fullscreenElement===this.fullscreenTarget;this.fullscreenButton.title=t?this.messages.exitFullscreen:this.messages.fullscreen,this.fullscreenButton.setAttribute("aria-label",this.fullscreenButton.title)}get said(){return this.saidTexts??=new qs(dl.preferencesFor(this))}saidTexts;async loadLocaleMessages(){const t=ng(dl.preferencesFor(this),sg);if(t===this.messagesLanguage||t==="en"&&this.messagesLanguage===void 0)return;this.messagesLanguage=t;const e=await Uv(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;for(const i of[this.timeStartLabel,this.timeEndLabel])i.classList.toggle("switchable",this.canSwitchTimeDisplay),this.canSwitchTimeDisplay?(i.setAttribute("role","button"),i.setAttribute("tabindex","0")):(i.removeAttribute("role"),i.removeAttribute("tabindex"))}applyMessages(t){this.messages=t,this.updateTimeLabelTitles(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateObserverMapButton(),this.updateReferencesButton(),this.updateMilestonesButton(),this.renderIssues()}updateTimeLabels(){const t=this.currentSighting.event,e=yv(t);this.realDurationMs=e!==void 0&&e>0?e:void 0,this.realStartMs=t.time?yu(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 ec(t);const e=this.currentSighting.timeline.duration,i=e>0&&t<=e?t/e*this.realDurationMs:t;return this.canShowClockTime?gf(mf(this.realStartMs+i)):ec(i)}formatEndOfTimeline(){return this.realDurationMs===void 0?ec(this.currentSighting.timeline.duration):this.canShowClockTime?gf(mf(this.realStartMs+this.realDurationMs)):ec(this.realDurationMs)}}function mf(r){const t=new Date(r);return{hour:t.getUTCHours(),minute:t.getUTCMinutes(),second:t.getUTCSeconds()}}function gf(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 ec(r){const t=Math.round(r/1e3),e=Math.floor(t/60),i=t%60;return`${e}:${String(i).padStart(2,"0")}`}const Su="rr0-ufo";function mg(){customElements.get(Su)||customElements.define(Su,ui)}const i2="recordingissues";/**
|
|
832
832
|
* @license
|
|
833
833
|
* Copyright 2010-2026 Three.js Authors
|
|
834
834
|
* SPDX-License-Identifier: MIT
|
|
@@ -5888,7 +5888,7 @@ void main() {
|
|
|
5888
5888
|
float blur = max(vNearBlur, vHaze);
|
|
5889
5889
|
gl_FragColor = vec4(color, tex.a * uOpacity * vNearFade * (1.0 - blur * ${G5.toFixed(2)}));
|
|
5890
5890
|
}
|
|
5891
|
-
`;function q5(r){let t=r;return function(){t|=0,t=t+1831565813|0;let i=Math.imul(t^t>>>15,1|t);return i=i+Math.imul(i^i>>>7,61|i)^i,((i^i>>>14)>>>0)/4294967296}}const $5=.14,Qp=4.5;let zc;function K5(){if(zc)return zc;const r=128,t=document.createElement("canvas");t.width=r,t.height=r;const e=t.getContext("2d"),i=e.createImageData(r,r),n=r/2,s=r*$5,a=r-s;for(let o=0;o<r;o++)for(let c=0;c<r;c++){const l=c+.5-n,h=o+.5<s?o+.5-s:o+.5>a?o+.5-a:0,u=Math.hypot(l,h),d=Math.exp(-(u*u)/(2*Qp*Qp)),f=(o*r+c)*4;i.data[f]=255,i.data[f+1]=255,i.data[f+2]=255,i.data[f+3]=Math.round(255*Math.min(1,d))}return e.putImageData(i,0,0),zc=new Ds(t),zc}function Z5(r){const t=q5(r.seed),e=new Float32Array(r.count*3),i=new Float32Array(r.count),n=r.radiusM;for(let l=0;l<r.count;l++){const h=t()*Math.PI*2,u=Math.sqrt(t())*r.radiusM;e[l*3]=Math.cos(h)*u,e[l*3+1]=t()*r.heightM,e[l*3+2]=Math.sin(h)*u,i[l]=.85+t()*.3}const s=new oe;s.setAttribute("position",new ee(e,3)),s.setAttribute("aSpeed",new ee(i,1)),s.setDrawRange(0,r.visibleCount);const a={uTime:{value:0},uOverallSpeed:{value:r.overallSpeed},uPixelSize:{value:r.pixelSize},uOpacity:{value:r.opacity},uColor:{value:r.color},uUvSquash:{value:1},uSpeedStreak:{value:r.speedStreak},uWindOffset:{value:new xt(0,0)},uDropVelocity:{value:new R(0,-1,0)},uAspect:{value:1},uHeight:{value:r.heightM},uBottomY:{value:r.bottomYM},uHalfWidth:{value:n},uTexture:{value:K5()},uNearFocusDistance:{value:r.nearFocusDistanceM},uHazeDistance:{value:r.hazeDistanceM},uHazeColor:{value:r.hazeColor}},o=new ce({uniforms:a,vertexShader:X5,fragmentShader:Y5,transparent:!0,depthWrite:!1,depthTest:!0}),c=new Ms(s,o);return c.frustumCulled=!1,{points:c,uniforms:a}}class Fa{static S10_MAG_PER_ARCSEC2=10+2.5*Math.log10(3600*3600);static toMagPerArcsec2(t){return Fa.S10_MAG_PER_ARCSEC2-2.5*Math.log10(Math.max(t,1e-12))}static fromMagPerArcsec2(t){return 10**(.4*(Fa.S10_MAG_PER_ARCSEC2-t))}static latitudeOfRowCoord(t){const e=2*t-1;return 90*Math.sign(e)*e*e}static rowCoordOfLatitude(t){return(Math.sign(t)*Math.sqrt(Math.min(Math.abs(t),90)/90)+1)/2}static angleOfColumnCoord(t){return 180*t*t}static columnCoordOfAngle(t){return Math.sqrt(Math.min(Math.max(t,0),180)/180)}}class ne{static LONGITUDE_STEPS=256;static LATITUDE_STEPS=128;static SUN_RADIUS_KPC=8.2;static SUN_HEIGHT_KPC=.02;static DISK_SCALE_LENGTH_KPC=2.6;static DISK_SCALE_HEIGHT_KPC=.3;static BULGE_SCALE_KPC=.5;static BULGE_FLATTENING=.6;static BULGE_TO_LOCAL_DISK=20;static DUST_SCALE_LENGTH_KPC=3.5;static DUST_SCALE_HEIGHT_KPC=.1;static EXTINCTION_MAG_PER_KPC=.8;static NEAR_LIMIT_KPC=.01;static FAR_LIMIT_KPC=40;static STEPS=192;static OPAQUE_MAG=15;static PEAK_MAG_PER_ARCSEC2=21;static PEAK_RADIANCE=6.278;static PEAK_LONGITUDE_DEG=0;static PEAK_LATITUDE_DEG=4.5;surfaceBrightnessS10(t,e){return this.radianceTowards(t,e)*ne.anchor()}static anchor(){return Fa.fromMagPerArcsec2(ne.PEAK_MAG_PER_ARCSEC2)/ne.PEAK_RADIANCE}radianceTowards(t,e){return this.trace(t,e).light}extinctionTowards(t,e){return this.trace(t,e).extinctionMag}trace(t,e){const i=t*Math.PI/180,n=e*Math.PI/180,s=-Math.cos(n)*Math.cos(i),a=Math.cos(n)*Math.sin(i),o=Math.sin(n);let c=0,l=0,h=0;const u=Math.log(ne.NEAR_LIMIT_KPC),d=Math.log(ne.FAR_LIMIT_KPC)-u;for(let f=0;f<ne.STEPS;f++){const p=Math.exp(u+d*f/(ne.STEPS-1)),v=p-h;h=p;const m=p-v/2,g=ne.SUN_RADIUS_KPC+m*s,S=m*a,_=ne.SUN_HEIGHT_KPC+m*o,M=Math.hypot(g,S),b=Math.exp(-(M-ne.SUN_RADIUS_KPC)/ne.DISK_SCALE_LENGTH_KPC-Math.abs(_)/ne.DISK_SCALE_HEIGHT_KPC),w=Math.hypot(M,_/ne.BULGE_FLATTENING),T=ne.BULGE_TO_LOCAL_DISK*Math.exp(-w/ne.BULGE_SCALE_KPC);if(c+=(b+T)*v*10**(-.4*l),l+=ne.EXTINCTION_MAG_PER_KPC*Math.exp(-(M-ne.SUN_RADIUS_KPC)/ne.DUST_SCALE_LENGTH_KPC-(Math.abs(_)-ne.SUN_HEIGHT_KPC)/ne.DUST_SCALE_HEIGHT_KPC)*v,l>ne.OPAQUE_MAG)break}return{light:c,extinctionMag:l}}values=new Float32Array(ne.LONGITUDE_STEPS*ne.LATITUDE_STEPS);walked=0;get done(){return this.walked>=ne.LATITUDE_STEPS}walk(t){const e=ne.LONGITUDE_STEPS,i=Math.min(ne.LATITUDE_STEPS,this.walked+t);for(;this.walked<i;this.walked++){const n=Fa.latitudeOfRowCoord((this.walked+.5)/ne.LATITUDE_STEPS);for(let s=0;s<e;s++)this.values[this.walked*e+s]=this.radianceTowards(360*(s+.5)/e,n)}}harvest(){let t=Number.POSITIVE_INFINITY;for(const n of this.values)n<t&&(t=n);const e=ne.anchor(),i=new Float32Array(this.values.length);for(let n=0;n<i.length;n++)i[n]=(this.values[n]-t)*e;return{width:ne.LONGITUDE_STEPS,height:ne.LATITUDE_STEPS,data:i}}}class Ge{static LONGITUDE_STEPS=128;static LATITUDE_STEPS=96;static RADIAL_FALLOFF=1.3;static FAN_EXPONENT=2.6;static SUBLIMATION_AU=.1;static NEAR_LIMIT_AU=.004;static FAR_LIMIT_AU=8;static STEPS=224;static LOBE_ASYMMETRY=[.7,-.2,-.81];static LOBE_WEIGHT=[.665,.33,.00541];static RIGHT_ANGLE_S10=200;static POLE_S10=77;surfaceBrightnessS10(t,e){return this.radianceTowards(t,e)*this.anchor()}anchored;anchor(){return this.anchored===void 0&&(this.anchored=Ge.RIGHT_ANGLE_S10/this.radianceTowards(90,0)),this.anchored}radianceTowards(t,e){const i=t*Math.PI/180,n=e*Math.PI/180,s=-Math.cos(n)*Math.cos(i),a=-Math.cos(n)*Math.sin(i),o=Math.sin(n),c=-s;let l=0,h=0;const u=Math.log(Ge.NEAR_LIMIT_AU),d=Math.log(Ge.FAR_LIMIT_AU)-u;for(let f=0;f<Ge.STEPS;f++){const p=Math.exp(u+d*f/(Ge.STEPS-1)),v=p-h;h=p;const m=p-v/2,g=1+m*s,S=m*a,_=m*o,M=Math.hypot(g,S,_);if(M<Ge.SUBLIMATION_AU)continue;const b=_/M,w=M**-1.3*Math.exp(-2.6*Math.abs(b)),T=(c-m)/M;l+=w*this.scattering(T)*v/(M*M)}return l}scattering(t){let e=0;for(let i=0;i<Ge.LOBE_ASYMMETRY.length;i++){const n=Ge.LOBE_ASYMMETRY[i],s=1+n*n-2*n*t;e+=Ge.LOBE_WEIGHT[i]*(1-n*n)/(4*Math.PI*s**1.5)}return e}values=new Float32Array(Ge.LONGITUDE_STEPS*Ge.LATITUDE_STEPS);walked=0;get done(){return this.walked>=Ge.LATITUDE_STEPS}walk(t){const e=Ge.LONGITUDE_STEPS,i=Math.min(Ge.LATITUDE_STEPS,this.walked+t);for(;this.walked<i;this.walked++){const n=Fa.latitudeOfRowCoord((this.walked+.5)/Ge.LATITUDE_STEPS);for(let s=0;s<e;s++){const a=Fa.angleOfColumnCoord((s+.5)/e);this.values[this.walked*e+s]=this.radianceTowards(a,n)}}}harvest(){const t=this.anchor();let e=Number.POSITIVE_INFINITY;for(const n of this.values)n<e&&(e=n);const i=new Float32Array(this.values.length);for(let n=0;n<i.length;n++)i[n]=(this.values[n]-e)*t;return{width:Ge.LONGITUDE_STEPS,height:Ge.LATITUDE_STEPS,data:i}}}class Mt{static get NANOLAMBERTS_PER_S10(){return Mt.toNanolamberts(10+2.5*Math.log10(3600*3600))}static nanolambertsOfS10(t){return t*Mt.NANOLAMBERTS_PER_S10}static TWILIGHT=[{sunAltitudeDeg:90,magPerArcsec2:3.5},{sunAltitudeDeg:10,magPerArcsec2:4.2},{sunAltitudeDeg:0,magPerArcsec2:7.5},...Array.from({length:15},(t,e)=>{const i=-4-e;return{sunAltitudeDeg:i,magPerArcsec2:Mt.patatV(i)}}),{sunAltitudeDeg:-24,magPerArcsec2:22}];static patatV(t){const e=90-t-95;return 11.84+1.518*e-.057*e*e}static moonlessMagPerArcsec2(t){const e=Mt.TWILIGHT;for(let i=0;i<e.length-1;i++){const n=e[i],s=e[i+1];if(t<=n.sunAltitudeDeg&&t>=s.sunAltitudeDeg){const a=(n.sunAltitudeDeg-t)/(n.sunAltitudeDeg-s.sunAltitudeDeg);return n.magPerArcsec2+(s.magPerArcsec2-n.magPerArcsec2)*a}}return t>0?e[0].magPerArcsec2:e[e.length-1].magPerArcsec2}static toNanolamberts(t){return 34.08*Math.exp(Mt.NANOLAMBERT_OFFSET-Mt.PER_MAGNITUDE*t)}static fromNanolamberts(t){return(Mt.NANOLAMBERT_OFFSET-Math.log(Math.max(t,1e-6)/34.08))/Mt.PER_MAGNITUDE}static NANOLAMBERT_OFFSET=20.7233;static PER_MAGNITUDE=Math.LN10/2.5;static airMass(t){const e=Math.cos(Math.max(t,0)*Math.PI/180);return 1/Math.sqrt(Math.max(1-.96*e*e,.001))}static EXTINCTION_PER_AIR_MASS=.172;static scatteringAt(t){const e=Math.min(Math.max(t,0),180)*Math.PI/180;return 10**5.36*(1.06+Math.cos(e)**2)+10**(6.15-Math.min(t,180)/40)}static scatteredFraction(t){return 1-10**(-.4*Mt.EXTINCTION_PER_AIR_MASS*Mt.airMass(t))}static AIRGLOW_MAG_PER_ARCSEC2=22;static twilightExcessNanolamberts(t){return Math.max(0,Mt.toNanolamberts(Mt.moonlessMagPerArcsec2(t))-Mt.toNanolamberts(Mt.AIRGLOW_MAG_PER_ARCSEC2))}static twilightOutput(t){const e=Mt.scatteringAt(90-t)*Mt.scatteredFraction(90);return Mt.twilightExcessNanolamberts(t)/e}static moonNanolamberts(t,e,i,n){return Mt.scatteringAt(i)*Mt.moonOutput(t,e)*Mt.scatteredFraction(n)}static moonOutput(t,e){if(e<=0)return 0;const i=Math.min(Math.abs(t),180);return 10**(-.4*(3.84+.026*i+4e-9*i**4))*10**(-.4*Mt.EXTINCTION_PER_AIR_MASS*Mt.airMass(e))}static phaseAngleOf(t){return Math.acos(Math.min(Math.max(2*t-1,-1),1))*180/Math.PI}static magPerArcsec2(t,e,i,n){const s=Mt.scatteredFraction(i),a=Mt.scatteringAt(t.separationDeg)*Mt.twilightOutput(t.altitudeDeg)*s,o=Mt.scatteringAt(e.separationDeg)*Mt.moonOutput(e.phaseAngleDeg,e.altitudeDeg)*s;return Mt.fromNanolamberts(Mt.toNanolamberts(Mt.AIRGLOW_MAG_PER_ARCSEC2)+a+o+Mt.artificialNanolamberts(n,i))}static artificialZenithNanolamberts(t){return t===void 0||!Number.isFinite(t)?0:Math.max(0,Mt.toNanolamberts(t)-Mt.toNanolamberts(Mt.AIRGLOW_MAG_PER_ARCSEC2))}static artificialNanolamberts(t,e){const i=Mt.artificialZenithNanolamberts(t);return i>0?i*Mt.artificialShape(e):0}static artificialShape(t){return Mt.scatteredFraction(t)/Mt.scatteredFraction(90)}static nakedEyeLimit(t){return 7.93-5*Math.log10(10**(4.316-t/5)+1)}static starLossMagnitudes(t,e,i){const n=Mt.moonlessMagPerArcsec2(t),s=Mt.fromNanolamberts(Mt.toNanolamberts(n)+Mt.scatteringAt(90-e.altitudeDeg)*Mt.moonOutput(e.phaseAngleDeg,e.altitudeDeg)*Mt.scatteredFraction(90)+Mt.artificialZenithNanolamberts(i));return Math.max(0,Mt.nakedEyeLimit(n)-Mt.nakedEyeLimit(s))}}class Ws{static RADIUS=890;static TOO_BRIGHT_MAG_PER_ARCSEC2=16;static MILKY_WAY_TINT=[.9,.94,1];static ZODIACAL_TINT=[1,.97,.9];object;material;maps=_a.shared;milkyWayTexture;zodiacalTexture;milkyWayTexels;zodiacalTexels;repaint;constructor(){this.milkyWayTexels=this.maps.milkyWayTexels,this.milkyWayTexture=Ws.buildTexture(this.milkyWayTexels,ne.LONGITUDE_STEPS,ne.LATITUDE_STEPS,Fo),this.zodiacalTexels=this.maps.zodiacalTexels,this.zodiacalTexture=Ws.buildTexture(this.zodiacalTexels,Ge.LONGITUDE_STEPS,Ge.LATITUDE_STEPS,bi),this.material=new ce({uniforms:{uMilkyWay:{value:this.milkyWayTexture},uZodiacal:{value:this.zodiacalTexture},uGalactic:{value:new Yt},uEclipticPole:{value:new R(0,1,0)},uSunLongitude:{value:new R(1,0,0)},uMoonDirection:{value:new R(0,-1,0)},uMoonOutput:{value:0},uSunDirection:{value:new R(0,-1,0)},uTwilightOutput:{value:0},uAirglowNanolamberts:{value:Mt.toNanolamberts(Mt.AIRGLOW_MAG_PER_ARCSEC2)},uArtificialNanolamberts:{value:0},uSkyColor:{value:new R(0,0,0)},uMilkyWayTint:{value:new R(...Ws.MILKY_WAY_TINT)},uZodiacalTint:{value:new R(...Ws.ZODIACAL_TINT)},uReady:{value:this.maps.done?1:0},uEncodeDestination:{value:1}},vertexShader:`
|
|
5891
|
+
`;function q5(r){let t=r;return function(){t|=0,t=t+1831565813|0;let i=Math.imul(t^t>>>15,1|t);return i=i+Math.imul(i^i>>>7,61|i)^i,((i^i>>>14)>>>0)/4294967296}}const $5=.14,Qp=2.25;let zc;function K5(){if(zc)return zc;const r=128,t=document.createElement("canvas");t.width=r,t.height=r;const e=t.getContext("2d"),i=e.createImageData(r,r),n=r/2,s=r*$5,a=r-s;for(let o=0;o<r;o++)for(let c=0;c<r;c++){const l=c+.5-n,h=o+.5<s?o+.5-s:o+.5>a?o+.5-a:0,u=Math.hypot(l,h),d=Math.exp(-(u*u)/(2*Qp*Qp)),f=(o*r+c)*4;i.data[f]=255,i.data[f+1]=255,i.data[f+2]=255,i.data[f+3]=Math.round(255*Math.min(1,d))}return e.putImageData(i,0,0),zc=new Ds(t),zc}function Z5(r){const t=q5(r.seed),e=new Float32Array(r.count*3),i=new Float32Array(r.count),n=r.radiusM;for(let l=0;l<r.count;l++){const h=t()*Math.PI*2,u=Math.sqrt(t())*r.radiusM;e[l*3]=Math.cos(h)*u,e[l*3+1]=t()*r.heightM,e[l*3+2]=Math.sin(h)*u,i[l]=.85+t()*.3}const s=new oe;s.setAttribute("position",new ee(e,3)),s.setAttribute("aSpeed",new ee(i,1)),s.setDrawRange(0,r.visibleCount);const a={uTime:{value:0},uOverallSpeed:{value:r.overallSpeed},uPixelSize:{value:r.pixelSize},uOpacity:{value:r.opacity},uColor:{value:r.color},uUvSquash:{value:1},uSpeedStreak:{value:r.speedStreak},uWindOffset:{value:new xt(0,0)},uDropVelocity:{value:new R(0,-1,0)},uAspect:{value:1},uHeight:{value:r.heightM},uBottomY:{value:r.bottomYM},uHalfWidth:{value:n},uTexture:{value:K5()},uNearFocusDistance:{value:r.nearFocusDistanceM},uHazeDistance:{value:r.hazeDistanceM},uHazeColor:{value:r.hazeColor}},o=new ce({uniforms:a,vertexShader:X5,fragmentShader:Y5,transparent:!0,depthWrite:!1,depthTest:!0}),c=new Ms(s,o);return c.frustumCulled=!1,{points:c,uniforms:a}}class Fa{static S10_MAG_PER_ARCSEC2=10+2.5*Math.log10(3600*3600);static toMagPerArcsec2(t){return Fa.S10_MAG_PER_ARCSEC2-2.5*Math.log10(Math.max(t,1e-12))}static fromMagPerArcsec2(t){return 10**(.4*(Fa.S10_MAG_PER_ARCSEC2-t))}static latitudeOfRowCoord(t){const e=2*t-1;return 90*Math.sign(e)*e*e}static rowCoordOfLatitude(t){return(Math.sign(t)*Math.sqrt(Math.min(Math.abs(t),90)/90)+1)/2}static angleOfColumnCoord(t){return 180*t*t}static columnCoordOfAngle(t){return Math.sqrt(Math.min(Math.max(t,0),180)/180)}}class ne{static LONGITUDE_STEPS=256;static LATITUDE_STEPS=128;static SUN_RADIUS_KPC=8.2;static SUN_HEIGHT_KPC=.02;static DISK_SCALE_LENGTH_KPC=2.6;static DISK_SCALE_HEIGHT_KPC=.3;static BULGE_SCALE_KPC=.5;static BULGE_FLATTENING=.6;static BULGE_TO_LOCAL_DISK=20;static DUST_SCALE_LENGTH_KPC=3.5;static DUST_SCALE_HEIGHT_KPC=.1;static EXTINCTION_MAG_PER_KPC=.8;static NEAR_LIMIT_KPC=.01;static FAR_LIMIT_KPC=40;static STEPS=192;static OPAQUE_MAG=15;static PEAK_MAG_PER_ARCSEC2=21;static PEAK_RADIANCE=6.278;static PEAK_LONGITUDE_DEG=0;static PEAK_LATITUDE_DEG=4.5;surfaceBrightnessS10(t,e){return this.radianceTowards(t,e)*ne.anchor()}static anchor(){return Fa.fromMagPerArcsec2(ne.PEAK_MAG_PER_ARCSEC2)/ne.PEAK_RADIANCE}radianceTowards(t,e){return this.trace(t,e).light}extinctionTowards(t,e){return this.trace(t,e).extinctionMag}trace(t,e){const i=t*Math.PI/180,n=e*Math.PI/180,s=-Math.cos(n)*Math.cos(i),a=Math.cos(n)*Math.sin(i),o=Math.sin(n);let c=0,l=0,h=0;const u=Math.log(ne.NEAR_LIMIT_KPC),d=Math.log(ne.FAR_LIMIT_KPC)-u;for(let f=0;f<ne.STEPS;f++){const p=Math.exp(u+d*f/(ne.STEPS-1)),v=p-h;h=p;const m=p-v/2,g=ne.SUN_RADIUS_KPC+m*s,S=m*a,_=ne.SUN_HEIGHT_KPC+m*o,M=Math.hypot(g,S),b=Math.exp(-(M-ne.SUN_RADIUS_KPC)/ne.DISK_SCALE_LENGTH_KPC-Math.abs(_)/ne.DISK_SCALE_HEIGHT_KPC),w=Math.hypot(M,_/ne.BULGE_FLATTENING),T=ne.BULGE_TO_LOCAL_DISK*Math.exp(-w/ne.BULGE_SCALE_KPC);if(c+=(b+T)*v*10**(-.4*l),l+=ne.EXTINCTION_MAG_PER_KPC*Math.exp(-(M-ne.SUN_RADIUS_KPC)/ne.DUST_SCALE_LENGTH_KPC-(Math.abs(_)-ne.SUN_HEIGHT_KPC)/ne.DUST_SCALE_HEIGHT_KPC)*v,l>ne.OPAQUE_MAG)break}return{light:c,extinctionMag:l}}values=new Float32Array(ne.LONGITUDE_STEPS*ne.LATITUDE_STEPS);walked=0;get done(){return this.walked>=ne.LATITUDE_STEPS}walk(t){const e=ne.LONGITUDE_STEPS,i=Math.min(ne.LATITUDE_STEPS,this.walked+t);for(;this.walked<i;this.walked++){const n=Fa.latitudeOfRowCoord((this.walked+.5)/ne.LATITUDE_STEPS);for(let s=0;s<e;s++)this.values[this.walked*e+s]=this.radianceTowards(360*(s+.5)/e,n)}}harvest(){let t=Number.POSITIVE_INFINITY;for(const n of this.values)n<t&&(t=n);const e=ne.anchor(),i=new Float32Array(this.values.length);for(let n=0;n<i.length;n++)i[n]=(this.values[n]-t)*e;return{width:ne.LONGITUDE_STEPS,height:ne.LATITUDE_STEPS,data:i}}}class Ge{static LONGITUDE_STEPS=128;static LATITUDE_STEPS=96;static RADIAL_FALLOFF=1.3;static FAN_EXPONENT=2.6;static SUBLIMATION_AU=.1;static NEAR_LIMIT_AU=.004;static FAR_LIMIT_AU=8;static STEPS=224;static LOBE_ASYMMETRY=[.7,-.2,-.81];static LOBE_WEIGHT=[.665,.33,.00541];static RIGHT_ANGLE_S10=200;static POLE_S10=77;surfaceBrightnessS10(t,e){return this.radianceTowards(t,e)*this.anchor()}anchored;anchor(){return this.anchored===void 0&&(this.anchored=Ge.RIGHT_ANGLE_S10/this.radianceTowards(90,0)),this.anchored}radianceTowards(t,e){const i=t*Math.PI/180,n=e*Math.PI/180,s=-Math.cos(n)*Math.cos(i),a=-Math.cos(n)*Math.sin(i),o=Math.sin(n),c=-s;let l=0,h=0;const u=Math.log(Ge.NEAR_LIMIT_AU),d=Math.log(Ge.FAR_LIMIT_AU)-u;for(let f=0;f<Ge.STEPS;f++){const p=Math.exp(u+d*f/(Ge.STEPS-1)),v=p-h;h=p;const m=p-v/2,g=1+m*s,S=m*a,_=m*o,M=Math.hypot(g,S,_);if(M<Ge.SUBLIMATION_AU)continue;const b=_/M,w=M**-1.3*Math.exp(-2.6*Math.abs(b)),T=(c-m)/M;l+=w*this.scattering(T)*v/(M*M)}return l}scattering(t){let e=0;for(let i=0;i<Ge.LOBE_ASYMMETRY.length;i++){const n=Ge.LOBE_ASYMMETRY[i],s=1+n*n-2*n*t;e+=Ge.LOBE_WEIGHT[i]*(1-n*n)/(4*Math.PI*s**1.5)}return e}values=new Float32Array(Ge.LONGITUDE_STEPS*Ge.LATITUDE_STEPS);walked=0;get done(){return this.walked>=Ge.LATITUDE_STEPS}walk(t){const e=Ge.LONGITUDE_STEPS,i=Math.min(Ge.LATITUDE_STEPS,this.walked+t);for(;this.walked<i;this.walked++){const n=Fa.latitudeOfRowCoord((this.walked+.5)/Ge.LATITUDE_STEPS);for(let s=0;s<e;s++){const a=Fa.angleOfColumnCoord((s+.5)/e);this.values[this.walked*e+s]=this.radianceTowards(a,n)}}}harvest(){const t=this.anchor();let e=Number.POSITIVE_INFINITY;for(const n of this.values)n<e&&(e=n);const i=new Float32Array(this.values.length);for(let n=0;n<i.length;n++)i[n]=(this.values[n]-e)*t;return{width:Ge.LONGITUDE_STEPS,height:Ge.LATITUDE_STEPS,data:i}}}class Mt{static get NANOLAMBERTS_PER_S10(){return Mt.toNanolamberts(10+2.5*Math.log10(3600*3600))}static nanolambertsOfS10(t){return t*Mt.NANOLAMBERTS_PER_S10}static TWILIGHT=[{sunAltitudeDeg:90,magPerArcsec2:3.5},{sunAltitudeDeg:10,magPerArcsec2:4.2},{sunAltitudeDeg:0,magPerArcsec2:7.5},...Array.from({length:15},(t,e)=>{const i=-4-e;return{sunAltitudeDeg:i,magPerArcsec2:Mt.patatV(i)}}),{sunAltitudeDeg:-24,magPerArcsec2:22}];static patatV(t){const e=90-t-95;return 11.84+1.518*e-.057*e*e}static moonlessMagPerArcsec2(t){const e=Mt.TWILIGHT;for(let i=0;i<e.length-1;i++){const n=e[i],s=e[i+1];if(t<=n.sunAltitudeDeg&&t>=s.sunAltitudeDeg){const a=(n.sunAltitudeDeg-t)/(n.sunAltitudeDeg-s.sunAltitudeDeg);return n.magPerArcsec2+(s.magPerArcsec2-n.magPerArcsec2)*a}}return t>0?e[0].magPerArcsec2:e[e.length-1].magPerArcsec2}static toNanolamberts(t){return 34.08*Math.exp(Mt.NANOLAMBERT_OFFSET-Mt.PER_MAGNITUDE*t)}static fromNanolamberts(t){return(Mt.NANOLAMBERT_OFFSET-Math.log(Math.max(t,1e-6)/34.08))/Mt.PER_MAGNITUDE}static NANOLAMBERT_OFFSET=20.7233;static PER_MAGNITUDE=Math.LN10/2.5;static airMass(t){const e=Math.cos(Math.max(t,0)*Math.PI/180);return 1/Math.sqrt(Math.max(1-.96*e*e,.001))}static EXTINCTION_PER_AIR_MASS=.172;static scatteringAt(t){const e=Math.min(Math.max(t,0),180)*Math.PI/180;return 10**5.36*(1.06+Math.cos(e)**2)+10**(6.15-Math.min(t,180)/40)}static scatteredFraction(t){return 1-10**(-.4*Mt.EXTINCTION_PER_AIR_MASS*Mt.airMass(t))}static AIRGLOW_MAG_PER_ARCSEC2=22;static twilightExcessNanolamberts(t){return Math.max(0,Mt.toNanolamberts(Mt.moonlessMagPerArcsec2(t))-Mt.toNanolamberts(Mt.AIRGLOW_MAG_PER_ARCSEC2))}static twilightOutput(t){const e=Mt.scatteringAt(90-t)*Mt.scatteredFraction(90);return Mt.twilightExcessNanolamberts(t)/e}static moonNanolamberts(t,e,i,n){return Mt.scatteringAt(i)*Mt.moonOutput(t,e)*Mt.scatteredFraction(n)}static moonOutput(t,e){if(e<=0)return 0;const i=Math.min(Math.abs(t),180);return 10**(-.4*(3.84+.026*i+4e-9*i**4))*10**(-.4*Mt.EXTINCTION_PER_AIR_MASS*Mt.airMass(e))}static phaseAngleOf(t){return Math.acos(Math.min(Math.max(2*t-1,-1),1))*180/Math.PI}static magPerArcsec2(t,e,i,n){const s=Mt.scatteredFraction(i),a=Mt.scatteringAt(t.separationDeg)*Mt.twilightOutput(t.altitudeDeg)*s,o=Mt.scatteringAt(e.separationDeg)*Mt.moonOutput(e.phaseAngleDeg,e.altitudeDeg)*s;return Mt.fromNanolamberts(Mt.toNanolamberts(Mt.AIRGLOW_MAG_PER_ARCSEC2)+a+o+Mt.artificialNanolamberts(n,i))}static artificialZenithNanolamberts(t){return t===void 0||!Number.isFinite(t)?0:Math.max(0,Mt.toNanolamberts(t)-Mt.toNanolamberts(Mt.AIRGLOW_MAG_PER_ARCSEC2))}static artificialNanolamberts(t,e){const i=Mt.artificialZenithNanolamberts(t);return i>0?i*Mt.artificialShape(e):0}static artificialShape(t){return Mt.scatteredFraction(t)/Mt.scatteredFraction(90)}static nakedEyeLimit(t){return 7.93-5*Math.log10(10**(4.316-t/5)+1)}static starLossMagnitudes(t,e,i){const n=Mt.moonlessMagPerArcsec2(t),s=Mt.fromNanolamberts(Mt.toNanolamberts(n)+Mt.scatteringAt(90-e.altitudeDeg)*Mt.moonOutput(e.phaseAngleDeg,e.altitudeDeg)*Mt.scatteredFraction(90)+Mt.artificialZenithNanolamberts(i));return Math.max(0,Mt.nakedEyeLimit(n)-Mt.nakedEyeLimit(s))}}class Ws{static RADIUS=890;static TOO_BRIGHT_MAG_PER_ARCSEC2=16;static MILKY_WAY_TINT=[.9,.94,1];static ZODIACAL_TINT=[1,.97,.9];object;material;maps=_a.shared;milkyWayTexture;zodiacalTexture;milkyWayTexels;zodiacalTexels;repaint;constructor(){this.milkyWayTexels=this.maps.milkyWayTexels,this.milkyWayTexture=Ws.buildTexture(this.milkyWayTexels,ne.LONGITUDE_STEPS,ne.LATITUDE_STEPS,Fo),this.zodiacalTexels=this.maps.zodiacalTexels,this.zodiacalTexture=Ws.buildTexture(this.zodiacalTexels,Ge.LONGITUDE_STEPS,Ge.LATITUDE_STEPS,bi),this.material=new ce({uniforms:{uMilkyWay:{value:this.milkyWayTexture},uZodiacal:{value:this.zodiacalTexture},uGalactic:{value:new Yt},uEclipticPole:{value:new R(0,1,0)},uSunLongitude:{value:new R(1,0,0)},uMoonDirection:{value:new R(0,-1,0)},uMoonOutput:{value:0},uSunDirection:{value:new R(0,-1,0)},uTwilightOutput:{value:0},uAirglowNanolamberts:{value:Mt.toNanolamberts(Mt.AIRGLOW_MAG_PER_ARCSEC2)},uArtificialNanolamberts:{value:0},uSkyColor:{value:new R(0,0,0)},uMilkyWayTint:{value:new R(...Ws.MILKY_WAY_TINT)},uZodiacalTint:{value:new R(...Ws.ZODIACAL_TINT)},uReady:{value:this.maps.done?1:0},uEncodeDestination:{value:1}},vertexShader:`
|
|
5892
5892
|
varying vec3 vDirection;
|
|
5893
5893
|
void main() {
|
|
5894
5894
|
vDirection = normalize((modelMatrix * vec4(position, 1.0)).xyz - cameraPosition);
|
|
@@ -6678,7 +6678,7 @@ void main()
|
|
|
6678
6678
|
if (ice <= 0.0) discard;
|
|
6679
6679
|
gl_FragColor = vec4(iceHaloLight(dir, ice), 1.0);
|
|
6680
6680
|
}
|
|
6681
|
-
`,transparent:!0,blending:Oi,depthWrite:!1,side:He,fog:!1}),this.object=new Dt(new si(Ii.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)<Ii.ALTITUDE_STEP_DEG)||!(Math.abs(e-this.mappedAlignment)<Ii.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)<Ii.LEAP_ALTITUDE_DEG)||!(Math.abs(e-this.pendingAlignment)<Ii.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)<Ii.ALTITUDE_STEP_DEG&&Math.abs(e-this.pendingAlignment)<Ii.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?Ii.URGENT_BUDGET_MS:Ii.BUDGET_MS;do this.sky.trace(Ii.RAYS_PER_BATCH);while(this.sky.tracedRays<Ii.RAYS&&performance.now()-e<i);if(this.sky.tracedRays>=Ii.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]=Nn.toHalfFloat(e[n]),this.texels[i+1]=Nn.toHalfFloat(e[n+1]),this.texels[i+2]=Nn.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 Mi{static MAX_CONCURRENT=24;static POINTS=8;static SEGMENTS=Mi.POINTS-1;static ACROSS=3;static VERTICES_PER_SEGMENT=(Mi.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=Mi.MAX_CONCURRENT*Mi.SEGMENTS*Mi.VERTICES_PER_SEGMENT;this.positions=new Float32Array(t*3),this.colors=new Float32Array(t*3);const e=new oe;e.setAttribute("position",new ee(this.positions,3)),e.setAttribute("color",new ee(this.colors,3)),e.setDrawRange(0,0),this.object=new Dt(e,new yn({vertexColors:!0,transparent:!0,blending:Oi,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=Ia.aliveAt(this.meteors,t).slice(0,Mi.MAX_CONCURRENT);let n=0;for(const{meteor:s,progress:a}of i){const o=this.radiantOf(s);if(!o)continue;const c=oi(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=_=>v*_**1.6,g=_=>this.onSphere(c,p,d+(u-d)*_),S=_=>Mi.RADIUS*((Mi.MIN_HALF_WIDTH_DEG+Mi.BRIGHT_HALF_WIDTH_DEG*s.brightness*_)*Math.PI/180);for(let _=1;_<Mi.POINTS;_++){const M=(_-1)/Mi.SEGMENTS,b=_/Mi.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=oi(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<Mi.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)*Mi.RADIUS,y:(t.y*s+e.y*a)*Mi.RADIUS,z:(t.z*s+e.z*a)*Mi.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 Pe{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??Pe.DEFAULT_DECK_THICKNESS_M),this.railHeight=e.railing?.heightM??Pe.DEFAULT_RAILING_HEIGHT_M,this.postSpacing=Math.max(.3,e.railing?.postSpacingM??Pe.DEFAULT_POST_SPACING_M),this.rails=Math.max(0,Math.round(e.railing?.rails??Pe.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(Pe.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(Pe.box(t+1,l,Pe.ABUTMENT_THICKNESS_M,0,l/2,c*(i-Pe.ABUTMENT_THICKNESS_M/2)))}}const s=[];this.span>0&&s.push(Pe.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-Pe.POST_SIDE_M)));return{concrete:Pe.merge(n),road:Pe.merge(s),earth:Pe.merge(a),railing:Pe.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+Pe.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 oe;return c.setAttribute("position",new ue(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 oe;return s.setAttribute("position",new ue(n,3)),s.computeVertexNormals(),s}stations(t){const e=[];for(let i=0;i<=Pe.BANK_STATIONS;i++)e.push(t*(this.span/2+this.bank*i/Pe.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=Pe.POST_SIDE_M;for(const o of n)s.push(Pe.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-Pe.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(Pe.beam(h,u))}}return s}static box(t,e,i,n,s,a){return new Vi(t,e,i).translate(n,s,a)}static beam(t,e){const i=new R().subVectors(e,t),n=new Vi(Pe.RAIL_DEPTH_M,Pe.RAIL_HEIGHT_M,i.length()),s=new ji().setFromUnitVectors(new R(0,0,1),i.clone().normalize()),a=new R().addVectors(t,e).multiplyScalar(.5);return n.applyMatrix4(new Zt().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 oe;o.setAttribute("position",new ue(n,3)),o.setAttribute("normal",new ue(s,3));for(const c of t)c.dispose();for(const c of e)c.dispose();return o}}const Yh=Math.PI/180;function Ne(r,t,e,i,n=!1){const s=n?new yn({color:new st(...e)}):new Ur({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 qh=.25,iw=.002,nw=100,sw=1500,aw=.25,rw=1e3,ow=.15;function cw(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 lw=[.32,.32,.3],D1=[1,.85,.5],hw=[.25,.25,.25],I1=[1,.97,.85],uw=[.55,.68,.72],Zn=.03,Jn=.05,C1={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 zi(r,t){return r?.[t]}function jn(r,t,e,i,n,s,a,o){if(o===void 0)return;const c=new Ur({color:new st(...uw),transparent:!0,opacity:o/100}),l=new Dt(new Vi(t,e,i),c);l.position.set(n,s,a),r.add(l)}const gn=.05,$h=[.6,.58,.53],tm=[.5,.5,.48];function gr(r,t,e,i,n,s,a,o){const c=new Ur({color:new st(...o),side:He}),l=new Dt(new Vi(t,e,i),c);l.position.set(n,s,a),r.add(l)}function dw(r,t,e,i,n,s,a,o,c){const l=(i-s)/2,h=(p,v,m,g)=>{p<=0||(t?gr(r,p,v,gn,m,o+g,a,c):gr(r,gn,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 P1(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?gr(r,v,u,gn,0,h,m,$h):gr(r,gn,u,v,m,h,0,$h):dw(r,p,v,u,f,s,m,h,$h)};d(a,!0,t*2,-e+gn),d(o,!0,t*2,e-gn),d(c,!1,e*2,-t+gn),d(l,!1,e*2,t-gn),gr(r,t*2,gn,e*2,0,i+gn,0,tm),gr(r,t*2,gn,e*2,0,n-gn,0,tm)}function Hd(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:-Qn};case"front-right":return{x:t-i,z:-Qn};case"behind-left":return{x:-(t-i),z:Qn};case"behind-right":return{x:t-i,z:Qn}}}function L1(r,t,e,i,n,s,a){const o=Wd();o.scale.setScalar(i),o.rotation.y=C1[t];const{x:c,z:l}=Hd(t,n,s,a);o.position.set(c,e,l),r.add(o)}const Gd=6,Vd=6,Ys=3,ao=1.4,ro=Ys*.5,O1=1.2,N1=.35,fw=.75,pw=1.6;function em(r,t,e,i){const n=new De,s=Math.max(1,r+1),a=s*Ys;Ne(n,new Vi(Gd,a,Vd),[.55,.54,.5],a/2);const o=Gd/2,c=Vd/2;for(let l=0;l<s;l++){const h=l*Ys+Ys/2;jn(n,ao,ro,Jn,0,h,-c-Zn,zi(t,"front")),jn(n,ao,ro,Jn,0,h,c+Zn,zi(t,"behind")),jn(n,Jn,ro,ao,-o-Zn,h,0,zi(t,"left")),jn(n,Jn,ro,ao,o+Zn,h,0,zi(t,"right"))}if(e){const l=Math.min(Math.max(i??0,0),s-1);L1(n,e,l*Ys,.72,o,c,O1);const h=u=>zi(t,u)!==void 0?[{main:ao,center:0}]:[];P1(n,o,c,l*Ys,(l+1)*Ys,ro,h("front"),h("behind"),h("left"),h("right"))}return n}function im(){const r=new De,t=[[0,0,.55,.5],[.4,.1,.35,.4],[-.35,-.2,.4,.38],[.1,-.4,.35,.36],[-.15,.4,.3,.34]];for(const[e,i,n,s]of t){const a=new si(n,10,7);a.scale(1,.85,1),a.translate(e,0,i),Ne(r,a,[.26,.28,.17],s)}return r}function mw(r){const t=new De,e=new Pe(ci.sizeOf(r),r.bridge).build();Ne(t,e.concrete,[.6,.6,.58],0);const i=Ne(t,e.road,[.2,.2,.21],0),n=Ne(t,e.earth,[.3,.36,.22],0);for(const s of[i,n])s.material.side=Ji;return Ne(t,e.railing,[.5,.52,.55],0),t}function nm(){const r=new De;return Ne(r,new os(.15,.22,2,8),[.32,.22,.14],1),Ne(r,new Fr(1.4,3,8),[.16,.32,.14],3.5),r}const sm=.275,gw=.35,vw=.9,Mw=34,xw=8,yw=1.4;function am(){const r=new De,t=new si(sm,7,3,0,Math.PI*2,0,Math.PI/2);t.scale(1,gw/sm,1);const e=ci.repeatOnGrid(t,Mw,vw,xw,yw),i=Ne(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 rm(){const r=new De,t=new si(1,7,3,0,Math.PI*2,0,Math.PI/2);return Ne(r,t,[.38,.36,.32],0),r}function om(r){const t=new De;return Ne(t,new os(.05,.08,5,8),[.28,.28,.3],2.5),Ne(t,new si(.25,12,8),r?D1:lw,5.1,!0),t}const _w=[.08,.08,.08],Gs=.8,hr=1,Xn=1.7,Kh=.6,ua=.4,Hc=1.2,cr=.7,Qn=.5,Sw=Xn;function cm(r,t,e){const i=new De;Ne(i,new Vi(1.8,1.4,4.2),[.45,.14,.14],.7),Ne(i,new Vi(Gs*2,Kh,hr*2),[.4,.12,.12],Xn);for(const s of[-1.4,1.4])for(const a of[-.95,.95]){const o=Ne(i,new os(.4,.4,.3,12),_w,.4);o.rotation.z=Math.PI/2,o.position.x=a,o.position.z=s}const n=r?I1:hw;for(const s of[-.7,.7])Ne(i,new si(.15,8,6),n,.7,!0).position.set(s,.7,-2.1);if(jn(i,Hc,ua,Jn,0,Xn,-hr-Zn,zi(t,"front")),jn(i,Hc,ua,Jn,0,Xn,hr+Zn,zi(t,"behind")),jn(i,Jn,ua,cr,-Gs-Zn,Xn,-Qn,zi(t,"front-left")),jn(i,Jn,ua,cr,-Gs-Zn,Xn,Qn,zi(t,"behind-left")),jn(i,Jn,ua,cr,Gs+Zn,Xn,-Qn,zi(t,"front-right")),jn(i,Jn,ua,cr,Gs+Zn,Xn,Qn,zi(t,"behind-right")),e){L1(i,e,fw,.5,Gs,hr,N1);const s=(c,l)=>{const h=[];return zi(t,c)!==void 0&&h.push({main:cr,center:-Qn}),zi(t,l)!==void 0&&h.push({main:cr,center:Qn}),h},a=zi(t,"front")!==void 0?[{main:Hc,center:0}]:[],o=zi(t,"behind")!==void 0?[{main:Hc,center:0}]:[];P1(i,Gs,hr,Xn-Kh/2,Xn+Kh/2,ua,a,o,s("front-left","behind-left"),s("front-right","behind-right"))}return i}const lm=new Map;function hm(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 Zh(r,t){return t>1e-6?r/t:1}const F1=[.95,.9,.82],um=[.72,.74,.78];function dm(){const r=new De;Ne(r,new os(.25,.3,1.5,10),um,.75),Ne(r,new si(.26,10,8),um,1.74);const t=Ne(r,new Fr(.07,.16,8),F1,1.74);return t.rotation.x=-Math.PI/2,t.position.z=-.22,r}function Wd(){const r=new De;Ne(r,new os(.25,.3,1.5,10),[.3,.3,.35],.75),Ne(r,new si(.22,10,8),[.62,.52,.46],1.72);const t=Ne(r,new Fr(.07,.16,8),F1,1.72);return t.rotation.x=-Math.PI/2,t.position.z=-.2,r}const bw=17,fm=18.5,Jh=[.16,.16,.18];function pm(){const r=new De,t=Ne(r,new os(1.8,1.8,fm*2,10),Jh,0);t.rotation.x=Math.PI/2,Ne(r,new Vi(bw*2,.5,4.5),Jh,0);const e=Ne(r,new Vi(.4,5.5,4),Jh,3);return e.position.z=-fm+2,r}class ci{static GROWS_FROM_GROUND=new Set(["tree","shrub","crop","mound"]);static groundUnderFootprint(t,e,i,n,s,a=0){const o=ci.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=ci.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"?Hd(e,Gs,hr,N1):Hd(e,Gd/2,Vd/2,O1),s=t.kind==="vehicle"?Sw:(t.occupiedFloor??0)*Ys+pw,a=(t.headingDeg??0)-C1[e]/Yh,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(ci.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 _=0;_<e;_++,m++){const M=v+S*s,b=p+_*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 oe;return g.setAttribute("position",new ue(u,3)),g.setAttribute("normal",new ue(d,3)),g.setIndex(new u0(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 Zt().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"?em(t.floors??q0,t.windows,t.observerSide,t.occupiedFloor):t.kind==="tree"?nm():t.kind==="shrub"?im():t.kind==="bridge"?mw(t):t.kind==="crop"?am():t.kind==="mound"?rm():t.kind==="streetlight"?om(e):t.kind==="vehicle"?cm(e,t.windows,t.observerSide):t.kind==="aircraft"?pm():t.kind==="entity"?dm():Wd();t.color&&this.paint(i,t.color);const n=this.scaleFor(t),s=new De;return i.name=ci.BODY_NAME,i.scale.copy(n),s.add(i),t.headingDeg!==void 0&&(s.rotation.y=-t.headingDeg*Yh),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:Zh(e.widthM,i.widthM),e.heightM===void 0?1:Zh(e.heightM,i.heightM),e.lengthM===void 0?1:Zh(e.lengthM,i.lengthM))}static naturalSize(t,e){const i=t==="building"?Math.max(1,(e??q0)+1):0;if(t==="bridge")return Pe.NATURAL_SIZE;const n=`${t}:${i}`,s=lm.get(n);if(s)return s;const a=t==="building"?em(i-1,void 0,void 0,void 0):t==="tree"?nm():t==="shrub"?im():t==="crop"?am():t==="mound"?rm():t==="streetlight"?om(!1):t==="vehicle"?cm(!1,void 0,void 0):t==="aircraft"?pm():t==="entity"?dm():Wd(),o=new Gi().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),lm.set(n,c),c}static usesModel(t){return t.model!==void 0&&!(t.observerSide!==void 0&&jm(t.kind))}static applyModel(t,e,i,n={}){const s=this.bodyOf(t),a=new De;a.name=ci.BODY_NAME,i.rotation.y=-(n.headingOffsetDeg??0)*Yh,i.updateMatrixWorld(!0);const o=new Gi().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=hm(e.sizeM,c)??hm(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=cw(i.color),s=Ne(t,new si(qh,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=iw){if(!e||e.length===0)return;const c=new Map(e.map(d=>[d.id,d])),l=Math.max(1,n*o/qh),h=qh*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?Qm(p,i,i+s):j1(p,i)?1:0;d.visible=v>0;const m=d.material,g=d.userData.lightColor;if(g){const S=v*nw*(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"?[sw,aw,D1]:[rw,ow,I1],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 jh="https://ufoathome.org/models/index.json";class ww{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??Ew()}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 Ew(){const r=`?v=${encodeURIComponent("0.75.1")}`,t=typeof location>"u"?void 0:new URL("/models/index.json",location.href).href;return(t&&t!==jh?[t,jh]:[jh]).map(e=>e+r)}const Aw=[{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 ww}];async function mm(r){const{GLTFLoader:t}=await es(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 U1=["ellipsoid","sphere","disc","cylinder","cone","box","torus","figure"];class cn{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 Wi(2,2),new ce({uniforms:{uColor:{value:new st(0,0,0)},uRadius:{value:1}},vertexShader:cn.VERTEX,fragmentShader:cn.FRAGMENT,transparent:!0,depthWrite:!1,blending:Oi,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*cn.MIN_ANGLE_RAD),a=cn.FILL*Math.PI*s*s;return{radiusM:s,luminanceCdM2:i*Math.min(cn.MAX_SHARE,e/a)}}static conserving(t){return Math.sqrt(t/(cn.MAX_SHARE*cn.FILL*Math.PI))}static VERTEX=`
|
|
6681
|
+
`,transparent:!0,blending:Oi,depthWrite:!1,side:He,fog:!1}),this.object=new Dt(new si(Ii.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)<Ii.ALTITUDE_STEP_DEG)||!(Math.abs(e-this.mappedAlignment)<Ii.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)<Ii.LEAP_ALTITUDE_DEG)||!(Math.abs(e-this.pendingAlignment)<Ii.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)<Ii.ALTITUDE_STEP_DEG&&Math.abs(e-this.pendingAlignment)<Ii.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?Ii.URGENT_BUDGET_MS:Ii.BUDGET_MS;do this.sky.trace(Ii.RAYS_PER_BATCH);while(this.sky.tracedRays<Ii.RAYS&&performance.now()-e<i);if(this.sky.tracedRays>=Ii.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]=Nn.toHalfFloat(e[n]),this.texels[i+1]=Nn.toHalfFloat(e[n+1]),this.texels[i+2]=Nn.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 Mi{static MAX_CONCURRENT=24;static POINTS=8;static SEGMENTS=Mi.POINTS-1;static ACROSS=3;static VERTICES_PER_SEGMENT=(Mi.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=Mi.MAX_CONCURRENT*Mi.SEGMENTS*Mi.VERTICES_PER_SEGMENT;this.positions=new Float32Array(t*3),this.colors=new Float32Array(t*3);const e=new oe;e.setAttribute("position",new ee(this.positions,3)),e.setAttribute("color",new ee(this.colors,3)),e.setDrawRange(0,0),this.object=new Dt(e,new yn({vertexColors:!0,transparent:!0,blending:Oi,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=Ia.aliveAt(this.meteors,t).slice(0,Mi.MAX_CONCURRENT);let n=0;for(const{meteor:s,progress:a}of i){const o=this.radiantOf(s);if(!o)continue;const c=oi(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=_=>v*_**1.6,g=_=>this.onSphere(c,p,d+(u-d)*_),S=_=>Mi.RADIUS*((Mi.MIN_HALF_WIDTH_DEG+Mi.BRIGHT_HALF_WIDTH_DEG*s.brightness*_)*Math.PI/180);for(let _=1;_<Mi.POINTS;_++){const M=(_-1)/Mi.SEGMENTS,b=_/Mi.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=oi(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<Mi.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)*Mi.RADIUS,y:(t.y*s+e.y*a)*Mi.RADIUS,z:(t.z*s+e.z*a)*Mi.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 Pe{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??Pe.DEFAULT_DECK_THICKNESS_M),this.railHeight=e.railing?.heightM??Pe.DEFAULT_RAILING_HEIGHT_M,this.postSpacing=Math.max(.3,e.railing?.postSpacingM??Pe.DEFAULT_POST_SPACING_M),this.rails=Math.max(0,Math.round(e.railing?.rails??Pe.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(Pe.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(Pe.box(t+1,l,Pe.ABUTMENT_THICKNESS_M,0,l/2,c*(i-Pe.ABUTMENT_THICKNESS_M/2)))}}const s=[];this.span>0&&s.push(Pe.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-Pe.POST_SIDE_M)));return{concrete:Pe.merge(n),road:Pe.merge(s),earth:Pe.merge(a),railing:Pe.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+Pe.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 oe;return c.setAttribute("position",new ue(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 oe;return s.setAttribute("position",new ue(n,3)),s.computeVertexNormals(),s}stations(t){const e=[];for(let i=0;i<=Pe.BANK_STATIONS;i++)e.push(t*(this.span/2+this.bank*i/Pe.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=Pe.POST_SIDE_M;for(const o of n)s.push(Pe.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-Pe.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(Pe.beam(h,u))}}return s}static box(t,e,i,n,s,a){return new Vi(t,e,i).translate(n,s,a)}static beam(t,e){const i=new R().subVectors(e,t),n=new Vi(Pe.RAIL_DEPTH_M,Pe.RAIL_HEIGHT_M,i.length()),s=new ji().setFromUnitVectors(new R(0,0,1),i.clone().normalize()),a=new R().addVectors(t,e).multiplyScalar(.5);return n.applyMatrix4(new Zt().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 oe;o.setAttribute("position",new ue(n,3)),o.setAttribute("normal",new ue(s,3));for(const c of t)c.dispose();for(const c of e)c.dispose();return o}}const Yh=Math.PI/180;function Ne(r,t,e,i,n=!1){const s=n?new yn({color:new st(...e)}):new Ur({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 qh=.25,iw=.002,nw=100,sw=1500,aw=.25,rw=1e3,ow=.15;function cw(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 lw=[.32,.32,.3],D1=[1,.85,.5],hw=[.25,.25,.25],I1=[1,.97,.85],uw=[.55,.68,.72],Zn=.03,Jn=.05,C1={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 zi(r,t){return r?.[t]}function jn(r,t,e,i,n,s,a,o){if(o===void 0)return;const c=new Ur({color:new st(...uw),transparent:!0,opacity:o/100}),l=new Dt(new Vi(t,e,i),c);l.position.set(n,s,a),r.add(l)}const gn=.05,$h=[.6,.58,.53],tm=[.5,.5,.48];function gr(r,t,e,i,n,s,a,o){const c=new Ur({color:new st(...o),side:He}),l=new Dt(new Vi(t,e,i),c);l.position.set(n,s,a),r.add(l)}function dw(r,t,e,i,n,s,a,o,c){const l=(i-s)/2,h=(p,v,m,g)=>{p<=0||(t?gr(r,p,v,gn,m,o+g,a,c):gr(r,gn,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 P1(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?gr(r,v,u,gn,0,h,m,$h):gr(r,gn,u,v,m,h,0,$h):dw(r,p,v,u,f,s,m,h,$h)};d(a,!0,t*2,-e+gn),d(o,!0,t*2,e-gn),d(c,!1,e*2,-t+gn),d(l,!1,e*2,t-gn),gr(r,t*2,gn,e*2,0,i+gn,0,tm),gr(r,t*2,gn,e*2,0,n-gn,0,tm)}function Hd(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:-Qn};case"front-right":return{x:t-i,z:-Qn};case"behind-left":return{x:-(t-i),z:Qn};case"behind-right":return{x:t-i,z:Qn}}}function L1(r,t,e,i,n,s,a){const o=Wd();o.scale.setScalar(i),o.rotation.y=C1[t];const{x:c,z:l}=Hd(t,n,s,a);o.position.set(c,e,l),r.add(o)}const Gd=6,Vd=6,Ys=3,ao=1.4,ro=Ys*.5,O1=1.2,N1=.35,fw=.75,pw=1.6;function em(r,t,e,i){const n=new De,s=Math.max(1,r+1),a=s*Ys;Ne(n,new Vi(Gd,a,Vd),[.55,.54,.5],a/2);const o=Gd/2,c=Vd/2;for(let l=0;l<s;l++){const h=l*Ys+Ys/2;jn(n,ao,ro,Jn,0,h,-c-Zn,zi(t,"front")),jn(n,ao,ro,Jn,0,h,c+Zn,zi(t,"behind")),jn(n,Jn,ro,ao,-o-Zn,h,0,zi(t,"left")),jn(n,Jn,ro,ao,o+Zn,h,0,zi(t,"right"))}if(e){const l=Math.min(Math.max(i??0,0),s-1);L1(n,e,l*Ys,.72,o,c,O1);const h=u=>zi(t,u)!==void 0?[{main:ao,center:0}]:[];P1(n,o,c,l*Ys,(l+1)*Ys,ro,h("front"),h("behind"),h("left"),h("right"))}return n}function im(){const r=new De,t=[[0,0,.55,.5],[.4,.1,.35,.4],[-.35,-.2,.4,.38],[.1,-.4,.35,.36],[-.15,.4,.3,.34]];for(const[e,i,n,s]of t){const a=new si(n,10,7);a.scale(1,.85,1),a.translate(e,0,i),Ne(r,a,[.26,.28,.17],s)}return r}function mw(r){const t=new De,e=new Pe(ci.sizeOf(r),r.bridge).build();Ne(t,e.concrete,[.6,.6,.58],0);const i=Ne(t,e.road,[.2,.2,.21],0),n=Ne(t,e.earth,[.3,.36,.22],0);for(const s of[i,n])s.material.side=Ji;return Ne(t,e.railing,[.5,.52,.55],0),t}function nm(){const r=new De;return Ne(r,new os(.15,.22,2,8),[.32,.22,.14],1),Ne(r,new Fr(1.4,3,8),[.16,.32,.14],3.5),r}const sm=.275,gw=.35,vw=.9,Mw=34,xw=8,yw=1.4;function am(){const r=new De,t=new si(sm,7,3,0,Math.PI*2,0,Math.PI/2);t.scale(1,gw/sm,1);const e=ci.repeatOnGrid(t,Mw,vw,xw,yw),i=Ne(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 rm(){const r=new De,t=new si(1,7,3,0,Math.PI*2,0,Math.PI/2);return Ne(r,t,[.38,.36,.32],0),r}function om(r){const t=new De;return Ne(t,new os(.05,.08,5,8),[.28,.28,.3],2.5),Ne(t,new si(.25,12,8),r?D1:lw,5.1,!0),t}const _w=[.08,.08,.08],Gs=.8,hr=1,Xn=1.7,Kh=.6,ua=.4,Hc=1.2,cr=.7,Qn=.5,Sw=Xn;function cm(r,t,e){const i=new De;Ne(i,new Vi(1.8,1.4,4.2),[.45,.14,.14],.7),Ne(i,new Vi(Gs*2,Kh,hr*2),[.4,.12,.12],Xn);for(const s of[-1.4,1.4])for(const a of[-.95,.95]){const o=Ne(i,new os(.4,.4,.3,12),_w,.4);o.rotation.z=Math.PI/2,o.position.x=a,o.position.z=s}const n=r?I1:hw;for(const s of[-.7,.7])Ne(i,new si(.15,8,6),n,.7,!0).position.set(s,.7,-2.1);if(jn(i,Hc,ua,Jn,0,Xn,-hr-Zn,zi(t,"front")),jn(i,Hc,ua,Jn,0,Xn,hr+Zn,zi(t,"behind")),jn(i,Jn,ua,cr,-Gs-Zn,Xn,-Qn,zi(t,"front-left")),jn(i,Jn,ua,cr,-Gs-Zn,Xn,Qn,zi(t,"behind-left")),jn(i,Jn,ua,cr,Gs+Zn,Xn,-Qn,zi(t,"front-right")),jn(i,Jn,ua,cr,Gs+Zn,Xn,Qn,zi(t,"behind-right")),e){L1(i,e,fw,.5,Gs,hr,N1);const s=(c,l)=>{const h=[];return zi(t,c)!==void 0&&h.push({main:cr,center:-Qn}),zi(t,l)!==void 0&&h.push({main:cr,center:Qn}),h},a=zi(t,"front")!==void 0?[{main:Hc,center:0}]:[],o=zi(t,"behind")!==void 0?[{main:Hc,center:0}]:[];P1(i,Gs,hr,Xn-Kh/2,Xn+Kh/2,ua,a,o,s("front-left","behind-left"),s("front-right","behind-right"))}return i}const lm=new Map;function hm(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 Zh(r,t){return t>1e-6?r/t:1}const F1=[.95,.9,.82],um=[.72,.74,.78];function dm(){const r=new De;Ne(r,new os(.25,.3,1.5,10),um,.75),Ne(r,new si(.26,10,8),um,1.74);const t=Ne(r,new Fr(.07,.16,8),F1,1.74);return t.rotation.x=-Math.PI/2,t.position.z=-.22,r}function Wd(){const r=new De;Ne(r,new os(.25,.3,1.5,10),[.3,.3,.35],.75),Ne(r,new si(.22,10,8),[.62,.52,.46],1.72);const t=Ne(r,new Fr(.07,.16,8),F1,1.72);return t.rotation.x=-Math.PI/2,t.position.z=-.2,r}const bw=17,fm=18.5,Jh=[.16,.16,.18];function pm(){const r=new De,t=Ne(r,new os(1.8,1.8,fm*2,10),Jh,0);t.rotation.x=Math.PI/2,Ne(r,new Vi(bw*2,.5,4.5),Jh,0);const e=Ne(r,new Vi(.4,5.5,4),Jh,3);return e.position.z=-fm+2,r}class ci{static GROWS_FROM_GROUND=new Set(["tree","shrub","crop","mound"]);static groundUnderFootprint(t,e,i,n,s,a=0){const o=ci.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=ci.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"?Hd(e,Gs,hr,N1):Hd(e,Gd/2,Vd/2,O1),s=t.kind==="vehicle"?Sw:(t.occupiedFloor??0)*Ys+pw,a=(t.headingDeg??0)-C1[e]/Yh,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(ci.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 _=0;_<e;_++,m++){const M=v+S*s,b=p+_*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 oe;return g.setAttribute("position",new ue(u,3)),g.setAttribute("normal",new ue(d,3)),g.setIndex(new u0(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 Zt().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"?em(t.floors??q0,t.windows,t.observerSide,t.occupiedFloor):t.kind==="tree"?nm():t.kind==="shrub"?im():t.kind==="bridge"?mw(t):t.kind==="crop"?am():t.kind==="mound"?rm():t.kind==="streetlight"?om(e):t.kind==="vehicle"?cm(e,t.windows,t.observerSide):t.kind==="aircraft"?pm():t.kind==="entity"?dm():Wd();t.color&&this.paint(i,t.color);const n=this.scaleFor(t),s=new De;return i.name=ci.BODY_NAME,i.scale.copy(n),s.add(i),t.headingDeg!==void 0&&(s.rotation.y=-t.headingDeg*Yh),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:Zh(e.widthM,i.widthM),e.heightM===void 0?1:Zh(e.heightM,i.heightM),e.lengthM===void 0?1:Zh(e.lengthM,i.lengthM))}static naturalSize(t,e){const i=t==="building"?Math.max(1,(e??q0)+1):0;if(t==="bridge")return Pe.NATURAL_SIZE;const n=`${t}:${i}`,s=lm.get(n);if(s)return s;const a=t==="building"?em(i-1,void 0,void 0,void 0):t==="tree"?nm():t==="shrub"?im():t==="crop"?am():t==="mound"?rm():t==="streetlight"?om(!1):t==="vehicle"?cm(!1,void 0,void 0):t==="aircraft"?pm():t==="entity"?dm():Wd(),o=new Gi().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),lm.set(n,c),c}static usesModel(t){return t.model!==void 0&&!(t.observerSide!==void 0&&jm(t.kind))}static applyModel(t,e,i,n={}){const s=this.bodyOf(t),a=new De;a.name=ci.BODY_NAME,i.rotation.y=-(n.headingOffsetDeg??0)*Yh,i.updateMatrixWorld(!0);const o=new Gi().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=hm(e.sizeM,c)??hm(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=cw(i.color),s=Ne(t,new si(qh,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=iw){if(!e||e.length===0)return;const c=new Map(e.map(d=>[d.id,d])),l=Math.max(1,n*o/qh),h=qh*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?Qm(p,i,i+s):j1(p,i)?1:0;d.visible=v>0;const m=d.material,g=d.userData.lightColor;if(g){const S=v*nw*(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"?[sw,aw,D1]:[rw,ow,I1],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 jh="https://ufoathome.org/models/index.json";class ww{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??Ew()}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 Ew(){const r=`?v=${encodeURIComponent("0.75.2")}`,t=typeof location>"u"?void 0:new URL("/models/index.json",location.href).href;return(t&&t!==jh?[t,jh]:[jh]).map(e=>e+r)}const Aw=[{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 ww}];async function mm(r){const{GLTFLoader:t}=await es(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 U1=["ellipsoid","sphere","disc","cylinder","cone","box","torus","figure"];class cn{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 Wi(2,2),new ce({uniforms:{uColor:{value:new st(0,0,0)},uRadius:{value:1}},vertexShader:cn.VERTEX,fragmentShader:cn.FRAGMENT,transparent:!0,depthWrite:!1,blending:Oi,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*cn.MIN_ANGLE_RAD),a=cn.FILL*Math.PI*s*s;return{radiusM:s,luminanceCdM2:i*Math.min(cn.MAX_SHARE,e/a)}}static conserving(t){return Math.sqrt(t/(cn.MAX_SHARE*cn.FILL*Math.PI))}static VERTEX=`
|
|
6682
6682
|
uniform float uRadius;
|
|
6683
6683
|
varying vec2 vOffset;
|
|
6684
6684
|
void main() {
|