@rr0/ufoathome 0.57.4 → 0.57.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-embed-sighting/SightingMessages_fr-D9EdTXgZ.js +1 -0
- package/dist-embed-sighting/rr0-sighting.mjs +3 -3
- package/dist-embed-sighting-editor/SightingEditorMessages_fr-Bc7zY0ZE.js +1 -0
- package/dist-embed-sighting-editor/rr0-sighting-editor.mjs +52 -21
- package/package.json +1 -1
- package/dist-embed-sighting/SightingMessages_fr-B3nfFBYj.js +0 -1
- package/dist-embed-sighting-editor/SightingEditorMessages_fr-DnwHxbSq.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const ym={cloudCover:0,cloudDarkness:0,precipitationType:"none",precipitationIntensity:0,windDirectionDeg:0,windSpeed:0,storm:!1};function _i(a){if(a.cloudLayers!==void 0)return a.cloudLayers;const e=[],t=a.lowerCloudCover??a.cloudCover;return t>0&&e.push({id:"lower",type:"cumulus",baseM:a.cloudBaseM??1e3,thicknessM:650,coverage:t,sizeM:1400,density:1,darkness:a.cloudDarkness}),(a.highCloudCover??0)>0&&e.push({id:"cirrus",type:"cirrus",baseM:8e3,thicknessM:400,coverage:a.highCloudCover,sizeM:2200,density:.35,darkness:a.cloudDarkness,iceCrystalAlignment:a.iceCrystalAlignment}),e}function pv(a,e,t,n,i,s){bm(a,e,t,r=>r.map(o=>o.id===n?i(o):o),s)}function bm(a,e,t,n,i){const s=r=>{const o=n(_i(r)),l=v=>1-o.filter(m=>m.type==="cirrus"===v).reduce((m,g)=>m*(1-g.coverage),1),c=l(!1),h=l(!0),d=o.filter(v=>v.coverage>0&&v.type!=="cirrus").map(v=>v.baseM),u=o.filter(v=>v.coverage>0||(v.instances?.length??0)>0),f=u.length?Math.max(...u.flatMap(v=>[v.darkness??r.cloudDarkness,...(v.instances??[]).map(m=>m.darkness??v.darkness??r.cloudDarkness)])):0,p=o.filter(v=>v.type==="cirrus"&&v.coverage>0).sort((v,m)=>m.coverage-v.coverage)[0];return{...r,cloudLayers:o,lowerCloudCover:c,highCloudCover:h,cloudDarkness:f,iceCrystalAlignment:p?.iceCrystalAlignment,cloudCover:1-(1-c)*(1-h),cloudBaseM:d.length?Math.min(...d):void 0}};if(i==="instant"||a.allKeyframes.length===0)a.addKeyframe(i==="observation"?0:t,s(a.getInterpolatedWeatherAt(t)??e));else for(const r of[...a.allKeyframes])a.addKeyframe(r.t,s(r.weather))}const xm=Math.PI/180,Al=111320;function un(a,e,t,n){const i=Al*Math.cos(t*xm),s=(a-t)*Al;return{x:(e-n)*i,z:-s}}function Wi(a,e,t,n){const i=Al*Math.cos(t*xm),s=-e,r=a;return{lat:t+s/Al,lng:n+r/i}}function Il(a,e,t,n,i,s){const r=n?.lat!==void 0&&n.lng!==void 0&&i?.lat!==void 0&&i.lng!==void 0?un(i.lat,i.lng,n.lat,n.lng):{x:0,z:0},o=Math.max(0,a),l=[0,...e.allKeyframes.map(c=>c.t).filter(c=>c>0&&c<o),o];for(let c=1;c<l.length;c++){const h=l[c-1],d=l[c]-h;if(d===0)continue;const u=32;for(let f=0;f<=u;f++){const p=e.getInterpolatedWeatherAt(h+d*f/u)??t,v=s===void 0?void 0:p.cloudLayers?.find(M=>M.id===s),m=(v?.windDirectionDeg??p.windDirectionDeg)*Math.PI/180,g=f===0||f===u?1:f%2===0?2:4,_=(v?.windSpeed??p.windSpeed)*d/1e3/u/3*g;r.x-=Math.sin(m)*_,r.z+=Math.cos(m)*_}}return r}class et{static MOON_ANGULAR_WIDTH_DEG=.5237;static CANVAS_WIDTH_PX=640;static CANVAS_HEIGHT_PX=360;static angularWidthDeg(e){return 2*Math.atan(e.sizeM/(2*e.distanceM))*180/Math.PI}static inMoons(e){return e/et.MOON_ANGULAR_WIDTH_DEG}static lerpAngular(e,t,n){if(!(!e||!t))return{widthDeg:e.widthDeg+(t.widthDeg-e.widthDeg)*n,heightDeg:e.heightDeg+(t.heightDeg-e.heightDeg)*n}}static sizeMAt(e,t){return 2*e*Math.tan(t*Math.PI/360)}static distanceMAt(e,t){return e/(2*Math.tan(t*Math.PI/360))}}function mv(a,e,t){if(!a||!e)return t<1?a:e;const n=((e.azimuthDeg-a.azimuthDeg)%360+540)%360-180;return{azimuthDeg:((a.azimuthDeg+n*t)%360+360)%360,altitudeDeg:a.altitudeDeg+(e.altitudeDeg-a.altitudeDeg)*t}}function gv(a,e="#39ff14"){return{kind:"oval",bounds:a,color:e,angle:0,transparency:0,haloScale:0,selected:!1}}function vv(a,e,t="#39ff14"){return{kind:"polygon",bounds:a,points:e,color:t,angle:0,transparency:0,haloScale:0,selected:!1}}function yv(a,e="#39ff14"){const{width:t,height:n}=a;return vv(a,[{x:0,y:0},{x:t,y:0},{x:t,y:n},{x:0,y:n}],e)}const bv={oval:gv,polygon:yv};function nf(a,e){return{...bv[e.presetId](a,e.color),transparency:e.transparency,haloScale:e.haloScale,blur:e.blur,brightness:e.brightness}}function xv(a,e,t){const{bounds:n}=a;return e>=n.x&&e<=n.x+n.width&&t>=n.y&&t<=n.y+n.height}function wm(a,e,t){const n=a.bounds.width,i=a.bounds.height;return{...a,bounds:{x:e-n/2,y:t-i/2,width:n,height:i}}}function Tn(a,e,t){return a+(e-a)*t}function sf(a){const e=/^#([0-9a-f]{6})$/i.exec(a);if(!e)return;const t=parseInt(e[1],16);return[t>>16&255,t>>8&255,t&255]}function wv(a){return`#${a.map(e=>Math.round(e).toString(16).padStart(2,"0")).join("")}`}function Mv(a,e,t){const n=sf(a),i=sf(e);return!n||!i?t<1?a:e:wv([Tn(n[0],i[0],t),Tn(n[1],i[1],t),Tn(n[2],i[2],t)])}function Sv(a,e,t){const n={x:Tn(a.bounds.x,e.bounds.x,t),y:Tn(a.bounds.y,e.bounds.y,t),width:Tn(a.bounds.width,e.bounds.width,t),height:Tn(a.bounds.height,e.bounds.height,t)},i=Tn(a.angle,e.angle,t),s=Tn(a.transparency,e.transparency,t),r=Tn(a.haloScale,e.haloScale,t),o=Tn(a.blur??0,e.blur??0,t),l=Tn(a.brightness??0,e.brightness??0,t),c=Mv(a.color,e.color,t),h=et.lerpAngular(a.angular,e.angular,t),d=mv(a.aim,e.aim,t);return a.kind==="polygon"&&e.kind==="polygon"&&a.points.length===e.points.length?{...a,bounds:n,angle:i,transparency:s,haloScale:r,blur:o,brightness:l,color:c,angular:h,aim:d,points:a.points.map((u,f)=>({x:Tn(u.x,e.points[f].x,t),y:Tn(u.y,e.points[f].y,t)}))}:{...t<1?a:e,bounds:n,angle:i,transparency:s,haloScale:r,blur:o,brightness:l,color:c,angular:h,aim:d}}class Jl{keyframes=[];order=[];groups=[];addKeyframe(e,t){const n=this.findInsertIndex(e);if(this.keyframes[n]?.t===e){const i=new Set(t.map(s=>s.sourceId));this.keyframes[n]={t:e,shapes:[...this.keyframes[n].shapes.filter(s=>!i.has(s.sourceId)),...t]}}else this.keyframes.splice(n,0,{t:e,shapes:[...t]});for(const i of t)this.order.includes(i.sourceId)||this.order.push(i.sourceId)}findInsertIndex(e){let t=0,n=this.keyframes.length;for(;t<n;){const i=t+n>>>1;this.keyframes[i].t<e?t=i+1:n=i}return t}getKeyframeAt(e){const t=this.findInsertIndex(e),n=this.keyframes[t];return n?.t===e?n:void 0}getShapeAt(e,t){return this.getKeyframeAt(e)?.shapes.find(n=>n.sourceId===t)?.shape}getLatestShapeAt(e,t){let n=this.findInsertIndex(e);for(this.keyframes[n]?.t!==e&&(n-=1);n>=0;n--){const i=this.keyframes[n].shapes.find(s=>s.sourceId===t);if(i)return i.shape}}getInterpolatedShapeAt(e,t){const n=this.findShapeAtOrBefore(e,t);if(n?.t===e)return n.shape;const i=this.findShapeAtOrAfter(e,t);return n?i?Sv(n.shape,i.shape,(e-n.t)/(i.t-n.t)):n.shape:i?.shape}findShapeAtOrBefore(e,t){let n=this.findInsertIndex(e);for(this.keyframes[n]?.t!==e&&(n-=1);n>=0;n--){const i=this.keyframes[n].shapes.find(s=>s.sourceId===t);if(i)return{t:this.keyframes[n].t,shape:i.shape}}}findShapeAtOrAfter(e,t){for(let n=this.findInsertIndex(e);n<this.keyframes.length;n++){const i=this.keyframes[n].shapes.find(s=>s.sourceId===t);if(i)return{t:this.keyframes[n].t,shape:i.shape}}}hitTest(e,t,n,i){const s=this.sourceIds;for(let r=s.length-1;r>=0;r--){if(i?.has(s[r]))continue;const o=this.getInterpolatedShapeAt(e,s[r]);if(o&&xv(o,t,n))return{sourceId:s[r],shape:o}}}removeSource(e){for(let t=this.keyframes.length-1;t>=0;t--){const n=this.keyframes[t].shapes.filter(i=>i.sourceId!==e);n.length===0?this.keyframes.splice(t,1):n.length!==this.keyframes[t].shapes.length&&(this.keyframes[t]={t:this.keyframes[t].t,shapes:n})}this.order=this.order.filter(t=>t!==e),this.removeFromGroup(e)}group(e){if(!(e.length<2)){for(const t of e)this.removeFromGroup(t);this.groups.push([...e])}}ungroup(e){const t=this.groups.findIndex(n=>n.includes(e));t!==-1&&this.groups.splice(t,1)}groupMembers(e){return this.groups.find(t=>t.includes(e))}removeFromGroup(e){const t=this.groups.findIndex(i=>i.includes(e));if(t===-1)return;const n=this.groups[t].filter(i=>i!==e);n.length<2?this.groups.splice(t,1):this.groups[t]=n}bringToFront(e){const t=this.order.indexOf(e);t!==-1&&(this.order.splice(t,1),this.order.push(e))}sendToBack(e){const t=this.order.indexOf(e);t!==-1&&(this.order.splice(t,1),this.order.unshift(e))}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(e){const t=new Jl;for(const n of e.keyframes)t.addKeyframe(n.t,n.shapes);if(e.order){const n=t.order.filter(i=>!e.order.includes(i));t.order=[...e.order,...n]}return e.groups&&(t.groups=e.groups.map(n=>n.filter(i=>t.order.includes(i))).filter(n=>n.length>=2)),t}}function _v(a,e,t){return Math.max(e,Math.min(t,a))}function Ev(a,e,t){const n=((e-a)%360+540)%360-180;return((a+n*t)%360+360)%360}function na(a,e,t){return a+(e-a)*t}function Tv(a,e,t){return{lat:a.lat===void 0||e.lat===void 0?void 0:na(a.lat,e.lat,t),lng:a.lng===void 0||e.lng===void 0?void 0:na(a.lng,e.lng,t),elevationM:na(a.elevationM,e.elevationM,t),headingDeg:a.headingDeg===void 0||e.headingDeg===void 0?void 0:Ev(a.headingDeg,e.headingDeg,t),pitchDeg:na(a.pitchDeg,e.pitchDeg,t),rollDeg:na(a.rollDeg??0,e.rollDeg??0,t),fovDeg:na(a.fovDeg,e.fovDeg,t),fNumber:a.fNumber,focusDistanceM:a.focusDistanceM}}class Yr{keyframes=[];addKeyframe(e,t){const n=this.findInsertIndex(e);this.keyframes[n]?.t===e?this.keyframes[n]={t:e,pose:t}:this.keyframes.splice(n,0,{t:e,pose:t})}clear(){this.keyframes.length=0}removeKeyframeAt(e){const t=this.findInsertIndex(e);this.keyframes[t]?.t===e&&this.keyframes.splice(t,1)}findInsertIndex(e){let t=0,n=this.keyframes.length;for(;t<n;){const i=t+n>>>1;this.keyframes[i].t<e?t=i+1:n=i}return t}getLatestPoseAt(e){let t=this.findInsertIndex(e);return this.keyframes[t]?.t!==e&&(t-=1),t>=0?this.keyframes[t].pose:void 0}getInterpolatedPoseAt(e){const t=this.findInsertIndex(e),n=this.keyframes[t]?.t===e?this.keyframes[t]:this.keyframes[t-1];if(n?.t===e)return n.pose;const i=this.keyframes[t]?.t===e?void 0:this.keyframes[t];return n?i?Tv(n.pose,i.pose,_v((e-n.t)/(i.t-n.t),0,1)):n.pose:i?.pose}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(e){const t=new Yr;for(const n of e.keyframes)t.addKeyframe(n.t,n.pose);return t}}function Tt(a,e,t){return a+(e-a)*t}function du(a,e,t){const n=((e-a)%360+540)%360-180;return((a+n*t)%360+360)%360}function Av(a,e,t){return Math.max(e,Math.min(t,a))}function Iv(a=[],e=[],t){if(!(!a.length&&!e.length))return[...new Set([...a.map(n=>n.id),...e.map(n=>n.id)])].map(n=>{const i=a.find(l=>l.id===n),s=e.find(l=>l.id===n),r=i??{...s,density:0},o=s??{...i,density:0};return{...r,eastM:Tt(r.eastM,o.eastM,t),northM:Tt(r.northM,o.northM,t),baseM:Tt(r.baseM,o.baseM,t),thicknessM:Tt(r.thicknessM,o.thicknessM,t),widthM:Tt(r.widthM,o.widthM,t),depthM:Tt(r.depthM,o.depthM,t),rotationDeg:du(r.rotationDeg,o.rotationDeg,t),density:Tt(r.density,o.density,t),darkness:Tt(r.darkness??0,o.darkness??0,t)}})}function Dv(a,e,t){if(a.cloudLayers===void 0&&e.cloudLayers===void 0)return;const n=_i(a),i=_i(e);return t>=1?i.map(r=>({...r})):[...new Set([...n.map(r=>r.id),...i.map(r=>r.id)])].map(r=>{const o=n.find(d=>d.id===r),l=i.find(d=>d.id===r),c=o??{...l,coverage:0},h=l??{...o,coverage:0};return{...c,instances:Iv(o?.instances,l?.instances,t),baseM:Tt(c.baseM,h.baseM,t),thicknessM:Tt(c.thicknessM,h.thicknessM,t),coverage:Tt(c.coverage,h.coverage,t),sizeM:Tt(c.sizeM,h.sizeM,t),density:Tt(c.density,h.density,t),darkness:Tt(c.darkness??a.cloudDarkness,h.darkness??e.cloudDarkness,t),iceCrystalAlignment:c.iceCrystalAlignment===void 0||h.iceCrystalAlignment===void 0?void 0:Tt(c.iceCrystalAlignment,h.iceCrystalAlignment,t),windSpeed:Tt(c.windSpeed??a.windSpeed,h.windSpeed??e.windSpeed,t),windDirectionDeg:du(c.windDirectionDeg??a.windDirectionDeg,h.windDirectionDeg??e.windDirectionDeg,t)}})}function Cv(a,e,t){return{cloudLayers:Dv(a,e,t),cloudCover:Tt(a.cloudCover,e.cloudCover,t),cloudDarkness:Tt(a.cloudDarkness,e.cloudDarkness,t),highCloudCover:a.highCloudCover===void 0||e.highCloudCover===void 0?void 0:Tt(a.highCloudCover,e.highCloudCover,t),iceCrystalAlignment:a.iceCrystalAlignment===void 0||e.iceCrystalAlignment===void 0?void 0:Tt(a.iceCrystalAlignment,e.iceCrystalAlignment,t),lowerCloudCover:a.lowerCloudCover===void 0||e.lowerCloudCover===void 0?void 0:Tt(a.lowerCloudCover,e.lowerCloudCover,t),cloudBaseM:a.cloudBaseM===void 0||e.cloudBaseM===void 0?void 0:Tt(a.cloudBaseM,e.cloudBaseM,t),precipitationType:t<1?a.precipitationType:e.precipitationType,precipitationIntensity:Tt(a.precipitationIntensity,e.precipitationIntensity,t),windDirectionDeg:du(a.windDirectionDeg,e.windDirectionDeg,t),windSpeed:Tt(a.windSpeed,e.windSpeed,t),storm:t<1?a.storm:e.storm}}class Kr{keyframes=[];addKeyframe(e,t){const n=this.findInsertIndex(e);this.keyframes[n]?.t===e?this.keyframes[n]={t:e,weather:t}:this.keyframes.splice(n,0,{t:e,weather:t})}clear(){this.keyframes.length=0}removeKeyframeAt(e){const t=this.findInsertIndex(e);this.keyframes[t]?.t===e&&this.keyframes.splice(t,1)}findInsertIndex(e){let t=0,n=this.keyframes.length;for(;t<n;){const i=t+n>>>1;this.keyframes[i].t<e?t=i+1:n=i}return t}getLatestWeatherAt(e){let t=this.findInsertIndex(e);return this.keyframes[t]?.t!==e&&(t-=1),t>=0?this.keyframes[t].weather:void 0}getInterpolatedWeatherAt(e){const t=this.findInsertIndex(e),n=this.keyframes[t]?.t===e?this.keyframes[t]:this.keyframes[t-1];if(n?.t===e)return n.weather;const i=this.keyframes[t]?.t===e?void 0:this.keyframes[t];return n?i?Cv(n.weather,i.weather,Av((e-n.t)/(i.t-n.t),0,1)):n.weather:i?.weather}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(e){const t=new Kr;for(const n of e.keyframes)t.addKeyframe(n.t,n.weather);return t}}class $r{keyframes=[];addKeyframe(e,t){const n=this.findInsertIndex(e);this.keyframes[n]?.t===e?this.keyframes[n]={t:e,sound:t}:this.keyframes.splice(n,0,{t:e,sound:t})}clear(){this.keyframes.length=0}removeKeyframeAt(e){const t=this.findInsertIndex(e);this.keyframes[t]?.t===e&&this.keyframes.splice(t,1)}getLatestSoundAt(e){let t=this.findInsertIndex(e);return this.keyframes[t]?.t!==e&&(t-=1),t>=0?this.keyframes[t].sound:void 0}getInterpolatedSoundAt(e){const t=this.findInsertIndex(e),n=this.keyframes[t]?.t===e?this.keyframes[t]:this.keyframes[t-1];if(n?.t===e)return n.sound;const i=this.keyframes[t]?.t===e?void 0:this.keyframes[t];if(!n)return i?.sound;if(!i)return n.sound;const s=(e-n.t)/(i.t-n.t);return this.lerp(n.sound,i.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(e){const t=new $r;for(const n of e.keyframes)t.addKeyframe(n.t,n.sound);return t}lerp(e,t,n){return{kind:n<1?e.kind:t.kind,volume:e.volume+(t.volume-e.volume)*n,pitchHz:e.pitchHz+(t.pitchHz-e.pitchHz)*n,src:n<1?e.src:t.src}}findInsertIndex(e){let t=0,n=this.keyframes.length;for(;t<n;){const i=t+n>>>1;this.keyframes[i].t<e?t=i+1:n=i}return t}}const Rv=["none","hum","whistle","rumble","crackle"],Pv=100,Lv={kind:"none",volume:0,pitchHz:Pv},po=[{id:"eye",name:{en:"Naked eye",fr:"Œil nu"},flare:0,projection:"equidistant",stabilization:.97},{id:"rectilinear-lens",name:{en:"Camera, unknown device",fr:"Appareil, modèle inconnu"},projection:"rectilinear",fNumber:8,fNumberRange:{min:2,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:8},apertureBlades:6},{id:"instamatic-126",name:{en:"Instamatic, 126 film",fr:"Instamatic, film 126"},projection:"rectilinear",frame:{widthMm:28,heightMm:28,focalLengthMm:43},fNumber:11,exposureSeconds:1/90,years:{from:1963,to:1988},apertureBlades:5,detailUm:20},{id:"slr-35mm-50",name:{en:"35 mm SLR, 50 mm lens",fr:"Reflex 35 mm, objectif 50 mm"},projection:"rectilinear",frame:{widthMm:36,heightMm:24,focalLengthMm:50},fNumber:8,fNumberRange:{min:2,max:16},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:3600},years:{from:1959},apertureBlades:6,detailUm:20},{id:"slr-35mm-zoom",name:{en:"35 mm SLR, 70-210 mm zoom",fr:"Reflex 35 mm, zoom 70-210 mm"},projection:"rectilinear",frame:{widthMm:36,heightMm:24,focalLengthMm:135,focalRangeMm:{minMm:70,maxMm:210}},fNumber:8,fNumberRange:{min:4,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:3600},apertureBlades:8,years:{from:1975},detailUm:20},{id:"phone-landscape",name:{en:"Phone, held sideways",fr:"Téléphone, tenu couché"},projection:"rectilinear",frame:{widthMm:7.6,heightMm:5.7,focalLengthMm:5.7},fNumber:1.8,exposureSeconds:1/120,exposureRangeSeconds:{min:1/8e3,max:10},years:{from:2007},apertureBlades:void 0,detailUm:1.4},{id:"phone-portrait",name:{en:"Phone, held upright",fr:"Téléphone, tenu debout"},projection:"rectilinear",frame:{widthMm:5.7,heightMm:7.6,focalLengthMm:5.7},fNumber:1.8,exposureSeconds:1/120,exposureRangeSeconds:{min:1/8e3,max:10},years:{from:2007},apertureBlades:void 0,detailUm:1.4}];class st{static get default(){return po[0]}static byId(e){return po.find(t=>t.id===e)??this.default}static UNAIDED_FIELD_DEG=60;static UNAIDED_ASPECT=16/9;static fieldOfViewDeg(e){const t=e.frame;return t?2*Math.atan(t.heightMm/(2*t.focalLengthMm))*180/Math.PI:st.UNAIDED_FIELD_DEG}static aspectOf(e){const t=e.frame;return t?t.widthMm/t.heightMm:st.UNAIDED_ASPECT}static frameWidthPx(e,t){return Math.round(t*st.aspectOf(e))}static availableAt(e){return e===void 0?po:po.filter(t=>!t.years||e>=t.years.from&&(t.years.to===void 0||e<=t.years.to))}static fieldOfViewDegAt(e,t){const n=e.frame;if(!(!n||t<=0))return 2*Math.atan(n.heightMm/(2*t))*180/Math.PI}static focalLengthMmFor(e,t){const n=e.frame;if(!(!n||t<=0||t>=180))return n.heightMm/(2*Math.tan(t*Math.PI/360))}static bladesShowing(e,t){const n=t??e.fNumber;if(n===void 0||e.apertureBlades===void 0)return 0;const i=e.fNumberRange;return!i||i.max<=i.min?1:Math.max(0,Math.min(1,(n-i.min)/(i.max-i.min)))}static LENS_FLARE_ARTIFACTS=1;static flareArtifactsOf(e){return e.flare??st.LENS_FLARE_ARTIFACTS}static starPointsOf(e){const t=e.apertureBlades;return t===void 0||t<3?0:t%2===0?t:t*2}}class On{constructor(e){this.entries=e}static empty(){return new On(new Map)}get size(){return this.entries.size}at(e){return this.entries.get(e)}paths(){return[...this.entries.keys()]}set(e,t){t.basis==="stated"&&t.rationale===void 0?this.entries.delete(e):this.entries.set(e,t)}clear(e){for(const t of this.entries.keys())(t===e||t.startsWith(`${e}.`))&&this.entries.delete(t)}static strip(e){const t=new On(new Map);return{recording:On.stripValue(e,[],t),provenance:t}}static restore(e,t){if(t.size===0)return e;const n=structuredClone(e);for(const i of t.paths()){const s=t.at(i),r=i.split("."),o=On.holderOf(n,r);if(!o)continue;const l=r[r.length-1],c=o[l];c!==void 0&&(s.of!==void 0&&JSON.stringify(s.of)!==JSON.stringify(c)||(o[l]={value:c,...s.basis==="stated"?{}:{basis:s.basis},...s.rationale===void 0?{}:{rationale:s.rationale}}))}return n}static isWrapper(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)&&"value"in e}static stripValue(e,t,n){return On.isWrapper(e)?(n.set(t.join("."),{basis:e.basis??"stated",...e.rationale===void 0?{}:{rationale:e.rationale},of:e.value}),On.stripValue(e.value,t,n)):Array.isArray(e)?e.map((i,s)=>On.stripValue(i,[...t,String(s)],n)):typeof e=="object"&&e!==null?Object.fromEntries(Object.entries(e).map(([i,s])=>[i,On.stripValue(s,[...t,i],n)])):e}static holderOf(e,t){let n=e;for(const i of t.slice(0,-1)){if(typeof n!="object"||n===null)return;n=n[i]}return typeof n=="object"&&n!==null?n:void 0}}const Nv=/^(?:(?<year>\d{4}|\d{3}X|\d{2}XX)(-(?<month>0[1-9]|1[0-2]))?(-(?<day>0[1-9]|[12]\d|3[01]))?(?:[T ](?<hour>[01]?\d|2[0-3]):(?<minute>[0-5]\d)(?::(?<second>[0-5]\d))?)?|(?<timeOnlyHour>[01]?\d|2[0-3]):(?<timeOnlyMinute>[0-5]\d)(?::(?<timeOnlySecond>[0-5]\d))?)[?~%]?$/;function af(a){const e=Nv.exec(a.trim());if(!e?.groups)return;const{year:t,month:n,day:i,hour:s,minute:r,second:o,timeOnlyHour:l,timeOnlyMinute:c,timeOnlySecond:h}=e.groups,d=s??l,u=r??c,f=o??h;return{year:t&&!t.includes("X")?Number(t):void 0,month:n?Number(n):void 0,day:i?Number(i):void 0,hour:d?Number(d):void 0,minute:u?Number(u):void 0,second:f?Number(f):void 0,raw:a.trim()}}function Dl(a){if(a.raw!==void 0)return a.raw;if(a.year===void 0){if(a.hour===void 0)return"";let t=`${String(a.hour).padStart(2,"0")}:${String(a.minute??0).padStart(2,"0")}`;return a.second!==void 0&&(t+=`:${String(a.second).padStart(2,"0")}`),t}let e=String(a.year).padStart(4,"0");return a.month===void 0||(e+=`-${String(a.month).padStart(2,"0")}`,a.day===void 0)||(e+=`-${String(a.day).padStart(2,"0")}`,a.hour===void 0)||(e+=`T${String(a.hour).padStart(2,"0")}:${String(a.minute??0).padStart(2,"0")}`,a.second!==void 0&&(e+=`:${String(a.second).padStart(2,"0")}`)),e}function Ph(a){if(a.year!==void 0)return Date.UTC(a.year,(a.month??1)-1,a.day??1,a.hour??0,a.minute??0,a.second??0)}function rf(a){return(((a.day??0)*24+(a.hour??0))*60+(a.minute??0))*6e4+(a.second??0)*1e3}const Ov=["year","month","day","hour","minute"],kv=["day","hour","minute"];function of(a,e){return e.filter(t=>a[t]!==void 0).join(",")}function ja(a){if(a.durationSeconds!==void 0)return a.durationSeconds*1e3;if(!a.time||!a.endTime)return;const e=a.time.year!==void 0&&a.endTime.year!==void 0,t=e?Ov:kv,n=of(a.time,t);if(!(n===""||n!==of(a.endTime,t)))return e?Ph(a.endTime)-Ph(a.time):rf(a.endTime)-rf(a.time)}function Fv(a){if(a.durationSeconds===void 0&&!(!a.time||!a.endTime))return ja(a)===void 0?"imprecise":void 0}class jl{constructor(e,t,n,i,s,r,o,l,c=[],h,d,u,f=[]){this.event=e,this.timeline=t,this.witnessTrack=n,this.weatherTrack=i,this.soundTrack=s,this.witness=r,this.caseId=o,this.weather=l,this.decor=c,this.weatherSource=h,this.instrumentId=d,this.exposureSeconds=u,this.milestones=f}provenance=On.empty();testimony;get witnessCount(){return 1+this.decor.filter(e=>e.kind==="witness").length}get exposure(){return this.exposureSeconds??this.instrument.exposureSeconds}get instrument(){return st.byId(this.instrumentId)}static create(e,t,n){return new jl({eventType:"sighting",time:e,place:t},new Jl,new Yr,new Kr,new $r,n)}}const Uv=0,Bv=0;function at(a,e){const t=a.witnessTrack.getInterpolatedPoseAt(e);if(t)return t;const n=a.event.place?.[0];if(n)return{lat:n.lat,lng:n.lng,elevationM:Uv,headingDeg:void 0,pitchDeg:Bv,fovDeg:st.fieldOfViewDeg(a.instrument)}}function Ht(a,e){return a.weatherTrack.getInterpolatedWeatherAt(e)??a.weather??ym}function uu(a,e){return a.soundTrack.getInterpolatedSoundAt(e)??Lv}function zv(a,e,t){const n=(o,l)=>o.x*l.x+o.y*l.y+o.z*l.z,i=n(t,a),s=n(e,a);if(i<=0||s<=.05)return;const r=i/s;return{x:e.x*r-a.x*i,y:e.y*r-a.y*i,z:e.z*r-a.z*i}}function Hv(a){const e=(n,i)=>a==="fr"?i:n,t=(n,i,s="",r="",o="")=>`<label>${i}<input id="${n}" type="number" step="any" ${s?`min="${s}"`:""} ${r?`max="${r}"`:""} placeholder="${o}"></label>`;return`<fieldset><legend>${e("Cloud layers","Couches nuageuses")}</legend>
|
|
1
|
+
const ym={cloudCover:0,cloudDarkness:0,precipitationType:"none",precipitationIntensity:0,windDirectionDeg:0,windSpeed:0,storm:!1};function _i(a){if(a.cloudLayers!==void 0)return a.cloudLayers;const e=[],t=a.lowerCloudCover??a.cloudCover;return t>0&&e.push({id:"lower",type:"cumulus",baseM:a.cloudBaseM??1e3,thicknessM:650,coverage:t,sizeM:1400,density:1,darkness:a.cloudDarkness}),(a.highCloudCover??0)>0&&e.push({id:"cirrus",type:"cirrus",baseM:8e3,thicknessM:400,coverage:a.highCloudCover,sizeM:2200,density:.35,darkness:a.cloudDarkness,iceCrystalAlignment:a.iceCrystalAlignment}),e}function pv(a,e,t,n,i,s){bm(a,e,t,r=>r.map(o=>o.id===n?i(o):o),s)}function bm(a,e,t,n,i){const s=r=>{const o=n(_i(r)),l=v=>1-o.filter(m=>m.type==="cirrus"===v).reduce((m,g)=>m*(1-g.coverage),1),c=l(!1),h=l(!0),d=o.filter(v=>v.coverage>0&&v.type!=="cirrus").map(v=>v.baseM),u=o.filter(v=>v.coverage>0||(v.instances?.length??0)>0),f=u.length?Math.max(...u.flatMap(v=>[v.darkness??r.cloudDarkness,...(v.instances??[]).map(m=>m.darkness??v.darkness??r.cloudDarkness)])):0,p=o.filter(v=>v.type==="cirrus"&&v.coverage>0).sort((v,m)=>m.coverage-v.coverage)[0];return{...r,cloudLayers:o,lowerCloudCover:c,highCloudCover:h,cloudDarkness:f,iceCrystalAlignment:p?.iceCrystalAlignment,cloudCover:1-(1-c)*(1-h),cloudBaseM:d.length?Math.min(...d):void 0}};if(i==="instant"||a.allKeyframes.length===0)a.addKeyframe(i==="observation"?0:t,s(a.getInterpolatedWeatherAt(t)??e));else for(const r of[...a.allKeyframes])a.addKeyframe(r.t,s(r.weather))}const xm=Math.PI/180,Al=111320;function un(a,e,t,n){const i=Al*Math.cos(t*xm),s=(a-t)*Al;return{x:(e-n)*i,z:-s}}function Wi(a,e,t,n){const i=Al*Math.cos(t*xm),s=-e,r=a;return{lat:t+s/Al,lng:n+r/i}}function Il(a,e,t,n,i,s){const r=n?.lat!==void 0&&n.lng!==void 0&&i?.lat!==void 0&&i.lng!==void 0?un(i.lat,i.lng,n.lat,n.lng):{x:0,z:0},o=Math.max(0,a),l=[0,...e.allKeyframes.map(c=>c.t).filter(c=>c>0&&c<o),o];for(let c=1;c<l.length;c++){const h=l[c-1],d=l[c]-h;if(d===0)continue;const u=32;for(let f=0;f<=u;f++){const p=e.getInterpolatedWeatherAt(h+d*f/u)??t,v=s===void 0?void 0:p.cloudLayers?.find(M=>M.id===s),m=(v?.windDirectionDeg??p.windDirectionDeg)*Math.PI/180,g=f===0||f===u?1:f%2===0?2:4,_=(v?.windSpeed??p.windSpeed)*d/1e3/u/3*g;r.x-=Math.sin(m)*_,r.z+=Math.cos(m)*_}}return r}class et{static MOON_ANGULAR_WIDTH_DEG=.5237;static CANVAS_WIDTH_PX=640;static CANVAS_HEIGHT_PX=360;static angularWidthDeg(e){return 2*Math.atan(e.sizeM/(2*e.distanceM))*180/Math.PI}static inMoons(e){return e/et.MOON_ANGULAR_WIDTH_DEG}static lerpAngular(e,t,n){if(!(!e||!t))return{widthDeg:e.widthDeg+(t.widthDeg-e.widthDeg)*n,heightDeg:e.heightDeg+(t.heightDeg-e.heightDeg)*n}}static sizeMAt(e,t){return 2*e*Math.tan(t*Math.PI/360)}static distanceMAt(e,t){return e/(2*Math.tan(t*Math.PI/360))}}function mv(a,e,t){if(!a||!e)return t<1?a:e;const n=((e.azimuthDeg-a.azimuthDeg)%360+540)%360-180;return{azimuthDeg:((a.azimuthDeg+n*t)%360+360)%360,altitudeDeg:a.altitudeDeg+(e.altitudeDeg-a.altitudeDeg)*t}}function gv(a,e="#39ff14"){return{kind:"oval",bounds:a,color:e,angle:0,transparency:0,haloScale:0,selected:!1}}function vv(a,e,t="#39ff14"){return{kind:"polygon",bounds:a,points:e,color:t,angle:0,transparency:0,haloScale:0,selected:!1}}function yv(a,e="#39ff14"){const{width:t,height:n}=a;return vv(a,[{x:0,y:0},{x:t,y:0},{x:t,y:n},{x:0,y:n}],e)}const bv={oval:gv,polygon:yv};function nf(a,e){return{...bv[e.presetId](a,e.color),transparency:e.transparency,haloScale:e.haloScale,blur:e.blur,brightness:e.brightness}}function xv(a,e,t){const{bounds:n}=a;return e>=n.x&&e<=n.x+n.width&&t>=n.y&&t<=n.y+n.height}function wm(a,e,t){const n=a.bounds.width,i=a.bounds.height;return{...a,bounds:{x:e-n/2,y:t-i/2,width:n,height:i}}}function Tn(a,e,t){return a+(e-a)*t}function sf(a){const e=/^#([0-9a-f]{6})$/i.exec(a);if(!e)return;const t=parseInt(e[1],16);return[t>>16&255,t>>8&255,t&255]}function wv(a){return`#${a.map(e=>Math.round(e).toString(16).padStart(2,"0")).join("")}`}function Mv(a,e,t){const n=sf(a),i=sf(e);return!n||!i?t<1?a:e:wv([Tn(n[0],i[0],t),Tn(n[1],i[1],t),Tn(n[2],i[2],t)])}function Sv(a,e,t){const n={x:Tn(a.bounds.x,e.bounds.x,t),y:Tn(a.bounds.y,e.bounds.y,t),width:Tn(a.bounds.width,e.bounds.width,t),height:Tn(a.bounds.height,e.bounds.height,t)},i=Tn(a.angle,e.angle,t),s=Tn(a.transparency,e.transparency,t),r=Tn(a.haloScale,e.haloScale,t),o=Tn(a.blur??0,e.blur??0,t),l=Tn(a.brightness??0,e.brightness??0,t),c=Mv(a.color,e.color,t),h=et.lerpAngular(a.angular,e.angular,t),d=mv(a.aim,e.aim,t);return a.kind==="polygon"&&e.kind==="polygon"&&a.points.length===e.points.length?{...a,bounds:n,angle:i,transparency:s,haloScale:r,blur:o,brightness:l,color:c,angular:h,aim:d,points:a.points.map((u,f)=>({x:Tn(u.x,e.points[f].x,t),y:Tn(u.y,e.points[f].y,t)}))}:{...t<1?a:e,bounds:n,angle:i,transparency:s,haloScale:r,blur:o,brightness:l,color:c,angular:h,aim:d}}class Jl{keyframes=[];order=[];groups=[];addKeyframe(e,t){const n=this.findInsertIndex(e);if(this.keyframes[n]?.t===e){const i=new Set(t.map(s=>s.sourceId));this.keyframes[n]={t:e,shapes:[...this.keyframes[n].shapes.filter(s=>!i.has(s.sourceId)),...t]}}else this.keyframes.splice(n,0,{t:e,shapes:[...t]});for(const i of t)this.order.includes(i.sourceId)||this.order.push(i.sourceId)}findInsertIndex(e){let t=0,n=this.keyframes.length;for(;t<n;){const i=t+n>>>1;this.keyframes[i].t<e?t=i+1:n=i}return t}getKeyframeAt(e){const t=this.findInsertIndex(e),n=this.keyframes[t];return n?.t===e?n:void 0}getShapeAt(e,t){return this.getKeyframeAt(e)?.shapes.find(n=>n.sourceId===t)?.shape}getLatestShapeAt(e,t){let n=this.findInsertIndex(e);for(this.keyframes[n]?.t!==e&&(n-=1);n>=0;n--){const i=this.keyframes[n].shapes.find(s=>s.sourceId===t);if(i)return i.shape}}getInterpolatedShapeAt(e,t){const n=this.findShapeAtOrBefore(e,t);if(n?.t===e)return n.shape;const i=this.findShapeAtOrAfter(e,t);return n?i?Sv(n.shape,i.shape,(e-n.t)/(i.t-n.t)):n.shape:i?.shape}findShapeAtOrBefore(e,t){let n=this.findInsertIndex(e);for(this.keyframes[n]?.t!==e&&(n-=1);n>=0;n--){const i=this.keyframes[n].shapes.find(s=>s.sourceId===t);if(i)return{t:this.keyframes[n].t,shape:i.shape}}}findShapeAtOrAfter(e,t){for(let n=this.findInsertIndex(e);n<this.keyframes.length;n++){const i=this.keyframes[n].shapes.find(s=>s.sourceId===t);if(i)return{t:this.keyframes[n].t,shape:i.shape}}}hitTest(e,t,n,i){const s=this.sourceIds;for(let r=s.length-1;r>=0;r--){if(i?.has(s[r]))continue;const o=this.getInterpolatedShapeAt(e,s[r]);if(o&&xv(o,t,n))return{sourceId:s[r],shape:o}}}removeSource(e){for(let t=this.keyframes.length-1;t>=0;t--){const n=this.keyframes[t].shapes.filter(i=>i.sourceId!==e);n.length===0?this.keyframes.splice(t,1):n.length!==this.keyframes[t].shapes.length&&(this.keyframes[t]={t:this.keyframes[t].t,shapes:n})}this.order=this.order.filter(t=>t!==e),this.removeFromGroup(e)}group(e){if(!(e.length<2)){for(const t of e)this.removeFromGroup(t);this.groups.push([...e])}}ungroup(e){const t=this.groups.findIndex(n=>n.includes(e));t!==-1&&this.groups.splice(t,1)}groupMembers(e){return this.groups.find(t=>t.includes(e))}removeFromGroup(e){const t=this.groups.findIndex(i=>i.includes(e));if(t===-1)return;const n=this.groups[t].filter(i=>i!==e);n.length<2?this.groups.splice(t,1):this.groups[t]=n}bringToFront(e){const t=this.order.indexOf(e);t!==-1&&(this.order.splice(t,1),this.order.push(e))}sendToBack(e){const t=this.order.indexOf(e);t!==-1&&(this.order.splice(t,1),this.order.unshift(e))}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(e){const t=new Jl;for(const n of e.keyframes)t.addKeyframe(n.t,n.shapes);if(e.order){const n=t.order.filter(i=>!e.order.includes(i));t.order=[...e.order,...n]}return e.groups&&(t.groups=e.groups.map(n=>n.filter(i=>t.order.includes(i))).filter(n=>n.length>=2)),t}}function _v(a,e,t){return Math.max(e,Math.min(t,a))}function Ev(a,e,t){const n=((e-a)%360+540)%360-180;return((a+n*t)%360+360)%360}function na(a,e,t){return a+(e-a)*t}function Tv(a,e,t){return{lat:a.lat===void 0||e.lat===void 0?void 0:na(a.lat,e.lat,t),lng:a.lng===void 0||e.lng===void 0?void 0:na(a.lng,e.lng,t),elevationM:na(a.elevationM,e.elevationM,t),headingDeg:a.headingDeg===void 0||e.headingDeg===void 0?void 0:Ev(a.headingDeg,e.headingDeg,t),pitchDeg:na(a.pitchDeg,e.pitchDeg,t),rollDeg:na(a.rollDeg??0,e.rollDeg??0,t),fovDeg:na(a.fovDeg,e.fovDeg,t),fNumber:a.fNumber,focusDistanceM:a.focusDistanceM}}class Yr{keyframes=[];addKeyframe(e,t){const n=this.findInsertIndex(e);this.keyframes[n]?.t===e?this.keyframes[n]={t:e,pose:t}:this.keyframes.splice(n,0,{t:e,pose:t})}clear(){this.keyframes.length=0}removeKeyframeAt(e){const t=this.findInsertIndex(e);this.keyframes[t]?.t===e&&this.keyframes.splice(t,1)}findInsertIndex(e){let t=0,n=this.keyframes.length;for(;t<n;){const i=t+n>>>1;this.keyframes[i].t<e?t=i+1:n=i}return t}getLatestPoseAt(e){let t=this.findInsertIndex(e);return this.keyframes[t]?.t!==e&&(t-=1),t>=0?this.keyframes[t].pose:void 0}getInterpolatedPoseAt(e){const t=this.findInsertIndex(e),n=this.keyframes[t]?.t===e?this.keyframes[t]:this.keyframes[t-1];if(n?.t===e)return n.pose;const i=this.keyframes[t]?.t===e?void 0:this.keyframes[t];return n?i?Tv(n.pose,i.pose,_v((e-n.t)/(i.t-n.t),0,1)):n.pose:i?.pose}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(e){const t=new Yr;for(const n of e.keyframes)t.addKeyframe(n.t,n.pose);return t}}function Tt(a,e,t){return a+(e-a)*t}function du(a,e,t){const n=((e-a)%360+540)%360-180;return((a+n*t)%360+360)%360}function Av(a,e,t){return Math.max(e,Math.min(t,a))}function Iv(a=[],e=[],t){if(!(!a.length&&!e.length))return[...new Set([...a.map(n=>n.id),...e.map(n=>n.id)])].map(n=>{const i=a.find(l=>l.id===n),s=e.find(l=>l.id===n),r=i??{...s,density:0},o=s??{...i,density:0};return{...r,eastM:Tt(r.eastM,o.eastM,t),northM:Tt(r.northM,o.northM,t),baseM:Tt(r.baseM,o.baseM,t),thicknessM:Tt(r.thicknessM,o.thicknessM,t),widthM:Tt(r.widthM,o.widthM,t),depthM:Tt(r.depthM,o.depthM,t),rotationDeg:du(r.rotationDeg,o.rotationDeg,t),density:Tt(r.density,o.density,t),darkness:Tt(r.darkness??0,o.darkness??0,t)}})}function Dv(a,e,t){if(a.cloudLayers===void 0&&e.cloudLayers===void 0)return;const n=_i(a),i=_i(e);return t>=1?i.map(r=>({...r})):[...new Set([...n.map(r=>r.id),...i.map(r=>r.id)])].map(r=>{const o=n.find(d=>d.id===r),l=i.find(d=>d.id===r),c=o??{...l,coverage:0},h=l??{...o,coverage:0};return{...c,instances:Iv(o?.instances,l?.instances,t),baseM:Tt(c.baseM,h.baseM,t),thicknessM:Tt(c.thicknessM,h.thicknessM,t),coverage:Tt(c.coverage,h.coverage,t),sizeM:Tt(c.sizeM,h.sizeM,t),density:Tt(c.density,h.density,t),darkness:Tt(c.darkness??a.cloudDarkness,h.darkness??e.cloudDarkness,t),iceCrystalAlignment:c.iceCrystalAlignment===void 0||h.iceCrystalAlignment===void 0?void 0:Tt(c.iceCrystalAlignment,h.iceCrystalAlignment,t),windSpeed:Tt(c.windSpeed??a.windSpeed,h.windSpeed??e.windSpeed,t),windDirectionDeg:du(c.windDirectionDeg??a.windDirectionDeg,h.windDirectionDeg??e.windDirectionDeg,t)}})}function Cv(a,e,t){return{cloudLayers:Dv(a,e,t),cloudCover:Tt(a.cloudCover,e.cloudCover,t),cloudDarkness:Tt(a.cloudDarkness,e.cloudDarkness,t),highCloudCover:a.highCloudCover===void 0||e.highCloudCover===void 0?void 0:Tt(a.highCloudCover,e.highCloudCover,t),iceCrystalAlignment:a.iceCrystalAlignment===void 0||e.iceCrystalAlignment===void 0?void 0:Tt(a.iceCrystalAlignment,e.iceCrystalAlignment,t),lowerCloudCover:a.lowerCloudCover===void 0||e.lowerCloudCover===void 0?void 0:Tt(a.lowerCloudCover,e.lowerCloudCover,t),cloudBaseM:a.cloudBaseM===void 0||e.cloudBaseM===void 0?void 0:Tt(a.cloudBaseM,e.cloudBaseM,t),precipitationType:t<1?a.precipitationType:e.precipitationType,precipitationIntensity:Tt(a.precipitationIntensity,e.precipitationIntensity,t),windDirectionDeg:du(a.windDirectionDeg,e.windDirectionDeg,t),windSpeed:Tt(a.windSpeed,e.windSpeed,t),storm:t<1?a.storm:e.storm}}class Kr{keyframes=[];addKeyframe(e,t){const n=this.findInsertIndex(e);this.keyframes[n]?.t===e?this.keyframes[n]={t:e,weather:t}:this.keyframes.splice(n,0,{t:e,weather:t})}clear(){this.keyframes.length=0}removeKeyframeAt(e){const t=this.findInsertIndex(e);this.keyframes[t]?.t===e&&this.keyframes.splice(t,1)}findInsertIndex(e){let t=0,n=this.keyframes.length;for(;t<n;){const i=t+n>>>1;this.keyframes[i].t<e?t=i+1:n=i}return t}getLatestWeatherAt(e){let t=this.findInsertIndex(e);return this.keyframes[t]?.t!==e&&(t-=1),t>=0?this.keyframes[t].weather:void 0}getInterpolatedWeatherAt(e){const t=this.findInsertIndex(e),n=this.keyframes[t]?.t===e?this.keyframes[t]:this.keyframes[t-1];if(n?.t===e)return n.weather;const i=this.keyframes[t]?.t===e?void 0:this.keyframes[t];return n?i?Cv(n.weather,i.weather,Av((e-n.t)/(i.t-n.t),0,1)):n.weather:i?.weather}get duration(){return this.keyframes.length===0?0:this.keyframes[this.keyframes.length-1].t}get allKeyframes(){return this.keyframes}toJSON(){return{keyframes:this.keyframes}}static fromJSON(e){const t=new Kr;for(const n of e.keyframes)t.addKeyframe(n.t,n.weather);return t}}class $r{keyframes=[];addKeyframe(e,t){const n=this.findInsertIndex(e);this.keyframes[n]?.t===e?this.keyframes[n]={t:e,sound:t}:this.keyframes.splice(n,0,{t:e,sound:t})}clear(){this.keyframes.length=0}removeKeyframeAt(e){const t=this.findInsertIndex(e);this.keyframes[t]?.t===e&&this.keyframes.splice(t,1)}getLatestSoundAt(e){let t=this.findInsertIndex(e);return this.keyframes[t]?.t!==e&&(t-=1),t>=0?this.keyframes[t].sound:void 0}getInterpolatedSoundAt(e){const t=this.findInsertIndex(e),n=this.keyframes[t]?.t===e?this.keyframes[t]:this.keyframes[t-1];if(n?.t===e)return n.sound;const i=this.keyframes[t]?.t===e?void 0:this.keyframes[t];if(!n)return i?.sound;if(!i)return n.sound;const s=(e-n.t)/(i.t-n.t);return this.lerp(n.sound,i.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(e){const t=new $r;for(const n of e.keyframes)t.addKeyframe(n.t,n.sound);return t}lerp(e,t,n){return{kind:n<1?e.kind:t.kind,volume:e.volume+(t.volume-e.volume)*n,pitchHz:e.pitchHz+(t.pitchHz-e.pitchHz)*n,src:n<1?e.src:t.src}}findInsertIndex(e){let t=0,n=this.keyframes.length;for(;t<n;){const i=t+n>>>1;this.keyframes[i].t<e?t=i+1:n=i}return t}}const Rv=["none","hum","whistle","rumble","crackle"],Pv=100,Lv={kind:"none",volume:0,pitchHz:Pv},po=[{id:"eye",name:{en:"Naked eye",fr:"Œil nu"},flare:0,projection:"equidistant",stabilization:.97},{id:"rectilinear-lens",name:{en:"Camera, unknown device",fr:"Appareil, modèle inconnu"},projection:"rectilinear",fNumber:8,fNumberRange:{min:2,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:8},apertureBlades:6},{id:"instamatic-126",name:{en:"Instamatic, 126 film",fr:"Instamatic, film 126"},projection:"rectilinear",frame:{widthMm:28,heightMm:28,focalLengthMm:43},fNumber:11,exposureSeconds:1/90,years:{from:1963,to:1988},apertureBlades:5,detailUm:20},{id:"slr-35mm-50",name:{en:"35 mm SLR, 50 mm lens",fr:"Reflex 35 mm, objectif 50 mm"},projection:"rectilinear",frame:{widthMm:36,heightMm:24,focalLengthMm:50},fNumber:8,fNumberRange:{min:2,max:16},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:3600},years:{from:1959},apertureBlades:6,detailUm:20},{id:"slr-35mm-zoom",name:{en:"35 mm SLR, 70-210 mm zoom",fr:"Reflex 35 mm, zoom 70-210 mm"},projection:"rectilinear",frame:{widthMm:36,heightMm:24,focalLengthMm:135,focalRangeMm:{minMm:70,maxMm:210}},fNumber:8,fNumberRange:{min:4,max:22},exposureSeconds:1/250,exposureRangeSeconds:{min:1/1e3,max:3600},apertureBlades:8,years:{from:1975},detailUm:20},{id:"phone-landscape",name:{en:"Phone, held sideways",fr:"Téléphone, tenu couché"},projection:"rectilinear",frame:{widthMm:7.6,heightMm:5.7,focalLengthMm:5.7},fNumber:1.8,exposureSeconds:1/120,exposureRangeSeconds:{min:1/8e3,max:10},years:{from:2007},apertureBlades:void 0,detailUm:1.4},{id:"phone-portrait",name:{en:"Phone, held upright",fr:"Téléphone, tenu debout"},projection:"rectilinear",frame:{widthMm:5.7,heightMm:7.6,focalLengthMm:5.7},fNumber:1.8,exposureSeconds:1/120,exposureRangeSeconds:{min:1/8e3,max:10},years:{from:2007},apertureBlades:void 0,detailUm:1.4}];class st{static get default(){return po[0]}static byId(e){return po.find(t=>t.id===e)??this.default}static UNAIDED_FIELD_DEG=60;static UNAIDED_ASPECT=16/9;static fieldOfViewDeg(e){const t=e.frame;return t?2*Math.atan(t.heightMm/(2*t.focalLengthMm))*180/Math.PI:st.UNAIDED_FIELD_DEG}static aspectOf(e){const t=e.frame;return t?t.widthMm/t.heightMm:st.UNAIDED_ASPECT}static frameWidthPx(e,t){return Math.round(t*st.aspectOf(e))}static availableAt(e){return e===void 0?po:po.filter(t=>!t.years||e>=t.years.from&&(t.years.to===void 0||e<=t.years.to))}static fieldOfViewDegAt(e,t){const n=e.frame;if(!(!n||t<=0))return 2*Math.atan(n.heightMm/(2*t))*180/Math.PI}static focalLengthMmFor(e,t){const n=e.frame;if(!(!n||t<=0||t>=180))return n.heightMm/(2*Math.tan(t*Math.PI/360))}static bladesShowing(e,t){const n=t??e.fNumber;if(n===void 0||e.apertureBlades===void 0)return 0;const i=e.fNumberRange;return!i||i.max<=i.min?1:Math.max(0,Math.min(1,(n-i.min)/(i.max-i.min)))}static LENS_FLARE_ARTIFACTS=1;static flareArtifactsOf(e){return e.flare??st.LENS_FLARE_ARTIFACTS}static starPointsOf(e){const t=e.apertureBlades;return t===void 0||t<3?0:t%2===0?t:t*2}}class On{constructor(e){this.entries=e}static empty(){return new On(new Map)}get size(){return this.entries.size}at(e){return this.entries.get(e)}paths(){return[...this.entries.keys()]}set(e,t){t.basis==="stated"&&t.rationale===void 0?this.entries.delete(e):this.entries.set(e,t)}clear(e){for(const t of this.entries.keys())(t===e||t.startsWith(`${e}.`))&&this.entries.delete(t)}static strip(e){const t=new On(new Map);return{recording:On.stripValue(e,[],t),provenance:t}}static restore(e,t){if(t.size===0)return e;const n=structuredClone(e);for(const i of t.paths()){const s=t.at(i),r=i.split("."),o=On.holderOf(n,r);if(!o)continue;const l=r[r.length-1],c=o[l];c!==void 0&&(s.of!==void 0&&JSON.stringify(s.of)!==JSON.stringify(c)||(o[l]={value:c,...s.basis==="stated"?{}:{basis:s.basis},...s.rationale===void 0?{}:{rationale:s.rationale}}))}return n}static isWrapper(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)&&"value"in e}static stripValue(e,t,n){return On.isWrapper(e)?(n.set(t.join("."),{basis:e.basis??"stated",...e.rationale===void 0?{}:{rationale:e.rationale},of:e.value}),On.stripValue(e.value,t,n)):Array.isArray(e)?e.map((i,s)=>On.stripValue(i,[...t,String(s)],n)):typeof e=="object"&&e!==null?Object.fromEntries(Object.entries(e).map(([i,s])=>[i,On.stripValue(s,[...t,i],n)])):e}static holderOf(e,t){let n=e;for(const i of t.slice(0,-1)){if(typeof n!="object"||n===null)return;n=n[i]}return typeof n=="object"&&n!==null?n:void 0}}const Nv=/^(?:(?<year>\d{4}|\d{3}X|\d{2}XX)(-(?<month>0[1-9]|1[0-2]))?(-(?<day>0[1-9]|[12]\d|3[01]))?(?:[T ](?<hour>[01]?\d|2[0-3]):(?<minute>[0-5]\d)(?::(?<second>[0-5]\d))?)?|(?<timeOnlyHour>[01]?\d|2[0-3]):(?<timeOnlyMinute>[0-5]\d)(?::(?<timeOnlySecond>[0-5]\d))?)[?~%]?$/;function af(a){const e=Nv.exec(a.trim());if(!e?.groups)return;const{year:t,month:n,day:i,hour:s,minute:r,second:o,timeOnlyHour:l,timeOnlyMinute:c,timeOnlySecond:h}=e.groups,d=s??l,u=r??c,f=o??h;return{year:t&&!t.includes("X")?Number(t):void 0,month:n?Number(n):void 0,day:i?Number(i):void 0,hour:d?Number(d):void 0,minute:u?Number(u):void 0,second:f?Number(f):void 0,raw:a.trim()}}function Dl(a){if(a.raw!==void 0)return a.raw;if(a.year===void 0){if(a.hour===void 0)return"";let t=`${String(a.hour).padStart(2,"0")}:${String(a.minute??0).padStart(2,"0")}`;return a.second!==void 0&&(t+=`:${String(a.second).padStart(2,"0")}`),t}let e=String(a.year).padStart(4,"0");return a.month===void 0||(e+=`-${String(a.month).padStart(2,"0")}`,a.day===void 0)||(e+=`-${String(a.day).padStart(2,"0")}`,a.hour===void 0)||(e+=`T${String(a.hour).padStart(2,"0")}:${String(a.minute??0).padStart(2,"0")}`,a.second!==void 0&&(e+=`:${String(a.second).padStart(2,"0")}`)),e}function Ph(a){if(a.year!==void 0)return Date.UTC(a.year,(a.month??1)-1,a.day??1,a.hour??0,a.minute??0,a.second??0)}function rf(a){return(((a.day??0)*24+(a.hour??0))*60+(a.minute??0))*6e4+(a.second??0)*1e3}const Ov=["year","month","day","hour","minute"],kv=["day","hour","minute"];function of(a,e){return e.filter(t=>a[t]!==void 0).join(",")}function ja(a){if(a.durationSeconds!==void 0)return a.durationSeconds*1e3;if(!a.time||!a.endTime)return;const e=a.time.year!==void 0&&a.endTime.year!==void 0,t=e?Ov:kv,n=of(a.time,t);if(!(n===""||n!==of(a.endTime,t)))return e?Ph(a.endTime)-Ph(a.time):rf(a.endTime)-rf(a.time)}function Fv(a){if(a.durationSeconds===void 0&&!(!a.time||!a.endTime))return ja(a)===void 0?"imprecise":void 0}class jl{constructor(e,t,n,i,s,r,o,l,c=[],h,d,u,f=[]){this.event=e,this.timeline=t,this.witnessTrack=n,this.weatherTrack=i,this.soundTrack=s,this.witness=r,this.caseId=o,this.weather=l,this.decor=c,this.weatherSource=h,this.instrumentId=d,this.exposureSeconds=u,this.milestones=f}provenance=On.empty();testimony;get witnessCount(){return 1+this.decor.filter(e=>e.kind==="witness").length}get exposure(){return this.exposureSeconds??this.instrument.exposureSeconds}get instrument(){return st.byId(this.instrumentId)}static create(e,t,n){return new jl({eventType:"sighting",time:e,place:t},new Jl,new Yr,new Kr,new $r,n)}}const Uv=0,Bv=0;function at(a,e){const t=a.witnessTrack.getInterpolatedPoseAt(e);if(t)return t;const n=a.event.place?.[0];if(n)return{lat:n.lat,lng:n.lng,elevationM:Uv,headingDeg:void 0,pitchDeg:Bv,fovDeg:st.fieldOfViewDeg(a.instrument)}}function Ft(a,e){return a.weatherTrack.getInterpolatedWeatherAt(e)??a.weather??ym}function uu(a,e){return a.soundTrack.getInterpolatedSoundAt(e)??Lv}function zv(a,e,t){const n=(o,l)=>o.x*l.x+o.y*l.y+o.z*l.z,i=n(t,a),s=n(e,a);if(i<=0||s<=.05)return;const r=i/s;return{x:e.x*r-a.x*i,y:e.y*r-a.y*i,z:e.z*r-a.z*i}}function Hv(a){const e=(n,i)=>a==="fr"?i:n,t=(n,i,s="",r="",o="")=>`<label>${i}<input id="${n}" type="number" step="any" ${s?`min="${s}"`:""} ${r?`max="${r}"`:""} placeholder="${o}"></label>`;return`<fieldset><legend>${e("Cloud layers","Couches nuageuses")}</legend>
|
|
2
2
|
<p>${e("Weather records supply coverage and wind when available. Cloud shape, thickness and size are visual estimates; they are not measured individual clouds.","Les relevés fournissent la couverture et le vent lorsqu’ils sont disponibles. La forme, l’épaisseur et la taille des nuages sont des estimations visuelles, pas des nuages individuels mesurés.")}</p>
|
|
3
3
|
<div class="cloud-fields">
|
|
4
4
|
<label>${e("Edit scope","Portée des modifications")}<select id="cloud-scope"><option value="instant">${e("Current time","Instant courant")}</option><option value="observation">${e("Whole observation","Toute l’observation")}</option></select></label>
|
|
@@ -34,7 +34,7 @@ const ym={cloudCover:0,cloudDarkness:0,precipitationType:"none",precipitationInt
|
|
|
34
34
|
${t("instance-density",e("Cloud density","Densité du nuage"),"0","2")}
|
|
35
35
|
${t("instance-darkness",e("Darkness","Obscurité"),"0","1",e("Layer darkness","Obscurité de la couche"))}
|
|
36
36
|
</div><p>${e("Individual clouds remain present at 0% global coverage. Dragging changes position and altitude; numeric fields provide precise dimensions. Clouds follow their layer's wind.","Les nuages individuels restent présents à 0 % de couverture globale. Le glissement change la position et l’altitude ; les champs règlent précisément les dimensions. Les nuages suivent le vent de leur couche.")}</p></details>
|
|
37
|
-
<p id="cloud-status" role="status"></p></fieldset>`}function Gv(a,e,t,n,i="en"){const s=(A,I)=>i==="fr"?I:A;a.innerHTML=Hv(i);const r=A=>a.querySelector("#"+A),o=A=>Number(r(A).value),l=a.querySelector("#cloud-layer"),c=a.querySelector("#cloud-instance"),h=a.querySelector("#cloud-status"),d=()=>r("cloud-scope").value,u=()=>_i(Ht(e.ufoElement.sighting,e.ufoElement.currentTime))[Number(l.value)],f=["east","north","base","thickness","width","depth","rotation","density","darkness"],p=()=>{const A=u()?.instances?.find(R=>R.id===c.value);for(const R of f)r(`instance-${R}`).disabled=!A;if(a.querySelector("#cloud-instance-delete").disabled=!A,a.querySelector("#cloud-instance-point").disabled=!A,!A)return;const I=[A.eastM,A.northM,A.baseM,A.thicknessM,A.widthM,A.depthM,A.rotationDeg,A.density,A.darkness];f.forEach((R,N)=>{r(`instance-${R}`).value=I[N]===void 0?"":String(Math.round(I[N]*100)/100)})};let v=-1;const m=()=>{const A=e.ufoElement.currentTime,I=a.getRootNode().activeElement;if(A===v&&I instanceof HTMLInputElement&&a.contains(I))return;v=A;const R=_i(Ht(e.ufoElement.sighting,e.ufoElement.currentTime)),N=l.selectedOptions[0]?.dataset.layerId;l.replaceChildren(...R.map((V,j)=>{const $=new Option(`${j+1} · ${V.type} · ${Math.round(V.baseM)} m`,String(j));return $.dataset.layerId=V.id,$}));const z=R.findIndex(V=>V.id===N);l.value=String(Math.max(0,z));const L=u();for(const V of["cloud-type","cloud-base","cloud-thickness","cloud-cover","cloud-size","cloud-density","cloud-darkness","cloud-crystal-alignment","cloud-wind-direction","cloud-wind-speed","cloud-seed","cloud-layer-delete","cloud-instance-add"])a.querySelector("#"+V).disabled=!L;if(r("cloud-crystal-alignment").closest("label").hidden=L?.type!=="cirrus",!L){c.replaceChildren(new Option("—","")),p();return}r("cloud-type").value=L.type;for(const[V,j]of Object.entries({base:L.baseM,thickness:L.thicknessM,cover:L.coverage*100,size:L.sizeM,density:L.density}))r(`cloud-${V}`).value=String(Math.round(j*100)/100);r("cloud-darkness").value=String(L.darkness??Ht(e.ufoElement.sighting,A).cloudDarkness);const B=r("cloud-crystal-alignment");B.value=String(L.iceCrystalAlignment??.65),r("cloud-wind-direction").value=L.windDirectionDeg===void 0?"":String(L.windDirectionDeg),r("cloud-wind-speed").value=L.windSpeed===void 0?"":String(L.windSpeed),r("cloud-seed").value=L.seed===void 0?"":String(L.seed);const F=c.value;c.replaceChildren(new Option(s("None","Aucun"),""),...(L.instances??[]).map((V,j)=>new Option(`${s("Cloud","Nuage")} ${j+1}`,V.id))),c.value=L.instances?.some(V=>V.id===F)?F:"",p()},g=(A,I=!0)=>{if(!u())return;e.ufoElement.pause(),t(I);const R=e.ufoElement.currentTime,N=e.ufoElement.sighting;pv(N.weatherTrack,Ht(N,R),R,u().id,A,d()),e.ufoElement.refresh(),h.textContent=d()==="observation"?s("Saved across the observation; winds preserved.","Modifications enregistrées sur toute l’observation, vents conservés."):`${(R/1e3).toFixed(1)} s · ${i==="fr"?"Météo enregistrée à cet instant.":"Weather saved at this time."}`};a.addEventListener("focusin",()=>e.ufoElement.pause()),l.addEventListener("change",()=>{c.value="",m()}),c.addEventListener("change",p);const _=A=>{e.ufoElement.pause(),t();const I=e.ufoElement.sighting,R=e.ufoElement.currentTime;bm(I.weatherTrack,Ht(I,R),R,A,d()),e.ufoElement.refresh(),m()};a.querySelector("#cloud-layer-add").addEventListener("click",()=>{const A=Ht(e.ufoElement.sighting,e.ufoElement.currentTime),I={id:crypto.randomUUID(),type:"cumulus",baseM:1500,thicknessM:800,coverage:.5,sizeM:1400,density:1,darkness:A.cloudDarkness};_(R=>[...R,I]),l.value=String(_i(Ht(e.ufoElement.sighting,e.ufoElement.currentTime)).findIndex(R=>R.id===I.id)),m()}),a.querySelector("#cloud-layer-delete").addEventListener("click",()=>{const A=u()?.id;A&&_(I=>I.filter(R=>R.id!==A))});const M=e.ufoElement.canvasElement,x=r("cloud-manipulate");let w;const E=A=>{const I=M.getBoundingClientRect();return{x:(A.clientX-I.left)/I.width*2-1,y:1-(A.clientY-I.top)/I.height*2}};x.addEventListener("change",()=>{M.style.touchAction=x.checked?"none":"",M.style.cursor=x.checked?"crosshair":""}),M.addEventListener("click",A=>{x.checked&&(A.preventDefault(),A.stopImmediatePropagation())},!0),M.addEventListener("pointerdown",A=>{if(!x.checked||A.button!==0)return;A.preventDefault(),A.stopImmediatePropagation(),e.ufoElement.pause();const I=E(A),R=e.pickCloudAt(I.x,I.y);if(!R){h.textContent=s("No individual cloud here.","Aucun nuage individuel à cet endroit.");return}const N=_i(Ht(e.ufoElement.sighting,e.ufoElement.currentTime));l.value=String(N.findIndex(B=>B.id===R.layerId)),m(),c.value=R.instanceId,p();const L=(d()==="observation"?e.ufoElement.sighting.weatherTrack.allKeyframes.map(B=>B.weather):[Ht(e.ufoElement.sighting,e.ufoElement.currentTime)]).flatMap(B=>_i(B).filter(F=>F.id===R.layerId).flatMap(F=>(F.instances??[]).filter(V=>V.id===R.instanceId).map(V=>V.baseM)));w={minBase:Math.min(...L),pointerId:A.pointerId,id:R.instanceId,center:R.center,ray:e.cloudDirectionAt(I.x,I.y),delta:{x:0,y:0,z:0}},M.setPointerCapture(A.pointerId),M.style.cursor="grabbing",h.textContent=s("Cloud selected. Drag to move it.","Nuage sélectionné. Faire glisser pour le déplacer.")},!0),M.addEventListener("pointermove",A=>{if(!w||A.pointerId!==w.pointerId)return;A.preventDefault(),A.stopImmediatePropagation();const I=E(A),R=zv(w.ray,e.cloudDirectionAt(I.x,I.y),w.center);if(!R)return;R.y=Math.max(R.y,-w.minBase);const N=w.delta,z=w.id;g(L=>({...L,instances:L.instances?.map(B=>B.id!==z?B:{...B,eastM:B.eastM+R.x-N.x,northM:B.northM-R.z+N.z,baseM:B.baseM+R.y-N.y})})),w.delta=R,p()},!0);const D=A=>{!w||A.pointerId!==w.pointerId||(w=void 0,M.hasPointerCapture(A.pointerId)&&M.releasePointerCapture(A.pointerId),M.style.cursor=x.checked?"crosshair":"")};M.addEventListener("pointerup",D),M.addEventListener("pointercancel",D),M.addEventListener("lostpointercapture",D);const y={"cloud-type":"type","cloud-base":"baseM","cloud-thickness":"thicknessM","cloud-cover":"coverage","cloud-size":"sizeM","cloud-density":"density","cloud-darkness":"darkness","cloud-crystal-alignment":"iceCrystalAlignment"};for(const[A,I]of Object.entries(y)){const R=()=>{if(r(A).value===""||!r(A).validity.valid)return;const N=A==="cloud-type"?r(A).value:o(A)/(A==="cloud-cover"?100:1);g(z=>({...z,[I]:N}),A!=="cloud-crystal-alignment")};r(A).addEventListener(A==="cloud-type"?"change":"input",R)}for(const[A,I]of[["cloud-wind-direction","windDirectionDeg"],["cloud-wind-speed","windSpeed"],["cloud-seed","seed"]])r(A).addEventListener("input",()=>{r(A).validity.valid&&g(R=>({...R,[I]:r(A).value===""?void 0:o(A)}))});a.querySelector("#cloud-instance-add").addEventListener("click",()=>{const A=u();if(!A)return;const I=crypto.randomUUID(),R=e.ufoElement.sighting,N=e.ufoElement.currentTime,z=at(R,N),L=Il(N,R.weatherTrack,Ht(R,0),at(R,0),z,A.id),B=e.cloudDirectionAt(0,0),F=A.baseM+A.thicknessM*.4-(z?.elevationM??0)-1.6,V=F*B.y>0?Math.max(500,Math.min(2e4,F/B.y)):5e3,j={id:I,eastM:L.x+B.x*V,northM:-(L.z+B.z*V),baseM:A.baseM,thicknessM:A.thicknessM,widthM:1800,depthM:1200,rotationDeg:0,density:1,darkness:A.darkness};g($=>({...$,instances:[...$.instances??[],j]})),m(),c.value=I,p(),h.textContent+=s(" Individual cloud added, independent of global coverage."," Nuage individuel ajouté : sa présence est indépendante de la couverture globale.")}),a.querySelector("#cloud-instance-delete").addEventListener("click",()=>{const A=c.value;A&&(g(I=>({...I,instances:I.instances?.filter(R=>R.id!==A)})),m())}),a.querySelector("#cloud-instance-point").addEventListener("click",()=>{const A=u(),I=A?.instances?.find($=>$.id===c.value);if(!I)return;e.ufoElement.pause();const R=e.ufoElement.sighting,N=e.ufoElement.currentTime,z=at(R,N),L=Il(N,R.weatherTrack,Ht(R,0),at(R,0),z,A.id),B=I.eastM-L.x,F=I.northM+L.z,V=Math.hypot(B,F),j=I.baseM+I.thicknessM/2-(z?.elevationM??0)-1.6-V**2/(2*6371e3);V===0&&j===0||n((Math.atan2(B,F)*180/Math.PI+360)%360,Math.atan2(j,V)*180/Math.PI)});const T=["eastM","northM","baseM","thicknessM","widthM","depthM","rotationDeg","density","darkness"];return f.forEach((A,I)=>r(`instance-${A}`).addEventListener("input",()=>{const R=c.value,N=r(`instance-${A}`);if(!R||!N.validity.valid||N.value===""&&A!=="darkness")return;const z=T[I],L=N.value===""?void 0:o(`instance-${A}`);g(B=>({...B,instances:B.instances?.map(F=>F.id!==R?F:{...F,[z]:L})}))})),{sync:m,stopManipulation(){w=void 0,x.checked=!1,M.style.touchAction="",M.style.cursor=""},reset(){w=void 0,x.checked=!1,M.style.cursor="",M.style.touchAction="",c.value="",v=-1,m()}}}const Mm=["nw","n","ne","e","se","s","sw","w"],Vv=24,gs=8,Sm=3,Wv=8;function Rr(a,e,t){const n=a.x-e.x,i=a.y-e.y,s=Math.cos(t),r=Math.sin(t);return{x:e.x+n*s-i*r,y:e.y+n*r+i*s}}function Fs(a){return{x:a.x+a.width/2,y:a.y+a.height/2}}const Xv={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 it{static handlePointsFor(e){const{x:t,y:n,width:i,height:s}=e.bounds,r={nw:{x:t,y:n},n:{x:t+i/2,y:n},ne:{x:t+i,y:n},e:{x:t+i,y:n+s/2},se:{x:t+i,y:n+s},s:{x:t+i/2,y:n+s},sw:{x:t,y:n+s},w:{x:t,y:n+s/2},rotate:{x:t+i/2,y:n-Vv}},o=Fs(e.bounds),l={};for(const c of Object.keys(r))l[c]=Rr(r[c],o,e.angle);return l}static hitTestHandle(e,t,n=8,i=[...Mm,"rotate"]){const s=it.handlePointsFor(e);for(const r of i)if(Math.hypot(t.x-s[r].x,t.y-s[r].y)<=n)return r}static HANDLE_DIRECTION_DEG={e:0,se:45,s:90,sw:135,w:180,nw:225,n:270,ne:315};static resizeAxisFor(e,t){const i=((it.HANDLE_DIRECTION_DEG[e]+t*180/Math.PI)%180+180)%180/45,s=["ew","nwse","ns","nesw"];return s[Math.round(i)%s.length]}static resizeBounds(e,t,n,i){const s=Fs(e),r=Rr(i,s,-t),{x:o,y:l,width:c,height:h}=e,d=Xv[n];let u=o,f=l,p=o+c,v=l+h;return d.left&&(u=Math.min(r.x,p-gs)),d.right&&(p=Math.max(r.x,u+gs)),d.top&&(f=Math.min(r.y,v-gs)),d.bottom&&(v=Math.max(r.y,f+gs)),{x:u,y:f,width:p-u,height:v-f}}static resizeShape(e,t,n){if(t==="rotate")throw new Error("resizeShape does not accept the rotate handle");const{width:i,height:s}=e.bounds,r=it.resizeBounds(e.bounds,e.angle,t,n);if(e.kind==="oval")return{...e,bounds:r};const o=i===0?1:r.width/i,l=s===0?1:r.height/s;return{...e,bounds:r,points:e.points.map(c=>({x:c.x*o,y:c.y*l}))}}static rotateShape(e,t){const n=Fs(e.bounds),i=Math.atan2(t.y-n.y,t.x-n.x)+Math.PI/2;return{...e,angle:i}}static groupBoundsFor(e){const t=Math.min(...e.map(r=>r.x)),n=Math.min(...e.map(r=>r.y)),i=Math.max(...e.map(r=>r.x+r.width)),s=Math.max(...e.map(r=>r.y+r.height));return{x:t,y:n,width:i-t,height:s-n}}static vertexPointsFor(e){const t=Fs(e.bounds);return e.points.map(n=>Rr({x:e.bounds.x+n.x,y:e.bounds.y+n.y},t,e.angle))}static hitTestVertex(e,t,n=Wv){const i=it.vertexPointsFor(e);let s,r=n;return i.forEach((o,l)=>{const c=Math.hypot(t.x-o.x,t.y-o.y);c<=r&&(r=c,s=l)}),s}static toLocalPoint(e,t){const n=Fs(e.bounds),i=Rr(t,n,-e.angle);return{x:i.x-e.bounds.x,y:i.y-e.bounds.y}}static moveVertex(e,t,n){const i=e.points.map((d,u)=>u===t?it.toLocalPoint(e,n):d),s=Math.min(...i.map(d=>d.x)),r=Math.min(...i.map(d=>d.y)),o=Math.max(...i.map(d=>d.x)),l=Math.max(...i.map(d=>d.y)),c={x:e.bounds.x+s,y:e.bounds.y+r,width:o-s,height:l-r},h=i.map(d=>({x:d.x-s,y:d.y-r}));return{...e,bounds:c,points:h}}static insertVertexNear(e,t){const n=it.toLocalPoint(e,t),{points:i}=e;let s=i.length-1,r=1/0;for(let l=0;l<i.length;l++){const c=i[l],h=i[(l+1)%i.length],d=it.distanceToSegment(n,c,h);d<r&&(r=d,s=l)}const o=[...i.slice(0,s+1),n,...i.slice(s+1)];return{...e,points:o}}static distanceToSegment(e,t,n){const i=n.x-t.x,s=n.y-t.y,r=i*i+s*s,o=r===0?0:Math.max(0,Math.min(1,((e.x-t.x)*i+(e.y-t.y)*s)/r)),l=t.x+o*i,c=t.y+o*s;return Math.hypot(e.x-l,e.y-c)}static deleteVertex(e,t){return e.points.length<=Sm?e:{...e,points:e.points.filter((n,i)=>i!==t)}}}class dc{constructor(e){this.members=e}bounds(){return it.groupBoundsFor(this.members.map(e=>e.shape.bounds))}scaleTo(e){const t=this.bounds(),n=t.width===0?1:e.width/t.width,i=t.height===0?1:e.height/t.height;return this.members.map(({sourceId:s,shape:r})=>{const o=Math.max(r.bounds.width*n,gs),l=Math.max(r.bounds.height*i,gs),c=e.x+(r.bounds.x-t.x)*n,h=e.y+(r.bounds.y-t.y)*i,d={x:c,y:h,width:o,height:l};return r.kind==="oval"?{sourceId:s,shape:{...r,bounds:d}}:{sourceId:s,shape:{...r,bounds:d,points:r.points.map(u=>({x:u.x*n,y:u.y*i}))}}})}resize(e,t){return this.scaleTo(it.resizeBounds(this.bounds(),0,e,t))}rotate(e,t){const n=Fs(this.bounds()),i=r=>Math.atan2(r.y-n.y,r.x-n.x),s=i(e)-i(t);return this.members.map(({sourceId:r,shape:o})=>{const l=Fs(o.bounds),c=Rr(l,n,s),h={x:c.x-o.bounds.width/2,y:c.y-o.bounds.height/2,width:o.bounds.width,height:o.bounds.height};return{sourceId:r,shape:{...o,bounds:h,angle:o.angle+s}}})}}const Lh=6,mo=Lh/2,lf=20,Nh=24,cf=9,hf=6,df=7,uf=6,ff=4;class Oh{constructor(e){this.ctx=e}starPoints=0;roll=0;clear(e,t){this.ctx.clearRect(0,0,e,t)}static paintExtent(e){const{x:t,y:n,width:i,height:s}=e.bounds,r=t+i/2,o=n+s/2,l=e.angle%(2*Math.PI)!==0,c=Math.hypot(i,s)/2,h=l?c:i/2,d=l?c:s/2,u=Math.max(i,s)/2,f=e.brightness??0,p=f>0?Math.max(u*(1+cf*f),uf*f)-u:0,v=f>0?u*(1+df*f)-u:0,m=3*Nh*(e.blur??0)+1.5*lf*e.haloScale,g=Math.max(p,v,0)+m+2;return{x:r-h-g,y:o-d-g,width:2*(h+g),height:2*(d+g)}}paintInto(e,t,n){this.ctx.save(),this.ctx.scale(n,n),this.ctx.translate(-t.x,-t.y),this.paintShape(e.selected?{...e,selected:!1}:e),this.ctx.restore()}paintShape(e){this.ctx.save(),this.ctx.globalAlpha=1-e.transparency;const t=e.blur??0;t>0&&(this.ctx.filter=`blur(${(Nh*t).toFixed(2)}px)`);const n=e.brightness??0;n>0&&this.paintDazzle(e,n),e.haloScale>0&&this.paintHalo(e),this.paintBase(e),this.ctx.restore(),e.selected&&this.paintSelectionHandles(e)}setStarPoints(e){this.starPoints=Math.max(0,Math.floor(e))}setRoll(e){this.roll=e}paintDazzle(e,t){const{x:n,y:i,width:s,height:r}=e.bounds,o=n+s/2,l=i+r/2,c=Math.max(s,r)/2,h=Math.max(c*(1+cf*t),uf*t);if(h<=0)return;this.ctx.save(),this.ctx.globalCompositeOperation="lighter";const d=this.ctx.createRadialGradient(o,l,0,o,l,h);for(let u=0;u<=hf;u++){const f=u/hf,p=1/(1+24*f*f);this.ctx.globalAlpha=1,d.addColorStop(f,this.withAlpha(e.color,p*t*.55))}if(this.ctx.fillStyle=d,this.ctx.beginPath(),this.ctx.arc(o,l,h,0,2*Math.PI),this.ctx.fill(),this.starPoints>0){const u=c*(1+df*t);this.ctx.lineWidth=Math.max(1,c*.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)*u,m=l+Math.sin(p)*u,g=this.ctx.createLinearGradient(o,l,v,m);g.addColorStop(0,this.withAlpha(e.color,t*.55)),g.addColorStop(.35,this.withAlpha(e.color,t*.22)),g.addColorStop(1,this.withAlpha(e.color,0)),this.ctx.strokeStyle=g,this.ctx.beginPath(),this.ctx.moveTo(o,l),this.ctx.lineTo(v,m),this.ctx.stroke()}}this.ctx.restore()}dazzledFill(e,t){if(t<=0)return e.color;const n=/^#([0-9a-f]{6})$/i.exec(e.color.trim());if(!n)return e.color;const i=Number.parseInt(n[1],16),s=r=>Math.round(r+(255-r)*t);return`rgb(${s(i>>16&255)}, ${s(i>>8&255)}, ${s(i&255)})`}withAlpha(e,t){const n=Math.max(0,Math.min(1,t)),i=/^#([0-9a-f]{6})$/i.exec(e.trim());if(!i)return e;const s=Number.parseInt(i[1],16);return`rgba(${s>>16&255}, ${s>>8&255}, ${s&255}, ${n.toFixed(3)})`}paintBase(e){if(this.ctx.fillStyle=this.dazzledFill(e,e.brightness??0),this.ctx.beginPath(),e.kind==="oval"){const{x:t,y:n,width:i,height:s}=e.bounds,r=i/2,o=s/2;this.ctx.ellipse(t+r,n+o,r,o,e.angle,0,2*Math.PI)}else{const{x:t,y:n,width:i,height:s}=e.bounds;this.ctx.save(),this.ctx.translate(t+i/2,n+s/2),this.ctx.rotate(e.angle),this.ctx.translate(-i/2,-s/2),e.points.forEach((r,o)=>{o===0?this.ctx.moveTo(r.x,r.y):this.ctx.lineTo(r.x,r.y)}),this.ctx.closePath(),this.ctx.restore()}this.ctx.fill()}paintHalo(e){this.ctx.save(),this.ctx.shadowColor=e.color,this.ctx.shadowBlur=lf*e.haloScale,this.paintBase(e),this.ctx.restore()}paintSelectionHandles(e){this.paintHandleFrame(it.handlePointsFor(e),{includeRotate:!0}),e.kind==="polygon"&&this.paintVertexHandles(e)}paintVertexHandles(e){this.ctx.fillStyle="#39f";for(const t of it.vertexPointsFor(e))this.ctx.beginPath(),this.ctx.ellipse(t.x,t.y,ff,ff,0,0,2*Math.PI),this.ctx.fill()}paintMemberOutline(e){this.paintOutline(it.handlePointsFor(e))}paintSelectionOnly(e){this.paintSelectionHandles(e)}paintGroupHandles(e){this.paintHandleFrame(it.handlePointsFor({bounds:e,angle:0}),{includeRotate:!0})}paintOutline(e){this.ctx.strokeStyle="lightgray",this.ctx.beginPath(),this.ctx.moveTo(e.nw.x,e.nw.y),this.ctx.lineTo(e.ne.x,e.ne.y),this.ctx.lineTo(e.se.x,e.se.y),this.ctx.lineTo(e.sw.x,e.sw.y),this.ctx.closePath(),this.ctx.stroke()}paintHandleFrame(e,{includeRotate:t}){this.paintOutline(e),this.ctx.fillStyle="lightgray";for(const n of Mm){const i=e[n];this.ctx.fillRect(i.x-mo,i.y-mo,Lh,Lh)}t&&(this.ctx.beginPath(),this.ctx.moveTo(e.n.x,e.n.y),this.ctx.lineTo(e.rotate.x,e.rotate.y),this.ctx.stroke(),this.ctx.beginPath(),this.ctx.ellipse(e.rotate.x,e.rotate.y,mo+1,mo+1,0,0,2*Math.PI),this.ctx.fill())}}class Os extends Error{constructor(e,t,n){super(`${e}: ${t}${n===void 0?"":` (HTTP ${n})`}`),this.kind=e,this.url=t,this.status=n,this.name="SightingFetchError"}}class fu{static async json(e){const t=new URL(e,location.href);if(location.protocol==="https:"&&t.protocol==="http:")throw new Os("mixed-content",e);let n;try{n=await fetch(e)}catch{throw await this.diagnose(e,t)}if(!n.ok)throw new Os("status",e,n.status);try{return await n.json()}catch{throw new Os("malformed",e)}}static async diagnose(e,t){if(t.origin===location.origin)return new Os("unreachable",e);try{return await fetch(e,{mode:"no-cors"}),new Os("cors",e)}catch{return new Os("unreachable",e)}}}const qv="modulepreload",Yv=function(a,e){return new URL(a,e).href},pf={},ii=function(e,t,n){let i=Promise.resolve();if(t&&t.length>0){let r=function(h){return Promise.all(h.map(d=>Promise.resolve(d).then(u=>({status:"fulfilled",value:u}),u=>({status:"rejected",reason:u}))))};const o=document.getElementsByTagName("link"),l=document.querySelector("meta[property=csp-nonce]"),c=l?.nonce||l?.getAttribute("nonce");i=r(t.map(h=>{if(h=Yv(h,n),h in pf)return;pf[h]=!0;const d=h.endsWith(".css"),u=d?'[rel="stylesheet"]':"";if(!!n)for(let v=o.length-1;v>=0;v--){const m=o[v];if(m.href===h&&(!d||m.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${h}"]${u}`))return;const p=document.createElement("link");if(p.rel=d?"stylesheet":qv,d||(p.as="script"),p.crossOrigin="",p.href=h,c&&p.setAttribute("nonce",c),document.head.appendChild(p),d)return new Promise((v,m)=>{p.addEventListener("load",v),p.addEventListener("error",()=>m(new Error(`Unable to preload CSS for ${h}`)))})}))}function s(r){const o=new Event("vite:preloadError",{cancelable:!0});if(o.payload=r,window.dispatchEvent(o),!o.defaultPrevented)throw r}return i.then(r=>{for(const o of r||[])o.status==="rejected"&&s(o.reason);return e().catch(s)})};class Ln extends Error{constructor(e,t,n){const i=e==="rejected"&&typeof t=="string"?t:void 0,s=e==="rejected"?n:t;super(i??e,s===void 0?void 0:{cause:s}),this.kind=e,this.name="NarrativeError",this.detail=i}detail}class Cl{static of(e){const{recording:t}=On.strip(e),{timeline:n,...i}=t,s=(n?.keyframes??[]).map(o=>Cl.keyframe(o)),r=Object.entries(i).filter(([o,l])=>o!=="version"&&l!==void 0);if(!(r.length===0&&s.every(o=>o.shapes.length===0)))return{...Object.fromEntries(r),...s.length>0?{timeline:{keyframes:s}}:{}}}static keyframe(e){return{t:e.t,shapes:e.shapes.map(t=>Cl.shape(t.sourceId,t.shape))}}static shape(e,t){const n=t??{},i=n.angular,s=n.aim;return{sourceId:e,kind:n.kind??"oval",...n.title===void 0?{}:{title:n.title},...i?.widthDeg===void 0||i.heightDeg===void 0?{}:{angular:{widthDeg:i.widthDeg,heightDeg:i.heightDeg}},...s?.azimuthDeg===void 0||s.altitudeDeg===void 0?{}:{aim:{azimuthDeg:s.azimuthDeg,altitudeDeg:s.altitudeDeg}}}}}const mf={name:"draft_recording",description:"Record what the account states, what justifies each value, and what it leaves out.",input_schema:{type:"object",properties:{recording:{type:"object",description:"The recording, in the format given above. Partial: only the fields the account actually states."},claims:{type:"array",description:"One entry per value in `recording`. EVERY value needs one: a value with no claim is a value nobody can check.",items:{type:"object",properties:{path:{type:"string",description:'Where the value sits in `recording`, dot-joined, array indices as steps: "time.hour", "place.0.lat", "timeline.keyframes.1.shapes.0.shape.angular.widthDeg".'},basis:{type:"string",enum:["stated","derived","assumed"],description:'"stated": the witness said it. "derived": worked out from what they said plus something checkable. "assumed": chosen so the reconstruction has a value at all, on nothing they said.'},rationale:{type:"string",description:`For "stated", the account's own words, copied verbatim, never a paraphrase. For "derived", the working, with the numbers in it. For "assumed", what the guess was chosen for and how wrong it could be.`}},required:["path","basis","rationale"]}},gaps:{type:"array",description:"What nothing could settle, not even a guess worth making — one short sentence each, in the reader's language. Usually empty.",items:{type:"string"}}},required:["recording","claims","gaps"]}},Kv=`You are reading a witness's account of an aerial sighting and reconstructing it in the
|
|
37
|
+
<p id="cloud-status" role="status"></p></fieldset>`}function Gv(a,e,t,n,i="en"){const s=(A,I)=>i==="fr"?I:A;a.innerHTML=Hv(i);const r=A=>a.querySelector("#"+A),o=A=>Number(r(A).value),l=a.querySelector("#cloud-layer"),c=a.querySelector("#cloud-instance"),h=a.querySelector("#cloud-status"),d=()=>r("cloud-scope").value,u=()=>_i(Ft(e.ufoElement.sighting,e.ufoElement.currentTime))[Number(l.value)],f=["east","north","base","thickness","width","depth","rotation","density","darkness"],p=()=>{const A=u()?.instances?.find(R=>R.id===c.value);for(const R of f)r(`instance-${R}`).disabled=!A;if(a.querySelector("#cloud-instance-delete").disabled=!A,a.querySelector("#cloud-instance-point").disabled=!A,!A)return;const I=[A.eastM,A.northM,A.baseM,A.thicknessM,A.widthM,A.depthM,A.rotationDeg,A.density,A.darkness];f.forEach((R,N)=>{r(`instance-${R}`).value=I[N]===void 0?"":String(Math.round(I[N]*100)/100)})};let v=-1;const m=()=>{const A=e.ufoElement.currentTime,I=a.getRootNode().activeElement;if(A===v&&I instanceof HTMLInputElement&&a.contains(I))return;v=A;const R=_i(Ft(e.ufoElement.sighting,e.ufoElement.currentTime)),N=l.selectedOptions[0]?.dataset.layerId;l.replaceChildren(...R.map((V,j)=>{const $=new Option(`${j+1} · ${V.type} · ${Math.round(V.baseM)} m`,String(j));return $.dataset.layerId=V.id,$}));const z=R.findIndex(V=>V.id===N);l.value=String(Math.max(0,z));const L=u();for(const V of["cloud-type","cloud-base","cloud-thickness","cloud-cover","cloud-size","cloud-density","cloud-darkness","cloud-crystal-alignment","cloud-wind-direction","cloud-wind-speed","cloud-seed","cloud-layer-delete","cloud-instance-add"])a.querySelector("#"+V).disabled=!L;if(r("cloud-crystal-alignment").closest("label").hidden=L?.type!=="cirrus",!L){c.replaceChildren(new Option("—","")),p();return}r("cloud-type").value=L.type;for(const[V,j]of Object.entries({base:L.baseM,thickness:L.thicknessM,cover:L.coverage*100,size:L.sizeM,density:L.density}))r(`cloud-${V}`).value=String(Math.round(j*100)/100);r("cloud-darkness").value=String(Math.round((L.darkness??Ft(e.ufoElement.sighting,A).cloudDarkness)*100)/100);const B=r("cloud-crystal-alignment");B.value=String(Math.round((L.iceCrystalAlignment??.65)*100)/100),r("cloud-wind-direction").value=L.windDirectionDeg===void 0?"":String(L.windDirectionDeg),r("cloud-wind-speed").value=L.windSpeed===void 0?"":String(L.windSpeed),r("cloud-seed").value=L.seed===void 0?"":String(L.seed);const F=c.value;c.replaceChildren(new Option(s("None","Aucun"),""),...(L.instances??[]).map((V,j)=>new Option(`${s("Cloud","Nuage")} ${j+1}`,V.id))),c.value=L.instances?.some(V=>V.id===F)?F:"",p()},g=(A,I=!0)=>{if(!u())return;e.ufoElement.pause(),t(I);const R=e.ufoElement.currentTime,N=e.ufoElement.sighting;pv(N.weatherTrack,Ft(N,R),R,u().id,A,d()),e.ufoElement.refresh(),h.textContent=d()==="observation"?s("Saved across the observation; winds preserved.","Modifications enregistrées sur toute l’observation, vents conservés."):`${(R/1e3).toFixed(1)} s · ${i==="fr"?"Météo enregistrée à cet instant.":"Weather saved at this time."}`};a.addEventListener("focusin",()=>e.ufoElement.pause()),l.addEventListener("change",()=>{c.value="",m()}),c.addEventListener("change",p);const _=A=>{e.ufoElement.pause(),t();const I=e.ufoElement.sighting,R=e.ufoElement.currentTime;bm(I.weatherTrack,Ft(I,R),R,A,d()),e.ufoElement.refresh(),m()};a.querySelector("#cloud-layer-add").addEventListener("click",()=>{const A=Ft(e.ufoElement.sighting,e.ufoElement.currentTime),I={id:crypto.randomUUID(),type:"cumulus",baseM:1500,thicknessM:800,coverage:.5,sizeM:1400,density:1,darkness:A.cloudDarkness};_(R=>[...R,I]),l.value=String(_i(Ft(e.ufoElement.sighting,e.ufoElement.currentTime)).findIndex(R=>R.id===I.id)),m()}),a.querySelector("#cloud-layer-delete").addEventListener("click",()=>{const A=u()?.id;A&&_(I=>I.filter(R=>R.id!==A))});const M=e.ufoElement.canvasElement,x=r("cloud-manipulate");let w;const E=A=>{const I=M.getBoundingClientRect();return{x:(A.clientX-I.left)/I.width*2-1,y:1-(A.clientY-I.top)/I.height*2}};x.addEventListener("change",()=>{M.style.touchAction=x.checked?"none":"",M.style.cursor=x.checked?"crosshair":""}),M.addEventListener("click",A=>{x.checked&&(A.preventDefault(),A.stopImmediatePropagation())},!0),M.addEventListener("pointerdown",A=>{if(!x.checked||A.button!==0)return;A.preventDefault(),A.stopImmediatePropagation(),e.ufoElement.pause();const I=E(A),R=e.pickCloudAt(I.x,I.y);if(!R){h.textContent=s("No individual cloud here.","Aucun nuage individuel à cet endroit.");return}const N=_i(Ft(e.ufoElement.sighting,e.ufoElement.currentTime));l.value=String(N.findIndex(B=>B.id===R.layerId)),m(),c.value=R.instanceId,p();const L=(d()==="observation"?e.ufoElement.sighting.weatherTrack.allKeyframes.map(B=>B.weather):[Ft(e.ufoElement.sighting,e.ufoElement.currentTime)]).flatMap(B=>_i(B).filter(F=>F.id===R.layerId).flatMap(F=>(F.instances??[]).filter(V=>V.id===R.instanceId).map(V=>V.baseM)));w={minBase:Math.min(...L),pointerId:A.pointerId,id:R.instanceId,center:R.center,ray:e.cloudDirectionAt(I.x,I.y),delta:{x:0,y:0,z:0}},M.setPointerCapture(A.pointerId),M.style.cursor="grabbing",h.textContent=s("Cloud selected. Drag to move it.","Nuage sélectionné. Faire glisser pour le déplacer.")},!0),M.addEventListener("pointermove",A=>{if(!w||A.pointerId!==w.pointerId)return;A.preventDefault(),A.stopImmediatePropagation();const I=E(A),R=zv(w.ray,e.cloudDirectionAt(I.x,I.y),w.center);if(!R)return;R.y=Math.max(R.y,-w.minBase);const N=w.delta,z=w.id;g(L=>({...L,instances:L.instances?.map(B=>B.id!==z?B:{...B,eastM:B.eastM+R.x-N.x,northM:B.northM-R.z+N.z,baseM:B.baseM+R.y-N.y})})),w.delta=R,p()},!0);const D=A=>{!w||A.pointerId!==w.pointerId||(w=void 0,M.hasPointerCapture(A.pointerId)&&M.releasePointerCapture(A.pointerId),M.style.cursor=x.checked?"crosshair":"")};M.addEventListener("pointerup",D),M.addEventListener("pointercancel",D),M.addEventListener("lostpointercapture",D);const y={"cloud-type":"type","cloud-base":"baseM","cloud-thickness":"thicknessM","cloud-cover":"coverage","cloud-size":"sizeM","cloud-density":"density","cloud-darkness":"darkness","cloud-crystal-alignment":"iceCrystalAlignment"};for(const[A,I]of Object.entries(y)){const R=()=>{if(r(A).value===""||!r(A).validity.valid)return;const N=A==="cloud-type"?r(A).value:o(A)/(A==="cloud-cover"?100:1);g(z=>({...z,[I]:N}),A!=="cloud-crystal-alignment")};r(A).addEventListener(A==="cloud-type"?"change":"input",R)}for(const[A,I]of[["cloud-wind-direction","windDirectionDeg"],["cloud-wind-speed","windSpeed"],["cloud-seed","seed"]])r(A).addEventListener("input",()=>{r(A).validity.valid&&g(R=>({...R,[I]:r(A).value===""?void 0:o(A)}))});a.querySelector("#cloud-instance-add").addEventListener("click",()=>{const A=u();if(!A)return;const I=crypto.randomUUID(),R=e.ufoElement.sighting,N=e.ufoElement.currentTime,z=at(R,N),L=Il(N,R.weatherTrack,Ft(R,0),at(R,0),z,A.id),B=e.cloudDirectionAt(0,0),F=A.baseM+A.thicknessM*.4-(z?.elevationM??0)-1.6,V=F*B.y>0?Math.max(500,Math.min(2e4,F/B.y)):5e3,j={id:I,eastM:L.x+B.x*V,northM:-(L.z+B.z*V),baseM:A.baseM,thicknessM:A.thicknessM,widthM:1800,depthM:1200,rotationDeg:0,density:1,darkness:A.darkness};g($=>({...$,instances:[...$.instances??[],j]})),m(),c.value=I,p(),h.textContent+=s(" Individual cloud added, independent of global coverage."," Nuage individuel ajouté : sa présence est indépendante de la couverture globale.")}),a.querySelector("#cloud-instance-delete").addEventListener("click",()=>{const A=c.value;A&&(g(I=>({...I,instances:I.instances?.filter(R=>R.id!==A)})),m())}),a.querySelector("#cloud-instance-point").addEventListener("click",()=>{const A=u(),I=A?.instances?.find($=>$.id===c.value);if(!I)return;e.ufoElement.pause();const R=e.ufoElement.sighting,N=e.ufoElement.currentTime,z=at(R,N),L=Il(N,R.weatherTrack,Ft(R,0),at(R,0),z,A.id),B=I.eastM-L.x,F=I.northM+L.z,V=Math.hypot(B,F),j=I.baseM+I.thicknessM/2-(z?.elevationM??0)-1.6-V**2/(2*6371e3);V===0&&j===0||n((Math.atan2(B,F)*180/Math.PI+360)%360,Math.atan2(j,V)*180/Math.PI)});const T=["eastM","northM","baseM","thicknessM","widthM","depthM","rotationDeg","density","darkness"];return f.forEach((A,I)=>r(`instance-${A}`).addEventListener("input",()=>{const R=c.value,N=r(`instance-${A}`);if(!R||!N.validity.valid||N.value===""&&A!=="darkness")return;const z=T[I],L=N.value===""?void 0:o(`instance-${A}`);g(B=>({...B,instances:B.instances?.map(F=>F.id!==R?F:{...F,[z]:L})}))})),{sync:m,stopManipulation(){w=void 0,x.checked=!1,M.style.touchAction="",M.style.cursor=""},reset(){w=void 0,x.checked=!1,M.style.cursor="",M.style.touchAction="",c.value="",v=-1,m()}}}const Mm=["nw","n","ne","e","se","s","sw","w"],Vv=24,gs=8,Sm=3,Wv=8;function Rr(a,e,t){const n=a.x-e.x,i=a.y-e.y,s=Math.cos(t),r=Math.sin(t);return{x:e.x+n*s-i*r,y:e.y+n*r+i*s}}function Fs(a){return{x:a.x+a.width/2,y:a.y+a.height/2}}const Xv={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 it{static handlePointsFor(e){const{x:t,y:n,width:i,height:s}=e.bounds,r={nw:{x:t,y:n},n:{x:t+i/2,y:n},ne:{x:t+i,y:n},e:{x:t+i,y:n+s/2},se:{x:t+i,y:n+s},s:{x:t+i/2,y:n+s},sw:{x:t,y:n+s},w:{x:t,y:n+s/2},rotate:{x:t+i/2,y:n-Vv}},o=Fs(e.bounds),l={};for(const c of Object.keys(r))l[c]=Rr(r[c],o,e.angle);return l}static hitTestHandle(e,t,n=8,i=[...Mm,"rotate"]){const s=it.handlePointsFor(e);for(const r of i)if(Math.hypot(t.x-s[r].x,t.y-s[r].y)<=n)return r}static HANDLE_DIRECTION_DEG={e:0,se:45,s:90,sw:135,w:180,nw:225,n:270,ne:315};static resizeAxisFor(e,t){const i=((it.HANDLE_DIRECTION_DEG[e]+t*180/Math.PI)%180+180)%180/45,s=["ew","nwse","ns","nesw"];return s[Math.round(i)%s.length]}static resizeBounds(e,t,n,i){const s=Fs(e),r=Rr(i,s,-t),{x:o,y:l,width:c,height:h}=e,d=Xv[n];let u=o,f=l,p=o+c,v=l+h;return d.left&&(u=Math.min(r.x,p-gs)),d.right&&(p=Math.max(r.x,u+gs)),d.top&&(f=Math.min(r.y,v-gs)),d.bottom&&(v=Math.max(r.y,f+gs)),{x:u,y:f,width:p-u,height:v-f}}static resizeShape(e,t,n){if(t==="rotate")throw new Error("resizeShape does not accept the rotate handle");const{width:i,height:s}=e.bounds,r=it.resizeBounds(e.bounds,e.angle,t,n);if(e.kind==="oval")return{...e,bounds:r};const o=i===0?1:r.width/i,l=s===0?1:r.height/s;return{...e,bounds:r,points:e.points.map(c=>({x:c.x*o,y:c.y*l}))}}static rotateShape(e,t){const n=Fs(e.bounds),i=Math.atan2(t.y-n.y,t.x-n.x)+Math.PI/2;return{...e,angle:i}}static groupBoundsFor(e){const t=Math.min(...e.map(r=>r.x)),n=Math.min(...e.map(r=>r.y)),i=Math.max(...e.map(r=>r.x+r.width)),s=Math.max(...e.map(r=>r.y+r.height));return{x:t,y:n,width:i-t,height:s-n}}static vertexPointsFor(e){const t=Fs(e.bounds);return e.points.map(n=>Rr({x:e.bounds.x+n.x,y:e.bounds.y+n.y},t,e.angle))}static hitTestVertex(e,t,n=Wv){const i=it.vertexPointsFor(e);let s,r=n;return i.forEach((o,l)=>{const c=Math.hypot(t.x-o.x,t.y-o.y);c<=r&&(r=c,s=l)}),s}static toLocalPoint(e,t){const n=Fs(e.bounds),i=Rr(t,n,-e.angle);return{x:i.x-e.bounds.x,y:i.y-e.bounds.y}}static moveVertex(e,t,n){const i=e.points.map((d,u)=>u===t?it.toLocalPoint(e,n):d),s=Math.min(...i.map(d=>d.x)),r=Math.min(...i.map(d=>d.y)),o=Math.max(...i.map(d=>d.x)),l=Math.max(...i.map(d=>d.y)),c={x:e.bounds.x+s,y:e.bounds.y+r,width:o-s,height:l-r},h=i.map(d=>({x:d.x-s,y:d.y-r}));return{...e,bounds:c,points:h}}static insertVertexNear(e,t){const n=it.toLocalPoint(e,t),{points:i}=e;let s=i.length-1,r=1/0;for(let l=0;l<i.length;l++){const c=i[l],h=i[(l+1)%i.length],d=it.distanceToSegment(n,c,h);d<r&&(r=d,s=l)}const o=[...i.slice(0,s+1),n,...i.slice(s+1)];return{...e,points:o}}static distanceToSegment(e,t,n){const i=n.x-t.x,s=n.y-t.y,r=i*i+s*s,o=r===0?0:Math.max(0,Math.min(1,((e.x-t.x)*i+(e.y-t.y)*s)/r)),l=t.x+o*i,c=t.y+o*s;return Math.hypot(e.x-l,e.y-c)}static deleteVertex(e,t){return e.points.length<=Sm?e:{...e,points:e.points.filter((n,i)=>i!==t)}}}class dc{constructor(e){this.members=e}bounds(){return it.groupBoundsFor(this.members.map(e=>e.shape.bounds))}scaleTo(e){const t=this.bounds(),n=t.width===0?1:e.width/t.width,i=t.height===0?1:e.height/t.height;return this.members.map(({sourceId:s,shape:r})=>{const o=Math.max(r.bounds.width*n,gs),l=Math.max(r.bounds.height*i,gs),c=e.x+(r.bounds.x-t.x)*n,h=e.y+(r.bounds.y-t.y)*i,d={x:c,y:h,width:o,height:l};return r.kind==="oval"?{sourceId:s,shape:{...r,bounds:d}}:{sourceId:s,shape:{...r,bounds:d,points:r.points.map(u=>({x:u.x*n,y:u.y*i}))}}})}resize(e,t){return this.scaleTo(it.resizeBounds(this.bounds(),0,e,t))}rotate(e,t){const n=Fs(this.bounds()),i=r=>Math.atan2(r.y-n.y,r.x-n.x),s=i(e)-i(t);return this.members.map(({sourceId:r,shape:o})=>{const l=Fs(o.bounds),c=Rr(l,n,s),h={x:c.x-o.bounds.width/2,y:c.y-o.bounds.height/2,width:o.bounds.width,height:o.bounds.height};return{sourceId:r,shape:{...o,bounds:h,angle:o.angle+s}}})}}const Lh=6,mo=Lh/2,lf=20,Nh=24,cf=9,hf=6,df=7,uf=6,ff=4;class Oh{constructor(e){this.ctx=e}starPoints=0;roll=0;clear(e,t){this.ctx.clearRect(0,0,e,t)}static paintExtent(e){const{x:t,y:n,width:i,height:s}=e.bounds,r=t+i/2,o=n+s/2,l=e.angle%(2*Math.PI)!==0,c=Math.hypot(i,s)/2,h=l?c:i/2,d=l?c:s/2,u=Math.max(i,s)/2,f=e.brightness??0,p=f>0?Math.max(u*(1+cf*f),uf*f)-u:0,v=f>0?u*(1+df*f)-u:0,m=3*Nh*(e.blur??0)+1.5*lf*e.haloScale,g=Math.max(p,v,0)+m+2;return{x:r-h-g,y:o-d-g,width:2*(h+g),height:2*(d+g)}}paintInto(e,t,n){this.ctx.save(),this.ctx.scale(n,n),this.ctx.translate(-t.x,-t.y),this.paintShape(e.selected?{...e,selected:!1}:e),this.ctx.restore()}paintShape(e){this.ctx.save(),this.ctx.globalAlpha=1-e.transparency;const t=e.blur??0;t>0&&(this.ctx.filter=`blur(${(Nh*t).toFixed(2)}px)`);const n=e.brightness??0;n>0&&this.paintDazzle(e,n),e.haloScale>0&&this.paintHalo(e),this.paintBase(e),this.ctx.restore(),e.selected&&this.paintSelectionHandles(e)}setStarPoints(e){this.starPoints=Math.max(0,Math.floor(e))}setRoll(e){this.roll=e}paintDazzle(e,t){const{x:n,y:i,width:s,height:r}=e.bounds,o=n+s/2,l=i+r/2,c=Math.max(s,r)/2,h=Math.max(c*(1+cf*t),uf*t);if(h<=0)return;this.ctx.save(),this.ctx.globalCompositeOperation="lighter";const d=this.ctx.createRadialGradient(o,l,0,o,l,h);for(let u=0;u<=hf;u++){const f=u/hf,p=1/(1+24*f*f);this.ctx.globalAlpha=1,d.addColorStop(f,this.withAlpha(e.color,p*t*.55))}if(this.ctx.fillStyle=d,this.ctx.beginPath(),this.ctx.arc(o,l,h,0,2*Math.PI),this.ctx.fill(),this.starPoints>0){const u=c*(1+df*t);this.ctx.lineWidth=Math.max(1,c*.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)*u,m=l+Math.sin(p)*u,g=this.ctx.createLinearGradient(o,l,v,m);g.addColorStop(0,this.withAlpha(e.color,t*.55)),g.addColorStop(.35,this.withAlpha(e.color,t*.22)),g.addColorStop(1,this.withAlpha(e.color,0)),this.ctx.strokeStyle=g,this.ctx.beginPath(),this.ctx.moveTo(o,l),this.ctx.lineTo(v,m),this.ctx.stroke()}}this.ctx.restore()}dazzledFill(e,t){if(t<=0)return e.color;const n=/^#([0-9a-f]{6})$/i.exec(e.color.trim());if(!n)return e.color;const i=Number.parseInt(n[1],16),s=r=>Math.round(r+(255-r)*t);return`rgb(${s(i>>16&255)}, ${s(i>>8&255)}, ${s(i&255)})`}withAlpha(e,t){const n=Math.max(0,Math.min(1,t)),i=/^#([0-9a-f]{6})$/i.exec(e.trim());if(!i)return e;const s=Number.parseInt(i[1],16);return`rgba(${s>>16&255}, ${s>>8&255}, ${s&255}, ${n.toFixed(3)})`}paintBase(e){if(this.ctx.fillStyle=this.dazzledFill(e,e.brightness??0),this.ctx.beginPath(),e.kind==="oval"){const{x:t,y:n,width:i,height:s}=e.bounds,r=i/2,o=s/2;this.ctx.ellipse(t+r,n+o,r,o,e.angle,0,2*Math.PI)}else{const{x:t,y:n,width:i,height:s}=e.bounds;this.ctx.save(),this.ctx.translate(t+i/2,n+s/2),this.ctx.rotate(e.angle),this.ctx.translate(-i/2,-s/2),e.points.forEach((r,o)=>{o===0?this.ctx.moveTo(r.x,r.y):this.ctx.lineTo(r.x,r.y)}),this.ctx.closePath(),this.ctx.restore()}this.ctx.fill()}paintHalo(e){this.ctx.save(),this.ctx.shadowColor=e.color,this.ctx.shadowBlur=lf*e.haloScale,this.paintBase(e),this.ctx.restore()}paintSelectionHandles(e){this.paintHandleFrame(it.handlePointsFor(e),{includeRotate:!0}),e.kind==="polygon"&&this.paintVertexHandles(e)}paintVertexHandles(e){this.ctx.fillStyle="#39f";for(const t of it.vertexPointsFor(e))this.ctx.beginPath(),this.ctx.ellipse(t.x,t.y,ff,ff,0,0,2*Math.PI),this.ctx.fill()}paintMemberOutline(e){this.paintOutline(it.handlePointsFor(e))}paintSelectionOnly(e){this.paintSelectionHandles(e)}paintGroupHandles(e){this.paintHandleFrame(it.handlePointsFor({bounds:e,angle:0}),{includeRotate:!0})}paintOutline(e){this.ctx.strokeStyle="lightgray",this.ctx.beginPath(),this.ctx.moveTo(e.nw.x,e.nw.y),this.ctx.lineTo(e.ne.x,e.ne.y),this.ctx.lineTo(e.se.x,e.se.y),this.ctx.lineTo(e.sw.x,e.sw.y),this.ctx.closePath(),this.ctx.stroke()}paintHandleFrame(e,{includeRotate:t}){this.paintOutline(e),this.ctx.fillStyle="lightgray";for(const n of Mm){const i=e[n];this.ctx.fillRect(i.x-mo,i.y-mo,Lh,Lh)}t&&(this.ctx.beginPath(),this.ctx.moveTo(e.n.x,e.n.y),this.ctx.lineTo(e.rotate.x,e.rotate.y),this.ctx.stroke(),this.ctx.beginPath(),this.ctx.ellipse(e.rotate.x,e.rotate.y,mo+1,mo+1,0,0,2*Math.PI),this.ctx.fill())}}class Os extends Error{constructor(e,t,n){super(`${e}: ${t}${n===void 0?"":` (HTTP ${n})`}`),this.kind=e,this.url=t,this.status=n,this.name="SightingFetchError"}}class fu{static async json(e){const t=new URL(e,location.href);if(location.protocol==="https:"&&t.protocol==="http:")throw new Os("mixed-content",e);let n;try{n=await fetch(e)}catch{throw await this.diagnose(e,t)}if(!n.ok)throw new Os("status",e,n.status);try{return await n.json()}catch{throw new Os("malformed",e)}}static async diagnose(e,t){if(t.origin===location.origin)return new Os("unreachable",e);try{return await fetch(e,{mode:"no-cors"}),new Os("cors",e)}catch{return new Os("unreachable",e)}}}const qv="modulepreload",Yv=function(a,e){return new URL(a,e).href},pf={},ii=function(e,t,n){let i=Promise.resolve();if(t&&t.length>0){let r=function(h){return Promise.all(h.map(d=>Promise.resolve(d).then(u=>({status:"fulfilled",value:u}),u=>({status:"rejected",reason:u}))))};const o=document.getElementsByTagName("link"),l=document.querySelector("meta[property=csp-nonce]"),c=l?.nonce||l?.getAttribute("nonce");i=r(t.map(h=>{if(h=Yv(h,n),h in pf)return;pf[h]=!0;const d=h.endsWith(".css"),u=d?'[rel="stylesheet"]':"";if(!!n)for(let v=o.length-1;v>=0;v--){const m=o[v];if(m.href===h&&(!d||m.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${h}"]${u}`))return;const p=document.createElement("link");if(p.rel=d?"stylesheet":qv,d||(p.as="script"),p.crossOrigin="",p.href=h,c&&p.setAttribute("nonce",c),document.head.appendChild(p),d)return new Promise((v,m)=>{p.addEventListener("load",v),p.addEventListener("error",()=>m(new Error(`Unable to preload CSS for ${h}`)))})}))}function s(r){const o=new Event("vite:preloadError",{cancelable:!0});if(o.payload=r,window.dispatchEvent(o),!o.defaultPrevented)throw r}return i.then(r=>{for(const o of r||[])o.status==="rejected"&&s(o.reason);return e().catch(s)})};class Ln extends Error{constructor(e,t,n){const i=e==="rejected"&&typeof t=="string"?t:void 0,s=e==="rejected"?n:t;super(i??e,s===void 0?void 0:{cause:s}),this.kind=e,this.name="NarrativeError",this.detail=i}detail}class Cl{static of(e){const{recording:t}=On.strip(e),{timeline:n,...i}=t,s=(n?.keyframes??[]).map(o=>Cl.keyframe(o)),r=Object.entries(i).filter(([o,l])=>o!=="version"&&l!==void 0);if(!(r.length===0&&s.every(o=>o.shapes.length===0)))return{...Object.fromEntries(r),...s.length>0?{timeline:{keyframes:s}}:{}}}static keyframe(e){return{t:e.t,shapes:e.shapes.map(t=>Cl.shape(t.sourceId,t.shape))}}static shape(e,t){const n=t??{},i=n.angular,s=n.aim;return{sourceId:e,kind:n.kind??"oval",...n.title===void 0?{}:{title:n.title},...i?.widthDeg===void 0||i.heightDeg===void 0?{}:{angular:{widthDeg:i.widthDeg,heightDeg:i.heightDeg}},...s?.azimuthDeg===void 0||s.altitudeDeg===void 0?{}:{aim:{azimuthDeg:s.azimuthDeg,altitudeDeg:s.altitudeDeg}}}}}const mf={name:"draft_recording",description:"Record what the account states, what justifies each value, and what it leaves out.",input_schema:{type:"object",properties:{recording:{type:"object",description:"The recording, in the format given above. Partial: only the fields the account actually states."},claims:{type:"array",description:"One entry per value in `recording`. EVERY value needs one: a value with no claim is a value nobody can check.",items:{type:"object",properties:{path:{type:"string",description:'Where the value sits in `recording`, dot-joined, array indices as steps: "time.hour", "place.0.lat", "timeline.keyframes.1.shapes.0.shape.angular.widthDeg".'},basis:{type:"string",enum:["stated","derived","assumed"],description:'"stated": the witness said it. "derived": worked out from what they said plus something checkable. "assumed": chosen so the reconstruction has a value at all, on nothing they said.'},rationale:{type:"string",description:`For "stated", the account's own words, copied verbatim, never a paraphrase. For "derived", the working, with the numbers in it. For "assumed", what the guess was chosen for and how wrong it could be.`}},required:["path","basis","rationale"]}},gaps:{type:"array",description:"What nothing could settle, not even a guess worth making — one short sentence each, in the reader's language. Usually empty.",items:{type:"string"}}},required:["recording","claims","gaps"]}},Kv=`You are reading a witness's account of an aerial sighting and reconstructing it in the
|
|
38
38
|
recording format of UFO@home, a tool that replays what a witness reported seeing, from where they
|
|
39
39
|
stood, under the real sky of that moment.
|
|
40
40
|
|
|
@@ -463,18 +463,30 @@ ${e.ask}`,"Answer by calling draft_recording."),t.join(`
|
|
|
463
463
|
<label hidden><span id="label-cloud-darkness">Cloud darkness</span> <input id="cloudDarkness" class="weather-field" type="range" min="0" max="1" step="0.05" value="0"/></label>
|
|
464
464
|
<label hidden><span id="label-cloud-base">Cloud base</span>
|
|
465
465
|
<input id="cloudBase" class="weather-field" type="number" min="0" step="50" placeholder="1000" title="Height of the cloud layer's base above the ground — decides whether the witness is under the deck or above it"/> m</label>
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
466
|
+
<!-- The weather in three parts — the clouds above (their own fieldset), what falls, and what
|
|
467
|
+
blows — because a dozen controls in one row read as one undifferentiated dial bank. The
|
|
468
|
+
storm sits with what falls, not with the clouds it is made of: a thunderstorm is what a
|
|
469
|
+
weather CODE reports (Open-Meteo's, where the provider reads it from, METAR's TS beside RA
|
|
470
|
+
and GR), a discrete present-weather event like hail, where a cloud layer is a continuous
|
|
471
|
+
thing with a height. -->
|
|
472
|
+
<fieldset class="weather-group">
|
|
473
|
+
<legend id="label-precipitation-group">Precipitation</legend>
|
|
474
|
+
<label><span id="label-precipitation-type">Precipitation</span>
|
|
475
|
+
<select id="precipitationType" class="weather-field">
|
|
476
|
+
<option id="option-precipitation-none" value="none">None</option>
|
|
477
|
+
<option id="option-precipitation-rain" value="rain">Rain</option>
|
|
478
|
+
<option id="option-precipitation-snow" value="snow">Snow</option>
|
|
479
|
+
<option id="option-precipitation-hail" value="hail">Hail</option>
|
|
480
|
+
</select>
|
|
481
|
+
</label>
|
|
482
|
+
<label><span id="label-precipitation-intensity">Intensity</span> <input id="precipitationIntensity" class="weather-field" type="range" min="0" max="1" step="0.05" value="0"/></label>
|
|
483
|
+
<label><span id="label-storm">Storm</span> <input id="storm" class="weather-field" type="checkbox"/></label>
|
|
484
|
+
</fieldset>
|
|
485
|
+
<fieldset class="weather-group">
|
|
486
|
+
<legend id="label-wind-group">Wind</legend>
|
|
487
|
+
<label><span id="label-wind-direction">Wind direction</span> <input id="windDirection" class="weather-field" type="number" min="0" max="360" step="1" value="0" title="The direction the wind blows TOWARD, clockwise from true north — the opposite of the meteorological convention a forecast uses (see Weather.windDirectionDeg)"/> °</label>
|
|
488
|
+
<label><span id="label-wind-speed">Wind speed</span> <input id="windSpeed" class="weather-field" type="number" min="0" max="30" step="0.5" value="0"/> m/s</label>
|
|
489
|
+
</fieldset>
|
|
478
490
|
</div>
|
|
479
491
|
</section>
|
|
480
492
|
<!-- Its own group rather than a row of the Shape group below: what the object sounded like is
|
|
@@ -941,6 +953,25 @@ select.weather-field:disabled {
|
|
|
941
953
|
.toolbar > label.checkbox {
|
|
942
954
|
gap: 0.35em;
|
|
943
955
|
}
|
|
956
|
+
/* A named part of a group — the weather's clouds, precipitation and wind. The same frame as the
|
|
957
|
+
cloud layers' own fieldset (see cloudEditorTemplate), so the three read as siblings. */
|
|
958
|
+
.toolbar fieldset {
|
|
959
|
+
min-width: 0;
|
|
960
|
+
margin: 0;
|
|
961
|
+
padding: 0.3em 0.6em 0.45em;
|
|
962
|
+
border: 1px solid color-mix(in srgb, currentColor 30%, transparent);
|
|
963
|
+
border-radius: 0.4em;
|
|
964
|
+
}
|
|
965
|
+
.toolbar fieldset > legend {
|
|
966
|
+
padding: 0 0.3em;
|
|
967
|
+
font-weight: 600;
|
|
968
|
+
}
|
|
969
|
+
.toolbar > fieldset.weather-group {
|
|
970
|
+
display: flex;
|
|
971
|
+
flex-wrap: wrap;
|
|
972
|
+
align-items: center;
|
|
973
|
+
gap: 0.5em;
|
|
974
|
+
}
|
|
944
975
|
#description {
|
|
945
976
|
font: inherit;
|
|
946
977
|
resize: vertical;
|
|
@@ -1390,7 +1421,7 @@ select.weather-field:disabled {
|
|
|
1390
1421
|
.submenu label:hover {
|
|
1391
1422
|
background: #eef;
|
|
1392
1423
|
}
|
|
1393
|
-
`,vf="#ff2200",yf="#00ff44",As="#ffffff",go="#ffa500",sa="#ff0000",i1="#2244ff",Uh=[{id:"airliner",name:"Airliner",kinds:["aircraft"],create:()=>[{id:"nav-port",offsetM:{x:-17,y:0,z:0},color:vf,pattern:{kind:"steady"}},{id:"nav-starboard",offsetM:{x:17,y:0,z:0},color:yf,pattern:{kind:"steady"}},{id:"nav-tail",offsetM:{x:0,y:1,z:-18},color:As,pattern:{kind:"steady"}},{id:"beacon-top",offsetM:{x:0,y:2,z:0},color:sa,intensity:1.5,pattern:{kind:"flash",perMinute:45,dutyCycle:.18}},{id:"beacon-bottom",offsetM:{x:0,y:-2,z:0},color:sa,intensity:1.5,pattern:{kind:"flash",perMinute:45,dutyCycle:.18}},{id:"strobe-port",offsetM:{x:-17,y:0,z:-1},color:As,intensity:20,pattern:{kind:"flash",perMinute:60,dutyCycle:.01}},{id:"strobe-starboard",offsetM:{x:17,y:0,z:-1},color:As,intensity:20,pattern:{kind:"flash",perMinute:60,dutyCycle:.01,phase:.08}}]},{id:"helicopter",name:"Helicopter",kinds:["aircraft"],create:()=>[{id:"nav-port",offsetM:{x:-5,y:0,z:0},color:vf,pattern:{kind:"steady"}},{id:"nav-starboard",offsetM:{x:5,y:0,z:0},color:yf,pattern:{kind:"steady"}},{id:"nav-tail",offsetM:{x:0,y:1,z:-7},color:As,pattern:{kind:"steady"}},{id:"beacon",offsetM:{x:0,y:2,z:-2},color:sa,intensity:1.5,pattern:{kind:"flash",perMinute:45,dutyCycle:.2}},{id:"strobe",offsetM:{x:0,y:-1,z:0},color:As,intensity:15,pattern:{kind:"flash",perMinute:75,dutyCycle:.015}}]},{id:"car-headlights",name:"Car, headlights on",kinds:["vehicle"],create:()=>[{id:"head-left",offsetM:{x:-.7,y:.6,z:2},color:As,intensity:2,pattern:{kind:"steady"}},{id:"head-right",offsetM:{x:.7,y:.6,z:2},color:As,intensity:2,pattern:{kind:"steady"}},{id:"tail-left",offsetM:{x:-.7,y:.6,z:-2},color:sa,pattern:{kind:"steady"}},{id:"tail-right",offsetM:{x:.7,y:.6,z:-2},color:sa,pattern:{kind:"steady"}}]},{id:"car-hazards",name:"Car, hazard flashers",kinds:["vehicle"],create:()=>[{id:"hazard-front-left",offsetM:{x:-.8,y:.6,z:2},color:go,pattern:{kind:"flash",perMinute:90,dutyCycle:.5}},{id:"hazard-front-right",offsetM:{x:.8,y:.6,z:2},color:go,pattern:{kind:"flash",perMinute:90,dutyCycle:.5}},{id:"hazard-rear-left",offsetM:{x:-.8,y:.6,z:-2},color:go,pattern:{kind:"flash",perMinute:90,dutyCycle:.5}},{id:"hazard-rear-right",offsetM:{x:.8,y:.6,z:-2},color:go,pattern:{kind:"flash",perMinute:90,dutyCycle:.5}}]},{id:"emergency-beacons",name:"Emergency vehicle beacons",kinds:["vehicle"],create:()=>[{id:"beacon-blue",offsetM:{x:-.4,y:1.6,z:0},color:i1,intensity:2.5,pattern:{kind:"flash",perMinute:120,dutyCycle:.1}},{id:"beacon-red",offsetM:{x:.4,y:1.6,z:0},color:sa,intensity:2.5,pattern:{kind:"flash",perMinute:120,dutyCycle:.1,phase:.5}}]},{id:"streetlamp",name:"Streetlamp",kinds:["streetlight"],create:()=>[{id:"lamp",offsetM:{x:0,y:5,z:0},color:"#ffd9a0",intensity:2,pattern:{kind:"steady"}}]}];class uc{static forKind(e){return Uh.filter(t=>t.kinds.includes(e))}static byId(e){return Uh.find(t=>t.id===e)}}class Bh{constructor(e){this.names=e}name(e){return this.names[e.toLowerCase()]??e}stored(e){const t=e.trim().toLowerCase();for(const[n,i]of Object.entries(this.names))if(i.toLowerCase()===t)return n;return e.trim()}}class bf{constructor(e,t,n,i=new Bh({})){this.labels=e,this.language=t,this.said=n,this.tags=i}entriesFor(e,t,n={}){const i=[];return this.addObservation(i,e),this.addWitness(i,e,t),this.addLocation(i,e,t,n.groundElevationM),this.addDecor(i,e,t,n),this.addTemporal(i,e),this.addWeather(i,e,t),this.addSound(i,e,t),i}push(e,t,n,i,s,r="",o={}){s===void 0||s===""||e.push({group:t,field:n,label:i,value:String(s),unit:r,color:o.color,fromSource:o.fromSource===!0})}percent(e){return e===void 0?void 0:`${Math.round(e*100)} %`}rounded(e,t=0){return e===void 0?void 0:String(Number(e.toFixed(t)))}shows(e,t=0){return e!==void 0&&Number(e.toFixed(t))!==0}showsPercent(e){return this.shows(e===void 0?void 0:e*100)}percentShown(e){return this.showsPercent(e)?this.percent(e):void 0}roundedShown(e,t=0){return this.shows(e,t)?this.rounded(e,t):void 0}addObservation(e,t){this.push(e,"observation","caseId",this.labels.caseId,t.caseId);const n=t.event.tags;this.push(e,"observation","tags",this.labels.tags,n&&n.length>0?n.map(i=>this.tags.name(i)).join(", "):void 0)}addWitness(e,t,n){const i=t.witness;this.push(e,"witness","witnessId",this.labels.witnessId,i?.id),this.push(e,"witness","witnessTitle",this.labels.witnessTitle,i?.title),this.push(e,"witness","witnessLastName",this.labels.witnessLastName,i?.lastName);const s=i?.firstNames;this.push(e,"witness","witnessFirstNames",this.labels.witnessFirstNames,s&&s.length>0?s.join(", "):void 0);const r=t.instrument;this.push(e,"witness","instrument",this.labels.instrument,r.name[this.language]);const o=t.exposure;this.push(e,"witness","exposureSeconds",this.labels.exposure,o===void 0?void 0:o<1?`1/${Math.round(1/o)}`:this.rounded(o,2),"s");const l=at(t,n);if(l){const c=st.focalLengthMmFor(r,l.fovDeg);c===void 0?this.push(e,"witness","focalLength",this.labels.fieldOfView,this.rounded(l.fovDeg,1),"°"):this.push(e,"witness","focalLength",this.labels.focalLength,this.rounded(c,1),"mm"),this.push(e,"witness","fNumber",this.labels.aperture,this.rounded(l.fNumber??r.fNumber,1)),this.push(e,"witness","focusDistance",this.labels.focusDistance,this.rounded(l.focusDistanceM,1),"m"),this.push(e,"witness","roll",this.labels.roll,this.roundedShown(l.rollDeg),"°")}}addLocation(e,t,n,i){const s=t.event.place?.[0];this.push(e,"location","placeName",this.labels.placeName,s?.name);const r=at(t,n);r&&(this.push(e,"location","lat",this.labels.latitude,this.rounded(r.lat,6)),this.push(e,"location","lng",this.labels.longitude,this.rounded(r.lng,6)),this.push(e,"location","heading",this.labels.heading,this.rounded(r.headingDeg),"°"),this.push(e,"location","pitch",this.labels.pitch,this.rounded(r.pitchDeg),"°"),i===void 0?this.push(e,"location","elevation",this.labels.heightAboveGround,this.roundedShown(r.elevationM),"m"):this.push(e,"location","elevation",this.labels.elevation,this.rounded(i+r.elevationM),"m"))}addDecor(e,t,n,i){const s=t.decor.find(c=>c.id===i.decorId);if(!s){if(i.decorPicker===!0)for(const c of t.decor)this.push(e,"decor",`decor:${c.id}`,this.decorLabel(c),this.decorKindName(c.kind));return}this.push(e,"decor","decorTitle",this.labels.decorTitle,this.said.read(s.title));const r=Qa(s,n);this.push(e,"decor","decorEast",this.labels.decorEast,this.rounded(r.eastM,1),"m"),this.push(e,"decor","decorNorth",this.labels.decorNorth,this.rounded(r.northM,1),"m"),this.push(e,"decor","decorAltitude",this.labels.decorAltitude,this.roundedShown(r.altitudeM),"m"),this.push(e,"decor","decorHeading",this.labels.decorHeading,this.rounded(r.headingDeg),"°"),Rl(s,n)&&this.push(e,"decor","decorLit",this.labels.decorLit,"✓");const o=s.lights?.map(c=>c.id).join()??"",l=o===""?void 0:Uh.find(c=>c.create().map(h=>h.id).join()===o);this.push(e,"decor","decorLightRig",this.labels.decorLights,l?.name),this.push(e,"decor","decorFloors",this.labels.decorFloors,s.floors),this.push(e,"decor","decorOccupiedFloor",this.labels.decorOccupiedFloor,s.occupiedFloor),this.push(e,"decor","decorWitnessSide",this.labels.decorWitnessSide,this.decorSideName(s.witnessSide));for(const[c,h]of Object.entries(s.windows??{}))this.push(e,"decor",`decorWindow${this.capitalise(c)}`,`${this.labels.decorWindows} ${this.decorSideName(c)}`,h,"%")}addTemporal(e,t){const n=t.event;this.push(e,"temporal","obs-time",this.labels.observationTime,n.time&&Dl(n.time)),this.push(e,"temporal","obs-end-time",this.labels.observationEndTime,n.endTime&&Dl(n.endTime));const i=ja(n);this.push(e,"temporal","durationSeconds",this.labels.duration,this.roundedShown(i&&i/1e3,1),"s"),this.push(e,"temporal","timeZone",this.labels.utcOffset,n.timeZone),this.push(e,"temporal","utcOffsetHours",this.labels.utcOffset,this.rounded(n.utcOffsetHours,1),"UTC±h")}addWeather(e,t,n){const i=Ht(t,n),r={fromSource:t.weatherSource!==void 0},o=this.showsPercent(i.cloudCover)||this.showsPercent(i.lowerCloudCover)||this.showsPercent(i.highCloudCover);this.push(e,"weather","cloudCover",this.labels.cloudCover,this.percentShown(i.cloudCover),"",r),this.push(e,"weather","highCloudCover",this.labels.highCloudCover,this.percentShown(i.highCloudCover),"",r),this.push(e,"weather","iceCrystalAlignment",this.labels.iceCrystalAlignment,this.showsPercent(i.highCloudCover)?this.percent(i.iceCrystalAlignment):void 0),this.push(e,"weather","cloudDarkness",this.labels.cloudDarkness,o?this.percent(i.cloudDarkness):void 0,"",r),this.push(e,"weather","cloudBase",this.labels.cloudBase,o?this.rounded(i.cloudBaseM):void 0,"m",r);const l=i.precipitationType!=="none"&&this.showsPercent(i.precipitationIntensity);this.push(e,"weather","precipitationType",this.labels.precipitationType,l?this.precipitationName(i.precipitationType):void 0,"",r),this.push(e,"weather","precipitationIntensity",this.labels.precipitationIntensity,l?this.percent(i.precipitationIntensity):void 0,"",r),this.push(e,"weather","windDirection",this.labels.windDirection,this.shows(i.windSpeed,2)?this.rounded(i.windDirectionDeg):void 0,"°",r),this.push(e,"weather","windSpeed",this.labels.windSpeed,this.roundedShown(i.windSpeed,2),"m/s",r),i.storm&&this.push(e,"weather","storm",this.labels.storm,"✓","",r)}addSound(e,t,n){const i=uu(t,n);i.kind!=="none"&&(this.push(e,"sound","soundKind",this.labels.soundKind,this.soundKindName(i.kind)),this.push(e,"sound","soundVolume",this.labels.soundVolume,this.percentShown(i.volume)),this.push(e,"sound","soundPitch",this.labels.soundPitch,this.roundedShown(i.pitchHz),"Hz"),this.push(e,"sound","soundSrc",this.labels.soundSrc,i.src))}decorLabel(e){return this.said.read(e.title)??this.decorKindName(e.kind)}decorKindName(e){switch(e){case"building":return this.labels.decorBuilding;case"tree":return this.labels.decorTree;case"crop":return this.labels.decorCrop;case"mound":return this.labels.decorMound;case"streetlight":return this.labels.decorStreetlight;case"vehicle":return this.labels.decorVehicle;case"aircraft":return this.labels.decorAircraft;default:return this.labels.decorWitness}}decorSideName(e){switch(e){case"front":return this.labels.decorSideFront;case"behind":return this.labels.decorSideBehind;case"left":return this.labels.decorSideLeft;case"right":return this.labels.decorSideRight;case"front-left":return this.labels.decorSideFrontLeft;case"front-right":return this.labels.decorSideFrontRight;case"behind-left":return this.labels.decorSideBehindLeft;case"behind-right":return this.labels.decorSideBehindRight;default:return}}precipitationName(e){switch(e){case"rain":return this.labels.precipitationRain;case"snow":return this.labels.precipitationSnow;case"hail":return this.labels.precipitationHail;default:return this.labels.precipitationNone}}soundKindName(e){switch(e){case"hum":return this.labels.soundHum;case"whistle":return this.labels.soundWhistle;case"rumble":return this.labels.soundRumble;case"crackle":return this.labels.soundCrackle;default:return this.labels.soundNone}}capitalise(e){return e.replace(/(^|-)([a-z])/g,(t,n,i)=>i.toUpperCase())}}const s1=`
|
|
1424
|
+
`,vf="#ff2200",yf="#00ff44",As="#ffffff",go="#ffa500",sa="#ff0000",i1="#2244ff",Uh=[{id:"airliner",name:"Airliner",kinds:["aircraft"],create:()=>[{id:"nav-port",offsetM:{x:-17,y:0,z:0},color:vf,pattern:{kind:"steady"}},{id:"nav-starboard",offsetM:{x:17,y:0,z:0},color:yf,pattern:{kind:"steady"}},{id:"nav-tail",offsetM:{x:0,y:1,z:-18},color:As,pattern:{kind:"steady"}},{id:"beacon-top",offsetM:{x:0,y:2,z:0},color:sa,intensity:1.5,pattern:{kind:"flash",perMinute:45,dutyCycle:.18}},{id:"beacon-bottom",offsetM:{x:0,y:-2,z:0},color:sa,intensity:1.5,pattern:{kind:"flash",perMinute:45,dutyCycle:.18}},{id:"strobe-port",offsetM:{x:-17,y:0,z:-1},color:As,intensity:20,pattern:{kind:"flash",perMinute:60,dutyCycle:.01}},{id:"strobe-starboard",offsetM:{x:17,y:0,z:-1},color:As,intensity:20,pattern:{kind:"flash",perMinute:60,dutyCycle:.01,phase:.08}}]},{id:"helicopter",name:"Helicopter",kinds:["aircraft"],create:()=>[{id:"nav-port",offsetM:{x:-5,y:0,z:0},color:vf,pattern:{kind:"steady"}},{id:"nav-starboard",offsetM:{x:5,y:0,z:0},color:yf,pattern:{kind:"steady"}},{id:"nav-tail",offsetM:{x:0,y:1,z:-7},color:As,pattern:{kind:"steady"}},{id:"beacon",offsetM:{x:0,y:2,z:-2},color:sa,intensity:1.5,pattern:{kind:"flash",perMinute:45,dutyCycle:.2}},{id:"strobe",offsetM:{x:0,y:-1,z:0},color:As,intensity:15,pattern:{kind:"flash",perMinute:75,dutyCycle:.015}}]},{id:"car-headlights",name:"Car, headlights on",kinds:["vehicle"],create:()=>[{id:"head-left",offsetM:{x:-.7,y:.6,z:2},color:As,intensity:2,pattern:{kind:"steady"}},{id:"head-right",offsetM:{x:.7,y:.6,z:2},color:As,intensity:2,pattern:{kind:"steady"}},{id:"tail-left",offsetM:{x:-.7,y:.6,z:-2},color:sa,pattern:{kind:"steady"}},{id:"tail-right",offsetM:{x:.7,y:.6,z:-2},color:sa,pattern:{kind:"steady"}}]},{id:"car-hazards",name:"Car, hazard flashers",kinds:["vehicle"],create:()=>[{id:"hazard-front-left",offsetM:{x:-.8,y:.6,z:2},color:go,pattern:{kind:"flash",perMinute:90,dutyCycle:.5}},{id:"hazard-front-right",offsetM:{x:.8,y:.6,z:2},color:go,pattern:{kind:"flash",perMinute:90,dutyCycle:.5}},{id:"hazard-rear-left",offsetM:{x:-.8,y:.6,z:-2},color:go,pattern:{kind:"flash",perMinute:90,dutyCycle:.5}},{id:"hazard-rear-right",offsetM:{x:.8,y:.6,z:-2},color:go,pattern:{kind:"flash",perMinute:90,dutyCycle:.5}}]},{id:"emergency-beacons",name:"Emergency vehicle beacons",kinds:["vehicle"],create:()=>[{id:"beacon-blue",offsetM:{x:-.4,y:1.6,z:0},color:i1,intensity:2.5,pattern:{kind:"flash",perMinute:120,dutyCycle:.1}},{id:"beacon-red",offsetM:{x:.4,y:1.6,z:0},color:sa,intensity:2.5,pattern:{kind:"flash",perMinute:120,dutyCycle:.1,phase:.5}}]},{id:"streetlamp",name:"Streetlamp",kinds:["streetlight"],create:()=>[{id:"lamp",offsetM:{x:0,y:5,z:0},color:"#ffd9a0",intensity:2,pattern:{kind:"steady"}}]}];class uc{static forKind(e){return Uh.filter(t=>t.kinds.includes(e))}static byId(e){return Uh.find(t=>t.id===e)}}class Bh{constructor(e){this.names=e}name(e){return this.names[e.toLowerCase()]??e}stored(e){const t=e.trim().toLowerCase();for(const[n,i]of Object.entries(this.names))if(i.toLowerCase()===t)return n;return e.trim()}}class bf{constructor(e,t,n,i=new Bh({})){this.labels=e,this.language=t,this.said=n,this.tags=i}entriesFor(e,t,n={}){const i=[];return this.addObservation(i,e),this.addWitness(i,e,t),this.addLocation(i,e,t,n.groundElevationM),this.addDecor(i,e,t,n),this.addTemporal(i,e),this.addWeather(i,e,t),this.addSound(i,e,t),i}push(e,t,n,i,s,r="",o={}){s===void 0||s===""||e.push({group:t,field:n,label:i,value:String(s),unit:r,color:o.color,fromSource:o.fromSource===!0})}percent(e){return e===void 0?void 0:`${Math.round(e*100)} %`}rounded(e,t=0){return e===void 0?void 0:String(Number(e.toFixed(t)))}shows(e,t=0){return e!==void 0&&Number(e.toFixed(t))!==0}showsPercent(e){return this.shows(e===void 0?void 0:e*100)}percentShown(e){return this.showsPercent(e)?this.percent(e):void 0}roundedShown(e,t=0){return this.shows(e,t)?this.rounded(e,t):void 0}addObservation(e,t){this.push(e,"observation","caseId",this.labels.caseId,t.caseId);const n=t.event.tags;this.push(e,"observation","tags",this.labels.tags,n&&n.length>0?n.map(i=>this.tags.name(i)).join(", "):void 0)}addWitness(e,t,n){const i=t.witness;this.push(e,"witness","witnessId",this.labels.witnessId,i?.id),this.push(e,"witness","witnessTitle",this.labels.witnessTitle,i?.title),this.push(e,"witness","witnessLastName",this.labels.witnessLastName,i?.lastName);const s=i?.firstNames;this.push(e,"witness","witnessFirstNames",this.labels.witnessFirstNames,s&&s.length>0?s.join(", "):void 0);const r=t.instrument;this.push(e,"witness","instrument",this.labels.instrument,r.name[this.language]);const o=t.exposure;this.push(e,"witness","exposureSeconds",this.labels.exposure,o===void 0?void 0:o<1?`1/${Math.round(1/o)}`:this.rounded(o,2),"s");const l=at(t,n);if(l){const c=st.focalLengthMmFor(r,l.fovDeg);c===void 0?this.push(e,"witness","focalLength",this.labels.fieldOfView,this.rounded(l.fovDeg,1),"°"):this.push(e,"witness","focalLength",this.labels.focalLength,this.rounded(c,1),"mm"),this.push(e,"witness","fNumber",this.labels.aperture,this.rounded(l.fNumber??r.fNumber,1)),this.push(e,"witness","focusDistance",this.labels.focusDistance,this.rounded(l.focusDistanceM,1),"m"),this.push(e,"witness","roll",this.labels.roll,this.roundedShown(l.rollDeg),"°")}}addLocation(e,t,n,i){const s=t.event.place?.[0];this.push(e,"location","placeName",this.labels.placeName,s?.name);const r=at(t,n);r&&(this.push(e,"location","lat",this.labels.latitude,this.rounded(r.lat,6)),this.push(e,"location","lng",this.labels.longitude,this.rounded(r.lng,6)),this.push(e,"location","heading",this.labels.heading,this.rounded(r.headingDeg),"°"),this.push(e,"location","pitch",this.labels.pitch,this.rounded(r.pitchDeg),"°"),i===void 0?this.push(e,"location","elevation",this.labels.heightAboveGround,this.roundedShown(r.elevationM),"m"):this.push(e,"location","elevation",this.labels.elevation,this.rounded(i+r.elevationM),"m"))}addDecor(e,t,n,i){const s=t.decor.find(c=>c.id===i.decorId);if(!s){if(i.decorPicker===!0)for(const c of t.decor)this.push(e,"decor",`decor:${c.id}`,this.decorLabel(c),this.decorKindName(c.kind));return}this.push(e,"decor","decorTitle",this.labels.decorTitle,this.said.read(s.title));const r=Qa(s,n);this.push(e,"decor","decorEast",this.labels.decorEast,this.rounded(r.eastM,1),"m"),this.push(e,"decor","decorNorth",this.labels.decorNorth,this.rounded(r.northM,1),"m"),this.push(e,"decor","decorAltitude",this.labels.decorAltitude,this.roundedShown(r.altitudeM),"m"),this.push(e,"decor","decorHeading",this.labels.decorHeading,this.rounded(r.headingDeg),"°"),Rl(s,n)&&this.push(e,"decor","decorLit",this.labels.decorLit,"✓");const o=s.lights?.map(c=>c.id).join()??"",l=o===""?void 0:Uh.find(c=>c.create().map(h=>h.id).join()===o);this.push(e,"decor","decorLightRig",this.labels.decorLights,l?.name),this.push(e,"decor","decorFloors",this.labels.decorFloors,s.floors),this.push(e,"decor","decorOccupiedFloor",this.labels.decorOccupiedFloor,s.occupiedFloor),this.push(e,"decor","decorWitnessSide",this.labels.decorWitnessSide,this.decorSideName(s.witnessSide));for(const[c,h]of Object.entries(s.windows??{}))this.push(e,"decor",`decorWindow${this.capitalise(c)}`,`${this.labels.decorWindows} ${this.decorSideName(c)}`,h,"%")}addTemporal(e,t){const n=t.event;this.push(e,"temporal","obs-time",this.labels.observationTime,n.time&&Dl(n.time)),this.push(e,"temporal","obs-end-time",this.labels.observationEndTime,n.endTime&&Dl(n.endTime));const i=ja(n);this.push(e,"temporal","durationSeconds",this.labels.duration,this.roundedShown(i&&i/1e3,1),"s"),this.push(e,"temporal","timeZone",this.labels.utcOffset,n.timeZone),this.push(e,"temporal","utcOffsetHours",this.labels.utcOffset,this.rounded(n.utcOffsetHours,1),"UTC±h")}addWeather(e,t,n){const i=Ft(t,n),r={fromSource:t.weatherSource!==void 0},o=this.showsPercent(i.cloudCover)||this.showsPercent(i.lowerCloudCover)||this.showsPercent(i.highCloudCover);this.push(e,"weather","cloudCover",this.labels.cloudCover,this.percentShown(i.cloudCover),"",r),this.push(e,"weather","highCloudCover",this.labels.highCloudCover,this.percentShown(i.highCloudCover),"",r),this.push(e,"weather","iceCrystalAlignment",this.labels.iceCrystalAlignment,this.showsPercent(i.highCloudCover)?this.percent(i.iceCrystalAlignment):void 0),this.push(e,"weather","cloudDarkness",this.labels.cloudDarkness,o?this.percent(i.cloudDarkness):void 0,"",r),this.push(e,"weather","cloudBase",this.labels.cloudBase,o?this.rounded(i.cloudBaseM):void 0,"m",r);const l=i.precipitationType!=="none"&&this.showsPercent(i.precipitationIntensity);this.push(e,"weather","precipitationType",this.labels.precipitationType,l?this.precipitationName(i.precipitationType):void 0,"",r),this.push(e,"weather","precipitationIntensity",this.labels.precipitationIntensity,l?this.percent(i.precipitationIntensity):void 0,"",r),this.push(e,"weather","windDirection",this.labels.windDirection,this.shows(i.windSpeed,2)?this.rounded(i.windDirectionDeg):void 0,"°",r),this.push(e,"weather","windSpeed",this.labels.windSpeed,this.roundedShown(i.windSpeed,2),"m/s",r),i.storm&&this.push(e,"weather","storm",this.labels.storm,"✓","",r)}addSound(e,t,n){const i=uu(t,n);i.kind!=="none"&&(this.push(e,"sound","soundKind",this.labels.soundKind,this.soundKindName(i.kind)),this.push(e,"sound","soundVolume",this.labels.soundVolume,this.percentShown(i.volume)),this.push(e,"sound","soundPitch",this.labels.soundPitch,this.roundedShown(i.pitchHz),"Hz"),this.push(e,"sound","soundSrc",this.labels.soundSrc,i.src))}decorLabel(e){return this.said.read(e.title)??this.decorKindName(e.kind)}decorKindName(e){switch(e){case"building":return this.labels.decorBuilding;case"tree":return this.labels.decorTree;case"crop":return this.labels.decorCrop;case"mound":return this.labels.decorMound;case"streetlight":return this.labels.decorStreetlight;case"vehicle":return this.labels.decorVehicle;case"aircraft":return this.labels.decorAircraft;default:return this.labels.decorWitness}}decorSideName(e){switch(e){case"front":return this.labels.decorSideFront;case"behind":return this.labels.decorSideBehind;case"left":return this.labels.decorSideLeft;case"right":return this.labels.decorSideRight;case"front-left":return this.labels.decorSideFrontLeft;case"front-right":return this.labels.decorSideFrontRight;case"behind-left":return this.labels.decorSideBehindLeft;case"behind-right":return this.labels.decorSideBehindRight;default:return}}precipitationName(e){switch(e){case"rain":return this.labels.precipitationRain;case"snow":return this.labels.precipitationSnow;case"hail":return this.labels.precipitationHail;default:return this.labels.precipitationNone}}soundKindName(e){switch(e){case"hum":return this.labels.soundHum;case"whistle":return this.labels.soundWhistle;case"rumble":return this.labels.soundRumble;case"crackle":return this.labels.soundCrackle;default:return this.labels.soundNone}}capitalise(e){return e.replace(/(^|-)([a-z])/g,(t,n,i)=>i.toUpperCase())}}const s1=`
|
|
1394
1425
|
<div class="stage" id="stage">
|
|
1395
1426
|
<div class="frame" id="frame">
|
|
1396
1427
|
<canvas id="canvas" width="640" height="360"></canvas>
|
|
@@ -1793,7 +1824,7 @@ input[type=range] {
|
|
|
1793
1824
|
pointer-events: none;
|
|
1794
1825
|
white-space: nowrap;
|
|
1795
1826
|
}
|
|
1796
|
-
`;class Zr{constructor(e){this.points=e}static STATIONARY_M=5;static of(e){const t=[];for(const n of e.witnessTrack.allKeyframes){const{lat:i,lng:s,headingDeg:r}=n.pose;i===void 0||s===void 0||t.push({t:n.t,lat:i,lng:s,headingDeg:r})}if(t.length===0){const n=e.event.place?.[0];if(!n)return;t.push({t:0,lat:n.lat,lng:n.lng})}return new Zr(t)}get moved(){return this.spanM>Zr.STATIONARY_M}get spanM(){const e=this.box,t=(e.south+e.north)/2,n=(e.west+e.east)/2;return Math.max(Math.abs(un(t,e.east,t,e.west).x),Math.abs(un(e.north,n,e.south,n).z))}get center(){const e=this.box;return{lat:(e.south+e.north)/2,lng:(e.west+e.east)/2}}boundsAround(e,t){const{lat:n,lng:i}=this.center,s=Math.max(this.spanM*(1+t),e)/2;return{north:Wi(0,-s,n,i).lat,south:Wi(0,s,n,i).lat,east:Wi(s,0,n,i).lng,west:Wi(-s,0,n,i).lng}}get box(){const e=this.points.map(n=>n.lat),t=this.points.map(n=>n.lng);return{south:Math.min(...e),north:Math.max(...e),west:Math.min(...t),east:Math.max(...t)}}}class qt{constructor(e,t){this.stretches=e,this.rotationPassed=t}static REFERENCE_SPEED_M_PER_S=1.4;static REFERENCE_STEP_HZ=1.9;static CADENCE_EXPONENT=.43;static RISE_M_PER_M_PER_S=.0175;static SWAY_M=.0175;static SLOWEST_WALK_M_PER_S=.2;static FASTEST_WALK_M_PER_S=2.2;static HEAD_ROLL_DEG=1.5;static HEAD_PITCH_DEG=1.25;static HEAD_YAW_DEG=1;static STILL=Object.freeze({eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0});static of(e){const t=Zr.of(e);if(!t||t.points.length<2)return;const n=[];let i=0;for(let s=1;s<t.points.length;s++){const r=t.points[s-1],o=t.points[s],l=(o.t-r.t)/1e3;if(l<=0)continue;const c=un(o.lat,o.lng,r.lat,r.lng),h=c.x,d=-c.z,u=Math.hypot(h,d),f=u/l,p=qt.stepHzFor(f);n.push({startMs:r.t,endMs:o.t,speedMPerS:f,eastUnit:u>0?h/u:0,northUnit:u>0?d/u:0,stepHz:p,stepsBefore:i,rampsIn:!0,rampsOut:!0}),i+=p*l}for(let s=0;s<n.length;s++){const r=n[s-1],o=n[s+1];n[s].rampsIn=r===void 0||r.stepHz===0,n[s].rampsOut=o===void 0||o.stepHz===0}if(n.some(s=>s.stepHz>0))return new qt(n,1-(e.instrument.stabilization??0))}static stepHzFor(e){return e<qt.SLOWEST_WALK_M_PER_S||e>qt.FASTEST_WALK_M_PER_S?0:qt.REFERENCE_STEP_HZ*Math.pow(e/qt.REFERENCE_SPEED_M_PER_S,qt.CADENCE_EXPONENT)}offsetAt(e){const t=this.stretches.find(l=>e>=l.startMs&&e<=l.endMs);if(!t||t.stepHz===0)return qt.STILL;const n=t.stepsBefore+t.stepHz*(e-t.startMs)/1e3,i=2*Math.PI*n,s=this.amplitudeAt(t,e),r=qt.SWAY_M*s*Math.cos(i/2),o=s*this.rotationPassed*t.speedMPerS/qt.REFERENCE_SPEED_M_PER_S;return{eastM:r*t.northUnit,northM:-r*t.eastUnit,upM:qt.RISE_M_PER_M_PER_S*t.speedMPerS*s*Math.cos(i),rollDeg:qt.HEAD_ROLL_DEG*o*Math.cos(i/2),pitchDeg:-1.25*o*Math.cos(i),yawDeg:qt.HEAD_YAW_DEG*o*Math.cos(i/2)}}amplitudeAt(e,t){const n=1e3/e.stepHz,i=Math.min(n,(e.endMs-e.startMs)/2);if(i<=0)return 1;const s=t-e.startMs,r=e.endMs-t,o=Math.min(e.rampsIn?s/i:1,e.rampsOut?r/i:1,1);return(1-Math.cos(Math.PI*Math.max(o,0)))/2}}class r1{constructor(e,t){this.timeline=e,this.onFrame=t}rafId=null;state="stopped";currentT=0;lastWallTime=0;playbackRate=1;loop=!1;onEnded;durationOverrideMs=0;get seekableDuration(){return Math.max(this.timeline.duration,this.durationOverrideMs)}play(){if(this.state==="playing")return;this.currentT>=this.seekableDuration&&(this.currentT=0,this.resolveFrame(0)),this.state="playing",this.lastWallTime=performance.now();const e=()=>{if(this.state!=="playing")return;const t=performance.now();if(this.currentT+=(t-this.lastWallTime)*this.playbackRate,this.lastWallTime=t,this.currentT>=this.seekableDuration){if(this.loop&&this.seekableDuration>0){this.currentT%=this.seekableDuration,this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(e);return}this.currentT=this.seekableDuration,this.stop(),this.resolveFrame(this.currentT),this.onEnded?.();return}this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(e)};this.rafId=requestAnimationFrame(e)}pause(){this.state==="playing"&&(this.state="paused",this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null))}stop(){this.state="stopped",this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}seek(e){this.currentT=Math.max(0,Math.min(e,this.seekableDuration)),this.resolveFrame(this.currentT)}get playbackState(){return this.state}get time(){return this.currentT}resolveFrame(e){const t=new Map;for(const n of this.timeline.sourceIds){const i=this.timeline.getInterpolatedShapeAt(e,n);i&&t.set(n,i)}this.onFrame(e,t)}}const xf=.05,wf=.08,Mf=2,Sf=3,o1=14,l1=.02;class c1{context;voice;voiceToken=0;buffers=new Map;noiseBuffer;crackleBuffer;requested;resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(e){console.warn("SightingAudio: Web Audio unavailable, the sighting stays silent:",e);return}}this.context.state==="suspended"&&this.context.resume()}setSound(e){if(this.requested=e,!this.context)return;const t=this.keyFor(e);if(!t){this.silence();return}if(this.voice?.key!==t){this.stopVoice();const n=++this.voiceToken;t.startsWith("src:")?this.buildRecordedVoice(e.src,t,n):this.voice=this.buildSynthesizedVoice(e,t)}this.applyTo(this.voice,e)}silence(){this.voiceToken++,this.stopVoice()}dispose(){this.silence(),this.context?.close(),this.context=void 0,this.buffers.clear(),this.noiseBuffer=void 0,this.crackleBuffer=void 0}keyFor(e){if(!(e.volume<=0))return e.src?`src:${e.src}`:e.kind==="none"?void 0:e.kind}applyTo(e,t){const n=this.context;if(!e||!n)return;const i=n.currentTime;e.volumeParam.setTargetAtTime(Math.max(0,Math.min(1,t.volume))*e.gainScale,i,xf);for(const{param:s,ratio:r}of e.pitch)s.setTargetAtTime(Math.min(t.pitchHz*r,n.sampleRate/2-1),i,xf)}buildSynthesizedVoice(e,t){const n=this.context;if(n)switch(e.kind){case"hum":return this.buildHum(n,t);case"whistle":return this.buildWhistle(n,t);case"rumble":return this.buildRumble(n,t);case"crackle":return this.buildCrackle(n,t);default:return}}buildHum(e,t){const n=e.createOscillator();n.type="sawtooth";const i=e.createOscillator();i.type="sawtooth";const s=e.createBiquadFilter();s.type="lowpass",s.Q.value=1;const r=e.createGain();return r.gain.value=0,n.connect(s),i.connect(s),s.connect(r).connect(e.destination),n.start(),i.start(),{key:t,nodes:[s,r],sources:[n,i],volumeParam:r.gain,gainScale:.16,pitch:[{param:n.frequency,ratio:1},{param:i.frequency,ratio:1.006},{param:s.frequency,ratio:6}]}}buildWhistle(e,t){const n=e.createOscillator();n.type="sine";const i=e.createOscillator();i.type="sine",i.frequency.value=5;const s=e.createGain(),r=e.createGain();return r.gain.value=0,i.connect(s).connect(n.frequency),n.connect(r).connect(e.destination),n.start(),i.start(),{key:t,nodes:[s,r],sources:[n,i],volumeParam:r.gain,gainScale:.22,pitch:[{param:n.frequency,ratio:1},{param:s.gain,ratio:.012}]}}buildRumble(e,t){const n=e.createBufferSource();n.buffer=this.brownNoise(e),n.loop=!0;const i=e.createBiquadFilter();i.type="lowpass",i.Q.value=.8;const s=e.createGain();return s.gain.value=0,n.connect(i).connect(s).connect(e.destination),n.start(),{key:t,nodes:[i,s],sources:[n],volumeParam:s.gain,gainScale:1.4,pitch:[{param:i.frequency,ratio:1}]}}buildCrackle(e,t){const n=e.createBufferSource();n.buffer=this.whiteNoise(e),n.loop=!0;const i=e.createBiquadFilter();i.type="bandpass",i.Q.value=1.2;const s=e.createGain();s.gain.value=0;const r=e.createBufferSource();r.buffer=this.crackleEnvelope(e),r.loop=!0;const o=e.createGain();return o.gain.value=0,r.connect(o).connect(s.gain),n.connect(i).connect(s).connect(e.destination),n.start(),r.start(),{key:t,nodes:[i,s,o],sources:[n,r],volumeParam:o.gain,gainScale:.9,pitch:[{param:i.frequency,ratio:4}]}}async buildRecordedVoice(e,t,n){const i=this.context;if(!i)return;let s;try{s=await this.getBuffer(e)}catch(l){console.warn("SightingAudio: the recorded sound failed to load, staying silent:",l);return}if(n!==this.voiceToken||!this.context)return;const r=i.createBufferSource();r.buffer=s,r.loop=!0;const o=i.createGain();o.gain.value=0,r.connect(o).connect(i.destination),r.start(),this.voice={key:t,nodes:[o],sources:[r],volumeParam:o.gain,gainScale:1,pitch:[]},this.requested&&this.applyTo(this.voice,this.requested)}async getBuffer(e){const t=this.context;if(!t)throw new Error("SightingAudio: AudioContext not ready — resume() must be called first");let n=this.buffers.get(e);return n||(n=fetch(e).then(i=>{if(!i.ok)throw new Error(`Audio fetch failed (${i.status}): ${e}`);return i.arrayBuffer()}).then(i=>t.decodeAudioData(i)),this.buffers.set(e,n)),n}whiteNoise(e){if(!this.noiseBuffer){const t=e.createBuffer(1,Math.floor(e.sampleRate*Mf),e.sampleRate),n=t.getChannelData(0);for(let i=0;i<n.length;i++)n[i]=Math.random()*2-1;this.noiseBuffer=t}return this.noiseBuffer}brownNoise(e){const t=e.createBuffer(1,Math.floor(e.sampleRate*Mf),e.sampleRate),n=t.getChannelData(0);let i=0,s=0;for(let r=0;r<n.length;r++)i=(i+.02*(Math.random()*2-1))/1.02,n[r]=i,s=Math.max(s,Math.abs(i));if(s>0)for(let r=0;r<n.length;r++)n[r]/=s;return t}crackleEnvelope(e){if(!this.crackleBuffer){const t=e.createBuffer(1,Math.floor(e.sampleRate*Sf),e.sampleRate),n=t.getChannelData(0),i=Math.max(1,Math.floor(l1*e.sampleRate)),s=Math.round(Sf*o1);for(let r=0;r<s;r++){const o=Math.floor(Math.random()*n.length),l=.4+Math.random()*.6;for(let c=0;c<i&&o+c<n.length;c++)n[o+c]=Math.max(n[o+c],l*(1-c/i))}this.crackleBuffer=t}return this.crackleBuffer}stopVoice(){const e=this.voice,t=this.context;if(this.voice=void 0,!e||!t)return;const n=t.currentTime;e.volumeParam.cancelScheduledValues(n),e.volumeParam.setTargetAtTime(0,n,wf/3);const i=n+wf;for(const s of e.sources){s.onended=()=>{s.disconnect();for(const r of e.nodes)r.disconnect()};try{s.stop(i)}catch{s.disconnect();for(const r of e.nodes)r.disconnect()}}}}function er(a){return[...a].sort((e,t)=>e.t-t.t)}function _f(a,e){let t;for(const n of er(a)){if(n.t>e)break;t=n}return t}const fc=Math.PI/180,vo=180/Math.PI;class ni{constructor(e,t,n){this.kind=e,this.canvasHeightPx=t,this.fovDeg=n;const i=n*fc/2;this.focalPx=e==="equidistant"?t/2/i:t/2/Math.tan(i)}focalPx;static of(e,t,n){return new ni(e.projection,t,n)}degToPx(e){const t=e*fc;return this.kind==="equidistant"?this.focalPx*t:2*this.focalPx*Math.tan(t/2)}pxToDeg(e){return this.kind==="equidistant"?e/this.focalPx*vo:2*Math.atan(e/(2*this.focalPx))*vo}angleDegToRadiusPx(e){const t=e*fc;return this.kind==="equidistant"?this.focalPx*t:this.focalPx*Math.tan(t)}halfWidthAngleDeg(e){return this.radiusPxToAngleDeg(this.canvasHeightPx*e/2)}radiusPxToAngleDeg(e){return this.kind==="equidistant"?e/this.focalPx*vo:Math.atan(e/this.focalPx)*vo}ofBounds(e){return{widthDeg:this.pxToDeg(e.width),heightDeg:this.pxToDeg(e.height)}}toBoundsSize(e){return{width:this.degToPx(e.widthDeg),height:this.degToPx(e.heightDeg)}}widthPx(e){return this.degToPx(et.angularWidthDeg(e))}}class an{static fovOf(e,t){return at(e,t)?.fovDeg??st.fieldOfViewDeg(e.instrument)}static toAngular(e){this.eachKeyframe(e,(t,n)=>({...t,angular:n.ofBounds(t.bounds)}))}static toBounds(e){this.eachKeyframe(e,(t,n)=>{if(!t.angular)return t;const{width:i,height:s}=n.toBoundsSize(t.angular),r={x:t.bounds.x+(t.bounds.width-i)/2,y:t.bounds.y+(t.bounds.height-s)/2,width:i,height:s};if(t.kind!=="polygon")return{...t,bounds:r};const o=t.bounds.width===0?1:i/t.bounds.width,l=t.bounds.height===0?1:s/t.bounds.height;return{...t,bounds:r,points:t.points.map(c=>({x:c.x*o,y:c.y*l}))}})}static toAim(e){this.eachKeyframe(e,(t,n,i)=>{const s=this.aimFrom(e,n,i,t.bounds);return s?{...t,aim:s}:t})}static aimOf(e,t,n){const i=ni.of(e.instrument,et.CANVAS_HEIGHT_PX,this.fovOf(e,t));return this.aimFrom(e,i,at(e,t),n)}static aimFrom(e,t,n,i){if(n?.headingDeg===void 0)return;const s=this.frameCentre(e),r=t.radiusPxToAngleDeg(i.x+i.width/2-s.x),o=t.radiusPxToAngleDeg(s.y-(i.y+i.height/2));return{azimuthDeg:((n.headingDeg+r)%360+360)%360,altitudeDeg:n.pitchDeg+o}}static toPosition(e){this.eachKeyframe(e,(t,n,i)=>{if(!t.aim||i?.headingDeg===void 0)return t;const s=this.frameCentre(e),r=this.shortestArc(t.aim.azimuthDeg-i.headingDeg),o=t.aim.altitudeDeg-i.pitchDeg,l=s.x+this.offAxisPx(n,r)-t.bounds.width/2,c=s.y-this.offAxisPx(n,o)-t.bounds.height/2;return{...t,bounds:{...t.bounds,x:l,y:c}}})}static frameCentre(e){return{x:st.frameWidthPx(e.instrument,et.CANVAS_HEIGHT_PX)/2,y:et.CANVAS_HEIGHT_PX/2}}static shortestArc(e){return(e%360+540)%360-180}static offAxisPx(e,t){return Math.abs(t)>=an.OFF_CANVAS_DEG?Math.sign(t)*an.OFF_CANVAS_PX:e.angleDegToRadiusPx(t)}static OFF_CANVAS_DEG=89;static OFF_CANVAS_PX=1e5;static reproject(e,t,n){const i=st.frameWidthPx(t,et.CANVAS_HEIGHT_PX)/2,s=st.frameWidthPx(e.instrument,et.CANVAS_HEIGHT_PX)/2,r=et.CANVAS_HEIGHT_PX/2;for(const o of[...e.timeline.allKeyframes]){const l=this.fovOf(e,o.t),c=n?.get(o.t)??l,h=ni.of(t,et.CANVAS_HEIGHT_PX,c),d=ni.of(e.instrument,et.CANVAS_HEIGHT_PX,l);e.timeline.addKeyframe(o.t,o.shapes.map(u=>{const{bounds:f}=u.shape,p=f.x+f.width/2-i,v=f.y+f.height/2-r,m=Math.hypot(p,v),g=m===0?1:d.angleDegToRadiusPx(h.radiusPxToAngleDeg(m))/m,_={...f,x:s+p*g-f.width/2,y:r+v*g-f.height/2};return{...u,shape:{...u.shape,bounds:_}}}))}this.toBounds(e)}static eachKeyframe(e,t){const{timeline:n}=e;for(const i of[...n.allKeyframes]){const s=at(e,i.t),r=this.fovOf(e,i.t),o=ni.of(e.instrument,et.CANVAS_HEIGHT_PX,r);n.addKeyframe(i.t,i.shapes.map(l=>({...l,shape:t(l.shape,o,s)})))}}}function h1(a){return On.restore(zh(a),a.provenance)}function zh(a){return an.toAngular(a),an.toAim(a),{version:1,time:a.event.time,endTime:a.event.endTime,durationSeconds:a.event.durationSeconds,utcOffsetHours:a.event.utcOffsetHours,timeZone:a.event.timeZone,place:a.event.place,witness:a.witness,testimony:a.testimony,caseId:a.caseId,description:a.event.description,tags:a.event.tags,timeline:a.timeline.toJSON(),witnessTrack:a.witnessTrack.toJSON(),weatherTrack:a.weatherTrack.toJSON(),soundTrack:a.soundTrack.toJSON(),weather:a.weather,decor:a.decor,milestones:a.milestones.length>0?a.milestones:void 0,weatherSource:a.weatherSource,instrument:a.instrumentId,exposureSeconds:a.exposureSeconds}}function d1(a){const{recording:e,provenance:t}=On.strip(a),n=u1(e);return n.provenance=t,n}function u1(a){const e=new jl({eventType:"sighting",time:a.time,endTime:a.endTime,durationSeconds:a.durationSeconds,utcOffsetHours:a.utcOffsetHours,timeZone:a.timeZone,place:a.place,description:a.description,tags:a.tags},Jl.fromJSON(a.timeline),a.witnessTrack?Yr.fromJSON(a.witnessTrack):new Yr,a.weatherTrack?Kr.fromJSON(a.weatherTrack):new Kr,a.soundTrack?$r.fromJSON(a.soundTrack):new $r,a.witness,a.caseId,a.weather,a.decor??[],a.weatherSource,a.instrument,a.exposureSeconds??a.witnessTrack?.keyframes.map(t=>t.pose.exposureSeconds).find(t=>t!==void 0),er(a.milestones??[]));return e.testimony=a.testimony,an.toBounds(e),an.toPosition(e),e}function za(a,e){for(const t of a){const n=t.toLowerCase().split("-")[0];if(e.includes(n))return n}return"en"}class vs{static preferencesFor(e){const t=navigator.languages??[],n=this.declaredFor(e);return n?[n,...t]:t}static declaredFor(e){for(let t=e;t;){const n=t.closest("[lang]")?.getAttribute("lang")?.trim();if(n)return n;const i=t.getRootNode();t=i instanceof ShadowRoot?i.host:void 0}}}class Gi{constructor(e){this.preferences=e}read(e){if(e===void 0||typeof e=="string")return e===""?void 0:e;for(const n of this.preferences){const i=e[n]??e[Gi.base(n)];if(i)return i}const t=new Set(this.preferences.map(n=>Gi.base(n)));for(const[n,i]of Object.entries(e))if(i&&t.has(Gi.base(n)))return i;return Object.values(e).find(n=>n)??void 0}write(e,t,n){const i=t?.trim()?t.trim():void 0;if(e===void 0||typeof e=="string")return i;const s={...e},r=Object.keys(s).find(o=>o===n)??Object.keys(s).find(o=>Gi.base(o)===Gi.base(n))??n;return i===void 0?delete s[r]:s[r]=i,Object.keys(s).length===0?void 0:s}static base(e){return e.toLowerCase().split("-")[0]}}const Hh=["en","fr"],f1={en:()=>ii(()=>Promise.resolve().then(()=>y1),void 0,import.meta.url).then(a=>a.ufoMessages_en),fr:()=>ii(()=>import("./UfoMessages_fr-BJPYHN17.js"),[],import.meta.url).then(a=>a.ufoMessages_fr)};function p1(a){return f1[a]()}const m1={en:()=>ii(()=>Promise.resolve().then(()=>rA),void 0,import.meta.url).then(a=>a.sightingEditorMessages_en),fr:()=>ii(()=>import("./SightingEditorMessages_fr-DnwHxbSq.js"),[],import.meta.url).then(a=>a.sightingEditorMessages_fr)};function g1(a){return m1[a]()}function v1(a){return a==="fr"?ii(()=>import("./TagNames_fr-Dnqq6HQ5.js"),[],import.meta.url).then(e=>e.tagNames_fr):Promise.resolve({})}const Tm={play:"Play",pause:"Pause",noDuration:"No observation duration",autoReplay:"Auto-replay",currentPosition:"Current position",duration:"Duration",switchToElapsed:"click to show elapsed time",switchToClockTime:"click to show the time of day",fullscreen:"Fullscreen",exitFullscreen:"Exit fullscreen",showWitnessMap:"Show where the witness was",hideWitnessMap:"Hide where the witness was",mapImageryUnavailable:"Aerial imagery unavailable",showMilestones:"Show the account's moments",hideMilestones:"Hide the account's moments",witnessHere:"The witness, here",decorHere:"Scenery"},y1=Object.freeze(Object.defineProperty({__proto__:null,ufoMessages_en:Tm},Symbol.toStringTag,{value:"Module"})),Am=Math.PI/180,b1=180/Math.PI,x1=256,w1=19;function M1(a,e){return 156543.03392*Math.cos(a*Am)/2**e}function S1(a,e){return M1(a,e)*x1}function Im(a,e){let t=0;for(;t<w1&&S1(a,t+1)>=e;)t++;return t}function gl(a){const e=a*Am;return(1-Math.log(Math.tan(e)+1/Math.cos(e))/Math.PI)/2}function Dm(a,e,t){const n=2**t;return{x:(a+180)/360*n,y:gl(e)*n}}function Cm(a,e,t){const n=gl(a.north),i=gl(a.south);return{x:(e-a.west)/(a.east-a.west),y:(gl(t)-n)/(i-n)}}function _1(a,e,t){const{x:n,y:i}=Dm(a,e,t);return{x:Math.floor(n),y:Math.floor(i),z:t}}function E1(a){const e=2**a.z,t=a.x/e*360-180,n=(a.x+1)/e*360-180,i=Ef(a.y,e);return{south:Ef(a.y+1,e),north:i,west:t,east:n}}function Ef(a,e){const t=a/e;return Math.atan(Math.sinh(Math.PI*(1-2*t)))*b1}function Rm(a,e,t,n){const i=_1(a,e,t),s=Math.floor(n/2),r=[];for(let c=-s;c<=s;c++)for(let h=-s;h<=s;h++)r.push({x:i.x+h,y:i.y+c,z:t});const o=r.map(E1),l={south:Math.min(...o.map(c=>c.south)),north:Math.max(...o.map(c=>c.north)),west:Math.min(...o.map(c=>c.west)),east:Math.max(...o.map(c=>c.east))};return{tiles:r,bounds:l}}class Us{constructor(e){this.ctx=e}static SCALE_STEPS_M=[5e3,2e3,1e3,500,200,100,50,20,10,5];static MARKER_RADIUS_PX=8.5;static ON_MARKER_M=3;targets=[];hitTest(e,t){let n,i=1/0;for(const s of this.targets){const r=Math.hypot(s.x-e,s.y-t);r>s.radius||r>i||(n=s,i=r)}return n}get width(){return this.ctx.canvas.width}get height(){return this.ctx.canvas.height}paint(e){const{ctx:t}=this;t.save(),this.targets=[],t.clearRect(0,0,this.width,this.height),this.paintGround(e),this.paintNight(e.nightFraction),this.paintPath(e),e.position?(this.paintCone(e,e.position),this.paintDecor(e),this.paintMarkers(e),this.paintWitness(e,e.position)):(this.paintDecor(e),this.paintMarkers(e)),this.paintNorth(),this.paintFooter(e.bounds,e.attribution),t.restore()}toCanvas(e,t,n){const i=Cm(e,n,t);return{x:i.x*this.width,y:i.y*this.height}}paintGround(e){const{ctx:t}=this;t.fillStyle="#1d2321",t.fillRect(0,0,this.width,this.height);const n=e.imagery;if(!n)return;const i=this.toCanvas(e.bounds,n.bounds.north,n.bounds.west),s=this.toCanvas(e.bounds,n.bounds.south,n.bounds.east);t.drawImage(n.source,i.x,i.y,s.x-i.x,s.y-i.y)}paintNight(e=0){if(e<=0)return;const{ctx:t}=this;t.save(),t.fillStyle=`rgba(6, 12, 30, ${Math.min(e,1)*.78})`,t.fillRect(0,0,this.width,this.height),t.restore()}paintDecor(e){const{ctx:t}=this;for(const n of e.decor){const i=this.toCanvas(e.bounds,n.lat,n.lng);if(n.label&&this.targets.push({kind:"decor",label:n.label,lat:n.lat,lng:n.lng,x:i.x,y:i.y,radius:7}),t.beginPath(),t.rect(i.x-3.5,i.y-3.5,7,7),t.fillStyle="rgba(120, 220, 255, 0.85)",t.fill(),t.lineWidth=1.5,t.strokeStyle="rgba(0, 0, 0, 0.7)",t.stroke(),n.headingDeg===void 0)continue;const s=(n.headingDeg-90)*Math.PI/180;t.beginPath(),t.moveTo(i.x,i.y),t.lineTo(i.x+Math.cos(s)*10,i.y+Math.sin(s)*10),t.lineWidth=3,t.strokeStyle="rgba(0, 0, 0, 0.6)",t.stroke(),t.lineWidth=1.5,t.strokeStyle="rgba(120, 220, 255, 0.9)",t.stroke()}}paintPath(e){if(!e.path.moved)return;const{ctx:t}=this,n=e.path.points.map(i=>this.toCanvas(e.bounds,i.lat,i.lng));t.beginPath(),t.moveTo(n[0].x,n[0].y);for(const i of n.slice(1))t.lineTo(i.x,i.y);t.lineJoin="round",t.lineCap="round",t.strokeStyle="rgba(0, 0, 0, 0.65)",t.lineWidth=5,t.stroke(),t.strokeStyle="rgba(255, 255, 255, 0.9)",t.lineWidth=2,t.stroke()}paintCone(e,t){const{headingDeg:n,coneHalfAngleDeg:i}=e;if(n===void 0||i===void 0)return;const{ctx:s}=this,r=this.toCanvas(e.bounds,t.lat,t.lng),o=Math.hypot(this.width,this.height),l=(n-90)*Math.PI/180,c=i*Math.PI/180;s.save(),s.beginPath(),s.moveTo(r.x,r.y),s.arc(r.x,r.y,o,l-c,l+c),s.closePath();const h=s.createRadialGradient(r.x,r.y,0,r.x,r.y,o);h.addColorStop(0,"rgba(255, 224, 130, 0.55)"),h.addColorStop(.35,"rgba(255, 224, 130, 0.22)"),h.addColorStop(1,"rgba(255, 224, 130, 0)"),s.fillStyle=h,s.fill(),s.restore()}paintMarkers(e){const{ctx:t}=this;t.textAlign="center",t.textBaseline="middle",t.font="bold 10px sans-serif";for(const n of[...e.markers].sort((i,s)=>Number(i.current)-Number(s.current))){const i=this.toCanvas(e.bounds,n.lat,n.lng);this.targets.push({kind:"milestone",label:n.note?`${n.label} — ${n.note}`:n.label,lat:n.lat,lng:n.lng,t:n.t,x:i.x,y:i.y,radius:Us.MARKER_RADIUS_PX}),t.beginPath(),t.arc(i.x,i.y,Us.MARKER_RADIUS_PX,0,Math.PI*2),t.fillStyle=n.current?"rgba(255, 224, 130, 0.95)":"rgba(0, 0, 0, 0.55)",t.fill(),t.lineWidth=2,t.strokeStyle="rgba(255, 255, 255, 0.9)",t.stroke(),t.fillStyle=n.current?"#1d2321":"#fff",t.fillText(n.label,i.x,i.y)}}paintWitness(e,t){const{ctx:n}=this,i=this.toCanvas(e.bounds,t.lat,t.lng);e.witnessLabel&&this.targets.push({kind:"witness",label:e.witnessLabel,lat:t.lat,lng:t.lng,x:i.x,y:i.y,radius:8});const s=e.markers.some(r=>{if(!r.current)return!1;const o=un(r.lat,r.lng,t.lat,t.lng);return Math.hypot(o.x,o.z)<=Us.ON_MARKER_M});n.beginPath(),n.arc(i.x,i.y,s?Us.MARKER_RADIUS_PX+2.5:5.5,0,Math.PI*2),s||(n.fillStyle="#ff5a3c",n.fill()),n.lineWidth=4,n.strokeStyle="rgba(0, 0, 0, 0.5)",n.stroke(),n.lineWidth=s?3:2.5,n.strokeStyle=s?"#ff5a3c":"#fff",n.stroke()}paintNorth(){const{ctx:e}=this,t=this.width-14,n=16;e.beginPath(),e.moveTo(t,n-9),e.lineTo(t-4.5,n+5),e.lineTo(t,n+2),e.lineTo(t+4.5,n+5),e.closePath(),e.fillStyle="rgba(255, 255, 255, 0.92)",e.strokeStyle="rgba(0, 0, 0, 0.6)",e.lineWidth=1,e.fill(),e.stroke(),e.font="bold 9px sans-serif",e.textAlign="center",e.textBaseline="top",e.strokeText("N",t,n+6),e.fillText("N",t,n+6)}paintFooter(e,t){const{ctx:n}=this;n.font="9px sans-serif",n.textBaseline="bottom";const i=t?this.wrap(t,this.width-20):[];let s=this.height-4;n.textAlign="right";for(const f of i.slice().reverse())this.paintOutlinedText(f,this.width-6,s),s-=11;const r=(e.south+e.north)/2,l=Math.abs(un(r,e.east,r,e.west).x)/this.width,c=Us.SCALE_STEPS_M.find(f=>f/l<=this.width/3);if(c===void 0)return;const h=c/l,d=8,u=s-3;n.lineWidth=3,n.strokeStyle="rgba(0, 0, 0, 0.6)",n.beginPath(),n.moveTo(d,u),n.lineTo(d+h,u),n.stroke(),n.lineWidth=1.5,n.strokeStyle="rgba(255, 255, 255, 0.95)",n.stroke(),n.textAlign="left",this.paintOutlinedText(c>=1e3?`${c/1e3} km`:`${c} m`,d,u-3)}paintOutlinedText(e,t,n){const{ctx:i}=this;i.lineWidth=3,i.strokeStyle="rgba(0, 0, 0, 0.75)",i.strokeText(e,t,n),i.fillStyle="#fff",i.fillText(e,t,n)}wrap(e,t){const n=[];let i="";for(const s of e.split(" ")){const r=i?`${i} ${s}`:s;i&&this.ctx.measureText(r).width>t?(n.push(i),i=s):i=r}return i&&n.push(i),n}}const Hn=256,Tf=3,T1=32768;class Pm{fetchImpl;tileUrlTemplate;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.tileUrlTemplate=e.tileUrlTemplate??"https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png"}async getElevationGrid(e,t){const n=(e.south+e.north)/2,i=(e.west+e.east)/2,s=Math.abs(un(n,e.east,n,e.west).x),r=Math.abs(un(e.north,i,e.south,i).z),o=Im(n,Math.max(s,r)),{tiles:l}=Rm(i,n,o,Tf),c=Tf*Hn,h=new Float32Array(c*c),d=l[0];await Promise.all(l.map(f=>this.decodeTileInto(f,d,h,c)));const u=new Float32Array(t.width*t.height);for(let f=0;f<t.height;f++){const p=e.north+(e.south-e.north)*(f/(t.height-1));for(let v=0;v<t.width;v++){const m=e.west+(e.east-e.west)*(v/(t.width-1));u[f*t.width+v]=this.sampleAt(p,m,o,d,h,c)}}return{heights:u,width:t.width,height:t.height,bounds:e}}async decodeTileInto(e,t,n,i){const s=this.tileUrlTemplate.replace("{z}",String(e.z)).replace("{x}",String(e.x)).replace("{y}",String(e.y)),r=await this.fetchImpl(s);if(!r.ok)throw new Error(`Elevation tile fetch failed (${r.status}): ${s}`);const o=await createImageBitmap(await r.blob()),l=document.createElement("canvas");l.width=Hn,l.height=Hn;const c=l.getContext("2d");if(!c)throw new Error("2D canvas context unavailable");c.drawImage(o,0,0);const{data:h}=c.getImageData(0,0,Hn,Hn),d=(e.x-t.x)*Hn,u=(e.y-t.y)*Hn;for(let f=0;f<Hn;f++)for(let p=0;p<Hn;p++){const v=(f*Hn+p)*4,m=h[v]*256+h[v+1]+h[v+2]/256-T1,g=d+p,_=u+f;n[_*i+g]=m}}sampleAt(e,t,n,i,s,r){const{x:o,y:l}=Dm(t,e,n),c=(o-i.x)*Hn,h=(l-i.y)*Hn,d=Math.max(0,Math.min(r-1,Math.floor(c))),u=Math.max(0,Math.min(r-1,Math.floor(h))),f=Math.min(r-1,d+1),p=Math.min(r-1,u+1),v=c-d,m=h-u,g=s[u*r+d],_=s[u*r+f],M=s[p*r+d],x=s[p*r+f],w=g+(_-g)*v,E=M+(x-M)*v;return w+(E-w)*m}}const pc=256,Af=3;async function Lm(a,e,t,n){const i=(a.south+a.north)/2,s=(a.west+a.east)/2,r=Math.abs(un(i,a.east,i,a.west).x),o=Math.abs(un(a.north,s,a.south,s).z),l=Im(i,Math.max(r,o)/2),{tiles:c,bounds:h}=Rm(s,i,l,Af),d=Af*pc,u=document.createElement("canvas");u.width=d,u.height=d;const f=u.getContext("2d");if(!f)throw new Error("2D canvas context unavailable");const p=c[0];await Promise.all(c.map(async g=>{const _=t(g),M=await n(_);if(!M.ok)throw new Error(`Imagery tile fetch failed (${M.status}): ${_}`);const x=await createImageBitmap(await M.blob());f.drawImage(x,(g.x-p.x)*pc,(g.y-p.y)*pc)}));const v=document.createElement("canvas");v.width=e.width,v.height=e.height;const m=v.getContext("2d");if(!m)throw new Error("2D canvas context unavailable");return m.drawImage(u,0,0,d,d,0,0,e.width,e.height),{source:v,width:e.width,height:e.height,bounds:h}}class Nm{attribution="Imagery © Esri, Maxar, Earthstar Geographics, and the GIS User Community";fetchImpl;tileUrlTemplate;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.tileUrlTemplate=e.tileUrlTemplate??"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"}async getImageryTexture(e,t){return Lm(e,t,n=>this.tileUrlTemplate.replace("{z}",String(n.z)).replace("{y}",String(n.y)).replace("{x}",String(n.x)),this.fetchImpl)}}function A1(){return{elevation:new Pm,imagery:Om()}}function Om(){return new Nm}const I1=new Set,Ys="show-witness-map",Ha="hide-milestones";class Vn extends HTMLElement{static get observedAttributes(){return["src",Ys,Ha]}shadow;stageElement;canvas;canvasRenderer;tooltip;toolbar;playPauseButton;loopButton;static WITNESS_MAP_MIN_SPAN_M=400;static WITNESS_MAP_MARGIN=.6;static WITNESS_MAP_IMAGERY_PX=768;fullscreenButton;cornerButtons;witnessMapButton;milestonesButton;witnessMapPanel;witnessMapCanvas;witnessMapRenderer;seekInput;milestoneMarks;milestoneCaption;timeStartLabel;timeEndLabel;witnessPath;witnessMapBounds;witnessMapImagery;witnessMapImageryRequested=!1;witnessMapImageryCredit;witnessMapImageryFailed=!1;creditShownExternally=!1;lookYawDeg=0;lookPitchDeg=0;milestonesShown=!0;currentSighting=jl.create();sightingAudio=new c1;soundPreview;player;loopEnabled=!0;playbackBeforeClick;highlightedSourceIds=new Set;paintsShapes=!0;enableClickToPlay=!0;fullscreenTarget;messages=Tm;realDurationMs;realStartMs;showClockTime=!0;handleFullscreenChange=()=>{this.updateFullscreenButton(),this.resizeWitnessMap()};witnessMapResizeObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>this.resizeWitnessMap());resizeWitnessMap(){this.witnessMapPanel.hidden||(this.sizeWitnessMapCanvas(),this.paintWitnessMap(this.currentTime))}simulatedFullscreen=!1;styleBeforeSimulatedFullscreen;bodyOverflowBeforeSimulatedFullscreen;handleSimulatedFullscreenKey=e=>{e.key==="Escape"&&this.exitSimulatedFullscreen()};handlePointerMove=e=>{const t=this.canvasPointFromEvent(e),n=t&&this.shapeAt(t.x,t.y),i=this.said.read(n?.shape.title);if(!i){this.tooltip.hidden=!0;return}this.tooltip.textContent=i,this.tooltip.hidden=!1;const s=this.stageElement.getBoundingClientRect();this.tooltip.style.left=`${e.clientX-s.left+12}px`,this.tooltip.style.top=`${e.clientY-s.top+12}px`};handleWitnessMapPointerMove=e=>{const t=this.witnessMapTargetFrom(e);if(!t){this.tooltip.hidden=!0,this.witnessMapCanvas.style.cursor="default";return}this.witnessMapCanvas.style.cursor="pointer",this.tooltip.textContent=t.label,this.tooltip.hidden=!1;const n=this.stageElement.getBoundingClientRect();this.tooltip.style.left=`${e.clientX-n.left+12}px`,this.tooltip.style.top=`${e.clientY-n.top+12}px`};handleWitnessMapClick=e=>{const t=this.witnessMapTargetFrom(e);if(t){if(t.kind==="milestone"&&t.t!==void 0){this.player.seek(t.t);return}this.dispatchEvent(new CustomEvent("lookat",{detail:{lat:t.lat,lng:t.lng,kind:t.kind},bubbles:!0,composed:!0}))}};witnessMapTargetFrom(e){const t=this.witnessMapCanvas.getBoundingClientRect();if(!(t.width===0||t.height===0))return this.witnessMapRenderer.hitTest((e.clientX-t.left)/t.width*this.witnessMapCanvas.width,(e.clientY-t.top)/t.height*this.witnessMapCanvas.height)}handlePointerLeave=()=>{this.tooltip.hidden=!0};constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${a1}</style>${s1}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.canvas=this.shadow.getElementById("canvas"),this.canvasRenderer=new Oh(this.canvas.getContext("2d")),this.tooltip=this.shadow.getElementById("tooltip"),this.toolbar=this.shadow.getElementById("toolbar"),this.playPauseButton=this.shadow.getElementById("play-pause"),this.loopButton=this.shadow.getElementById("loop"),this.fullscreenButton=this.shadow.getElementById("fullscreen"),this.cornerButtons=this.shadow.getElementById("corner-buttons"),this.witnessMapButton=this.shadow.getElementById("witness-map"),this.milestonesButton=this.shadow.getElementById("milestones"),this.witnessMapPanel=this.shadow.getElementById("witness-map-panel"),this.witnessMapCanvas=this.shadow.getElementById("witness-map-canvas"),this.witnessMapRenderer=new Us(this.witnessMapCanvas.getContext("2d")),this.seekInput=this.shadow.getElementById("seek"),this.milestoneMarks=this.shadow.getElementById("milestone-marks"),this.milestoneCaption=this.shadow.getElementById("milestone-caption"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end");for(const t of[this.timeStartLabel,this.timeEndLabel])t.addEventListener("click",()=>this.toggleTimeDisplay()),t.addEventListener("keydown",n=>{n.key!=="Enter"&&n.key!==" "||(n.preventDefault(),this.toggleTimeDisplay())});this.fullscreenTarget=this.stageElement,this.playPauseButton.addEventListener("click",()=>this.togglePlayPause()),this.loopButton.addEventListener("click",()=>this.toggleLoop()),this.fullscreenButton.addEventListener("click",()=>this.toggleFullscreen()),this.witnessMapButton.addEventListener("click",()=>this.toggleWitnessMap()),this.milestonesButton.addEventListener("click",()=>this.toggleMilestones()),this.witnessMapCanvas.addEventListener("pointermove",this.handleWitnessMapPointerMove),this.witnessMapCanvas.addEventListener("pointerleave",this.handlePointerLeave),this.witnessMapCanvas.addEventListener("click",this.handleWitnessMapClick),this.seekInput.addEventListener("input",()=>this.player.seek(Number(this.seekInput.value))),this.canvas.addEventListener("click",t=>{this.enableClickToPlay&&(t.detail<=1&&(this.playbackBeforeClick={state:this.playbackState,time:this.currentTime}),this.togglePlayPause())}),this.canvas.addEventListener("dblclick",t=>{this.enableClickToPlay&&(t.preventDefault(),this.restorePlayback(),this.toggleFullscreen())}),this.canvas.addEventListener("pointermove",this.handlePointerMove),this.canvas.addEventListener("pointerleave",this.handlePointerLeave),document.addEventListener("fullscreenchange",this.handleFullscreenChange),this.witnessMapResizeObserver?.observe(this.witnessMapPanel),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateWitnessMapButton(),this.updateMilestonesButton(),this.refresh(),this.loadLocaleMessages()}connectedCallback(){this.saidTexts=void 0;const e=this.getAttribute("src");e&&this.loadFromSrc(e)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.handleFullscreenChange),this.witnessMapResizeObserver?.disconnect(),this.exitSimulatedFullscreen(),this.sightingAudio.dispose()}attributeChangedCallback(e,t,n){e==="src"&&n&&n!==t&&this.isConnected&&this.loadFromSrc(n),e===Ys&&this.applyWitnessMapDefault(),e===Ha&&this.setMilestonesShown(!this.hasAttribute(Ha))}async loadFromSrc(e){this.sightingData=await fu.json(e)}get sightingData(){return h1(this.currentSighting)}set sightingData(e){this.player.stop(),this.soundPreview=void 0,this.sightingAudio.silence(),this.currentSighting=d1(e),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.refresh(),this.applyWitnessMapDefault()}get sighting(){return this.currentSighting}previewSound(e){this.soundPreview=e,this.sightingAudio.resume(),this.sightingAudio.setSound(e)}stopSoundPreview(){this.soundPreview=void 0,this.sightingAudio.silence()}get canvasElement(){return this.canvas}get renderer(){return this.canvasRenderer}get currentTime(){return this.player.time}set currentTime(e){this.player.seek(e)}get seekableDuration(){return this.player.seekableDuration}get autoReplayEnabled(){return this.loopEnabled}set autoReplayEnabled(e){e!==this.loopEnabled&&this.toggleLoop()}play(){this.player.seekableDuration<=0||this.playbackState==="playing"||this.togglePlayPause()}pause(){this.playbackState==="playing"&&this.togglePlayPause()}get positionLabel(){return this.timeStartLabel.textContent??""}get durationLabel(){return this.timeEndLabel.textContent??""}get showingClockTime(){return this.canShowClockTime}get canSwitchTimeDisplay(){return this.realStartMs!==void 0}toggleTimeDisplay(){this.canSwitchTimeDisplay&&(this.showClockTime=!this.showClockTime,this.updateTimeLabels(),this.updateTimeLabelTitles(),this.dispatchEvent(new CustomEvent("timedisplaychange",{bubbles:!0,composed:!0})))}get canShowClockTime(){return this.realStartMs!==void 0&&this.showClockTime}set showToolbar(e){this.toolbar.classList.toggle("hidden",!e)}get playbackState(){return this.player.playbackState}get selectedSourceIds(){return this.highlightedSourceIds}get durationSeconds(){return this.currentSighting.event.durationSeconds}set durationSeconds(e){this.currentSighting.event.durationSeconds=e,this.updateTimeLabels(),this.refresh(),this.updatePlayPauseButton()}set selectedSourceIds(e){const t=new Set(e);t.size===this.highlightedSourceIds.size&&[...t].every(i=>this.highlightedSourceIds.has(i))||(this.highlightedSourceIds=t,this.refresh())}hasVisibleShapeAt(e,t){return this.shapeAt(e,t)!==void 0}refresh(){this.applyFrameFormat(),this.updateTimeLabels(),this.seekInput.max=String(this.player.seekableDuration),this.refreshMilestoneMarks(),this.updateMilestonesButton(),this.updateWitnessMap(),this.player.seek(this.player.time)}refreshMilestoneMarks(){const e=this.player.seekableDuration,t=e>0?er(this.sighting.milestones):[];this.milestoneMarks.replaceChildren(...t.map(n=>{const i=document.createElement("button");i.type="button",i.className="milestone-mark",i.style.left=`${Math.min(Math.max(n.t/e,0),1)*100}%`;const s=this.said.read(n.label)??"",r=this.said.read(n.note),o=r?`${s} — ${r}`:s;return i.title=o,i.setAttribute("aria-label",o),i.addEventListener("click",()=>this.player.seek(n.t)),i}))}showMilestoneAt(e){const t=this.milestonesShown&&this.sighting.milestones.length>0?_f(this.sighting.milestones,e):void 0;if(this.milestoneCaption.hidden=t===void 0,!t)return;const n=document.createElement("b");n.textContent=this.said.read(t.label)??"";const i=this.said.read(t.note),s=i?` — ${i}`:"";this.milestoneCaption.replaceChildren(n,document.createTextNode(s))}exposureInstants(e){const t=this.exposureTimes(e),n=1/t.length;return t.map(i=>({shapes:this.shapesAt(i),share:n}))}exposureTimes(e=this.currentTime){const t=(this.currentSighting.exposure??0)*1e3;if(t<Vn.SHORTEST_VISIBLE_EXPOSURE_MS)return[e];const n=Math.min(Vn.MAX_EXPOSURE_STEPS,Math.max(2,Math.round(t/Vn.SHORTEST_VISIBLE_EXPOSURE_MS))),i=Math.ceil(this.travelPxOver(e,t)/Vn.EXPOSURE_STEP_PX),s=Math.min(Vn.MAX_TRAVEL_STEPS,Math.max(n,i)),r=[];for(let o=0;o<s;o++)r.push(e+t*o/s);return r}travelPxOver(e,t){const n=this.shapesAt(e),i=this.shapesAt(e+t);let s=0;for(const[r,o]of n){const l=i.get(r);if(!l)continue;const c=l.bounds.x+l.bounds.width/2-(o.bounds.x+o.bounds.width/2),h=l.bounds.y+l.bounds.height/2-(o.bounds.y+o.bounds.height/2);s=Math.max(s,Math.hypot(c,h))}return s}shapeAt(e,t,n){for(const i of this.exposureTimes()){const s=this.currentSighting.timeline.hitTest(i,e,t,n);if(s)return s}}shapesAt(e){const t=new Map;for(const n of this.currentSighting.timeline.sourceIds){const i=this.currentSighting.timeline.getInterpolatedShapeAt(e,n);i&&t.set(n,i)}return t}static SHORTEST_VISIBLE_EXPOSURE_MS=20;static MAX_EXPOSURE_STEPS=48;static EXPOSURE_STEP_PX=2;static MAX_TRAVEL_STEPS=320;applyFrameFormat(){const e=st.frameWidthPx(this.currentSighting.instrument,this.canvas.height);if(this.canvas.width===e)return;this.canvas.width=e,this.canvas.parentElement?.style.setProperty("--frame-aspect",`${e} / ${this.canvas.height}`)}canvasPointFromEvent(e){const t=this.canvas.getBoundingClientRect();if(!(t.width===0||t.height===0))return{x:(e.clientX-t.left)/t.width*this.canvas.width,y:(e.clientY-t.top)/t.height*this.canvas.height}}onFrame(e,t){this.canvasRenderer.clear(this.canvas.width,this.canvas.height);const n=this.playbackState!=="playing"?this.highlightedSourceIds:I1;this.canvasRenderer.setStarPoints(st.starPointsOf(this.sighting.instrument));const i=(at(this.sighting,e)?.rollDeg??0)+this.gaitAt(e).rollDeg;this.canvasRenderer.setRoll(i*Math.PI/180);const s=this.exposureInstants(e),r=this.frameShift;if(this.paintsShapes)for(const o of s)for(const[,l]of o.shapes){const c=o.share,h=c===1?l:{...l,transparency:1-(1-l.transparency)*c};this.canvasRenderer.paintShape(this.shifted(h,r))}for(const[o,l]of s[0].shapes)n.has(o)&&(this.paintsShapes?n.size===1?this.canvasRenderer.paintShape({...l,selected:!0}):this.canvasRenderer.paintMemberOutline(l):this.canvasRenderer.paintSelectionOnly(this.shifted(l,r)));if(n.size>1){const o=it.groupBoundsFor([...t].filter(([l])=>n.has(l)).map(([,l])=>l.bounds));this.canvasRenderer.paintGroupHandles(o)}this.keepWitnessMapClear(s[0].shapes),this.seekInput.value=String(e),this.timeStartLabel.textContent=this.formatPosition(e),this.showMilestoneAt(e),this.paintWitnessMap(e),this.playbackState==="playing"?(this.soundPreview=void 0,this.sightingAudio.setSound(uu(this.currentSighting,e))):this.soundPreview?this.sightingAudio.setSound(this.soundPreview):this.sightingAudio.silence(),this.updatePlayPauseButton(),this.dispatchEvent(new CustomEvent("timeupdate",{detail:{time:e}}))}shifted(e,t){return t.x===0&&t.y===0?e:{...e,bounds:{...e.bounds,x:e.bounds.x+t.x,y:e.bounds.y+t.y}}}createPlayer(){const e=new r1(this.currentSighting.timeline,(t,n)=>this.onFrame(t,n));return e.loop=this.loopEnabled,e.onEnded=()=>{this.updatePlayPauseButton(),this.dispatchEvent(new CustomEvent("ended",{bubbles:!0,composed:!0}))},e}togglePlayPause(){this.player.seekableDuration<=0||(this.player.playbackState==="playing"?(this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh()):(this.sightingAudio.resume(),this.player.play()),this.updatePlayPauseButton())}updatePlayPauseButton(){const e=this.player.playbackState==="playing";this.playPauseButton.textContent=e?"⏸":"▶";const t=this.player.seekableDuration>0;this.playPauseButton.disabled=!t;const n=t?e?this.messages.pause:this.messages.play:this.messages.noDuration;this.playPauseButton.title=n,this.playPauseButton.setAttribute("aria-label",n),this.toolbar.classList.toggle("auto-hide",e),this.cornerButtons.classList.toggle("auto-hide",e)}toggleLoop(){this.loopEnabled=!this.loopEnabled,this.loopButton.setAttribute("aria-pressed",String(this.loopEnabled)),this.player.loop=this.loopEnabled}restorePlayback(){const e=this.playbackBeforeClick;e&&(this.currentTime=e.time,e.state==="playing"?this.play():this.pause())}get canUseNativeFullscreen(){return typeof this.fullscreenTarget.requestFullscreen=="function"&&document.fullscreenEnabled}toggleFullscreen(){if(!this.canUseNativeFullscreen){this.simulatedFullscreen?this.exitSimulatedFullscreen():this.enterSimulatedFullscreen();return}document.fullscreenElement?document.exitFullscreen():this.fullscreenTarget.requestFullscreen().catch(e=>{console.error("<rr0-ufo>: requestFullscreen() failed —",e)})}enterSimulatedFullscreen(){const e=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen=e.getAttribute("style")??"",this.bodyOverflowBeforeSimulatedFullscreen=document.body.style.overflow;const t=e.style;t.setProperty("position","fixed"),t.setProperty("inset","0"),t.setProperty("margin","0"),t.setProperty("max-width","none"),t.setProperty("max-height","none"),t.setProperty("aspect-ratio","auto"),t.setProperty("z-index","2147483647"),t.setProperty("background","#000"),t.setProperty("width","100vw"),t.setProperty("width","100dvw"),t.setProperty("height","100vh"),t.setProperty("height","100dvh"),document.body.style.overflow="hidden",this.simulatedFullscreen=!0,document.addEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton()}exitSimulatedFullscreen(){if(!this.simulatedFullscreen)return;const e=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen?e.setAttribute("style",this.styleBeforeSimulatedFullscreen):e.removeAttribute("style"),document.body.style.overflow=this.bodyOverflowBeforeSimulatedFullscreen??"",this.simulatedFullscreen=!1,document.removeEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton()}toggleWitnessMap(){this.setWitnessMapOpen(this.witnessMapPanel.hidden)}applyWitnessMapDefault(){this.setWitnessMapOpen(this.hasAttribute(Ys)&&this.witnessPath!==void 0)}setWitnessMapOpen(e){this.witnessMapPanel.hidden=!e,this.witnessMapPanel.removeAttribute("title"),this.witnessMapButton.setAttribute("aria-pressed",String(e)),this.updateWitnessMapButton(),e&&(this.sizeWitnessMapCanvas(),this.loadWitnessMapImagery(),this.paintWitnessMap(this.currentTime))}updateWitnessMapButton(){const t=!this.witnessMapPanel.hidden?this.messages.hideWitnessMap:this.messages.showWitnessMap;this.witnessMapButton.title=t,this.witnessMapButton.setAttribute("aria-label",t)}updateWitnessMap(){const e=this.witnessPath!==void 0;if(this.witnessPath=Zr.of(this.currentSighting),this.witnessMapButton.hidden=this.witnessPath===void 0,!e&&this.witnessPath&&this.applyWitnessMapDefault(),!this.witnessPath){this.setWitnessMapOpen(!1),this.witnessMapBounds=void 0;return}const t=this.witnessPath.boundsAround(Vn.WITNESS_MAP_MIN_SPAN_M,Vn.WITNESS_MAP_MARGIN);(!this.witnessMapBounds||!this.sameGround(this.witnessMapBounds,t))&&(this.witnessMapBounds=t,this.witnessMapImagery=void 0,this.witnessMapImageryCredit=void 0,this.witnessMapImageryFailed=!1,this.witnessMapImageryRequested=!1,this.witnessMapPanel.hidden||this.loadWitnessMapImagery())}sameGround(e,t){const n=Math.abs(e.east-e.west)/20;return Math.abs(e.north-t.north)<n&&Math.abs(e.south-t.south)<n&&Math.abs(e.west-t.west)<n&&Math.abs(e.east-t.east)<n}async loadWitnessMapImagery(){if(this.witnessMapImageryRequested||!this.witnessMapBounds)return;this.witnessMapImageryRequested=!0;const e=Om(),t=this.witnessMapBounds;try{const n=await e.getImageryTexture(t,{width:Vn.WITNESS_MAP_IMAGERY_PX,height:Vn.WITNESS_MAP_IMAGERY_PX});if(this.witnessMapBounds!==t)return;this.witnessMapImagery=n,this.witnessMapImageryCredit=e.attribution}catch{this.witnessMapImageryFailed=!0}this.paintWitnessMap(this.currentTime)}get witnessMapCredit(){return this.witnessMapImageryCredit}get witnessMapFooterLine(){return this.witnessMapImageryFailed?this.messages.mapImageryUnavailable:this.creditShownExternally?void 0:this.witnessMapImageryCredit}keepWitnessMapClear(e){if(this.witnessMapPanel.hidden)return;const t=this.witnessMapBoxPx;if(!t)return;const n=(o,l,c)=>{for(const h of e.values())if(!(h.transparency>=1)&&!(h.bounds.x+h.bounds.width<o-c||h.bounds.x>l+c)&&!(h.bounds.y>t.bottom+c||h.bounds.y+h.bounds.height<t.top-c))return!0;return!1},i=[this.canvas.width-t.width,this.canvas.width],s=[0,t.width],r=Vn.WITNESS_MAP_CLEARANCE_PX;if(this.witnessMapPanel.classList.contains("on-the-left")){n(i[0],i[1],r)||this.witnessMapPanel.classList.remove("on-the-left");return}n(i[0],i[1],0)&&!n(s[0],s[1],0)&&this.witnessMapPanel.classList.add("on-the-left")}witnessMapBoxPx;static WITNESS_MAP_CLEARANCE_PX=24;sizeWitnessMapCanvas(){const e=this.witnessMapPanel.clientWidth;if(e===0)return;const t=Math.round(e*(globalThis.devicePixelRatio??1));this.measureWitnessMapBox(),this.witnessMapCanvas.width!==t&&(this.witnessMapCanvas.width=t,this.witnessMapCanvas.height=t)}measureWitnessMapBox(){const e=this.witnessMapPanel.getBoundingClientRect(),t=this.canvas.getBoundingClientRect();if(t.width===0||t.height===0)return;const n=this.canvas.width/t.width,i=this.canvas.height/t.height;this.witnessMapBoxPx={width:e.width*n,top:(e.top-t.top)*i,bottom:(e.bottom-t.top)*i}}paintWitnessMap(e){if(this.witnessMapPanel.hidden||!this.witnessPath||!this.witnessMapBounds)return;const t=at(this.currentSighting,e),n=this.currentSighting.instrument,i=[],s=this.currentSighting.milestones.length>0?_f(this.currentSighting.milestones,e):void 0;for(const r of this.milestonesShown?er(this.currentSighting.milestones):[]){const o=at(this.currentSighting,r.t);o?.lat===void 0||o.lng===void 0||i.push({label:this.said.read(r.label)??"",note:this.said.read(r.note),t:r.t,lat:o.lat,lng:o.lng,current:r===s})}this.witnessMapRenderer.paint({bounds:this.witnessMapBounds,imagery:this.witnessMapImagery,path:this.witnessPath,position:t?.lat!==void 0&&t.lng!==void 0?{lat:t.lat,lng:t.lng}:void 0,headingDeg:t?.headingDeg===void 0?void 0:t.headingDeg+this.lookYawDeg,coneHalfAngleDeg:t?ni.of(n,this.canvas.height,t.fovDeg).halfWidthAngleDeg(st.aspectOf(n)):void 0,markers:i,decor:this.witnessMapDecorAt(e),witnessLabel:this.said.read(this.currentSighting.witness?.title)??this.messages.witnessHere,nightFraction:this.witnessMapNightFraction,attribution:this.witnessMapFooterLine})}toggleMilestones(){this.setMilestonesShown(!this.milestonesShown)}setMilestonesShown(e){this.milestonesShown=e,this.milestoneMarks.hidden=!e,this.milestonesButton.setAttribute("aria-pressed",String(e)),this.updateMilestonesButton(),this.showMilestoneAt(this.currentTime),this.paintWitnessMap(this.currentTime)}updateMilestonesButton(){this.milestonesButton.hidden=this.currentSighting.milestones.length===0;const e=this.milestonesShown?this.messages.hideMilestones:this.messages.showMilestones;this.milestonesButton.title=e,this.milestonesButton.setAttribute("aria-label",e)}witnessMapDecorAt(e){const t=at(this.currentSighting,0);return t?.lat===void 0||t.lng===void 0?[]:this.currentSighting.decor.filter(n=>n.kind!=="crop").map(n=>{const i=Qa(n,e),{lat:s,lng:r}=Wi(i.eastM,-i.northM,t.lat,t.lng);return{lat:s,lng:r,headingDeg:i.headingDeg,label:this.said.read(n.title)??this.messages.decorHere}})}witnessMapNightFraction;setSunAltitude(e){const t=e===void 0?void 0:Math.max(0,Math.min(1,-e/12));t!==this.witnessMapNightFraction&&(this.witnessMapNightFraction=t,this.paintWitnessMap(this.currentTime))}setLookOffset(e,t){e===this.lookYawDeg&&t===this.lookPitchDeg||(this.lookYawDeg=e,this.lookPitchDeg=t,this.refresh())}get frameShiftPx(){return this.frameShift}get frameShift(){const e=this.gaitAt(this.currentTime),t=this.lookYawDeg+e.yawDeg,n=this.lookPitchDeg+e.pitchDeg;if(t===0&&n===0)return{x:0,y:0};const i=at(this.currentSighting,this.currentTime),s=ni.of(this.currentSighting.instrument,this.canvas.height,i?.fovDeg??60);return{x:-s.angleDegToRadiusPx(t),y:s.angleDegToRadiusPx(n)}}gaitAt(e){return qt.of(this.currentSighting)?.offsetAt(e)??qt.STILL}updateFullscreenButton(){const e=this.simulatedFullscreen||document.fullscreenElement===this.fullscreenTarget;this.fullscreenButton.title=e?this.messages.exitFullscreen:this.messages.fullscreen,this.fullscreenButton.setAttribute("aria-label",this.fullscreenButton.title)}get said(){return this.saidTexts??=new Gi(vs.preferencesFor(this))}saidTexts;async loadLocaleMessages(){const e=za(vs.preferencesFor(this),Hh);e!=="en"&&this.applyMessages(await p1(e))}updateTimeLabelTitles(){const e=this.showClockTime?this.messages.switchToElapsed:this.messages.switchToClockTime,t=this.canSwitchTimeDisplay?` — ${e}`:"";this.timeStartLabel.title=this.messages.currentPosition+t,this.timeEndLabel.title=this.messages.duration+t;for(const n of[this.timeStartLabel,this.timeEndLabel])n.classList.toggle("switchable",this.canSwitchTimeDisplay),this.canSwitchTimeDisplay?(n.setAttribute("role","button"),n.setAttribute("tabindex","0")):(n.removeAttribute("role"),n.removeAttribute("tabindex"))}applyMessages(e){this.messages=e,this.updateTimeLabelTitles(),this.loopButton.title=e.autoReplay,this.loopButton.setAttribute("aria-label",e.autoReplay),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateWitnessMapButton(),this.updateMilestonesButton()}updateTimeLabels(){const e=this.currentSighting.event,t=ja(e);this.realDurationMs=t!==void 0&&t>0?t:void 0,this.realStartMs=e.time?Ph(e.time):void 0;const n=this.currentSighting.timeline.duration;this.player.playbackRate=this.realDurationMs!==void 0&&n>0?n/this.realDurationMs:1,this.player.durationOverrideMs=n>0?0:this.realDurationMs??0,this.timeEndLabel.textContent=this.formatEndOfTimeline(),this.timeStartLabel.textContent=this.formatPosition(this.player.time),this.updateTimeLabelTitles()}formatPosition(e){if(this.realDurationMs===void 0)return yo(e);const t=this.currentSighting.timeline.duration,n=t>0&&e<=t?e/t*this.realDurationMs:e;return this.canShowClockTime?Df(If(this.realStartMs+n)):yo(n)}formatEndOfTimeline(){return this.realDurationMs===void 0?yo(this.currentSighting.timeline.duration):this.canShowClockTime?Df(If(this.realStartMs+this.realDurationMs)):yo(this.realDurationMs)}}function If(a){const e=new Date(a);return{hour:e.getUTCHours(),minute:e.getUTCMinutes(),second:e.getUTCSeconds()}}function Df(a){if(a.hour===void 0)return"0:00";const e=t=>String(t).padStart(2,"0");return a.second?`${e(a.hour)}:${e(a.minute??0)}:${e(a.second)}`:`${e(a.hour)}:${e(a.minute??0)}`}function yo(a){const e=Math.round(a/1e3),t=Math.floor(e/60),n=e%60;return`${t}:${String(n).padStart(2,"0")}`}const Gh="rr0-ufo";function Ql(){customElements.get(Gh)||customElements.define(Gh,Vn)}const D1=`
|
|
1827
|
+
`;class Zr{constructor(e){this.points=e}static STATIONARY_M=5;static of(e){const t=[];for(const n of e.witnessTrack.allKeyframes){const{lat:i,lng:s,headingDeg:r}=n.pose;i===void 0||s===void 0||t.push({t:n.t,lat:i,lng:s,headingDeg:r})}if(t.length===0){const n=e.event.place?.[0];if(!n)return;t.push({t:0,lat:n.lat,lng:n.lng})}return new Zr(t)}get moved(){return this.spanM>Zr.STATIONARY_M}get spanM(){const e=this.box,t=(e.south+e.north)/2,n=(e.west+e.east)/2;return Math.max(Math.abs(un(t,e.east,t,e.west).x),Math.abs(un(e.north,n,e.south,n).z))}get center(){const e=this.box;return{lat:(e.south+e.north)/2,lng:(e.west+e.east)/2}}boundsAround(e,t){const{lat:n,lng:i}=this.center,s=Math.max(this.spanM*(1+t),e)/2;return{north:Wi(0,-s,n,i).lat,south:Wi(0,s,n,i).lat,east:Wi(s,0,n,i).lng,west:Wi(-s,0,n,i).lng}}get box(){const e=this.points.map(n=>n.lat),t=this.points.map(n=>n.lng);return{south:Math.min(...e),north:Math.max(...e),west:Math.min(...t),east:Math.max(...t)}}}class qt{constructor(e,t){this.stretches=e,this.rotationPassed=t}static REFERENCE_SPEED_M_PER_S=1.4;static REFERENCE_STEP_HZ=1.9;static CADENCE_EXPONENT=.43;static RISE_M_PER_M_PER_S=.0175;static SWAY_M=.0175;static SLOWEST_WALK_M_PER_S=.2;static FASTEST_WALK_M_PER_S=2.2;static HEAD_ROLL_DEG=1.5;static HEAD_PITCH_DEG=1.25;static HEAD_YAW_DEG=1;static STILL=Object.freeze({eastM:0,northM:0,upM:0,rollDeg:0,pitchDeg:0,yawDeg:0});static of(e){const t=Zr.of(e);if(!t||t.points.length<2)return;const n=[];let i=0;for(let s=1;s<t.points.length;s++){const r=t.points[s-1],o=t.points[s],l=(o.t-r.t)/1e3;if(l<=0)continue;const c=un(o.lat,o.lng,r.lat,r.lng),h=c.x,d=-c.z,u=Math.hypot(h,d),f=u/l,p=qt.stepHzFor(f);n.push({startMs:r.t,endMs:o.t,speedMPerS:f,eastUnit:u>0?h/u:0,northUnit:u>0?d/u:0,stepHz:p,stepsBefore:i,rampsIn:!0,rampsOut:!0}),i+=p*l}for(let s=0;s<n.length;s++){const r=n[s-1],o=n[s+1];n[s].rampsIn=r===void 0||r.stepHz===0,n[s].rampsOut=o===void 0||o.stepHz===0}if(n.some(s=>s.stepHz>0))return new qt(n,1-(e.instrument.stabilization??0))}static stepHzFor(e){return e<qt.SLOWEST_WALK_M_PER_S||e>qt.FASTEST_WALK_M_PER_S?0:qt.REFERENCE_STEP_HZ*Math.pow(e/qt.REFERENCE_SPEED_M_PER_S,qt.CADENCE_EXPONENT)}offsetAt(e){const t=this.stretches.find(l=>e>=l.startMs&&e<=l.endMs);if(!t||t.stepHz===0)return qt.STILL;const n=t.stepsBefore+t.stepHz*(e-t.startMs)/1e3,i=2*Math.PI*n,s=this.amplitudeAt(t,e),r=qt.SWAY_M*s*Math.cos(i/2),o=s*this.rotationPassed*t.speedMPerS/qt.REFERENCE_SPEED_M_PER_S;return{eastM:r*t.northUnit,northM:-r*t.eastUnit,upM:qt.RISE_M_PER_M_PER_S*t.speedMPerS*s*Math.cos(i),rollDeg:qt.HEAD_ROLL_DEG*o*Math.cos(i/2),pitchDeg:-1.25*o*Math.cos(i),yawDeg:qt.HEAD_YAW_DEG*o*Math.cos(i/2)}}amplitudeAt(e,t){const n=1e3/e.stepHz,i=Math.min(n,(e.endMs-e.startMs)/2);if(i<=0)return 1;const s=t-e.startMs,r=e.endMs-t,o=Math.min(e.rampsIn?s/i:1,e.rampsOut?r/i:1,1);return(1-Math.cos(Math.PI*Math.max(o,0)))/2}}class r1{constructor(e,t){this.timeline=e,this.onFrame=t}rafId=null;state="stopped";currentT=0;lastWallTime=0;playbackRate=1;loop=!1;onEnded;durationOverrideMs=0;get seekableDuration(){return Math.max(this.timeline.duration,this.durationOverrideMs)}play(){if(this.state==="playing")return;this.currentT>=this.seekableDuration&&(this.currentT=0,this.resolveFrame(0)),this.state="playing",this.lastWallTime=performance.now();const e=()=>{if(this.state!=="playing")return;const t=performance.now();if(this.currentT+=(t-this.lastWallTime)*this.playbackRate,this.lastWallTime=t,this.currentT>=this.seekableDuration){if(this.loop&&this.seekableDuration>0){this.currentT%=this.seekableDuration,this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(e);return}this.currentT=this.seekableDuration,this.stop(),this.resolveFrame(this.currentT),this.onEnded?.();return}this.resolveFrame(this.currentT),this.rafId=requestAnimationFrame(e)};this.rafId=requestAnimationFrame(e)}pause(){this.state==="playing"&&(this.state="paused",this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null))}stop(){this.state="stopped",this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}seek(e){this.currentT=Math.max(0,Math.min(e,this.seekableDuration)),this.resolveFrame(this.currentT)}get playbackState(){return this.state}get time(){return this.currentT}resolveFrame(e){const t=new Map;for(const n of this.timeline.sourceIds){const i=this.timeline.getInterpolatedShapeAt(e,n);i&&t.set(n,i)}this.onFrame(e,t)}}const xf=.05,wf=.08,Mf=2,Sf=3,o1=14,l1=.02;class c1{context;voice;voiceToken=0;buffers=new Map;noiseBuffer;crackleBuffer;requested;resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(e){console.warn("SightingAudio: Web Audio unavailable, the sighting stays silent:",e);return}}this.context.state==="suspended"&&this.context.resume()}setSound(e){if(this.requested=e,!this.context)return;const t=this.keyFor(e);if(!t){this.silence();return}if(this.voice?.key!==t){this.stopVoice();const n=++this.voiceToken;t.startsWith("src:")?this.buildRecordedVoice(e.src,t,n):this.voice=this.buildSynthesizedVoice(e,t)}this.applyTo(this.voice,e)}silence(){this.voiceToken++,this.stopVoice()}dispose(){this.silence(),this.context?.close(),this.context=void 0,this.buffers.clear(),this.noiseBuffer=void 0,this.crackleBuffer=void 0}keyFor(e){if(!(e.volume<=0))return e.src?`src:${e.src}`:e.kind==="none"?void 0:e.kind}applyTo(e,t){const n=this.context;if(!e||!n)return;const i=n.currentTime;e.volumeParam.setTargetAtTime(Math.max(0,Math.min(1,t.volume))*e.gainScale,i,xf);for(const{param:s,ratio:r}of e.pitch)s.setTargetAtTime(Math.min(t.pitchHz*r,n.sampleRate/2-1),i,xf)}buildSynthesizedVoice(e,t){const n=this.context;if(n)switch(e.kind){case"hum":return this.buildHum(n,t);case"whistle":return this.buildWhistle(n,t);case"rumble":return this.buildRumble(n,t);case"crackle":return this.buildCrackle(n,t);default:return}}buildHum(e,t){const n=e.createOscillator();n.type="sawtooth";const i=e.createOscillator();i.type="sawtooth";const s=e.createBiquadFilter();s.type="lowpass",s.Q.value=1;const r=e.createGain();return r.gain.value=0,n.connect(s),i.connect(s),s.connect(r).connect(e.destination),n.start(),i.start(),{key:t,nodes:[s,r],sources:[n,i],volumeParam:r.gain,gainScale:.16,pitch:[{param:n.frequency,ratio:1},{param:i.frequency,ratio:1.006},{param:s.frequency,ratio:6}]}}buildWhistle(e,t){const n=e.createOscillator();n.type="sine";const i=e.createOscillator();i.type="sine",i.frequency.value=5;const s=e.createGain(),r=e.createGain();return r.gain.value=0,i.connect(s).connect(n.frequency),n.connect(r).connect(e.destination),n.start(),i.start(),{key:t,nodes:[s,r],sources:[n,i],volumeParam:r.gain,gainScale:.22,pitch:[{param:n.frequency,ratio:1},{param:s.gain,ratio:.012}]}}buildRumble(e,t){const n=e.createBufferSource();n.buffer=this.brownNoise(e),n.loop=!0;const i=e.createBiquadFilter();i.type="lowpass",i.Q.value=.8;const s=e.createGain();return s.gain.value=0,n.connect(i).connect(s).connect(e.destination),n.start(),{key:t,nodes:[i,s],sources:[n],volumeParam:s.gain,gainScale:1.4,pitch:[{param:i.frequency,ratio:1}]}}buildCrackle(e,t){const n=e.createBufferSource();n.buffer=this.whiteNoise(e),n.loop=!0;const i=e.createBiquadFilter();i.type="bandpass",i.Q.value=1.2;const s=e.createGain();s.gain.value=0;const r=e.createBufferSource();r.buffer=this.crackleEnvelope(e),r.loop=!0;const o=e.createGain();return o.gain.value=0,r.connect(o).connect(s.gain),n.connect(i).connect(s).connect(e.destination),n.start(),r.start(),{key:t,nodes:[i,s,o],sources:[n,r],volumeParam:o.gain,gainScale:.9,pitch:[{param:i.frequency,ratio:4}]}}async buildRecordedVoice(e,t,n){const i=this.context;if(!i)return;let s;try{s=await this.getBuffer(e)}catch(l){console.warn("SightingAudio: the recorded sound failed to load, staying silent:",l);return}if(n!==this.voiceToken||!this.context)return;const r=i.createBufferSource();r.buffer=s,r.loop=!0;const o=i.createGain();o.gain.value=0,r.connect(o).connect(i.destination),r.start(),this.voice={key:t,nodes:[o],sources:[r],volumeParam:o.gain,gainScale:1,pitch:[]},this.requested&&this.applyTo(this.voice,this.requested)}async getBuffer(e){const t=this.context;if(!t)throw new Error("SightingAudio: AudioContext not ready — resume() must be called first");let n=this.buffers.get(e);return n||(n=fetch(e).then(i=>{if(!i.ok)throw new Error(`Audio fetch failed (${i.status}): ${e}`);return i.arrayBuffer()}).then(i=>t.decodeAudioData(i)),this.buffers.set(e,n)),n}whiteNoise(e){if(!this.noiseBuffer){const t=e.createBuffer(1,Math.floor(e.sampleRate*Mf),e.sampleRate),n=t.getChannelData(0);for(let i=0;i<n.length;i++)n[i]=Math.random()*2-1;this.noiseBuffer=t}return this.noiseBuffer}brownNoise(e){const t=e.createBuffer(1,Math.floor(e.sampleRate*Mf),e.sampleRate),n=t.getChannelData(0);let i=0,s=0;for(let r=0;r<n.length;r++)i=(i+.02*(Math.random()*2-1))/1.02,n[r]=i,s=Math.max(s,Math.abs(i));if(s>0)for(let r=0;r<n.length;r++)n[r]/=s;return t}crackleEnvelope(e){if(!this.crackleBuffer){const t=e.createBuffer(1,Math.floor(e.sampleRate*Sf),e.sampleRate),n=t.getChannelData(0),i=Math.max(1,Math.floor(l1*e.sampleRate)),s=Math.round(Sf*o1);for(let r=0;r<s;r++){const o=Math.floor(Math.random()*n.length),l=.4+Math.random()*.6;for(let c=0;c<i&&o+c<n.length;c++)n[o+c]=Math.max(n[o+c],l*(1-c/i))}this.crackleBuffer=t}return this.crackleBuffer}stopVoice(){const e=this.voice,t=this.context;if(this.voice=void 0,!e||!t)return;const n=t.currentTime;e.volumeParam.cancelScheduledValues(n),e.volumeParam.setTargetAtTime(0,n,wf/3);const i=n+wf;for(const s of e.sources){s.onended=()=>{s.disconnect();for(const r of e.nodes)r.disconnect()};try{s.stop(i)}catch{s.disconnect();for(const r of e.nodes)r.disconnect()}}}}function er(a){return[...a].sort((e,t)=>e.t-t.t)}function _f(a,e){let t;for(const n of er(a)){if(n.t>e)break;t=n}return t}const fc=Math.PI/180,vo=180/Math.PI;class ni{constructor(e,t,n){this.kind=e,this.canvasHeightPx=t,this.fovDeg=n;const i=n*fc/2;this.focalPx=e==="equidistant"?t/2/i:t/2/Math.tan(i)}focalPx;static of(e,t,n){return new ni(e.projection,t,n)}degToPx(e){const t=e*fc;return this.kind==="equidistant"?this.focalPx*t:2*this.focalPx*Math.tan(t/2)}pxToDeg(e){return this.kind==="equidistant"?e/this.focalPx*vo:2*Math.atan(e/(2*this.focalPx))*vo}angleDegToRadiusPx(e){const t=e*fc;return this.kind==="equidistant"?this.focalPx*t:this.focalPx*Math.tan(t)}halfWidthAngleDeg(e){return this.radiusPxToAngleDeg(this.canvasHeightPx*e/2)}radiusPxToAngleDeg(e){return this.kind==="equidistant"?e/this.focalPx*vo:Math.atan(e/this.focalPx)*vo}ofBounds(e){return{widthDeg:this.pxToDeg(e.width),heightDeg:this.pxToDeg(e.height)}}toBoundsSize(e){return{width:this.degToPx(e.widthDeg),height:this.degToPx(e.heightDeg)}}widthPx(e){return this.degToPx(et.angularWidthDeg(e))}}class an{static fovOf(e,t){return at(e,t)?.fovDeg??st.fieldOfViewDeg(e.instrument)}static toAngular(e){this.eachKeyframe(e,(t,n)=>({...t,angular:n.ofBounds(t.bounds)}))}static toBounds(e){this.eachKeyframe(e,(t,n)=>{if(!t.angular)return t;const{width:i,height:s}=n.toBoundsSize(t.angular),r={x:t.bounds.x+(t.bounds.width-i)/2,y:t.bounds.y+(t.bounds.height-s)/2,width:i,height:s};if(t.kind!=="polygon")return{...t,bounds:r};const o=t.bounds.width===0?1:i/t.bounds.width,l=t.bounds.height===0?1:s/t.bounds.height;return{...t,bounds:r,points:t.points.map(c=>({x:c.x*o,y:c.y*l}))}})}static toAim(e){this.eachKeyframe(e,(t,n,i)=>{const s=this.aimFrom(e,n,i,t.bounds);return s?{...t,aim:s}:t})}static aimOf(e,t,n){const i=ni.of(e.instrument,et.CANVAS_HEIGHT_PX,this.fovOf(e,t));return this.aimFrom(e,i,at(e,t),n)}static aimFrom(e,t,n,i){if(n?.headingDeg===void 0)return;const s=this.frameCentre(e),r=t.radiusPxToAngleDeg(i.x+i.width/2-s.x),o=t.radiusPxToAngleDeg(s.y-(i.y+i.height/2));return{azimuthDeg:((n.headingDeg+r)%360+360)%360,altitudeDeg:n.pitchDeg+o}}static toPosition(e){this.eachKeyframe(e,(t,n,i)=>{if(!t.aim||i?.headingDeg===void 0)return t;const s=this.frameCentre(e),r=this.shortestArc(t.aim.azimuthDeg-i.headingDeg),o=t.aim.altitudeDeg-i.pitchDeg,l=s.x+this.offAxisPx(n,r)-t.bounds.width/2,c=s.y-this.offAxisPx(n,o)-t.bounds.height/2;return{...t,bounds:{...t.bounds,x:l,y:c}}})}static frameCentre(e){return{x:st.frameWidthPx(e.instrument,et.CANVAS_HEIGHT_PX)/2,y:et.CANVAS_HEIGHT_PX/2}}static shortestArc(e){return(e%360+540)%360-180}static offAxisPx(e,t){return Math.abs(t)>=an.OFF_CANVAS_DEG?Math.sign(t)*an.OFF_CANVAS_PX:e.angleDegToRadiusPx(t)}static OFF_CANVAS_DEG=89;static OFF_CANVAS_PX=1e5;static reproject(e,t,n){const i=st.frameWidthPx(t,et.CANVAS_HEIGHT_PX)/2,s=st.frameWidthPx(e.instrument,et.CANVAS_HEIGHT_PX)/2,r=et.CANVAS_HEIGHT_PX/2;for(const o of[...e.timeline.allKeyframes]){const l=this.fovOf(e,o.t),c=n?.get(o.t)??l,h=ni.of(t,et.CANVAS_HEIGHT_PX,c),d=ni.of(e.instrument,et.CANVAS_HEIGHT_PX,l);e.timeline.addKeyframe(o.t,o.shapes.map(u=>{const{bounds:f}=u.shape,p=f.x+f.width/2-i,v=f.y+f.height/2-r,m=Math.hypot(p,v),g=m===0?1:d.angleDegToRadiusPx(h.radiusPxToAngleDeg(m))/m,_={...f,x:s+p*g-f.width/2,y:r+v*g-f.height/2};return{...u,shape:{...u.shape,bounds:_}}}))}this.toBounds(e)}static eachKeyframe(e,t){const{timeline:n}=e;for(const i of[...n.allKeyframes]){const s=at(e,i.t),r=this.fovOf(e,i.t),o=ni.of(e.instrument,et.CANVAS_HEIGHT_PX,r);n.addKeyframe(i.t,i.shapes.map(l=>({...l,shape:t(l.shape,o,s)})))}}}function h1(a){return On.restore(zh(a),a.provenance)}function zh(a){return an.toAngular(a),an.toAim(a),{version:1,time:a.event.time,endTime:a.event.endTime,durationSeconds:a.event.durationSeconds,utcOffsetHours:a.event.utcOffsetHours,timeZone:a.event.timeZone,place:a.event.place,witness:a.witness,testimony:a.testimony,caseId:a.caseId,description:a.event.description,tags:a.event.tags,timeline:a.timeline.toJSON(),witnessTrack:a.witnessTrack.toJSON(),weatherTrack:a.weatherTrack.toJSON(),soundTrack:a.soundTrack.toJSON(),weather:a.weather,decor:a.decor,milestones:a.milestones.length>0?a.milestones:void 0,weatherSource:a.weatherSource,instrument:a.instrumentId,exposureSeconds:a.exposureSeconds}}function d1(a){const{recording:e,provenance:t}=On.strip(a),n=u1(e);return n.provenance=t,n}function u1(a){const e=new jl({eventType:"sighting",time:a.time,endTime:a.endTime,durationSeconds:a.durationSeconds,utcOffsetHours:a.utcOffsetHours,timeZone:a.timeZone,place:a.place,description:a.description,tags:a.tags},Jl.fromJSON(a.timeline),a.witnessTrack?Yr.fromJSON(a.witnessTrack):new Yr,a.weatherTrack?Kr.fromJSON(a.weatherTrack):new Kr,a.soundTrack?$r.fromJSON(a.soundTrack):new $r,a.witness,a.caseId,a.weather,a.decor??[],a.weatherSource,a.instrument,a.exposureSeconds??a.witnessTrack?.keyframes.map(t=>t.pose.exposureSeconds).find(t=>t!==void 0),er(a.milestones??[]));return e.testimony=a.testimony,an.toBounds(e),an.toPosition(e),e}function za(a,e){for(const t of a){const n=t.toLowerCase().split("-")[0];if(e.includes(n))return n}return"en"}class vs{static preferencesFor(e){const t=navigator.languages??[],n=this.declaredFor(e);return n?[n,...t]:t}static declaredFor(e){for(let t=e;t;){const n=t.closest("[lang]")?.getAttribute("lang")?.trim();if(n)return n;const i=t.getRootNode();t=i instanceof ShadowRoot?i.host:void 0}}}class Gi{constructor(e){this.preferences=e}read(e){if(e===void 0||typeof e=="string")return e===""?void 0:e;for(const n of this.preferences){const i=e[n]??e[Gi.base(n)];if(i)return i}const t=new Set(this.preferences.map(n=>Gi.base(n)));for(const[n,i]of Object.entries(e))if(i&&t.has(Gi.base(n)))return i;return Object.values(e).find(n=>n)??void 0}write(e,t,n){const i=t?.trim()?t.trim():void 0;if(e===void 0||typeof e=="string")return i;const s={...e},r=Object.keys(s).find(o=>o===n)??Object.keys(s).find(o=>Gi.base(o)===Gi.base(n))??n;return i===void 0?delete s[r]:s[r]=i,Object.keys(s).length===0?void 0:s}static base(e){return e.toLowerCase().split("-")[0]}}const Hh=["en","fr"],f1={en:()=>ii(()=>Promise.resolve().then(()=>y1),void 0,import.meta.url).then(a=>a.ufoMessages_en),fr:()=>ii(()=>import("./UfoMessages_fr-BJPYHN17.js"),[],import.meta.url).then(a=>a.ufoMessages_fr)};function p1(a){return f1[a]()}const m1={en:()=>ii(()=>Promise.resolve().then(()=>rA),void 0,import.meta.url).then(a=>a.sightingEditorMessages_en),fr:()=>ii(()=>import("./SightingEditorMessages_fr-Bc7zY0ZE.js"),[],import.meta.url).then(a=>a.sightingEditorMessages_fr)};function g1(a){return m1[a]()}function v1(a){return a==="fr"?ii(()=>import("./TagNames_fr-Dnqq6HQ5.js"),[],import.meta.url).then(e=>e.tagNames_fr):Promise.resolve({})}const Tm={play:"Play",pause:"Pause",noDuration:"No observation duration",autoReplay:"Auto-replay",currentPosition:"Current position",duration:"Duration",switchToElapsed:"click to show elapsed time",switchToClockTime:"click to show the time of day",fullscreen:"Fullscreen",exitFullscreen:"Exit fullscreen",showWitnessMap:"Show where the witness was",hideWitnessMap:"Hide where the witness was",mapImageryUnavailable:"Aerial imagery unavailable",showMilestones:"Show the account's moments",hideMilestones:"Hide the account's moments",witnessHere:"The witness, here",decorHere:"Scenery"},y1=Object.freeze(Object.defineProperty({__proto__:null,ufoMessages_en:Tm},Symbol.toStringTag,{value:"Module"})),Am=Math.PI/180,b1=180/Math.PI,x1=256,w1=19;function M1(a,e){return 156543.03392*Math.cos(a*Am)/2**e}function S1(a,e){return M1(a,e)*x1}function Im(a,e){let t=0;for(;t<w1&&S1(a,t+1)>=e;)t++;return t}function gl(a){const e=a*Am;return(1-Math.log(Math.tan(e)+1/Math.cos(e))/Math.PI)/2}function Dm(a,e,t){const n=2**t;return{x:(a+180)/360*n,y:gl(e)*n}}function Cm(a,e,t){const n=gl(a.north),i=gl(a.south);return{x:(e-a.west)/(a.east-a.west),y:(gl(t)-n)/(i-n)}}function _1(a,e,t){const{x:n,y:i}=Dm(a,e,t);return{x:Math.floor(n),y:Math.floor(i),z:t}}function E1(a){const e=2**a.z,t=a.x/e*360-180,n=(a.x+1)/e*360-180,i=Ef(a.y,e);return{south:Ef(a.y+1,e),north:i,west:t,east:n}}function Ef(a,e){const t=a/e;return Math.atan(Math.sinh(Math.PI*(1-2*t)))*b1}function Rm(a,e,t,n){const i=_1(a,e,t),s=Math.floor(n/2),r=[];for(let c=-s;c<=s;c++)for(let h=-s;h<=s;h++)r.push({x:i.x+h,y:i.y+c,z:t});const o=r.map(E1),l={south:Math.min(...o.map(c=>c.south)),north:Math.max(...o.map(c=>c.north)),west:Math.min(...o.map(c=>c.west)),east:Math.max(...o.map(c=>c.east))};return{tiles:r,bounds:l}}class Us{constructor(e){this.ctx=e}static SCALE_STEPS_M=[5e3,2e3,1e3,500,200,100,50,20,10,5];static MARKER_RADIUS_PX=8.5;static ON_MARKER_M=3;targets=[];hitTest(e,t){let n,i=1/0;for(const s of this.targets){const r=Math.hypot(s.x-e,s.y-t);r>s.radius||r>i||(n=s,i=r)}return n}get width(){return this.ctx.canvas.width}get height(){return this.ctx.canvas.height}paint(e){const{ctx:t}=this;t.save(),this.targets=[],t.clearRect(0,0,this.width,this.height),this.paintGround(e),this.paintNight(e.nightFraction),this.paintPath(e),e.position?(this.paintCone(e,e.position),this.paintDecor(e),this.paintMarkers(e),this.paintWitness(e,e.position)):(this.paintDecor(e),this.paintMarkers(e)),this.paintNorth(),this.paintFooter(e.bounds,e.attribution),t.restore()}toCanvas(e,t,n){const i=Cm(e,n,t);return{x:i.x*this.width,y:i.y*this.height}}paintGround(e){const{ctx:t}=this;t.fillStyle="#1d2321",t.fillRect(0,0,this.width,this.height);const n=e.imagery;if(!n)return;const i=this.toCanvas(e.bounds,n.bounds.north,n.bounds.west),s=this.toCanvas(e.bounds,n.bounds.south,n.bounds.east);t.drawImage(n.source,i.x,i.y,s.x-i.x,s.y-i.y)}paintNight(e=0){if(e<=0)return;const{ctx:t}=this;t.save(),t.fillStyle=`rgba(6, 12, 30, ${Math.min(e,1)*.78})`,t.fillRect(0,0,this.width,this.height),t.restore()}paintDecor(e){const{ctx:t}=this;for(const n of e.decor){const i=this.toCanvas(e.bounds,n.lat,n.lng);if(n.label&&this.targets.push({kind:"decor",label:n.label,lat:n.lat,lng:n.lng,x:i.x,y:i.y,radius:7}),t.beginPath(),t.rect(i.x-3.5,i.y-3.5,7,7),t.fillStyle="rgba(120, 220, 255, 0.85)",t.fill(),t.lineWidth=1.5,t.strokeStyle="rgba(0, 0, 0, 0.7)",t.stroke(),n.headingDeg===void 0)continue;const s=(n.headingDeg-90)*Math.PI/180;t.beginPath(),t.moveTo(i.x,i.y),t.lineTo(i.x+Math.cos(s)*10,i.y+Math.sin(s)*10),t.lineWidth=3,t.strokeStyle="rgba(0, 0, 0, 0.6)",t.stroke(),t.lineWidth=1.5,t.strokeStyle="rgba(120, 220, 255, 0.9)",t.stroke()}}paintPath(e){if(!e.path.moved)return;const{ctx:t}=this,n=e.path.points.map(i=>this.toCanvas(e.bounds,i.lat,i.lng));t.beginPath(),t.moveTo(n[0].x,n[0].y);for(const i of n.slice(1))t.lineTo(i.x,i.y);t.lineJoin="round",t.lineCap="round",t.strokeStyle="rgba(0, 0, 0, 0.65)",t.lineWidth=5,t.stroke(),t.strokeStyle="rgba(255, 255, 255, 0.9)",t.lineWidth=2,t.stroke()}paintCone(e,t){const{headingDeg:n,coneHalfAngleDeg:i}=e;if(n===void 0||i===void 0)return;const{ctx:s}=this,r=this.toCanvas(e.bounds,t.lat,t.lng),o=Math.hypot(this.width,this.height),l=(n-90)*Math.PI/180,c=i*Math.PI/180;s.save(),s.beginPath(),s.moveTo(r.x,r.y),s.arc(r.x,r.y,o,l-c,l+c),s.closePath();const h=s.createRadialGradient(r.x,r.y,0,r.x,r.y,o);h.addColorStop(0,"rgba(255, 224, 130, 0.55)"),h.addColorStop(.35,"rgba(255, 224, 130, 0.22)"),h.addColorStop(1,"rgba(255, 224, 130, 0)"),s.fillStyle=h,s.fill(),s.restore()}paintMarkers(e){const{ctx:t}=this;t.textAlign="center",t.textBaseline="middle",t.font="bold 10px sans-serif";for(const n of[...e.markers].sort((i,s)=>Number(i.current)-Number(s.current))){const i=this.toCanvas(e.bounds,n.lat,n.lng);this.targets.push({kind:"milestone",label:n.note?`${n.label} — ${n.note}`:n.label,lat:n.lat,lng:n.lng,t:n.t,x:i.x,y:i.y,radius:Us.MARKER_RADIUS_PX}),t.beginPath(),t.arc(i.x,i.y,Us.MARKER_RADIUS_PX,0,Math.PI*2),t.fillStyle=n.current?"rgba(255, 224, 130, 0.95)":"rgba(0, 0, 0, 0.55)",t.fill(),t.lineWidth=2,t.strokeStyle="rgba(255, 255, 255, 0.9)",t.stroke(),t.fillStyle=n.current?"#1d2321":"#fff",t.fillText(n.label,i.x,i.y)}}paintWitness(e,t){const{ctx:n}=this,i=this.toCanvas(e.bounds,t.lat,t.lng);e.witnessLabel&&this.targets.push({kind:"witness",label:e.witnessLabel,lat:t.lat,lng:t.lng,x:i.x,y:i.y,radius:8});const s=e.markers.some(r=>{if(!r.current)return!1;const o=un(r.lat,r.lng,t.lat,t.lng);return Math.hypot(o.x,o.z)<=Us.ON_MARKER_M});n.beginPath(),n.arc(i.x,i.y,s?Us.MARKER_RADIUS_PX+2.5:5.5,0,Math.PI*2),s||(n.fillStyle="#ff5a3c",n.fill()),n.lineWidth=4,n.strokeStyle="rgba(0, 0, 0, 0.5)",n.stroke(),n.lineWidth=s?3:2.5,n.strokeStyle=s?"#ff5a3c":"#fff",n.stroke()}paintNorth(){const{ctx:e}=this,t=this.width-14,n=16;e.beginPath(),e.moveTo(t,n-9),e.lineTo(t-4.5,n+5),e.lineTo(t,n+2),e.lineTo(t+4.5,n+5),e.closePath(),e.fillStyle="rgba(255, 255, 255, 0.92)",e.strokeStyle="rgba(0, 0, 0, 0.6)",e.lineWidth=1,e.fill(),e.stroke(),e.font="bold 9px sans-serif",e.textAlign="center",e.textBaseline="top",e.strokeText("N",t,n+6),e.fillText("N",t,n+6)}paintFooter(e,t){const{ctx:n}=this;n.font="9px sans-serif",n.textBaseline="bottom";const i=t?this.wrap(t,this.width-20):[];let s=this.height-4;n.textAlign="right";for(const f of i.slice().reverse())this.paintOutlinedText(f,this.width-6,s),s-=11;const r=(e.south+e.north)/2,l=Math.abs(un(r,e.east,r,e.west).x)/this.width,c=Us.SCALE_STEPS_M.find(f=>f/l<=this.width/3);if(c===void 0)return;const h=c/l,d=8,u=s-3;n.lineWidth=3,n.strokeStyle="rgba(0, 0, 0, 0.6)",n.beginPath(),n.moveTo(d,u),n.lineTo(d+h,u),n.stroke(),n.lineWidth=1.5,n.strokeStyle="rgba(255, 255, 255, 0.95)",n.stroke(),n.textAlign="left",this.paintOutlinedText(c>=1e3?`${c/1e3} km`:`${c} m`,d,u-3)}paintOutlinedText(e,t,n){const{ctx:i}=this;i.lineWidth=3,i.strokeStyle="rgba(0, 0, 0, 0.75)",i.strokeText(e,t,n),i.fillStyle="#fff",i.fillText(e,t,n)}wrap(e,t){const n=[];let i="";for(const s of e.split(" ")){const r=i?`${i} ${s}`:s;i&&this.ctx.measureText(r).width>t?(n.push(i),i=s):i=r}return i&&n.push(i),n}}const Hn=256,Tf=3,T1=32768;class Pm{fetchImpl;tileUrlTemplate;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.tileUrlTemplate=e.tileUrlTemplate??"https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png"}async getElevationGrid(e,t){const n=(e.south+e.north)/2,i=(e.west+e.east)/2,s=Math.abs(un(n,e.east,n,e.west).x),r=Math.abs(un(e.north,i,e.south,i).z),o=Im(n,Math.max(s,r)),{tiles:l}=Rm(i,n,o,Tf),c=Tf*Hn,h=new Float32Array(c*c),d=l[0];await Promise.all(l.map(f=>this.decodeTileInto(f,d,h,c)));const u=new Float32Array(t.width*t.height);for(let f=0;f<t.height;f++){const p=e.north+(e.south-e.north)*(f/(t.height-1));for(let v=0;v<t.width;v++){const m=e.west+(e.east-e.west)*(v/(t.width-1));u[f*t.width+v]=this.sampleAt(p,m,o,d,h,c)}}return{heights:u,width:t.width,height:t.height,bounds:e}}async decodeTileInto(e,t,n,i){const s=this.tileUrlTemplate.replace("{z}",String(e.z)).replace("{x}",String(e.x)).replace("{y}",String(e.y)),r=await this.fetchImpl(s);if(!r.ok)throw new Error(`Elevation tile fetch failed (${r.status}): ${s}`);const o=await createImageBitmap(await r.blob()),l=document.createElement("canvas");l.width=Hn,l.height=Hn;const c=l.getContext("2d");if(!c)throw new Error("2D canvas context unavailable");c.drawImage(o,0,0);const{data:h}=c.getImageData(0,0,Hn,Hn),d=(e.x-t.x)*Hn,u=(e.y-t.y)*Hn;for(let f=0;f<Hn;f++)for(let p=0;p<Hn;p++){const v=(f*Hn+p)*4,m=h[v]*256+h[v+1]+h[v+2]/256-T1,g=d+p,_=u+f;n[_*i+g]=m}}sampleAt(e,t,n,i,s,r){const{x:o,y:l}=Dm(t,e,n),c=(o-i.x)*Hn,h=(l-i.y)*Hn,d=Math.max(0,Math.min(r-1,Math.floor(c))),u=Math.max(0,Math.min(r-1,Math.floor(h))),f=Math.min(r-1,d+1),p=Math.min(r-1,u+1),v=c-d,m=h-u,g=s[u*r+d],_=s[u*r+f],M=s[p*r+d],x=s[p*r+f],w=g+(_-g)*v,E=M+(x-M)*v;return w+(E-w)*m}}const pc=256,Af=3;async function Lm(a,e,t,n){const i=(a.south+a.north)/2,s=(a.west+a.east)/2,r=Math.abs(un(i,a.east,i,a.west).x),o=Math.abs(un(a.north,s,a.south,s).z),l=Im(i,Math.max(r,o)/2),{tiles:c,bounds:h}=Rm(s,i,l,Af),d=Af*pc,u=document.createElement("canvas");u.width=d,u.height=d;const f=u.getContext("2d");if(!f)throw new Error("2D canvas context unavailable");const p=c[0];await Promise.all(c.map(async g=>{const _=t(g),M=await n(_);if(!M.ok)throw new Error(`Imagery tile fetch failed (${M.status}): ${_}`);const x=await createImageBitmap(await M.blob());f.drawImage(x,(g.x-p.x)*pc,(g.y-p.y)*pc)}));const v=document.createElement("canvas");v.width=e.width,v.height=e.height;const m=v.getContext("2d");if(!m)throw new Error("2D canvas context unavailable");return m.drawImage(u,0,0,d,d,0,0,e.width,e.height),{source:v,width:e.width,height:e.height,bounds:h}}class Nm{attribution="Imagery © Esri, Maxar, Earthstar Geographics, and the GIS User Community";fetchImpl;tileUrlTemplate;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.tileUrlTemplate=e.tileUrlTemplate??"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}"}async getImageryTexture(e,t){return Lm(e,t,n=>this.tileUrlTemplate.replace("{z}",String(n.z)).replace("{y}",String(n.y)).replace("{x}",String(n.x)),this.fetchImpl)}}function A1(){return{elevation:new Pm,imagery:Om()}}function Om(){return new Nm}const I1=new Set,Ys="show-witness-map",Ha="hide-milestones";class Vn extends HTMLElement{static get observedAttributes(){return["src",Ys,Ha]}shadow;stageElement;canvas;canvasRenderer;tooltip;toolbar;playPauseButton;loopButton;static WITNESS_MAP_MIN_SPAN_M=400;static WITNESS_MAP_MARGIN=.6;static WITNESS_MAP_IMAGERY_PX=768;fullscreenButton;cornerButtons;witnessMapButton;milestonesButton;witnessMapPanel;witnessMapCanvas;witnessMapRenderer;seekInput;milestoneMarks;milestoneCaption;timeStartLabel;timeEndLabel;witnessPath;witnessMapBounds;witnessMapImagery;witnessMapImageryRequested=!1;witnessMapImageryCredit;witnessMapImageryFailed=!1;creditShownExternally=!1;lookYawDeg=0;lookPitchDeg=0;milestonesShown=!0;currentSighting=jl.create();sightingAudio=new c1;soundPreview;player;loopEnabled=!0;playbackBeforeClick;highlightedSourceIds=new Set;paintsShapes=!0;enableClickToPlay=!0;fullscreenTarget;messages=Tm;realDurationMs;realStartMs;showClockTime=!0;handleFullscreenChange=()=>{this.updateFullscreenButton(),this.resizeWitnessMap()};witnessMapResizeObserver=typeof ResizeObserver>"u"?void 0:new ResizeObserver(()=>this.resizeWitnessMap());resizeWitnessMap(){this.witnessMapPanel.hidden||(this.sizeWitnessMapCanvas(),this.paintWitnessMap(this.currentTime))}simulatedFullscreen=!1;styleBeforeSimulatedFullscreen;bodyOverflowBeforeSimulatedFullscreen;handleSimulatedFullscreenKey=e=>{e.key==="Escape"&&this.exitSimulatedFullscreen()};handlePointerMove=e=>{const t=this.canvasPointFromEvent(e),n=t&&this.shapeAt(t.x,t.y),i=this.said.read(n?.shape.title);if(!i){this.tooltip.hidden=!0;return}this.tooltip.textContent=i,this.tooltip.hidden=!1;const s=this.stageElement.getBoundingClientRect();this.tooltip.style.left=`${e.clientX-s.left+12}px`,this.tooltip.style.top=`${e.clientY-s.top+12}px`};handleWitnessMapPointerMove=e=>{const t=this.witnessMapTargetFrom(e);if(!t){this.tooltip.hidden=!0,this.witnessMapCanvas.style.cursor="default";return}this.witnessMapCanvas.style.cursor="pointer",this.tooltip.textContent=t.label,this.tooltip.hidden=!1;const n=this.stageElement.getBoundingClientRect();this.tooltip.style.left=`${e.clientX-n.left+12}px`,this.tooltip.style.top=`${e.clientY-n.top+12}px`};handleWitnessMapClick=e=>{const t=this.witnessMapTargetFrom(e);if(t){if(t.kind==="milestone"&&t.t!==void 0){this.player.seek(t.t);return}this.dispatchEvent(new CustomEvent("lookat",{detail:{lat:t.lat,lng:t.lng,kind:t.kind},bubbles:!0,composed:!0}))}};witnessMapTargetFrom(e){const t=this.witnessMapCanvas.getBoundingClientRect();if(!(t.width===0||t.height===0))return this.witnessMapRenderer.hitTest((e.clientX-t.left)/t.width*this.witnessMapCanvas.width,(e.clientY-t.top)/t.height*this.witnessMapCanvas.height)}handlePointerLeave=()=>{this.tooltip.hidden=!0};constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${a1}</style>${s1}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.canvas=this.shadow.getElementById("canvas"),this.canvasRenderer=new Oh(this.canvas.getContext("2d")),this.tooltip=this.shadow.getElementById("tooltip"),this.toolbar=this.shadow.getElementById("toolbar"),this.playPauseButton=this.shadow.getElementById("play-pause"),this.loopButton=this.shadow.getElementById("loop"),this.fullscreenButton=this.shadow.getElementById("fullscreen"),this.cornerButtons=this.shadow.getElementById("corner-buttons"),this.witnessMapButton=this.shadow.getElementById("witness-map"),this.milestonesButton=this.shadow.getElementById("milestones"),this.witnessMapPanel=this.shadow.getElementById("witness-map-panel"),this.witnessMapCanvas=this.shadow.getElementById("witness-map-canvas"),this.witnessMapRenderer=new Us(this.witnessMapCanvas.getContext("2d")),this.seekInput=this.shadow.getElementById("seek"),this.milestoneMarks=this.shadow.getElementById("milestone-marks"),this.milestoneCaption=this.shadow.getElementById("milestone-caption"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end");for(const t of[this.timeStartLabel,this.timeEndLabel])t.addEventListener("click",()=>this.toggleTimeDisplay()),t.addEventListener("keydown",n=>{n.key!=="Enter"&&n.key!==" "||(n.preventDefault(),this.toggleTimeDisplay())});this.fullscreenTarget=this.stageElement,this.playPauseButton.addEventListener("click",()=>this.togglePlayPause()),this.loopButton.addEventListener("click",()=>this.toggleLoop()),this.fullscreenButton.addEventListener("click",()=>this.toggleFullscreen()),this.witnessMapButton.addEventListener("click",()=>this.toggleWitnessMap()),this.milestonesButton.addEventListener("click",()=>this.toggleMilestones()),this.witnessMapCanvas.addEventListener("pointermove",this.handleWitnessMapPointerMove),this.witnessMapCanvas.addEventListener("pointerleave",this.handlePointerLeave),this.witnessMapCanvas.addEventListener("click",this.handleWitnessMapClick),this.seekInput.addEventListener("input",()=>this.player.seek(Number(this.seekInput.value))),this.canvas.addEventListener("click",t=>{this.enableClickToPlay&&(t.detail<=1&&(this.playbackBeforeClick={state:this.playbackState,time:this.currentTime}),this.togglePlayPause())}),this.canvas.addEventListener("dblclick",t=>{this.enableClickToPlay&&(t.preventDefault(),this.restorePlayback(),this.toggleFullscreen())}),this.canvas.addEventListener("pointermove",this.handlePointerMove),this.canvas.addEventListener("pointerleave",this.handlePointerLeave),document.addEventListener("fullscreenchange",this.handleFullscreenChange),this.witnessMapResizeObserver?.observe(this.witnessMapPanel),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateWitnessMapButton(),this.updateMilestonesButton(),this.refresh(),this.loadLocaleMessages()}connectedCallback(){this.saidTexts=void 0;const e=this.getAttribute("src");e&&this.loadFromSrc(e)}disconnectedCallback(){document.removeEventListener("fullscreenchange",this.handleFullscreenChange),this.witnessMapResizeObserver?.disconnect(),this.exitSimulatedFullscreen(),this.sightingAudio.dispose()}attributeChangedCallback(e,t,n){e==="src"&&n&&n!==t&&this.isConnected&&this.loadFromSrc(n),e===Ys&&this.applyWitnessMapDefault(),e===Ha&&this.setMilestonesShown(!this.hasAttribute(Ha))}async loadFromSrc(e){this.sightingData=await fu.json(e)}get sightingData(){return h1(this.currentSighting)}set sightingData(e){this.player.stop(),this.soundPreview=void 0,this.sightingAudio.silence(),this.currentSighting=d1(e),this.player=this.createPlayer(),this.updateTimeLabels(),this.updatePlayPauseButton(),this.refresh(),this.applyWitnessMapDefault()}get sighting(){return this.currentSighting}previewSound(e){this.soundPreview=e,this.sightingAudio.resume(),this.sightingAudio.setSound(e)}stopSoundPreview(){this.soundPreview=void 0,this.sightingAudio.silence()}get canvasElement(){return this.canvas}get renderer(){return this.canvasRenderer}get currentTime(){return this.player.time}set currentTime(e){this.player.seek(e)}get seekableDuration(){return this.player.seekableDuration}get autoReplayEnabled(){return this.loopEnabled}set autoReplayEnabled(e){e!==this.loopEnabled&&this.toggleLoop()}play(){this.player.seekableDuration<=0||this.playbackState==="playing"||this.togglePlayPause()}pause(){this.playbackState==="playing"&&this.togglePlayPause()}get positionLabel(){return this.timeStartLabel.textContent??""}get durationLabel(){return this.timeEndLabel.textContent??""}get showingClockTime(){return this.canShowClockTime}get canSwitchTimeDisplay(){return this.realStartMs!==void 0}toggleTimeDisplay(){this.canSwitchTimeDisplay&&(this.showClockTime=!this.showClockTime,this.updateTimeLabels(),this.updateTimeLabelTitles(),this.dispatchEvent(new CustomEvent("timedisplaychange",{bubbles:!0,composed:!0})))}get canShowClockTime(){return this.realStartMs!==void 0&&this.showClockTime}set showToolbar(e){this.toolbar.classList.toggle("hidden",!e)}get playbackState(){return this.player.playbackState}get selectedSourceIds(){return this.highlightedSourceIds}get durationSeconds(){return this.currentSighting.event.durationSeconds}set durationSeconds(e){this.currentSighting.event.durationSeconds=e,this.updateTimeLabels(),this.refresh(),this.updatePlayPauseButton()}set selectedSourceIds(e){const t=new Set(e);t.size===this.highlightedSourceIds.size&&[...t].every(i=>this.highlightedSourceIds.has(i))||(this.highlightedSourceIds=t,this.refresh())}hasVisibleShapeAt(e,t){return this.shapeAt(e,t)!==void 0}refresh(){this.applyFrameFormat(),this.updateTimeLabels(),this.seekInput.max=String(this.player.seekableDuration),this.refreshMilestoneMarks(),this.updateMilestonesButton(),this.updateWitnessMap(),this.player.seek(this.player.time)}refreshMilestoneMarks(){const e=this.player.seekableDuration,t=e>0?er(this.sighting.milestones):[];this.milestoneMarks.replaceChildren(...t.map(n=>{const i=document.createElement("button");i.type="button",i.className="milestone-mark",i.style.left=`${Math.min(Math.max(n.t/e,0),1)*100}%`;const s=this.said.read(n.label)??"",r=this.said.read(n.note),o=r?`${s} — ${r}`:s;return i.title=o,i.setAttribute("aria-label",o),i.addEventListener("click",()=>this.player.seek(n.t)),i}))}showMilestoneAt(e){const t=this.milestonesShown&&this.sighting.milestones.length>0?_f(this.sighting.milestones,e):void 0;if(this.milestoneCaption.hidden=t===void 0,!t)return;const n=document.createElement("b");n.textContent=this.said.read(t.label)??"";const i=this.said.read(t.note),s=i?` — ${i}`:"";this.milestoneCaption.replaceChildren(n,document.createTextNode(s))}exposureInstants(e){const t=this.exposureTimes(e),n=1/t.length;return t.map(i=>({shapes:this.shapesAt(i),share:n}))}exposureTimes(e=this.currentTime){const t=(this.currentSighting.exposure??0)*1e3;if(t<Vn.SHORTEST_VISIBLE_EXPOSURE_MS)return[e];const n=Math.min(Vn.MAX_EXPOSURE_STEPS,Math.max(2,Math.round(t/Vn.SHORTEST_VISIBLE_EXPOSURE_MS))),i=Math.ceil(this.travelPxOver(e,t)/Vn.EXPOSURE_STEP_PX),s=Math.min(Vn.MAX_TRAVEL_STEPS,Math.max(n,i)),r=[];for(let o=0;o<s;o++)r.push(e+t*o/s);return r}travelPxOver(e,t){const n=this.shapesAt(e),i=this.shapesAt(e+t);let s=0;for(const[r,o]of n){const l=i.get(r);if(!l)continue;const c=l.bounds.x+l.bounds.width/2-(o.bounds.x+o.bounds.width/2),h=l.bounds.y+l.bounds.height/2-(o.bounds.y+o.bounds.height/2);s=Math.max(s,Math.hypot(c,h))}return s}shapeAt(e,t,n){for(const i of this.exposureTimes()){const s=this.currentSighting.timeline.hitTest(i,e,t,n);if(s)return s}}shapesAt(e){const t=new Map;for(const n of this.currentSighting.timeline.sourceIds){const i=this.currentSighting.timeline.getInterpolatedShapeAt(e,n);i&&t.set(n,i)}return t}static SHORTEST_VISIBLE_EXPOSURE_MS=20;static MAX_EXPOSURE_STEPS=48;static EXPOSURE_STEP_PX=2;static MAX_TRAVEL_STEPS=320;applyFrameFormat(){const e=st.frameWidthPx(this.currentSighting.instrument,this.canvas.height);if(this.canvas.width===e)return;this.canvas.width=e,this.canvas.parentElement?.style.setProperty("--frame-aspect",`${e} / ${this.canvas.height}`)}canvasPointFromEvent(e){const t=this.canvas.getBoundingClientRect();if(!(t.width===0||t.height===0))return{x:(e.clientX-t.left)/t.width*this.canvas.width,y:(e.clientY-t.top)/t.height*this.canvas.height}}onFrame(e,t){this.canvasRenderer.clear(this.canvas.width,this.canvas.height);const n=this.playbackState!=="playing"?this.highlightedSourceIds:I1;this.canvasRenderer.setStarPoints(st.starPointsOf(this.sighting.instrument));const i=(at(this.sighting,e)?.rollDeg??0)+this.gaitAt(e).rollDeg;this.canvasRenderer.setRoll(i*Math.PI/180);const s=this.exposureInstants(e),r=this.frameShift;if(this.paintsShapes)for(const o of s)for(const[,l]of o.shapes){const c=o.share,h=c===1?l:{...l,transparency:1-(1-l.transparency)*c};this.canvasRenderer.paintShape(this.shifted(h,r))}for(const[o,l]of s[0].shapes)n.has(o)&&(this.paintsShapes?n.size===1?this.canvasRenderer.paintShape({...l,selected:!0}):this.canvasRenderer.paintMemberOutline(l):this.canvasRenderer.paintSelectionOnly(this.shifted(l,r)));if(n.size>1){const o=it.groupBoundsFor([...t].filter(([l])=>n.has(l)).map(([,l])=>l.bounds));this.canvasRenderer.paintGroupHandles(o)}this.keepWitnessMapClear(s[0].shapes),this.seekInput.value=String(e),this.timeStartLabel.textContent=this.formatPosition(e),this.showMilestoneAt(e),this.paintWitnessMap(e),this.playbackState==="playing"?(this.soundPreview=void 0,this.sightingAudio.setSound(uu(this.currentSighting,e))):this.soundPreview?this.sightingAudio.setSound(this.soundPreview):this.sightingAudio.silence(),this.updatePlayPauseButton(),this.dispatchEvent(new CustomEvent("timeupdate",{detail:{time:e}}))}shifted(e,t){return t.x===0&&t.y===0?e:{...e,bounds:{...e.bounds,x:e.bounds.x+t.x,y:e.bounds.y+t.y}}}createPlayer(){const e=new r1(this.currentSighting.timeline,(t,n)=>this.onFrame(t,n));return e.loop=this.loopEnabled,e.onEnded=()=>{this.updatePlayPauseButton(),this.dispatchEvent(new CustomEvent("ended",{bubbles:!0,composed:!0}))},e}togglePlayPause(){this.player.seekableDuration<=0||(this.player.playbackState==="playing"?(this.player.pause(),this.soundPreview=void 0,this.sightingAudio.silence(),this.refresh()):(this.sightingAudio.resume(),this.player.play()),this.updatePlayPauseButton())}updatePlayPauseButton(){const e=this.player.playbackState==="playing";this.playPauseButton.textContent=e?"⏸":"▶";const t=this.player.seekableDuration>0;this.playPauseButton.disabled=!t;const n=t?e?this.messages.pause:this.messages.play:this.messages.noDuration;this.playPauseButton.title=n,this.playPauseButton.setAttribute("aria-label",n),this.toolbar.classList.toggle("auto-hide",e),this.cornerButtons.classList.toggle("auto-hide",e)}toggleLoop(){this.loopEnabled=!this.loopEnabled,this.loopButton.setAttribute("aria-pressed",String(this.loopEnabled)),this.player.loop=this.loopEnabled}restorePlayback(){const e=this.playbackBeforeClick;e&&(this.currentTime=e.time,e.state==="playing"?this.play():this.pause())}get canUseNativeFullscreen(){return typeof this.fullscreenTarget.requestFullscreen=="function"&&document.fullscreenEnabled}toggleFullscreen(){if(!this.canUseNativeFullscreen){this.simulatedFullscreen?this.exitSimulatedFullscreen():this.enterSimulatedFullscreen();return}document.fullscreenElement?document.exitFullscreen():this.fullscreenTarget.requestFullscreen().catch(e=>{console.error("<rr0-ufo>: requestFullscreen() failed —",e)})}enterSimulatedFullscreen(){const e=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen=e.getAttribute("style")??"",this.bodyOverflowBeforeSimulatedFullscreen=document.body.style.overflow;const t=e.style;t.setProperty("position","fixed"),t.setProperty("inset","0"),t.setProperty("margin","0"),t.setProperty("max-width","none"),t.setProperty("max-height","none"),t.setProperty("aspect-ratio","auto"),t.setProperty("z-index","2147483647"),t.setProperty("background","#000"),t.setProperty("width","100vw"),t.setProperty("width","100dvw"),t.setProperty("height","100vh"),t.setProperty("height","100dvh"),document.body.style.overflow="hidden",this.simulatedFullscreen=!0,document.addEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton()}exitSimulatedFullscreen(){if(!this.simulatedFullscreen)return;const e=this.fullscreenTarget;this.styleBeforeSimulatedFullscreen?e.setAttribute("style",this.styleBeforeSimulatedFullscreen):e.removeAttribute("style"),document.body.style.overflow=this.bodyOverflowBeforeSimulatedFullscreen??"",this.simulatedFullscreen=!1,document.removeEventListener("keydown",this.handleSimulatedFullscreenKey),this.updateFullscreenButton()}toggleWitnessMap(){this.setWitnessMapOpen(this.witnessMapPanel.hidden)}applyWitnessMapDefault(){this.setWitnessMapOpen(this.hasAttribute(Ys)&&this.witnessPath!==void 0)}setWitnessMapOpen(e){this.witnessMapPanel.hidden=!e,this.witnessMapPanel.removeAttribute("title"),this.witnessMapButton.setAttribute("aria-pressed",String(e)),this.updateWitnessMapButton(),e&&(this.sizeWitnessMapCanvas(),this.loadWitnessMapImagery(),this.paintWitnessMap(this.currentTime))}updateWitnessMapButton(){const t=!this.witnessMapPanel.hidden?this.messages.hideWitnessMap:this.messages.showWitnessMap;this.witnessMapButton.title=t,this.witnessMapButton.setAttribute("aria-label",t)}updateWitnessMap(){const e=this.witnessPath!==void 0;if(this.witnessPath=Zr.of(this.currentSighting),this.witnessMapButton.hidden=this.witnessPath===void 0,!e&&this.witnessPath&&this.applyWitnessMapDefault(),!this.witnessPath){this.setWitnessMapOpen(!1),this.witnessMapBounds=void 0;return}const t=this.witnessPath.boundsAround(Vn.WITNESS_MAP_MIN_SPAN_M,Vn.WITNESS_MAP_MARGIN);(!this.witnessMapBounds||!this.sameGround(this.witnessMapBounds,t))&&(this.witnessMapBounds=t,this.witnessMapImagery=void 0,this.witnessMapImageryCredit=void 0,this.witnessMapImageryFailed=!1,this.witnessMapImageryRequested=!1,this.witnessMapPanel.hidden||this.loadWitnessMapImagery())}sameGround(e,t){const n=Math.abs(e.east-e.west)/20;return Math.abs(e.north-t.north)<n&&Math.abs(e.south-t.south)<n&&Math.abs(e.west-t.west)<n&&Math.abs(e.east-t.east)<n}async loadWitnessMapImagery(){if(this.witnessMapImageryRequested||!this.witnessMapBounds)return;this.witnessMapImageryRequested=!0;const e=Om(),t=this.witnessMapBounds;try{const n=await e.getImageryTexture(t,{width:Vn.WITNESS_MAP_IMAGERY_PX,height:Vn.WITNESS_MAP_IMAGERY_PX});if(this.witnessMapBounds!==t)return;this.witnessMapImagery=n,this.witnessMapImageryCredit=e.attribution}catch{this.witnessMapImageryFailed=!0}this.paintWitnessMap(this.currentTime)}get witnessMapCredit(){return this.witnessMapImageryCredit}get witnessMapFooterLine(){return this.witnessMapImageryFailed?this.messages.mapImageryUnavailable:this.creditShownExternally?void 0:this.witnessMapImageryCredit}keepWitnessMapClear(e){if(this.witnessMapPanel.hidden)return;const t=this.witnessMapBoxPx;if(!t)return;const n=(o,l,c)=>{for(const h of e.values())if(!(h.transparency>=1)&&!(h.bounds.x+h.bounds.width<o-c||h.bounds.x>l+c)&&!(h.bounds.y>t.bottom+c||h.bounds.y+h.bounds.height<t.top-c))return!0;return!1},i=[this.canvas.width-t.width,this.canvas.width],s=[0,t.width],r=Vn.WITNESS_MAP_CLEARANCE_PX;if(this.witnessMapPanel.classList.contains("on-the-left")){n(i[0],i[1],r)||this.witnessMapPanel.classList.remove("on-the-left");return}n(i[0],i[1],0)&&!n(s[0],s[1],0)&&this.witnessMapPanel.classList.add("on-the-left")}witnessMapBoxPx;static WITNESS_MAP_CLEARANCE_PX=24;sizeWitnessMapCanvas(){const e=this.witnessMapPanel.clientWidth;if(e===0)return;const t=Math.round(e*(globalThis.devicePixelRatio??1));this.measureWitnessMapBox(),this.witnessMapCanvas.width!==t&&(this.witnessMapCanvas.width=t,this.witnessMapCanvas.height=t)}measureWitnessMapBox(){const e=this.witnessMapPanel.getBoundingClientRect(),t=this.canvas.getBoundingClientRect();if(t.width===0||t.height===0)return;const n=this.canvas.width/t.width,i=this.canvas.height/t.height;this.witnessMapBoxPx={width:e.width*n,top:(e.top-t.top)*i,bottom:(e.bottom-t.top)*i}}paintWitnessMap(e){if(this.witnessMapPanel.hidden||!this.witnessPath||!this.witnessMapBounds)return;const t=at(this.currentSighting,e),n=this.currentSighting.instrument,i=[],s=this.currentSighting.milestones.length>0?_f(this.currentSighting.milestones,e):void 0;for(const r of this.milestonesShown?er(this.currentSighting.milestones):[]){const o=at(this.currentSighting,r.t);o?.lat===void 0||o.lng===void 0||i.push({label:this.said.read(r.label)??"",note:this.said.read(r.note),t:r.t,lat:o.lat,lng:o.lng,current:r===s})}this.witnessMapRenderer.paint({bounds:this.witnessMapBounds,imagery:this.witnessMapImagery,path:this.witnessPath,position:t?.lat!==void 0&&t.lng!==void 0?{lat:t.lat,lng:t.lng}:void 0,headingDeg:t?.headingDeg===void 0?void 0:t.headingDeg+this.lookYawDeg,coneHalfAngleDeg:t?ni.of(n,this.canvas.height,t.fovDeg).halfWidthAngleDeg(st.aspectOf(n)):void 0,markers:i,decor:this.witnessMapDecorAt(e),witnessLabel:this.said.read(this.currentSighting.witness?.title)??this.messages.witnessHere,nightFraction:this.witnessMapNightFraction,attribution:this.witnessMapFooterLine})}toggleMilestones(){this.setMilestonesShown(!this.milestonesShown)}setMilestonesShown(e){this.milestonesShown=e,this.milestoneMarks.hidden=!e,this.milestonesButton.setAttribute("aria-pressed",String(e)),this.updateMilestonesButton(),this.showMilestoneAt(this.currentTime),this.paintWitnessMap(this.currentTime)}updateMilestonesButton(){this.milestonesButton.hidden=this.currentSighting.milestones.length===0;const e=this.milestonesShown?this.messages.hideMilestones:this.messages.showMilestones;this.milestonesButton.title=e,this.milestonesButton.setAttribute("aria-label",e)}witnessMapDecorAt(e){const t=at(this.currentSighting,0);return t?.lat===void 0||t.lng===void 0?[]:this.currentSighting.decor.filter(n=>n.kind!=="crop").map(n=>{const i=Qa(n,e),{lat:s,lng:r}=Wi(i.eastM,-i.northM,t.lat,t.lng);return{lat:s,lng:r,headingDeg:i.headingDeg,label:this.said.read(n.title)??this.messages.decorHere}})}witnessMapNightFraction;setSunAltitude(e){const t=e===void 0?void 0:Math.max(0,Math.min(1,-e/12));t!==this.witnessMapNightFraction&&(this.witnessMapNightFraction=t,this.paintWitnessMap(this.currentTime))}setLookOffset(e,t){e===this.lookYawDeg&&t===this.lookPitchDeg||(this.lookYawDeg=e,this.lookPitchDeg=t,this.refresh())}get frameShiftPx(){return this.frameShift}get frameShift(){const e=this.gaitAt(this.currentTime),t=this.lookYawDeg+e.yawDeg,n=this.lookPitchDeg+e.pitchDeg;if(t===0&&n===0)return{x:0,y:0};const i=at(this.currentSighting,this.currentTime),s=ni.of(this.currentSighting.instrument,this.canvas.height,i?.fovDeg??60);return{x:-s.angleDegToRadiusPx(t),y:s.angleDegToRadiusPx(n)}}gaitAt(e){return qt.of(this.currentSighting)?.offsetAt(e)??qt.STILL}updateFullscreenButton(){const e=this.simulatedFullscreen||document.fullscreenElement===this.fullscreenTarget;this.fullscreenButton.title=e?this.messages.exitFullscreen:this.messages.fullscreen,this.fullscreenButton.setAttribute("aria-label",this.fullscreenButton.title)}get said(){return this.saidTexts??=new Gi(vs.preferencesFor(this))}saidTexts;async loadLocaleMessages(){const e=za(vs.preferencesFor(this),Hh);e!=="en"&&this.applyMessages(await p1(e))}updateTimeLabelTitles(){const e=this.showClockTime?this.messages.switchToElapsed:this.messages.switchToClockTime,t=this.canSwitchTimeDisplay?` — ${e}`:"";this.timeStartLabel.title=this.messages.currentPosition+t,this.timeEndLabel.title=this.messages.duration+t;for(const n of[this.timeStartLabel,this.timeEndLabel])n.classList.toggle("switchable",this.canSwitchTimeDisplay),this.canSwitchTimeDisplay?(n.setAttribute("role","button"),n.setAttribute("tabindex","0")):(n.removeAttribute("role"),n.removeAttribute("tabindex"))}applyMessages(e){this.messages=e,this.updateTimeLabelTitles(),this.loopButton.title=e.autoReplay,this.loopButton.setAttribute("aria-label",e.autoReplay),this.updatePlayPauseButton(),this.updateFullscreenButton(),this.updateWitnessMapButton(),this.updateMilestonesButton()}updateTimeLabels(){const e=this.currentSighting.event,t=ja(e);this.realDurationMs=t!==void 0&&t>0?t:void 0,this.realStartMs=e.time?Ph(e.time):void 0;const n=this.currentSighting.timeline.duration;this.player.playbackRate=this.realDurationMs!==void 0&&n>0?n/this.realDurationMs:1,this.player.durationOverrideMs=n>0?0:this.realDurationMs??0,this.timeEndLabel.textContent=this.formatEndOfTimeline(),this.timeStartLabel.textContent=this.formatPosition(this.player.time),this.updateTimeLabelTitles()}formatPosition(e){if(this.realDurationMs===void 0)return yo(e);const t=this.currentSighting.timeline.duration,n=t>0&&e<=t?e/t*this.realDurationMs:e;return this.canShowClockTime?Df(If(this.realStartMs+n)):yo(n)}formatEndOfTimeline(){return this.realDurationMs===void 0?yo(this.currentSighting.timeline.duration):this.canShowClockTime?Df(If(this.realStartMs+this.realDurationMs)):yo(this.realDurationMs)}}function If(a){const e=new Date(a);return{hour:e.getUTCHours(),minute:e.getUTCMinutes(),second:e.getUTCSeconds()}}function Df(a){if(a.hour===void 0)return"0:00";const e=t=>String(t).padStart(2,"0");return a.second?`${e(a.hour)}:${e(a.minute??0)}:${e(a.second)}`:`${e(a.hour)}:${e(a.minute??0)}`}function yo(a){const e=Math.round(a/1e3),t=Math.floor(e/60),n=e%60;return`${t}:${String(n).padStart(2,"0")}`}const Gh="rr0-ufo";function Ql(){customElements.get(Gh)||customElements.define(Gh,Vn)}const D1=`
|
|
1797
1828
|
<div class="stage" id="stage">
|
|
1798
1829
|
<div class="frame" id="frame">
|
|
1799
1830
|
<canvas id="scene-canvas"></canvas>
|
|
@@ -6014,7 +6045,7 @@ void main() {
|
|
|
6014
6045
|
|
|
6015
6046
|
}
|
|
6016
6047
|
|
|
6017
|
-
}`;class NS{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(e,t){if(this.texture===null){const n=new rg(e.texture);(e.depthNear!==t.depthNear||e.depthFar!==t.depthFar)&&(this.depthNear=e.depthNear,this.depthFar=e.depthFar),this.texture=n}}getMesh(e){if(this.texture!==null&&this.mesh===null){const t=e.cameras[0].viewport,n=new Rt({vertexShader:PS,fragmentShader:LS,uniforms:{depthColor:{value:this.texture},depthWidth:{value:t.z},depthHeight:{value:t.w}}});this.mesh=new Ke(new es(20,20),n)}return this.mesh}reset(){this.texture=null,this.mesh=null}getDepthTexture(){return this.texture}}class OS extends Qs{constructor(e,t){super();const n=this;let i=null,s=1,r=null,o="local-floor",l=1,c=null,h=null,d=null,u=null,f=null,p=null;const v=typeof XRWebGLBinding<"u",m=new NS,g={},_=t.getContextAttributes();let M=null,x=null;const w=[],E=[],D=new Re;let y=null;const T=new An;T.viewport=new pt;const A=new An;A.viewport=new pt;const I=[T,A],R=new kb;let N=null,z=null;this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(K){let ae=w[K];return ae===void 0&&(ae=new _c,w[K]=ae),ae.getTargetRaySpace()},this.getControllerGrip=function(K){let ae=w[K];return ae===void 0&&(ae=new _c,w[K]=ae),ae.getGripSpace()},this.getHand=function(K){let ae=w[K];return ae===void 0&&(ae=new _c,w[K]=ae),ae.getHandSpace()};function L(K){const ae=E.indexOf(K.inputSource);if(ae===-1)return;const ie=w[ae];ie!==void 0&&(ie.update(K.inputSource,K.frame,c||r),ie.dispatchEvent({type:K.type,data:K.inputSource}))}function B(){i.removeEventListener("select",L),i.removeEventListener("selectstart",L),i.removeEventListener("selectend",L),i.removeEventListener("squeeze",L),i.removeEventListener("squeezestart",L),i.removeEventListener("squeezeend",L),i.removeEventListener("end",B),i.removeEventListener("inputsourceschange",F);for(let K=0;K<w.length;K++){const ae=E[K];ae!==null&&(E[K]=null,w[K].disconnect(ae))}N=null,z=null,m.reset();for(const K in g)delete g[K];e.setRenderTarget(M),f=null,u=null,d=null,i=null,x=null,ze.stop(),n.isPresenting=!1,e.setPixelRatio(y),e.setSize(D.width,D.height,!1),n.dispatchEvent({type:"sessionend"})}this.setFramebufferScaleFactor=function(K){s=K,n.isPresenting===!0&&Ee("WebXRManager: Cannot change framebuffer scale while presenting.")},this.setReferenceSpaceType=function(K){o=K,n.isPresenting===!0&&Ee("WebXRManager: Cannot change reference space type while presenting.")},this.getReferenceSpace=function(){return c||r},this.setReferenceSpace=function(K){c=K},this.getBaseLayer=function(){return u!==null?u:f},this.getBinding=function(){return d===null&&v&&(d=new XRWebGLBinding(i,t)),d},this.getFrame=function(){return p},this.getSession=function(){return i},this.setSession=async function(K){if(i=K,i!==null){if(M=e.getRenderTarget(),i.addEventListener("select",L),i.addEventListener("selectstart",L),i.addEventListener("selectend",L),i.addEventListener("squeeze",L),i.addEventListener("squeezestart",L),i.addEventListener("squeezeend",L),i.addEventListener("end",B),i.addEventListener("inputsourceschange",F),_.xrCompatible!==!0&&await t.makeXRCompatible(),y=e.getPixelRatio(),e.getSize(D),v&&"createProjectionLayer"in XRWebGLBinding.prototype){let ie=null,G=null,_e=null;_.depth&&(_e=_.stencil?t.DEPTH24_STENCIL8:t.DEPTH_COMPONENT24,ie=_.stencil?Ws:Ki,G=_.stencil?Qr:ri);const Pe={colorFormat:t.RGBA8,depthFormat:_e,scaleFactor:s};d=this.getBinding(),u=d.createProjectionLayer(Pe),i.updateRenderState({layers:[u]}),e.setPixelRatio(1),e.setSize(u.textureWidth,u.textureHeight,!1),x=new In(u.textureWidth,u.textureHeight,{format:Mn,type:Bn,depthTexture:new Js(u.textureWidth,u.textureHeight,G,void 0,void 0,void 0,void 0,void 0,void 0,ie),stencilBuffer:_.stencil,colorSpace:e.outputColorSpace,samples:_.antialias?4:0,resolveDepthBuffer:u.ignoreDepthValues===!1,resolveStencilBuffer:u.ignoreDepthValues===!1})}else{const ie={antialias:_.antialias,alpha:!0,depth:_.depth,stencil:_.stencil,framebufferScaleFactor:s};f=new XRWebGLLayer(i,t,ie),i.updateRenderState({baseLayer:f}),e.setPixelRatio(1),e.setSize(f.framebufferWidth,f.framebufferHeight,!1),x=new In(f.framebufferWidth,f.framebufferHeight,{format:Mn,type:Bn,colorSpace:e.outputColorSpace,stencilBuffer:_.stencil,resolveDepthBuffer:f.ignoreDepthValues===!1,resolveStencilBuffer:f.ignoreDepthValues===!1})}x.isXRRenderTarget=!0,this.setFoveation(l),c=null,r=await i.requestReferenceSpace(o),ze.setContext(i),ze.start(),n.isPresenting=!0,n.dispatchEvent({type:"sessionstart"})}},this.getEnvironmentBlendMode=function(){if(i!==null)return i.environmentBlendMode},this.getDepthTexture=function(){return m.getDepthTexture()};function F(K){for(let ae=0;ae<K.removed.length;ae++){const ie=K.removed[ae],G=E.indexOf(ie);G>=0&&(E[G]=null,w[G].disconnect(ie))}for(let ae=0;ae<K.added.length;ae++){const ie=K.added[ae];let G=E.indexOf(ie);if(G===-1){for(let Pe=0;Pe<w.length;Pe++)if(Pe>=E.length){E.push(ie),G=Pe;break}else if(E[Pe]===null){E[Pe]=ie,G=Pe;break}if(G===-1)break}const _e=w[G];_e&&_e.connect(ie)}}const V=new P,j=new P;function $(K,ae,ie){V.setFromMatrixPosition(ae.matrixWorld),j.setFromMatrixPosition(ie.matrixWorld);const G=V.distanceTo(j),_e=ae.projectionMatrix.elements,Pe=ie.projectionMatrix.elements,Ae=_e[14]/(_e[10]-1),be=_e[14]/(_e[10]+1),Ne=(_e[9]+1)/_e[5],Oe=(_e[9]-1)/_e[5],ke=(_e[8]-1)/_e[0],rt=(Pe[8]+1)/Pe[0],ot=Ae*ke,Pt=Ae*rt,wt=G/(-ke+rt),Lt=wt*-ke;if(ae.matrixWorld.decompose(K.position,K.quaternion,K.scale),K.translateX(Lt),K.translateZ(wt),K.matrixWorld.compose(K.position,K.quaternion,K.scale),K.matrixWorldInverse.copy(K.matrixWorld).invert(),_e[10]===-1)K.projectionMatrix.copy(ae.projectionMatrix),K.projectionMatrixInverse.copy(ae.projectionMatrixInverse);else{const Wt=Ae+wt,k=be+wt,_n=ot-Lt,lt=Pt+(G-Lt),C=Ne*be/k*Wt,b=Oe*be/k*Wt;K.projectionMatrix.makePerspective(_n,lt,C,b,Wt,k),K.projectionMatrixInverse.copy(K.projectionMatrix).invert()}}function ne(K,ae){ae===null?K.matrixWorld.copy(K.matrix):K.matrixWorld.multiplyMatrices(ae.matrixWorld,K.matrix),K.matrixWorldInverse.copy(K.matrixWorld).invert()}this.updateCamera=function(K){if(i===null)return;let ae=K.near,ie=K.far;m.texture!==null&&(m.depthNear>0&&(ae=m.depthNear),m.depthFar>0&&(ie=m.depthFar)),R.near=A.near=T.near=ae,R.far=A.far=T.far=ie,(N!==R.near||z!==R.far)&&(i.updateRenderState({depthNear:R.near,depthFar:R.far}),N=R.near,z=R.far),R.layers.mask=K.layers.mask|6,T.layers.mask=R.layers.mask&-5,A.layers.mask=R.layers.mask&-3;const G=K.parent,_e=R.cameras;ne(R,G);for(let Pe=0;Pe<_e.length;Pe++)ne(_e[Pe],G);_e.length===2?$(R,T,A):R.projectionMatrix.copy(T.projectionMatrix),re(K,R,G)};function re(K,ae,ie){ie===null?K.matrix.copy(ae.matrixWorld):(K.matrix.copy(ie.matrixWorld),K.matrix.invert(),K.matrix.multiply(ae.matrixWorld)),K.matrix.decompose(K.position,K.quaternion,K.scale),K.updateMatrixWorld(!0),K.projectionMatrix.copy(ae.projectionMatrix),K.projectionMatrixInverse.copy(ae.projectionMatrixInverse),K.isPerspectiveCamera&&(K.fov=ir*2*Math.atan(1/K.projectionMatrix.elements[5]),K.zoom=1)}this.getCamera=function(){return R},this.getFoveation=function(){if(!(u===null&&f===null))return l},this.setFoveation=function(K){l=K,u!==null&&(u.fixedFoveation=K),f!==null&&f.fixedFoveation!==void 0&&(f.fixedFoveation=K)},this.hasDepthSensing=function(){return m.texture!==null},this.getDepthSensingMesh=function(){return m.getMesh(R)},this.getCameraTexture=function(K){return g[K]};let He=null;function Ze(K,ae){if(h=ae.getViewerPose(c||r),p=ae,h!==null){const ie=h.views;f!==null&&(e.setRenderTargetFramebuffer(x,f.framebuffer),e.setRenderTarget(x));let G=!1;ie.length!==R.cameras.length&&(R.cameras.length=0,G=!0);for(let be=0;be<ie.length;be++){const Ne=ie[be];let Oe=null;if(f!==null)Oe=f.getViewport(Ne);else{const rt=d.getViewSubImage(u,Ne);Oe=rt.viewport,be===0&&(e.setRenderTargetTextures(x,rt.colorTexture,rt.depthStencilTexture),e.setRenderTarget(x))}let ke=I[be];ke===void 0&&(ke=new An,ke.layers.enable(be),ke.viewport=new pt,I[be]=ke),ke.matrix.fromArray(Ne.transform.matrix),ke.matrix.decompose(ke.position,ke.quaternion,ke.scale),ke.projectionMatrix.fromArray(Ne.projectionMatrix),ke.projectionMatrixInverse.copy(ke.projectionMatrix).invert(),ke.viewport.set(Oe.x,Oe.y,Oe.width,Oe.height),be===0&&(R.matrix.copy(ke.matrix),R.matrix.decompose(R.position,R.quaternion,R.scale)),G===!0&&R.cameras.push(ke)}const _e=i.enabledFeatures;if(_e&&_e.includes("depth-sensing")&&i.depthUsage=="gpu-optimized"&&v){d=n.getBinding();const be=d.getDepthInformation(ie[0]);be&&be.isValid&&be.texture&&m.init(be,i.renderState)}if(_e&&_e.includes("camera-access")&&v){e.state.unbindTexture(),d=n.getBinding();for(let be=0;be<ie.length;be++){const Ne=ie[be].camera;if(Ne){let Oe=g[Ne];Oe||(Oe=new rg,g[Ne]=Oe);const ke=d.getCameraImage(Ne);Oe.sourceTexture=ke}}}}for(let ie=0;ie<w.length;ie++){const G=E[ie],_e=w[ie];G!==null&&_e!==void 0&&_e.update(G,ae,c||r)}He&&He(K,ae),ae.detectedPlanes&&n.dispatchEvent({type:"planesdetected",data:ae}),p=null}const ze=new ug;ze.setAnimationLoop(Ze),this.setAnimationLoop=function(K){He=K},this.dispose=function(){}}}const kS=new qe,bg=new Be;bg.set(-1,0,0,0,1,0,0,0,1);function FS(a,e){function t(m,g){m.matrixAutoUpdate===!0&&m.updateMatrix(),g.value.copy(m.matrix)}function n(m,g){g.color.getRGB(m.fogColor.value,og(a)),g.isFog?(m.fogNear.value=g.near,m.fogFar.value=g.far):g.isFogExp2&&(m.fogDensity.value=g.density)}function i(m,g,_,M,x){g.isNodeMaterial?g.uniformsNeedUpdate=!1:g.isMeshBasicMaterial?s(m,g):g.isMeshLambertMaterial?(s(m,g),g.envMap&&(m.envMapIntensity.value=g.envMapIntensity)):g.isMeshToonMaterial?(s(m,g),d(m,g)):g.isMeshPhongMaterial?(s(m,g),h(m,g),g.envMap&&(m.envMapIntensity.value=g.envMapIntensity)):g.isMeshStandardMaterial?(s(m,g),u(m,g),g.isMeshPhysicalMaterial&&f(m,g,x)):g.isMeshMatcapMaterial?(s(m,g),p(m,g)):g.isMeshDepthMaterial?s(m,g):g.isMeshDistanceMaterial?(s(m,g),v(m,g)):g.isMeshNormalMaterial?s(m,g):g.isLineBasicMaterial?(r(m,g),g.isLineDashedMaterial&&o(m,g)):g.isPointsMaterial?l(m,g,_,M):g.isSpriteMaterial?c(m,g):g.isShadowMaterial?(m.color.value.copy(g.color),m.opacity.value=g.opacity):g.isShaderMaterial&&(g.uniformsNeedUpdate=!1)}function s(m,g){m.opacity.value=g.opacity,g.color&&m.diffuse.value.copy(g.color),g.emissive&&m.emissive.value.copy(g.emissive).multiplyScalar(g.emissiveIntensity),g.map&&(m.map.value=g.map,t(g.map,m.mapTransform)),g.alphaMap&&(m.alphaMap.value=g.alphaMap,t(g.alphaMap,m.alphaMapTransform)),g.bumpMap&&(m.bumpMap.value=g.bumpMap,t(g.bumpMap,m.bumpMapTransform),m.bumpScale.value=g.bumpScale,g.side===Vt&&(m.bumpScale.value*=-1)),g.normalMap&&(m.normalMap.value=g.normalMap,t(g.normalMap,m.normalMapTransform),m.normalScale.value.copy(g.normalScale),g.side===Vt&&m.normalScale.value.negate()),g.displacementMap&&(m.displacementMap.value=g.displacementMap,t(g.displacementMap,m.displacementMapTransform),m.displacementScale.value=g.displacementScale,m.displacementBias.value=g.displacementBias),g.emissiveMap&&(m.emissiveMap.value=g.emissiveMap,t(g.emissiveMap,m.emissiveMapTransform)),g.specularMap&&(m.specularMap.value=g.specularMap,t(g.specularMap,m.specularMapTransform)),g.alphaTest>0&&(m.alphaTest.value=g.alphaTest);const _=e.get(g),M=_.envMap,x=_.envMapRotation;M&&(m.envMap.value=M,m.envMapRotation.value.setFromMatrix4(kS.makeRotationFromEuler(x)).transpose(),M.isCubeTexture&&M.isRenderTargetTexture===!1&&m.envMapRotation.value.premultiply(bg),m.reflectivity.value=g.reflectivity,m.ior.value=g.ior,m.refractionRatio.value=g.refractionRatio),g.lightMap&&(m.lightMap.value=g.lightMap,m.lightMapIntensity.value=g.lightMapIntensity,t(g.lightMap,m.lightMapTransform)),g.aoMap&&(m.aoMap.value=g.aoMap,m.aoMapIntensity.value=g.aoMapIntensity,t(g.aoMap,m.aoMapTransform))}function r(m,g){m.diffuse.value.copy(g.color),m.opacity.value=g.opacity,g.map&&(m.map.value=g.map,t(g.map,m.mapTransform))}function o(m,g){m.dashSize.value=g.dashSize,m.totalSize.value=g.dashSize+g.gapSize,m.scale.value=g.scale}function l(m,g,_,M){m.diffuse.value.copy(g.color),m.opacity.value=g.opacity,m.size.value=g.size*_,m.scale.value=M*.5,g.map&&(m.map.value=g.map,t(g.map,m.uvTransform)),g.alphaMap&&(m.alphaMap.value=g.alphaMap,t(g.alphaMap,m.alphaMapTransform)),g.alphaTest>0&&(m.alphaTest.value=g.alphaTest)}function c(m,g){m.diffuse.value.copy(g.color),m.opacity.value=g.opacity,m.rotation.value=g.rotation,g.map&&(m.map.value=g.map,t(g.map,m.mapTransform)),g.alphaMap&&(m.alphaMap.value=g.alphaMap,t(g.alphaMap,m.alphaMapTransform)),g.alphaTest>0&&(m.alphaTest.value=g.alphaTest)}function h(m,g){m.specular.value.copy(g.specular),m.shininess.value=Math.max(g.shininess,1e-4)}function d(m,g){g.gradientMap&&(m.gradientMap.value=g.gradientMap)}function u(m,g){m.metalness.value=g.metalness,g.metalnessMap&&(m.metalnessMap.value=g.metalnessMap,t(g.metalnessMap,m.metalnessMapTransform)),m.roughness.value=g.roughness,g.roughnessMap&&(m.roughnessMap.value=g.roughnessMap,t(g.roughnessMap,m.roughnessMapTransform)),g.envMap&&(m.envMapIntensity.value=g.envMapIntensity)}function f(m,g,_){m.ior.value=g.ior,g.sheen>0&&(m.sheenColor.value.copy(g.sheenColor).multiplyScalar(g.sheen),m.sheenRoughness.value=g.sheenRoughness,g.sheenColorMap&&(m.sheenColorMap.value=g.sheenColorMap,t(g.sheenColorMap,m.sheenColorMapTransform)),g.sheenRoughnessMap&&(m.sheenRoughnessMap.value=g.sheenRoughnessMap,t(g.sheenRoughnessMap,m.sheenRoughnessMapTransform))),g.clearcoat>0&&(m.clearcoat.value=g.clearcoat,m.clearcoatRoughness.value=g.clearcoatRoughness,g.clearcoatMap&&(m.clearcoatMap.value=g.clearcoatMap,t(g.clearcoatMap,m.clearcoatMapTransform)),g.clearcoatRoughnessMap&&(m.clearcoatRoughnessMap.value=g.clearcoatRoughnessMap,t(g.clearcoatRoughnessMap,m.clearcoatRoughnessMapTransform)),g.clearcoatNormalMap&&(m.clearcoatNormalMap.value=g.clearcoatNormalMap,t(g.clearcoatNormalMap,m.clearcoatNormalMapTransform),m.clearcoatNormalScale.value.copy(g.clearcoatNormalScale),g.side===Vt&&m.clearcoatNormalScale.value.negate())),g.dispersion>0&&(m.dispersion.value=g.dispersion),g.iridescence>0&&(m.iridescence.value=g.iridescence,m.iridescenceIOR.value=g.iridescenceIOR,m.iridescenceThicknessMinimum.value=g.iridescenceThicknessRange[0],m.iridescenceThicknessMaximum.value=g.iridescenceThicknessRange[1],g.iridescenceMap&&(m.iridescenceMap.value=g.iridescenceMap,t(g.iridescenceMap,m.iridescenceMapTransform)),g.iridescenceThicknessMap&&(m.iridescenceThicknessMap.value=g.iridescenceThicknessMap,t(g.iridescenceThicknessMap,m.iridescenceThicknessMapTransform))),g.transmission>0&&(m.transmission.value=g.transmission,m.transmissionSamplerMap.value=_.texture,m.transmissionSamplerSize.value.set(_.width,_.height),g.transmissionMap&&(m.transmissionMap.value=g.transmissionMap,t(g.transmissionMap,m.transmissionMapTransform)),m.thickness.value=g.thickness,g.thicknessMap&&(m.thicknessMap.value=g.thicknessMap,t(g.thicknessMap,m.thicknessMapTransform)),m.attenuationDistance.value=g.attenuationDistance,m.attenuationColor.value.copy(g.attenuationColor)),g.anisotropy>0&&(m.anisotropyVector.value.set(g.anisotropy*Math.cos(g.anisotropyRotation),g.anisotropy*Math.sin(g.anisotropyRotation)),g.anisotropyMap&&(m.anisotropyMap.value=g.anisotropyMap,t(g.anisotropyMap,m.anisotropyMapTransform))),m.specularIntensity.value=g.specularIntensity,m.specularColor.value.copy(g.specularColor),g.specularColorMap&&(m.specularColorMap.value=g.specularColorMap,t(g.specularColorMap,m.specularColorMapTransform)),g.specularIntensityMap&&(m.specularIntensityMap.value=g.specularIntensityMap,t(g.specularIntensityMap,m.specularIntensityMapTransform))}function p(m,g){g.matcap&&(m.matcap.value=g.matcap)}function v(m,g){const _=e.get(g).light;m.referencePosition.value.setFromMatrixPosition(_.matrixWorld),m.nearDistance.value=_.shadow.camera.near,m.farDistance.value=_.shadow.camera.far}return{refreshFogUniforms:n,refreshMaterialUniforms:i}}function US(a,e,t,n){let i={},s={},r=[];const o=a.getParameter(a.MAX_UNIFORM_BUFFER_BINDINGS);function l(x,w){const E=w.program;n.uniformBlockBinding(x,E)}function c(x,w){let E=i[x.id];E===void 0&&(m(x),E=h(x),i[x.id]=E,x.addEventListener("dispose",_));const D=w.program;n.updateUBOMapping(x,D);const y=e.render.frame;s[x.id]!==y&&(u(x),s[x.id]=y)}function h(x){const w=d();x.__bindingPointIndex=w;const E=a.createBuffer(),D=x.__size,y=x.usage;return a.bindBuffer(a.UNIFORM_BUFFER,E),a.bufferData(a.UNIFORM_BUFFER,D,y),a.bindBuffer(a.UNIFORM_BUFFER,null),a.bindBufferBase(a.UNIFORM_BUFFER,w,E),E}function d(){for(let x=0;x<o;x++)if(r.indexOf(x)===-1)return r.push(x),x;return Ue("WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached."),0}function u(x){const w=i[x.id],E=x.uniforms,D=x.__cache;a.bindBuffer(a.UNIFORM_BUFFER,w);for(let y=0,T=E.length;y<T;y++){const A=E[y];if(Array.isArray(A))for(let I=0,R=A.length;I<R;I++)f(A[I],y,I,D);else f(A,y,0,D)}a.bindBuffer(a.UNIFORM_BUFFER,null)}function f(x,w,E,D){if(v(x,w,E,D)===!0){const y=x.__offset,T=x.value;if(Array.isArray(T)){let A=0;for(let I=0;I<T.length;I++){const R=T[I],N=g(R);p(R,x.__data,A),typeof R!="number"&&typeof R!="boolean"&&!R.isMatrix3&&!ArrayBuffer.isView(R)&&(A+=N.storage/Float32Array.BYTES_PER_ELEMENT)}}else p(T,x.__data,0);a.bufferSubData(a.UNIFORM_BUFFER,y,x.__data)}}function p(x,w,E){typeof x=="number"||typeof x=="boolean"?w[0]=x:x.isMatrix3?(w[0]=x.elements[0],w[1]=x.elements[1],w[2]=x.elements[2],w[3]=0,w[4]=x.elements[3],w[5]=x.elements[4],w[6]=x.elements[5],w[7]=0,w[8]=x.elements[6],w[9]=x.elements[7],w[10]=x.elements[8],w[11]=0):ArrayBuffer.isView(x)?w.set(new x.constructor(x.buffer,x.byteOffset,w.length)):x.toArray(w,E)}function v(x,w,E,D){const y=x.value,T=w+"_"+E;if(D[T]===void 0)return typeof y=="number"||typeof y=="boolean"?D[T]=y:ArrayBuffer.isView(y)?D[T]=y.slice():D[T]=y.clone(),!0;{const A=D[T];if(typeof y=="number"||typeof y=="boolean"){if(A!==y)return D[T]=y,!0}else{if(ArrayBuffer.isView(y))return!0;if(A.equals(y)===!1)return A.copy(y),!0}}return!1}function m(x){const w=x.uniforms;let E=0;const D=16;for(let T=0,A=w.length;T<A;T++){const I=Array.isArray(w[T])?w[T]:[w[T]];for(let R=0,N=I.length;R<N;R++){const z=I[R],L=Array.isArray(z.value)?z.value:[z.value];for(let B=0,F=L.length;B<F;B++){const V=L[B],j=g(V),$=E%D,ne=$%j.boundary,re=$+ne;E+=ne,re!==0&&D-re<j.storage&&(E+=D-re),z.__data=new Float32Array(j.storage/Float32Array.BYTES_PER_ELEMENT),z.__offset=E,E+=j.storage}}}const y=E%D;return y>0&&(E+=D-y),x.__size=E,x.__cache={},this}function g(x){const w={boundary:0,storage:0};return typeof x=="number"||typeof x=="boolean"?(w.boundary=4,w.storage=4):x.isVector2?(w.boundary=8,w.storage=8):x.isVector3||x.isColor?(w.boundary=16,w.storage=12):x.isVector4?(w.boundary=16,w.storage=16):x.isMatrix3?(w.boundary=48,w.storage=48):x.isMatrix4?(w.boundary=64,w.storage=64):x.isTexture?Ee("WebGLRenderer: Texture samplers can not be part of an uniforms group."):ArrayBuffer.isView(x)?(w.boundary=16,w.storage=x.byteLength):Ee("WebGLRenderer: Unsupported uniform value type.",x),w}function _(x){const w=x.target;w.removeEventListener("dispose",_);const E=r.indexOf(w.__bindingPointIndex);r.splice(E,1),a.deleteBuffer(i[w.id]),delete i[w.id],delete s[w.id]}function M(){for(const x in i)a.deleteBuffer(i[x]);r=[],i={},s={}}return{bind:l,update:c,dispose:M}}const BS=new Uint16Array([12469,15057,12620,14925,13266,14620,13807,14376,14323,13990,14545,13625,14713,13328,14840,12882,14931,12528,14996,12233,15039,11829,15066,11525,15080,11295,15085,10976,15082,10705,15073,10495,13880,14564,13898,14542,13977,14430,14158,14124,14393,13732,14556,13410,14702,12996,14814,12596,14891,12291,14937,11834,14957,11489,14958,11194,14943,10803,14921,10506,14893,10278,14858,9960,14484,14039,14487,14025,14499,13941,14524,13740,14574,13468,14654,13106,14743,12678,14818,12344,14867,11893,14889,11509,14893,11180,14881,10751,14852,10428,14812,10128,14765,9754,14712,9466,14764,13480,14764,13475,14766,13440,14766,13347,14769,13070,14786,12713,14816,12387,14844,11957,14860,11549,14868,11215,14855,10751,14825,10403,14782,10044,14729,9651,14666,9352,14599,9029,14967,12835,14966,12831,14963,12804,14954,12723,14936,12564,14917,12347,14900,11958,14886,11569,14878,11247,14859,10765,14828,10401,14784,10011,14727,9600,14660,9289,14586,8893,14508,8533,15111,12234,15110,12234,15104,12216,15092,12156,15067,12010,15028,11776,14981,11500,14942,11205,14902,10752,14861,10393,14812,9991,14752,9570,14682,9252,14603,8808,14519,8445,14431,8145,15209,11449,15208,11451,15202,11451,15190,11438,15163,11384,15117,11274,15055,10979,14994,10648,14932,10343,14871,9936,14803,9532,14729,9218,14645,8742,14556,8381,14461,8020,14365,7603,15273,10603,15272,10607,15267,10619,15256,10631,15231,10614,15182,10535,15118,10389,15042,10167,14963,9787,14883,9447,14800,9115,14710,8665,14615,8318,14514,7911,14411,7507,14279,7198,15314,9675,15313,9683,15309,9712,15298,9759,15277,9797,15229,9773,15166,9668,15084,9487,14995,9274,14898,8910,14800,8539,14697,8234,14590,7790,14479,7409,14367,7067,14178,6621,15337,8619,15337,8631,15333,8677,15325,8769,15305,8871,15264,8940,15202,8909,15119,8775,15022,8565,14916,8328,14804,8009,14688,7614,14569,7287,14448,6888,14321,6483,14088,6171,15350,7402,15350,7419,15347,7480,15340,7613,15322,7804,15287,7973,15229,8057,15148,8012,15046,7846,14933,7611,14810,7357,14682,7069,14552,6656,14421,6316,14251,5948,14007,5528,15356,5942,15356,5977,15353,6119,15348,6294,15332,6551,15302,6824,15249,7044,15171,7122,15070,7050,14949,6861,14818,6611,14679,6349,14538,6067,14398,5651,14189,5311,13935,4958,15359,4123,15359,4153,15356,4296,15353,4646,15338,5160,15311,5508,15263,5829,15188,6042,15088,6094,14966,6001,14826,5796,14678,5543,14527,5287,14377,4985,14133,4586,13869,4257,15360,1563,15360,1642,15358,2076,15354,2636,15341,3350,15317,4019,15273,4429,15203,4732,15105,4911,14981,4932,14836,4818,14679,4621,14517,4386,14359,4156,14083,3795,13808,3437,15360,122,15360,137,15358,285,15355,636,15344,1274,15322,2177,15281,2765,15215,3223,15120,3451,14995,3569,14846,3567,14681,3466,14511,3305,14344,3121,14037,2800,13753,2467,15360,0,15360,1,15359,21,15355,89,15346,253,15325,479,15287,796,15225,1148,15133,1492,15008,1749,14856,1882,14685,1886,14506,1783,14324,1608,13996,1398,13702,1183]);let ui=null;function zS(){return ui===null&&(ui=new or(BS,16,16,Zs,pn),ui.name="DFG_LUT",ui.minFilter=At,ui.magFilter=At,ui.wrapS=wn,ui.wrapT=wn,ui.generateMipmaps=!1,ui.needsUpdate=!0),ui}class HS{constructor(e={}){const{canvas:t=fy(),context:n=null,depth:i=!0,stencil:s=!1,alpha:r=!1,antialias:o=!1,premultipliedAlpha:l=!0,preserveDrawingBuffer:c=!1,powerPreference:h="default",failIfMajorPerformanceCaveat:d=!1,reversedDepthBuffer:u=!1,outputBufferType:f=Bn}=e;this.isWebGLRenderer=!0;let p;if(n!==null){if(typeof WebGLRenderingContext<"u"&&n instanceof WebGLRenderingContext)throw new Error("THREE.WebGLRenderer: WebGL 1 is not supported since r163.");p=n.getContextAttributes().alpha}else p=r;const v=f,m=new Set([Su,Mu,wu]),g=new Set([Bn,ri,jr,Qr,bu,xu]),_=new Uint32Array(4),M=new Int32Array(4),x=new P;let w=null,E=null;const D=[],y=[];let T=null;this.domElement=t,this.debug={checkShaderErrors:!0,onShaderError:null},this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.clippingPlanes=[],this.localClippingEnabled=!1,this.toneMapping=Ii,this.toneMappingExposure=1,this.transmissionResolutionScale=1;const A=this;let I=!1,R=null,N=null,z=null,L=null;this._outputColorSpace=Fn;let B=0,F=0,V=null,j=-1,$=null;const ne=new pt,re=new pt;let He=null;const Ze=new le(0);let ze=0,K=t.width,ae=t.height,ie=1,G=null,_e=null;const Pe=new pt(0,0,K,ae),Ae=new pt(0,0,K,ae);let be=!1;const Ne=new Ru;let Oe=!1,ke=!1;const rt=new qe,ot=new P,Pt=new pt,wt={background:null,fog:null,environment:null,overrideMaterial:null,isScene:!0};let Lt=!1;function Wt(){return V===null?ie:1}let k=n;function _n(S,U){return t.getContext(S,U)}try{const S={alpha:!0,depth:i,stencil:s,antialias:o,premultipliedAlpha:l,preserveDrawingBuffer:c,powerPreference:h,failIfMajorPerformanceCaveat:d};if("setAttribute"in t&&t.setAttribute("data-engine",`three.js r${gu}`),t.addEventListener("webglcontextlost",Nt,!1),t.addEventListener("webglcontextrestored",yt,!1),t.addEventListener("webglcontextcreationerror",li,!1),k===null){const U="webgl2";if(k=_n(U,S),k===null)throw _n(U)?new Error("THREE.WebGLRenderer: Error creating WebGL context with your selected attributes."):new Error("THREE.WebGLRenderer: Error creating WebGL context.")}}catch(S){throw Ue("WebGLRenderer: "+S.message),S}let lt,C,b,H,q,Z,se,ce,J,ee,he,Ie,fe,de,Le,Fe,Ge,O,oe,Q,ue,ve,te;function Te(){lt=new zM(k),lt.init(),ue=new RS(k,lt),C=new PM(k,lt,e,ue),b=new DS(k,lt),C.reversedDepthBuffer&&u&&b.buffers.depth.setReversed(!0),N=k.createFramebuffer(),z=k.createFramebuffer(),L=k.createFramebuffer(),H=new VM(k),q=new mS,Z=new CS(k,lt,b,q,C,ue,H),se=new BM(A),ce=new Yb(k),ve=new CM(k,ce),J=new HM(k,ce,H,ve),ee=new XM(k,J,ce,ve,H),O=new WM(k,C,Z),Le=new LM(q),he=new pS(A,se,lt,C,ve,Le),Ie=new FS(A,q),fe=new vS,de=new SS(lt),Ge=new DM(A,se,b,ee,p,l),Fe=new IS(A,ee,C),te=new US(k,H,C,b),oe=new RM(k,lt,H),Q=new GM(k,lt,H),H.programs=he.programs,A.capabilities=C,A.extensions=lt,A.properties=q,A.renderLists=fe,A.shadowMap=Fe,A.state=b,A.info=H}Te(),v!==Bn&&(T=new YM(v,t.width,t.height,o,i,s));const we=new OS(A,k);this.xr=we,this.getContext=function(){return k},this.getContextAttributes=function(){return k.getContextAttributes()},this.forceContextLoss=function(){const S=lt.get("WEBGL_lose_context");S&&S.loseContext()},this.forceContextRestore=function(){const S=lt.get("WEBGL_lose_context");S&&S.restoreContext()},this.getPixelRatio=function(){return ie},this.setPixelRatio=function(S){S!==void 0&&(ie=S,this.setSize(K,ae,!1))},this.getSize=function(S){return S.set(K,ae)},this.setSize=function(S,U,Y=!0){if(we.isPresenting){Ee("WebGLRenderer: Can't change size while VR device is presenting.");return}K=S,ae=U,t.width=Math.floor(S*ie),t.height=Math.floor(U*ie),Y===!0&&(t.style.width=S+"px",t.style.height=U+"px"),T!==null&&T.setSize(t.width,t.height),this.setViewport(0,0,S,U)},this.getDrawingBufferSize=function(S){return S.set(K*ie,ae*ie).floor()},this.setDrawingBufferSize=function(S,U,Y){K=S,ae=U,ie=Y,t.width=Math.floor(S*Y),t.height=Math.floor(U*Y),this.setViewport(0,0,S,U)},this.setEffects=function(S){if(v===Bn){Ue("WebGLRenderer: setEffects() requires outputBufferType set to HalfFloatType or FloatType.");return}if(S){for(let U=0;U<S.length;U++)if(S[U].isOutputPass===!0){Ee("WebGLRenderer: OutputPass is not needed in setEffects(). Tone mapping and color space conversion are applied automatically.");break}}T.setEffects(S||[])},this.getCurrentViewport=function(S){return S.copy(ne)},this.getViewport=function(S){return S.copy(Pe)},this.setViewport=function(S,U,Y,W){S.isVector4?Pe.set(S.x,S.y,S.z,S.w):Pe.set(S,U,Y,W),b.viewport(ne.copy(Pe).multiplyScalar(ie).round())},this.getScissor=function(S){return S.copy(Ae)},this.setScissor=function(S,U,Y,W){S.isVector4?Ae.set(S.x,S.y,S.z,S.w):Ae.set(S,U,Y,W),b.scissor(re.copy(Ae).multiplyScalar(ie).round())},this.getScissorTest=function(){return be},this.setScissorTest=function(S){b.setScissorTest(be=S)},this.setOpaqueSort=function(S){G=S},this.setTransparentSort=function(S){_e=S},this.getClearColor=function(S){return S.copy(Ge.getClearColor())},this.setClearColor=function(){Ge.setClearColor(...arguments)},this.getClearAlpha=function(){return Ge.getClearAlpha()},this.setClearAlpha=function(){Ge.setClearAlpha(...arguments)},this.clear=function(S=!0,U=!0,Y=!0){let W=0;if(S){let X=!1;if(V!==null){const ge=V.texture.format;X=m.has(ge)}if(X){const ge=V.texture.type,xe=g.has(ge),me=Ge.getClearColor(),Se=Ge.getClearAlpha(),De=me.r,Ve=me.g,Ye=me.b;xe?(_[0]=De,_[1]=Ve,_[2]=Ye,_[3]=Se,k.clearBufferuiv(k.COLOR,0,_)):(M[0]=De,M[1]=Ve,M[2]=Ye,M[3]=Se,k.clearBufferiv(k.COLOR,0,M))}else W|=k.COLOR_BUFFER_BIT}U&&(W|=k.DEPTH_BUFFER_BIT,this.state.buffers.depth.setMask(!0)),Y&&(W|=k.STENCIL_BUFFER_BIT,this.state.buffers.stencil.setMask(4294967295)),W!==0&&k.clear(W)},this.clearColor=function(){this.clear(!0,!1,!1)},this.clearDepth=function(){this.clear(!1,!0,!1)},this.clearStencil=function(){this.clear(!1,!1,!0)},this.setNodesHandler=function(S){S.setRenderer(this),R=S},this.dispose=function(){t.removeEventListener("webglcontextlost",Nt,!1),t.removeEventListener("webglcontextrestored",yt,!1),t.removeEventListener("webglcontextcreationerror",li,!1),Ge.dispose(),fe.dispose(),de.dispose(),q.dispose(),se.dispose(),ee.dispose(),ve.dispose(),te.dispose(),he.dispose(),we.dispose(),we.removeEventListener("sessionstart",Ku),we.removeEventListener("sessionend",$u),Es.stop()};function Nt(S){S.preventDefault(),Bl("WebGLRenderer: Context Lost."),I=!0}function yt(){Bl("WebGLRenderer: Context Restored."),I=!1;const S=H.autoReset,U=Fe.enabled,Y=Fe.autoUpdate,W=Fe.needsUpdate,X=Fe.type;Te(),H.autoReset=S,Fe.enabled=U,Fe.autoUpdate=Y,Fe.needsUpdate=W,Fe.type=X}function li(S){Ue("WebGLRenderer: A WebGL context could not be created. Reason: ",S.statusMessage)}function ci(S){const U=S.target;U.removeEventListener("dispose",ci),ov(U)}function ov(S){lv(S),q.remove(S)}function lv(S){const U=q.get(S).programs;U!==void 0&&(U.forEach(function(Y){he.releaseProgram(Y)}),S.isShaderMaterial&&he.releaseShaderCache(S))}this.renderBufferDirect=function(S,U,Y,W,X,ge){U===null&&(U=wt);const xe=X.isMesh&&X.matrixWorld.determinantAffine()<0,me=dv(S,U,Y,W,X);b.setMaterial(W,xe);let Se=Y.index,De=1;if(W.wireframe===!0){if(Se=J.getWireframeAttribute(Y),Se===void 0)return;De=2}const Ve=Y.drawRange,Ye=Y.attributes.position;let Ce=Ve.start*De,ut=(Ve.start+Ve.count)*De;ge!==null&&(Ce=Math.max(Ce,ge.start*De),ut=Math.min(ut,(ge.start+ge.count)*De)),Se!==null?(Ce=Math.max(Ce,0),ut=Math.min(ut,Se.count)):Ye!=null&&(Ce=Math.max(Ce,0),ut=Math.min(ut,Ye.count));const Ft=ut-Ce;if(Ft<0||Ft===1/0)return;ve.setup(X,W,me,Y,Se);let Ot,mt=oe;if(Se!==null&&(Ot=ce.get(Se),mt=Q,mt.setIndex(Ot)),X.isMesh)W.wireframe===!0?(b.setLineWidth(W.wireframeLinewidth*Wt()),mt.setMode(k.LINES)):mt.setMode(k.TRIANGLES);else if(X.isLine){let on=W.linewidth;on===void 0&&(on=1),b.setLineWidth(on*Wt()),X.isLineSegments?mt.setMode(k.LINES):X.isLineLoop?mt.setMode(k.LINE_LOOP):mt.setMode(k.LINE_STRIP)}else X.isPoints?mt.setMode(k.POINTS):X.isSprite&&mt.setMode(k.TRIANGLES);if(X.isBatchedMesh)if(lt.get("WEBGL_multi_draw"))mt.renderMultiDraw(X._multiDrawStarts,X._multiDrawCounts,X._multiDrawCount);else{const on=X._multiDrawStarts,ye=X._multiDrawCounts,Dn=X._multiDrawCount,tt=Se?ce.get(Se).bytesPerElement:1,zn=q.get(W).currentProgram.getUniforms();for(let hi=0;hi<Dn;hi++)zn.setValue(k,"_gl_DrawID",hi),mt.render(on[hi]/tt,ye[hi])}else if(X.isInstancedMesh)mt.renderInstances(Ce,Ft,X.count);else if(Y.isInstancedBufferGeometry){const on=Y._maxInstanceCount!==void 0?Y._maxInstanceCount:1/0,ye=Math.min(Y.instanceCount,on);mt.renderInstances(Ce,Ft,ye)}else mt.render(Ce,Ft)};function Yu(S,U,Y){S.transparent===!0&&S.side===Qn&&S.forceSinglePass===!1?(S.side=Vt,S.needsUpdate=!0,fo(S,U,Y),S.side=Ms,S.needsUpdate=!0,fo(S,U,Y),S.side=Qn):fo(S,U,Y)}this.compile=function(S,U,Y=null){Y===null&&(Y=S),E=de.get(Y),E.init(U),y.push(E),Y.traverseVisible(function(X){X.isLight&&X.layers.test(U.layers)&&(E.pushLight(X),X.castShadow&&E.pushShadow(X))}),S!==Y&&S.traverseVisible(function(X){X.isLight&&X.layers.test(U.layers)&&(E.pushLight(X),X.castShadow&&E.pushShadow(X))}),E.setupLights();const W=new Set;return S.traverse(function(X){if(!(X.isMesh||X.isPoints||X.isLine||X.isSprite))return;const ge=X.material;if(ge)if(Array.isArray(ge))for(let xe=0;xe<ge.length;xe++){const me=ge[xe];Yu(me,Y,X),W.add(me)}else Yu(ge,Y,X),W.add(ge)}),E=y.pop(),W},this.compileAsync=function(S,U,Y=null){const W=this.compile(S,U,Y);return new Promise(X=>{function ge(){if(W.forEach(function(xe){q.get(xe).currentProgram.isReady()&&W.delete(xe)}),W.size===0){X(S);return}setTimeout(ge,10)}lt.get("KHR_parallel_shader_compile")!==null?ge():setTimeout(ge,10)})};let cc=null;function cv(S){cc&&cc(S)}function Ku(){Es.stop()}function $u(){Es.start()}const Es=new ug;Es.setAnimationLoop(cv),typeof self<"u"&&Es.setContext(self),this.setAnimationLoop=function(S){cc=S,we.setAnimationLoop(S),S===null?Es.stop():Es.start()},we.addEventListener("sessionstart",Ku),we.addEventListener("sessionend",$u),this.render=function(S,U){if(U!==void 0&&U.isCamera!==!0){Ue("WebGLRenderer.render: camera is not an instance of THREE.Camera.");return}if(I===!0)return;R!==null&&R.renderStart(S,U);const Y=we.enabled===!0&&we.isPresenting===!0,W=T!==null&&(V===null||Y)&&T.begin(A,V);if(S.matrixWorldAutoUpdate===!0&&S.updateMatrixWorld(),U.parent===null&&U.matrixWorldAutoUpdate===!0&&U.updateMatrixWorld(),we.enabled===!0&&we.isPresenting===!0&&(T===null||T.isCompositing()===!1)&&(we.cameraAutoUpdate===!0&&we.updateCamera(U),U=we.getCamera()),S.isScene===!0&&S.onBeforeRender(A,S,U,V),E=de.get(S,y.length),E.init(U),E.state.textureUnits=Z.getTextureUnits(),y.push(E),rt.multiplyMatrices(U.projectionMatrix,U.matrixWorldInverse),Ne.setFromProjectionMatrix(rt,Ei,U.reversedDepth),ke=this.localClippingEnabled,Oe=Le.init(this.clippingPlanes,ke),w=fe.get(S,D.length),w.init(),D.push(w),we.enabled===!0&&we.isPresenting===!0){const xe=A.xr.getDepthSensingMesh();xe!==null&&hc(xe,U,-1/0,A.sortObjects)}hc(S,U,0,A.sortObjects),w.finish(),A.sortObjects===!0&&w.sort(G,_e,U.reversedDepth),Lt=we.enabled===!1||we.isPresenting===!1||we.hasDepthSensing()===!1,Lt&&Ge.addToRenderList(w,S),this.info.render.frame++,this.info.autoReset===!0&&this.info.reset(),Oe===!0&&Le.beginShadows();const X=E.state.shadowsArray;if(Fe.render(X,S,U),Oe===!0&&Le.endShadows(),(W&&T.hasRenderPass())===!1){const xe=w.opaque,me=w.transmissive;if(E.setupLights(),U.isArrayCamera){const Se=U.cameras;if(me.length>0)for(let De=0,Ve=Se.length;De<Ve;De++){const Ye=Se[De];Ju(xe,me,S,Ye)}Lt&&Ge.render(S);for(let De=0,Ve=Se.length;De<Ve;De++){const Ye=Se[De];Zu(w,S,Ye,Ye.viewport)}}else me.length>0&&Ju(xe,me,S,U),Lt&&Ge.render(S),Zu(w,S,U)}V!==null&&F===0&&(Z.updateMultisampleRenderTarget(V),Z.updateRenderTargetMipmap(V)),W&&T.end(A),S.isScene===!0&&S.onAfterRender(A,S,U),ve.resetDefaultState(),j=-1,$=null,y.pop(),y.length>0?(E=y[y.length-1],Z.setTextureUnits(E.state.textureUnits),Oe===!0&&Le.setGlobalState(A.clippingPlanes,E.state.camera)):E=null,D.pop(),D.length>0?w=D[D.length-1]:w=null,R!==null&&R.renderEnd()};function hc(S,U,Y,W){if(S.visible===!1)return;if(S.layers.test(U.layers)){if(S.isGroup)Y=S.renderOrder;else if(S.isLOD)S.autoUpdate===!0&&S.update(U);else if(S.isLightProbeGrid)E.pushLightProbeGrid(S);else if(S.isLight)E.pushLight(S),S.castShadow&&E.pushShadow(S);else if(S.isSprite){if(!S.frustumCulled||Ne.intersectsSprite(S)){W&&Pt.setFromMatrixPosition(S.matrixWorld).applyMatrix4(rt);const xe=ee.update(S),me=S.material;me.visible&&w.push(S,xe,me,Y,Pt.z,null)}}else if((S.isMesh||S.isLine||S.isPoints)&&(!S.frustumCulled||Ne.intersectsObject(S))){const xe=ee.update(S),me=S.material;if(W&&(S.boundingSphere!==void 0?(S.boundingSphere===null&&S.computeBoundingSphere(),Pt.copy(S.boundingSphere.center)):(xe.boundingSphere===null&&xe.computeBoundingSphere(),Pt.copy(xe.boundingSphere.center)),Pt.applyMatrix4(S.matrixWorld).applyMatrix4(rt)),Array.isArray(me)){const Se=xe.groups;for(let De=0,Ve=Se.length;De<Ve;De++){const Ye=Se[De],Ce=me[Ye.materialIndex];Ce&&Ce.visible&&w.push(S,xe,Ce,Y,Pt.z,Ye)}}else me.visible&&w.push(S,xe,me,Y,Pt.z,null)}}const ge=S.children;for(let xe=0,me=ge.length;xe<me;xe++)hc(ge[xe],U,Y,W)}function Zu(S,U,Y,W){const{opaque:X,transmissive:ge,transparent:xe}=S;E.setupLightsView(Y),Oe===!0&&Le.setGlobalState(A.clippingPlanes,Y),W&&b.viewport(ne.copy(W)),X.length>0&&uo(X,U,Y),ge.length>0&&uo(ge,U,Y),xe.length>0&&uo(xe,U,Y),b.buffers.depth.setTest(!0),b.buffers.depth.setMask(!0),b.buffers.color.setMask(!0),b.setPolygonOffset(!1)}function Ju(S,U,Y,W){if((Y.isScene===!0?Y.overrideMaterial:null)!==null)return;if(E.state.transmissionRenderTarget[W.id]===void 0){const Ce=lt.has("EXT_color_buffer_half_float")||lt.has("EXT_color_buffer_float");E.state.transmissionRenderTarget[W.id]=new In(1,1,{generateMipmaps:!0,type:Ce?pn:Bn,minFilter:Vs,samples:Math.max(4,C.samples),stencilBuffer:s,resolveDepthBuffer:!1,resolveStencilBuffer:!1,colorSpace:Qe.workingColorSpace})}const ge=E.state.transmissionRenderTarget[W.id],xe=W.viewport||ne;ge.setSize(xe.z*A.transmissionResolutionScale,xe.w*A.transmissionResolutionScale);const me=A.getRenderTarget(),Se=A.getActiveCubeFace(),De=A.getActiveMipmapLevel();A.setRenderTarget(ge),A.getClearColor(Ze),ze=A.getClearAlpha(),ze<1&&A.setClearColor(16777215,.5),A.clear(),Lt&&Ge.render(Y);const Ve=A.toneMapping;A.toneMapping=Ii;const Ye=W.viewport;if(W.viewport!==void 0&&(W.viewport=void 0),E.setupLightsView(W),Oe===!0&&Le.setGlobalState(A.clippingPlanes,W),uo(S,Y,W),Z.updateMultisampleRenderTarget(ge),Z.updateRenderTargetMipmap(ge),lt.has("WEBGL_multisampled_render_to_texture")===!1){let Ce=!1;for(let ut=0,Ft=U.length;ut<Ft;ut++){const Ot=U[ut],{object:mt,geometry:on,material:ye,group:Dn}=Ot;if(ye.side===Qn&&mt.layers.test(W.layers)){const tt=ye.side;ye.side=Vt,ye.needsUpdate=!0,ju(mt,Y,W,on,ye,Dn),ye.side=tt,ye.needsUpdate=!0,Ce=!0}}Ce===!0&&(Z.updateMultisampleRenderTarget(ge),Z.updateRenderTargetMipmap(ge))}A.setRenderTarget(me,Se,De),A.setClearColor(Ze,ze),Ye!==void 0&&(W.viewport=Ye),A.toneMapping=Ve}function uo(S,U,Y){const W=U.isScene===!0?U.overrideMaterial:null;for(let X=0,ge=S.length;X<ge;X++){const xe=S[X],{object:me,geometry:Se,group:De}=xe;let Ve=xe.material;Ve.allowOverride===!0&&W!==null&&(Ve=W),me.layers.test(Y.layers)&&ju(me,U,Y,Se,Ve,De)}}function ju(S,U,Y,W,X,ge){S.onBeforeRender(A,U,Y,W,X,ge),S.modelViewMatrix.multiplyMatrices(Y.matrixWorldInverse,S.matrixWorld),S.normalMatrix.getNormalMatrix(S.modelViewMatrix),X.onBeforeRender(A,U,Y,W,S,ge),X.transparent===!0&&X.side===Qn&&X.forceSinglePass===!1?(X.side=Vt,X.needsUpdate=!0,A.renderBufferDirect(Y,U,W,X,S,ge),X.side=Ms,X.needsUpdate=!0,A.renderBufferDirect(Y,U,W,X,S,ge),X.side=Qn):A.renderBufferDirect(Y,U,W,X,S,ge),S.onAfterRender(A,U,Y,W,X,ge)}function fo(S,U,Y){U.isScene!==!0&&(U=wt);const W=q.get(S),X=E.state.lights,ge=E.state.shadowsArray,xe=X.state.version,me=he.getParameters(S,X.state,ge,U,Y,E.state.lightProbeGridArray),Se=he.getProgramCacheKey(me);let De=W.programs;W.environment=S.isMeshStandardMaterial||S.isMeshLambertMaterial||S.isMeshPhongMaterial?U.environment:null,W.fog=U.fog;const Ve=S.isMeshStandardMaterial||S.isMeshLambertMaterial&&!S.envMap||S.isMeshPhongMaterial&&!S.envMap;W.envMap=se.get(S.envMap||W.environment,Ve),W.envMapRotation=W.environment!==null&&S.envMap===null?U.environmentRotation:S.envMapRotation,De===void 0&&(S.addEventListener("dispose",ci),De=new Map,W.programs=De);let Ye=De.get(Se);if(Ye!==void 0){if(W.currentProgram===Ye&&W.lightsStateVersion===xe)return ef(S,me),Ye}else me.uniforms=he.getUniforms(S),R!==null&&S.isNodeMaterial&&R.build(S,Y,me),S.onBeforeCompile(me,A),Ye=he.acquireProgram(me,Se),De.set(Se,Ye),W.uniforms=me.uniforms;const Ce=W.uniforms;return(!S.isShaderMaterial&&!S.isRawShaderMaterial||S.clipping===!0)&&(Ce.clippingPlanes=Le.uniform),ef(S,me),W.needsLights=fv(S),W.lightsStateVersion=xe,W.needsLights&&(Ce.ambientLightColor.value=X.state.ambient,Ce.lightProbe.value=X.state.probe,Ce.directionalLights.value=X.state.directional,Ce.directionalLightShadows.value=X.state.directionalShadow,Ce.spotLights.value=X.state.spot,Ce.spotLightShadows.value=X.state.spotShadow,Ce.rectAreaLights.value=X.state.rectArea,Ce.ltc_1.value=X.state.rectAreaLTC1,Ce.ltc_2.value=X.state.rectAreaLTC2,Ce.pointLights.value=X.state.point,Ce.pointLightShadows.value=X.state.pointShadow,Ce.hemisphereLights.value=X.state.hemi,Ce.directionalShadowMatrix.value=X.state.directionalShadowMatrix,Ce.spotLightMatrix.value=X.state.spotLightMatrix,Ce.spotLightMap.value=X.state.spotLightMap,Ce.pointShadowMatrix.value=X.state.pointShadowMatrix),W.lightProbeGrid=E.state.lightProbeGridArray.length>0,W.currentProgram=Ye,W.uniformsList=null,Ye}function Qu(S){if(S.uniformsList===null){const U=S.currentProgram.getUniforms();S.uniformsList=Ml.seqWithValue(U.seq,S.uniforms)}return S.uniformsList}function ef(S,U){const Y=q.get(S);Y.outputColorSpace=U.outputColorSpace,Y.batching=U.batching,Y.batchingColor=U.batchingColor,Y.instancing=U.instancing,Y.instancingColor=U.instancingColor,Y.instancingMorph=U.instancingMorph,Y.skinning=U.skinning,Y.morphTargets=U.morphTargets,Y.morphNormals=U.morphNormals,Y.morphColors=U.morphColors,Y.morphTargetsCount=U.morphTargetsCount,Y.numClippingPlanes=U.numClippingPlanes,Y.numIntersection=U.numClipIntersection,Y.vertexAlphas=U.vertexAlphas,Y.vertexTangents=U.vertexTangents,Y.toneMapping=U.toneMapping}function hv(S,U){if(S.length===0)return null;if(S.length===1)return S[0].texture!==null?S[0]:null;x.setFromMatrixPosition(U.matrixWorld);for(let Y=0,W=S.length;Y<W;Y++){const X=S[Y];if(X.texture!==null&&X.boundingBox.containsPoint(x))return X}return null}function dv(S,U,Y,W,X){U.isScene!==!0&&(U=wt),Z.resetTextureUnits();const ge=U.fog,xe=W.isMeshStandardMaterial||W.isMeshLambertMaterial||W.isMeshPhongMaterial?U.environment:null,me=V===null?A.outputColorSpace:V.isXRRenderTarget===!0?V.texture.colorSpace:Qe.workingColorSpace,Se=W.isMeshStandardMaterial||W.isMeshLambertMaterial&&!W.envMap||W.isMeshPhongMaterial&&!W.envMap,De=se.get(W.envMap||xe,Se),Ve=W.vertexColors===!0&&!!Y.attributes.color&&Y.attributes.color.itemSize===4,Ye=!!Y.attributes.tangent&&(!!W.normalMap||W.anisotropy>0),Ce=!!Y.morphAttributes.position,ut=!!Y.morphAttributes.normal,Ft=!!Y.morphAttributes.color;let Ot=Ii;W.toneMapped&&(V===null||V.isXRRenderTarget===!0)&&(Ot=A.toneMapping);const mt=Y.morphAttributes.position||Y.morphAttributes.normal||Y.morphAttributes.color,on=mt!==void 0?mt.length:0,ye=q.get(W),Dn=E.state.lights;if(Oe===!0&&(ke===!0||S!==$)){const bt=S===$&&W.id===j;Le.setState(W,S,bt)}let tt=!1;W.version===ye.__version?(ye.needsLights&&ye.lightsStateVersion!==Dn.state.version||ye.outputColorSpace!==me||X.isBatchedMesh&&ye.batching===!1||!X.isBatchedMesh&&ye.batching===!0||X.isBatchedMesh&&ye.batchingColor===!0&&X.colorTexture===null||X.isBatchedMesh&&ye.batchingColor===!1&&X.colorTexture!==null||X.isInstancedMesh&&ye.instancing===!1||!X.isInstancedMesh&&ye.instancing===!0||X.isSkinnedMesh&&ye.skinning===!1||!X.isSkinnedMesh&&ye.skinning===!0||X.isInstancedMesh&&ye.instancingColor===!0&&X.instanceColor===null||X.isInstancedMesh&&ye.instancingColor===!1&&X.instanceColor!==null||X.isInstancedMesh&&ye.instancingMorph===!0&&X.morphTexture===null||X.isInstancedMesh&&ye.instancingMorph===!1&&X.morphTexture!==null||ye.envMap!==De||W.fog===!0&&ye.fog!==ge||ye.numClippingPlanes!==void 0&&(ye.numClippingPlanes!==Le.numPlanes||ye.numIntersection!==Le.numIntersection)||ye.vertexAlphas!==Ve||ye.vertexTangents!==Ye||ye.morphTargets!==Ce||ye.morphNormals!==ut||ye.morphColors!==Ft||ye.toneMapping!==Ot||ye.morphTargetsCount!==on||!!ye.lightProbeGrid!=E.state.lightProbeGridArray.length>0)&&(tt=!0):(tt=!0,ye.__version=W.version);let zn=ye.currentProgram;tt===!0&&(zn=fo(W,U,X),R&&W.isNodeMaterial&&R.onUpdateProgram(W,zn,ye));let hi=!1,ts=!1,ea=!1;const gt=zn.getUniforms(),Ut=ye.uniforms;if(b.useProgram(zn.program)&&(hi=!0,ts=!0,ea=!0),W.id!==j&&(j=W.id,ts=!0),ye.needsLights){const bt=hv(E.state.lightProbeGridArray,X);ye.lightProbeGrid!==bt&&(ye.lightProbeGrid=bt,ts=!0)}if(hi||$!==S){b.buffers.depth.getReversed()&&S.reversedDepth!==!0&&(S._reversedDepth=!0,S.updateProjectionMatrix()),gt.setValue(k,"projectionMatrix",S.projectionMatrix),gt.setValue(k,"viewMatrix",S.matrixWorldInverse);const is=gt.map.cameraPosition;is!==void 0&&is.setValue(k,ot.setFromMatrixPosition(S.matrixWorld)),C.logarithmicDepthBuffer&>.setValue(k,"logDepthBufFC",2/(Math.log(S.far+1)/Math.LN2)),(W.isMeshPhongMaterial||W.isMeshToonMaterial||W.isMeshLambertMaterial||W.isMeshBasicMaterial||W.isMeshStandardMaterial||W.isShaderMaterial)&>.setValue(k,"isOrthographic",S.isOrthographicCamera===!0),$!==S&&($=S,ts=!0,ea=!0)}if(ye.needsLights&&(Dn.state.directionalShadowMap.length>0&>.setValue(k,"directionalShadowMap",Dn.state.directionalShadowMap,Z),Dn.state.spotShadowMap.length>0&>.setValue(k,"spotShadowMap",Dn.state.spotShadowMap,Z),Dn.state.pointShadowMap.length>0&>.setValue(k,"pointShadowMap",Dn.state.pointShadowMap,Z)),X.isSkinnedMesh){gt.setOptional(k,X,"bindMatrix"),gt.setOptional(k,X,"bindMatrixInverse");const bt=X.skeleton;bt&&(bt.boneTexture===null&&bt.computeBoneTexture(),gt.setValue(k,"boneTexture",bt.boneTexture,Z))}X.isBatchedMesh&&(gt.setOptional(k,X,"batchingTexture"),gt.setValue(k,"batchingTexture",X._matricesTexture,Z),gt.setOptional(k,X,"batchingIdTexture"),gt.setValue(k,"batchingIdTexture",X._indirectTexture,Z),gt.setOptional(k,X,"batchingColorTexture"),X._colorsTexture!==null&>.setValue(k,"batchingColorTexture",X._colorsTexture,Z));const ns=Y.morphAttributes;if((ns.position!==void 0||ns.normal!==void 0||ns.color!==void 0)&&O.update(X,Y,zn),(ts||ye.receiveShadow!==X.receiveShadow)&&(ye.receiveShadow=X.receiveShadow,gt.setValue(k,"receiveShadow",X.receiveShadow)),(W.isMeshStandardMaterial||W.isMeshLambertMaterial||W.isMeshPhongMaterial)&&W.envMap===null&&U.environment!==null&&(Ut.envMapIntensity.value=U.environmentIntensity),Ut.dfgLUT!==void 0&&(Ut.dfgLUT.value=zS()),ts){if(gt.setValue(k,"toneMappingExposure",A.toneMappingExposure),ye.needsLights&&uv(Ut,ea),ge&&W.fog===!0&&Ie.refreshFogUniforms(Ut,ge),Ie.refreshMaterialUniforms(Ut,W,ie,ae,E.state.transmissionRenderTarget[S.id]),ye.needsLights&&ye.lightProbeGrid){const bt=ye.lightProbeGrid;Ut.probesSH.value=bt.texture,Ut.probesMin.value.copy(bt.boundingBox.min),Ut.probesMax.value.copy(bt.boundingBox.max),Ut.probesResolution.value.copy(bt.resolution)}Ml.upload(k,Qu(ye),Ut,Z)}if(W.isShaderMaterial&&W.uniformsNeedUpdate===!0&&(Ml.upload(k,Qu(ye),Ut,Z),W.uniformsNeedUpdate=!1),W.isSpriteMaterial&>.setValue(k,"center",X.center),gt.setValue(k,"modelViewMatrix",X.modelViewMatrix),gt.setValue(k,"normalMatrix",X.normalMatrix),gt.setValue(k,"modelMatrix",X.matrixWorld),W.uniformsGroups!==void 0){const bt=W.uniformsGroups;for(let is=0,ta=bt.length;is<ta;is++){const tf=bt[is];te.update(tf,zn),te.bind(tf,zn)}}return zn}function uv(S,U){S.ambientLightColor.needsUpdate=U,S.lightProbe.needsUpdate=U,S.directionalLights.needsUpdate=U,S.directionalLightShadows.needsUpdate=U,S.pointLights.needsUpdate=U,S.pointLightShadows.needsUpdate=U,S.spotLights.needsUpdate=U,S.spotLightShadows.needsUpdate=U,S.rectAreaLights.needsUpdate=U,S.hemisphereLights.needsUpdate=U}function fv(S){return S.isMeshLambertMaterial||S.isMeshToonMaterial||S.isMeshPhongMaterial||S.isMeshStandardMaterial||S.isShadowMaterial||S.isShaderMaterial&&S.lights===!0}this.getActiveCubeFace=function(){return B},this.getActiveMipmapLevel=function(){return F},this.getRenderTarget=function(){return V},this.setRenderTargetTextures=function(S,U,Y){const W=q.get(S);W.__autoAllocateDepthBuffer=S.resolveDepthBuffer===!1,W.__autoAllocateDepthBuffer===!1&&(W.__useRenderToTexture=!1),q.get(S.texture).__webglTexture=U,q.get(S.depthTexture).__webglTexture=W.__autoAllocateDepthBuffer?void 0:Y,W.__hasExternalTextures=!0},this.setRenderTargetFramebuffer=function(S,U){const Y=q.get(S);Y.__webglFramebuffer=U,Y.__useDefaultFramebuffer=U===void 0},this.setRenderTarget=function(S,U=0,Y=0){V=S,B=U,F=Y;let W=null,X=!1,ge=!1;if(S){const me=q.get(S);if(me.__useDefaultFramebuffer!==void 0){b.bindFramebuffer(k.FRAMEBUFFER,me.__webglFramebuffer),ne.copy(S.viewport),re.copy(S.scissor),He=S.scissorTest,b.viewport(ne),b.scissor(re),b.setScissorTest(He),j=-1;return}else if(me.__webglFramebuffer===void 0)Z.setupRenderTarget(S);else if(me.__hasExternalTextures)Z.rebindTextures(S,q.get(S.texture).__webglTexture,q.get(S.depthTexture).__webglTexture);else if(S.depthBuffer){const Ve=S.depthTexture;if(me.__boundDepthTexture!==Ve){if(Ve!==null&&q.has(Ve)&&(S.width!==Ve.image.width||S.height!==Ve.image.height))throw new Error("THREE.WebGLRenderer: Attached DepthTexture is initialized to the incorrect size.");Z.setupDepthRenderbuffer(S)}}const Se=S.texture;(Se.isData3DTexture||Se.isDataArrayTexture||Se.isCompressedArrayTexture)&&(ge=!0);const De=q.get(S).__webglFramebuffer;S.isWebGLCubeRenderTarget?(Array.isArray(De[U])?W=De[U][Y]:W=De[U],X=!0):S.samples>0&&Z.useMultisampledRTT(S)===!1?W=q.get(S).__webglMultisampledFramebuffer:Array.isArray(De)?W=De[Y]:W=De,ne.copy(S.viewport),re.copy(S.scissor),He=S.scissorTest}else ne.copy(Pe).multiplyScalar(ie).floor(),re.copy(Ae).multiplyScalar(ie).floor(),He=be;if(Y!==0&&(W=N),b.bindFramebuffer(k.FRAMEBUFFER,W)&&b.drawBuffers(S,W),b.viewport(ne),b.scissor(re),b.setScissorTest(He),X){const me=q.get(S.texture);k.framebufferTexture2D(k.FRAMEBUFFER,k.COLOR_ATTACHMENT0,k.TEXTURE_CUBE_MAP_POSITIVE_X+U,me.__webglTexture,Y)}else if(ge){const me=U;for(let Se=0;Se<S.textures.length;Se++){const De=q.get(S.textures[Se]);k.framebufferTextureLayer(k.FRAMEBUFFER,k.COLOR_ATTACHMENT0+Se,De.__webglTexture,Y,me)}}else if(S!==null&&Y!==0){const me=q.get(S.texture);k.framebufferTexture2D(k.FRAMEBUFFER,k.COLOR_ATTACHMENT0,k.TEXTURE_2D,me.__webglTexture,Y)}j=-1},this.readRenderTargetPixels=function(S,U,Y,W,X,ge,xe,me=0){if(!(S&&S.isWebGLRenderTarget)){Ue("WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");return}let Se=q.get(S).__webglFramebuffer;if(S.isWebGLCubeRenderTarget&&xe!==void 0&&(Se=Se[xe]),Se){b.bindFramebuffer(k.FRAMEBUFFER,Se);try{const De=S.textures[me],Ve=De.format,Ye=De.type;if(S.textures.length>1&&k.readBuffer(k.COLOR_ATTACHMENT0+me),!C.textureFormatReadable(Ve)){Ue("WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.");return}if(!C.textureTypeReadable(Ye)){Ue("WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.");return}U>=0&&U<=S.width-W&&Y>=0&&Y<=S.height-X&&k.readPixels(U,Y,W,X,ue.convert(Ve),ue.convert(Ye),ge)}finally{const De=V!==null?q.get(V).__webglFramebuffer:null;b.bindFramebuffer(k.FRAMEBUFFER,De)}}},this.readRenderTargetPixelsAsync=async function(S,U,Y,W,X,ge,xe,me=0){if(!(S&&S.isWebGLRenderTarget))throw new Error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let Se=q.get(S).__webglFramebuffer;if(S.isWebGLCubeRenderTarget&&xe!==void 0&&(Se=Se[xe]),Se)if(U>=0&&U<=S.width-W&&Y>=0&&Y<=S.height-X){b.bindFramebuffer(k.FRAMEBUFFER,Se);const De=S.textures[me],Ve=De.format,Ye=De.type;if(S.textures.length>1&&k.readBuffer(k.COLOR_ATTACHMENT0+me),!C.textureFormatReadable(Ve))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.");if(!C.textureTypeReadable(Ye))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.");const Ce=k.createBuffer();k.bindBuffer(k.PIXEL_PACK_BUFFER,Ce),k.bufferData(k.PIXEL_PACK_BUFFER,ge.byteLength,k.STREAM_READ),k.readPixels(U,Y,W,X,ue.convert(Ve),ue.convert(Ye),0);const ut=V!==null?q.get(V).__webglFramebuffer:null;b.bindFramebuffer(k.FRAMEBUFFER,ut);const Ft=k.fenceSync(k.SYNC_GPU_COMMANDS_COMPLETE,0);return k.flush(),await py(k,Ft,4),k.bindBuffer(k.PIXEL_PACK_BUFFER,Ce),k.getBufferSubData(k.PIXEL_PACK_BUFFER,0,ge),k.deleteBuffer(Ce),k.deleteSync(Ft),ge}else throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.")},this.copyFramebufferToTexture=function(S,U=null,Y=0){const W=Math.pow(2,-Y),X=Math.floor(S.image.width*W),ge=Math.floor(S.image.height*W),xe=U!==null?U.x:0,me=U!==null?U.y:0;Z.setTexture2D(S,0),k.copyTexSubImage2D(k.TEXTURE_2D,Y,0,0,xe,me,X,ge),b.unbindTexture()},this.copyTextureToTexture=function(S,U,Y=null,W=null,X=0,ge=0){let xe,me,Se,De,Ve,Ye,Ce,ut,Ft;const Ot=S.isCompressedTexture?S.mipmaps[ge]:S.image;if(Y!==null)xe=Y.max.x-Y.min.x,me=Y.max.y-Y.min.y,Se=Y.isBox3?Y.max.z-Y.min.z:1,De=Y.min.x,Ve=Y.min.y,Ye=Y.isBox3?Y.min.z:0;else{const Ut=Math.pow(2,-X);xe=Math.floor(Ot.width*Ut),me=Math.floor(Ot.height*Ut),S.isDataArrayTexture?Se=Ot.depth:S.isData3DTexture?Se=Math.floor(Ot.depth*Ut):Se=1,De=0,Ve=0,Ye=0}W!==null?(Ce=W.x,ut=W.y,Ft=W.z):(Ce=0,ut=0,Ft=0);const mt=ue.convert(U.format),on=ue.convert(U.type);let ye;U.isData3DTexture?(Z.setTexture3D(U,0),ye=k.TEXTURE_3D):U.isDataArrayTexture||U.isCompressedArrayTexture?(Z.setTexture2DArray(U,0),ye=k.TEXTURE_2D_ARRAY):(Z.setTexture2D(U,0),ye=k.TEXTURE_2D),b.activeTexture(k.TEXTURE0),b.pixelStorei(k.UNPACK_FLIP_Y_WEBGL,U.flipY),b.pixelStorei(k.UNPACK_PREMULTIPLY_ALPHA_WEBGL,U.premultiplyAlpha),b.pixelStorei(k.UNPACK_ALIGNMENT,U.unpackAlignment);const Dn=b.getParameter(k.UNPACK_ROW_LENGTH),tt=b.getParameter(k.UNPACK_IMAGE_HEIGHT),zn=b.getParameter(k.UNPACK_SKIP_PIXELS),hi=b.getParameter(k.UNPACK_SKIP_ROWS),ts=b.getParameter(k.UNPACK_SKIP_IMAGES);b.pixelStorei(k.UNPACK_ROW_LENGTH,Ot.width),b.pixelStorei(k.UNPACK_IMAGE_HEIGHT,Ot.height),b.pixelStorei(k.UNPACK_SKIP_PIXELS,De),b.pixelStorei(k.UNPACK_SKIP_ROWS,Ve),b.pixelStorei(k.UNPACK_SKIP_IMAGES,Ye);const ea=S.isDataArrayTexture||S.isData3DTexture,gt=U.isDataArrayTexture||U.isData3DTexture;if(S.isDepthTexture){const Ut=q.get(S),ns=q.get(U),bt=q.get(Ut.__renderTarget),is=q.get(ns.__renderTarget);b.bindFramebuffer(k.READ_FRAMEBUFFER,bt.__webglFramebuffer),b.bindFramebuffer(k.DRAW_FRAMEBUFFER,is.__webglFramebuffer);for(let ta=0;ta<Se;ta++)ea&&(k.framebufferTextureLayer(k.READ_FRAMEBUFFER,k.COLOR_ATTACHMENT0,q.get(S).__webglTexture,X,Ye+ta),k.framebufferTextureLayer(k.DRAW_FRAMEBUFFER,k.COLOR_ATTACHMENT0,q.get(U).__webglTexture,ge,Ft+ta)),k.blitFramebuffer(De,Ve,xe,me,Ce,ut,xe,me,k.DEPTH_BUFFER_BIT,k.NEAREST);b.bindFramebuffer(k.READ_FRAMEBUFFER,null),b.bindFramebuffer(k.DRAW_FRAMEBUFFER,null)}else if(X!==0||S.isRenderTargetTexture||q.has(S)){const Ut=q.get(S),ns=q.get(U);b.bindFramebuffer(k.READ_FRAMEBUFFER,z),b.bindFramebuffer(k.DRAW_FRAMEBUFFER,L);for(let bt=0;bt<Se;bt++)ea?k.framebufferTextureLayer(k.READ_FRAMEBUFFER,k.COLOR_ATTACHMENT0,Ut.__webglTexture,X,Ye+bt):k.framebufferTexture2D(k.READ_FRAMEBUFFER,k.COLOR_ATTACHMENT0,k.TEXTURE_2D,Ut.__webglTexture,X),gt?k.framebufferTextureLayer(k.DRAW_FRAMEBUFFER,k.COLOR_ATTACHMENT0,ns.__webglTexture,ge,Ft+bt):k.framebufferTexture2D(k.DRAW_FRAMEBUFFER,k.COLOR_ATTACHMENT0,k.TEXTURE_2D,ns.__webglTexture,ge),X!==0?k.blitFramebuffer(De,Ve,xe,me,Ce,ut,xe,me,k.COLOR_BUFFER_BIT,k.NEAREST):gt?k.copyTexSubImage3D(ye,ge,Ce,ut,Ft+bt,De,Ve,xe,me):k.copyTexSubImage2D(ye,ge,Ce,ut,De,Ve,xe,me);b.bindFramebuffer(k.READ_FRAMEBUFFER,null),b.bindFramebuffer(k.DRAW_FRAMEBUFFER,null)}else gt?S.isDataTexture||S.isData3DTexture?k.texSubImage3D(ye,ge,Ce,ut,Ft,xe,me,Se,mt,on,Ot.data):U.isCompressedArrayTexture?k.compressedTexSubImage3D(ye,ge,Ce,ut,Ft,xe,me,Se,mt,Ot.data):k.texSubImage3D(ye,ge,Ce,ut,Ft,xe,me,Se,mt,on,Ot):S.isDataTexture?k.texSubImage2D(k.TEXTURE_2D,ge,Ce,ut,xe,me,mt,on,Ot.data):S.isCompressedTexture?k.compressedTexSubImage2D(k.TEXTURE_2D,ge,Ce,ut,Ot.width,Ot.height,mt,Ot.data):k.texSubImage2D(k.TEXTURE_2D,ge,Ce,ut,xe,me,mt,on,Ot);b.pixelStorei(k.UNPACK_ROW_LENGTH,Dn),b.pixelStorei(k.UNPACK_IMAGE_HEIGHT,tt),b.pixelStorei(k.UNPACK_SKIP_PIXELS,zn),b.pixelStorei(k.UNPACK_SKIP_ROWS,hi),b.pixelStorei(k.UNPACK_SKIP_IMAGES,ts),ge===0&&U.generateMipmaps&&k.generateMipmap(ye),b.unbindTexture()},this.initRenderTarget=function(S){q.get(S).__webglFramebuffer===void 0&&Z.setupRenderTarget(S)},this.initTexture=function(S){S.isCubeTexture?Z.setTextureCube(S,0):S.isData3DTexture?Z.setTexture3D(S,0):S.isDataArrayTexture||S.isCompressedArrayTexture?Z.setTexture2DArray(S,0):Z.setTexture2D(S,0),b.unbindTexture()},this.resetState=function(){B=0,F=0,V=null,b.reset(),ve.reset()},typeof __THREE_DEVTOOLS__<"u"&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}get coordinateSystem(){return Ei}get outputColorSpace(){return this._outputColorSpace}set outputColorSpace(e){this._outputColorSpace=e;const t=this.getContext();t.drawingBufferColorSpace=Qe._getDrawingBufferColorSpace(e),t.unpackColorSpace=Qe._getUnpackColorSpace()}}const GS=`
|
|
6048
|
+
}`;class NS{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(e,t){if(this.texture===null){const n=new rg(e.texture);(e.depthNear!==t.depthNear||e.depthFar!==t.depthFar)&&(this.depthNear=e.depthNear,this.depthFar=e.depthFar),this.texture=n}}getMesh(e){if(this.texture!==null&&this.mesh===null){const t=e.cameras[0].viewport,n=new Rt({vertexShader:PS,fragmentShader:LS,uniforms:{depthColor:{value:this.texture},depthWidth:{value:t.z},depthHeight:{value:t.w}}});this.mesh=new Ke(new es(20,20),n)}return this.mesh}reset(){this.texture=null,this.mesh=null}getDepthTexture(){return this.texture}}class OS extends Qs{constructor(e,t){super();const n=this;let i=null,s=1,r=null,o="local-floor",l=1,c=null,h=null,d=null,u=null,f=null,p=null;const v=typeof XRWebGLBinding<"u",m=new NS,g={},_=t.getContextAttributes();let M=null,x=null;const w=[],E=[],D=new Re;let y=null;const T=new An;T.viewport=new pt;const A=new An;A.viewport=new pt;const I=[T,A],R=new kb;let N=null,z=null;this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(K){let ae=w[K];return ae===void 0&&(ae=new _c,w[K]=ae),ae.getTargetRaySpace()},this.getControllerGrip=function(K){let ae=w[K];return ae===void 0&&(ae=new _c,w[K]=ae),ae.getGripSpace()},this.getHand=function(K){let ae=w[K];return ae===void 0&&(ae=new _c,w[K]=ae),ae.getHandSpace()};function L(K){const ae=E.indexOf(K.inputSource);if(ae===-1)return;const ie=w[ae];ie!==void 0&&(ie.update(K.inputSource,K.frame,c||r),ie.dispatchEvent({type:K.type,data:K.inputSource}))}function B(){i.removeEventListener("select",L),i.removeEventListener("selectstart",L),i.removeEventListener("selectend",L),i.removeEventListener("squeeze",L),i.removeEventListener("squeezestart",L),i.removeEventListener("squeezeend",L),i.removeEventListener("end",B),i.removeEventListener("inputsourceschange",F);for(let K=0;K<w.length;K++){const ae=E[K];ae!==null&&(E[K]=null,w[K].disconnect(ae))}N=null,z=null,m.reset();for(const K in g)delete g[K];e.setRenderTarget(M),f=null,u=null,d=null,i=null,x=null,ze.stop(),n.isPresenting=!1,e.setPixelRatio(y),e.setSize(D.width,D.height,!1),n.dispatchEvent({type:"sessionend"})}this.setFramebufferScaleFactor=function(K){s=K,n.isPresenting===!0&&Ee("WebXRManager: Cannot change framebuffer scale while presenting.")},this.setReferenceSpaceType=function(K){o=K,n.isPresenting===!0&&Ee("WebXRManager: Cannot change reference space type while presenting.")},this.getReferenceSpace=function(){return c||r},this.setReferenceSpace=function(K){c=K},this.getBaseLayer=function(){return u!==null?u:f},this.getBinding=function(){return d===null&&v&&(d=new XRWebGLBinding(i,t)),d},this.getFrame=function(){return p},this.getSession=function(){return i},this.setSession=async function(K){if(i=K,i!==null){if(M=e.getRenderTarget(),i.addEventListener("select",L),i.addEventListener("selectstart",L),i.addEventListener("selectend",L),i.addEventListener("squeeze",L),i.addEventListener("squeezestart",L),i.addEventListener("squeezeend",L),i.addEventListener("end",B),i.addEventListener("inputsourceschange",F),_.xrCompatible!==!0&&await t.makeXRCompatible(),y=e.getPixelRatio(),e.getSize(D),v&&"createProjectionLayer"in XRWebGLBinding.prototype){let ie=null,G=null,_e=null;_.depth&&(_e=_.stencil?t.DEPTH24_STENCIL8:t.DEPTH_COMPONENT24,ie=_.stencil?Ws:Ki,G=_.stencil?Qr:ri);const Pe={colorFormat:t.RGBA8,depthFormat:_e,scaleFactor:s};d=this.getBinding(),u=d.createProjectionLayer(Pe),i.updateRenderState({layers:[u]}),e.setPixelRatio(1),e.setSize(u.textureWidth,u.textureHeight,!1),x=new In(u.textureWidth,u.textureHeight,{format:Mn,type:Bn,depthTexture:new Js(u.textureWidth,u.textureHeight,G,void 0,void 0,void 0,void 0,void 0,void 0,ie),stencilBuffer:_.stencil,colorSpace:e.outputColorSpace,samples:_.antialias?4:0,resolveDepthBuffer:u.ignoreDepthValues===!1,resolveStencilBuffer:u.ignoreDepthValues===!1})}else{const ie={antialias:_.antialias,alpha:!0,depth:_.depth,stencil:_.stencil,framebufferScaleFactor:s};f=new XRWebGLLayer(i,t,ie),i.updateRenderState({baseLayer:f}),e.setPixelRatio(1),e.setSize(f.framebufferWidth,f.framebufferHeight,!1),x=new In(f.framebufferWidth,f.framebufferHeight,{format:Mn,type:Bn,colorSpace:e.outputColorSpace,stencilBuffer:_.stencil,resolveDepthBuffer:f.ignoreDepthValues===!1,resolveStencilBuffer:f.ignoreDepthValues===!1})}x.isXRRenderTarget=!0,this.setFoveation(l),c=null,r=await i.requestReferenceSpace(o),ze.setContext(i),ze.start(),n.isPresenting=!0,n.dispatchEvent({type:"sessionstart"})}},this.getEnvironmentBlendMode=function(){if(i!==null)return i.environmentBlendMode},this.getDepthTexture=function(){return m.getDepthTexture()};function F(K){for(let ae=0;ae<K.removed.length;ae++){const ie=K.removed[ae],G=E.indexOf(ie);G>=0&&(E[G]=null,w[G].disconnect(ie))}for(let ae=0;ae<K.added.length;ae++){const ie=K.added[ae];let G=E.indexOf(ie);if(G===-1){for(let Pe=0;Pe<w.length;Pe++)if(Pe>=E.length){E.push(ie),G=Pe;break}else if(E[Pe]===null){E[Pe]=ie,G=Pe;break}if(G===-1)break}const _e=w[G];_e&&_e.connect(ie)}}const V=new P,j=new P;function $(K,ae,ie){V.setFromMatrixPosition(ae.matrixWorld),j.setFromMatrixPosition(ie.matrixWorld);const G=V.distanceTo(j),_e=ae.projectionMatrix.elements,Pe=ie.projectionMatrix.elements,Ae=_e[14]/(_e[10]-1),be=_e[14]/(_e[10]+1),Ne=(_e[9]+1)/_e[5],Oe=(_e[9]-1)/_e[5],ke=(_e[8]-1)/_e[0],rt=(Pe[8]+1)/Pe[0],ot=Ae*ke,Pt=Ae*rt,wt=G/(-ke+rt),Lt=wt*-ke;if(ae.matrixWorld.decompose(K.position,K.quaternion,K.scale),K.translateX(Lt),K.translateZ(wt),K.matrixWorld.compose(K.position,K.quaternion,K.scale),K.matrixWorldInverse.copy(K.matrixWorld).invert(),_e[10]===-1)K.projectionMatrix.copy(ae.projectionMatrix),K.projectionMatrixInverse.copy(ae.projectionMatrixInverse);else{const Wt=Ae+wt,k=be+wt,_n=ot-Lt,lt=Pt+(G-Lt),C=Ne*be/k*Wt,b=Oe*be/k*Wt;K.projectionMatrix.makePerspective(_n,lt,C,b,Wt,k),K.projectionMatrixInverse.copy(K.projectionMatrix).invert()}}function ne(K,ae){ae===null?K.matrixWorld.copy(K.matrix):K.matrixWorld.multiplyMatrices(ae.matrixWorld,K.matrix),K.matrixWorldInverse.copy(K.matrixWorld).invert()}this.updateCamera=function(K){if(i===null)return;let ae=K.near,ie=K.far;m.texture!==null&&(m.depthNear>0&&(ae=m.depthNear),m.depthFar>0&&(ie=m.depthFar)),R.near=A.near=T.near=ae,R.far=A.far=T.far=ie,(N!==R.near||z!==R.far)&&(i.updateRenderState({depthNear:R.near,depthFar:R.far}),N=R.near,z=R.far),R.layers.mask=K.layers.mask|6,T.layers.mask=R.layers.mask&-5,A.layers.mask=R.layers.mask&-3;const G=K.parent,_e=R.cameras;ne(R,G);for(let Pe=0;Pe<_e.length;Pe++)ne(_e[Pe],G);_e.length===2?$(R,T,A):R.projectionMatrix.copy(T.projectionMatrix),re(K,R,G)};function re(K,ae,ie){ie===null?K.matrix.copy(ae.matrixWorld):(K.matrix.copy(ie.matrixWorld),K.matrix.invert(),K.matrix.multiply(ae.matrixWorld)),K.matrix.decompose(K.position,K.quaternion,K.scale),K.updateMatrixWorld(!0),K.projectionMatrix.copy(ae.projectionMatrix),K.projectionMatrixInverse.copy(ae.projectionMatrixInverse),K.isPerspectiveCamera&&(K.fov=ir*2*Math.atan(1/K.projectionMatrix.elements[5]),K.zoom=1)}this.getCamera=function(){return R},this.getFoveation=function(){if(!(u===null&&f===null))return l},this.setFoveation=function(K){l=K,u!==null&&(u.fixedFoveation=K),f!==null&&f.fixedFoveation!==void 0&&(f.fixedFoveation=K)},this.hasDepthSensing=function(){return m.texture!==null},this.getDepthSensingMesh=function(){return m.getMesh(R)},this.getCameraTexture=function(K){return g[K]};let He=null;function Ze(K,ae){if(h=ae.getViewerPose(c||r),p=ae,h!==null){const ie=h.views;f!==null&&(e.setRenderTargetFramebuffer(x,f.framebuffer),e.setRenderTarget(x));let G=!1;ie.length!==R.cameras.length&&(R.cameras.length=0,G=!0);for(let be=0;be<ie.length;be++){const Ne=ie[be];let Oe=null;if(f!==null)Oe=f.getViewport(Ne);else{const rt=d.getViewSubImage(u,Ne);Oe=rt.viewport,be===0&&(e.setRenderTargetTextures(x,rt.colorTexture,rt.depthStencilTexture),e.setRenderTarget(x))}let ke=I[be];ke===void 0&&(ke=new An,ke.layers.enable(be),ke.viewport=new pt,I[be]=ke),ke.matrix.fromArray(Ne.transform.matrix),ke.matrix.decompose(ke.position,ke.quaternion,ke.scale),ke.projectionMatrix.fromArray(Ne.projectionMatrix),ke.projectionMatrixInverse.copy(ke.projectionMatrix).invert(),ke.viewport.set(Oe.x,Oe.y,Oe.width,Oe.height),be===0&&(R.matrix.copy(ke.matrix),R.matrix.decompose(R.position,R.quaternion,R.scale)),G===!0&&R.cameras.push(ke)}const _e=i.enabledFeatures;if(_e&&_e.includes("depth-sensing")&&i.depthUsage=="gpu-optimized"&&v){d=n.getBinding();const be=d.getDepthInformation(ie[0]);be&&be.isValid&&be.texture&&m.init(be,i.renderState)}if(_e&&_e.includes("camera-access")&&v){e.state.unbindTexture(),d=n.getBinding();for(let be=0;be<ie.length;be++){const Ne=ie[be].camera;if(Ne){let Oe=g[Ne];Oe||(Oe=new rg,g[Ne]=Oe);const ke=d.getCameraImage(Ne);Oe.sourceTexture=ke}}}}for(let ie=0;ie<w.length;ie++){const G=E[ie],_e=w[ie];G!==null&&_e!==void 0&&_e.update(G,ae,c||r)}He&&He(K,ae),ae.detectedPlanes&&n.dispatchEvent({type:"planesdetected",data:ae}),p=null}const ze=new ug;ze.setAnimationLoop(Ze),this.setAnimationLoop=function(K){He=K},this.dispose=function(){}}}const kS=new qe,bg=new Be;bg.set(-1,0,0,0,1,0,0,0,1);function FS(a,e){function t(m,g){m.matrixAutoUpdate===!0&&m.updateMatrix(),g.value.copy(m.matrix)}function n(m,g){g.color.getRGB(m.fogColor.value,og(a)),g.isFog?(m.fogNear.value=g.near,m.fogFar.value=g.far):g.isFogExp2&&(m.fogDensity.value=g.density)}function i(m,g,_,M,x){g.isNodeMaterial?g.uniformsNeedUpdate=!1:g.isMeshBasicMaterial?s(m,g):g.isMeshLambertMaterial?(s(m,g),g.envMap&&(m.envMapIntensity.value=g.envMapIntensity)):g.isMeshToonMaterial?(s(m,g),d(m,g)):g.isMeshPhongMaterial?(s(m,g),h(m,g),g.envMap&&(m.envMapIntensity.value=g.envMapIntensity)):g.isMeshStandardMaterial?(s(m,g),u(m,g),g.isMeshPhysicalMaterial&&f(m,g,x)):g.isMeshMatcapMaterial?(s(m,g),p(m,g)):g.isMeshDepthMaterial?s(m,g):g.isMeshDistanceMaterial?(s(m,g),v(m,g)):g.isMeshNormalMaterial?s(m,g):g.isLineBasicMaterial?(r(m,g),g.isLineDashedMaterial&&o(m,g)):g.isPointsMaterial?l(m,g,_,M):g.isSpriteMaterial?c(m,g):g.isShadowMaterial?(m.color.value.copy(g.color),m.opacity.value=g.opacity):g.isShaderMaterial&&(g.uniformsNeedUpdate=!1)}function s(m,g){m.opacity.value=g.opacity,g.color&&m.diffuse.value.copy(g.color),g.emissive&&m.emissive.value.copy(g.emissive).multiplyScalar(g.emissiveIntensity),g.map&&(m.map.value=g.map,t(g.map,m.mapTransform)),g.alphaMap&&(m.alphaMap.value=g.alphaMap,t(g.alphaMap,m.alphaMapTransform)),g.bumpMap&&(m.bumpMap.value=g.bumpMap,t(g.bumpMap,m.bumpMapTransform),m.bumpScale.value=g.bumpScale,g.side===Vt&&(m.bumpScale.value*=-1)),g.normalMap&&(m.normalMap.value=g.normalMap,t(g.normalMap,m.normalMapTransform),m.normalScale.value.copy(g.normalScale),g.side===Vt&&m.normalScale.value.negate()),g.displacementMap&&(m.displacementMap.value=g.displacementMap,t(g.displacementMap,m.displacementMapTransform),m.displacementScale.value=g.displacementScale,m.displacementBias.value=g.displacementBias),g.emissiveMap&&(m.emissiveMap.value=g.emissiveMap,t(g.emissiveMap,m.emissiveMapTransform)),g.specularMap&&(m.specularMap.value=g.specularMap,t(g.specularMap,m.specularMapTransform)),g.alphaTest>0&&(m.alphaTest.value=g.alphaTest);const _=e.get(g),M=_.envMap,x=_.envMapRotation;M&&(m.envMap.value=M,m.envMapRotation.value.setFromMatrix4(kS.makeRotationFromEuler(x)).transpose(),M.isCubeTexture&&M.isRenderTargetTexture===!1&&m.envMapRotation.value.premultiply(bg),m.reflectivity.value=g.reflectivity,m.ior.value=g.ior,m.refractionRatio.value=g.refractionRatio),g.lightMap&&(m.lightMap.value=g.lightMap,m.lightMapIntensity.value=g.lightMapIntensity,t(g.lightMap,m.lightMapTransform)),g.aoMap&&(m.aoMap.value=g.aoMap,m.aoMapIntensity.value=g.aoMapIntensity,t(g.aoMap,m.aoMapTransform))}function r(m,g){m.diffuse.value.copy(g.color),m.opacity.value=g.opacity,g.map&&(m.map.value=g.map,t(g.map,m.mapTransform))}function o(m,g){m.dashSize.value=g.dashSize,m.totalSize.value=g.dashSize+g.gapSize,m.scale.value=g.scale}function l(m,g,_,M){m.diffuse.value.copy(g.color),m.opacity.value=g.opacity,m.size.value=g.size*_,m.scale.value=M*.5,g.map&&(m.map.value=g.map,t(g.map,m.uvTransform)),g.alphaMap&&(m.alphaMap.value=g.alphaMap,t(g.alphaMap,m.alphaMapTransform)),g.alphaTest>0&&(m.alphaTest.value=g.alphaTest)}function c(m,g){m.diffuse.value.copy(g.color),m.opacity.value=g.opacity,m.rotation.value=g.rotation,g.map&&(m.map.value=g.map,t(g.map,m.mapTransform)),g.alphaMap&&(m.alphaMap.value=g.alphaMap,t(g.alphaMap,m.alphaMapTransform)),g.alphaTest>0&&(m.alphaTest.value=g.alphaTest)}function h(m,g){m.specular.value.copy(g.specular),m.shininess.value=Math.max(g.shininess,1e-4)}function d(m,g){g.gradientMap&&(m.gradientMap.value=g.gradientMap)}function u(m,g){m.metalness.value=g.metalness,g.metalnessMap&&(m.metalnessMap.value=g.metalnessMap,t(g.metalnessMap,m.metalnessMapTransform)),m.roughness.value=g.roughness,g.roughnessMap&&(m.roughnessMap.value=g.roughnessMap,t(g.roughnessMap,m.roughnessMapTransform)),g.envMap&&(m.envMapIntensity.value=g.envMapIntensity)}function f(m,g,_){m.ior.value=g.ior,g.sheen>0&&(m.sheenColor.value.copy(g.sheenColor).multiplyScalar(g.sheen),m.sheenRoughness.value=g.sheenRoughness,g.sheenColorMap&&(m.sheenColorMap.value=g.sheenColorMap,t(g.sheenColorMap,m.sheenColorMapTransform)),g.sheenRoughnessMap&&(m.sheenRoughnessMap.value=g.sheenRoughnessMap,t(g.sheenRoughnessMap,m.sheenRoughnessMapTransform))),g.clearcoat>0&&(m.clearcoat.value=g.clearcoat,m.clearcoatRoughness.value=g.clearcoatRoughness,g.clearcoatMap&&(m.clearcoatMap.value=g.clearcoatMap,t(g.clearcoatMap,m.clearcoatMapTransform)),g.clearcoatRoughnessMap&&(m.clearcoatRoughnessMap.value=g.clearcoatRoughnessMap,t(g.clearcoatRoughnessMap,m.clearcoatRoughnessMapTransform)),g.clearcoatNormalMap&&(m.clearcoatNormalMap.value=g.clearcoatNormalMap,t(g.clearcoatNormalMap,m.clearcoatNormalMapTransform),m.clearcoatNormalScale.value.copy(g.clearcoatNormalScale),g.side===Vt&&m.clearcoatNormalScale.value.negate())),g.dispersion>0&&(m.dispersion.value=g.dispersion),g.iridescence>0&&(m.iridescence.value=g.iridescence,m.iridescenceIOR.value=g.iridescenceIOR,m.iridescenceThicknessMinimum.value=g.iridescenceThicknessRange[0],m.iridescenceThicknessMaximum.value=g.iridescenceThicknessRange[1],g.iridescenceMap&&(m.iridescenceMap.value=g.iridescenceMap,t(g.iridescenceMap,m.iridescenceMapTransform)),g.iridescenceThicknessMap&&(m.iridescenceThicknessMap.value=g.iridescenceThicknessMap,t(g.iridescenceThicknessMap,m.iridescenceThicknessMapTransform))),g.transmission>0&&(m.transmission.value=g.transmission,m.transmissionSamplerMap.value=_.texture,m.transmissionSamplerSize.value.set(_.width,_.height),g.transmissionMap&&(m.transmissionMap.value=g.transmissionMap,t(g.transmissionMap,m.transmissionMapTransform)),m.thickness.value=g.thickness,g.thicknessMap&&(m.thicknessMap.value=g.thicknessMap,t(g.thicknessMap,m.thicknessMapTransform)),m.attenuationDistance.value=g.attenuationDistance,m.attenuationColor.value.copy(g.attenuationColor)),g.anisotropy>0&&(m.anisotropyVector.value.set(g.anisotropy*Math.cos(g.anisotropyRotation),g.anisotropy*Math.sin(g.anisotropyRotation)),g.anisotropyMap&&(m.anisotropyMap.value=g.anisotropyMap,t(g.anisotropyMap,m.anisotropyMapTransform))),m.specularIntensity.value=g.specularIntensity,m.specularColor.value.copy(g.specularColor),g.specularColorMap&&(m.specularColorMap.value=g.specularColorMap,t(g.specularColorMap,m.specularColorMapTransform)),g.specularIntensityMap&&(m.specularIntensityMap.value=g.specularIntensityMap,t(g.specularIntensityMap,m.specularIntensityMapTransform))}function p(m,g){g.matcap&&(m.matcap.value=g.matcap)}function v(m,g){const _=e.get(g).light;m.referencePosition.value.setFromMatrixPosition(_.matrixWorld),m.nearDistance.value=_.shadow.camera.near,m.farDistance.value=_.shadow.camera.far}return{refreshFogUniforms:n,refreshMaterialUniforms:i}}function US(a,e,t,n){let i={},s={},r=[];const o=a.getParameter(a.MAX_UNIFORM_BUFFER_BINDINGS);function l(x,w){const E=w.program;n.uniformBlockBinding(x,E)}function c(x,w){let E=i[x.id];E===void 0&&(m(x),E=h(x),i[x.id]=E,x.addEventListener("dispose",_));const D=w.program;n.updateUBOMapping(x,D);const y=e.render.frame;s[x.id]!==y&&(u(x),s[x.id]=y)}function h(x){const w=d();x.__bindingPointIndex=w;const E=a.createBuffer(),D=x.__size,y=x.usage;return a.bindBuffer(a.UNIFORM_BUFFER,E),a.bufferData(a.UNIFORM_BUFFER,D,y),a.bindBuffer(a.UNIFORM_BUFFER,null),a.bindBufferBase(a.UNIFORM_BUFFER,w,E),E}function d(){for(let x=0;x<o;x++)if(r.indexOf(x)===-1)return r.push(x),x;return Ue("WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached."),0}function u(x){const w=i[x.id],E=x.uniforms,D=x.__cache;a.bindBuffer(a.UNIFORM_BUFFER,w);for(let y=0,T=E.length;y<T;y++){const A=E[y];if(Array.isArray(A))for(let I=0,R=A.length;I<R;I++)f(A[I],y,I,D);else f(A,y,0,D)}a.bindBuffer(a.UNIFORM_BUFFER,null)}function f(x,w,E,D){if(v(x,w,E,D)===!0){const y=x.__offset,T=x.value;if(Array.isArray(T)){let A=0;for(let I=0;I<T.length;I++){const R=T[I],N=g(R);p(R,x.__data,A),typeof R!="number"&&typeof R!="boolean"&&!R.isMatrix3&&!ArrayBuffer.isView(R)&&(A+=N.storage/Float32Array.BYTES_PER_ELEMENT)}}else p(T,x.__data,0);a.bufferSubData(a.UNIFORM_BUFFER,y,x.__data)}}function p(x,w,E){typeof x=="number"||typeof x=="boolean"?w[0]=x:x.isMatrix3?(w[0]=x.elements[0],w[1]=x.elements[1],w[2]=x.elements[2],w[3]=0,w[4]=x.elements[3],w[5]=x.elements[4],w[6]=x.elements[5],w[7]=0,w[8]=x.elements[6],w[9]=x.elements[7],w[10]=x.elements[8],w[11]=0):ArrayBuffer.isView(x)?w.set(new x.constructor(x.buffer,x.byteOffset,w.length)):x.toArray(w,E)}function v(x,w,E,D){const y=x.value,T=w+"_"+E;if(D[T]===void 0)return typeof y=="number"||typeof y=="boolean"?D[T]=y:ArrayBuffer.isView(y)?D[T]=y.slice():D[T]=y.clone(),!0;{const A=D[T];if(typeof y=="number"||typeof y=="boolean"){if(A!==y)return D[T]=y,!0}else{if(ArrayBuffer.isView(y))return!0;if(A.equals(y)===!1)return A.copy(y),!0}}return!1}function m(x){const w=x.uniforms;let E=0;const D=16;for(let T=0,A=w.length;T<A;T++){const I=Array.isArray(w[T])?w[T]:[w[T]];for(let R=0,N=I.length;R<N;R++){const z=I[R],L=Array.isArray(z.value)?z.value:[z.value];for(let B=0,F=L.length;B<F;B++){const V=L[B],j=g(V),$=E%D,ne=$%j.boundary,re=$+ne;E+=ne,re!==0&&D-re<j.storage&&(E+=D-re),z.__data=new Float32Array(j.storage/Float32Array.BYTES_PER_ELEMENT),z.__offset=E,E+=j.storage}}}const y=E%D;return y>0&&(E+=D-y),x.__size=E,x.__cache={},this}function g(x){const w={boundary:0,storage:0};return typeof x=="number"||typeof x=="boolean"?(w.boundary=4,w.storage=4):x.isVector2?(w.boundary=8,w.storage=8):x.isVector3||x.isColor?(w.boundary=16,w.storage=12):x.isVector4?(w.boundary=16,w.storage=16):x.isMatrix3?(w.boundary=48,w.storage=48):x.isMatrix4?(w.boundary=64,w.storage=64):x.isTexture?Ee("WebGLRenderer: Texture samplers can not be part of an uniforms group."):ArrayBuffer.isView(x)?(w.boundary=16,w.storage=x.byteLength):Ee("WebGLRenderer: Unsupported uniform value type.",x),w}function _(x){const w=x.target;w.removeEventListener("dispose",_);const E=r.indexOf(w.__bindingPointIndex);r.splice(E,1),a.deleteBuffer(i[w.id]),delete i[w.id],delete s[w.id]}function M(){for(const x in i)a.deleteBuffer(i[x]);r=[],i={},s={}}return{bind:l,update:c,dispose:M}}const BS=new Uint16Array([12469,15057,12620,14925,13266,14620,13807,14376,14323,13990,14545,13625,14713,13328,14840,12882,14931,12528,14996,12233,15039,11829,15066,11525,15080,11295,15085,10976,15082,10705,15073,10495,13880,14564,13898,14542,13977,14430,14158,14124,14393,13732,14556,13410,14702,12996,14814,12596,14891,12291,14937,11834,14957,11489,14958,11194,14943,10803,14921,10506,14893,10278,14858,9960,14484,14039,14487,14025,14499,13941,14524,13740,14574,13468,14654,13106,14743,12678,14818,12344,14867,11893,14889,11509,14893,11180,14881,10751,14852,10428,14812,10128,14765,9754,14712,9466,14764,13480,14764,13475,14766,13440,14766,13347,14769,13070,14786,12713,14816,12387,14844,11957,14860,11549,14868,11215,14855,10751,14825,10403,14782,10044,14729,9651,14666,9352,14599,9029,14967,12835,14966,12831,14963,12804,14954,12723,14936,12564,14917,12347,14900,11958,14886,11569,14878,11247,14859,10765,14828,10401,14784,10011,14727,9600,14660,9289,14586,8893,14508,8533,15111,12234,15110,12234,15104,12216,15092,12156,15067,12010,15028,11776,14981,11500,14942,11205,14902,10752,14861,10393,14812,9991,14752,9570,14682,9252,14603,8808,14519,8445,14431,8145,15209,11449,15208,11451,15202,11451,15190,11438,15163,11384,15117,11274,15055,10979,14994,10648,14932,10343,14871,9936,14803,9532,14729,9218,14645,8742,14556,8381,14461,8020,14365,7603,15273,10603,15272,10607,15267,10619,15256,10631,15231,10614,15182,10535,15118,10389,15042,10167,14963,9787,14883,9447,14800,9115,14710,8665,14615,8318,14514,7911,14411,7507,14279,7198,15314,9675,15313,9683,15309,9712,15298,9759,15277,9797,15229,9773,15166,9668,15084,9487,14995,9274,14898,8910,14800,8539,14697,8234,14590,7790,14479,7409,14367,7067,14178,6621,15337,8619,15337,8631,15333,8677,15325,8769,15305,8871,15264,8940,15202,8909,15119,8775,15022,8565,14916,8328,14804,8009,14688,7614,14569,7287,14448,6888,14321,6483,14088,6171,15350,7402,15350,7419,15347,7480,15340,7613,15322,7804,15287,7973,15229,8057,15148,8012,15046,7846,14933,7611,14810,7357,14682,7069,14552,6656,14421,6316,14251,5948,14007,5528,15356,5942,15356,5977,15353,6119,15348,6294,15332,6551,15302,6824,15249,7044,15171,7122,15070,7050,14949,6861,14818,6611,14679,6349,14538,6067,14398,5651,14189,5311,13935,4958,15359,4123,15359,4153,15356,4296,15353,4646,15338,5160,15311,5508,15263,5829,15188,6042,15088,6094,14966,6001,14826,5796,14678,5543,14527,5287,14377,4985,14133,4586,13869,4257,15360,1563,15360,1642,15358,2076,15354,2636,15341,3350,15317,4019,15273,4429,15203,4732,15105,4911,14981,4932,14836,4818,14679,4621,14517,4386,14359,4156,14083,3795,13808,3437,15360,122,15360,137,15358,285,15355,636,15344,1274,15322,2177,15281,2765,15215,3223,15120,3451,14995,3569,14846,3567,14681,3466,14511,3305,14344,3121,14037,2800,13753,2467,15360,0,15360,1,15359,21,15355,89,15346,253,15325,479,15287,796,15225,1148,15133,1492,15008,1749,14856,1882,14685,1886,14506,1783,14324,1608,13996,1398,13702,1183]);let ui=null;function zS(){return ui===null&&(ui=new or(BS,16,16,Zs,pn),ui.name="DFG_LUT",ui.minFilter=At,ui.magFilter=At,ui.wrapS=wn,ui.wrapT=wn,ui.generateMipmaps=!1,ui.needsUpdate=!0),ui}class HS{constructor(e={}){const{canvas:t=fy(),context:n=null,depth:i=!0,stencil:s=!1,alpha:r=!1,antialias:o=!1,premultipliedAlpha:l=!0,preserveDrawingBuffer:c=!1,powerPreference:h="default",failIfMajorPerformanceCaveat:d=!1,reversedDepthBuffer:u=!1,outputBufferType:f=Bn}=e;this.isWebGLRenderer=!0;let p;if(n!==null){if(typeof WebGLRenderingContext<"u"&&n instanceof WebGLRenderingContext)throw new Error("THREE.WebGLRenderer: WebGL 1 is not supported since r163.");p=n.getContextAttributes().alpha}else p=r;const v=f,m=new Set([Su,Mu,wu]),g=new Set([Bn,ri,jr,Qr,bu,xu]),_=new Uint32Array(4),M=new Int32Array(4),x=new P;let w=null,E=null;const D=[],y=[];let T=null;this.domElement=t,this.debug={checkShaderErrors:!0,onShaderError:null},this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.clippingPlanes=[],this.localClippingEnabled=!1,this.toneMapping=Ii,this.toneMappingExposure=1,this.transmissionResolutionScale=1;const A=this;let I=!1,R=null,N=null,z=null,L=null;this._outputColorSpace=Fn;let B=0,F=0,V=null,j=-1,$=null;const ne=new pt,re=new pt;let He=null;const Ze=new le(0);let ze=0,K=t.width,ae=t.height,ie=1,G=null,_e=null;const Pe=new pt(0,0,K,ae),Ae=new pt(0,0,K,ae);let be=!1;const Ne=new Ru;let Oe=!1,ke=!1;const rt=new qe,ot=new P,Pt=new pt,wt={background:null,fog:null,environment:null,overrideMaterial:null,isScene:!0};let Lt=!1;function Wt(){return V===null?ie:1}let k=n;function _n(S,U){return t.getContext(S,U)}try{const S={alpha:!0,depth:i,stencil:s,antialias:o,premultipliedAlpha:l,preserveDrawingBuffer:c,powerPreference:h,failIfMajorPerformanceCaveat:d};if("setAttribute"in t&&t.setAttribute("data-engine",`three.js r${gu}`),t.addEventListener("webglcontextlost",Nt,!1),t.addEventListener("webglcontextrestored",yt,!1),t.addEventListener("webglcontextcreationerror",li,!1),k===null){const U="webgl2";if(k=_n(U,S),k===null)throw _n(U)?new Error("THREE.WebGLRenderer: Error creating WebGL context with your selected attributes."):new Error("THREE.WebGLRenderer: Error creating WebGL context.")}}catch(S){throw Ue("WebGLRenderer: "+S.message),S}let lt,C,b,H,q,Z,se,ce,J,ee,he,Ie,fe,de,Le,Fe,Ge,O,oe,Q,ue,ve,te;function Te(){lt=new zM(k),lt.init(),ue=new RS(k,lt),C=new PM(k,lt,e,ue),b=new DS(k,lt),C.reversedDepthBuffer&&u&&b.buffers.depth.setReversed(!0),N=k.createFramebuffer(),z=k.createFramebuffer(),L=k.createFramebuffer(),H=new VM(k),q=new mS,Z=new CS(k,lt,b,q,C,ue,H),se=new BM(A),ce=new Yb(k),ve=new CM(k,ce),J=new HM(k,ce,H,ve),ee=new XM(k,J,ce,ve,H),O=new WM(k,C,Z),Le=new LM(q),he=new pS(A,se,lt,C,ve,Le),Ie=new FS(A,q),fe=new vS,de=new SS(lt),Ge=new DM(A,se,b,ee,p,l),Fe=new IS(A,ee,C),te=new US(k,H,C,b),oe=new RM(k,lt,H),Q=new GM(k,lt,H),H.programs=he.programs,A.capabilities=C,A.extensions=lt,A.properties=q,A.renderLists=fe,A.shadowMap=Fe,A.state=b,A.info=H}Te(),v!==Bn&&(T=new YM(v,t.width,t.height,o,i,s));const we=new OS(A,k);this.xr=we,this.getContext=function(){return k},this.getContextAttributes=function(){return k.getContextAttributes()},this.forceContextLoss=function(){const S=lt.get("WEBGL_lose_context");S&&S.loseContext()},this.forceContextRestore=function(){const S=lt.get("WEBGL_lose_context");S&&S.restoreContext()},this.getPixelRatio=function(){return ie},this.setPixelRatio=function(S){S!==void 0&&(ie=S,this.setSize(K,ae,!1))},this.getSize=function(S){return S.set(K,ae)},this.setSize=function(S,U,Y=!0){if(we.isPresenting){Ee("WebGLRenderer: Can't change size while VR device is presenting.");return}K=S,ae=U,t.width=Math.floor(S*ie),t.height=Math.floor(U*ie),Y===!0&&(t.style.width=S+"px",t.style.height=U+"px"),T!==null&&T.setSize(t.width,t.height),this.setViewport(0,0,S,U)},this.getDrawingBufferSize=function(S){return S.set(K*ie,ae*ie).floor()},this.setDrawingBufferSize=function(S,U,Y){K=S,ae=U,ie=Y,t.width=Math.floor(S*Y),t.height=Math.floor(U*Y),this.setViewport(0,0,S,U)},this.setEffects=function(S){if(v===Bn){Ue("WebGLRenderer: setEffects() requires outputBufferType set to HalfFloatType or FloatType.");return}if(S){for(let U=0;U<S.length;U++)if(S[U].isOutputPass===!0){Ee("WebGLRenderer: OutputPass is not needed in setEffects(). Tone mapping and color space conversion are applied automatically.");break}}T.setEffects(S||[])},this.getCurrentViewport=function(S){return S.copy(ne)},this.getViewport=function(S){return S.copy(Pe)},this.setViewport=function(S,U,Y,W){S.isVector4?Pe.set(S.x,S.y,S.z,S.w):Pe.set(S,U,Y,W),b.viewport(ne.copy(Pe).multiplyScalar(ie).round())},this.getScissor=function(S){return S.copy(Ae)},this.setScissor=function(S,U,Y,W){S.isVector4?Ae.set(S.x,S.y,S.z,S.w):Ae.set(S,U,Y,W),b.scissor(re.copy(Ae).multiplyScalar(ie).round())},this.getScissorTest=function(){return be},this.setScissorTest=function(S){b.setScissorTest(be=S)},this.setOpaqueSort=function(S){G=S},this.setTransparentSort=function(S){_e=S},this.getClearColor=function(S){return S.copy(Ge.getClearColor())},this.setClearColor=function(){Ge.setClearColor(...arguments)},this.getClearAlpha=function(){return Ge.getClearAlpha()},this.setClearAlpha=function(){Ge.setClearAlpha(...arguments)},this.clear=function(S=!0,U=!0,Y=!0){let W=0;if(S){let X=!1;if(V!==null){const ge=V.texture.format;X=m.has(ge)}if(X){const ge=V.texture.type,xe=g.has(ge),me=Ge.getClearColor(),Se=Ge.getClearAlpha(),De=me.r,Ve=me.g,Ye=me.b;xe?(_[0]=De,_[1]=Ve,_[2]=Ye,_[3]=Se,k.clearBufferuiv(k.COLOR,0,_)):(M[0]=De,M[1]=Ve,M[2]=Ye,M[3]=Se,k.clearBufferiv(k.COLOR,0,M))}else W|=k.COLOR_BUFFER_BIT}U&&(W|=k.DEPTH_BUFFER_BIT,this.state.buffers.depth.setMask(!0)),Y&&(W|=k.STENCIL_BUFFER_BIT,this.state.buffers.stencil.setMask(4294967295)),W!==0&&k.clear(W)},this.clearColor=function(){this.clear(!0,!1,!1)},this.clearDepth=function(){this.clear(!1,!0,!1)},this.clearStencil=function(){this.clear(!1,!1,!0)},this.setNodesHandler=function(S){S.setRenderer(this),R=S},this.dispose=function(){t.removeEventListener("webglcontextlost",Nt,!1),t.removeEventListener("webglcontextrestored",yt,!1),t.removeEventListener("webglcontextcreationerror",li,!1),Ge.dispose(),fe.dispose(),de.dispose(),q.dispose(),se.dispose(),ee.dispose(),ve.dispose(),te.dispose(),he.dispose(),we.dispose(),we.removeEventListener("sessionstart",Ku),we.removeEventListener("sessionend",$u),Es.stop()};function Nt(S){S.preventDefault(),Bl("WebGLRenderer: Context Lost."),I=!0}function yt(){Bl("WebGLRenderer: Context Restored."),I=!1;const S=H.autoReset,U=Fe.enabled,Y=Fe.autoUpdate,W=Fe.needsUpdate,X=Fe.type;Te(),H.autoReset=S,Fe.enabled=U,Fe.autoUpdate=Y,Fe.needsUpdate=W,Fe.type=X}function li(S){Ue("WebGLRenderer: A WebGL context could not be created. Reason: ",S.statusMessage)}function ci(S){const U=S.target;U.removeEventListener("dispose",ci),ov(U)}function ov(S){lv(S),q.remove(S)}function lv(S){const U=q.get(S).programs;U!==void 0&&(U.forEach(function(Y){he.releaseProgram(Y)}),S.isShaderMaterial&&he.releaseShaderCache(S))}this.renderBufferDirect=function(S,U,Y,W,X,ge){U===null&&(U=wt);const xe=X.isMesh&&X.matrixWorld.determinantAffine()<0,me=dv(S,U,Y,W,X);b.setMaterial(W,xe);let Se=Y.index,De=1;if(W.wireframe===!0){if(Se=J.getWireframeAttribute(Y),Se===void 0)return;De=2}const Ve=Y.drawRange,Ye=Y.attributes.position;let Ce=Ve.start*De,ut=(Ve.start+Ve.count)*De;ge!==null&&(Ce=Math.max(Ce,ge.start*De),ut=Math.min(ut,(ge.start+ge.count)*De)),Se!==null?(Ce=Math.max(Ce,0),ut=Math.min(ut,Se.count)):Ye!=null&&(Ce=Math.max(Ce,0),ut=Math.min(ut,Ye.count));const Ut=ut-Ce;if(Ut<0||Ut===1/0)return;ve.setup(X,W,me,Y,Se);let Ot,mt=oe;if(Se!==null&&(Ot=ce.get(Se),mt=Q,mt.setIndex(Ot)),X.isMesh)W.wireframe===!0?(b.setLineWidth(W.wireframeLinewidth*Wt()),mt.setMode(k.LINES)):mt.setMode(k.TRIANGLES);else if(X.isLine){let on=W.linewidth;on===void 0&&(on=1),b.setLineWidth(on*Wt()),X.isLineSegments?mt.setMode(k.LINES):X.isLineLoop?mt.setMode(k.LINE_LOOP):mt.setMode(k.LINE_STRIP)}else X.isPoints?mt.setMode(k.POINTS):X.isSprite&&mt.setMode(k.TRIANGLES);if(X.isBatchedMesh)if(lt.get("WEBGL_multi_draw"))mt.renderMultiDraw(X._multiDrawStarts,X._multiDrawCounts,X._multiDrawCount);else{const on=X._multiDrawStarts,ye=X._multiDrawCounts,Dn=X._multiDrawCount,tt=Se?ce.get(Se).bytesPerElement:1,zn=q.get(W).currentProgram.getUniforms();for(let hi=0;hi<Dn;hi++)zn.setValue(k,"_gl_DrawID",hi),mt.render(on[hi]/tt,ye[hi])}else if(X.isInstancedMesh)mt.renderInstances(Ce,Ut,X.count);else if(Y.isInstancedBufferGeometry){const on=Y._maxInstanceCount!==void 0?Y._maxInstanceCount:1/0,ye=Math.min(Y.instanceCount,on);mt.renderInstances(Ce,Ut,ye)}else mt.render(Ce,Ut)};function Yu(S,U,Y){S.transparent===!0&&S.side===Qn&&S.forceSinglePass===!1?(S.side=Vt,S.needsUpdate=!0,fo(S,U,Y),S.side=Ms,S.needsUpdate=!0,fo(S,U,Y),S.side=Qn):fo(S,U,Y)}this.compile=function(S,U,Y=null){Y===null&&(Y=S),E=de.get(Y),E.init(U),y.push(E),Y.traverseVisible(function(X){X.isLight&&X.layers.test(U.layers)&&(E.pushLight(X),X.castShadow&&E.pushShadow(X))}),S!==Y&&S.traverseVisible(function(X){X.isLight&&X.layers.test(U.layers)&&(E.pushLight(X),X.castShadow&&E.pushShadow(X))}),E.setupLights();const W=new Set;return S.traverse(function(X){if(!(X.isMesh||X.isPoints||X.isLine||X.isSprite))return;const ge=X.material;if(ge)if(Array.isArray(ge))for(let xe=0;xe<ge.length;xe++){const me=ge[xe];Yu(me,Y,X),W.add(me)}else Yu(ge,Y,X),W.add(ge)}),E=y.pop(),W},this.compileAsync=function(S,U,Y=null){const W=this.compile(S,U,Y);return new Promise(X=>{function ge(){if(W.forEach(function(xe){q.get(xe).currentProgram.isReady()&&W.delete(xe)}),W.size===0){X(S);return}setTimeout(ge,10)}lt.get("KHR_parallel_shader_compile")!==null?ge():setTimeout(ge,10)})};let cc=null;function cv(S){cc&&cc(S)}function Ku(){Es.stop()}function $u(){Es.start()}const Es=new ug;Es.setAnimationLoop(cv),typeof self<"u"&&Es.setContext(self),this.setAnimationLoop=function(S){cc=S,we.setAnimationLoop(S),S===null?Es.stop():Es.start()},we.addEventListener("sessionstart",Ku),we.addEventListener("sessionend",$u),this.render=function(S,U){if(U!==void 0&&U.isCamera!==!0){Ue("WebGLRenderer.render: camera is not an instance of THREE.Camera.");return}if(I===!0)return;R!==null&&R.renderStart(S,U);const Y=we.enabled===!0&&we.isPresenting===!0,W=T!==null&&(V===null||Y)&&T.begin(A,V);if(S.matrixWorldAutoUpdate===!0&&S.updateMatrixWorld(),U.parent===null&&U.matrixWorldAutoUpdate===!0&&U.updateMatrixWorld(),we.enabled===!0&&we.isPresenting===!0&&(T===null||T.isCompositing()===!1)&&(we.cameraAutoUpdate===!0&&we.updateCamera(U),U=we.getCamera()),S.isScene===!0&&S.onBeforeRender(A,S,U,V),E=de.get(S,y.length),E.init(U),E.state.textureUnits=Z.getTextureUnits(),y.push(E),rt.multiplyMatrices(U.projectionMatrix,U.matrixWorldInverse),Ne.setFromProjectionMatrix(rt,Ei,U.reversedDepth),ke=this.localClippingEnabled,Oe=Le.init(this.clippingPlanes,ke),w=fe.get(S,D.length),w.init(),D.push(w),we.enabled===!0&&we.isPresenting===!0){const xe=A.xr.getDepthSensingMesh();xe!==null&&hc(xe,U,-1/0,A.sortObjects)}hc(S,U,0,A.sortObjects),w.finish(),A.sortObjects===!0&&w.sort(G,_e,U.reversedDepth),Lt=we.enabled===!1||we.isPresenting===!1||we.hasDepthSensing()===!1,Lt&&Ge.addToRenderList(w,S),this.info.render.frame++,this.info.autoReset===!0&&this.info.reset(),Oe===!0&&Le.beginShadows();const X=E.state.shadowsArray;if(Fe.render(X,S,U),Oe===!0&&Le.endShadows(),(W&&T.hasRenderPass())===!1){const xe=w.opaque,me=w.transmissive;if(E.setupLights(),U.isArrayCamera){const Se=U.cameras;if(me.length>0)for(let De=0,Ve=Se.length;De<Ve;De++){const Ye=Se[De];Ju(xe,me,S,Ye)}Lt&&Ge.render(S);for(let De=0,Ve=Se.length;De<Ve;De++){const Ye=Se[De];Zu(w,S,Ye,Ye.viewport)}}else me.length>0&&Ju(xe,me,S,U),Lt&&Ge.render(S),Zu(w,S,U)}V!==null&&F===0&&(Z.updateMultisampleRenderTarget(V),Z.updateRenderTargetMipmap(V)),W&&T.end(A),S.isScene===!0&&S.onAfterRender(A,S,U),ve.resetDefaultState(),j=-1,$=null,y.pop(),y.length>0?(E=y[y.length-1],Z.setTextureUnits(E.state.textureUnits),Oe===!0&&Le.setGlobalState(A.clippingPlanes,E.state.camera)):E=null,D.pop(),D.length>0?w=D[D.length-1]:w=null,R!==null&&R.renderEnd()};function hc(S,U,Y,W){if(S.visible===!1)return;if(S.layers.test(U.layers)){if(S.isGroup)Y=S.renderOrder;else if(S.isLOD)S.autoUpdate===!0&&S.update(U);else if(S.isLightProbeGrid)E.pushLightProbeGrid(S);else if(S.isLight)E.pushLight(S),S.castShadow&&E.pushShadow(S);else if(S.isSprite){if(!S.frustumCulled||Ne.intersectsSprite(S)){W&&Pt.setFromMatrixPosition(S.matrixWorld).applyMatrix4(rt);const xe=ee.update(S),me=S.material;me.visible&&w.push(S,xe,me,Y,Pt.z,null)}}else if((S.isMesh||S.isLine||S.isPoints)&&(!S.frustumCulled||Ne.intersectsObject(S))){const xe=ee.update(S),me=S.material;if(W&&(S.boundingSphere!==void 0?(S.boundingSphere===null&&S.computeBoundingSphere(),Pt.copy(S.boundingSphere.center)):(xe.boundingSphere===null&&xe.computeBoundingSphere(),Pt.copy(xe.boundingSphere.center)),Pt.applyMatrix4(S.matrixWorld).applyMatrix4(rt)),Array.isArray(me)){const Se=xe.groups;for(let De=0,Ve=Se.length;De<Ve;De++){const Ye=Se[De],Ce=me[Ye.materialIndex];Ce&&Ce.visible&&w.push(S,xe,Ce,Y,Pt.z,Ye)}}else me.visible&&w.push(S,xe,me,Y,Pt.z,null)}}const ge=S.children;for(let xe=0,me=ge.length;xe<me;xe++)hc(ge[xe],U,Y,W)}function Zu(S,U,Y,W){const{opaque:X,transmissive:ge,transparent:xe}=S;E.setupLightsView(Y),Oe===!0&&Le.setGlobalState(A.clippingPlanes,Y),W&&b.viewport(ne.copy(W)),X.length>0&&uo(X,U,Y),ge.length>0&&uo(ge,U,Y),xe.length>0&&uo(xe,U,Y),b.buffers.depth.setTest(!0),b.buffers.depth.setMask(!0),b.buffers.color.setMask(!0),b.setPolygonOffset(!1)}function Ju(S,U,Y,W){if((Y.isScene===!0?Y.overrideMaterial:null)!==null)return;if(E.state.transmissionRenderTarget[W.id]===void 0){const Ce=lt.has("EXT_color_buffer_half_float")||lt.has("EXT_color_buffer_float");E.state.transmissionRenderTarget[W.id]=new In(1,1,{generateMipmaps:!0,type:Ce?pn:Bn,minFilter:Vs,samples:Math.max(4,C.samples),stencilBuffer:s,resolveDepthBuffer:!1,resolveStencilBuffer:!1,colorSpace:Qe.workingColorSpace})}const ge=E.state.transmissionRenderTarget[W.id],xe=W.viewport||ne;ge.setSize(xe.z*A.transmissionResolutionScale,xe.w*A.transmissionResolutionScale);const me=A.getRenderTarget(),Se=A.getActiveCubeFace(),De=A.getActiveMipmapLevel();A.setRenderTarget(ge),A.getClearColor(Ze),ze=A.getClearAlpha(),ze<1&&A.setClearColor(16777215,.5),A.clear(),Lt&&Ge.render(Y);const Ve=A.toneMapping;A.toneMapping=Ii;const Ye=W.viewport;if(W.viewport!==void 0&&(W.viewport=void 0),E.setupLightsView(W),Oe===!0&&Le.setGlobalState(A.clippingPlanes,W),uo(S,Y,W),Z.updateMultisampleRenderTarget(ge),Z.updateRenderTargetMipmap(ge),lt.has("WEBGL_multisampled_render_to_texture")===!1){let Ce=!1;for(let ut=0,Ut=U.length;ut<Ut;ut++){const Ot=U[ut],{object:mt,geometry:on,material:ye,group:Dn}=Ot;if(ye.side===Qn&&mt.layers.test(W.layers)){const tt=ye.side;ye.side=Vt,ye.needsUpdate=!0,ju(mt,Y,W,on,ye,Dn),ye.side=tt,ye.needsUpdate=!0,Ce=!0}}Ce===!0&&(Z.updateMultisampleRenderTarget(ge),Z.updateRenderTargetMipmap(ge))}A.setRenderTarget(me,Se,De),A.setClearColor(Ze,ze),Ye!==void 0&&(W.viewport=Ye),A.toneMapping=Ve}function uo(S,U,Y){const W=U.isScene===!0?U.overrideMaterial:null;for(let X=0,ge=S.length;X<ge;X++){const xe=S[X],{object:me,geometry:Se,group:De}=xe;let Ve=xe.material;Ve.allowOverride===!0&&W!==null&&(Ve=W),me.layers.test(Y.layers)&&ju(me,U,Y,Se,Ve,De)}}function ju(S,U,Y,W,X,ge){S.onBeforeRender(A,U,Y,W,X,ge),S.modelViewMatrix.multiplyMatrices(Y.matrixWorldInverse,S.matrixWorld),S.normalMatrix.getNormalMatrix(S.modelViewMatrix),X.onBeforeRender(A,U,Y,W,S,ge),X.transparent===!0&&X.side===Qn&&X.forceSinglePass===!1?(X.side=Vt,X.needsUpdate=!0,A.renderBufferDirect(Y,U,W,X,S,ge),X.side=Ms,X.needsUpdate=!0,A.renderBufferDirect(Y,U,W,X,S,ge),X.side=Qn):A.renderBufferDirect(Y,U,W,X,S,ge),S.onAfterRender(A,U,Y,W,X,ge)}function fo(S,U,Y){U.isScene!==!0&&(U=wt);const W=q.get(S),X=E.state.lights,ge=E.state.shadowsArray,xe=X.state.version,me=he.getParameters(S,X.state,ge,U,Y,E.state.lightProbeGridArray),Se=he.getProgramCacheKey(me);let De=W.programs;W.environment=S.isMeshStandardMaterial||S.isMeshLambertMaterial||S.isMeshPhongMaterial?U.environment:null,W.fog=U.fog;const Ve=S.isMeshStandardMaterial||S.isMeshLambertMaterial&&!S.envMap||S.isMeshPhongMaterial&&!S.envMap;W.envMap=se.get(S.envMap||W.environment,Ve),W.envMapRotation=W.environment!==null&&S.envMap===null?U.environmentRotation:S.envMapRotation,De===void 0&&(S.addEventListener("dispose",ci),De=new Map,W.programs=De);let Ye=De.get(Se);if(Ye!==void 0){if(W.currentProgram===Ye&&W.lightsStateVersion===xe)return ef(S,me),Ye}else me.uniforms=he.getUniforms(S),R!==null&&S.isNodeMaterial&&R.build(S,Y,me),S.onBeforeCompile(me,A),Ye=he.acquireProgram(me,Se),De.set(Se,Ye),W.uniforms=me.uniforms;const Ce=W.uniforms;return(!S.isShaderMaterial&&!S.isRawShaderMaterial||S.clipping===!0)&&(Ce.clippingPlanes=Le.uniform),ef(S,me),W.needsLights=fv(S),W.lightsStateVersion=xe,W.needsLights&&(Ce.ambientLightColor.value=X.state.ambient,Ce.lightProbe.value=X.state.probe,Ce.directionalLights.value=X.state.directional,Ce.directionalLightShadows.value=X.state.directionalShadow,Ce.spotLights.value=X.state.spot,Ce.spotLightShadows.value=X.state.spotShadow,Ce.rectAreaLights.value=X.state.rectArea,Ce.ltc_1.value=X.state.rectAreaLTC1,Ce.ltc_2.value=X.state.rectAreaLTC2,Ce.pointLights.value=X.state.point,Ce.pointLightShadows.value=X.state.pointShadow,Ce.hemisphereLights.value=X.state.hemi,Ce.directionalShadowMatrix.value=X.state.directionalShadowMatrix,Ce.spotLightMatrix.value=X.state.spotLightMatrix,Ce.spotLightMap.value=X.state.spotLightMap,Ce.pointShadowMatrix.value=X.state.pointShadowMatrix),W.lightProbeGrid=E.state.lightProbeGridArray.length>0,W.currentProgram=Ye,W.uniformsList=null,Ye}function Qu(S){if(S.uniformsList===null){const U=S.currentProgram.getUniforms();S.uniformsList=Ml.seqWithValue(U.seq,S.uniforms)}return S.uniformsList}function ef(S,U){const Y=q.get(S);Y.outputColorSpace=U.outputColorSpace,Y.batching=U.batching,Y.batchingColor=U.batchingColor,Y.instancing=U.instancing,Y.instancingColor=U.instancingColor,Y.instancingMorph=U.instancingMorph,Y.skinning=U.skinning,Y.morphTargets=U.morphTargets,Y.morphNormals=U.morphNormals,Y.morphColors=U.morphColors,Y.morphTargetsCount=U.morphTargetsCount,Y.numClippingPlanes=U.numClippingPlanes,Y.numIntersection=U.numClipIntersection,Y.vertexAlphas=U.vertexAlphas,Y.vertexTangents=U.vertexTangents,Y.toneMapping=U.toneMapping}function hv(S,U){if(S.length===0)return null;if(S.length===1)return S[0].texture!==null?S[0]:null;x.setFromMatrixPosition(U.matrixWorld);for(let Y=0,W=S.length;Y<W;Y++){const X=S[Y];if(X.texture!==null&&X.boundingBox.containsPoint(x))return X}return null}function dv(S,U,Y,W,X){U.isScene!==!0&&(U=wt),Z.resetTextureUnits();const ge=U.fog,xe=W.isMeshStandardMaterial||W.isMeshLambertMaterial||W.isMeshPhongMaterial?U.environment:null,me=V===null?A.outputColorSpace:V.isXRRenderTarget===!0?V.texture.colorSpace:Qe.workingColorSpace,Se=W.isMeshStandardMaterial||W.isMeshLambertMaterial&&!W.envMap||W.isMeshPhongMaterial&&!W.envMap,De=se.get(W.envMap||xe,Se),Ve=W.vertexColors===!0&&!!Y.attributes.color&&Y.attributes.color.itemSize===4,Ye=!!Y.attributes.tangent&&(!!W.normalMap||W.anisotropy>0),Ce=!!Y.morphAttributes.position,ut=!!Y.morphAttributes.normal,Ut=!!Y.morphAttributes.color;let Ot=Ii;W.toneMapped&&(V===null||V.isXRRenderTarget===!0)&&(Ot=A.toneMapping);const mt=Y.morphAttributes.position||Y.morphAttributes.normal||Y.morphAttributes.color,on=mt!==void 0?mt.length:0,ye=q.get(W),Dn=E.state.lights;if(Oe===!0&&(ke===!0||S!==$)){const bt=S===$&&W.id===j;Le.setState(W,S,bt)}let tt=!1;W.version===ye.__version?(ye.needsLights&&ye.lightsStateVersion!==Dn.state.version||ye.outputColorSpace!==me||X.isBatchedMesh&&ye.batching===!1||!X.isBatchedMesh&&ye.batching===!0||X.isBatchedMesh&&ye.batchingColor===!0&&X.colorTexture===null||X.isBatchedMesh&&ye.batchingColor===!1&&X.colorTexture!==null||X.isInstancedMesh&&ye.instancing===!1||!X.isInstancedMesh&&ye.instancing===!0||X.isSkinnedMesh&&ye.skinning===!1||!X.isSkinnedMesh&&ye.skinning===!0||X.isInstancedMesh&&ye.instancingColor===!0&&X.instanceColor===null||X.isInstancedMesh&&ye.instancingColor===!1&&X.instanceColor!==null||X.isInstancedMesh&&ye.instancingMorph===!0&&X.morphTexture===null||X.isInstancedMesh&&ye.instancingMorph===!1&&X.morphTexture!==null||ye.envMap!==De||W.fog===!0&&ye.fog!==ge||ye.numClippingPlanes!==void 0&&(ye.numClippingPlanes!==Le.numPlanes||ye.numIntersection!==Le.numIntersection)||ye.vertexAlphas!==Ve||ye.vertexTangents!==Ye||ye.morphTargets!==Ce||ye.morphNormals!==ut||ye.morphColors!==Ut||ye.toneMapping!==Ot||ye.morphTargetsCount!==on||!!ye.lightProbeGrid!=E.state.lightProbeGridArray.length>0)&&(tt=!0):(tt=!0,ye.__version=W.version);let zn=ye.currentProgram;tt===!0&&(zn=fo(W,U,X),R&&W.isNodeMaterial&&R.onUpdateProgram(W,zn,ye));let hi=!1,ts=!1,ea=!1;const gt=zn.getUniforms(),Bt=ye.uniforms;if(b.useProgram(zn.program)&&(hi=!0,ts=!0,ea=!0),W.id!==j&&(j=W.id,ts=!0),ye.needsLights){const bt=hv(E.state.lightProbeGridArray,X);ye.lightProbeGrid!==bt&&(ye.lightProbeGrid=bt,ts=!0)}if(hi||$!==S){b.buffers.depth.getReversed()&&S.reversedDepth!==!0&&(S._reversedDepth=!0,S.updateProjectionMatrix()),gt.setValue(k,"projectionMatrix",S.projectionMatrix),gt.setValue(k,"viewMatrix",S.matrixWorldInverse);const is=gt.map.cameraPosition;is!==void 0&&is.setValue(k,ot.setFromMatrixPosition(S.matrixWorld)),C.logarithmicDepthBuffer&>.setValue(k,"logDepthBufFC",2/(Math.log(S.far+1)/Math.LN2)),(W.isMeshPhongMaterial||W.isMeshToonMaterial||W.isMeshLambertMaterial||W.isMeshBasicMaterial||W.isMeshStandardMaterial||W.isShaderMaterial)&>.setValue(k,"isOrthographic",S.isOrthographicCamera===!0),$!==S&&($=S,ts=!0,ea=!0)}if(ye.needsLights&&(Dn.state.directionalShadowMap.length>0&>.setValue(k,"directionalShadowMap",Dn.state.directionalShadowMap,Z),Dn.state.spotShadowMap.length>0&>.setValue(k,"spotShadowMap",Dn.state.spotShadowMap,Z),Dn.state.pointShadowMap.length>0&>.setValue(k,"pointShadowMap",Dn.state.pointShadowMap,Z)),X.isSkinnedMesh){gt.setOptional(k,X,"bindMatrix"),gt.setOptional(k,X,"bindMatrixInverse");const bt=X.skeleton;bt&&(bt.boneTexture===null&&bt.computeBoneTexture(),gt.setValue(k,"boneTexture",bt.boneTexture,Z))}X.isBatchedMesh&&(gt.setOptional(k,X,"batchingTexture"),gt.setValue(k,"batchingTexture",X._matricesTexture,Z),gt.setOptional(k,X,"batchingIdTexture"),gt.setValue(k,"batchingIdTexture",X._indirectTexture,Z),gt.setOptional(k,X,"batchingColorTexture"),X._colorsTexture!==null&>.setValue(k,"batchingColorTexture",X._colorsTexture,Z));const ns=Y.morphAttributes;if((ns.position!==void 0||ns.normal!==void 0||ns.color!==void 0)&&O.update(X,Y,zn),(ts||ye.receiveShadow!==X.receiveShadow)&&(ye.receiveShadow=X.receiveShadow,gt.setValue(k,"receiveShadow",X.receiveShadow)),(W.isMeshStandardMaterial||W.isMeshLambertMaterial||W.isMeshPhongMaterial)&&W.envMap===null&&U.environment!==null&&(Bt.envMapIntensity.value=U.environmentIntensity),Bt.dfgLUT!==void 0&&(Bt.dfgLUT.value=zS()),ts){if(gt.setValue(k,"toneMappingExposure",A.toneMappingExposure),ye.needsLights&&uv(Bt,ea),ge&&W.fog===!0&&Ie.refreshFogUniforms(Bt,ge),Ie.refreshMaterialUniforms(Bt,W,ie,ae,E.state.transmissionRenderTarget[S.id]),ye.needsLights&&ye.lightProbeGrid){const bt=ye.lightProbeGrid;Bt.probesSH.value=bt.texture,Bt.probesMin.value.copy(bt.boundingBox.min),Bt.probesMax.value.copy(bt.boundingBox.max),Bt.probesResolution.value.copy(bt.resolution)}Ml.upload(k,Qu(ye),Bt,Z)}if(W.isShaderMaterial&&W.uniformsNeedUpdate===!0&&(Ml.upload(k,Qu(ye),Bt,Z),W.uniformsNeedUpdate=!1),W.isSpriteMaterial&>.setValue(k,"center",X.center),gt.setValue(k,"modelViewMatrix",X.modelViewMatrix),gt.setValue(k,"normalMatrix",X.normalMatrix),gt.setValue(k,"modelMatrix",X.matrixWorld),W.uniformsGroups!==void 0){const bt=W.uniformsGroups;for(let is=0,ta=bt.length;is<ta;is++){const tf=bt[is];te.update(tf,zn),te.bind(tf,zn)}}return zn}function uv(S,U){S.ambientLightColor.needsUpdate=U,S.lightProbe.needsUpdate=U,S.directionalLights.needsUpdate=U,S.directionalLightShadows.needsUpdate=U,S.pointLights.needsUpdate=U,S.pointLightShadows.needsUpdate=U,S.spotLights.needsUpdate=U,S.spotLightShadows.needsUpdate=U,S.rectAreaLights.needsUpdate=U,S.hemisphereLights.needsUpdate=U}function fv(S){return S.isMeshLambertMaterial||S.isMeshToonMaterial||S.isMeshPhongMaterial||S.isMeshStandardMaterial||S.isShadowMaterial||S.isShaderMaterial&&S.lights===!0}this.getActiveCubeFace=function(){return B},this.getActiveMipmapLevel=function(){return F},this.getRenderTarget=function(){return V},this.setRenderTargetTextures=function(S,U,Y){const W=q.get(S);W.__autoAllocateDepthBuffer=S.resolveDepthBuffer===!1,W.__autoAllocateDepthBuffer===!1&&(W.__useRenderToTexture=!1),q.get(S.texture).__webglTexture=U,q.get(S.depthTexture).__webglTexture=W.__autoAllocateDepthBuffer?void 0:Y,W.__hasExternalTextures=!0},this.setRenderTargetFramebuffer=function(S,U){const Y=q.get(S);Y.__webglFramebuffer=U,Y.__useDefaultFramebuffer=U===void 0},this.setRenderTarget=function(S,U=0,Y=0){V=S,B=U,F=Y;let W=null,X=!1,ge=!1;if(S){const me=q.get(S);if(me.__useDefaultFramebuffer!==void 0){b.bindFramebuffer(k.FRAMEBUFFER,me.__webglFramebuffer),ne.copy(S.viewport),re.copy(S.scissor),He=S.scissorTest,b.viewport(ne),b.scissor(re),b.setScissorTest(He),j=-1;return}else if(me.__webglFramebuffer===void 0)Z.setupRenderTarget(S);else if(me.__hasExternalTextures)Z.rebindTextures(S,q.get(S.texture).__webglTexture,q.get(S.depthTexture).__webglTexture);else if(S.depthBuffer){const Ve=S.depthTexture;if(me.__boundDepthTexture!==Ve){if(Ve!==null&&q.has(Ve)&&(S.width!==Ve.image.width||S.height!==Ve.image.height))throw new Error("THREE.WebGLRenderer: Attached DepthTexture is initialized to the incorrect size.");Z.setupDepthRenderbuffer(S)}}const Se=S.texture;(Se.isData3DTexture||Se.isDataArrayTexture||Se.isCompressedArrayTexture)&&(ge=!0);const De=q.get(S).__webglFramebuffer;S.isWebGLCubeRenderTarget?(Array.isArray(De[U])?W=De[U][Y]:W=De[U],X=!0):S.samples>0&&Z.useMultisampledRTT(S)===!1?W=q.get(S).__webglMultisampledFramebuffer:Array.isArray(De)?W=De[Y]:W=De,ne.copy(S.viewport),re.copy(S.scissor),He=S.scissorTest}else ne.copy(Pe).multiplyScalar(ie).floor(),re.copy(Ae).multiplyScalar(ie).floor(),He=be;if(Y!==0&&(W=N),b.bindFramebuffer(k.FRAMEBUFFER,W)&&b.drawBuffers(S,W),b.viewport(ne),b.scissor(re),b.setScissorTest(He),X){const me=q.get(S.texture);k.framebufferTexture2D(k.FRAMEBUFFER,k.COLOR_ATTACHMENT0,k.TEXTURE_CUBE_MAP_POSITIVE_X+U,me.__webglTexture,Y)}else if(ge){const me=U;for(let Se=0;Se<S.textures.length;Se++){const De=q.get(S.textures[Se]);k.framebufferTextureLayer(k.FRAMEBUFFER,k.COLOR_ATTACHMENT0+Se,De.__webglTexture,Y,me)}}else if(S!==null&&Y!==0){const me=q.get(S.texture);k.framebufferTexture2D(k.FRAMEBUFFER,k.COLOR_ATTACHMENT0,k.TEXTURE_2D,me.__webglTexture,Y)}j=-1},this.readRenderTargetPixels=function(S,U,Y,W,X,ge,xe,me=0){if(!(S&&S.isWebGLRenderTarget)){Ue("WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");return}let Se=q.get(S).__webglFramebuffer;if(S.isWebGLCubeRenderTarget&&xe!==void 0&&(Se=Se[xe]),Se){b.bindFramebuffer(k.FRAMEBUFFER,Se);try{const De=S.textures[me],Ve=De.format,Ye=De.type;if(S.textures.length>1&&k.readBuffer(k.COLOR_ATTACHMENT0+me),!C.textureFormatReadable(Ve)){Ue("WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.");return}if(!C.textureTypeReadable(Ye)){Ue("WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.");return}U>=0&&U<=S.width-W&&Y>=0&&Y<=S.height-X&&k.readPixels(U,Y,W,X,ue.convert(Ve),ue.convert(Ye),ge)}finally{const De=V!==null?q.get(V).__webglFramebuffer:null;b.bindFramebuffer(k.FRAMEBUFFER,De)}}},this.readRenderTargetPixelsAsync=async function(S,U,Y,W,X,ge,xe,me=0){if(!(S&&S.isWebGLRenderTarget))throw new Error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let Se=q.get(S).__webglFramebuffer;if(S.isWebGLCubeRenderTarget&&xe!==void 0&&(Se=Se[xe]),Se)if(U>=0&&U<=S.width-W&&Y>=0&&Y<=S.height-X){b.bindFramebuffer(k.FRAMEBUFFER,Se);const De=S.textures[me],Ve=De.format,Ye=De.type;if(S.textures.length>1&&k.readBuffer(k.COLOR_ATTACHMENT0+me),!C.textureFormatReadable(Ve))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.");if(!C.textureTypeReadable(Ye))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.");const Ce=k.createBuffer();k.bindBuffer(k.PIXEL_PACK_BUFFER,Ce),k.bufferData(k.PIXEL_PACK_BUFFER,ge.byteLength,k.STREAM_READ),k.readPixels(U,Y,W,X,ue.convert(Ve),ue.convert(Ye),0);const ut=V!==null?q.get(V).__webglFramebuffer:null;b.bindFramebuffer(k.FRAMEBUFFER,ut);const Ut=k.fenceSync(k.SYNC_GPU_COMMANDS_COMPLETE,0);return k.flush(),await py(k,Ut,4),k.bindBuffer(k.PIXEL_PACK_BUFFER,Ce),k.getBufferSubData(k.PIXEL_PACK_BUFFER,0,ge),k.deleteBuffer(Ce),k.deleteSync(Ut),ge}else throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.")},this.copyFramebufferToTexture=function(S,U=null,Y=0){const W=Math.pow(2,-Y),X=Math.floor(S.image.width*W),ge=Math.floor(S.image.height*W),xe=U!==null?U.x:0,me=U!==null?U.y:0;Z.setTexture2D(S,0),k.copyTexSubImage2D(k.TEXTURE_2D,Y,0,0,xe,me,X,ge),b.unbindTexture()},this.copyTextureToTexture=function(S,U,Y=null,W=null,X=0,ge=0){let xe,me,Se,De,Ve,Ye,Ce,ut,Ut;const Ot=S.isCompressedTexture?S.mipmaps[ge]:S.image;if(Y!==null)xe=Y.max.x-Y.min.x,me=Y.max.y-Y.min.y,Se=Y.isBox3?Y.max.z-Y.min.z:1,De=Y.min.x,Ve=Y.min.y,Ye=Y.isBox3?Y.min.z:0;else{const Bt=Math.pow(2,-X);xe=Math.floor(Ot.width*Bt),me=Math.floor(Ot.height*Bt),S.isDataArrayTexture?Se=Ot.depth:S.isData3DTexture?Se=Math.floor(Ot.depth*Bt):Se=1,De=0,Ve=0,Ye=0}W!==null?(Ce=W.x,ut=W.y,Ut=W.z):(Ce=0,ut=0,Ut=0);const mt=ue.convert(U.format),on=ue.convert(U.type);let ye;U.isData3DTexture?(Z.setTexture3D(U,0),ye=k.TEXTURE_3D):U.isDataArrayTexture||U.isCompressedArrayTexture?(Z.setTexture2DArray(U,0),ye=k.TEXTURE_2D_ARRAY):(Z.setTexture2D(U,0),ye=k.TEXTURE_2D),b.activeTexture(k.TEXTURE0),b.pixelStorei(k.UNPACK_FLIP_Y_WEBGL,U.flipY),b.pixelStorei(k.UNPACK_PREMULTIPLY_ALPHA_WEBGL,U.premultiplyAlpha),b.pixelStorei(k.UNPACK_ALIGNMENT,U.unpackAlignment);const Dn=b.getParameter(k.UNPACK_ROW_LENGTH),tt=b.getParameter(k.UNPACK_IMAGE_HEIGHT),zn=b.getParameter(k.UNPACK_SKIP_PIXELS),hi=b.getParameter(k.UNPACK_SKIP_ROWS),ts=b.getParameter(k.UNPACK_SKIP_IMAGES);b.pixelStorei(k.UNPACK_ROW_LENGTH,Ot.width),b.pixelStorei(k.UNPACK_IMAGE_HEIGHT,Ot.height),b.pixelStorei(k.UNPACK_SKIP_PIXELS,De),b.pixelStorei(k.UNPACK_SKIP_ROWS,Ve),b.pixelStorei(k.UNPACK_SKIP_IMAGES,Ye);const ea=S.isDataArrayTexture||S.isData3DTexture,gt=U.isDataArrayTexture||U.isData3DTexture;if(S.isDepthTexture){const Bt=q.get(S),ns=q.get(U),bt=q.get(Bt.__renderTarget),is=q.get(ns.__renderTarget);b.bindFramebuffer(k.READ_FRAMEBUFFER,bt.__webglFramebuffer),b.bindFramebuffer(k.DRAW_FRAMEBUFFER,is.__webglFramebuffer);for(let ta=0;ta<Se;ta++)ea&&(k.framebufferTextureLayer(k.READ_FRAMEBUFFER,k.COLOR_ATTACHMENT0,q.get(S).__webglTexture,X,Ye+ta),k.framebufferTextureLayer(k.DRAW_FRAMEBUFFER,k.COLOR_ATTACHMENT0,q.get(U).__webglTexture,ge,Ut+ta)),k.blitFramebuffer(De,Ve,xe,me,Ce,ut,xe,me,k.DEPTH_BUFFER_BIT,k.NEAREST);b.bindFramebuffer(k.READ_FRAMEBUFFER,null),b.bindFramebuffer(k.DRAW_FRAMEBUFFER,null)}else if(X!==0||S.isRenderTargetTexture||q.has(S)){const Bt=q.get(S),ns=q.get(U);b.bindFramebuffer(k.READ_FRAMEBUFFER,z),b.bindFramebuffer(k.DRAW_FRAMEBUFFER,L);for(let bt=0;bt<Se;bt++)ea?k.framebufferTextureLayer(k.READ_FRAMEBUFFER,k.COLOR_ATTACHMENT0,Bt.__webglTexture,X,Ye+bt):k.framebufferTexture2D(k.READ_FRAMEBUFFER,k.COLOR_ATTACHMENT0,k.TEXTURE_2D,Bt.__webglTexture,X),gt?k.framebufferTextureLayer(k.DRAW_FRAMEBUFFER,k.COLOR_ATTACHMENT0,ns.__webglTexture,ge,Ut+bt):k.framebufferTexture2D(k.DRAW_FRAMEBUFFER,k.COLOR_ATTACHMENT0,k.TEXTURE_2D,ns.__webglTexture,ge),X!==0?k.blitFramebuffer(De,Ve,xe,me,Ce,ut,xe,me,k.COLOR_BUFFER_BIT,k.NEAREST):gt?k.copyTexSubImage3D(ye,ge,Ce,ut,Ut+bt,De,Ve,xe,me):k.copyTexSubImage2D(ye,ge,Ce,ut,De,Ve,xe,me);b.bindFramebuffer(k.READ_FRAMEBUFFER,null),b.bindFramebuffer(k.DRAW_FRAMEBUFFER,null)}else gt?S.isDataTexture||S.isData3DTexture?k.texSubImage3D(ye,ge,Ce,ut,Ut,xe,me,Se,mt,on,Ot.data):U.isCompressedArrayTexture?k.compressedTexSubImage3D(ye,ge,Ce,ut,Ut,xe,me,Se,mt,Ot.data):k.texSubImage3D(ye,ge,Ce,ut,Ut,xe,me,Se,mt,on,Ot):S.isDataTexture?k.texSubImage2D(k.TEXTURE_2D,ge,Ce,ut,xe,me,mt,on,Ot.data):S.isCompressedTexture?k.compressedTexSubImage2D(k.TEXTURE_2D,ge,Ce,ut,Ot.width,Ot.height,mt,Ot.data):k.texSubImage2D(k.TEXTURE_2D,ge,Ce,ut,xe,me,mt,on,Ot);b.pixelStorei(k.UNPACK_ROW_LENGTH,Dn),b.pixelStorei(k.UNPACK_IMAGE_HEIGHT,tt),b.pixelStorei(k.UNPACK_SKIP_PIXELS,zn),b.pixelStorei(k.UNPACK_SKIP_ROWS,hi),b.pixelStorei(k.UNPACK_SKIP_IMAGES,ts),ge===0&&U.generateMipmaps&&k.generateMipmap(ye),b.unbindTexture()},this.initRenderTarget=function(S){q.get(S).__webglFramebuffer===void 0&&Z.setupRenderTarget(S)},this.initTexture=function(S){S.isCubeTexture?Z.setTextureCube(S,0):S.isData3DTexture?Z.setTexture3D(S,0):S.isDataArrayTexture||S.isCompressedArrayTexture?Z.setTexture2DArray(S,0):Z.setTexture2D(S,0),b.unbindTexture()},this.resetState=function(){B=0,F=0,V=null,b.reset(),ve.reset()},typeof __THREE_DEVTOOLS__<"u"&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}get coordinateSystem(){return Ei}get outputColorSpace(){return this._outputColorSpace}set outputColorSpace(e){this._outputColorSpace=e;const t=this.getContext();t.drawingBufferColorSpace=Qe._getDrawingBufferColorSpace(e),t.unpackColorSpace=Qe._getUnpackColorSpace()}}const GS=`
|
|
6018
6049
|
varying vec3 vDir;
|
|
6019
6050
|
|
|
6020
6051
|
void main() {
|
|
@@ -6201,7 +6232,7 @@ void main() {
|
|
|
6201
6232
|
|
|
6202
6233
|
gl_FragColor = vec4(color, alpha);
|
|
6203
6234
|
}
|
|
6204
|
-
`;function Od(a,e,t,n=0){const i={sunDir:{value:new P(0,1,0)},sunColor:{value:new le(1,1,1)},ambientColor:{value:new le(.5,.5,.5)},baseColor:{value:a},coverage:{value:e},opticalDensity:{value:1},darkness:{value:0},layerHeight:{value:t},fieldOffset:{value:new P},fibrous:{value:n}};return{material:new Rt({uniforms:i,vertexShader:GS,fragmentShader:qS,transparent:!0,depthWrite:!1,depthTest:!0,side:Vt}),uniforms:i}}function kd(a){return new mn(a,48,24,0,Math.PI*2,0,Math.PI/2)}class kt{static OCTAVES=4;static GAIN=.55;static LACUNARITY=2.03;static fract(e){return e-Math.floor(e)}static hash3(e,t,n){const i=e*127.1+t*311.7+n*74.7,s=e*269.5+t*183.3+n*246.1,r=e*113.5+t*271.9+n*124.6;return[kt.fract(Math.sin(i)*43758.5453)*2-1,kt.fract(Math.sin(s)*43758.5453)*2-1,kt.fract(Math.sin(r)*43758.5453)*2-1]}static noise3D(e,t,n){const i=Math.floor(e),s=Math.floor(t),r=Math.floor(n),o=e-i,l=t-s,c=n-r,h=o*o*(3-2*o),d=l*l*(3-2*l),u=c*c*(3-2*c),f=(v,m,g)=>{const[_,M,x]=kt.hash3(i+v,s+m,r+g);return _*(o-v)+M*(l-m)+x*(c-g)},p=(v,m,g)=>v+(m-v)*g;return p(p(p(f(0,0,0),f(1,0,0),h),p(f(0,1,0),f(1,1,0),h),d),p(p(f(0,0,1),f(1,0,1),h),p(f(0,1,1),f(1,1,1),h),d),u)}static thresholdFor(e,t,n){const i=Math.min(.999,Math.max(.001,e));return t-n*(Math.sqrt(3)/Math.PI)*Math.log(i/(1-i))}static fbm(e,t,n){let i=0,s=kt.GAIN;for(let r=0;r<kt.OCTAVES;r++)i+=kt.noise3D(e,t,n)*s,e*=kt.LACUNARITY,t*=kt.LACUNARITY,n*=kt.LACUNARITY,s*=kt.GAIN;return i}static worley(e,t,n){const i=Math.floor(e),s=Math.floor(t),r=Math.floor(n),o=e-i,l=t-s,c=n-r;let h=1/0;for(let d=-1;d<=1;d++)for(let u=-1;u<=1;u++)for(let f=-1;f<=1;f++){const[p,v,m]=kt.hash3(i+d,s+u,r+f),g=d+(p*.5+.5)-o,_=u+(v*.5+.5)-l,M=f+(m*.5+.5)-c;h=Math.min(h,g*g+_*_+M*M)}return Math.sqrt(h)}static alphaAt(e,t,n,i={x:0,z:0}){if(n<=0)return 0;const s=Math.abs(e.y),r=t/Math.max(s,.04),o=e.x*r+i.x,l=e.y*r,c=e.z*r+i.z,h=o*.006,d=l*.006,u=c*.006,f=o+kt.fbm(h+12.3,d+12.3,u+12.3)*40,p=l+kt.fbm(h+47.1,d+47.1,u+47.1)*40,v=c+kt.fbm(h+91.7,d+91.7,u+91.7)*40,m=kt.fbm(f*.014,p*.014,v*.014)*.5+.5,g=1-kt.worley(f*.011,p*.011,v*.011),_=m+(g-m)*.4,M=kt.thresholdFor(n,wg,Mg),x=(E,D,y)=>{const T=Math.min(1,Math.max(0,(y-E)/(D-E)));return T*T*(3-2*T)},w=x(M-.08,M+.08,_);return w+(1-w)*x(.82,1,n)}}const Oa=6371e3,
|
|
6235
|
+
`;function Od(a,e,t,n=0){const i={sunDir:{value:new P(0,1,0)},sunColor:{value:new le(1,1,1)},ambientColor:{value:new le(.5,.5,.5)},baseColor:{value:a},coverage:{value:e},opticalDensity:{value:1},darkness:{value:0},layerHeight:{value:t},fieldOffset:{value:new P},fibrous:{value:n}};return{material:new Rt({uniforms:i,vertexShader:GS,fragmentShader:qS,transparent:!0,depthWrite:!1,depthTest:!0,side:Vt}),uniforms:i}}function kd(a){return new mn(a,48,24,0,Math.PI*2,0,Math.PI/2)}class kt{static OCTAVES=4;static GAIN=.55;static LACUNARITY=2.03;static fract(e){return e-Math.floor(e)}static hash3(e,t,n){const i=e*127.1+t*311.7+n*74.7,s=e*269.5+t*183.3+n*246.1,r=e*113.5+t*271.9+n*124.6;return[kt.fract(Math.sin(i)*43758.5453)*2-1,kt.fract(Math.sin(s)*43758.5453)*2-1,kt.fract(Math.sin(r)*43758.5453)*2-1]}static noise3D(e,t,n){const i=Math.floor(e),s=Math.floor(t),r=Math.floor(n),o=e-i,l=t-s,c=n-r,h=o*o*(3-2*o),d=l*l*(3-2*l),u=c*c*(3-2*c),f=(v,m,g)=>{const[_,M,x]=kt.hash3(i+v,s+m,r+g);return _*(o-v)+M*(l-m)+x*(c-g)},p=(v,m,g)=>v+(m-v)*g;return p(p(p(f(0,0,0),f(1,0,0),h),p(f(0,1,0),f(1,1,0),h),d),p(p(f(0,0,1),f(1,0,1),h),p(f(0,1,1),f(1,1,1),h),d),u)}static thresholdFor(e,t,n){const i=Math.min(.999,Math.max(.001,e));return t-n*(Math.sqrt(3)/Math.PI)*Math.log(i/(1-i))}static fbm(e,t,n){let i=0,s=kt.GAIN;for(let r=0;r<kt.OCTAVES;r++)i+=kt.noise3D(e,t,n)*s,e*=kt.LACUNARITY,t*=kt.LACUNARITY,n*=kt.LACUNARITY,s*=kt.GAIN;return i}static worley(e,t,n){const i=Math.floor(e),s=Math.floor(t),r=Math.floor(n),o=e-i,l=t-s,c=n-r;let h=1/0;for(let d=-1;d<=1;d++)for(let u=-1;u<=1;u++)for(let f=-1;f<=1;f++){const[p,v,m]=kt.hash3(i+d,s+u,r+f),g=d+(p*.5+.5)-o,_=u+(v*.5+.5)-l,M=f+(m*.5+.5)-c;h=Math.min(h,g*g+_*_+M*M)}return Math.sqrt(h)}static alphaAt(e,t,n,i={x:0,z:0}){if(n<=0)return 0;const s=Math.abs(e.y),r=t/Math.max(s,.04),o=e.x*r+i.x,l=e.y*r,c=e.z*r+i.z,h=o*.006,d=l*.006,u=c*.006,f=o+kt.fbm(h+12.3,d+12.3,u+12.3)*40,p=l+kt.fbm(h+47.1,d+47.1,u+47.1)*40,v=c+kt.fbm(h+91.7,d+91.7,u+91.7)*40,m=kt.fbm(f*.014,p*.014,v*.014)*.5+.5,g=1-kt.worley(f*.011,p*.011,v*.011),_=m+(g-m)*.4,M=kt.thresholdFor(n,wg,Mg),x=(E,D,y)=>{const T=Math.min(1,Math.max(0,(y-E)/(D-E)));return T*T*(3-2*T)},w=x(M-.08,M+.08,_);return w+(1-w)*x(.82,1,n)}}const Oa=6371e3,Ht=64,Er=8,eh=.2787;function Fd(a){if(a.seed!==void 0)return a.seed;let e=2166136261;for(const t of a.id)e=Math.imul(e^t.charCodeAt(0),16777619);return e>>>0}function YS(){const a=new Uint8Array(Ht**3),e=(i,s,r,o)=>{let l=Math.imul(i%o+1,374761393)^Math.imul(s%o+1,668265263)^Math.imul(r%o+1,1274126177);return l=Math.imul(l^l>>>13,1274126177),((l^l>>>16)>>>0)/4294967295},t=(i,s,r,o)=>{const l=Math.floor(i),c=Math.floor(s),h=Math.floor(r),d=m=>m*m*(3-2*m),u=d(i-l),f=d(s-c),p=d(r-h);let v=0;for(let m=0;m<2;m++)for(let g=0;g<2;g++)for(let _=0;_<2;_++)v+=e(l+_,c+g,h+m,o)*(_?u:1-u)*(g?f:1-f)*(m?p:1-p);return v};for(let i=0;i<Ht;i++)for(let s=0;s<Ht;s++)for(let r=0;r<Ht;r++){let o=0;for(const[l,c]of[[4,.65],[8,.25],[16,.1]])o+=t(r/Ht*l,s/Ht*l,i/Ht*l,l)*c;a[r+Ht*(s+Ht*i)]=Math.round(o*255)}const n=new jm(a,Ht,Ht,Ht);return n.format=tc,n.minFilter=n.magFilter=At,n.wrapS=n.wrapT=n.wrapR=Jr,n.needsUpdate=!0,n}function KS(a,e,t,n){const i=h=>{const d=(Oa+e)*a,u=(e-h)*(2*Oa+e+h),f=d*d-u;if(f<0)return;const p=-d-(d>=0?1:-1)*Math.sqrt(f),v=p===0?0:u/p;return[Math.min(p,v),Math.max(p,v)]},s=i(t+n);if(!s||s[1]<=0)return;let r=Math.max(0,s[0]),o=s[1];const l=i(t);l&&(r>=l[0]&&r<l[1]?r=l[1]:l[0]>r&&(o=Math.min(o,l[0])));const c=i(0);return c&&c[0]>=0&&(o=Math.min(o,c[0])),o>r?[r,o]:void 0}const $S=`varying vec3 vCloudDirection;
|
|
6205
6236
|
void main() {
|
|
6206
6237
|
vCloudDirection = position;
|
|
6207
6238
|
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
@@ -6386,7 +6417,7 @@ float transmissionAt(vec3 dir, float distanceM) {
|
|
|
6386
6417
|
if (transmission < 0.015) break;
|
|
6387
6418
|
}
|
|
6388
6419
|
return transmission;
|
|
6389
|
-
}`,n=/\b(noiseMap|sunDir|sunColor|ambientColor|hazeColor|offsetM|seedOffset|localCenter|localSize|localRotation|baseM|thicknessM|eyeM|coverage|sizeM|density|darkness|flatness|SLICE|MAX_HOLES|holeCount|holeCenter|holeSize|holeRotation|R|roots|altitude|coverageThreshold|ellipsoidRadius|clipLocal|densityAt|transmissionAt)\b/g;return(e+t).replace(n,i=>a+i)}class Vl{mesh;uniforms;constructor(e,t){this.uniforms={noiseMap:{value:e},sunDir:{value:new P(0,1,0)},sunColor:{value:new le(1,1,1)},ambientColor:{value:new le(.4,.45,.5)},hazeColor:{value:new le(.5,.6,.7)},offsetM:{value:new P},seedOffset:{value:new P},localCenter:{value:new P},localSize:{value:new P},localRotation:{value:0},holeCount:{value:0},holeCenter:{value:Array.from({length:Er},()=>new P)},holeSize:{value:Array.from({length:Er},()=>new P)},holeRotation:{value:new Array(Er).fill(0)},baseM:{value:1e3},thicknessM:{value:650},eyeM:{value:1.6},coverage:{value:.5},sizeM:{value:1400},density:{value:1},darkness:{value:0},flatness:{value:0}};const n=new Rt({uniforms:this.uniforms,vertexShader:$S,fragmentShader:Ud,transparent:!0,depthWrite:!1,depthTest:!0,side:Vt});this.mesh=new Ke(new mn(t,32,16),n),this.mesh.frustumCulled=!1}update(e,t,n,i=[]){const s=this.uniforms;s.localSize.value.set(n?.widthM??0,n?.thicknessM??0,n?.depthM??0),s.localCenter.value.set(n?.eastM??0,n?n.baseM+n.thicknessM/2:0,-(n?.northM??0)),s.localRotation.value=(n?.rotationDeg??0)*Math.PI/180,s.holeCount.value=Math.min(Er,i.length),i.slice(0,Er).forEach((o,l)=>{s.holeCenter.value[l].set(o.eastM,o.baseM+o.thicknessM/2,-o.northM),s.holeSize.value[l].set(o.widthM,o.thicknessM,o.depthM),s.holeRotation.value[l]=o.rotationDeg*Math.PI/180}),s.baseM.value=Math.max(0,e.baseM),s.thicknessM.value=Math.max(10,e.thicknessM),s.coverage.value=Math.max(0,Math.min(1,e.coverage)),s.sizeM.value=Math.max(50,e.sizeM),s.density.value=Math.max(0,Math.min(2,e.density)),s.darkness.value=Math.max(0,Math.min(1,e.darkness??0)),s.eyeM.value=Math.max(.1,t),s.flatness.value=e.type==="stratus"?1:e.type==="stratocumulus"?.45:0;const r=Fd(e);s.seedOffset.value.set(r%97/97,r%61/61,r%37/37),this.mesh.visible=s.density.value>0&&(n!==void 0||s.coverage.value>0)}static thresholdFor(e){const t=Math.min(.999,Math.max(.001,e));return .645-.23*(Math.sqrt(3)/Math.PI)*Math.log(t/(1-t))}densityAt(e){const t=this.uniforms,n=(N,z,L)=>{const B=Math.max(0,Math.min(1,(L-N)/(z-N)));return B*B*(3-2*B)},i=(N,z,L)=>N+(z-N)*L,s=t.eyeM.value+e.y,r=2*Oa*s+e.x**2+s**2+e.z**2,o=r/(Math.sqrt(Oa**2+r)+Oa),l=(o-t.baseM.value)/t.thicknessM.value,c=t.localSize.value.x>0;if(l<=0||l>=1||t.coverage.value<=0&&!c)return 0;const h=(N,z,L)=>{const B=e.x+t.offsetM.value.x-N.x,F=e.z+t.offsetM.value.z-N.z,V=Math.cos(L),j=Math.sin(L);return Math.hypot((V*B-j*F)/(z.x*.5),(o-N.y)/(z.y*.5),(j*B+V*F)/(z.z*.5))},d=c?h(t.localCenter.value,t.localSize.value,t.localRotation.value):0;if(d>1.3)return 0;const u=[e.x,e.y,e.z].map((N,z)=>(N+t.offsetM.value.getComponent(z))/(t.sizeM.value*4)+t.seedOffset.value.getComponent(z)),f=t.noiseMap.value.image.data,p=(N,z,L)=>{const B=[N,z,L].map($=>($%1+1)%1*
|
|
6420
|
+
}`,n=/\b(noiseMap|sunDir|sunColor|ambientColor|hazeColor|offsetM|seedOffset|localCenter|localSize|localRotation|baseM|thicknessM|eyeM|coverage|sizeM|density|darkness|flatness|SLICE|MAX_HOLES|holeCount|holeCenter|holeSize|holeRotation|R|roots|altitude|coverageThreshold|ellipsoidRadius|clipLocal|densityAt|transmissionAt)\b/g;return(e+t).replace(n,i=>a+i)}class Vl{mesh;uniforms;constructor(e,t){this.uniforms={noiseMap:{value:e},sunDir:{value:new P(0,1,0)},sunColor:{value:new le(1,1,1)},ambientColor:{value:new le(.4,.45,.5)},hazeColor:{value:new le(.5,.6,.7)},offsetM:{value:new P},seedOffset:{value:new P},localCenter:{value:new P},localSize:{value:new P},localRotation:{value:0},holeCount:{value:0},holeCenter:{value:Array.from({length:Er},()=>new P)},holeSize:{value:Array.from({length:Er},()=>new P)},holeRotation:{value:new Array(Er).fill(0)},baseM:{value:1e3},thicknessM:{value:650},eyeM:{value:1.6},coverage:{value:.5},sizeM:{value:1400},density:{value:1},darkness:{value:0},flatness:{value:0}};const n=new Rt({uniforms:this.uniforms,vertexShader:$S,fragmentShader:Ud,transparent:!0,depthWrite:!1,depthTest:!0,side:Vt});this.mesh=new Ke(new mn(t,32,16),n),this.mesh.frustumCulled=!1}update(e,t,n,i=[]){const s=this.uniforms;s.localSize.value.set(n?.widthM??0,n?.thicknessM??0,n?.depthM??0),s.localCenter.value.set(n?.eastM??0,n?n.baseM+n.thicknessM/2:0,-(n?.northM??0)),s.localRotation.value=(n?.rotationDeg??0)*Math.PI/180,s.holeCount.value=Math.min(Er,i.length),i.slice(0,Er).forEach((o,l)=>{s.holeCenter.value[l].set(o.eastM,o.baseM+o.thicknessM/2,-o.northM),s.holeSize.value[l].set(o.widthM,o.thicknessM,o.depthM),s.holeRotation.value[l]=o.rotationDeg*Math.PI/180}),s.baseM.value=Math.max(0,e.baseM),s.thicknessM.value=Math.max(10,e.thicknessM),s.coverage.value=Math.max(0,Math.min(1,e.coverage)),s.sizeM.value=Math.max(50,e.sizeM),s.density.value=Math.max(0,Math.min(2,e.density)),s.darkness.value=Math.max(0,Math.min(1,e.darkness??0)),s.eyeM.value=Math.max(.1,t),s.flatness.value=e.type==="stratus"?1:e.type==="stratocumulus"?.45:0;const r=Fd(e);s.seedOffset.value.set(r%97/97,r%61/61,r%37/37),this.mesh.visible=s.density.value>0&&(n!==void 0||s.coverage.value>0)}static thresholdFor(e){const t=Math.min(.999,Math.max(.001,e));return .645-.23*(Math.sqrt(3)/Math.PI)*Math.log(t/(1-t))}densityAt(e){const t=this.uniforms,n=(N,z,L)=>{const B=Math.max(0,Math.min(1,(L-N)/(z-N)));return B*B*(3-2*B)},i=(N,z,L)=>N+(z-N)*L,s=t.eyeM.value+e.y,r=2*Oa*s+e.x**2+s**2+e.z**2,o=r/(Math.sqrt(Oa**2+r)+Oa),l=(o-t.baseM.value)/t.thicknessM.value,c=t.localSize.value.x>0;if(l<=0||l>=1||t.coverage.value<=0&&!c)return 0;const h=(N,z,L)=>{const B=e.x+t.offsetM.value.x-N.x,F=e.z+t.offsetM.value.z-N.z,V=Math.cos(L),j=Math.sin(L);return Math.hypot((V*B-j*F)/(z.x*.5),(o-N.y)/(z.y*.5),(j*B+V*F)/(z.z*.5))},d=c?h(t.localCenter.value,t.localSize.value,t.localRotation.value):0;if(d>1.3)return 0;const u=[e.x,e.y,e.z].map((N,z)=>(N+t.offsetM.value.getComponent(z))/(t.sizeM.value*4)+t.seedOffset.value.getComponent(z)),f=t.noiseMap.value.image.data,p=(N,z,L)=>{const B=[N,z,L].map($=>($%1+1)%1*Ht-.5),F=B.map(Math.floor),V=B.map(($,ne)=>$-F[ne]);let j=0;for(let $=0;$<2;$++)for(let ne=0;ne<2;ne++)for(let re=0;re<2;re++){const He=(F[0]+re+Ht)%Ht,Ze=(F[1]+ne+Ht)%Ht,ze=(F[2]+$+Ht)%Ht;j+=f[He+Ht*(Ze+Ht*ze)]/255*(re?V[0]:1-V[0])*(ne?V[1]:1-V[1])*($?V[2]:1-V[2])}return j},v=[u[0]*.173,eh,u[2]*.173];u[0]+=(p(v[0]+.13,v[1]+.27,v[2]+.41)-.5)*1.3,u[2]+=(p(v[0]+.67,v[1]+.53,v[2]+.19)-.5)*1.3;const m=(u[0]*.731+u[2]*.682)*1.371,g=(-u[0]*.682+u[2]*.731)*1.371;let _=n(.2,.8,p(u[0],eh,u[2])*.65+p(m,eh+.37,g)*.35);const M=n(8e3,4e4,Math.hypot(e.x,e.y,e.z)),x=i(p(u[0]*2,u[1]*3,u[2]*2),.5,M),w=i(p(u[0]*7,u[1]*7,u[2]*7),.5,M);let E=Vl.thresholdFor(t.coverage.value),D=1,y=0;if(c){const N=d+(x-.5)*.18;y=1-n(.35,1,N),D=1-n(.85,1.15,N),_=i(_,1,y),E=Math.min(E,Vl.thresholdFor(.5))}for(let N=0;N<t.holeCount.value;N++)D*=n(.85,1.15,h(t.holeCenter.value[N],t.holeSize.value[N],t.holeRotation.value[N])+(x-.5)*.18);if(D<.001)return 0;let T=n(E-.1,E+.1,_);if(T=i(T,1,n(.92,1,t.coverage.value)),T=i(T,Math.max(t.coverage.value,y),M),T<.001)return 0;const A=i(.45+.55*x,.96,t.flatness.value),I=n(0,.09,l)*(1-n(A-.22,A,l)),R=i(Math.max(0,T-(1-x)*.38-(1-w)*.1),T*.8,t.flatness.value);return I*R*t.density.value*D}transmissionAt(e,t=1/0){const n=this.uniforms,i=KS(e.y,n.eyeM.value,n.baseM.value,n.thicknessM.value);if(!i)return 1;let[s,r]=i;if(n.localSize.value.x>0){const h=n.localCenter.value.clone().sub(n.offsetM.value);h.y-=n.eyeM.value+(h.x**2+h.z**2)/(2*Oa);const d=n.localSize.value.length()*.5+25,u=e.x*h.x+e.y*h.y+e.z*h.z,f=u*u-h.lengthSq()+d*d;if(f<0)return 1;s=Math.max(s,u-Math.sqrt(f)),r=Math.min(r,u+Math.sqrt(f))}const o=Math.min(r,t,s+18e3);if(o<=s)return 1;const l=(o-s)/48;let c=1;for(let h=0;h<48;h++){const d=s+(h+.5)*l;if(c*=Math.exp(-this.densityAt({x:e.x*d,y:e.y*d,z:e.z*d})*l*.006),c<.015)break}return c}dispose(){this.mesh.removeFromParent(),this.mesh.geometry.dispose(),this.mesh.material.dispose()}}class JS{constructor(e,t,n){this.group=e,this.radius=t,this.mode=n}decks=new Map;noise;update(e,t){const n=_i(e).flatMap(r=>{const o={...r,darkness:r.darkness??e.cloudDarkness};return[{layer:o,parentId:o.id,key:JSON.stringify([o.id]),instance:void 0},...(o.instances??[]).map(l=>({parentId:o.id,key:JSON.stringify([o.id,l.id]),instance:l,layer:{...o,id:`${o.id}/${l.id}`,baseM:l.baseM,thicknessM:l.thicknessM,density:l.density,darkness:l.darkness??o.darkness,seed:l.seed??Fd(o),instances:void 0}}))]}),i=new Set(n.map(r=>r.key));for(const[r,o]of this.decks)i.has(r)||(this.disposeDeck(o),this.decks.delete(r));[...n].sort((r,o)=>Math.abs(o.layer.baseM+o.layer.thicknessM/2-t)-Math.abs(r.layer.baseM+r.layer.thicknessM/2-t)).forEach(({layer:r,key:o,instance:l,parentId:c},h)=>{const d=l!==void 0||r.type!=="cirrus"&&(this.mode==="volume"||(r.instances?.length??0)>0);let u=this.decks.get(o);if(u&&!!u.volume!==d&&(this.disposeDeck(u),this.decks.delete(o),u=void 0),!u){if(u={layer:r,parentId:c,instance:l},d)this.noise??=YS(),u.volume=new Vl(this.noise,this.radius),this.group.add(u.volume.mesh);else{const p=Od(new le(1,1,1),r.coverage,Math.max(1,Math.abs(r.baseM-t)*.25*1400/Math.max(50,r.sizeM)),r.type==="cirrus"?1:0);u.uniforms=p.uniforms,u.surface=new Ke(kd(this.radius),p.material),this.group.add(u.surface)}this.decks.set(o,u)}u.layer=r,u.instance=l;const f=4+h/Math.max(1,n.length);u.volume&&(u.volume.update(r,t,l,l?[]:r.instances??[]),u.volume.mesh.renderOrder=f),u.surface&&u.uniforms&&(u.surface.renderOrder=f,u.surface.scale.y=r.baseM<t?-1:1,u.surface.visible=r.coverage>0&&r.density>0,u.uniforms.coverage.value=r.coverage,u.uniforms.opticalDensity.value=r.type==="cirrus"?r.density/.35:r.density,u.uniforms.darkness.value=Math.max(0,Math.min(1,r.darkness??e.cloudDarkness)),u.uniforms.layerHeight.value=Math.max(1,Math.abs(r.baseM-t)*.25*1400/Math.max(50,r.sizeM)),u.uniforms.fibrous.value=r.type==="cirrus"?1:0)})}setOffsets(e,t){for(const n of this.decks.values()){const i=t[n.parentId]??e;n.volume?.uniforms.offsetM.value.set(i.x,0,i.z);const s=.25*1400/Math.max(50,n.layer.sizeM),r=Fd(n.layer);n.uniforms?.fieldOffset.value.set(i.x*s+r%97,0,i.z*s+r%37)}}setLighting(e,t,n,i){for(const s of this.decks.values()){const r=s.volume?.uniforms??s.uniforms;r.sunDir.value.copy(e),r.sunColor.value.copy(t),r.ambientColor.value.copy(n),s.volume?.uniforms.hazeColor.value.copy(i)}}get cirrusMask(){const e=[...this.decks.values()].filter(t=>t.layer.type==="cirrus"&&t.uniforms).sort((t,n)=>n.layer.coverage-t.layer.coverage)[0];return e?.uniforms?{cover:e.layer.coverage,layerHeight:e.uniforms.layerHeight.value,offset:e.uniforms.fieldOffset.value,iceCrystalAlignment:e.layer.iceCrystalAlignment}:void 0}get volumes(){return[...this.decks.values()].flatMap(e=>e.volume?.mesh.visible?[e.volume]:[])}pickInstance(e){let t=1/0,n;for(const i of this.decks.values()){if(!i.instance||!i.volume?.mesh.visible)continue;const s=i.volume.uniforms,r=s.localCenter.value.clone().sub(s.offsetM.value);r.y-=s.eyeM.value+(r.x**2+r.z**2)/(2*6371e3);const o=r.dot(e);o<=0||o>=t||i.volume.transmissionAt(e)>.98||(t=o,n={layerId:i.parentId,instanceId:i.instance.id,center:r})}return n}transmissionAt(e){let t=1;for(const n of this.decks.values())n.volume?t*=n.volume.transmissionAt(e):n.uniforms&&(t*=1-kt.alphaAt(e,n.uniforms.layerHeight.value,n.layer.coverage,n.uniforms.fieldOffset.value)*(n.layer.type==="cirrus"?.2:.95));return t}disposeDeck(e){e.volume?.dispose(),e.surface&&(e.surface.removeFromParent(),e.surface.geometry.dispose(),e.surface.material.dispose())}dispose(){for(const e of this.decks.values())this.disposeDeck(e);this.decks.clear(),this.noise?.dispose()}}const rc=`
|
|
6390
6421
|
vec3 encodeSrgb(vec3 linear) {
|
|
6391
6422
|
vec3 clamped = max(linear, vec3(0.0));
|
|
6392
6423
|
vec3 low = clamped * 12.92;
|
|
@@ -7270,7 +7301,7 @@ void main()
|
|
|
7270
7301
|
// display fades at the edge of a fibre instead of ending on a cut line.
|
|
7271
7302
|
gl_FragColor = vec4(light * uStrength * (0.25 + 0.75 * ice), 1.0);
|
|
7272
7303
|
}
|
|
7273
|
-
`,transparent:!0,blending:ai,depthWrite:!1,side:Vt,fog:!1}),this.object=new Ke(new mn(pi.RADIUS,64,32),this.material),this.object.renderOrder=-1,this.object.frustumCulled=!1,this.object.visible=!1}set onReady(e){this.onRepaint=e}update(e,t,n,i,s,r){const o=this.material.uniforms;if(n<=0){o.uStrength.value=0,this.object.visible=!1,this.stopWork();return}o.uSource.value.set(e.x,e.y,e.z).normalize(),o.uStrength.value=n,o.uTint.value.set(i[0],i[1],i[2]),o.uIceCover.value=s.cover,o.uIceHeight.value=s.layerHeight,this.object.visible=this.everDisplayed,this.requestMap(t,r)}requestMap(e,t){!(!(Math.abs(e-this.mappedAltitudeDeg)<pi.ALTITUDE_STEP_DEG)||t!==this.mappedAlignment)||this.tracingFor(e,t)||(this.pendingAltitudeDeg=e,this.pendingAlignment=t,this.sky.begin(e,t),this.tracing=!0,this.nextGlimpse=pi.FIRST_GLIMPSE_RAYS,this.scheduleWork())}pendingAltitudeDeg=Number.NaN;pendingAlignment=Number.NaN;tracingFor(e,t){return this.tracing&&Math.abs(e-this.pendingAltitudeDeg)<pi.ALTITUDE_STEP_DEG&&t===this.pendingAlignment}scheduleWork(){if(this.workHandle!==void 0)return;const e=()=>{if(this.workHandle=void 0,!this.tracing)return;this.sky.trace(pi.RAYS_PER_FRAME);const t=this.sky.tracedRays>=pi.RAYS,n=this.refining&&this.sky.tracedRays>=this.nextGlimpse;if(n&&(this.nextGlimpse*=2),(t||n)&&this.publish(),t){this.tracing=!1,this.refining=!1,this.mappedAltitudeDeg=this.pendingAltitudeDeg,this.mappedAlignment=this.pendingAlignment;return}this.workHandle=requestAnimationFrame(e)};this.workHandle=requestAnimationFrame(e)}stopWork(){this.workHandle!==void 0&&cancelAnimationFrame(this.workHandle),this.workHandle=void 0,this.tracing=!1}publish(){const t=this.sky.harvest().data;for(let n=0,i=0;i<t.length;n+=4,i+=3)this.texels[n]=xs.toHalfFloat(t[i]),this.texels[n+1]=xs.toHalfFloat(t[i+1]),this.texels[n+2]=xs.toHalfFloat(t[i+2]),this.texels[n+3]=1;this.texture.needsUpdate=!0,this.everDisplayed=!0,this.object.visible=this.material.uniforms.uStrength.value>0,this.onRepaint?.()}dispose(){this.stopWork(),this.texture.dispose(),this.object.geometry.dispose(),this.material.dispose()}}class
|
|
7304
|
+
`,transparent:!0,blending:ai,depthWrite:!1,side:Vt,fog:!1}),this.object=new Ke(new mn(pi.RADIUS,64,32),this.material),this.object.renderOrder=-1,this.object.frustumCulled=!1,this.object.visible=!1}set onReady(e){this.onRepaint=e}update(e,t,n,i,s,r){const o=this.material.uniforms;if(n<=0){o.uStrength.value=0,this.object.visible=!1,this.stopWork();return}o.uSource.value.set(e.x,e.y,e.z).normalize(),o.uStrength.value=n,o.uTint.value.set(i[0],i[1],i[2]),o.uIceCover.value=s.cover,o.uIceHeight.value=s.layerHeight,this.object.visible=this.everDisplayed,this.requestMap(t,r)}requestMap(e,t){!(!(Math.abs(e-this.mappedAltitudeDeg)<pi.ALTITUDE_STEP_DEG)||t!==this.mappedAlignment)||this.tracingFor(e,t)||(this.pendingAltitudeDeg=e,this.pendingAlignment=t,this.sky.begin(e,t),this.tracing=!0,this.nextGlimpse=pi.FIRST_GLIMPSE_RAYS,this.scheduleWork())}pendingAltitudeDeg=Number.NaN;pendingAlignment=Number.NaN;tracingFor(e,t){return this.tracing&&Math.abs(e-this.pendingAltitudeDeg)<pi.ALTITUDE_STEP_DEG&&t===this.pendingAlignment}scheduleWork(){if(this.workHandle!==void 0)return;const e=()=>{if(this.workHandle=void 0,!this.tracing)return;this.sky.trace(pi.RAYS_PER_FRAME);const t=this.sky.tracedRays>=pi.RAYS,n=this.refining&&this.sky.tracedRays>=this.nextGlimpse;if(n&&(this.nextGlimpse*=2),(t||n)&&this.publish(),t){this.tracing=!1,this.refining=!1,this.mappedAltitudeDeg=this.pendingAltitudeDeg,this.mappedAlignment=this.pendingAlignment;return}this.workHandle=requestAnimationFrame(e)};this.workHandle=requestAnimationFrame(e)}stopWork(){this.workHandle!==void 0&&cancelAnimationFrame(this.workHandle),this.workHandle=void 0,this.tracing=!1}publish(){const t=this.sky.harvest().data;for(let n=0,i=0;i<t.length;n+=4,i+=3)this.texels[n]=xs.toHalfFloat(t[i]),this.texels[n+1]=xs.toHalfFloat(t[i+1]),this.texels[n+2]=xs.toHalfFloat(t[i+2]),this.texels[n+3]=1;this.texture.needsUpdate=!0,this.everDisplayed=!0,this.object.visible=this.material.uniforms.uStrength.value>0,this.onRepaint?.()}dispose(){this.stopWork(),this.texture.dispose(),this.object.geometry.dispose(),this.material.dispose()}}class zt{static BINS=1800;static SOURCE_RADIUS_DEG=.265;static FULL_UNTIL_DEG=60;static FADED_BY_DEG=90;static IMPACT_STEPS=4096;drop=new $a;previous=zt.emergences();current=zt.emergences();tally=new Float32Array(zt.BINS*3);radiance=new Float32Array(zt.BINS*3);scratch=new Float32Array(zt.BINS*3);static emergences(){return Array.from({length:$a.MAX_CHORDS+1},()=>({chords:0,scatteringAngle:0,weight:0}))}compute(){this.tally.fill(0);for(const e of ti.SAMPLES)this.sweep(e);return this.toRadiance(),this.blurBySourceDisc(),{bins:zt.BINS,data:this.radiance,binDeg:180/zt.BINS}}sweep(e){this.drop.refractiveIndex=en.indexAt(e.wavelengthNm);const t=zt.IMPACT_STEPS;let n=this.drop.trace(0,this.previous);const i=1/t;for(let s=1;s<=t;s++){const r=this.drop.trace(Math.sqrt(s/t),this.current);for(let o=0;o<Math.min(r,n);o++){const l=this.previous[o],c=this.current[o];l.chords===c.chords&&this.deposit(l.scatteringAngle,c.scatteringAngle,(l.weight+c.weight)/2*i,e)}n=r,this.copyInto(this.current,this.previous)}}copyInto(e,t){for(let n=0;n<e.length;n++)t[n].chords=e[n].chords,t[n].scatteringAngle=e[n].scatteringAngle,t[n].weight=e[n].weight}deposit(e,t,n,i){if(n<=0)return;const s=zt.BINS,r=Math.PI/s,o=Math.min(e,t),l=Math.max(e,t),c=l-o,h=Math.min(s-1,Math.max(0,Math.floor(o/r))),d=Math.min(s-1,Math.max(0,Math.floor(l/r)));if(c<=0||h===d){this.add(h,n,i);return}for(let u=h;u<=d;u++){const f=Math.min(l,(u+1)*r)-Math.max(o,u*r);f>0&&this.add(u,n*f/c,i)}}add(e,t,n){const i=e*3,s=t*ti.SAMPLES.length;this.tally[i]+=s*n.r,this.tally[i+1]+=s*n.g,this.tally[i+2]+=s*n.b}toRadiance(){const e=zt.BINS,t=Math.PI/e;for(let n=0;n<e;n++){const i=2*Math.PI*(Math.cos(n*t)-Math.cos((n+1)*t)),s=i>0?this.backwardShare((n+.5)*(180/e))/i:0,r=n*3;this.radiance[r]=this.tally[r]*s,this.radiance[r+1]=this.tally[r+1]*s,this.radiance[r+2]=this.tally[r+2]*s}}backwardShare(e){const t=180-e;if(t<=zt.FULL_UNTIL_DEG)return 1;if(t>=zt.FADED_BY_DEG)return 0;const n=(t-zt.FULL_UNTIL_DEG)/(zt.FADED_BY_DEG-zt.FULL_UNTIL_DEG);return Math.cos(n*Math.PI/2)**2}blurBySourceDisc(){const e=zt.BINS,t=zt.SOURCE_RADIUS_DEG*e/180,n=Math.max(1,Math.ceil(t)),i=[];let s=0;for(let r=-n;r<=n;r++){const o=Math.max(0,t*t-r*r),l=Math.sqrt(o);i.push(l),s+=l}if(!(s<=0)){this.scratch.set(this.radiance);for(let r=0;r<e;r++){let o=0,l=0,c=0;for(let d=-n;d<=n;d++){const u=Math.min(e-1,Math.max(0,r+d))*3,f=i[d+n];o+=this.scratch[u]*f,l+=this.scratch[u+1]*f,c+=this.scratch[u+2]*f}const h=r*3;this.radiance[h]=o/s,this.radiance[h+1]=l/s,this.radiance[h+2]=c/s}}}}class Wr{static RADIUS=880;static GAIN=.22;static MOON_SATURATION=.15;object;material;sky=new zt;texture;texels;computed=!1;constructor(){this.texels=new Uint16Array(zt.BINS*4),this.texture=new or(this.texels,zt.BINS,1,Mn,pn),this.texture.minFilter=At,this.texture.magFilter=At,this.texture.wrapS=wn,this.texture.wrapT=wn,this.texture.needsUpdate=!0,this.material=new Rt({uniforms:{uSource:{value:new P(0,1,0)},uStrength:{value:0},uTint:{value:new P(1,1,1)},uSaturation:{value:1},uProfile:{value:this.texture},uGain:{value:Wr.GAIN}},vertexShader:`
|
|
7274
7305
|
varying vec3 vDirection;
|
|
7275
7306
|
void main() {
|
|
7276
7307
|
vDirection = normalize((modelMatrix * vec4(position, 1.0)).xyz - cameraPosition);
|
|
@@ -7368,4 +7399,4 @@ void main() {
|
|
|
7368
7399
|
gl_FragColor = vec4(color, tex.a * uOpacity * (1.0 - blur * 0.5));
|
|
7369
7400
|
}
|
|
7370
7401
|
`;let fl;function oT(){if(fl)return fl;const a=128,e=document.createElement("canvas");e.width=a,e.height=a;const t=e.getContext("2d"),n=t.createRadialGradient(a/2,a/2,0,a/2,a/2,a/2);return n.addColorStop(0,"rgba(255,255,255,1)"),n.addColorStop(.4,"rgba(255,255,255,0.35)"),n.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=n,t.fillRect(0,0,a,a),fl=new Ri(e),fl}function lT(a){const t=document.createElement("canvas");t.width=128,t.height=128;const n=t.getContext("2d"),i=128/2-2,s=128/2,r=128/2,o="#2e2b26",l="#f4f1e2";n.fillStyle=o,n.beginPath(),n.arc(s,r,i,0,Math.PI*2),n.fill();const c=Zl(a.illuminatedFraction,0,1),h=a.phaseFraction<.5,d=i*Math.abs(1-2*c),u=c<.5;return n.save(),n.beginPath(),n.arc(s,r,i,0,Math.PI*2),n.clip(),n.fillStyle=l,n.beginPath(),h?(n.arc(s,r,i,-Math.PI/2,Math.PI/2,!1),n.ellipse(s,r,d,i,0,Math.PI/2,-Math.PI/2,u)):(n.arc(s,r,i,Math.PI/2,-Math.PI/2,!1),n.ellipse(s,r,d,i,0,-Math.PI/2,Math.PI/2,u)),n.fill(),n.restore(),new Ri(t)}function cT(a){const e=document.createElement("canvas");e.width=128,e.height=128;const t=e.getContext("2d");return t.fillStyle="rgba(0, 0, 0, 0.55)",t.beginPath(),t.arc(64,64,60,0,Math.PI*2),t.fill(),t.fillStyle="#ffffff",t.font="bold 52px sans-serif",t.textAlign="center",t.textBaseline="middle",t.fillText(a,64,68),new Ri(e)}function Sh(a){let e=a;return function(){e|=0,e=e+1831565813|0;let n=Math.imul(e^e>>>15,1|e);return n=n+Math.imul(n^n>>>7,61|n)^n,((n^n>>>14)>>>0)/4294967296}}const _h=7.5,Xr=9;class gi{static cache=new Map;static load(e){let t=gi.cache.get(e);return t||(t=fetch(e).then(n=>n.arrayBuffer()).then(n=>gi.parse(n)),gi.cache.set(e,t)),t}static upTo(e,t){const n=e.filter((r,o)=>o===0||e[o-1].magnitudeLimit<t);if(n.length<=1)return gi.load(e[0].url);const i=n.map(r=>r.url).join(`
|
|
7371
|
-
`);let s=gi.cache.get(i);return s||(s=Promise.all(n.map(r=>gi.load(r.url))).then(r=>r.reduce((o,l)=>gi.concat(o,l))),gi.cache.set(i,s)),s}static parse(e){const t=e.byteLength/(4*Float32Array.BYTES_PER_ELEMENT),n=t*Float32Array.BYTES_PER_ELEMENT;return{count:t,ra:new Float32Array(e,0*n,t),dec:new Float32Array(e,1*n,t),mag:new Float32Array(e,2*n,t),ci:new Float32Array(e,3*n,t)}}static concat(e,t){const n=(i,s)=>{const r=new Float32Array(i.length+s.length);return r.set(i,0),r.set(s,i.length),r};return{count:e.count+t.count,ra:n(e.ra,t.ra),dec:n(e.dec,t.dec),mag:n(e.mag,t.mag),ci:n(e.ci,t.ci)}}}const hT=new URL(""+new URL("rain-BvWZrB9h.ogg",import.meta.url).href,import.meta.url).href,dT=new URL(""+new URL("wind-BjklexY7.ogg",import.meta.url).href,import.meta.url).href,uT=new URL(""+new URL("thunder-DA48qs_v.wav",import.meta.url).href,import.meta.url).href,fT=20,pT=1;class mT{context;buffers=new Map;ambientSource;ambientGain;ambientKey="none";ambientToken=0;ambientVolume=0;windSource;windGain;windActive=!1;windToken=0;windVolume=0;paused=!0;requested={type:"none",intensity:0,windSpeed:0};resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(e){console.warn("WeatherAudio: Web Audio unavailable, weather sounds disabled:",e);return}}this.context.state==="suspended"&&this.context.resume()}setAmbient(e,t,n){if(this.requested={type:e,intensity:t,windSpeed:n},!this.context)return;this.paused&&(e="none",t=0,n=0);const i=e==="rain"||e==="hail"?e:"none";if(this.ambientVolume=i==="hail"?Math.min(1,t*1.3+.2):i==="rain"?t:0,i!==this.ambientKey){this.ambientKey=i;const r=++this.ambientToken;this.stopSource(this.ambientSource,this.ambientGain),this.ambientSource=void 0,this.ambientGain=void 0,i!=="none"&&this.startLoop(hT,this.ambientVolume).then(o=>this.applyIfCurrent(o,r,()=>this.ambientToken,l=>{this.ambientSource=l?.source,this.ambientGain=l?.gain,l&&(l.gain.gain.value=this.ambientVolume)}))}else this.ambientGain&&(this.ambientGain.gain.value=this.ambientVolume);this.windVolume=Math.min(n/fT,1);const s=n>pT;if(s!==this.windActive){this.windActive=s;const r=++this.windToken;this.stopSource(this.windSource,this.windGain),this.windSource=void 0,this.windGain=void 0,s&&this.startLoop(dT,this.windVolume).then(o=>this.applyIfCurrent(o,r,()=>this.windToken,l=>{this.windSource=l?.source,this.windGain=l?.gain,l&&(l.gain.gain.value=this.windVolume)}))}else this.windGain&&(this.windGain.gain.value=this.windVolume)}setPaused(e){if(e===this.paused)return;this.paused=e;const{type:t,intensity:n,windSpeed:i}=this.requested;this.setAmbient(t,n,i)}playThunder(){!this.context||this.paused||this.playOneShot(uT,.9)}dispose(){this.ambientToken++,this.windToken++,this.stopSource(this.ambientSource,this.ambientGain),this.stopSource(this.windSource,this.windGain),this.ambientSource=void 0,this.ambientGain=void 0,this.windSource=void 0,this.windGain=void 0,this.context?.close(),this.context=void 0,this.buffers.clear()}applyIfCurrent(e,t,n,i){if(t!==n()){e?.source.stop();return}i(e)}async startLoop(e,t){const n=this.context;if(n)try{const i=await this.getBuffer(e),s=n.createBufferSource();s.buffer=i,s.loop=!0;const r=n.createGain();return r.gain.value=t,s.connect(r).connect(n.destination),s.start(),{source:s,gain:r}}catch(i){console.warn("Weather ambient sound failed to load, staying silent:",i);return}}async playOneShot(e,t){const n=this.context;if(n)try{const i=await this.getBuffer(e),s=n.createBufferSource();s.buffer=i;const r=n.createGain();r.gain.value=t,s.connect(r).connect(n.destination),s.start()}catch(i){console.warn("Thunder sound failed to load:",i)}}async getBuffer(e){const t=this.context;if(!t)throw new Error("WeatherAudio: AudioContext not ready — resume() must be called first");let n=this.buffers.get(e);return n||(n=fetch(e).then(i=>{if(!i.ok)throw new Error(`Audio fetch failed (${i.status}): ${e}`);return i.arrayBuffer()}).then(i=>t.decodeAudioData(i)),this.buffers.set(e,n)),n}stopSource(e,t){try{e?.stop()}catch{}e?.disconnect(),t?.disconnect()}}class zi{constructor(e){this.elements=e;const{eccentricity:t,perihelionAu:n}=e,[i,s]=this.perifocalAxes(),r=Math.sqrt(zi.SUN_GM_AU3_PER_DAY2*(1+t)/n);this.perihelionPosition=this.scale(i,n),this.perihelionVelocity=this.scale(s,r),this.inverseSemiMajorAxis=(1-t)/n}static SUN_GM_AU3_PER_DAY2=.0002959122082855911;static MAX_ITERATIONS=200;perihelionPosition;perihelionVelocity;inverseSemiMajorAxis;positionAt(e){const t=e-this.elements.perihelionJd,n=this.universalAnomaly(t),i=this.inverseSemiMajorAxis*n*n,s=this.elements.perihelionAu,r=1-n*n/s*zi.stumpffC(i),o=t-n*n*n/Math.sqrt(zi.SUN_GM_AU3_PER_DAY2)*zi.stumpffS(i);return{x:r*this.perihelionPosition.x+o*this.perihelionVelocity.x,y:r*this.perihelionPosition.y+o*this.perihelionVelocity.y,z:r*this.perihelionPosition.z+o*this.perihelionVelocity.z}}heliocentricDistanceAt(e){const t=this.positionAt(e);return Math.hypot(t.x,t.y,t.z)}universalAnomaly(e){if(e===0)return 0;const t=Math.sign(e),n=Math.sqrt(zi.SUN_GM_AU3_PER_DAY2)*Math.abs(e),i=o=>{const l=this.inverseSemiMajorAxis*o*o,c=this.elements.perihelionAu;return(1-this.inverseSemiMajorAxis*c)*o*o*o*zi.stumpffS(l)+c*o};let s=Math.max(1,n/this.elements.perihelionAu);for(;i(s)<n;)s*=2;let r=0;for(let o=0;o<zi.MAX_ITERATIONS&&s-r>1e-13*Math.max(1,s);o++){const l=(r+s)/2;i(l)<n?r=l:s=l}return t*(r+s)/2}perifocalAxes(){const e=this.elements.ascendingNodeDeg*Math.PI/180,t=this.elements.argumentOfPerihelionDeg*Math.PI/180,n=this.elements.inclinationDeg*Math.PI/180,i=Math.cos(e),s=Math.sin(e),r=Math.cos(t),o=Math.sin(t),l=Math.cos(n),c=Math.sin(n);return[{x:i*r-s*o*l,y:s*r+i*o*l,z:o*c},{x:-i*o-s*r*l,y:-s*o+i*r*l,z:r*c}]}scale(e,t){return{x:e.x*t,y:e.y*t,z:e.z*t}}static stumpffC(e){if(Math.abs(e)<1e-6)return 1/2-e/24+e*e/720;if(e>0)return(1-Math.cos(Math.sqrt(e)))/e;const t=Math.sqrt(-e);return(Math.cosh(t)-1)/-e}static stumpffS(e){if(Math.abs(e)<1e-6)return 1/6-e/120+e*e/5040;if(e>0){const n=Math.sqrt(e);return(n-Math.sin(n))/(n*n*n)}const t=Math.sqrt(-e);return(Math.sinh(t)-t)/(t*t*t)}}const iv=[{id:"halley-1910",designation:"1P/Halley",name:{en:"Halley's Comet",fr:"comète de Halley"},orbit:{eccentricity:.9672960498922706,perihelionAu:.5872100477652511,inclinationDeg:162.218798367122,ascendingNodeDeg:58.56208298700436,argumentOfPerihelionDeg:111.7366940639061,perihelionJd:2.4187816784171113e6},peakMagnitude:0,peakOn:"1910-05-20",absoluteMagnitude:4.72,activityExponent:4,tailLengthDeg:100,tailLengthAu:.1638,note:"Passed 0.15 au from Earth on 20 May 1910, and the Earth crossed the outer tail the day before — the apparition that produced a genuine public panic."},{id:"brooks-1911",designation:"C/1911 O1",name:{en:"Comet Brooks",fr:"comète Brooks"},orbit:{eccentricity:.9876404970138669,perihelionAu:.4898172916113738,inclinationDeg:33.34043866978714,ascendingNodeDeg:293.7022074981857,argumentOfPerihelionDeg:153.5578007321686,perihelionJd:2.4193378856140426e6},peakMagnitude:2,peakOn:"1911-10-25",absoluteMagnitude:5.59,activityExponent:4},{id:"skjellerup-maristany-1927",designation:"C/1927 X1",name:{en:"Comet Skjellerup-Maristany",fr:"comète Skjellerup-Maristany"},orbit:{eccentricity:.999839726885059,perihelionAu:.1761569619628186,inclinationDeg:85.1125991950808,ascendingNodeDeg:78.24360172472711,argumentOfPerihelionDeg:47.15877857390136,perihelionJd:2.4252326808989984e6},peakMagnitude:-6,peakOn:"1927-12-15",absoluteMagnitude:1.19,activityExponent:4,note:"One of the few comets of the century seen in full daylight."},{id:"de-kock-paraskevopoulos-1941",designation:"C/1941 B2",name:{en:"Comet de Kock-Paraskevopoulos",fr:"comète de Kock-Paraskevopoulos"},orbit:{eccentricity:.9991026715181549,perihelionAu:.7900329662827822,inclinationDeg:168.2039226531089,ascendingNodeDeg:43.10609347214336,argumentOfPerihelionDeg:268.6990344196369,perihelionJd:2430022157765061e-9},peakMagnitude:2,peakOn:"1941-02-05",absoluteMagnitude:5.01,activityExponent:4},{id:"southern-1947",designation:"C/1947 X1",name:{en:"the Southern Comet",fr:"comète australe"},orbit:{eccentricity:.9998424430916737,perihelionAu:.1100045955093761,inclinationDeg:138.5113919632757,ascendingNodeDeg:337.3114969669252,argumentOfPerihelionDeg:196.1820121395961,perihelionJd:2.4325220864727003e6},peakMagnitude:-3,peakOn:"1947-12-08",absoluteMagnitude:3.01,activityExponent:4,note:"A bright southern-hemisphere comet of December 1947, the month the American sighting wave of that year was still being argued over."},{id:"eclipse-1948",designation:"C/1948 V1",name:{en:"the Eclipse Comet",fr:"comète de l'éclipse"},orbit:{eccentricity:.9999130678247334,perihelionAu:.1354437057263306,inclinationDeg:23.11668597152911,ascendingNodeDeg:211.0454985994762,argumentOfPerihelionDeg:107.2474157073104,perihelionJd:2.4328519265329437e6},peakMagnitude:-2,peakOn:"1948-11-01",absoluteMagnitude:4.79,activityExponent:4,note:"Found during the total solar eclipse of 1 November 1948, which is how a comet that bright had gone unnoticed: it had been hidden in the Sun's glare."},{id:"arend-roland-1957",designation:"C/1956 R1",name:{en:"Comet Arend-Roland",fr:"comète Arend-Roland"},orbit:{eccentricity:1.0002570255357,perihelionAu:.3160532361485914,inclinationDeg:119.9440863251822,ascendingNodeDeg:215.8548157717755,argumentOfPerihelionDeg:308.775920364167,perihelionJd:2.4359365327396123e6},peakMagnitude:.5,peakOn:"1957-04-25",absoluteMagnitude:3.96,activityExponent:4,note:"Showed a spike pointing back TOWARD the Sun in late April 1957 — a real anti-tail, and much reported at the time."},{id:"mrkos-1957",designation:"C/1957 P1",name:{en:"Comet Mrkos",fr:"comète Mrkos"},orbit:{eccentricity:.9993521583504134,perihelionAu:.3549238508212375,inclinationDeg:93.9433042053929,ascendingNodeDeg:68.32441518619923,argumentOfPerihelionDeg:40.31823675802871,perihelionJd:243605193752228e-8},peakMagnitude:1,peakOn:"1957-08-05",absoluteMagnitude:5.07,activityExponent:4,note:"The second bright naked-eye comet of 1957, four months after Arend-Roland."},{id:"seki-lines-1962",designation:"C/1962 C1",name:{en:"Comet Seki-Lines",fr:"comète Seki-Lines"},orbit:{eccentricity:1.000003791331562,perihelionAu:.03139689112215131,inclinationDeg:65.01487186102287,ascendingNodeDeg:304.6776602796538,argumentOfPerihelionDeg:11.47295326312573,perihelionJd:2437756163010178e-9},peakMagnitude:-2.5,peakOn:"1962-04-01",absoluteMagnitude:9.3,activityExponent:4},{id:"ikeya-seki-1965",designation:"C/1965 S1",name:{en:"Comet Ikeya-Seki",fr:"comète Ikeya-Seki"},orbit:{eccentricity:.9999141178248997,perihelionAu:.007785966366889336,inclinationDeg:141.8642315267051,ascendingNodeDeg:346.9951764632611,argumentOfPerihelionDeg:69.04909813996062,perihelionJd:2.4390546837018197e6},peakMagnitude:-10,peakOn:"1965-10-21",alsoRecordedMagnitude:2,alsoRecordedOn:"1965-10-30",absoluteMagnitude:5.26,activityExponent:4.002,tailLengthDeg:25,tailLengthAu:.5048,note:"A sungrazer that passed 450 000 km above the Sun's surface and was seen beside it in broad daylight — the brightest comet of the twentieth century. It then stood in the dawn sky for a fortnight with a tail some 25 degrees long, which is the second magnitude recorded here."},{id:"bennett-1970",designation:"C/1969 Y1",name:{en:"Comet Bennett",fr:"comète Bennett"},orbit:{eccentricity:.9962979048768408,perihelionAu:.5376209981502136,inclinationDeg:90.03975717147327,ascendingNodeDeg:224.6576652531314,argumentOfPerihelionDeg:354.1494209173161,perihelionJd:2.4406655455270996e6},peakMagnitude:0,peakOn:"1970-03-26",absoluteMagnitude:3.36,activityExponent:4},{id:"white-ortiz-bolelli-1970",designation:"C/1970 K1",name:{en:"Comet White-Ortiz-Bolelli",fr:"comète White-Ortiz-Bolelli"},orbit:{eccentricity:.9999488875801225,perihelionAu:.00884411465256722,inclinationDeg:138.9520738221631,ascendingNodeDeg:336.8194095816687,argumentOfPerihelionDeg:61.10224765396615,perihelionJd:2.4407209807728203e6},peakMagnitude:1,peakOn:"1970-05-22",absoluteMagnitude:4.35,activityExponent:4},{id:"kohoutek-1973",designation:"C/1973 E1",name:{en:"Comet Kohoutek",fr:"comète Kohoutek"},orbit:{eccentricity:1.000007152175185,perihelionAu:.1424250377812859,inclinationDeg:14.30414984159355,ascendingNodeDeg:258.4893339663974,argumentOfPerihelionDeg:37.79772760699667,perihelionJd:2442044930687027e-9},peakMagnitude:0,peakOn:"1974-01-05",absoluteMagnitude:4.89,activityExponent:4,note:"Announced in advance as the comet of the century and remembered for disappointing: it was an ordinary naked-eye object, not the spectacle the press had promised."},{id:"west-1976",designation:"C/1975 V1",name:{en:"Comet West",fr:"comète West"},orbit:{eccentricity:1.000017859625611,perihelionAu:.1966006188461085,inclinationDeg:43.07319920579427,ascendingNodeDeg:118.9189245655447,argumentOfPerihelionDeg:358.4315101259072,perihelionJd:2442833721841768e-9},peakMagnitude:-3,peakOn:"1976-02-25",absoluteMagnitude:4.41,activityExponent:4,tailLengthDeg:30,tailLengthAu:.4325,note:"Broke into four pieces at perihelion. Barely reported at the time — the press had been burned by Kohoutek two years earlier."},{id:"iras-araki-alcock-1983",designation:"C/1983 H1",name:{en:"Comet IRAS-Araki-Alcock",fr:"comète IRAS-Araki-Alcock"},orbit:{eccentricity:.9898409731606003,perihelionAu:.9913412593828502,inclinationDeg:73.25000846947029,ascendingNodeDeg:49.10235754476374,argumentOfPerihelionDeg:192.8506176754439,perihelionJd:2.4454757545235856e6},peakMagnitude:1.7,peakOn:"1983-05-11",absoluteMagnitude:9.04,activityExponent:4,note:"Passed 0.031 au from Earth on 11 May 1983, one of the closest cometary approaches on record: it crossed a quarter of the sky in a night, which no other comet in this list did."},{id:"halley-1986",designation:"1P/Halley",name:{en:"Halley's Comet",fr:"comète de Halley"},orbit:{eccentricity:.9672792271749998,perihelionAu:.5871034488173393,inclinationDeg:162.2422242700916,ascendingNodeDeg:58.85993640671803,argumentOfPerihelionDeg:111.8655480539208,perihelionJd:2.4464709589610207e6},peakMagnitude:2.1,peakOn:"1986-03-10",absoluteMagnitude:2.71,activityExponent:4,note:"The worst-placed return in two thousand years — famous, expected, and for most observers a faint smudge."},{id:"hyakutake-1996",designation:"C/1996 B2",name:{en:"Comet Hyakutake",fr:"comète Hyakutake"},orbit:{eccentricity:.9997295133739305,perihelionAu:.2302272039470452,inclinationDeg:124.923592343765,ascendingNodeDeg:188.0454295899424,argumentOfPerihelionDeg:130.1724036582639,perihelionJd:2.4502048946148166e6},peakMagnitude:0,peakOn:"1996-03-25",absoluteMagnitude:4.75,activityExponent:4,tailLengthDeg:80,tailLengthAu:1,note:"Passed 0.10 au from Earth in March 1996, five weeks BEFORE perihelion, with a tail measured at some 80 degrees — the longest of the modern era."},{id:"hale-bopp-1997",designation:"C/1995 O1",name:{en:"Comet Hale-Bopp",fr:"comète Hale-Bopp"},orbit:{eccentricity:.9951314746156615,perihelionAu:.9141695067003724,inclinationDeg:89.43017155012492,ascendingNodeDeg:282.470602866853,argumentOfPerihelionDeg:130.5872524854533,perihelionJd:2450539633099368e-9},peakMagnitude:-.8,peakOn:"1997-04-01",absoluteMagnitude:-1.06,activityExponent:4,tailLengthDeg:20,tailLengthAu:.9938,note:"Visible to the naked eye for about eighteen months, longer than any comet on record."},{id:"mcnaught-2007",designation:"C/2006 P1",name:{en:"Comet McNaught",fr:"comète McNaught"},orbit:{eccentricity:1.00001811603225,perihelionAu:.1707325614080681,inclinationDeg:77.83726446452654,ascendingNodeDeg:267.4149080498975,argumentOfPerihelionDeg:155.9756130642756,perihelionJd:2454113298753579e-9},peakMagnitude:-5.5,peakOn:"2007-01-13",absoluteMagnitude:2.53,activityExponent:4,tailLengthDeg:35,tailLengthAu:.5009,note:"The brightest comet since Ikeya-Seki, seen in daylight beside the Sun in January 2007."},{id:"lovejoy-2011",designation:"C/2011 W3",name:{en:"Comet Lovejoy",fr:"comète Lovejoy"},orbit:{eccentricity:.999915056276912,perihelionAu:.005553783989325053,inclinationDeg:134.3558712062691,ascendingNodeDeg:326.3693517957772,argumentOfPerihelionDeg:53.50991655176601,perihelionJd:2455911511809431e-9},peakMagnitude:-3,peakOn:"2011-12-16",alsoRecordedMagnitude:1.5,alsoRecordedOn:"2011-12-22",absoluteMagnitude:3.51,activityExponent:1.194,note:"A sungrazer that was expected to be destroyed at perihelion and came out the other side, to stand in the southern dawn sky for the rest of December — which is the second magnitude recorded here."},{id:"panstarrs-2013",designation:"C/2011 L4",name:{en:"Comet PANSTARRS",fr:"comète PANSTARRS"},orbit:{eccentricity:1.000032542889696,perihelionAu:.301544229714915,inclinationDeg:84.2081978367921,ascendingNodeDeg:65.66588626213694,argumentOfPerihelionDeg:333.6516444379993,perihelionJd:2456361669960698e-9},peakMagnitude:1,peakOn:"2013-03-10",absoluteMagnitude:5.98,activityExponent:4},{id:"neowise-2020",designation:"C/2020 F3",name:{en:"Comet NEOWISE",fr:"comète NEOWISE"},orbit:{eccentricity:.9991782081129224,perihelionAu:.2946512466331692,inclinationDeg:128.9375043020912,ascendingNodeDeg:61.01042991771634,argumentOfPerihelionDeg:37.2786526292898,perihelionJd:2.4590341788972816e6},peakMagnitude:.9,peakOn:"2020-07-08",absoluteMagnitude:5.79,activityExponent:4,tailLengthDeg:10,tailLengthAu:.1808,note:"The first comet since Hale-Bopp that ordinary observers in the northern hemisphere saw without being told where to look."},{id:"tsuchinshan-atlas-2024",designation:"C/2023 A3",name:{en:"Comet Tsuchinshan-ATLAS",fr:"comète Tsuchinshan-ATLAS"},orbit:{eccentricity:1.000020192843226,perihelionAu:.3914228969475176,inclinationDeg:139.1105462619479,ascendingNodeDeg:21.55945689078845,argumentOfPerihelionDeg:308.4913086299446,perihelionJd:2460581242087108e-9},peakMagnitude:0,peakOn:"2024-10-14",absoluteMagnitude:3.97,activityExponent:4,tailLengthDeg:20,tailLengthAu:.1902,note:"Briefly reported far brighter around 9 October 2024, when it stood almost between the observer and the Sun and forward-scattered the light through its own dust — a geometry this catalog's brightness model does not attempt, so what is stored is the ordinary evening-sky peak a few days later."}];class Tl{static WINDOW_DAYS=200;static TWILIGHT_ELONGATION_DEG=15;static LIGHT_SPEED_AU_PER_DAY=173.144632674;static orbits=new Map;static aroundDate(e){const t=this.julianDayOf(e);return iv.filter(n=>Math.abs(t-n.orbit.perihelionJd)<=this.WINDOW_DAYS)}static brightestAt(e,t){return this.aroundDate(e).map(n=>this.appearanceOf(n,e,t)).sort((n,i)=>n.magnitude-i.magnitude)[0]}static appearanceOf(e,t,n){const i=Zt(t),s=this.earthPositionAt(i),r=this.apparentPositionOf(e,2451545+i.tt,s),o=this.subtract(r,s),l=this.length(r),c=this.length(o),h=this.tailEndAt(e,r,s,l,i,t,n),d=this.horizontalOf(o,i,t,n);return{apparition:e,position:d,...h,heliocentricDistanceAu:l,earthDistanceAu:c,elongationDeg:this.angleBetween(o,this.subtract({x:0,y:0,z:0},s)),magnitude:this.magnitudeAt(e,l,c)}}static magnitudeAt(e,t,n){const i=e.absoluteMagnitude+5*Math.log10(n)+2.5*e.activityExponent*Math.log10(t);return Math.max(i,e.peakMagnitude)}static tailEndAt(e,t,n,i,s,r,o){if(e.tailLengthAu===void 0)return{};const l=1+e.tailLengthAu/i,c=this.subtract({x:t.x*l,y:t.y*l,z:t.z*l},n),h=this.subtract(t,n);return{tailEnd:this.horizontalOf(c,s,r,o),tailLengthDeg:this.angleBetween(h,c)}}static apparentPositionOf(e,t,n){const i=this.orbitOf(e);let s=i.positionAt(t);for(let r=0;r<2;r++){const o=this.length(this.subtract(s,n))/this.LIGHT_SPEED_AU_PER_DAY;s=i.positionAt(t-o)}return s}static horizontalOf(e,t,n,i){const s=_l(yE(),new xt(e.x,e.y,e.z,t)),r=_l(bE(t),s),o=$_(t,new Xu(i.lat,i.lng,i.elevationM)),l=new xt(r.x-o.x,r.y-o.y,r.z-o.z,t),c=Vg(l);return rr(c.ra,c.dec,n,i)}static earthPositionAt(e){return _l(vE(),ws(Me.Earth,e))}static julianDayOf(e){return 2451545+Zt(e).tt}static orbitOf(e){const t=this.orbits.get(e.id);if(t)return t;const n=new zi(e.orbit);return this.orbits.set(e.id,n),n}static subtract(e,t){return{x:e.x-t.x,y:e.y-t.y,z:e.z-t.z}}static length(e){return Math.hypot(e.x,e.y,e.z)}static angleBetween(e,t){const n=(e.x*t.x+e.y*t.y+e.z*t.z)/(this.length(e)*this.length(t)||1);return Math.acos(Math.min(1,Math.max(-1,n)))*180/Math.PI}}const gT=[{id:"quadrantids",code:"QUA",name:{en:"Quadrantids",fr:"Quadrantides"},radiantRaHours:15.33,radiantDecDeg:49.7,start:{month:12,day:28},peak:{month:1,day:3},end:{month:1,day:12},peakZhr:110,velocityKmS:41,populationIndex:2.1},{id:"lyrids",code:"LYR",name:{en:"April Lyrids",fr:"Lyrides d'avril"},radiantRaHours:18.13,radiantDecDeg:33.3,start:{month:4,day:16},peak:{month:4,day:22},end:{month:4,day:25},peakZhr:18,velocityKmS:49,populationIndex:2.1},{id:"eta-aquariids",code:"ETA",name:{en:"eta Aquariids",fr:"Êta Aquarides"},radiantRaHours:22.53,radiantDecDeg:-1,start:{month:4,day:19},peak:{month:5,day:6},end:{month:5,day:28},peakZhr:50,velocityKmS:66,populationIndex:2.4},{id:"alpha-capricornids",code:"CAP",name:{en:"alpha Capricornids",fr:"Alpha Capricornides"},radiantRaHours:20.47,radiantDecDeg:-9.2,start:{month:7,day:3},peak:{month:7,day:30},end:{month:8,day:15},peakZhr:5,velocityKmS:23,populationIndex:2.5},{id:"southern-delta-aquariids",code:"SDA",name:{en:"Southern delta Aquariids",fr:"Delta Aquarides du Sud"},radiantRaHours:22.67,radiantDecDeg:-16.4,start:{month:7,day:12},peak:{month:7,day:30},end:{month:8,day:23},peakZhr:25,velocityKmS:41,populationIndex:3.2},{id:"perseids",code:"PER",name:{en:"Perseids",fr:"Perséides"},radiantRaHours:3.22,radiantDecDeg:58,start:{month:7,day:17},peak:{month:8,day:12},end:{month:8,day:24},peakZhr:100,velocityKmS:59,populationIndex:2.2},{id:"southern-taurids",code:"STA",name:{en:"Southern Taurids",fr:"Taurides du Sud"},radiantRaHours:3.47,radiantDecDeg:13,start:{month:9,day:10},peak:{month:10,day:10},end:{month:11,day:20},peakZhr:5,velocityKmS:27,populationIndex:2.3},{id:"draconids",code:"DRA",name:{en:"October Draconids",fr:"Draconides d'octobre"},radiantRaHours:17.47,radiantDecDeg:54,start:{month:10,day:6},peak:{month:10,day:8},end:{month:10,day:10},peakZhr:10,velocityKmS:20,populationIndex:2.6},{id:"orionids",code:"ORI",name:{en:"Orionids",fr:"Orionides"},radiantRaHours:6.35,radiantDecDeg:15.6,start:{month:10,day:2},peak:{month:10,day:21},end:{month:11,day:7},peakZhr:20,velocityKmS:66,populationIndex:2.5},{id:"northern-taurids",code:"NTA",name:{en:"Northern Taurids",fr:"Taurides du Nord"},radiantRaHours:3.87,radiantDecDeg:22,start:{month:10,day:20},peak:{month:11,day:12},end:{month:12,day:10},peakZhr:5,velocityKmS:29,populationIndex:2.3},{id:"leonids",code:"LEO",name:{en:"Leonids",fr:"Léonides"},radiantRaHours:10.13,radiantDecDeg:21.6,start:{month:11,day:6},peak:{month:11,day:17},end:{month:11,day:30},peakZhr:15,velocityKmS:71,populationIndex:2.5},{id:"geminids",code:"GEM",name:{en:"Geminids",fr:"Géminides"},radiantRaHours:7.47,radiantDecDeg:32.3,start:{month:12,day:4},peak:{month:12,day:14},end:{month:12,day:17},peakZhr:150,velocityKmS:35,populationIndex:2.6},{id:"ursids",code:"URS",name:{en:"Ursids",fr:"Ursides"},radiantRaHours:14.47,radiantDecDeg:75.3,start:{month:12,day:17},peak:{month:12,day:22},end:{month:12,day:26},peakZhr:10,velocityKmS:33,populationIndex:3}],io=6.5;class Za{static activeAt(e){return gT.flatMap(t=>{const n=this.nearness(t,e);return n<=0?[]:[{shower:t,zhr:t.peakZhr*n,nearness:n}]})}static nearness(e,t){const n=this.dayOfYear(t),i=this.dayOfYear(this.asDate(e.start)),s=this.dayOfYear(this.asDate(e.peak)),r=this.dayOfYear(this.asDate(e.end)),o=this.wrappedDelta(n,s),l=this.wrappedDelta(s,i),c=this.wrappedDelta(r,s);return o<0?o<-l?0:1+o/l:o>0?o>c?0:1-o/c:1}static observedRatePerHour(e,t,n,i=io){if(t<=0)return 0;const s=io-i;return e*Math.sin(t*Math.PI/180)/Math.pow(n,s)}static radiantPosition(e,t,n){return rr(e.radiantRaHours,e.radiantDecDeg,t,n)}static dayOfYear(e){const t=Date.UTC(e.getUTCFullYear(),0,1);return Math.floor((Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate())-t)/864e5)+1}static asDate(e){return new Date(Date.UTC(2001,e.month-1,e.day))}static wrappedDelta(e,t){const n=e-t;return n>182?n-365:n<-182?n+365:n}}class Et{static QUIET_RATE_PER_HOUR=2;static APEX_RATE_PER_HOUR=8;static POPULATION_INDEX=3;static apexPosition(e,t){const n=Zt(e),i=new Vu(0,Y_(e).elon-90,1),s=_l(xE(n),Gg(i,n)),r=Vg(s);return rr(r.ra,r.dec,e,t)}static observedRatePerHour(e,t=io){const n=Et.APEX_RATE_PER_HOUR*Math.max(0,Math.sin(e*Math.PI/180)),i=io-t;return(Et.QUIET_RATE_PER_HOUR+n)/Math.pow(Et.POPULATION_INDEX,i)}static schedule(e){const t=new Xg(e.seed^1542469173);return Ks.schedule(e).map(n=>{const i=Et.toCartesian({altitudeDeg:Math.asin(t.next())*180/Math.PI,azimuthDeg:t.between(0,360)}),s=n.fromRadiantDeg*Math.PI/180,r=Et.turnAround(i,t.between(0,360)),o={x:i.x*Math.cos(s)+r.x*Math.sin(s),y:i.y*Math.cos(s)+r.y*Math.sin(s),z:i.z*Math.cos(s)+r.z*Math.sin(s)};return{...n,radiant:Et.toHorizontal(o),bearingDeg:Et.bearingFrom(o,i)}})}static turnAround(e,t){const[n,i]=Et.basisAround(e),s=t*Math.PI/180;return{x:n.x*Math.cos(s)+i.x*Math.sin(s),y:n.y*Math.cos(s)+i.y*Math.sin(s),z:n.z*Math.cos(s)+i.z*Math.sin(s)}}static bearingFrom(e,t){const[n,i]=Et.basisAround(e),s=e.x*t.x+e.y*t.y+e.z*t.z,r=Et.normalise({x:t.x-e.x*s,y:t.y-e.y*s,z:t.z-e.z*s});return(Math.atan2(r.x*i.x+r.y*i.y+r.z*i.z,r.x*n.x+r.y*n.y+r.z*n.z)*180/Math.PI%360+360)%360}static basisAround(e){const t=Math.abs(e.y)<.9?{x:0,y:1,z:0}:{x:1,y:0,z:0},n=Et.normalise(Et.cross(e,t));return[n,Et.normalise(Et.cross(e,n))]}static toHorizontal(e){const t=Math.hypot(e.x,e.y,e.z)||1;return{altitudeDeg:Math.asin(Math.min(1,Math.max(-1,e.y/t)))*180/Math.PI,azimuthDeg:(Math.atan2(e.x,-e.z)*180/Math.PI%360+360)%360}}static appearanceOf(e){const t=Et.toCartesian(e.radiant??{altitudeDeg:90,azimuthDeg:0}),n=Et.turnAround(t,e.bearingDeg),i=e.fromRadiantDeg*Math.PI/180;return Et.toHorizontal({x:t.x*Math.cos(i)+n.x*Math.sin(i),y:t.y*Math.cos(i)+n.y*Math.sin(i),z:t.z*Math.cos(i)+n.z*Math.sin(i)})}static toCartesian(e){const t=e.altitudeDeg*Math.PI/180,n=e.azimuthDeg*Math.PI/180,i=Math.cos(t);return{x:i*Math.sin(n),y:Math.sin(t),z:-i*Math.cos(n)}}static cross(e,t){return{x:e.y*t.z-e.z*t.y,y:e.z*t.x-e.x*t.z,z:e.x*t.y-e.y*t.x}}static normalise(e){const t=Math.hypot(e.x,e.y,e.z)||1;return{x:e.x/t,y:e.y/t,z:e.z/t}}static TYPICAL_VELOCITY_KM_S=40}class vT{lowerM;upperM;add(e,t){if(!(e<=0)){if(t.behindM!==void 0){const n=et.sizeMAt(t.behindM,e);this.lowerM=this.lowerM===void 0?n:Math.max(this.lowerM,n)}if(t.inFrontM!==void 0){const n=et.sizeMAt(t.inFrontM,e);this.upperM=this.upperM===void 0?n:Math.min(this.upperM,n)}}}get sizeRange(){return{minM:this.lowerM,maxM:this.upperM}}get empty(){return this.lowerM===void 0&&this.upperM===void 0}get contradictory(){return this.lowerM!==void 0&&this.upperM!==void 0&&this.lowerM>this.upperM}distanceRangeAt(e){return e<=0?{}:{minM:this.lowerM===void 0?void 0:et.distanceMAt(this.lowerM,e),maxM:this.upperM===void 0?void 0:et.distanceMAt(this.upperM,e)}}clear(){this.lowerM=void 0,this.upperM=void 0}}class Ja{static DEG_PER_SECOND=360/86164.0905;static degOver(e){return Math.max(0,e)*Ja.DEG_PER_SECOND}static instants(e,t){if(!(t>0))return 1;const n=Ja.degOver(e)/t;return n<1?1:Math.min(Ja.MAX_INSTANTS,Math.max(2,Math.ceil(n)))}static MAX_INSTANTS=64}class hn{static EYE={apertureMm:7,exposureSeconds:.1,resolutionArcsec:60};static WAVELENGTH_M=55e-8;static ARCSEC_PER_RADIAN=180*3600/Math.PI;static UNKNOWN_CAMERA_FOCAL_MM=50;static UNKNOWN_CAMERA_DETAIL_UM=20;static get skyDriftArcsecPerSecond(){return Ja.DEG_PER_SECOND*3600}static graspOf(e,t={}){const n=t.exposureSeconds??e.exposureSeconds,i=t.fNumber??e.fNumber;if(n===void 0||i===void 0||!(n>0)||!(i>0))return hn.EYE;const s=t.focalLengthMm??e.frame?.focalLengthMm??hn.UNKNOWN_CAMERA_FOCAL_MM,r=s/i,o=hn.resolutionArcsec(e,s,r);return{apertureMm:r,exposureSeconds:Math.min(n,hn.trailLimitedSeconds(o)),resolutionArcsec:o}}static resolutionArcsec(e,t,n){const s=(e.detailUm??hn.UNKNOWN_CAMERA_DETAIL_UM)/1e3/t*hn.ARCSEC_PER_RADIAN,r=1.22*hn.WAVELENGTH_M/(n/1e3)*hn.ARCSEC_PER_RADIAN;return Math.max(s,r)}static trailLimitedSeconds(e){return e/hn.skyDriftArcsecPerSecond}static gainOverEye(e,t={}){const n=hn.graspOf(e,t),i=hn.EYE,s=(n.apertureMm/i.apertureMm)**2,r=n.exposureSeconds/i.exposureSeconds,o=(i.resolutionArcsec/n.resolutionArcsec)**2;return 1.25*Math.log10(s*r*o)}static gainFor(e,t){const n=t.fieldOfViewDeg===void 0?void 0:st.focalLengthMmFor(e,t.fieldOfViewDeg);return hn.gainOverEye(e,{fNumber:t.fNumber,focalLengthMm:n,exposureSeconds:t.exposureSeconds})}}class Hi{static PIXELS_PER_INSTANT=2;static INSTANTS_PER_FLASH=2;static MAX_INSTANTS=512;static instants(e,t,n,i,s){if(!(i>0))return 1;const r=s>0?Hi.travelDegOver(e,t,n,n+i*1e3)/s/Hi.PIXELS_PER_INSTANT:0,o=Hi.flashesOver(e,i)*Hi.INSTANTS_PER_FLASH,l=Math.ceil(Math.max(r,o));return l<2?1:Math.min(Hi.MAX_INSTANTS,l)}static travelDegOver(e,t,n,i){let s=0;for(const r of e){if(!r.track||r.track.length<2)continue;const o=Hi.directionAt(r,t,n),l=Hi.directionAt(r,t,i),c=Math.min(1,Math.max(-1,o.x*l.x+o.y*l.y+o.z*l.z));s=Math.max(s,Math.acos(c)*180/Math.PI)}return s}static flashesOver(e,t){let n=0;for(const i of e)for(const s of i.lights??[])s.pattern.kind==="flash"&&(n=Math.max(n,s.pattern.perMinute));return n/60*t}static directionAt(e,t,n){const i=Qa(e,n),s=i.eastM,r=i.altitudeM-t,o=i.northM,l=Math.hypot(s,r,o);return l===0?{x:0,y:1,z:0}:{x:s/l,y:r/l,z:o/l}}}const tm=111320,Cr=Math.PI/180,yT=1.02,bT=1;class qr{static of(e,t){const n=qr.sightings(e,t);if(n.length<2)return;const i=qr.baseline(n);if(!i)return;const{near:s,far:r,closedM:o}=i,l=Math.tan(r.widthDeg/2*Cr)===0?0:Math.tan(s.widthDeg/2*Cr)/Math.tan(r.widthDeg/2*Cr);if(l<yT)return;const c=o/(l-1),h=et.sizeMAt(c,s.widthDeg),d=n.map(u=>({t:u.t,m:et.distanceMAt(h,u.widthDeg)}));return{widthM:h,distanceM:d,nearestM:Math.min(...d.map(u=>u.m)),fromT:r.t,toT:s.t,closedM:o}}static sightings(e,t){return e.timeline.allKeyframes.flatMap(n=>{const i=n.shapes.find(o=>o.sourceId===t)?.shape,s=i?.angular?.widthDeg,r=at(e,n.t);return s===void 0||s<=0||r?.lat===void 0||r.lng===void 0?[]:[{t:n.t,widthDeg:s,lat:r.lat,lng:r.lng,sightAzimuthDeg:i?.aim?.azimuthDeg??r.headingDeg}]}).sort((n,i)=>n.t-i.t)}static baseline(e){let t;for(const n of e)for(const i of e){if(n.t>=i.t)continue;const s=qr.closedAlongSight(n,i),[r,o,l]=s>=0?[i,n,s]:[n,i,-s];l<bT||r.widthDeg<=o.widthDeg||(!t||l>t.closedM)&&(t={near:r,far:o,closedM:l})}return t}static closedAlongSight(e,t){const n=(t.lat-e.lat)*tm,i=(t.lng-e.lng)*tm*Math.cos(e.lat*Cr),s=(e.sightAzimuthDeg??0)*Cr;return n*Math.cos(s)+i*Math.sin(s)}}class yn{static CONVENTIONAL_M=5;static NEAREST_M=.2;static MARGIN=1.1;static resolve(e){if(e.statedM!==void 0&&e.statedM>0)return{distanceM:yn.atLeastNearest(e.statedM),basis:"stated"};if(e.hypothesisM!==void 0&&e.hypothesisM>0)return{distanceM:yn.atLeastNearest(e.hypothesisM),basis:"hypothesis"};if(e.derivedM!==void 0&&e.derivedM>0)return{distanceM:yn.atLeastNearest(e.derivedM),basis:"derived"};const t=yn.largest(e.range?.minM,e.crossing?.behindM),n=yn.smallest(e.range?.maxM,e.crossing?.inFrontM),i=t===void 0?void 0:t*yn.MARGIN,s=n===void 0?void 0:n/yn.MARGIN;return i!==void 0&&s!==void 0?{distanceM:yn.atLeastNearest(i<=s?Math.sqrt(i*s):i),basis:"bounded"}:i!==void 0?{distanceM:yn.atLeastNearest(i),basis:"bounded"}:s!==void 0&&s<yn.CONVENTIONAL_M?{distanceM:yn.atLeastNearest(s),basis:"bounded"}:{distanceM:yn.CONVENTIONAL_M,basis:"conventional"}}static atLeastNearest(e){return Math.max(yn.NEAREST_M,e)}static largest(...e){const t=e.filter(n=>n!==void 0&&n>0);return t.length===0?void 0:Math.max(...t)}static smallest(...e){const t=e.filter(n=>n!==void 0&&n>0);return t.length===0?void 0:Math.min(...t)}}Ql();const xT={sun:{en:"Sun",fr:"Soleil"},moon:{en:"Moon",fr:"Lune"},Venus:{en:"Venus",fr:"Vénus"},Mars:{en:"Mars",fr:"Mars"},Jupiter:{en:"Jupiter",fr:"Jupiter"},Saturn:{en:"Saturn",fr:"Saturne"}},wT=["en","fr"],MT={en:"{name} — mag {mag}, {alt}° above the horizon",fr:"{name} — mag {mag}, {alt}° au-dessus de l'horizon"},ST={en:"{name} — mag {mag}, {alt}° below the horizontal",fr:"{name} — mag {mag}, {alt}° sous l'horizontale"},nm="comet:",_T={building:{en:"Building",fr:"Bâtiment"},tree:{en:"Tree",fr:"Arbre"},crop:{en:"Crop row",fr:"Rang de culture"},mound:{en:"Stone heap",fr:"Tas de pierres"},streetlight:{en:"Streetlight",fr:"Lampadaire"},vehicle:{en:"Vehicle",fr:"Véhicule"},witness:{en:"Witness",fr:"Témoin"},aircraft:{en:"Aircraft",fr:"Aéronef"},entity:{en:"Being",fr:"Être"}},ET=new URL(""+new URL("stars-mag7.5-B43R6Wvg.bin",import.meta.url).href,import.meta.url).href,TT=new URL(""+new URL("stars-mag7.5-9-BLV2tFmZ.bin",import.meta.url).href,import.meta.url).href,AT=-18,IT={sun:{altitudeDeg:-3,azimuthDeg:180,magnitude:-26.7},moon:{altitudeDeg:-90,azimuthDeg:0,phase:{phaseFraction:0,illuminatedFraction:0},magnitude:-12.7},planets:[]},Eh={lat:0,lng:0,elevationM:0,headingDeg:void 0,pitchDeg:0,fovDeg:60};class DT extends HTMLElement{static get observedAttributes(){return["src","star-catalog-src","deep-star-catalog-src","show-compass",Ys,Ha]}shadow;stageElement;frameElement;sceneCanvas;ufoElement;sceneRenderer;hoverTooltip;resizeObserver;sizeEstimates=new Map;sizeEstimatesFor;distanceHypotheses=new Map;depths=new Map;directionScratch=new P;meteorScheduleFor;lastTimeMs=0;lastSkyKey;starCatalog;starCatalogRequest=0;starCatalogDepth=0;weatherAudio=new mT;animateWhilePausedValue=!1;set animateWhilePaused(e){e!==this.animateWhilePausedValue&&(this.animateWhilePausedValue=e,this.syncAnimationsToPlayback())}get animateWhilePaused(){return this.animateWhilePausedValue}thunderTimeoutId;handleFullscreenChange=()=>this.resizeToStage();handlePointerMove=e=>{this.sceneRenderer.setCompassHovered(!0);const t=this.ufoElement.canvasElement,n=t.getBoundingClientRect();if(n.width===0||n.height===0)return;const i=(e.clientX-n.left)/n.width*t.width,s=(e.clientY-n.top)/n.height*t.height;if(this.ufoElement.hasVisibleShapeAt(i,s)){this.hoverTooltip.hidden=!0;return}const r=(e.clientX-n.left)/n.width*2-1,o=-((e.clientY-n.top)/n.height*2-1),l=za(vs.preferencesFor(this),wT),c=this.sceneRenderer.pickBodyAt(r,o);if(c){this.showHoverTooltip(e,this.bodyName(c,l));return}const h=this.sceneRenderer.pickDecorAt(r,o),d=h?this.ufoElement.sighting.decor.find(f=>f.id===h):void 0;if(d){this.showHoverTooltip(e,this.said.read(d.title)||_T[d.kind][l]);return}const u=this.sceneRenderer.pickStarAt(r,o);if(u){const f=u.star.mag,p=u.altitudeDeg,v=(p<0?ST:MT)[l];this.showHoverTooltip(e,v.replace("{name}",u.star.name[l]).replace("{mag}",f.toLocaleString(void 0,{maximumFractionDigits:Math.abs(f)<1?2:1})).replace("{alt}",String(Math.round(Math.abs(p)))));return}this.hoverTooltip.hidden=!0};bodyName(e,t){const n=e.startsWith(nm)?e.slice(nm.length):void 0;return(n?iv.find(s=>s.id===n):void 0)?.name[t]??xT[e]?.[t]??e}showHoverTooltip(e,t){this.hoverTooltip.textContent=t,this.hoverTooltip.hidden=!1;const n=this.stageElement.getBoundingClientRect();this.hoverTooltip.style.left=`${e.clientX-n.left+12}px`,this.hoverTooltip.style.top=`${e.clientY-n.top+12}px`}handlePointerLeave=()=>{this.hoverTooltip.hidden=!0,this.sceneRenderer.setCompassHovered(!1)};handleLightningFlash=()=>{clearTimeout(this.thunderTimeoutId);const e=(.5+Math.random()*3.5)*1e3;this.thunderTimeoutId=window.setTimeout(()=>this.weatherAudio.playThunder(),e)};handleFirstInteraction=()=>{this.weatherAudio.resume(),this.setWeather(Ht(this.ufoElement.sighting,this.lastTimeMs))};handleTimeUpdate=e=>{this.lastTimeMs=e.detail.time,this.syncAnimationsToPlayback(),this.updateAstronomy(this.lastTimeMs)};syncAnimationsToPlayback(){const e=this.ufoElement.playbackState==="playing"||this.animateWhilePaused;this.sceneRenderer.setAnimationsRunning(e),this.weatherAudio.setPaused(!e),e||clearTimeout(this.thunderTimeoutId)}constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${C1}</style>${D1}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.frameElement=this.shadow.getElementById("frame"),this.sceneCanvas=this.shadow.getElementById("scene-canvas"),this.sceneRenderer=new mi(this.sceneCanvas,void 0,this.handleLightningFlash),this.hoverTooltip=this.shadow.getElementById("hover-tooltip"),this.ufoElement=document.createElement(Gh),this.ufoElement.classList.add("ufo-overlay"),this.ufoElement.paintsShapes=!1,this.forwardPlayerAttributes(),this.ufoElement.addEventListener("lookat",t=>this.lookToward(t.detail)),this.ufoElement.style.setProperty("--ufo-canvas-background","transparent"),this.ufoElement.style.setProperty("--ufo-canvas-border","none"),this.ufoElement.fullscreenTarget=this.stageElement,this.shadow.getElementById("ufo-slot").replaceWith(this.ufoElement),this.ufoElement.addEventListener("timeupdate",this.handleTimeUpdate),this.ufoElement.canvasElement.addEventListener("pointermove",this.handlePointerMove),this.ufoElement.canvasElement.addEventListener("pointerleave",this.handlePointerLeave),this.ufoElement.canvasElement.addEventListener("pointerdown",this.handleFirstInteraction,{once:!0})}get said(){return this.saidTexts??=new Gi(vs.preferencesFor(this))}saidTexts;connectedCallback(){this.saidTexts=void 0,this.resizeToStage(),this.updateAstronomy(this.lastTimeMs),this.loadStars(),this.resizeObserver=new ResizeObserver(()=>this.resizeToStage()),this.resizeObserver.observe(this.frameElement),document.addEventListener("fullscreenchange",this.handleFullscreenChange);const e=this.getAttribute("src");e&&this.loadFromSrc(e)}disconnectedCallback(){this.resizeObserver?.disconnect(),document.removeEventListener("fullscreenchange",this.handleFullscreenChange),this.sceneRenderer.stopTwinkle(),clearTimeout(this.thunderTimeoutId),this.weatherAudio.dispose()}attributeChangedCallback(e,t,n){e==="src"&&n&&n!==t&&this.isConnected&&this.loadFromSrc(n),(e==="star-catalog-src"||e==="deep-star-catalog-src")&&n!==t&&this.isConnected&&this.loadStars(),e==="show-compass"&&n!==t&&this.sceneRenderer.setShowCompass(this.hasAttribute("show-compass")),(e===Ys||e===Ha)&&n!==t&&this.forwardPlayerAttributes()}forwardPlayerAttributes(){for(const e of[Ys,Ha])this.ufoElement.toggleAttribute(e,this.hasAttribute(e))}setCompassForced(e){this.sceneRenderer.setCompassForced(e)}lookToward(e){const t=at(this.ufoElement.sighting,this.lastTimeMs);if(e.kind==="witness"||t?.lat===void 0||t.lng===void 0||t.headingDeg===void 0){this.setLookOffset(0,0);return}const{x:n,z:i}=un(e.lat,e.lng,t.lat,t.lng);if(Math.hypot(n,i)<1)return this.setLookOffset(0,0);const s=(Math.atan2(n,-i)*180/Math.PI+360)%360;this.setLookOffset(((s-t.headingDeg)%360+540)%360-180,-t.pitchDeg)}setLookOffset(e,t){this.sceneRenderer.setLookOffset(e,t),this.ufoElement.setLookOffset(e,t),this.updateAstronomy(this.lastTimeMs)}setIndoorLook(e,t){this.sceneRenderer.setIndoorLook(e,t)}setCloudRendering(e){this.sceneRenderer.setCloudRendering(e)}setWeather(e){this.sceneRenderer.setWeather(e),this.weatherAudio.setAmbient(e.precipitationType,e.precipitationIntensity,e.windSpeed)}pickCloudAt(e,t){return this.sceneRenderer.pickCloudAt(e,t)}cloudDirectionAt(e,t){return this.sceneRenderer.cloudDirectionAt(e,t)}pickDecorAt(e,t){return this.sceneRenderer.pickDecorAt(e,t)}resumeWeatherAudio(){this.weatherAudio.resume()}async loadFromSrc(e){this.sightingData=await fu.json(e)}get sightingData(){return this.ufoElement.sightingData}set sightingData(e){this.ufoElement.sightingData=e,this.applyFrameFormat(),this.lastTimeMs=0,this.updateAstronomy(0)}get currentTerrainAttribution(){return this.sceneRenderer.currentTerrainAttribution}setTerrainProviders(e){this.sceneRenderer.setTerrainProviders(e)}setDecorModelProvider(e){this.sceneRenderer.setDecorModelProvider(e)}get decorModelCredits(){return this.sceneRenderer.currentDecorModelCredits}applyFrameFormat(){const e=this.ufoElement.sighting.instrument,t=et.CANVAS_HEIGHT_PX,n=st.frameWidthPx(e,t);this.frameElement.style.setProperty("--frame-aspect",`${n} / ${t}`)}resizeToStage(){const e=this.frameElement.getBoundingClientRect(),t=Math.max(1,Math.round(e.width)),n=Math.max(1,Math.round(e.height));this.sceneCanvas.width=t,this.sceneCanvas.height=n,this.sceneRenderer.resize(t,n)}async loadStars(){const e=[{magnitudeLimit:_h,url:this.getAttribute("star-catalog-src")??ET},{magnitudeLimit:Xr,url:this.getAttribute("deep-star-catalog-src")??TT}],t=this.instrumentReach(),n=++this.starCatalogRequest;this.starCatalogDepth=t>_h?Xr:_h;const i=await gi.upTo(e,t);n===this.starCatalogRequest&&(this.starCatalog=i,this.updateAstronomy(this.lastTimeMs))}ensureStarsDeepEnough(){!this.starCatalog||this.starCatalogDepth>=Xr||this.instrumentReach()<=this.starCatalogDepth||this.loadStars()}instrumentReach(){const e=this.ufoElement.sighting,t=hn.gainFor(e.instrument,{fNumber:at(e,0)?.fNumber,fieldOfViewDeg:an.fovOf(e,0),exposureSeconds:e.exposure});return Hr(AT,t)}updateAstronomy(e){this.ensureStarsDeepEnough(),this.applySceneAt(e);const t=this.exposureSeconds(),n=this.degreesPerPixelAt(e),i=Ja.instants(t,n),s=Math.max(i,this.ufoElement.exposureTimes(e).length,Hi.instants(this.ufoElement.sighting.decor,at(this.ufoElement.sighting,e)?.elevationM??0,e,t,n));if(s<=1){this.sceneRenderer.setExposure(1);return}const r=t*1e3;this.sceneRenderer.setExposure(s,o=>this.applySceneAt(e+r*o/s,{sky:Math.floor(o*i/s)!==Math.floor((o-1)*i/s),stepMs:r/s}))}exposureSeconds(){return this.ufoElement.sighting.exposure??0}degreesPerPixelAt(e){const t=this.sceneCanvas.height;return t<=0?0:an.fovOf(this.ufoElement.sighting,e)/t}applySceneAt(e,t){const n=this.ufoElement.sighting;this.setWeather(Ht(n,e)),this.sceneRenderer.setInstrument(n.instrument),this.updateMeteorShower(n,e),this.sceneRenderer.setDecor(n.decor);const i=at(n,e),s=at(n,0),r=Ht(n,0),o=Object.fromEntries(_i(Ht(n,e)).map(g=>[g.id,Il(e,n.weatherTrack,r,s,i,g.id)]));if(this.sceneRenderer.setCloudOffset(Il(e,n.weatherTrack,r,s,i),o),this.sceneRenderer.setObserverPose(i??Eh),this.sceneRenderer.setLensOptics(this.lensOpticsAt(e)),this.sceneRenderer.setInstrumentGain(hn.gainFor(n.instrument,{fNumber:i?.fNumber,fieldOfViewDeg:an.fovOf(n,e),exposureSeconds:n.exposure})),this.sceneRenderer.setGait(qt.of(n)?.offsetAt(e)??qt.STILL),this.sceneRenderer.updateDecorAnchoring(at(n,0),i,e),this.sceneRenderer.updateDecorLitState(e,t?.stepMs??0),this.sceneRenderer.setTerrainOrigin(i?.lat,i?.lng),this.pushPhenomenaAt(e),t&&!t.sky)return;const l=i?.lat??Eh.lat,c=i?.lng??Eh.lng,h=Ka(n.event.time??{},c,n.event.utcOffsetHours);if(!h){this.sceneRenderer.setAstronomy(IT);return}const d=new Date(h.getTime()+e),u={lat:l,lng:c,elevationM:i?.elevationM??0},f=`${d.getTime()}|${l}|${c}|${u.elevationM}|${this.starCatalog?this.starCatalogDepth:0}`;if(f===this.lastSkyKey){this.sceneRenderer.render();return}this.lastSkyKey=f;const p={...Un("Sun",d,u),magnitude:rh("Sun",d)},v={...Un("Moon",d,u),phase:Kl(d),magnitude:rh("Moon",d)},m=wE.map(g=>({body:g,position:Un(g,d,u),magnitude:rh(g,d)}));this.sceneRenderer.setAstronomy({sun:p,moon:v,planets:m,comet:this.cometAt(d,u),stars:this.starCatalog?{catalog:this.starCatalog,date:d,observer:u}:void 0,frame:{date:d,observer:u}}),this.ufoElement.setSunAltitude(p.altitudeDeg)}cometAt(e,t){const n=Tl.brightestAt(e,t);if(n)return{id:n.apparition.id,position:n.position,tailEnd:n.tailEnd,magnitude:n.magnitude}}pushPhenomenaAt(e){const t=this.ufoElement.sighting;t!==this.sizeEstimatesFor&&(this.sizeEstimates.clear(),this.distanceHypotheses.clear(),this.sizeEstimatesFor=t);const n=t.timeline,i=this.ufoElement.canvasElement,s=this.ufoElement.frameShiftPx,r=this.projectionAt(e),o=new Map,l=new Map,c=new Set;for(const p of n.sourceIds){const v=n.getInterpolatedShapeAt(e,p);if(!v)continue;const m={...v,bounds:{...v.bounds,x:v.bounds.x+s.x,y:v.bounds.y+s.y}};o.set(p,m);const g=v.aim?this.sceneRenderer.screenPointOf(jn.directionOf(v.aim,this.directionScratch)):{ndcX:(m.bounds.x+m.bounds.width/2)/i.width*2-1,ndcY:-((m.bounds.y+m.bounds.height/2)/i.height*2-1)},_=g!==void 0&&Math.abs(g.ndcX)<=1&&Math.abs(g.ndcY)<=1,M=_?this.sceneRenderer.decorDistancesAt(g.ndcX,g.ndcY,p):{};c.add(p),(_||v.aim)&&c.delete(p);const x=v.angular?.widthDeg??r.pxToDeg(v.bounds.width),w=this.sizeEstimateOf(p);w.add(x,M);const E=qr.of(t,p);l.set(p,yn.resolve({hypothesisM:this.distanceHypotheses.get(p),derivedM:E&&x>0?et.distanceMAt(E.widthM,x):void 0,range:w.distanceRangeAt(x),crossing:M}))}for(const[p,v]of o)for(const[m,g]of o){if(m===p||g.transparency>=1||g.bounds.width*g.bounds.height<=v.bounds.width*v.bounds.height||!(v.bounds.x>=g.bounds.x&&v.bounds.y>=g.bounds.y&&v.bounds.x+v.bounds.width<=g.bounds.x+g.bounds.width&&v.bounds.y+v.bounds.height<=g.bounds.y+g.bounds.height))continue;const M=l.get(m);M&&l.set(p,{distanceM:M.distanceM*.999,basis:M.basis});break}this.depths=l;const h=n.sourceIds,d=[];for(const[p,v]of o)d.push({sourceId:p,shape:v,distanceM:l.get(p).distanceM,renderOrder:h.indexOf(p),aim:v.aim,hidden:c.has(p)});const f=(at(t,e)?.rollDeg??0)+(qt.of(t)?.offsetAt(e)??qt.STILL).rollDeg;this.sceneRenderer.setPhenomena(d,{projection:r,canvasWidthPx:i.width,canvasHeightPx:i.height,scale:Math.max(1,this.sceneCanvas.height/Math.max(1,i.height)),starPoints:st.starPointsOf(t.instrument),rollRad:f*Math.PI/180})}setDistanceHypothesis(e,t){t===void 0||!(t>0)?this.distanceHypotheses.delete(e):this.distanceHypotheses.set(e,t),this.updateAstronomy(this.lastTimeMs)}depthOf(e){return this.depths.get(e)}sizeRangeOf(e){return this.sizeEstimateOf(e).sizeRange}distanceRangeAt(e,t){const n=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(t,e);if(!n)return{};const i=n.angular?.widthDeg??this.projectionAt(t).pxToDeg(n.bounds.width);return this.sizeEstimateOf(e).distanceRangeAt(i)}sizeContradictory(e){return this.sizeEstimateOf(e).contradictory}updateMeteorShower(e,t){this.ensureMeteorSchedule(e),this.sceneRenderer.updateMeteors(t)}ensureMeteorSchedule(e){const t=this.meteorInputsOf(e);t!==this.meteorScheduleFor&&(this.meteorScheduleFor=t,this.scheduleMeteors(e))}meteorInputsOf(e){const t=e.event.place?.[0],n=e.event.time;return JSON.stringify([t?.lat,t?.lng,n?.year,n?.month,n?.day,n?.hour,n?.minute,e.event.utcOffsetHours,e.event.durationSeconds,e.timeline.duration])}scheduleMeteors(e){const t=e.event.place?.[0],n=e.event.time,i=t?.lat!==void 0&&t.lng!==void 0&&n?.year!==void 0?Ka(n,t.lng,e.event.utcOffsetHours):void 0;if(!i||t?.lat===void 0||t.lng===void 0){this.sceneRenderer.setMeteorShower([],0,0);return}const s={lat:t.lat,lng:t.lng,elevationM:0},r=(e.event.durationSeconds??0)*1e3||e.timeline.duration||2e4,o=Math.round(i.getTime()/1e3)+Math.round(t.lat*1e3),l=Et.schedule({ratePerHour:Et.observedRatePerHour(Et.apexPosition(i,s).altitudeDeg),durationMs:r,velocityKmS:Et.TYPICAL_VELOCITY_KM_S,seed:o}),c=Za.activeAt(i).map(d=>{const u=Za.radiantPosition(d.shower,i,s);return{entry:d,position:u,rate:Za.observedRatePerHour(d.zhr,u.altitudeDeg,d.shower.populationIndex)}}).sort((d,u)=>u.rate-d.rate)[0];if(!c||c.rate<=0){this.sceneRenderer.setMeteorShower(l,0,0);return}const h=Ks.schedule({ratePerHour:c.rate,durationMs:r,velocityKmS:c.entry.shower.velocityKmS,seed:o+1});this.sceneRenderer.setMeteorShower([...h,...l],c.position.altitudeDeg,c.position.azimuthDeg)}meteorByRank(e){this.ensureMeteorSchedule(this.ufoElement.sighting);const t=[...this.sceneRenderer.meteorSchedule].filter(s=>s.t+s.durationMs<=this.ufoElement.seekableDuration).sort((s,r)=>r.brightness-s.brightness);if(t.length===0)return;const n=t[e%t.length],i=this.sceneRenderer.meteorMidpoint(n);if(i)return{t:Math.round(n.t+n.durationMs*.45),...i}}lensOpticsAt(e){const t=this.ufoElement.sighting,n=t.instrument,i=n.frame,s=at(t,e),r=s?.fNumber??n.fNumber;if(!i||r===void 0)return;const o=st.focalLengthMmFor(n,an.fovOf(t,e));if(o!==void 0)return{focalLengthMm:o,fNumber:r,focusDistance:s?.focusDistanceM??0,frameHeightMm:i.heightMm}}projectionAt(e){const t=this.ufoElement.sighting;return ni.of(t.instrument,et.CANVAS_HEIGHT_PX,an.fovOf(t,e))}sizeEstimateOf(e){let t=this.sizeEstimates.get(e);return t||(t=new vT,this.sizeEstimates.set(e,t)),t}}const hu="rr0-scene";function CT(){Ql(),customElements.get(hu)||customElements.define(hu,DT)}class RT{constructor(e,t){this.timeline=e,this.clock=t}currentPointer=null;shapePrototype=null;sourceId="";start(e,t){this.sourceId=e,this.shapePrototype=t,this.currentPointer=null,this.clock.start(n=>this.recordSample(n))}onPointerMove(e,t){this.currentPointer={x:e,y:t}}stop(){this.clock.stop()}recordSample(e){if(!this.currentPointer||!this.shapePrototype)return;const t=wm(this.shapePrototype,this.currentPointer.x,this.currentPointer.y);this.timeline.addKeyframe(e,[{sourceId:this.sourceId,shape:t}])}}class PT{constructor(e){this.intervalMs=e}rafId=null;startTime=0;lastTick=0;start(e){this.startTime=performance.now(),this.lastTick=0;const t=()=>{const n=performance.now()-this.startTime;n-this.lastTick>=this.intervalMs&&(this.lastTick=n,e(n)),this.rafId=requestAnimationFrame(t)};this.rafId=requestAnimationFrame(t)}stop(){this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}}const LT=[{id:"echo",name:{en:"the Echo balloons",fr:"les ballons Echo"},from:"1960-08-12",to:"1969-06-07",peakMagnitude:-1,note:"Echo 1 and 2 were 30- and 40-metre reflective balloons, as bright as the brightest stars and moving slowly enough to be watched — deliberately visible, widely announced in newspapers, and the first objects most people ever saw crossing the night sky. They fall squarely inside the sighting waves this project reconstructs."},{id:"iridium-flares",name:{en:"the Iridium flares",fr:"les flashes d'Iridium"},from:"1997-05-05",to:"2019-12-27",peakMagnitude:-8,note:"The original Iridium satellites carried flat, mirror-finish antennas that threw a sunbeam a few kilometres wide across the ground: a still point of sky flaring to magnitude -8 over five seconds and vanishing again. Nothing else in the sky does that."},{id:"iss",name:{en:"the International Space Station",fr:"la Station spatiale internationale"},from:"1998-11-20",peakMagnitude:-5.9,note:"Since its first module, and much brighter as it grew: at its best it outshines everything in the sky but the Sun and the Moon, crossing in a straight silent line in about four minutes."},{id:"starlink-trains",name:{en:"the Starlink trains",fr:"les trains de Starlink"},from:"2019-05-24",peakMagnitude:1,note:"In the days after a launch, satellites still bunched in their deployment string cross as an evenly spaced line of lights — the most reported 'formation of UFOs' of the era. They spread out within weeks, so a train is a fact about the days after a launch rather than about the year."}],NT=23493,im=[2,3,2,1,2,5,4,6,5,6,6,6,6,6,6,6,9,9,9,9,9,9,14,14,15,16,16,16,16,16,18,22,25,24,29,28,29,33,34,35,40,40,42,42,43,46,48,48,49,53,53,54,58,61,70,70,74,78,79,83,92,92,99,97,101,102,109,115,126,125,123,125,127,130,139,153,157,156,161,156,165,174,193,193,201,203,212,215,224,244,255,263,262,281,293,307,312,327,339,336,343,353,359,369,386,396,405,410,421,419,424,434,443,450,460,480,492,504,509,516,519,524,527,530,527,535,543,549,564,571,573,576,582,584,600,600,608,618,625,632,637,642,648,654,661,667,669,667,671,671,697,692,703,697,710,714,724,731,747,755,764,770,782,802,801,815,819,837,846,856,878,881,877,900,906,907,917,932,932,936,954,973,989,986,991,990,1002,1009,1021,1024,1040,1038,1058,1078,1098,1092,1094,1099,1122,1132,1140,1151,1154,1161,1176,1185,1202,1206,1227,1228,1243,1265,1281,1288,1296,1325,1328,1336,1354,1373,1375,1393,1398,1411,1432,1457,1462,1476,1487,1485,1506,1509,1521,1524,1537,1543,1563,1586,1598,1614,1621,1620,1640,1658,1660,1673,1670,1686,1708,1715,1726,1726,1745,1749,1767,1774,1790,1798,1803,1805,1815,1818,1819,1820,1833,1822,1821,1819,1838,1835,1845,1841,1851,1869,1865,1868,1871,1870,1879,1882,1886,1900,1899,1908,1921,1928,1954,1966,1976,1986,1999,2007,2015,2030,2036,2057,2067,2072,2077,2088,2101,2106,2112,2119,2127,2142,2171,2176,2203,2226,2242,2241,2244,2254,2263,2284,2300,2320,2327,2345,2364,2367,2402,2423,2425,2434,2443,2461,2476,2495,2505,2520,2531,2535,2556,2567,2599,2608,2625,2639,2660,2663,2668,2681,2695,2702,2709,2719,2720,2738,2746,2763,2778,2788,2796,2807,2822,2831,2831,2853,2863,2866,2883,2892,2895,2921,2919,2937,2941,2947,2964,2987,2992,2987,2995,3002,3021,3025,3026,3036,3052,3049,3059,3077,3075,3083,3086,3107,3123,3124,3146,3155,3168,3179,3204,3205,3211,3233,3252,3253,3276,3287,3294,3293,3297,3314,3326,3335,3338,3355,3362,3358,3365,3364,3376,3375,3382,3418,3429,3432,3455,3463,3483,3490,3502,3509,3521,3532,3542,3544,3553,3571,3580,3588,3596,3603,3633,3639,3649,3655,3660,3670,3699,3699,3707,3723,3747,3752,3754,3766,3772,3778,3781,3798,3815,3814,3824,3832,3853,3859,3879,3885,3899,3912,3910,3924,3937,3951,3951,3961,3963,3961,3976,3977,3988,4004,4018,4025,4047,4074,4086,4108,4133,4136,4159,4168,4182,4192,4200,4215,4230,4239,4257,4678,4698,4694,4713,4719,4739,4750,4756,4764,4771,4788,4792,4790,4809,4821,4829,4834,4836,4843,4853,4863,4872,4881,4890,4898,4901,4897,4895,4884,4886,4886,4894,4897,4905,4905,4909,4907,4925,4918,4920,4929,4925,4928,4936,4943,4944,4951,4955,4952,4974,4976,4975,4981,4994,4997,5022,5023,5032,5043,5048,5051,5066,5062,5068,5075,5082,5082,5098,5102,5110,5113,5119,5123,5138,5138,5145,5149,5157,5165,5166,5169,5178,5183,5190,5192,5203,5204,5207,5214,5228,5234,5245,5249,5256,5262,5275,5278,5305,5303,5315,5321,5348,5358,5369,5369,5372,5385,5402,5409,5427,5429,5429,5439,5456,5464,5481,5485,5494,5509,5520,5526,5543,5555,5568,5575,5585,5596,5602,5620,5627,5644,5647,5660,5678,5680,5684,5692,5700,5711,5727,5733,5736,5756,5776,5797,5805,5804,5807,5800,5808,5814,5822,5839,5856,5869,5889,5902,5919,5921,5936,5937,5936,5957,5961,5975,5981,6002,6015,6027,6035,6042,6059,6062,6080,6081,6092,6097,6106,6127,6129,6198,6227,6231,6243,6249,6262,6255,6279,6304,6315,6326,6330,6334,6361,6358,6359,6379,6381,6389,6388,6404,6404,6443,6465,6473,6497,6500,6513,6524,6532,6538,6578,6572,6576,6584,6582,6608,6639,6656,6761,6764,6768,6772,6836,6905,6916,6925,6951,6984,7009,7072,7092,7110,7122,7140,7148,7170,7168,7180,7194,7247,7374,7391,7393,7382,7425,7485,7530,7568,7587,7602,7602,7715,7771,7900,8004,8103,8153,8162,8296,8319,8437,8566,8746,8860,8913,9128,9275,9585,9739,10014,10123,10167,10203,10288,10323,10398,10544,10721,10883,11044,11157,11442,11515,11787,12070,12269,12468,12484,12619,12883,13008,13264,13317,13549,13859,14049,14175,14360,14498,14687,14843,14984,15093,15279,15431,15623,15741,15788,15966,16025,16132,16419,16568,16791,16892,17060,17269,17598,17959,18194,18482,18804,19136,19564,19990,20249,20509,20943,21248,21539,21845,22196,22412];class vi{static FIRST_ORBIT="1957-10-04";static EARTH_RADIUS_KM=6371;static LOW_ORBIT_KM=500;static shadowHeightKm(e){if(e>=0)return 0;const t=-e*Math.PI/180;return vi.EARTH_RADIUS_KM*(1/Math.cos(t)-1)}static isLitOverhead(e,t){return e>vi.shadowHeightKm(t)}static classesAt(e){const t=e.getTime();return LT.filter(n=>{const i=Date.parse(`${n.from}T00:00:00Z`),s=n.to===void 0?1/0:Date.parse(`${n.to}T23:59:59Z`);return t>=i&&t<=s})}static trackedInOrbitAt(e){const t=e.getUTCFullYear()*12+e.getUTCMonth()-NT;if(!(t<0))return im[Math.min(t,im.length-1)]}static visibilityAt(e,t){const n=Un("Sun",e,t).altitudeDeg;return{sunAltitudeDeg:n,shadowHeightKm:vi.shadowHeightKm(n),lowOrbitLit:vi.isLitOverhead(vi.LOW_ORBIT_KM,n),classes:vi.classesAt(e),trackedObjects:vi.trackedInOrbitAt(e),anythingInOrbit:e.getTime()>=Date.parse(`${vi.FIRST_ORBIT}T00:00:00Z`)}}}const OT={en:["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW"],fr:["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSO","SO","OSO","O","ONO","NO","NNO"]};class qs{static POINT_DEG=360/16;static point(e,t){const n=(e%360+360)%360,i=Math.round(n/qs.POINT_DEG)%16;return OT[t][i]}static towards(e,t){const n=qs.point(e,t);return t==="en"?`to the ${n}`:kT.test(n)?`à l'${n}`:`au ${n}`}}const kT=/^[EO]/;class nt{static COARSE_STEP_DEG=10;static FINE_STEP_DEG=2;static FINE_SPAN_DEG=10;static LOWEST_DEG=5;static THRESHOLD_CONTRAST=.5;static CONE_SEPARATION_DEG=60;galaxy=new Je;dust=new _t;assess(e,t){const n=Un("Sun",e,t),i=Un("Moon",e,t),s={altitudeDeg:i.altitudeDeg,phaseAngleDeg:We.phaseAngleOf(Kl(e).illuminatedFraction)},r=kn.galactic(e,t),o=nt.unit(r.centre),l=nt.unit(r.rotation),c=nt.unit(r.pole),h=nt.unit(kn.eclipticPole(e,t)),d=nt.unit(n),u=nt.unit(i),f=nt.normalize(nt.reject(d,h));let p,v,m=0;const g=(_,M)=>{const x=nt.unit({altitudeDeg:_,azimuthDeg:M}),w=nt.between(x,d),E=We.magPerArcsec2({altitudeDeg:n.altitudeDeg,separationDeg:w},{...s,separationDeg:nt.between(x,u)},_);E>m&&(m=E);const D=Zi.fromMagPerArcsec2(E),y=10**(-.4*We.EXTINCTION_PER_AIR_MASS*(We.airMass(_)-1)),T=this.galaxy.surfaceBrightnessS10(Math.atan2(nt.dot(x,l),nt.dot(x,o))*180/Math.PI,Math.asin(Math.max(-1,Math.min(1,nt.dot(x,c))))*180/Math.PI)*y;p=nt.better(p,T,D,E,_,M,w);const A=Math.max(-1,Math.min(1,nt.dot(x,h))),I=nt.normalize(nt.reject(x,h)),R=this.dust.surfaceBrightnessS10(nt.between(I,f),Math.asin(A)*180/Math.PI)*y;v=nt.better(v,R,D,E,_,M,w)};for(let _=nt.LOWEST_DEG;_<=90;_+=nt.COARSE_STEP_DEG)for(let M=0;M<360;M+=nt.COARSE_STEP_DEG)g(_,M);for(const _ of[p,v]){if(!_)continue;const M=nt.FINE_SPAN_DEG,x=nt.FINE_STEP_DEG;for(let w=_.altitudeDeg-M;w<=_.altitudeDeg+M;w+=x)if(!(w<nt.LOWEST_DEG||w>90))for(let E=_.azimuthDeg-M;E<=_.azimuthDeg+M;E+=x)g(w,(E+360)%360)}return{milkyWay:p&&p.contrast>=nt.THRESHOLD_CONTRAST?p:void 0,zodiacal:v&&v.contrast>=nt.THRESHOLD_CONTRAST?v:void 0,darkestSkyMagPerArcsec2:m}}static better(e,t,n,i,s,r,o){const l=t/n;return e&&e.contrast>=l?e:{contrast:l,altitudeDeg:s,azimuthDeg:r,magPerArcsec2:Zi.toMagPerArcsec2(t),skyMagPerArcsec2:i,sunSeparationDeg:o}}static unit(e){const t=e.altitudeDeg*Math.PI/180,n=e.azimuthDeg*Math.PI/180,i=Math.cos(t);return[i*Math.sin(n),Math.sin(t),-i*Math.cos(n)]}static dot(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]}static between(e,t){return Math.acos(Math.max(-1,Math.min(1,nt.dot(e,t))))*180/Math.PI}static reject(e,t){const n=nt.dot(e,t);return[e[0]-n*t[0],e[1]-n*t[1],e[2]-n*t[2]]}static normalize(e){const t=Math.hypot(...e)||1;return[e[0]/t,e[1]/t,e[2]/t]}}const pl=36e5,sm=25;class Th{constructor(e){this.provider=e}async infer(e){const t=this.questionOf(e);if(!t)return{status:"incomplete"};const{origin:n,start:i}=t,s=ja(e.event)??0,r=this.sampleTimings(e,i,s);let o;try{o=await this.provider.getWeather({points:r.map(l=>this.pointAt(e,l,n))})}catch{return{status:"failed",at:i}}return o?{status:"inferred",at:i,source:o.source,keyframes:o.samples.map((l,c)=>({t:r[c].t,weather:l.weather}))}:{status:"unavailable",at:i}}applyTo(e,t){if(!(t.status!=="inferred"||!t.keyframes||!t.source)){e.weatherTrack.clear();for(const n of t.keyframes)e.weatherTrack.addKeyframe(n.t,n.weather);e.weatherSource=t.source}}sampleTimes(e,t){const n=[e],i=e.getTime()+t;let s=Math.floor(e.getTime()/pl)*pl+pl;for(;s<=i&&n.length<sm;)n.push(new Date(s)),s+=pl;return t>0&&n[n.length-1].getTime()!==i&&n.length<sm&&n.push(new Date(i)),n}sampleTimings(e,t,n){const i=e.timeline.duration>0?e.timeline.duration:n;return n<=0||i<=0?[{time:t,t:0}]:this.sampleTimes(t,n).map(s=>{const r=(s.getTime()-t.getTime())/n;return{time:s,t:Math.round(i*Math.max(0,Math.min(1,r)))}})}canInfer(e){return this.questionOf(e)!==void 0}questionOf(e){const t=this.originOf(e);if(!t)return;const n=e.event.time;if(n?.year===void 0||n.month===void 0||n.day===void 0)return;const i=Ka(n,t.lng,e.event.utcOffsetHours);return i?{origin:t,start:i}:void 0}originOf(e){const t=at(e,0),n=e.event.place?.[0],i=t?.lat??n?.lat,s=t?.lng??n?.lng;return i===void 0||s===void 0?void 0:{lat:i,lng:s}}pointAt(e,t,n){const i=at(e,t.t);return{lat:i?.lat??n.lat,lng:i?.lng??n.lng,time:t.time}}}const FT=Date.UTC(1940,0,1),am=36e5,rm=.25,UT=.7,BT=.45,zT=.1,HT=2,GT=.3,VT=.2,WT=8,Ah=.125,XT=.05,om=125,lm=100,cm=2500,Ih=3500,Dh=8e3,qT=95,YT=99,KT=[96,99],$T=["cloud_cover","cloud_cover_low","cloud_cover_mid","cloud_cover_high","precipitation","snowfall","weather_code","wind_speed_10m","wind_direction_10m","temperature_2m","dew_point_2m"];class sv{fetchImpl;baseUrl;cache=new Map;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.baseUrl=e.baseUrl??"https://archive-api.open-meteo.com/v1/archive"}async getWeather(e){if(e.points.length===0)return;const t=e.points.map(f=>f.time.getTime()),n=Math.min(...t);if(n<FT)return;const i=new Map;for(const f of e.points){const p=this.cellKey(f);i.has(p)||i.set(p,{lat:f.lat,lng:f.lng,index:i.size})}const s=this.requestUrl([...i.values()],new Date(n),new Date(Math.max(...t))),r=this.cache.get(s);if(r)return r;const o=await this.fetchImpl(s);if(!o.ok)throw new Error(`Open-Meteo HTTP ${o.status}`);const l=await o.json(),c=Array.isArray(l)?l:[l];if(c.length<i.size||c.some(f=>f.error||!f.hourly))return;const h={id:"era5",name:"ERA5 (Open-Meteo)",url:s},d=e.points.map(f=>this.sampleAt(c[i.get(this.cellKey(f)).index].hourly,f.time));if(d.some(f=>f===void 0))return;const u={samples:d,source:h};return this.cache.set(s,u),u}cellKey(e){return`${Math.round(e.lat/rm)},${Math.round(e.lng/rm)}`}requestUrl(e,t,n){const i=new URLSearchParams({latitude:e.map(s=>s.lat).join(","),longitude:e.map(s=>s.lng).join(","),start_date:this.isoDate(t),end_date:this.isoDate(n),hourly:$T.join(","),wind_speed_unit:"ms",timezone:"UTC"});return`${this.baseUrl}?${i}`}isoDate(e){return e.toISOString().slice(0,10)}sampleAt(e,t){const n=this.recordAt(e,t);return n&&{time:t,weather:this.toWeather(n)}}recordAt(e,t){const n=e.time.map(o=>Date.parse(`${o}Z`)),i=t.getTime();if(n.length===0||i<n[0]-am||i>n[n.length-1]+am)return;if(i<=n[0])return this.recordFrom(e,0);if(i>=n[n.length-1])return this.recordFrom(e,n.length-1);let s=0;for(;s+1<n.length&&n[s+1]<=i;)s++;const r=n[s+1]-n[s];return this.blendRecords(this.recordFrom(e,s),this.recordFrom(e,s+1),r>0?(i-n[s])/r:0)}recordFrom(e,t){const n={cloudCover:e.cloud_cover[t]/100,cloudCoverLow:e.cloud_cover_low[t]/100,cloudCoverMid:e.cloud_cover_mid[t]/100,cloudCoverHigh:e.cloud_cover_high[t]/100,precipitationMm:e.precipitation[t],snowfallCm:e.snowfall[t],weatherCode:e.weather_code[t],windSpeedMs:e.wind_speed_10m[t],windFromDeg:e.wind_direction_10m[t],temperatureC:e.temperature_2m[t],dewPointC:e.dew_point_2m[t]};return Object.values(n).some(i=>i===void 0||Number.isNaN(i))?void 0:n}blendRecords(e,t,n){if(!e||!t)return e??t;const i=(r,o)=>r+(o-r)*n,s=((t.windFromDeg-e.windFromDeg)%360+540)%360-180;return{cloudCover:i(e.cloudCover,t.cloudCover),cloudCoverLow:i(e.cloudCoverLow,t.cloudCoverLow),cloudCoverMid:i(e.cloudCoverMid,t.cloudCoverMid),cloudCoverHigh:i(e.cloudCoverHigh,t.cloudCoverHigh),precipitationMm:i(e.precipitationMm,t.precipitationMm),snowfallCm:i(e.snowfallCm,t.snowfallCm),weatherCode:n<.5?e.weatherCode:t.weatherCode,windSpeedMs:i(e.windSpeedMs,t.windSpeedMs),windFromDeg:((e.windFromDeg+s*n)%360+360)%360,temperatureC:i(e.temperatureC,t.temperatureC),dewPointC:i(e.dewPointC,t.dewPointC)}}cloudLayersFrom(e){return[{id:"record-low",type:"unknown",baseM:Math.round(this.clamp(om*(e.temperatureC-e.dewPointC),lm,cm)),thicknessM:650,coverage:this.clamp(e.cloudCoverLow,0,1),sizeM:1400,density:1},{id:"record-mid",type:"unknown",baseM:Ih,thicknessM:800,coverage:this.clamp(e.cloudCoverMid,0,1),sizeM:2500,density:1},{id:"record-high",type:"cirrus",baseM:Dh,thicknessM:400,coverage:this.clamp(e.cloudCoverHigh,0,1),sizeM:2200,density:.35}]}toWeather(e){const t=e.weatherCode>=qT&&e.weatherCode<=YT,n=this.precipitationTypeFrom(e);return{cloudLayers:this.cloudLayersFrom(e),cloudCover:this.clamp(e.cloudCover,0,1),cloudDarkness:this.cloudDarknessFrom(e,t),cloudBaseM:this.cloudBaseFrom(e),highCloudCover:e.cloudCoverHigh,lowerCloudCover:Math.max(e.cloudCoverLow,e.cloudCoverMid),precipitationType:n,precipitationIntensity:n==="none"?0:this.clamp(Math.sqrt(e.precipitationMm/WT),0,1),windDirectionDeg:(e.windFromDeg+180)%360,windSpeed:e.windSpeedMs,storm:t}}precipitationTypeFrom(e){return e.snowfallCm>0?"snow":KT.includes(e.weatherCode)?"hail":e.precipitationMm>0?"rain":"none"}cloudDarknessFrom(e,t){const n=e.cloudCoverLow+e.cloudCoverMid+e.cloudCoverHigh;if(n<=0)return 0;const i=(UT*e.cloudCoverLow+BT*e.cloudCoverMid+zT*e.cloudCoverHigh)/n,s=Math.min(1,e.precipitationMm/HT);return this.clamp(i+GT*s+(t?VT:0),0,1)}cloudBaseFrom(e){if(e.cloudCover<XT)return;const t=this.clamp(om*(e.temperatureC-e.dewPointC),lm,cm);if(e.cloudCoverLow>=Ah)return Math.round(t);if(e.cloudCoverMid>=Ah)return Ih;if(e.cloudCoverHigh>=Ah)return Dh;const n=Math.max(e.cloudCoverLow,e.cloudCoverMid,e.cloudCoverHigh);if(!(n<=0))return n===e.cloudCoverLow?Math.round(t):n===e.cloudCoverMid?Ih:Dh}clamp(e,t,n){return Math.max(t,Math.min(n,e))}}function ZT(){return new sv}const JT=5;class av{attribution={text:"© OpenStreetMap",url:"https://osm.org/copyright"};fetchImpl;baseUrl;reverseUrl;cache=new Map;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.baseUrl=e.baseUrl??"https://nominatim.openstreetmap.org/search",this.reverseUrl=e.reverseUrl??"https://nominatim.openstreetmap.org/reverse"}async reverse(e,t,n={}){const i=new URLSearchParams({lat:String(e),lon:String(t),format:"jsonv2"});n.language&&i.set("accept-language",n.language);const s=`${this.reverseUrl}?${i}`,r=this.cache.get(s);if(r)return r[0];const o=await this.fetchImpl(s,{signal:n.signal});if(!o.ok)throw new Error(`Nominatim HTTP ${o.status}`);const l=await o.json(),c=l.error?void 0:this.toMatch(l);return this.cache.set(s,c?[c]:[]),c}async search(e,t={}){const n=e.trim();if(n==="")return[];const i=this.requestUrl(n,t),s=this.cache.get(i);if(s)return s;const r=await this.fetchImpl(i,{signal:t.signal});if(!r.ok)throw new Error(`Nominatim HTTP ${r.status}`);const o=await r.json(),l=(Array.isArray(o)?o:[]).map(c=>this.toMatch(c)).filter(c=>c!==void 0);return this.cache.set(i,l),l}requestUrl(e,t){const n=new URLSearchParams({q:e,format:"jsonv2",limit:String(t.limit??JT)});return t.language&&n.set("accept-language",t.language),`${this.baseUrl}?${n}`}toMatch(e){const t=e.display_name??e.name,n=this.coordinate(e.lat),i=this.coordinate(e.lon);return t&&n!==void 0&&i!==void 0?{name:t,lat:n,lng:i}:void 0}coordinate(e){if(e===void 0||e.trim()==="")return;const t=Number(e);return Number.isFinite(t)?t:void 0}}function jT(){return new av}const QT=[{id:"nominatim",name:"Nominatim",credit:"© OpenStreetMap",creditUrl:"https://osm.org/copyright",create:()=>new av}],eA=[{id:"era5",name:"ERA5 (Open-Meteo)",credit:"© Copernicus/ECMWF",creditUrl:"https://open-meteo.com/en/docs/historical-weather-api",create:()=>new sv}];class tA{attribution;fetchImpl;tileUrlTemplate;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis);const t=e.year??2024;this.tileUrlTemplate=`https://tiles.maps.eox.at/wmts/1.0.0/s2cloudless-${t}_3857/default/g/{z}/{y}/{x}.jpg`,this.attribution=`EOxCloudless https://cloudless.eox.at by EOX IT Services GmbH (Contains modified Copernicus Sentinel data ${t})`}async getImageryTexture(e,t){return Lm(e,t,n=>this.tileUrlTemplate.replace("{z}",String(n.z)).replace("{y}",String(n.y)).replace("{x}",String(n.x)),this.fetchImpl)}}const Ch=[{id:"aws-terrarium",name:"AWS Terrain Tiles",credit:"© AWS Open Data (SRTM, ETOPO1)",creditUrl:"https://registry.opendata.aws/terrain-tiles/",create:()=>new Pm}],hm=[{id:"esri-world",name:"Esri World Imagery",credit:"Imagery © Esri, Maxar, Earthstar Geographics, and the GIS User Community",creditUrl:"https://www.arcgis.com/home/item.html?id=10df2279f9684e4a9f6a7f08febac2a9",create:()=>new Nm},{id:"eox-s2cloudless",name:"EOX Sentinel-2 cloudless",credit:"EOxCloudless by EOX IT Services GmbH (contains modified Copernicus Sentinel data)",creditUrl:"https://cloudless.eox.at",create:()=>new tA}];class qu{constructor(e){this.provider=e}static SPAN_DEG=.002;async at(e,t){const n=qu.SPAN_DEG;try{const s=(await this.provider.getElevationGrid({south:e-n,north:e+n,west:t-n,east:t+n},{width:2,height:2})).heights[0];return Number.isFinite(s)?s:void 0}catch{return}}}class nA{available(){const e=Intl.supportedValuesOf;return e?[...e.call(Intl,"timeZone")].sort():[]}offsetHoursAt(e,t){if(t.year===void 0)return;const n=Date.UTC(t.year,(t.month??1)-1,t.day??1,t.hour??12,t.minute??0,t.second??0),i=this.zoneOffsetHours(e,new Date(n));if(i!==void 0)return this.zoneOffsetHours(e,new Date(n-i*36e5))??i}zoneOffsetHours(e,t){let n;try{n=new Intl.DateTimeFormat("en-US",{timeZone:e,timeZoneName:"longOffset"}).formatToParts(t).find(s=>s.type==="timeZoneName")?.value??""}catch{return}const i=/^GMT(?:([+-])(\d{2}):(\d{2}))?$/.exec(n);if(i)return i[1]?(i[1]==="-"?-1:1)*(Number(i[2])+Number(i[3])/60):0}}function Ia(a,e){return a.find(t=>t.id===e)??a[0]}class iA{constructor(e="https://api.open-meteo.com/v1/forecast"){this.endpoint=e}async zoneAt(e,t){const n=new URL(this.endpoint);n.searchParams.set("latitude",String(e)),n.searchParams.set("longitude",String(t)),n.searchParams.set("timezone","auto"),n.searchParams.set("forecast_days","1");try{const i=await fetch(n.toString());if(!i.ok)return;const s=await i.json();return s.timezone&&s.timezone!=="GMT"?s.timezone:void 0}catch{return}}}const sA=[{id:"open-meteo",name:"Open-Meteo",credit:"© Open-Meteo",creditUrl:"https://open-meteo.com/en/docs",create:()=>new iA}],aA={color:"Color",transparency:"Transparency",halo:"Halo",blur:"Blur",brightness:"Brilliance",shapeTitle:"Name",utcOffset:"Time zone",cloudBase:"Cloud base",elevation:"Altitude",heightAboveGround:"Height above ground",duration:"Duration",placeName:"Place",latitude:"Latitude",longitude:"Longitude",heading:"Heading",pitch:"Tilt",roll:"Roll",observationTime:"Observation start",observationEndTime:"Observation end",assessmentGroup:"Assessment",assessmentNames:{coverage:"Witness info"},assessmentVerdicts:{"hynek.nl":"NL — nocturnal light","hynek.dd":"DD — daylight disc","hynek.rv":"RV — radar-visual","hynek.ce1":"CE1 — close encounter","hynek.ce2":"CE2 — with a physical trace","hynek.ce3":"CE3 — with entities"},witnessGroup:"Witness",witnessId:"ID",witnessTitle:"Title",witnessLastName:"Last name",witnessFirstNames:"First names",caseId:"Case ID",tags:"Tags",cloudCover:"Cloud cover",highCloudCover:"Ice cloud (cirrus)",focalLength:"Focal length",fieldOfView:"Field of view",aperture:"Aperture",exposure:"Exposure",focusDistance:"Focused at",iceCrystalAlignment:"Crystal alignment",cloudDarkness:"Cloud darkness",precipitationType:"Precipitation",precipitationNone:"None",precipitationRain:"Rain",precipitationSnow:"Snow",precipitationHail:"Hail",precipitationIntensity:"Intensity",windDirection:"Wind direction",windSpeed:"Wind speed",storm:"Storm",soundKind:"Sound",soundNone:"None (silent)",soundHum:"Hum",soundWhistle:"Whistle",soundRumble:"Rumble",soundCrackle:"Crackle",soundVolume:"Loudness",soundPitch:"Pitch",soundSrc:"Recording",instrument:"Observed through",decorAircraft:"Aircraft",decorEntity:"Being",decorAltitude:"Altitude",decorLights:"Lights",decorLightsNone:"none",decor:"Environment",decorBuilding:"Building",decorTree:"Tree",decorCrop:"Crop row",decorMound:"Stone heap",decorStreetlight:"Streetlight",decorVehicle:"Vehicle",decorWitness:"Other witness",decorEast:"Distance east",decorNorth:"Distance north",decorHeading:"Heading",decorColor:"Colour",decorLit:"Lit",decorTitle:"Name",milestones:"Moments",milestoneLabel:"Label",milestoneNote:"What happens",addMilestone:"Name this moment",deleteMilestone:"Delete moment",confirmAccept:"Delete",confirmDecline:"Cancel",decorWidth:"Width",decorLength:"Length",decorHeight:"Height",decorModel:"3D model",decorModelNone:"Built-in shape",decorModelAdvanced:"Model from an address",decorModelUrl:"glTF/GLB address",decorModelTitle:"Model name",decorModelAuthor:"Author",decorModelLicense:"Licence",decorModelSource:"Where it came from",decorFloors:"Floors",decorOccupiedFloor:"Occupied floor",decorWitnessSide:"Witness location",decorWitnessSideNone:"Not present",decorWindows:"Windows",decorSideFront:"Front",decorSideBehind:"Behind",decorSideLeft:"Left",decorSideRight:"Right",decorSideFrontLeft:"Front-left",decorSideFrontRight:"Front-right",decorSideBehindLeft:"Behind-left",decorSideBehindRight:"Behind-right"},rv={...aA,oval:"Oval",polygon:"Polygon",addVertex:"Add vertex",deleteVertex:"Delete vertex",notAPolygon:"Select a single polygon shape",tooFewVertices:"A shape needs at least 3 points",shape:"Shape",apparentWidth:"Apparent width",realWidth:"Real width",distance:"Distance",sizeLock:"Hold",lockNone:"nothing",lockApparent:"the apparent width",lockReal:"the real width",lockDistance:"the distance",apparentSize:"{moons}× the Moon",utcOffsetPlaceholder:"from longitude",realSizeBetween:"The scene bounds that width: between {min} and {max} m, from what it crosses",realSizeAtLeast:"The scene bounds that width: at least {min} m, from what it passes behind",realSizeAtMost:"The scene bounds that width: at most {max} m, from what it passes in front of",realSizeUnknown:"Nothing in the scene bounds that width: it is only what the distance implies",realSizeOutside:" — the width above is outside that",blurBound:"Blurred through this lens: nearer than {max} m",blurBoundNoInstrument:"Blur through the naked eye bounds no distance — an eye has no aperture to be out of focus with",blurBoundNotAtInfinity:"Blur bounds a distance only for a lens focused at infinity: this one is focused at {focus} m, which blurs on both sides of it",realSizeContradiction:"Contradiction: the declared crossings cannot all be true",realDistanceHere:" — i.e. between {min} and {max} m here",clearDistanceHypothesis:"Withdraw the distance hypothesis",clearDistanceHypothesisTitle:"Back to what the recording establishes",depthStated:"Drawn at {m} m, as the recording states",depthHypothesis:"Drawn at {m} m: your hypothesis — what the decor hides of it is what a thing that far would lose",depthDerived:"Drawn at {m} m, from the witness's own walk",depthBounded:"Drawn at {m} m, from what it passes behind and in front of",depthConventional:"Drawn at {m} m by convention: nothing in the recording establishes a distance",addShape:"Add shape",deleteShape:"Delete shape",play:"Play",pause:"Pause",noDuration:"No observation duration",autoReplay:"Auto-replay",group:"Group",ungroup:"Ungroup",bringToFront:"Bring to front",sendToBack:"Send to back",contextMenuDelete:"Delete",confirmDeleteShape:"Delete {name}? This can't be undone.",confirmDeleteShapes:"Delete {count} shapes? This can't be undone.",confirmDeleteMilestone:"Stop naming moment {name}? The recording itself is unchanged.",onlyOneShape:"There is only one shape",alreadyAtFront:"This shape is already at the front",alreadyAtBack:"This shape is already at the back",needTwoShapesToGroup:"Select at least two shapes to group them",notGrouped:"This shape isn't part of a group",multipleShapesSelected:"Multiple shapes selected — select just one to edit this",samplingRate:"Sampling rate",currentPosition:"Current position",switchToElapsed:"click to show elapsed time",switchToClockTime:"click to show the time of day",durationPlaceholder:"observation length",durationImprecise:"These dates don't precisely enough determine a duration — enter it manually.",export:"Export",importFile:"Load JSON file",importUrl:"Or load from URL",importUrlPlaceholder:"https://…/sighting.json",importButton:"Load",importError:"Couldn't load that recording — check the file or URL and try again.",importErrorCors:'That address answers, but the browser is not allowed to read it from this page. The file itself is fine — its server needs to send the header "Access-Control-Allow-Origin: *" with it. If it is not your server, that is what to ask its administrator for.',importErrorMixedContent:"A secure page cannot load an address starting with http://. Use https:// if that server offers it.",importErrorUnreachable:"Nothing answered at that address. Check the spelling, and that you are online.",importErrorStatus:"That server answered with an error ({status}). The address is probably wrong, or the file has moved.",importErrorMalformed:"That address answered, but what came back is not a recording.",record:"Record",stop:"Stop",according:"according to",sourceElevation:"Relief",sourceImagery:"Imagery",placeNamePlaceholder:"Valensole, France",searchPlace:"Locate",placeMatch:"Matches",placeSearching:"Looking up the place…",placeMatchFound:"place found",placeMatchesFound:"places found",placeNotFound:"No place by that name",placeSearchFailed:"Place search temporarily unavailable",utcOffsetImplausible:"This time zone doesn't match the longitude entered, whose own solar time is UTC{solar} — yet the scene and the weather record both obey what is declared here. Clear the field to derive it from the longitude.",timeZoneManual:"offset entered",altitudeAboveSeaLevel:"The witness's altitude above sea level — the ground at the location entered sets its floor: a witness in the Alps is not at 0 m.",groundAt:"ground at {m} m",headingPlaceholder:"unknown",edtfInvalid:"Not a valid EDTF date/time (e.g. 1965-07-01T05:00, 2025-06?, 2025~).",edtfPlaceholder:"YYYY-MM-DDThh:mm[?~%] or hh:mm",observationTimeHint:"EDTF — e.g. 1965-07-01T05:00, 2025-06? (uncertain), 2025~ (approximate), or just 05:00 if the date isn't known",observationEndTimeHint:"EDTF — e.g. 1965-07-01T05:10, 2025-06? (uncertain), 2025~ (approximate), or just 05:10 if the date isn't known",presetsGroupLabel:"UFO shape",witnessDirName:"Dir name",description:"Description",tagsPlaceholder:"comma-separated",weather:"Weather",shapeGroup:"Phenomenon",soundGroup:"Sound",temporalGroup:"Moment",timeQualifierExact:"Exact",timeQualifierApproximate:"Approximate",timeQualifierUncertain:"Uncertain",timeQualifierBoth:"Uncertain and approximate",edtfModeTitle:"Type an imprecise date instead: a year alone, a month, a time with no date",locationGroup:"Location",observationGroup:"Observation",weatherWhilePlaying:"Pause the recording to state the weather — while it plays, the instant these would be written at is moving",weatherInferred:"From weather records",weatherInferredTitle:"Weather isn't testimony: it's a measurable fact, on record for the observation's own date, time and place. Uncheck to state the conditions the witness reported, which then override the record.",weatherLookingUp:"Looking up the record…",weatherNeedsDateAndPlace:"A full date and a place are needed to look up the record",weatherNoRecord:"No record for this date and place",weatherLookupFailed:"Weather records temporarily unreachable",instrumentOutOfPeriod:"{name} — not of this date",unitMillimetres:"mm",unitDegrees:"°",soundSrcPlaceholder:"URL of a real recording",skyLine:"Sky: {parts}",skyStarsEye:"stars down to magnitude {limit}, which is as faint as an eye went under this sky",skyStarsDeeper:"stars down to magnitude {limit} through a {device} — {gain} magnitudes past the {eye} the witness's own eyes reached",skyStarsShallower:"stars down to magnitude {limit} through a {device} — {gain} magnitudes short of the {eye} the witness's own eyes reached",skyStarsCatalogue:", drawn to {catalogue}, where this project's catalogue stops",skyStarsNone:"no star could be picked out of a sky this bright",skyDetails:"Show the records in full",skyDetailsHide:"Hide the records",skyShowerActive:"{name} — radiant {altitude}° above the horizon, {bearing} — about {rate}/h under this sky, over a sporadic background of {sporadic}/h",skyShowerBelowHorizon:"{name} is active, but its radiant is below the horizon — it can have produced nothing",skyNothingActive:"no meteor shower active on this date — a sporadic background of about {sporadic}/h",showMeteor:"Show me one",skyComet:"{name}, magnitude {magnitude}, {altitude}° above the horizon {bearing}, tail {tail}° long",skyCometNoTail:"{name}, magnitude {magnitude}, {altitude}° above the horizon {bearing}",skyCometBelowHorizon:"{name} was there at magnitude {magnitude}, but below the horizon — nobody here saw it",skyCometInDaylight:"{name}, magnitude {magnitude}, {altitude}° above the horizon {bearing} — but only {elongation}° from the Sun",showComet:"Show me the comet",skyOpticsPossible:"ice cloud enough, around the {source}, for {forms}",skyOpticsAlignment:" — everything but the rings needs crystals falling level, stated here at {alignment}% since no record holds it",skyOpticsHalo22:"a {angle}° ring",skyOpticsHalo46:"a {angle}° ring",skyOpticsParhelia:"sundogs {angle}° to either side",skyOpticsTangentArc:"an arc tangent on top of it",skyOpticsParhelicCircle:"a white circle right round the sky at its own height",skyOpticsCircumzenithal:"a circumzenithal arc {angle}° up",skyOpticsCircumhorizontal:"a circumhorizontal arc far below it",skyOpticsPillar:"a pillar standing over it",skyOpticsNoIce:"no ice cloud: no halo and no sundogs",skyOpticsHidden:"ice cloud above, but a lower deck between it and the witness",skyOpticsSun:"Sun",skyOpticsMoon:"Moon",skyBowPossible:"rain and sunlight enough for {forms}",skyBowMoon:"rain under a Moon {lit}% lit, enough for {forms} — a moonbow, which the eye sees as a white arc",skyGlowBand:"the Milky Way {contrast}× the sky behind it, {altitude}° up {bearing}",skyGlowCone:"the zodiacal light {contrast}× the sky behind it, {altitude}° up {bearing}, {elongation}° from the Sun — a leaning cone with no edge, gone within the hour",skyGlowZodiacalBand:"the zodiacal band {contrast}× the sky behind it, {altitude}° up {bearing} — the whole ecliptic faintly alight, which is not the sight people report",skyGlowMoon:"no Milky Way and no zodiacal light: a Moon {lit}% lit held the sky at {sky} magnitudes a square arcsecond, where they need 22",skyGlowTwilight:"no Milky Way and no zodiacal light: twilight still held the sky at {sky} magnitudes a square arcsecond, where they need 22",skyGlowNothingUp:"sky dark enough ({sky} magnitudes a square arcsecond) but neither the galactic plane nor the ecliptic stood high enough in it",skyBowPrimary:"a bow {radius}° across, its top {top}° up",skyBowSecondary:"a second, fainter one at {radius}° with its colours reversed",skyBowSourceTooHigh:"rain, but with the source {altitude}° up no bow could clear the horizon: they stand {radius}° from the point opposite it",skyBowHidden:"rain, but an unbroken deck between it and the light: no bow",skyBowNoSource:"rain, and nothing lit to make a bow of it",skySatellitesLit:"the Earth's shadow stood {height} km above the witness, so low orbit was still in sunlight — {count} tracked objects were in orbit that month",skySatellitesLitWith:"the Earth's shadow stood {height} km above the witness, so low orbit was still in sunlight — {count} tracked objects were in orbit that month, among them {eras}",skySatellitesShadowed:"the Earth's shadow stood {height} km above the witness: of the {count} tracked objects in orbit that month, nothing in low orbit was lit",skySatellitesNotYet:"nothing had been put in orbit yet",skySatellitesDaylight:"everything in orbit was sunlit, as it always is by day, and {eras} could outshine even this sky",skySatellitesDaylightOne:"everything in orbit was sunlit, as it always is by day, and {eras} could outshine even this sky",skyUnknown:"cannot be worked out without a date and a place",lookAtDecor:"Look at it",addDecor:"Add",deleteDecor:"Delete decor",decorSightingUrl:"Their own recording URL",viewTestimony:"View testimony",noWitnessRecording:"No recording URL set for this witness",masks:"Masks",addWitness:"Add witness",narrativePlaceholder:"What the witness reported, in their own words",narrativeKey:"{source} API key",narrativeNeedsKey:"Enter your own {source} API key to generate a reconstruction from the account",narrativeKeyUnlikely:"This does not look like a Claude API key: they begin with sk-ant-",narrativeWorkspace:"Workspace ID",narrativeWorkspacePlaceholder:"only if your key spans several",narrativeWorkspaceHint:"Only for a key whose scope is the whole organisation. Simpler: leave this empty and create a key scoped to one workspace instead.",narrativeNeedsAsk:"Nothing to send yet",narrativeRemember:"Remember on this device",narrativeDraft:"Generate reconstruction",narrativeStop:"Stop",narrativeWorking:"Reading the account…",narrativeApplied:"{count} fields written into the editor",narrativeUnchanged:"The account states nothing the recording can hold yet",narrativeStated:"What the witness said",narrativeDerived:"Worked out from the account",narrativeAssumed:"Guessed, so the reconstruction runs — check these",narrativeGaps:"What nothing could settle",narrativeErrorCredential:"No key, or one that was refused — check it at console.anthropic.com",narrativeErrorRateLimited:"Too many requests on your account: wait a moment and ask again",narrativeErrorRefused:"The account was not answered. Rephrasing may help; asking again will not",narrativeErrorMalformed:"The answer was not a usable draft — worth asking once more",narrativeErrorUnreachable:"Nothing answered: check the connection",narrativeErrorRejected:"Refused: {detail}",witnessAge:"Age then",witnessOccupation:"Occupation",testimonySource:"Account obtained",testimonySourceUnknown:"unknown",testimonySourceOnSite:"on-site investigation",testimonySourceInterview:"interview in person",testimonySourceTelephone:"by telephone",testimonySourceQuestionnaire:"questionnaire",testimonySourceLetter:"the witness wrote it",testimonySourcePress:"press or broadcast",testimonyFollowedUp:"Followed up",testimonyUnknown:"unknown",testimonyYes:"yes",testimonyNo:"no",questionUnanswered:"Nothing in this recording answers one of the questions a reconstruction needs settled",durationRequired:"The observation needs a length to be replayed at all — state one, or an end time, which may be approximate",questionsUnanswered:"{count} of the questions a full reconstruction answers are unanswered here"},rA=Object.freeze(Object.defineProperty({__proto__:null,sightingEditorMessages_en:rv},Symbol.toStringTag,{value:"Module"})),dm=new Set;Ql();CT();const Da={width:48,height:28},oA=2500,lA=600,um=900,Ca=2e-4,cA=900,hA=-1.46,dA=3,fm=.2,uA=.01,fA=1.6,Rh=2e3,pA=250,pm=new Set(["ArrowLeft","ArrowRight","ArrowUp","ArrowDown"]),us=4,ml="ufo-1",mm=["oval","polygon"],mA={presetId:"oval",color:"#39ff14",transparency:0,haloScale:1.5,blur:0,brightness:0};function gA(a){return a.kind==="oval"?"oval":"polygon"}const vA=-6,yA=21;class Mt extends HTMLElement{shadow;sceneElement;ufoElement;recordButton;samplingRateInput;presetButtons;presetsGroup;colorInput;transparencyInput;haloScaleInput;blurInput;brightnessInput;blurBoundOutput;sourceSelect;shapeTitleInput;utcOffsetInput;timeZoneSelect;timeZoneProvider=sA[0].create();timeZoneLookupTimer;timeZoneLookedUpAt;autoFilledTimeZone;timeZones=new nA;apparentWidthInput;realWidthInput;objectDistanceInput;sizeLockSelect;apparentSizeOutput;realSizeOutput;clearDistanceHypothesisButton;depthBasisOutput;addShapeButton;deleteShapeButton;contextMenu;contextGroupButton;contextUngroupButton;contextBringToFrontButton;contextSendToBackButton;contextDeleteButton;contextAddVertexButton;contextDeleteVertexButton;decorContextMenu;contextViewTestimonyButton;contextMasksSubmenu;labelContextMasks;playPauseButton;seekInput;timeStartLabel;timeEndLabel;loopButton;durationInput;exportButton;importFileInput;importUrlInput;importUrlButton;narrativeKeyInput;narrativeWorkspaceInput;narrativeRememberInput;narrativeDraftButton;narrativeStopButton;narrativeCreditLink;narrativeStatus;narrativeReport;placeNameInput;searchPlaceButton;placeMatchRow;placeMatchSelect;placeStatusText;placeProvider=jT();placeMatches=[];placeSearchToken=0;placeReverseTimer;namedCoordinates;latInput;lngInput;headingInput;pitchInput;rollInput;elevationInput;groundElevationOutput;weatherFromRecords=!0;groundElevationM;groundElevationFor;groundElevationTimer;groundElevationToken=0;obsTimeInput;obsTimeNativeInput;obsEndTimeNativeInput;obsTimeQualifier;obsEndTimeQualifier;edtfModeButton;edtfMode=!1;obsEndTimeInput;witnessIdInput;witnessDirNameInput;witnessTitleInput;witnessLastNameInput;witnessFirstNamesInput;witnessAgeInput;witnessOccupationInput;testimonySourceSelect;testimonyFollowedUpSelect;caseIdInput;descriptionInput;tagsInput;cloudEditor;cloudCoverInput;cloudDarknessInput;cloudBaseInput;precipitationTypeSelect;precipitationIntensityInput;windDirectionInput;windSpeedInput;stormInput;weatherInferredInput;weatherSourceText;skyCandidatesOutput;showMeteorButton;showCometButton;weatherSourceLink;weatherFields;weatherInference=new Th(ZT());weatherLookupTimer;weatherLookupToken=0;weatherLookupPending=!1;weatherLookupResult;weatherTrackSpan;soundKindSelect;soundVolumeInput;soundPitchInput;soundPitchValue;soundSrcInput;soundFields;soundKindOptions=new Map;soundPreviewTimer;instrumentSelect;focalLengthInput;labelFocalLength;unitFocalLength;labelFNumber;labelExposure;labelFocusDistance;fNumberInput;exposureInput;focusDistanceInput;labelColor;labelTransparency;labelHalo;labelBlur;labelBrightness;labelShape;labelShapeTitle;labelUtcOffset;labelApparentWidth;labelRealWidth;labelObjectDistance;labelSizeLock;labelSamplingRate;labelDuration;placeSourceRow;weatherSourceRow;terrainSourceRows;chosenSourceId=new Map;labelPlaceName;labelPlaceMatch;labelLatitude;labelLongitude;labelHeading;labelPitch;labelRoll;labelElevation;labelObservationTime;labelObservationEndTime;labelWitnessId;labelWitnessDirName;labelWitnessTitle;labelWitnessLastName;labelWitnessFirstNames;labelWitnessAge;labelWitnessOccupation;labelTestimonySource;labelTestimonyFollowedUp;labelCaseId;labelDescription;labelTags;labelImportFile;labelImportUrl;labelNarrativeKey;labelNarrativeWorkspace;labelNarrativeRemember;groupTabs;groupPanels;paramSummary;paramSummaryBuilder;paramSummarySignature="";labelShapeGroup;labelTemporalGroup;labelLocationGroup;labelObservationGroup;labelWitnessGroup;skyDetailsButton;clampedLines;labelWeatherGroup;labelCloudCover;labelHighCloud;labelIceAlignment;highCloudCoverInput;iceCrystalAlignmentInput;labelCloudDarkness;labelCloudBase;labelPrecipitationType;labelPrecipitationIntensity;labelWindDirection;labelWindSpeed;labelStorm;labelWeatherInferred;labelSoundGroup;labelSoundKind;labelSoundVolume;labelSoundPitch;labelSoundSrc;labelInstrument;optionPrecipitationNone;optionPrecipitationRain;optionPrecipitationSnow;optionPrecipitationHail;decorKindSelect;addDecorWitnessButton;addDecorBuildingButton;deleteDecorButton;decorSelect;decorTitleInput;decorEastInput;decorNorthInput;decorHeadingInput;decorColorInput;decorLitInput;decorLightRigSelect;lookAtDecorButton;decorAltitudeInput;labelDecorAltitude;decorSightingUrlInput;decorModelProvider=El[0].create();confirmOverlay;confirmMessage;confirmAcceptButton;confirmDeclineButton;confirmAnswer;milestoneSelect;milestoneLabelInput;milestoneNoteInput;addMilestoneButton;deleteMilestoneButton;currentMilestoneT;decorWidthInput;decorLengthInput;decorHeightInput;decorModelSelect;decorModelAdvanced;decorModelUrlInput;decorModelTitleInput;decorModelAuthorInput;decorModelLicenseInput;decorModelSourceInput;decorFloorsInput;decorOccupiedFloorInput;decorWitnessSideSelect;decorWindowInputs;labelDecorSide;optionWitnessSide;labelDecor;labelDecorGroup;labelDecorTitle;labelDecorEast;labelDecorNorth;labelDecorHeading;labelDecorColor;labelDecorLit;labelDecorSightingUrl;labelMilestones;labelMilestoneLabel;labelMilestoneNote;labelDecorWidth;labelDecorLength;labelDecorHeight;labelDecorModel;labelDecorModelAdvanced;labelDecorModelUrl;labelDecorModelTitle;labelDecorModelAuthor;labelDecorModelLicense;labelDecorModelSource;labelDecorFloors;labelDecorOccupiedFloor;labelDecorWitnessSide;labelDecorWindows;optionWitnessSideNone;optionDecorBuilding;optionDecorTree;optionDecorCrop;optionDecorMound;optionDecorStreetlight;optionDecorVehicle;optionDecorAircraft;optionDecorEntity;labelDecorLights;optionDecorWitness;recorder;isRecording=!1;messages=rv;currentAppearance={...mA};currentSourceId=ml;selectedSourceIds=new Set([ml]);currentDecorId;contextMenuDecorId;contextMenuPoint;dragState;cameraDragState;hoverCursor;indoorLookYawDeg=0;indoorLookPitchDeg=0;lastInhabitedKey;handleKeyDown=e=>{if(e.key==="Escape"&&(this.isRecording&&this.toggleRecording(),this.confirmOverlay.hidden||this.answerConfirm(!1),this.contextMenu.hidden||this.hideContextMenu(),this.decorContextMenu.hidden||this.hideDecorContextMenu()),pm.has(e.key)||e.key==="Delete"||e.key==="Backspace"){const t=e.composedPath()[0];if(t instanceof HTMLInputElement||t instanceof HTMLSelectElement||t instanceof HTMLTextAreaElement)return;pm.has(e.key)?this.moveOrResizeSelectedShapes(e):this.deleteShape()}};handleDragPointerMove=e=>this.onDragPointerMove(e);handleDragPointerUp=()=>this.endDrag();constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${n1}</style>${t1}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.sceneElement=document.createElement(hu),this.sceneElement.setAttribute("show-compass",""),this.sceneElement.setAttribute(Ys,""),this.sceneElement.animateWhilePaused=!0,this.ufoElement=this.sceneElement.ufoElement,this.ufoElement.enableClickToPlay=!1,this.ufoElement.showToolbar=!1,this.shadow.getElementById("ufo-slot").replaceWith(this.sceneElement),this.recordButton=this.shadow.getElementById("record"),this.samplingRateInput=this.shadow.getElementById("samplingRate"),this.presetsGroup=this.shadow.getElementById("presets-group"),this.presetButtons={oval:this.shadow.getElementById("preset-oval"),polygon:this.shadow.getElementById("preset-polygon")},this.colorInput=this.shadow.getElementById("color"),this.transparencyInput=this.shadow.getElementById("transparency"),this.haloScaleInput=this.shadow.getElementById("haloScale"),this.blurInput=this.shadow.getElementById("blur"),this.brightnessInput=this.shadow.getElementById("brightness"),this.blurBoundOutput=this.shadow.getElementById("blur-bound"),this.sourceSelect=this.shadow.getElementById("source"),this.shapeTitleInput=this.shadow.getElementById("shapeTitle"),this.utcOffsetInput=this.shadow.getElementById("utcOffsetHours"),this.timeZoneSelect=this.shadow.getElementById("timeZone"),this.apparentWidthInput=this.shadow.getElementById("apparentWidth"),this.realWidthInput=this.shadow.getElementById("realWidth"),this.objectDistanceInput=this.shadow.getElementById("objectDistance"),this.sizeLockSelect=this.shadow.getElementById("sizeLock"),this.apparentSizeOutput=this.shadow.getElementById("apparent-size"),this.realSizeOutput=this.shadow.getElementById("real-size"),this.clearDistanceHypothesisButton=this.shadow.getElementById("clear-distance-hypothesis"),this.depthBasisOutput=this.shadow.getElementById("depth-basis"),this.addShapeButton=this.shadow.getElementById("add-shape"),this.deleteShapeButton=this.shadow.getElementById("delete-shape"),this.contextMenu=this.shadow.getElementById("context-menu"),this.contextGroupButton=this.shadow.getElementById("context-group"),this.contextUngroupButton=this.shadow.getElementById("context-ungroup"),this.contextBringToFrontButton=this.shadow.getElementById("context-bring-to-front"),this.contextSendToBackButton=this.shadow.getElementById("context-send-to-back"),this.contextDeleteButton=this.shadow.getElementById("context-delete"),this.contextAddVertexButton=this.shadow.getElementById("context-add-vertex"),this.contextDeleteVertexButton=this.shadow.getElementById("context-delete-vertex"),this.decorContextMenu=this.shadow.getElementById("decor-context-menu"),this.contextViewTestimonyButton=this.shadow.getElementById("context-view-testimony"),this.contextMasksSubmenu=this.shadow.getElementById("context-masks-submenu"),this.labelContextMasks=this.shadow.getElementById("label-context-masks"),this.playPauseButton=this.shadow.getElementById("play-pause"),this.seekInput=this.shadow.getElementById("seek"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end");for(const t of[this.timeStartLabel,this.timeEndLabel])t.addEventListener("click",()=>this.switchTimeDisplay()),t.addEventListener("keydown",n=>{n.key!=="Enter"&&n.key!==" "||(n.preventDefault(),this.switchTimeDisplay())});this.loopButton=this.shadow.getElementById("loop"),this.durationInput=this.shadow.getElementById("durationSeconds"),this.exportButton=this.shadow.getElementById("export"),this.importFileInput=this.shadow.getElementById("import-file"),this.importUrlInput=this.shadow.getElementById("import-url"),this.importUrlButton=this.shadow.getElementById("import-url-button"),this.narrativeKeyInput=this.shadow.getElementById("narrativeKey"),this.narrativeWorkspaceInput=this.shadow.getElementById("narrativeWorkspace"),this.narrativeRememberInput=this.shadow.getElementById("narrativeRemember"),this.narrativeDraftButton=this.shadow.getElementById("narrative-draft"),this.narrativeStopButton=this.shadow.getElementById("narrative-stop"),this.narrativeCreditLink=this.shadow.getElementById("narrative-credit"),this.narrativeStatus=this.shadow.getElementById("narrative-status"),this.narrativeReport=this.shadow.getElementById("narrative-report"),this.placeNameInput=this.shadow.getElementById("placeName"),this.searchPlaceButton=this.shadow.getElementById("search-place"),this.placeMatchRow=this.shadow.getElementById("place-match-row"),this.placeMatchSelect=this.shadow.getElementById("placeMatch"),this.placeStatusText=this.shadow.getElementById("place-status-text"),this.latInput=this.shadow.getElementById("lat"),this.lngInput=this.shadow.getElementById("lng"),this.headingInput=this.shadow.getElementById("heading"),this.pitchInput=this.shadow.getElementById("pitch"),this.rollInput=this.shadow.getElementById("roll"),this.elevationInput=this.shadow.getElementById("elevation"),this.groundElevationOutput=this.shadow.getElementById("ground-elevation"),this.obsTimeInput=this.shadow.getElementById("obs-time"),this.obsEndTimeInput=this.shadow.getElementById("obs-end-time"),this.obsTimeNativeInput=this.shadow.getElementById("obs-time-native"),this.obsEndTimeNativeInput=this.shadow.getElementById("obs-end-time-native"),this.obsTimeQualifier=this.shadow.getElementById("obs-time-qualifier"),this.obsEndTimeQualifier=this.shadow.getElementById("obs-end-time-qualifier"),this.edtfModeButton=this.shadow.getElementById("edtf-mode"),this.witnessIdInput=this.shadow.getElementById("witnessId"),this.witnessDirNameInput=this.shadow.getElementById("witnessDirName"),this.witnessTitleInput=this.shadow.getElementById("witnessTitle"),this.witnessLastNameInput=this.shadow.getElementById("witnessLastName"),this.witnessFirstNamesInput=this.shadow.getElementById("witnessFirstNames"),this.witnessAgeInput=this.shadow.getElementById("witnessAge"),this.witnessOccupationInput=this.shadow.getElementById("witnessOccupation"),this.testimonySourceSelect=this.shadow.getElementById("testimonySource"),this.testimonyFollowedUpSelect=this.shadow.getElementById("testimonyFollowedUp"),this.caseIdInput=this.shadow.getElementById("caseId"),this.descriptionInput=this.shadow.getElementById("description"),this.tagsInput=this.shadow.getElementById("tags"),this.cloudCoverInput=this.shadow.getElementById("cloudCover"),this.highCloudCoverInput=this.shadow.getElementById("highCloudCover"),this.iceCrystalAlignmentInput=this.shadow.getElementById("iceCrystalAlignment"),this.cloudDarknessInput=this.shadow.getElementById("cloudDarkness"),this.cloudBaseInput=this.shadow.getElementById("cloudBase"),this.precipitationTypeSelect=this.shadow.getElementById("precipitationType"),this.precipitationIntensityInput=this.shadow.getElementById("precipitationIntensity"),this.windDirectionInput=this.shadow.getElementById("windDirection"),this.windSpeedInput=this.shadow.getElementById("windSpeed"),this.stormInput=this.shadow.getElementById("storm"),this.weatherInferredInput=this.shadow.getElementById("weatherInferred"),this.weatherSourceText=this.shadow.getElementById("weather-source-text"),this.skyCandidatesOutput=this.shadow.getElementById("sky-candidates"),this.showMeteorButton=this.shadow.getElementById("show-meteor"),this.showCometButton=this.shadow.getElementById("show-comet"),this.weatherSourceLink=this.shadow.getElementById("weather-source-link"),this.weatherFields=[this.cloudCoverInput,this.highCloudCoverInput,this.iceCrystalAlignmentInput,this.cloudDarknessInput,this.cloudBaseInput,this.precipitationTypeSelect,this.precipitationIntensityInput,this.windDirectionInput,this.windSpeedInput,this.stormInput],this.soundKindSelect=this.shadow.getElementById("soundKind"),this.soundVolumeInput=this.shadow.getElementById("soundVolume"),this.soundPitchInput=this.shadow.getElementById("soundPitch"),this.soundPitchValue=this.shadow.getElementById("sound-pitch-value"),this.soundSrcInput=this.shadow.getElementById("soundSrc"),this.soundFields=[this.soundKindSelect,this.soundVolumeInput,this.soundPitchInput,this.soundSrcInput],this.buildSoundKindOptions(),this.instrumentSelect=this.shadow.getElementById("instrument"),this.focalLengthInput=this.shadow.getElementById("focalLength"),this.labelFocalLength=this.shadow.getElementById("label-focal-length"),this.unitFocalLength=this.shadow.getElementById("unit-focal-length"),this.labelFNumber=this.shadow.getElementById("label-f-number"),this.labelExposure=this.shadow.getElementById("label-exposure"),this.fNumberInput=this.shadow.getElementById("fNumber"),this.exposureInput=this.shadow.getElementById("exposureSeconds"),this.focusDistanceInput=this.shadow.getElementById("focusDistance"),this.labelFocusDistance=this.shadow.getElementById("label-focus-distance"),this.refreshInstrumentOptions(),this.labelColor=this.shadow.getElementById("label-color"),this.labelTransparency=this.shadow.getElementById("label-transparency"),this.labelHalo=this.shadow.getElementById("label-halo"),this.labelBlur=this.shadow.getElementById("label-blur"),this.labelBrightness=this.shadow.getElementById("label-brightness"),this.labelShape=this.shadow.getElementById("label-shape"),this.labelShapeTitle=this.shadow.getElementById("label-shape-title"),this.labelUtcOffset=this.shadow.getElementById("label-utc-offset"),this.labelApparentWidth=this.shadow.getElementById("label-apparent-width"),this.labelRealWidth=this.shadow.getElementById("label-real-width"),this.labelObjectDistance=this.shadow.getElementById("label-object-distance"),this.labelSizeLock=this.shadow.getElementById("label-size-lock"),this.labelSamplingRate=this.shadow.getElementById("label-sampling-rate"),this.labelSoundGroup=this.shadow.getElementById("label-sound-group"),this.labelSoundKind=this.shadow.getElementById("label-sound-kind"),this.labelSoundVolume=this.shadow.getElementById("label-sound-volume"),this.labelSoundPitch=this.shadow.getElementById("label-sound-pitch"),this.labelSoundSrc=this.shadow.getElementById("label-sound-src"),this.labelDuration=this.shadow.getElementById("label-duration"),this.placeSourceRow=this.shadow.getElementById("place-source-row"),this.weatherSourceRow=this.shadow.getElementById("weather-source-row"),this.terrainSourceRows=this.shadow.getElementById("terrain-source-rows"),this.labelPlaceName=this.shadow.getElementById("label-place-name"),this.labelPlaceMatch=this.shadow.getElementById("label-place-match"),this.labelLatitude=this.shadow.getElementById("label-lat"),this.labelLongitude=this.shadow.getElementById("label-lng"),this.labelHeading=this.shadow.getElementById("label-heading"),this.labelPitch=this.shadow.getElementById("label-pitch"),this.labelRoll=this.shadow.getElementById("label-roll"),this.labelElevation=this.shadow.getElementById("label-elevation"),this.labelObservationTime=this.shadow.getElementById("label-observation-time"),this.labelObservationEndTime=this.shadow.getElementById("label-observation-end-time"),this.labelWitnessId=this.shadow.getElementById("label-witness-id"),this.labelWitnessDirName=this.shadow.getElementById("label-witness-dir-name"),this.labelWitnessTitle=this.shadow.getElementById("label-witness-title"),this.labelWitnessLastName=this.shadow.getElementById("label-witness-last-name"),this.labelWitnessFirstNames=this.shadow.getElementById("label-witness-first-names"),this.labelWitnessAge=this.shadow.getElementById("label-witness-age"),this.labelWitnessOccupation=this.shadow.getElementById("label-witness-occupation"),this.labelTestimonySource=this.shadow.getElementById("label-testimony-source"),this.labelTestimonyFollowedUp=this.shadow.getElementById("label-testimony-followed-up"),this.labelCaseId=this.shadow.getElementById("label-case-id"),this.labelDescription=this.shadow.getElementById("label-description"),this.labelTags=this.shadow.getElementById("label-tags"),this.labelImportFile=this.shadow.getElementById("label-import-file"),this.labelImportUrl=this.shadow.getElementById("label-import-url"),this.labelNarrativeKey=this.shadow.getElementById("label-narrative-key"),this.labelNarrativeWorkspace=this.shadow.getElementById("label-narrative-workspace"),this.labelNarrativeRemember=this.shadow.getElementById("label-narrative-remember"),this.labelShapeGroup=this.shadow.getElementById("label-shape-group"),this.labelTemporalGroup=this.shadow.getElementById("label-temporal-group"),this.labelLocationGroup=this.shadow.getElementById("label-location-group"),this.labelObservationGroup=this.shadow.getElementById("label-observation-group"),this.labelWitnessGroup=this.shadow.getElementById("label-witness-group"),this.labelWeatherGroup=this.shadow.getElementById("label-weather-group"),this.labelCloudCover=this.shadow.getElementById("label-cloud-cover"),this.labelHighCloud=this.shadow.getElementById("label-high-cloud"),this.labelIceAlignment=this.shadow.getElementById("label-ice-alignment"),this.labelCloudDarkness=this.shadow.getElementById("label-cloud-darkness"),this.labelCloudBase=this.shadow.getElementById("label-cloud-base"),this.labelPrecipitationType=this.shadow.getElementById("label-precipitation-type"),this.labelPrecipitationIntensity=this.shadow.getElementById("label-precipitation-intensity"),this.labelWindDirection=this.shadow.getElementById("label-wind-direction"),this.labelWindSpeed=this.shadow.getElementById("label-wind-speed"),this.labelStorm=this.shadow.getElementById("label-storm"),this.labelWeatherInferred=this.shadow.getElementById("label-weather-inferred"),this.labelInstrument=this.shadow.getElementById("label-instrument"),this.optionPrecipitationNone=this.shadow.getElementById("option-precipitation-none"),this.optionPrecipitationRain=this.shadow.getElementById("option-precipitation-rain"),this.optionPrecipitationSnow=this.shadow.getElementById("option-precipitation-snow"),this.optionPrecipitationHail=this.shadow.getElementById("option-precipitation-hail"),this.decorKindSelect=this.shadow.getElementById("decorKind"),this.addDecorWitnessButton=this.shadow.getElementById("add-decor-witness"),this.addDecorBuildingButton=this.shadow.getElementById("add-decor-building"),this.deleteDecorButton=this.shadow.getElementById("delete-decor"),this.decorSelect=this.shadow.getElementById("decor"),this.decorTitleInput=this.shadow.getElementById("decorTitle"),this.decorEastInput=this.shadow.getElementById("decorEast"),this.decorNorthInput=this.shadow.getElementById("decorNorth"),this.decorHeadingInput=this.shadow.getElementById("decorHeading"),this.decorColorInput=this.shadow.getElementById("decorColor"),this.decorLitInput=this.shadow.getElementById("decorLit"),this.decorLightRigSelect=this.shadow.getElementById("decorLightRig"),this.lookAtDecorButton=this.shadow.getElementById("look-at-decor"),this.decorAltitudeInput=this.shadow.getElementById("decorAltitude"),this.labelDecorAltitude=this.shadow.getElementById("label-decor-altitude"),this.decorSightingUrlInput=this.shadow.getElementById("decorSightingUrl"),this.confirmOverlay=this.shadow.getElementById("confirm-overlay"),this.confirmMessage=this.shadow.getElementById("confirm-message"),this.confirmAcceptButton=this.shadow.getElementById("confirm-ok"),this.confirmDeclineButton=this.shadow.getElementById("confirm-cancel"),this.milestoneSelect=this.shadow.getElementById("milestone"),this.milestoneLabelInput=this.shadow.getElementById("milestoneLabel"),this.milestoneNoteInput=this.shadow.getElementById("milestoneNote"),this.addMilestoneButton=this.shadow.getElementById("add-milestone"),this.deleteMilestoneButton=this.shadow.getElementById("delete-milestone"),this.decorWidthInput=this.shadow.getElementById("decorWidth"),this.decorLengthInput=this.shadow.getElementById("decorLength"),this.decorHeightInput=this.shadow.getElementById("decorHeight"),this.decorModelSelect=this.shadow.getElementById("decorModel"),this.decorModelAdvanced=this.shadow.getElementById("decor-model-advanced"),this.decorModelUrlInput=this.shadow.getElementById("decorModelUrl"),this.decorModelTitleInput=this.shadow.getElementById("decorModelTitle"),this.decorModelAuthorInput=this.shadow.getElementById("decorModelAuthor"),this.decorModelLicenseInput=this.shadow.getElementById("decorModelLicense"),this.decorModelSourceInput=this.shadow.getElementById("decorModelSource"),this.decorFloorsInput=this.shadow.getElementById("decorFloors"),this.decorOccupiedFloorInput=this.shadow.getElementById("decorOccupiedFloor"),this.decorWitnessSideSelect=this.shadow.getElementById("decorWitnessSide"),this.decorWindowInputs={front:this.shadow.getElementById("decorWindowFront"),behind:this.shadow.getElementById("decorWindowBehind"),left:this.shadow.getElementById("decorWindowLeft"),right:this.shadow.getElementById("decorWindowRight"),"front-left":this.shadow.getElementById("decorWindowFrontLeft"),"front-right":this.shadow.getElementById("decorWindowFrontRight"),"behind-left":this.shadow.getElementById("decorWindowBehindLeft"),"behind-right":this.shadow.getElementById("decorWindowBehindRight")},this.labelDecorSide={front:this.shadow.getElementById("label-decor-window-front"),behind:this.shadow.getElementById("label-decor-window-behind"),left:this.shadow.getElementById("label-decor-window-left"),right:this.shadow.getElementById("label-decor-window-right"),"front-left":this.shadow.getElementById("label-decor-window-front-left"),"front-right":this.shadow.getElementById("label-decor-window-front-right"),"behind-left":this.shadow.getElementById("label-decor-window-behind-left"),"behind-right":this.shadow.getElementById("label-decor-window-behind-right")},this.optionWitnessSide={front:this.shadow.getElementById("option-witness-side-front"),behind:this.shadow.getElementById("option-witness-side-behind"),left:this.shadow.getElementById("option-witness-side-left"),right:this.shadow.getElementById("option-witness-side-right"),"front-left":this.shadow.getElementById("option-witness-side-front-left"),"front-right":this.shadow.getElementById("option-witness-side-front-right"),"behind-left":this.shadow.getElementById("option-witness-side-behind-left"),"behind-right":this.shadow.getElementById("option-witness-side-behind-right")},this.optionWitnessSideNone=this.shadow.getElementById("option-witness-side-none"),this.labelDecor=this.shadow.getElementById("label-decor"),this.labelDecorGroup=this.shadow.getElementById("label-decor-group"),this.labelDecorTitle=this.shadow.getElementById("label-decor-title"),this.labelDecorEast=this.shadow.getElementById("label-decor-east"),this.labelDecorNorth=this.shadow.getElementById("label-decor-north"),this.labelDecorHeading=this.shadow.getElementById("label-decor-heading"),this.labelDecorColor=this.shadow.getElementById("label-decor-color"),this.labelDecorLit=this.shadow.getElementById("label-decor-lit"),this.labelDecorSightingUrl=this.shadow.getElementById("label-decor-sighting-url"),this.labelMilestones=this.shadow.getElementById("label-milestones"),this.labelMilestoneLabel=this.shadow.getElementById("label-milestone-label"),this.labelMilestoneNote=this.shadow.getElementById("label-milestone-note"),this.labelDecorWidth=this.shadow.getElementById("label-decor-width"),this.labelDecorLength=this.shadow.getElementById("label-decor-length"),this.labelDecorHeight=this.shadow.getElementById("label-decor-height"),this.labelDecorModel=this.shadow.getElementById("label-decor-model"),this.labelDecorModelAdvanced=this.shadow.getElementById("label-decor-model-advanced"),this.labelDecorModelUrl=this.shadow.getElementById("label-decor-model-url"),this.labelDecorModelTitle=this.shadow.getElementById("label-decor-model-title"),this.labelDecorModelAuthor=this.shadow.getElementById("label-decor-model-author"),this.labelDecorModelLicense=this.shadow.getElementById("label-decor-model-license"),this.labelDecorModelSource=this.shadow.getElementById("label-decor-model-source"),this.labelDecorFloors=this.shadow.getElementById("label-decor-floors"),this.labelDecorOccupiedFloor=this.shadow.getElementById("label-decor-occupied-floor"),this.labelDecorWitnessSide=this.shadow.getElementById("label-decor-witness-side"),this.labelDecorWindows=this.shadow.getElementById("label-decor-windows"),this.optionDecorBuilding=this.shadow.getElementById("option-decor-building"),this.optionDecorTree=this.shadow.getElementById("option-decor-tree"),this.optionDecorCrop=this.shadow.getElementById("option-decor-crop"),this.optionDecorMound=this.shadow.getElementById("option-decor-mound"),this.optionDecorStreetlight=this.shadow.getElementById("option-decor-streetlight"),this.optionDecorVehicle=this.shadow.getElementById("option-decor-vehicle"),this.optionDecorAircraft=this.shadow.getElementById("option-decor-aircraft"),this.optionDecorEntity=this.shadow.getElementById("option-decor-entity"),this.labelDecorLights=this.shadow.getElementById("label-decor-lights"),this.optionDecorWitness=this.shadow.getElementById("option-decor-witness"),this.ufoElement.canvasElement.addEventListener("pointerdown",t=>{this.focus({preventScroll:!0}),this.onPointerDown(t)}),this.ufoElement.canvasElement.addEventListener("pointermove",t=>this.onPointerMove(t)),this.ufoElement.canvasElement.addEventListener("contextmenu",t=>this.onContextMenu(t)),this.contextGroupButton.addEventListener("click",()=>this.groupSelected()),this.contextUngroupButton.addEventListener("click",()=>this.ungroupSelected()),this.contextBringToFrontButton.addEventListener("click",()=>this.bringSelectedToFront()),this.contextSendToBackButton.addEventListener("click",()=>this.sendSelectedToBack()),this.contextDeleteButton.addEventListener("click",()=>{this.hideContextMenu(),this.deleteShape()}),this.contextAddVertexButton.addEventListener("click",()=>this.addVertexAtContextMenu()),this.contextDeleteVertexButton.addEventListener("click",()=>this.deleteVertexAtContextMenu()),this.contextViewTestimonyButton.addEventListener("click",()=>this.viewWitnessTestimony()),this.playPauseButton.addEventListener("click",()=>{this.ufoElement.togglePlayPause(),this.syncPlaybackControls()}),this.loopButton.addEventListener("click",()=>{this.ufoElement.toggleLoop(),this.syncPlaybackControls()}),this.seekInput.addEventListener("input",()=>this.ufoElement.currentTime=Number(this.seekInput.value)),this.recordButton.addEventListener("click",()=>this.toggleRecording()),this.addShapeButton.addEventListener("click",()=>this.addShape()),this.deleteShapeButton.addEventListener("click",()=>this.deleteShape()),this.exportButton.addEventListener("click",()=>this.exportJson()),this.importFileInput.addEventListener("change",()=>this.importFromFile()),this.importUrlButton.addEventListener("click",()=>this.importFromUrl()),this.testimonySourceSelect.addEventListener("change",()=>this.updateWitnessMetadata()),this.testimonyFollowedUpSelect.addEventListener("change",()=>this.updateWitnessMetadata()),this.narrativeDraftButton.addEventListener("click",()=>this.draftFromDescription()),this.narrativeStopButton.addEventListener("click",()=>this.narrativeAbort?.abort()),this.narrativeRememberInput.addEventListener("change",()=>this.rememberNarrativeKey()),this.narrativeWorkspaceInput.addEventListener("input",()=>this.rememberNarrativeKey()),this.narrativeKeyInput.addEventListener("input",()=>{this.rememberNarrativeKey(),this.syncNarrativeEnabled()}),this.narrativeCreditLink.textContent=`${Ts[0].name} — ${Ts[0].credit}`,this.narrativeCreditLink.href=Ts[0].creditUrl,this.labelNarrativeKey.textContent=this.messages.narrativeKey.replace("{source}",Ts[0].name),this.narrativeWorkspaceInput.title=this.messages.narrativeWorkspaceHint,this.restoreNarrativeKey(),this.syncNarrativeEnabled(),this.durationInput.addEventListener("input",()=>{this.ufoElement.durationSeconds=this.durationInput.value===""?void 0:Number(this.durationInput.value),this.ufoElement.refresh(),this.updateDurationValidity(),this.scheduleWeatherLookup()}),this.sourceSelect.addEventListener("change",()=>this.selectUnit(this.sourceSelect.value)),this.shapeTitleInput.addEventListener("input",()=>this.updateShapeTitle()),this.apparentWidthInput.addEventListener("input",()=>this.typing(this.apparentWidthInput,()=>this.onApparentWidthInput())),this.realWidthInput.addEventListener("input",()=>this.typing(this.realWidthInput,()=>this.onRealWidthInput())),this.objectDistanceInput.addEventListener("input",()=>this.typing(this.objectDistanceInput,()=>this.onDistanceInput())),this.sizeLockSelect.addEventListener("change",()=>this.applySizeLock()),this.clearDistanceHypothesisButton.addEventListener("click",()=>this.clearDistanceHypothesis()),this.addDecorWitnessButton.addEventListener("click",()=>this.addDecor("witness")),this.addDecorBuildingButton.addEventListener("click",()=>this.addDecor()),this.deleteDecorButton.addEventListener("click",()=>this.deleteDecor()),this.decorSelect.addEventListener("change",()=>this.selectDecor(this.decorSelect.value));for(const t of[this.decorTitleInput,this.decorEastInput,this.decorNorthInput,this.decorAltitudeInput,this.decorHeadingInput,this.decorColorInput,this.decorSightingUrlInput,this.decorWidthInput,this.decorLengthInput,this.decorHeightInput,this.decorModelUrlInput,this.decorModelTitleInput,this.decorModelAuthorInput,this.decorModelLicenseInput,this.decorModelSourceInput,this.decorFloorsInput,this.decorOccupiedFloorInput])t.addEventListener("input",()=>this.updateDecor());this.decorWitnessSideSelect.addEventListener("change",()=>this.updateDecor()),this.decorModelSelect.addEventListener("change",()=>this.updateDecorModelChoice()),this.addMilestoneButton.addEventListener("click",()=>this.addMilestone()),this.deleteMilestoneButton.addEventListener("click",()=>this.deleteMilestone()),this.milestoneSelect.addEventListener("change",()=>this.selectMilestone(Number(this.milestoneSelect.value)));for(const t of[this.milestoneLabelInput,this.milestoneNoteInput])t.addEventListener("input",()=>this.updateMilestone());this.confirmAcceptButton.addEventListener("click",()=>this.answerConfirm(!0)),this.confirmDeclineButton.addEventListener("click",()=>this.answerConfirm(!1)),this.confirmOverlay.addEventListener("click",t=>{t.target===this.confirmOverlay&&this.answerConfirm(!1)});for(const t of ia)this.decorWindowInputs[t].addEventListener("input",()=>this.updateDecorWindows());this.decorLitInput.addEventListener("input",()=>this.updateDecorLit()),this.decorLightRigSelect.addEventListener("change",()=>this.updateDecorLightRig()),this.lookAtDecorButton.addEventListener("click",()=>this.lookAtDecor()),this.showMeteorButton.addEventListener("click",()=>this.showNextMeteor()),this.showCometButton.addEventListener("click",()=>this.lookAtComet()),this.ufoElement.addEventListener("timeupdate",()=>{this.onSelectionOrTimeChanged(),this.syncPlaybackControls(),this.dispatchEvent(new CustomEvent("sightingchange"))}),this.addEventListener("keydown",this.handleKeyDown);for(const t of mm)this.presetButtons[t].addEventListener("click",()=>this.setAppearance({presetId:t}));this.colorInput.addEventListener("input",()=>this.setAppearance({color:this.colorInput.value})),this.transparencyInput.addEventListener("input",()=>this.setAppearance({transparency:Number(this.transparencyInput.value)})),this.brightnessInput.addEventListener("input",()=>this.setAppearance({brightness:Number(this.brightnessInput.value)})),this.blurInput.addEventListener("input",()=>{this.setAppearance({blur:Number(this.blurInput.value)}),this.refreshBlurDistanceBound()}),this.haloScaleInput.addEventListener("input",()=>this.setAppearance({haloScale:Number(this.haloScaleInput.value)}));for(const t of[this.latInput,this.lngInput,this.headingInput,this.pitchInput,this.rollInput,this.elevationInput])t.addEventListener("input",()=>this.updateObserver());for(const t of[this.focalLengthInput,this.fNumberInput,this.exposureInput,this.focusDistanceInput])t.addEventListener("input",()=>this.updateObserver());this.searchPlaceButton.addEventListener("click",()=>void this.searchPlace()),this.placeNameInput.addEventListener("keydown",t=>{t.key==="Enter"&&(t.preventDefault(),this.searchPlace())}),this.placeMatchSelect.addEventListener("change",()=>this.applyPlaceMatch(this.placeMatchSelect.selectedIndex)),this.placeNameInput.addEventListener("input",()=>this.updatePlaceName()),this.headingInput.addEventListener("focus",()=>this.sceneElement.setCompassForced(!0)),this.headingInput.addEventListener("blur",()=>this.sceneElement.setCompassForced(!1)),this.instrumentSelect.addEventListener("change",()=>{const t=this.ufoElement.sighting.instrument;this.ufoElement.sighting.instrumentId=this.instrumentSelect.value;const n=new Map(this.ufoElement.sighting.timeline.allKeyframes.map(i=>[i.t,an.fovOf(this.ufoElement.sighting,i.t)]));this.retuneFieldOfView(t),this.retuneExposure(t),an.reproject(this.ufoElement.sighting,t,n),this.sceneElement.applyFrameFormat(),this.syncOpticsFromInstrument(),this.ufoElement.refresh(),this.dispatchEvent(new CustomEvent("sightingchange"))}),this.utcOffsetInput.addEventListener("input",()=>this.updateUtcOffset()),this.timeZoneSelect.addEventListener("change",()=>{this.autoFilledTimeZone=void 0,this.updateTimeZone()}),this.obsTimeInput.addEventListener("input",()=>this.updateObservationTime()),this.obsEndTimeInput.addEventListener("input",()=>this.updateObservationEndTime()),this.obsTimeNativeInput.addEventListener("change",()=>this.writeFromPicker(this.obsTimeNativeInput,this.obsTimeQualifier,this.obsTimeInput,()=>this.updateObservationTime())),this.obsEndTimeNativeInput.addEventListener("change",()=>this.writeFromPicker(this.obsEndTimeNativeInput,this.obsEndTimeQualifier,this.obsEndTimeInput,()=>this.updateObservationEndTime())),this.obsTimeQualifier.addEventListener("change",()=>this.writeFromPicker(this.obsTimeNativeInput,this.obsTimeQualifier,this.obsTimeInput,()=>this.updateObservationTime())),this.obsEndTimeQualifier.addEventListener("change",()=>this.writeFromPicker(this.obsEndTimeNativeInput,this.obsEndTimeQualifier,this.obsEndTimeInput,()=>this.updateObservationEndTime())),this.edtfModeButton.addEventListener("click",()=>this.setEdtfMode(!this.edtfMode)),this.obsTimeInput.addEventListener("blur",()=>this.validateEdtfTimeInput(this.obsTimeInput)),this.obsEndTimeInput.addEventListener("blur",()=>this.validateEdtfTimeInput(this.obsEndTimeInput));for(const t of[this.witnessIdInput,this.witnessDirNameInput,this.witnessTitleInput,this.witnessLastNameInput,this.witnessFirstNamesInput,this.witnessAgeInput,this.witnessOccupationInput,this.caseIdInput])t.addEventListener("input",()=>this.updateWitnessMetadata());this.descriptionInput.addEventListener("input",()=>{this.updateDescription(),this.syncNarrativeEnabled()}),this.tagsInput.addEventListener("input",()=>this.updateTags());for(const t of this.weatherFields){if(t===this.iceCrystalAlignmentInput){t.addEventListener("input",()=>this.applyIceAlignmentAtPlayhead());continue}t.addEventListener("input",()=>this.applyWeatherAtPlayhead())}for(const t of this.soundFields)t.addEventListener("input",()=>this.applySoundAtPlayhead());this.weatherInferredInput.addEventListener("change",()=>this.onWeatherInferredToggled()),this.skyDetailsButton=this.shadow.getElementById("sky-details"),this.clampedLines=[this.shadow.getElementById("weather-source"),this.shadow.getElementById("sky-candidates")],this.skyDetailsButton.addEventListener("click",()=>this.toggleSkyDetails()),this.groupTabs=[...this.shadow.querySelectorAll(".group-tab")],this.groupPanels=this.groupTabs.map(t=>this.shadow.getElementById(t.getAttribute("aria-controls")));for(const t of this.groupTabs)t.addEventListener("click",()=>this.toggleGroup(t,!this.isGroupOpen(t)));this.paramSummary=this.shadow.getElementById("param-summary"),this.paramSummaryBuilder=new bf(this.messages,this.showerLanguage(),this.said,this.tagNames),this.paramSummary.addEventListener("click",t=>this.onParamSummaryClick(t)),this.toggleGroup(this.groupTabs[this.groupTabs.length-1],!0),this.updatePresetButtons(),this.setRecordButtonLabel(!1),this.applyAppearanceAtPlayhead(),this.shapeTitleInput.value=this.shapeLabel(this.currentSourceId),this.updateShapeTitle(),this.currentDecorId=this.ufoElement.sighting.decor[0]?.id,this.refreshDecorList(),this.sceneElement.setCloudRendering("volume"),this.cloudEditor=Gv(this.shadow.getElementById("cloud-editor"),this.sceneElement,(t=!0)=>{t&&(this.weatherFromRecords=!1,this.cancelWeatherLookup(),this.ufoElement.sighting.weatherSource=void 0,this.syncWeatherSourceState())},(t,n)=>{this.headingInput.value=String(this.rounded(t)),this.pitchInput.value=String(this.rounded(n)),this.updateObserver()},za(vs.preferencesFor(this),Hh)),this.currentMilestoneT=this.ufoElement.sighting.milestones[0]?.t,this.refreshMilestoneList(),this.onSelectionOrTimeChanged(),this.syncDurationField(),this.syncPlaybackControls(),this.refreshSourceRows(),this.refreshTimeQualifierOptions(),this.refreshTimeZoneOptions(),this.syncWeatherSourceState(),this.loadLocaleMessages()}static get observedAttributes(){return["src"]}connectedCallback(){this.hasAttribute("tabindex")||(this.tabIndex=-1);const e=this.getAttribute("src");e&&this.importFromUrl(e)}attributeChangedCallback(e,t,n){e==="src"&&n&&n!==t&&this.isConnected&&this.importFromUrl(n)}disconnectedCallback(){this.cloudEditor.stopManipulation(),document.removeEventListener("click",this.handleOutsideContextMenuClick),this.endDrag()}setCloudRendering(e){this.sceneElement.setCloudRendering(e)}showWeatherEditor(){const e=this.groupPanels.findIndex(t=>t.id==="group-weather");e>=0&&this.toggleGroup(this.groupTabs[e],!0)}get sightingData(){return this.ufoElement.sightingData}set sightingData(e){this.endDrag(),this.ufoElement.sightingData=e,this.cloudEditor.reset(),this.currentSourceId=this.ufoElement.sighting.timeline.sourceIds[0]??ml,this.selectedSourceIds=new Set([this.currentSourceId]),this.refreshSourceList(),this.currentDecorId=this.ufoElement.sighting.decor[0]?.id,this.refreshDecorList(),this.currentMilestoneT=this.ufoElement.sighting.milestones[0]?.t,this.refreshMilestoneList(),this.onSelectionOrTimeChanged(),this.syncDurationField(),this.syncObservationTimeFields(),this.syncObservationEndTimeFields(),this.chooseTimeInputMode(),this.syncWitnessMetadataFields(),this.refreshTimeZoneOptions(),this.utcOffsetInput.readOnly=this.ufoElement.sighting.event.timeZone!==void 0,this.syncUtcOffsetField(),this.syncPlaceNameField(),this.syncGroundElevationField(),this.syncWeatherOwnership()}exportJson(){const e=this.sightingData,t=`${e.witness?.id??"sighting"}-sighting.json`,n=new Blob([JSON.stringify(e,null,2)],{type:"application/json"}),i=URL.createObjectURL(n),s=document.createElement("a");s.href=i,s.download=t,s.click(),URL.revokeObjectURL(i)}async importFromFile(){const e=this.importFileInput.files?.[0];if(e)try{const t=await new Promise((n,i)=>{const s=new FileReader;s.onload=()=>n(s.result),s.onerror=()=>i(s.error),s.readAsText(e)});this.sightingData=JSON.parse(t)}catch{window.alert(this.messages.importError)}finally{this.importFileInput.value=""}}async importFromUrl(e=this.importUrlInput.value.trim()){if(e)try{this.sightingData=await fu.json(e)}catch(t){window.alert(this.importErrorFor(t))}}importErrorFor(e){if(!(e instanceof Os))return this.messages.importError;switch(e.kind){case"cors":return this.messages.importErrorCors;case"mixed-content":return this.messages.importErrorMixedContent;case"unreachable":return this.messages.importErrorUnreachable;case"status":return this.messages.importErrorStatus.replace("{status}",String(e.status??""));case"malformed":return this.messages.importErrorMalformed;default:return this.messages.importError}}static NARRATIVE_KEY_STORAGE="rr0-sighting-editor.narrative-key";static NARRATIVE_SCOPE_STORAGE="rr0-sighting-editor.narrative-workspace";narrativeProvider=Ts[0].create();narrativeAbort;async draftFromDescription(){const e=this.descriptionInput.value.trim();if(e===""||this.narrativeAbort)return;const t=this.narrativeAbort=new AbortController;this.setNarrativeBusy(!0);try{const n=await this.narrativeProvider.draft({ask:e,current:this.sightingData,language:this.showerLanguage()==="fr"?"French":"English",credential:this.narrativeKeyInput.value.trim()||void 0,credentialScope:this.narrativeWorkspaceInput.value.trim()||void 0},t.signal);this.applyNarrativeDraft(n)}catch(n){const i=n instanceof Ln&&n.kind==="cancelled";this.narrativeStatus.textContent=i?"":this.narrativeErrorFor(n),this.narrativeStatus.classList.toggle("error",!i)}finally{this.narrativeAbort=void 0,this.setNarrativeBusy(!1)}}applyNarrativeDraft(e){const{description:t,...n}=e.recording,{utcOffsetHours:i,...s}=n,r=n.timeZone?s:n,o=yi.stated(r);if(o.length>0){const l=this.ufoElement.sighting.provenance,c=zh(this.ufoElement.sighting);this.sightingData=yi.apply(c,Pl.loadable(r),o),this.ufoElement.sighting.provenance=l,this.recordNarrativeProvenance(e,o),this.ufoElement.sighting.event.timeZone&&this.applyTimeZoneOffset()}this.narrativeStatus.textContent=o.length>0?this.messages.narrativeApplied.replace("{count}",String(o.length)):this.messages.narrativeUnchanged,this.narrativeStatus.classList.remove("error"),this.showNarrativeReport(e),this.syncNarrativeEnabled()}recordNarrativeProvenance(e,t){const n=this.ufoElement.sighting,i=new Set(t);for(const s of e.claims)!i.has(s.path)&&!t.some(r=>s.path.startsWith(`${r}.`))||n.provenance.set(s.path,{basis:s.basis,rationale:s.rationale,of:Mt.valueAt(zh(this.ufoElement.sighting),s.path)})}static valueAt(e,t){let n=e;for(const i of t.split(".")){if(typeof n!="object"||n===null)return;n=n[i]}return n}showNarrativeReport(e){this.narrativeReport.replaceChildren();for(const t of["assumed","derived","stated"]){const n=e.claims.filter(i=>i.basis===t);if(n.length!==0){this.narrativeReport.append(this.narrativeHeading(this.messages[bA[t]]));for(const i of n){const s=document.createElement("div");s.className=`claim ${t}`;const r=document.createElement("code");r.textContent=i.path;const o=document.createElement(t==="stated"?"q":"span");o.textContent=i.rationale,s.append(r,o),this.narrativeReport.append(s)}}}if(e.gaps.length>0){this.narrativeReport.append(this.narrativeHeading(this.messages.narrativeGaps));const t=document.createElement("ul");t.className="gaps";for(const n of e.gaps){const i=document.createElement("li");i.textContent=n,t.append(i)}this.narrativeReport.append(t)}this.narrativeReport.hidden=this.narrativeReport.childElementCount===0}narrativeHeading(e){const t=document.createElement("h4");return t.textContent=e,t}setNarrativeBusy(e){this.descriptionInput.disabled=e,this.narrativeStopButton.hidden=!e,e&&(this.narrativeStatus.textContent=this.messages.narrativeWorking,this.narrativeStatus.classList.remove("error")),this.syncNarrativeEnabled()}syncNarrativeEnabled(){const e=Ts[0].name,t=this.narrativeProvider.needsCredential&&this.narrativeKeyInput.value.trim()==="",n=this.descriptionInput.value.trim()==="";this.narrativeDraftButton.disabled=!!this.narrativeAbort||t||n,this.narrativeDraftButton.title=t?this.messages.narrativeNeedsKey.replace("{source}",e):n?this.messages.narrativeNeedsAsk:"",this.narrativeKeyInput.parentElement.hidden=!this.narrativeProvider.needsCredential,this.narrativeRememberInput.parentElement.hidden=!this.narrativeProvider.needsCredential,this.narrativeWorkspaceInput.parentElement.hidden=!this.narrativeProvider.acceptsCredentialScope;const i=this.narrativeKeyInput.value.trim(),s=i!==""&&!i.startsWith("sk-ant-");this.narrativeKeyInput.classList.toggle("invalid",s),this.narrativeKeyInput.title=s?this.messages.narrativeKeyUnlikely:""}narrativeErrorFor(e){if(!(e instanceof Ln))return this.messages.narrativeErrorMalformed;switch(e.kind){case"rejected":return this.messages.narrativeErrorRejected.replace("{detail}",e.detail??"");case"credential":return this.messages.narrativeErrorCredential;case"rate-limited":return this.messages.narrativeErrorRateLimited;case"refused":return this.messages.narrativeErrorRefused;case"unreachable":return this.messages.narrativeErrorUnreachable;default:return this.messages.narrativeErrorMalformed}}rememberNarrativeKey(){try{this.narrativeRememberInput.checked?(localStorage.setItem(Mt.NARRATIVE_KEY_STORAGE,this.narrativeKeyInput.value),localStorage.setItem(Mt.NARRATIVE_SCOPE_STORAGE,this.narrativeWorkspaceInput.value)):(localStorage.removeItem(Mt.NARRATIVE_KEY_STORAGE),localStorage.removeItem(Mt.NARRATIVE_SCOPE_STORAGE))}catch{}}restoreNarrativeKey(){let e=null;try{e=localStorage.getItem(Mt.NARRATIVE_KEY_STORAGE)}catch{return}e!==null&&(this.narrativeKeyInput.value=e,this.narrativeWorkspaceInput.value=localStorage.getItem(Mt.NARRATIVE_SCOPE_STORAGE)??"",this.narrativeRememberInput.checked=!0)}numberOrUndefined(e){return e===""?void 0:Number(e)}stringOrUndefined(e){return e===""?void 0:e}wrapDegrees(e,t){if(e===void 0)return;const n=(e%360+360)%360;return String(n)!==t.value&&(t.value=String(n)),n}refreshSourceRows(){this.placeSourceRow.replaceChildren(document.createTextNode(`${this.messages.according} `),this.sourcePicker("place",QT,e=>{this.placeProvider=e.create()})),this.weatherSourceRow.replaceChildren(this.sourcePicker("weather",eA,e=>{this.weatherInference=new Th(e.create()),this.scheduleWeatherLookup()})),this.terrainSourceRows.replaceChildren(this.labelledPicker("elevation",this.messages.sourceElevation,Ch,()=>this.applyTerrainSources()),this.labelledPicker("imagery",this.messages.sourceImagery,hm,()=>this.applyTerrainSources()),this.labelledPicker("decor-model",this.messages.decorModel,El,()=>this.applyDecorModelSource()))}sourcePicker(e,t,n){const i=document.createDocumentFragment(),s=document.createElement("select");s.id=`${e}Source`;for(const l of t){const c=document.createElement("option");c.value=l.id,c.textContent=l.name,c.title=l.credit,s.appendChild(c)}s.value=this.chosenSourceId.get(e)??t[0].id;const r=document.createElement("a");r.className="source-credit",r.target="_blank",r.rel="noopener noreferrer";const o=()=>{const l=Ia(t,s.value);s.title=l.credit,r.href=l.creditUrl,r.textContent=l.credit};return o(),s.addEventListener("change",()=>{this.chosenSourceId.set(e,s.value),o(),n(Ia(t,s.value))}),i.append(s,document.createTextNode(" "),r),i}labelledPicker(e,t,n,i){const s=document.createElement("label"),r=document.createElement("span");return r.textContent=t,s.append(r,this.sourcePicker(e,n,i)),s}applyTerrainSources(){this.sceneElement.setTerrainProviders({elevation:Ia(Ch,this.chosenSourceId.get("elevation")).create(),imagery:Ia(hm,this.chosenSourceId.get("imagery")).create()}),this.ufoElement.refresh()}applyDecorModelSource(){this.decorModelProvider=Ia(El,this.chosenSourceId.get("decor-model")).create(),this.sceneElement.setDecorModelProvider(this.decorModelProvider),this.refreshDecorModelOptions(),this.ufoElement.refresh()}get placeSearchLanguage(){return navigator.languages?.[0]}set placeSearchProvider(e){this.placeProvider=e}async searchPlace(){const e=this.placeNameInput.value.trim();if(e==="")return;const t=++this.placeSearchToken;this.placeStatusText.textContent=this.messages.placeSearching;let n;try{n=await this.placeProvider.search(e,{language:this.placeSearchLanguage})}catch{if(t!==this.placeSearchToken)return;this.placeStatusText.textContent=this.messages.placeSearchFailed;return}t===this.placeSearchToken&&(this.placeMatches=n,this.refreshPlaceMatches(),n.length>0&&this.applyPlaceMatch(0))}refreshPlaceMatches(){this.placeMatchSelect.replaceChildren(...this.placeMatches.map(t=>{const n=document.createElement("option");return n.textContent=t.name,n.title=t.name,n})),this.placeMatchRow.hidden=this.placeMatches.length===0;const e=this.placeMatches.length===1?this.messages.placeMatchFound:this.messages.placeMatchesFound;this.placeStatusText.textContent=this.placeMatches.length===0?this.messages.placeNotFound:`${this.placeMatches.length} ${e} `,this.placeSourceRow.hidden=this.placeMatches.length===0}applyPlaceMatch(e){const t=this.placeMatches[e];t&&(this.placeMatchSelect.selectedIndex=e,this.placeNameInput.value=t.name,this.placeNameInput.title=t.name,this.latInput.value=String(t.lat),this.lngInput.value=String(t.lng),this.namedCoordinates={lat:t.lat,lng:t.lng},this.updateObserver())}updatePlaceName(){this.placeMatches=[],this.placeMatchRow.hidden=!0,this.placeStatusText.textContent="",this.placeSourceRow.hidden=!0,this.placeNameInput.title=this.placeNameInput.value,this.namedCoordinates=void 0,this.updateObserver()}schedulePlaceReverse(){if(!this.namedCoordinates)return;const e=this.numberOrUndefined(this.latInput.value),t=this.numberOrUndefined(this.lngInput.value);e===void 0||t===void 0||Math.abs(e-this.namedCoordinates.lat)<Ca&&Math.abs(t-this.namedCoordinates.lng)<Ca||(clearTimeout(this.placeReverseTimer),this.placeReverseTimer=setTimeout(()=>void this.reversePlace(e,t),um))}scheduleTimeZoneLookup(){const e=this.numberOrUndefined(this.latInput.value),t=this.numberOrUndefined(this.lngInput.value);if(e===void 0||t===void 0)return;const n=this.ufoElement.sighting.event.timeZone;if(n&&n!==this.autoFilledTimeZone)return;const i=this.timeZoneLookedUpAt;i&&Math.abs(e-i.lat)<Ca&&Math.abs(t-i.lng)<Ca||(clearTimeout(this.timeZoneLookupTimer),this.timeZoneLookupTimer=setTimeout(()=>void this.lookUpTimeZone(e,t),um))}async lookUpTimeZone(e,t){this.timeZoneLookedUpAt={lat:e,lng:t};const n=await this.timeZoneProvider.zoneAt(e,t),i=this.ufoElement.sighting.event.timeZone;!n||i&&i!==this.autoFilledTimeZone||this.timeZones.available().includes(n)&&(this.autoFilledTimeZone=n,this.timeZoneSelect.value=n,this.updateTimeZone(),this.dispatchEvent(new CustomEvent("sightingchange")))}async reversePlace(e,t){const n=++this.placeSearchToken;let i;try{i=await this.placeProvider.reverse(e,t,{language:this.placeSearchLanguage})}catch{return}n===this.placeSearchToken&&(this.namedCoordinates={lat:e,lng:t},this.placeNameInput.value=i?.name??"",this.placeNameInput.title=i?.name??"",this.placeMatches=[],this.placeMatchRow.hidden=!0,this.placeStatusText.textContent=i?"":this.messages.placeNotFound,this.placeSourceRow.hidden=!i,this.updateObserver())}updateObserver(){if(this.ufoElement.playbackState==="playing")return;const e=this.numberOrUndefined(this.latInput.value),t=this.numberOrUndefined(this.lngInput.value),n=this.wrapDegrees(this.numberOrUndefined(this.headingInput.value),this.headingInput),i=this.numberOrUndefined(this.pitchInput.value)??0,s=this.numberOrUndefined(this.rollInput.value)??0,r=this.numberOrUndefined(this.elevationInput.value)??this.groundElevationM??0,o=Math.max(0,r-(this.groundElevationM??0)),l=this.ufoElement.sighting.event,c=this.ufoElement.sighting.witnessTrack,h=this.ufoElement.currentTime,d=this.stringOrUndefined(this.placeNameInput.value.trim());l.place=e!==void 0&&t!==void 0?[{lat:e,lng:t,name:d}]:void 0;const u=this.ufoElement.sighting.instrument,f=this.numberOrUndefined(this.focalLengthInput.value),p=(u.frame&&f!==void 0?st.fieldOfViewDegAt(u,f):f)??this.currentFovDeg(),v=this.numberOrUndefined(this.fNumberInput.value),m=this.statedExposureSeconds(u);this.ufoElement.sighting.exposureSeconds=m===u.exposureSeconds?void 0:m;const g=this.numberOrUndefined(this.focusDistanceInput.value),_=Math.abs(p-st.fieldOfViewDeg(u))>.01||v!==u.fNumber||g!==void 0;e===void 0&&t===void 0&&n===void 0&&i===0&&s===0&&o===0&&!_?c.removeKeyframeAt(h):c.addKeyframe(h,{lat:e,lng:t,elevationM:o,headingDeg:n,pitchDeg:i,rollDeg:s===0?void 0:s,fovDeg:p,fNumber:v,focusDistanceM:g}),this.ufoElement.refresh(),this.scheduleWeatherLookup(),this.schedulePlaceReverse(),this.scheduleTimeZoneLookup(),this.scheduleGroundElevation(),this.updateUtcOffsetValidity()}applyEdtfTimeInput(e,t){const n=e.value.trim();if(n==="")t(void 0);else{const i=af(n);if(!i)return;t(i)}e.setCustomValidity(""),e.classList.remove("invalid"),this.dropDurationOutrankedByDates(),this.ufoElement.sighting.event.timeZone&&this.applyTimeZoneOffset(),this.ufoElement.refresh(),this.syncDurationField(),this.scheduleWeatherLookup()}dropDurationOutrankedByDates(){const e=this.ufoElement.sighting.event;e.durationSeconds!==void 0&&ja({...e,durationSeconds:void 0})!==void 0&&(this.ufoElement.durationSeconds=void 0)}validateEdtfTimeInput(e){const t=e.value.trim();t===""||af(t)||(e.setCustomValidity(this.messages.edtfInvalid),e.classList.add("invalid"))}refreshTimeZoneOptions(){const e=document.createElement("option");e.value="",e.textContent=this.messages.timeZoneManual,this.timeZoneSelect.replaceChildren(e,...this.timeZones.available().map(t=>{const n=document.createElement("option");return n.value=t,n.textContent=t,n})),this.timeZoneSelect.value=this.ufoElement.sighting.event.timeZone??""}updateTimeZone(){const e=this.stringOrUndefined(this.timeZoneSelect.value);this.ufoElement.sighting.event.timeZone=e,this.applyTimeZoneOffset()}applyTimeZoneOffset(){const e=this.ufoElement.sighting.event,t=e.timeZone&&e.time?this.timeZones.offsetHoursAt(e.timeZone,e.time):void 0;t!==void 0&&(e.utcOffsetHours=t),this.utcOffsetInput.readOnly=e.timeZone!==void 0,this.syncUtcOffsetField(),this.ufoElement.refresh(),this.scheduleWeatherLookup()}updateUtcOffset(){this.ufoElement.sighting.event.utcOffsetHours=this.numberOrUndefined(this.utcOffsetInput.value),this.updateUtcOffsetValidity(),this.ufoElement.refresh(),this.scheduleWeatherLookup()}updateObservationTime(){this.applyEdtfTimeInput(this.obsTimeInput,e=>{this.ufoElement.sighting.event.time=e})}updateObservationEndTime(){this.applyEdtfTimeInput(this.obsEndTimeInput,e=>{this.ufoElement.sighting.event.endTime=e})}updateWitnessMetadata(){const e=this.ufoElement.sighting,t=this.witnessFirstNamesInput.value.split(",").map(i=>i.trim()).filter(i=>i.length>0),n={id:this.stringOrUndefined(this.witnessIdInput.value),dirName:this.stringOrUndefined(this.witnessDirNameInput.value),title:this.stringOrUndefined(this.witnessTitleInput.value),lastName:this.stringOrUndefined(this.witnessLastNameInput.value),firstNames:t.length>0?t:void 0};e.witness=Object.values(n).some(i=>i!==void 0)?n:void 0,e.caseId=this.stringOrUndefined(this.caseIdInput.value),this.updateTestimony(),this.ufoElement.refresh()}updateTestimony(){const e=this.ufoElement.sighting,t=this.testimonyFollowedUpSelect.value,n={witnessAgeYears:this.numberOrUndefined(this.witnessAgeInput.value),witnessOccupation:this.witnessOccupationInput.value.trim()===""?void 0:this.said.write(e.testimony?.witnessOccupation,this.witnessOccupationInput.value,this.writingLanguage),source:this.stringOrUndefined(this.testimonySourceSelect.value),followedUp:t===""?void 0:t==="yes"};e.testimony=Object.values(n).some(i=>i!==void 0)?n:void 0}updateDescription(){this.ufoElement.sighting.event.description=this.said.write(this.ufoElement.sighting.event.description,this.descriptionInput.value,this.writingLanguage),this.ufoElement.refresh()}updateTags(){const e=this.tagsInput.value.split(",").map(t=>t.trim()).filter(t=>t.length>0).map(t=>this.tagNames.stored(t));this.ufoElement.sighting.event.tags=e.length>0?e:void 0,this.ufoElement.refresh()}applyWeatherAtPlayhead(){if(this.ufoElement.playbackState==="playing")return;this.sceneElement.resumeWeatherAudio(),this.weatherFromRecords&&(this.weatherFromRecords=!1,this.cancelWeatherLookup(),this.ufoElement.sighting.weatherSource=void 0,this.syncWeatherSourceState());const e={...Ht(this.ufoElement.sighting,this.ufoElement.currentTime),cloudCover:Number(this.cloudCoverInput.value),highCloudCover:Number(this.highCloudCoverInput.value),lowerCloudCover:Number(this.cloudCoverInput.value),cloudDarkness:Number(this.cloudDarknessInput.value),cloudBaseM:this.numberOrUndefined(this.cloudBaseInput.value),precipitationType:this.precipitationTypeSelect.value,precipitationIntensity:Number(this.precipitationIntensityInput.value),windDirectionDeg:this.wrapDegrees(this.numberOrUndefined(this.windDirectionInput.value),this.windDirectionInput)??0,windSpeed:Number(this.windSpeedInput.value),storm:this.stormInput.checked};this.ufoElement.sighting.weatherTrack.addKeyframe(this.ufoElement.currentTime,e),this.ufoElement.refresh()}applyIceAlignmentAtPlayhead(){if(this.ufoElement.playbackState==="playing")return;this.sceneElement.resumeWeatherAudio();const e={...Ht(this.ufoElement.sighting,this.ufoElement.currentTime),iceCrystalAlignment:Number(this.iceCrystalAlignmentInput.value)};this.ufoElement.sighting.weatherTrack.addKeyframe(this.ufoElement.currentTime,e),this.ufoElement.refresh()}buildSoundKindOptions(){for(const e of Rv){const t=document.createElement("option");t.value=e,t.textContent=this.soundKindLabel(e,this.messages),this.soundKindOptions.set(e,t),this.soundKindSelect.appendChild(t)}}soundKindLabel(e,t){switch(e){case"hum":return t.soundHum;case"whistle":return t.soundWhistle;case"rumble":return t.soundRumble;case"crackle":return t.soundCrackle;default:return t.soundNone}}applySoundAtPlayhead(){if(this.ufoElement.playbackState==="playing")return;const e=this.readSound();this.ufoElement.sighting.soundTrack.addKeyframe(this.ufoElement.currentTime,e),this.updateSoundPitchReadout(e.pitchHz),this.updateSoundFieldsDisabledState(e),this.ufoElement.refresh(),this.previewSound(e)}previewSound(e){clearTimeout(this.soundPreviewTimer),this.ufoElement.previewSound(e),this.soundPreviewTimer=setTimeout(()=>this.ufoElement.stopSoundPreview(),oA)}readSound(){return{kind:this.soundKindSelect.value,volume:Number(this.soundVolumeInput.value),pitchHz:Number(this.soundPitchInput.value),src:this.soundSrcInput.value.trim()||void 0}}syncSoundFromTimeline(){if(this.ufoElement.playbackState==="playing")return;const e=uu(this.ufoElement.sighting,this.ufoElement.currentTime),t=this.shadow.activeElement;t!==this.soundKindSelect&&(this.soundKindSelect.value=e.kind),t!==this.soundVolumeInput&&(this.soundVolumeInput.value=String(e.volume)),t!==this.soundPitchInput&&(this.soundPitchInput.value=String(e.pitchHz)),t!==this.soundSrcInput&&(this.soundSrcInput.value=e.src??""),this.updateSoundPitchReadout(e.pitchHz),this.updateSoundFieldsDisabledState(e)}updateSoundPitchReadout(e){this.soundPitchValue.textContent=`${Math.round(e)} Hz`}updateSoundFieldsDisabledState(e){const t=e.kind==="none"&&!e.src;this.soundVolumeInput.disabled=t,this.soundSrcInput.disabled=t,this.soundPitchInput.disabled=t||e.src!==void 0}set weatherProvider(e){this.weatherInference=new Th(e),this.scheduleWeatherLookup()}onWeatherInferredToggled(){this.weatherFromRecords=this.weatherInferredInput.checked,this.weatherFromRecords?this.scheduleWeatherLookup():(this.cancelWeatherLookup(),this.ufoElement.sighting.weatherSource=void 0,this.syncWeatherSourceState())}scheduleWeatherLookup(){this.weatherFromRecords&&(clearTimeout(this.weatherLookupTimer),this.weatherLookupTimer=setTimeout(()=>void this.inferWeather(),lA))}cancelWeatherLookup(){clearTimeout(this.weatherLookupTimer),this.weatherLookupToken++,this.weatherLookupPending=!1}async inferWeather(){if(!this.weatherFromRecords)return;const e=++this.weatherLookupToken;this.weatherLookupPending=!0,this.syncWeatherSourceState();const t=await this.weatherInference.infer(this.ufoElement.sighting);e!==this.weatherLookupToken||!this.weatherFromRecords||(this.weatherLookupPending=!1,this.weatherLookupResult=t,t.status==="inferred"?(this.weatherInference.applyTo(this.ufoElement.sighting,t),this.weatherTrackSpan=this.ufoElement.seekableDuration,this.ufoElement.refresh(),this.syncWeatherFromTimeline()):this.ufoElement.sighting.weatherSource=void 0,this.syncWeatherSourceState())}ensureWeatherTrackSpan(){if(!this.weatherFromRecords||this.ufoElement.sighting.weatherSource===void 0)return;const e=this.ufoElement.seekableDuration;this.weatherTrackSpan===void 0||e===this.weatherTrackSpan||(this.weatherTrackSpan=e,this.scheduleWeatherLookup())}syncWeatherSourceState(){const e=this.ufoElement.sighting.weatherSource,t=this.weatherFromRecords;for(const o of this.weatherFields)o.disabled=t&&e!==void 0&&o!==this.iceCrystalAlignmentInput||this.ufoElement.playbackState==="playing",this.ufoElement.playbackState==="playing"?o.title=this.messages.weatherWhilePlaying:o.title===this.messages.weatherWhilePlaying&&(o.title="");const n=this.weatherInference.canInfer(this.ufoElement.sighting);this.weatherInferredInput.disabled=!n,this.weatherInferredInput.checked=n&&this.weatherFromRecords;const i=n?this.messages.weatherInferredTitle:this.messages.weatherNeedsDateAndPlace;this.weatherInferredInput.title=i,this.labelWeatherInferred.title=i;const s=t&&e!==void 0;if(this.weatherSourceLink.hidden=!s,s){this.weatherSourceRow.hidden=!1,this.weatherSourceText.textContent="",this.weatherSourceLink.href=e.url,this.weatherSourceLink.textContent=this.observationInstantLabel();return}const r=t?this.weatherStatusMessage():"";this.weatherSourceText.textContent=r===""?"":`${r} `,this.weatherSourceRow.hidden=r===""}weatherStatusMessage(){if(this.weatherLookupPending)return this.messages.weatherLookingUp;switch(this.weatherLookupResult?.status){case"unavailable":return this.messages.weatherNoRecord;case"failed":return this.messages.weatherLookupFailed;default:return""}}observationInstantLabel(){const e=this.ufoElement.sighting.event,t=e.time&&Ka(e.time,e.place?.[0]?.lng??0,e.utcOffsetHours);return t?`, ${t.toISOString().slice(0,16).replace("T"," ")} UTC`:""}syncWeatherOwnership(){const e=this.ufoElement.sighting;this.cancelWeatherLookup(),this.weatherLookupResult=void 0,this.weatherFromRecords=e.weatherSource!==void 0||e.weatherTrack.allKeyframes.length===0,this.syncWeatherSourceState(),this.weatherFromRecords&&e.weatherSource===void 0&&this.scheduleWeatherLookup()}syncDurationField(){if(this.shadow.activeElement!==this.durationInput){const e=ja(this.ufoElement.sighting.event);this.durationInput.value=e!==void 0?String(e/1e3):""}this.updateDurationValidity()}updateDurationValidity(){const e=this.durationInput.value==="";this.durationInput.classList.toggle("missing-required",e),this.markUnansweredQuestions(),this.durationInput.setAttribute("aria-invalid",String(e));const t=Fv(this.ufoElement.sighting.event);this.durationInput.title=t==="imprecise"?this.messages.durationImprecise:""}syncPlaybackControls(){this.ensureWeatherTrackSpan();const e=this.ufoElement.playbackState==="playing",t=this.ufoElement.seekableDuration>0;this.playPauseButton.textContent=e?"⏸":"▶",this.playPauseButton.disabled=!t;const n=t?e?this.messages.pause:this.messages.play:this.messages.noDuration;this.playPauseButton.title=n,this.playPauseButton.setAttribute("aria-label",n),this.loopButton.setAttribute("aria-pressed",String(this.ufoElement.autoReplayEnabled)),this.seekInput.max=String(this.ufoElement.seekableDuration),this.shadow.activeElement!==this.seekInput&&(this.seekInput.value=String(this.ufoElement.currentTime)),this.timeStartLabel.textContent=this.ufoElement.positionLabel,this.timeEndLabel.textContent=this.ufoElement.durationLabel,this.syncTimeDisplaySwitch()}switchTimeDisplay(){this.ufoElement.toggleTimeDisplay(),this.timeStartLabel.textContent=this.ufoElement.positionLabel,this.timeEndLabel.textContent=this.ufoElement.durationLabel,this.syncTimeDisplaySwitch()}syncTimeDisplaySwitch(){const e=this.ufoElement.canSwitchTimeDisplay,t=this.ufoElement.showingClockTime?this.messages.switchToElapsed:this.messages.switchToClockTime;for(const[n,i]of[[this.timeStartLabel,this.messages.currentPosition],[this.timeEndLabel,this.messages.duration]])n.title=e?`${i} — ${t}`:i,n.classList.toggle("switchable",e),e?(n.setAttribute("role","button"),n.setAttribute("tabindex","0")):(n.removeAttribute("role"),n.removeAttribute("tabindex"))}static TIME_QUALIFIERS=[{value:"",key:"timeQualifierExact"},{value:"~",key:"timeQualifierApproximate"},{value:"?",key:"timeQualifierUncertain"},{value:"%",key:"timeQualifierBoth"}];refreshTimeQualifierOptions(){for(const e of[this.obsTimeQualifier,this.obsEndTimeQualifier]){const t=e.value;e.replaceChildren(...Mt.TIME_QUALIFIERS.map(n=>{const i=document.createElement("option");return i.value=n.value,i.textContent=this.messages[n.key],i})),e.value=t}}qualifierOf(e){const t=e.trim().slice(-1);return"?~%".includes(t)?t:""}isPickable(e){return e?e.year!==void 0&&e.month!==void 0&&e.day!==void 0&&e.hour!==void 0&&e.minute!==void 0&&(e.second===void 0||e.second===0):!1}pickerValueOf(e){if(!this.isPickable(e))return"";const t=(n,i=2)=>String(n).padStart(i,"0");return`${t(e.year,4)}-${t(e.month)}-${t(e.day)}T${t(e.hour)}:${t(e.minute)}`}writeFromPicker(e,t,n,i){e.value===""&&e.validity.badInput||(n.value=e.value===""?"":`${e.value}${t.value}`,i())}chooseTimeInputMode(){const e=this.ufoElement.sighting.event,t=n=>n===void 0||this.isPickable(n);this.setEdtfMode(!(t(e.time)&&t(e.endTime)))}setEdtfMode(e){this.edtfMode=e,this.edtfModeButton.setAttribute("aria-pressed",String(e));for(const[t,n,i]of[[this.obsTimeInput,this.obsTimeNativeInput,this.obsTimeQualifier],[this.obsEndTimeInput,this.obsEndTimeNativeInput,this.obsEndTimeQualifier]])t.hidden=!e,n.hidden=e,i.hidden=e}syncObservationTimeFields(){const e=this.ufoElement.sighting.event.time;this.obsTimeInput.value=e?Dl(e):"",this.obsTimeNativeInput.value=this.pickerValueOf(e),this.obsTimeQualifier.value=this.qualifierOf(this.obsTimeInput.value),this.obsTimeInput.setCustomValidity(""),this.obsTimeInput.classList.remove("invalid")}syncObservationEndTimeFields(){const e=this.ufoElement.sighting.event.endTime;this.obsEndTimeInput.value=e?Dl(e):"",this.obsEndTimeNativeInput.value=this.pickerValueOf(e),this.obsEndTimeQualifier.value=this.qualifierOf(this.obsEndTimeInput.value),this.obsEndTimeInput.setCustomValidity(""),this.obsEndTimeInput.classList.remove("invalid")}syncUtcOffsetField(){const e=this.ufoElement.sighting.event.utcOffsetHours;this.utcOffsetInput.value=e===void 0?"":String(e),this.updateUtcOffsetValidity()}updateUtcOffsetValidity(){const e=this.ufoElement.sighting.event.utcOffsetHours,t=this.ufoElement.sighting.event.place?.[0]?.lng,n=t===void 0?void 0:Math.round(t/15),i=e!==void 0&&n!==void 0&&Math.abs(e-n)>dA;this.utcOffsetInput.classList.toggle("invalid",i),this.utcOffsetInput.title=i?this.messages.utcOffsetImplausible.replace("{solar}",n>=0?`+${n}`:String(n)):""}scheduleGroundElevation(){const e=this.numberOrUndefined(this.latInput.value),t=this.numberOrUndefined(this.lngInput.value);e===void 0||t===void 0||this.groundElevationFor&&this.isSamePlace(this.groundElevationFor,e,t)||(clearTimeout(this.groundElevationTimer),this.groundElevationTimer=setTimeout(()=>void this.applyGroundElevation(e,t),cA))}isSamePlace(e,t,n){return Math.abs(e.lat-t)<Ca&&Math.abs(e.lng-n)<Ca}async applyGroundElevation(e,t){const n=++this.groundElevationToken,i=Ia(Ch,this.chosenSourceId.get("elevation")),s=await new qu(i.create()).at(e,t);if(n!==this.groundElevationToken||s===void 0)return;this.groundElevationFor={lat:e,lng:t};const r=Math.max(0,(this.numberOrUndefined(this.elevationInput.value)??0)-(this.groundElevationM??0));this.groundElevationM=Math.round(s),this.syncElevationField(r),this.updateObserver()}syncElevationField(e){const t=this.groundElevationM;this.elevationInput.value=String(Math.round((t??0)+e)),this.elevationInput.min=t===void 0?"":String(t),this.elevationInput.title=t===void 0?"":this.messages.altitudeAboveSeaLevel,this.groundElevationOutput.textContent=t===void 0?"":this.messages.groundAt.replace("{m}",String(t))}syncGroundElevationField(){this.groundElevationToken++,clearTimeout(this.groundElevationTimer),this.groundElevationM=void 0,this.groundElevationFor=void 0,this.syncElevationField(at(this.ufoElement.sighting,0)?.elevationM??0),this.scheduleGroundElevation()}syncPlaceNameField(){const e=this.ufoElement.sighting.event.place?.[0],t=e?.name??"";this.placeNameInput.value=t,this.placeNameInput.title=t,this.namedCoordinates=e&&t?{lat:e.lat,lng:e.lng}:void 0,this.placeMatches=[],this.placeMatchRow.hidden=!0,this.placeStatusText.textContent=""}syncWitnessMetadataFields(){const e=this.ufoElement.sighting;this.witnessIdInput.value=e.witness?.id??"",this.witnessDirNameInput.value=e.witness?.dirName??"",this.witnessTitleInput.value=e.witness?.title??"",this.witnessLastNameInput.value=e.witness?.lastName??"",this.witnessFirstNamesInput.value=e.witness?.firstNames?.join(", ")??"",this.caseIdInput.value=e.caseId??"",this.witnessAgeInput.value=e.testimony?.witnessAgeYears?.toString()??"",this.witnessOccupationInput.value=this.said.read(e.testimony?.witnessOccupation)??"",this.testimonySourceSelect.value=e.testimony?.source??"",this.testimonyFollowedUpSelect.value=e.testimony?.followedUp===void 0?"":e.testimony.followedUp?"yes":"no",this.descriptionInput.value=this.said.read(e.event.description)??"",this.showTags(),this.instrumentSelect.value=e.instrument.id}syncWeatherFromTimeline(){if(this.cloudEditor?.sync(),this.ufoElement.playbackState==="playing")return;const e=Ht(this.ufoElement.sighting,this.ufoElement.currentTime),t=this.shadow.activeElement;t!==this.cloudCoverInput&&(this.cloudCoverInput.value=String(e.cloudCover)),t!==this.highCloudCoverInput&&(this.highCloudCoverInput.value=String(e.highCloudCover??0)),t!==this.iceCrystalAlignmentInput&&(this.iceCrystalAlignmentInput.value=String(e.iceCrystalAlignment??.65)),t!==this.cloudDarknessInput&&(this.cloudDarknessInput.value=String(e.cloudDarkness)),t!==this.cloudBaseInput&&(this.cloudBaseInput.value=e.cloudBaseM===void 0?"":String(e.cloudBaseM)),t!==this.precipitationTypeSelect&&(this.precipitationTypeSelect.value=e.precipitationType),t!==this.precipitationIntensityInput&&(this.precipitationIntensityInput.value=String(e.precipitationIntensity)),t!==this.windDirectionInput&&(this.windDirectionInput.value=String(e.windDirectionDeg)),t!==this.windSpeedInput&&(this.windSpeedInput.value=String(e.windSpeed)),t!==this.stormInput&&(this.stormInput.checked=e.storm)}syncObserverFromTimeline(){if(this.ufoElement.playbackState==="playing")return;const e=this.ufoElement.sighting,t=e.witnessTrack.getInterpolatedPoseAt(this.ufoElement.currentTime),n=e.event.place?.[0],i=this.shadow.activeElement;i!==this.latInput&&(this.latInput.value=t?.lat!==void 0?String(t.lat):n?String(n.lat):""),i!==this.lngInput&&(this.lngInput.value=t?.lng!==void 0?String(t.lng):n?String(n.lng):""),i!==this.headingInput&&(this.headingInput.value=t?.headingDeg!==void 0?String(this.rounded(t.headingDeg)):""),i!==this.pitchInput&&(this.pitchInput.value=String(this.rounded(t?.pitchDeg??0)),this.rollInput.value=String(this.rounded(t?.rollDeg??0))),i!==this.elevationInput&&this.syncElevationField(t?.elevationM??0)}get appearance(){return{...this.currentAppearance}}set appearance(e){this.setAppearance(e)}setAppearance(e){const t="presetId"in e;this.currentAppearance={...this.currentAppearance,...e},this.updatePresetButtons(),!(this.isRecording||this.ufoElement.playbackState==="playing")&&this.applyAppearanceAtPlayhead(void 0,t)}applyAppearanceAtPlayhead(e,t=!0){const n=this.ufoElement.sighting.timeline,i=this.ufoElement.currentTime,s=n.getInterpolatedShapeAt(i,this.currentSourceId),r=this.buildAppearanceShape(e??s?.bounds??this.defaultBounds(),s,t);this.commitShapes(i,[{sourceId:this.currentSourceId,shape:r}]),this.ufoElement.refresh()}buildAppearanceShape(e,t,n=!0){if(t&&!n)return{...t,color:this.currentAppearance.color,transparency:this.currentAppearance.transparency,haloScale:this.currentAppearance.haloScale,blur:this.currentAppearance.blur,brightness:this.currentAppearance.brightness};const i=nf(e,this.currentAppearance);return t?{...i,angle:t.angle,title:t.title,selected:t.selected}:i}toggleSkyDetails(){const e=this.skyDetailsButton.getAttribute("aria-expanded")!=="true";this.skyDetailsButton.setAttribute("aria-expanded",String(e)),this.skyDetailsButton.textContent=e?"▴":"▾",this.skyDetailsButton.title=e?this.messages.skyDetailsHide:this.messages.skyDetails,this.skyDetailsButton.setAttribute("aria-label",this.skyDetailsButton.title);for(const t of this.clampedLines)t.classList.toggle("clamped",!e)}isGroupOpen(e){return e.getAttribute("aria-expanded")==="true"}toggleGroup(e,t){this.cloudEditor?.stopManipulation();for(const[n,i]of this.groupTabs.entries()){const s=i===e&&t;i.setAttribute("aria-expanded",String(s)),this.groupPanels[n].hidden=!s}}static SUMMARY_GROUPS=["observation","witness","location","decor","temporal","weather","sound"];static PANEL_ORDER=["observation","witness","location","decor","temporal","weather","sound","shape"];refreshParamSummary(){const t=this.paramSummaryBuilder.entriesFor(this.ufoElement.sighting,this.ufoElement.currentTime,{decorId:this.currentDecorId,decorPicker:!0,groundElevationM:this.groundElevationM??0}).map(i=>({...i,panel:Mt.SUMMARY_GROUPS.indexOf(i.group)})),n=t.map(i=>`${i.field}=${i.label}=${i.value}${i.unit}${i.fromSource?"*":""}`).join("|");n!==this.paramSummarySignature&&(this.paramSummarySignature=n,this.paramChips=t,this.renderParamSummary(),this.runAssessments())}paramChips=[];renderParamSummary(){const e=Mt.NESTED_GROUPS,t=[];let n;for(const i of[...this.paramChips,...this.assessmentChips]){if(n&&n.group!==i.group&&(n=void 0),e.includes(i.group)&&!n){const r=document.createElement("span");r.className="param-nest",r.dataset.group=i.group;const o=document.createElement("span");o.className="param-nest-label",o.textContent=i.group==="assessment"?this.messages.assessmentGroup:Mt.tabLabel(this.groupTabs[Mt.SUMMARY_GROUPS.indexOf(i.group)]),r.append(o),n={group:i.group,element:r},t.push(r)}const s=this.paramChip(i);n?n.element.append(s):t.push(s)}this.paramSummary.replaceChildren(...t)}static NESTED_GROUPS=["witness","decor","assessment"];static QUESTION_FIELDS={when:{panel:"temporal",fields:["obs-time","obs-time-native"]},where:{panel:"location",fields:["lat","lng"]},facing:{panel:"location",fields:["heading"]},"apparent-size":{panel:"shape",fields:[]},"sky-position":{panel:"shape",fields:[]},"how-long":{panel:"temporal",fields:["durationSeconds","obs-end-time","obs-end-time-native"]},appearance:{panel:"shape",fields:["shapeTitle","color"]},movement:{panel:"shape",fields:[]},sound:{panel:"sound",fields:["soundKind"]},conditions:{panel:"weather",fields:["cloudCover"]}};assessmentChips=[];assessmentToken=0;async runAssessments(){const e=++this.assessmentToken,t=await new Zv(this.messages).read(this.ufoElement.sighting);e===this.assessmentToken&&(this.assessmentChips=t.entries.map(n=>({...n,panel:Mt.PANEL_ORDER.indexOf(n.about??"")})),this.markUnansweredQuestions(t.unanswered),this.renderParamSummary())}static tabLabel(e){return(e.querySelector("span:not(.tab-badge)")??e).textContent.trim()}static badgeOn(e){const t=e.querySelector(".tab-badge");if(t)return t;const n=document.createElement("span");return n.className="tab-badge",n.hidden=!0,e.append(n),n}unansweredQuestions=new Set;markUnansweredQuestions(e=this.unansweredQuestions){this.unansweredQuestions=e;const t=new Set;for(const s of e){const r=Mt.QUESTION_FIELDS[s];if(r&&!r.fields.some(o=>this.shadow.getElementById(o)?.classList.contains("missing-required")))for(const o of r.fields){const l=this.shadow.getElementById(o);l&&!l.hidden&&l.value===""&&t.add(o)}}for(const[s,r]of Object.entries(Mt.QUESTION_FIELDS))for(const o of Mt.QUESTION_FIELDS[s].fields){const l=this.shadow.getElementById(o);if(!l)continue;const c=t.has(o)&&!l.classList.contains("missing-required");l.classList.toggle("wanted",c),(c||l.title===this.messages.questionUnanswered)&&(l.title=c?this.messages.questionUnanswered:"")}const n=new Map;let i;for(const[s,r]of Object.entries(Mt.QUESTION_FIELDS))for(const o of r.fields){const l=this.shadow.getElementById(o);if(!l)continue;const c=l.classList.contains("missing-required");!c&&!l.classList.contains("wanted")||(c&&(i=r.panel),n.set(r.panel,(n.get(r.panel)??0)+1))}for(const[s,r]of this.groupTabs.entries()){const o=Mt.PANEL_ORDER[s],l=n.get(o)??0,c=o===i,h=Mt.badgeOn(r);h.hidden=l===0,h.textContent=String(l),h.classList.toggle("optional",!c),r.title=l===0?"":c?this.messages.durationRequired:this.messages.questionsUnanswered.replace("{count}",String(l))}}paramChip(e){const t=document.createElement("button");t.type="button",t.className=e.fromSource?"param-chip from-source":"param-chip",t.dataset.panel=String(e.panel),t.dataset.field=e.field;const n=document.createElement("span");if(n.className="param-chip-label",n.textContent=`${e.label} `,t.append(n),e.color!==void 0){const s=document.createElement("span");s.className="param-chip-swatch",s.style.background=e.color,t.append(s)}const i=document.createElement("span");return i.className="param-chip-value",i.textContent=e.unit===""?e.value:`${e.value} ${e.unit}`,t.append(i),t}onParamSummaryClick(e){const t=e.target.closest(".param-chip");if(t==null)return;const n=Number(t.dataset.panel);if(n<0)return;const i=this.groupPanels[n];this.toggleGroup(this.groupTabs[n],!0);const s=t.dataset.field;if(s.startsWith("decor:")){this.currentDecorId=s.slice(6),this.refreshDecorList(),this.decorSelect.focus();return}const r=this.shadow.getElementById(s);r===null||!i.contains(r)||(r.focus(),r instanceof HTMLInputElement&&r.type!=="checkbox"&&r.type!=="color"&&r.type!=="range"&&r.select(),r.scrollIntoView?.({block:"center"}))}onSelectionOrTimeChanged(){this.syncAppearanceFromTimeline(),this.syncObserverFromTimeline(),this.syncWeatherFromTimeline(),this.syncWeatherSourceState(),this.syncSoundFromTimeline(),this.syncDecorLitFromTimeline(),this.syncDecorPlacementFromTimeline(),this.syncIndoorLookReset(),this.updateAppearanceFieldsDisabledState(),this.updateShapeTitleValidity(),this.refreshRealSize(),this.refreshBlurDistanceBound(),this.refreshSkyCandidates(),this.refreshInstrumentOptions(),this.syncOpticsFromInstrument(),this.ufoElement.selectedSourceIds=this.selectedSourceIds;const e=this.ufoElement.sighting.timeline.sourceIds,t=e.filter(n=>this.selectedSourceIds.has(n)).length;this.deleteShapeButton.disabled=this.isRecording||this.ufoElement.playbackState==="playing"||t===0||e.length-t<1,this.refreshParamSummary()}updateAppearanceFieldsDisabledState(){const e=this.selectedSourceIds.size>1,t=e?this.messages.multipleShapesSelected:"";for(const n of[this.shapeTitleInput,this.colorInput,this.transparencyInput,this.haloScaleInput,this.blurInput,this.brightnessInput,this.apparentWidthInput,this.realWidthInput,this.objectDistanceInput,this.sizeLockSelect,this.clearDistanceHypothesisButton,this.sourceSelect,...Object.values(this.presetButtons)])n.disabled=e,n.title=t}syncAppearanceFromTimeline(){if(this.ufoElement.playbackState==="playing"||this.selectedSourceIds.size>1)return;const e=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,this.currentSourceId);e&&(this.currentAppearance={presetId:gA(e),color:e.color,transparency:e.transparency,haloScale:e.haloScale,blur:e.blur??0,brightness:e.brightness??0},this.updatePresetButtons(),this.colorInput.value=this.currentAppearance.color,this.transparencyInput.value=String(this.currentAppearance.transparency),this.haloScaleInput.value=String(this.currentAppearance.haloScale),this.blurInput.value=String(this.currentAppearance.blur),this.brightnessInput.value=String(this.currentAppearance.brightness),this.shadow.activeElement!==this.shapeTitleInput&&(this.shapeTitleInput.value=this.said.read(e.title)??""),this.refreshApparentSize())}updateShapeTitle(){const e=this.ufoElement.sighting.timeline,t=this.ufoElement.currentTime,n=e.getInterpolatedShapeAt(t,this.currentSourceId);n&&(this.commitShapes(t,[{sourceId:this.currentSourceId,shape:{...n,title:this.said.write(n.title,this.shapeTitleInput.value,this.writingLanguage)}}]),this.ufoElement.refresh(),this.refreshSourceList(),this.updateShapeTitleValidity())}sizeLock="none";onApparentWidthInput(){const e=this.numberOrUndefined(this.apparentWidthInput.value);if(!(e===void 0||e<=0||this.selectedSourceIds.size!==1)){if(this.sizeLock==="real"){const t=this.numberOrUndefined(this.realWidthInput.value);t!==void 0&&t>0&&this.sceneElement.setDistanceHypothesis(this.currentSourceId,et.distanceMAt(t,e))}this.applyApparentWidth(e)}}onRealWidthInput(){const e=this.numberOrUndefined(this.realWidthInput.value);if(e===void 0||e<=0||this.selectedSourceIds.size!==1)return;if(this.sizeLock==="apparent"){const n=this.currentApparentWidthDeg();n!==void 0&&n>0&&(this.sceneElement.setDistanceHypothesis(this.currentSourceId,et.distanceMAt(e,n)),this.refreshDepth());return}const t=this.currentDistanceM();t!==void 0&&t>0&&this.applyApparentWidth(et.angularWidthDeg({sizeM:e,distanceM:t}))}onDistanceInput(){const e=this.numberOrUndefined(this.objectDistanceInput.value);e===void 0||e<=0||this.applyDistance(e)}applyDistance(e){if(this.selectedSourceIds.size===1){if(this.sizeLock!=="apparent"){const t=this.numberOrUndefined(this.realWidthInput.value);t!==void 0&&t>0&&this.applyApparentWidth(et.angularWidthDeg({sizeM:t,distanceM:e}))}this.sceneElement.setDistanceHypothesis(this.currentSourceId,e),this.refreshDepth()}}applySizeLock(){this.sizeLock=this.sizeLockSelect.value,this.apparentWidthInput.readOnly=this.sizeLock==="apparent",this.realWidthInput.readOnly=this.sizeLock==="real",this.objectDistanceInput.readOnly=this.sizeLock==="distance"}currentApparentWidthDeg(){const e=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,this.currentSourceId);if(e)return e.angular?.widthDeg??this.currentProjection().pxToDeg(e.bounds.width)}currentDistanceM(){return this.sceneElement.depthOf(this.currentSourceId)?.distanceM}applyApparentWidth(e){const t=this.ufoElement.sighting.timeline,n=this.ufoElement.currentTime,i=t.getInterpolatedShapeAt(n,this.currentSourceId);if(!i)return;const s=this.currentProjection(),r=s.degToPx(e),o=i.bounds.height*(i.bounds.width===0?1:r/i.bounds.width),l={x:i.bounds.x+(i.bounds.width-r)/2,y:i.bounds.y+(i.bounds.height-o)/2,width:r,height:o},c=s.ofBounds(l),h=i.kind==="oval"?{...i,bounds:l,angular:c}:{...i,bounds:l,angular:c,points:this.scalePoints(i,l)};this.commitShapes(n,[{sourceId:this.currentSourceId,shape:h}]),this.ufoElement.refresh(),this.refreshApparentSize()}scalePoints(e,t){const n=e.bounds.width===0?1:t.width/e.bounds.width,i=e.bounds.height===0?1:t.height/e.bounds.height;return e.points.map(s=>({x:s.x*n,y:s.y*i}))}refreshInstrumentOptions(){const e=this.ufoElement.sighting,t=e.event.time?.year,n=st.availableAt(t),i=e.instrument,s=n.includes(i)?n:[...n,i],r=this.instrumentSelect.value||i.id;this.instrumentSelect.replaceChildren();for(const o of s){const l=document.createElement("option");l.value=o.id;const c=o.name[this.showerLanguage()];l.textContent=n.includes(o)?c:this.messages.instrumentOutOfPeriod.replace("{name}",c),this.instrumentSelect.appendChild(l)}this.instrumentSelect.value=s.some(o=>o.id===r)?r:i.id}static exposureText(e){return e>=1?String(Math.round(e*100)/100):`1/${Math.round(1/e)}`}statedExposureSeconds(e){const t=Mt.exposureSeconds(this.exposureInput.value),n=e.exposureRangeSeconds;if(!n)return e.exposureSeconds??t;if(t!==void 0)return Math.min(n.max,Math.max(n.min,t))}static exposureSeconds(e){const t=e.trim();if(!t)return;const n=/^(\d*\.?\d+)\s*\/\s*(\d*\.?\d+)$/.exec(t);if(n){const s=Number(n[1]),r=Number(n[2]);return r>0?s/r:void 0}const i=Number(t);return Number.isFinite(i)&&i>0?i:void 0}syncOpticsFromInstrument(){const e=this.ufoElement.sighting,t=e.instrument,n=at(e,this.ufoElement.currentTime),i=t.frame,s=n?.fovDeg??st.fieldOfViewDeg(t),r=i?st.focalLengthMmFor(t,s):s;this.focalLengthInput!==this.shadow.activeElement&&(this.focalLengthInput.value=r===void 0?"":String(Math.round(r*10)/10)),this.unitFocalLength.textContent=i?this.messages.unitMillimetres:this.messages.unitDegrees,this.labelFocalLength.textContent=i?this.messages.focalLength:this.messages.fieldOfView,this.focalLengthInput.disabled=i!==void 0&&i.focalRangeMm===void 0,this.focalLengthInput.min=String(i?.focalRangeMm?.minMm??1),this.focalLengthInput.max=String(i?.focalRangeMm?.maxMm??2e3);const o=n?.fNumber??t.fNumber;this.fNumberInput!==this.shadow.activeElement&&(this.fNumberInput.value=o===void 0?"":String(o)),this.setRowVisible(this.fNumberInput,t.fNumber!==void 0),this.fNumberInput.disabled=t.fNumberRange===void 0,this.fNumberInput.min=String(t.fNumberRange?.min??.7),this.fNumberInput.max=String(t.fNumberRange?.max??64);const l=e.exposure;this.exposureInput!==this.shadow.activeElement&&(this.exposureInput.value=l===void 0?"":Mt.exposureText(l)),this.setRowVisible(this.exposureInput,t.exposureSeconds!==void 0),this.exposureInput.disabled=t.exposureRangeSeconds===void 0,this.focusDistanceInput!==this.shadow.activeElement&&(this.focusDistanceInput.value=n?.focusDistanceM===void 0?"":String(n.focusDistanceM)),this.setRowVisible(this.focusDistanceInput,i!==void 0&&t.fNumber!==void 0)}retuneFieldOfView(e){const t=this.ufoElement.sighting,n=st.fieldOfViewDeg(e),i=st.fieldOfViewDeg(t.instrument);for(const s of[...t.witnessTrack.allKeyframes])Math.abs(s.pose.fovDeg-n)>uA||t.witnessTrack.addKeyframe(s.t,{...s.pose,fovDeg:i})}retuneExposure(e){const t=this.ufoElement.sighting,n=t.exposureSeconds,i=t.instrument.exposureRangeSeconds;if(n===void 0||n===e.exposureSeconds||!i){t.exposureSeconds=void 0;return}t.exposureSeconds=Math.min(i.max,Math.max(i.min,n))}currentFovDeg(){const e=this.ufoElement.sighting;return at(e,this.ufoElement.currentTime)?.fovDeg??st.fieldOfViewDeg(e.instrument)}currentProjection(){return ni.of(this.ufoElement.sighting.instrument,this.ufoElement.canvasElement.height,this.currentFovDeg())}refreshApparentSize(){const e=this.selectedSourceIds.size===1?this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,this.currentSourceId):void 0;if(!e){this.apparentSizeOutput.textContent="",this.hasFocus(this.apparentWidthInput)||(this.apparentWidthInput.value=""),this.refreshRealSize();return}const t=e.angular?.widthDeg??this.currentProjection().pxToDeg(e.bounds.width),n=et.inMoons(t);this.hasFocus(this.apparentWidthInput)||(this.apparentWidthInput.value=this.plain(t,t<1?2:1)),this.apparentSizeOutput.textContent=this.messages.apparentSize.replace("{moons}",n.toLocaleString(void 0,{maximumFractionDigits:n<10?1:0})),this.refreshRealSize()}hasFocus(e){return this.typingIn===e}typingIn;typing(e,t){this.typingIn=e;try{t()}finally{this.typingIn=void 0}}plain(e,t){return String(Number(e.toFixed(t)))}refreshBlurDistanceBound(){const e=this.currentAppearance.blur;if(e<=0||this.selectedSourceIds.size!==1){this.blurBoundOutput.textContent="";return}const t=this.ufoElement.sighting.instrument,n=t.frame;if(!n){this.blurBoundOutput.textContent=this.messages.blurBoundNoInstrument;return}const i=at(this.ufoElement.sighting,this.ufoElement.currentTime),s=i?.focusDistanceM;if(s!==void 0){this.blurBoundOutput.textContent=this.messages.blurBoundNotAtInfinity.replace("{focus}",this.meters(s));return}const r=(i?st.focalLengthMmFor(t,i.fovDeg):void 0)??n.focalLengthMm,o=i?.fNumber??t.fNumber;if(o===void 0||r<=0){this.blurBoundOutput.textContent="";return}const l=this.ufoElement.canvasElement.height;if(l<=0)return;const c=2*Nh*e/l*n.heightMm,h=r*r/(o*c)/1e3;this.blurBoundOutput.textContent=this.messages.blurBound.replace("{max}",this.meters(h))}refreshRealSize(){if(this.refreshDepth(),this.selectedSourceIds.size!==1){this.realSizeOutput.textContent="";return}const e=this.currentSourceId;if(this.sceneElement.sizeContradictory(e)){this.realSizeOutput.textContent=this.messages.realSizeContradiction;return}const{minM:t,maxM:n}=this.sceneElement.sizeRangeOf(e);if(t===void 0&&n===void 0){this.realSizeOutput.textContent=this.messages.realSizeUnknown;return}const i=this.numberOrUndefined(this.realWidthInput.value),s=i!==void 0&&(t!==void 0&&i<t||n!==void 0&&i>n)?this.messages.realSizeOutside:"";if(t!==void 0&&n!==void 0){const r=this.sceneElement.distanceRangeAt(e,this.ufoElement.currentTime),o=r.minM===void 0||r.maxM===void 0?"":this.messages.realDistanceHere.replace("{min}",this.meters(r.minM)).replace("{max}",this.meters(r.maxM));this.realSizeOutput.textContent=this.messages.realSizeBetween.replace("{min}",this.meters(t)).replace("{max}",this.meters(n))+o+s;return}this.realSizeOutput.textContent=(t!==void 0?this.messages.realSizeAtLeast.replace("{min}",this.meters(t)):this.messages.realSizeAtMost.replace("{max}",this.meters(n)))+s}decimal(e,t){return e.toLocaleString(void 0,{minimumFractionDigits:t,maximumFractionDigits:t})}clearDistanceHypothesis(){this.selectedSourceIds.size===1&&(this.sceneElement.setDistanceHypothesis(this.currentSourceId,void 0),this.refreshDepth())}refreshDepth(){const e=this.selectedSourceIds.size===1?this.sceneElement.depthOf(this.currentSourceId):void 0;if(!e){this.depthBasisOutput.textContent="",this.hasFocus(this.objectDistanceInput)||(this.objectDistanceInput.value=""),this.hasFocus(this.realWidthInput)||(this.realWidthInput.value="");return}const t=this.meters(e.distanceM);this.hasFocus(this.objectDistanceInput)||(this.objectDistanceInput.value=this.plain(e.distanceM,e.distanceM<10?1:0));const n=this.currentApparentWidthDeg();if(!this.hasFocus(this.realWidthInput)){const s=n===void 0||n<=0?void 0:et.sizeMAt(e.distanceM,n);this.realWidthInput.value=s===void 0?"":this.plain(s,s<1?2:s<10?1:0)}this.clearDistanceHypothesisButton.hidden=e.basis!=="hypothesis";const i={stated:this.messages.depthStated,hypothesis:this.messages.depthHypothesis,derived:this.messages.depthDerived,bounded:this.messages.depthBounded,conventional:this.messages.depthConventional}[e.basis];this.depthBasisOutput.textContent=i.replace("{m}",t)}commitShapes(e,t){const n=this.ufoElement.sighting,i=ni.of(n.instrument,et.CANVAS_HEIGHT_PX,an.fovOf(n,e));n.timeline.addKeyframe(e,t.map(s=>{const r=an.aimOf(n,e,s.shape.bounds),o=i.ofBounds(s.shape.bounds);return{...s,shape:r?{...s.shape,aim:r,angular:o}:{...s.shape,angular:o}}}))}meters(e){const t=e<1?2:e<10?1:0;return e.toLocaleString(void 0,{maximumFractionDigits:t})}updateShapeTitleValidity(){const e=this.selectedSourceIds.size===1&&this.shapeTitleInput.value==="";this.shapeTitleInput.classList.toggle("invalid",e),this.shapeTitleInput.setAttribute("aria-invalid",String(e))}shapeLabel(e){const t=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,e),n=this.said.read(t?.title);if(n)return n;const i=/^ufo-(\d+)$/.exec(e);return i?`${this.messages.shape} ${i[1]}`:e}addShape(){if(this.isRecording)return;const e=this.ufoElement.sighting.timeline,t=new Set([...e.sourceIds,this.currentSourceId]);let n=t.size+1;for(;t.has(`ufo-${n}`);)n++;this.currentSourceId=`ufo-${n}`,this.selectedSourceIds=new Set([this.currentSourceId]),this.applyAppearanceAtPlayhead(this.offsetDefaultBounds(e.sourceIds.length)),this.shapeTitleInput.value=this.shapeLabel(this.currentSourceId),this.updateShapeTitle()}deleteShape(){if(this.isRecording||this.ufoElement.playbackState==="playing")return;const e=this.ufoElement.sighting.timeline,t=e.sourceIds.filter(i=>this.selectedSourceIds.has(i));if(t.length===0||e.sourceIds.length-t.length<1)return;const n=t.length===1?this.messages.confirmDeleteShape.replace("{name}",this.shapeLabel(t[0])):this.messages.confirmDeleteShapes.replace("{count}",String(t.length));this.askConfirm(n,()=>this.removeShapes(t))}removeShapes(e){const t=this.ufoElement.sighting.timeline;for(const n of e)t.removeSource(n);this.currentSourceId=t.sourceIds[0],this.selectedSourceIds=new Set([this.currentSourceId]),this.refreshSourceList(),this.ufoElement.refresh()}askConfirm(e,t){this.answerConfirm(!1),this.confirmMessage.textContent=e,this.confirmOverlay.hidden=!1,this.confirmAcceptButton.focus(),this.confirmAnswer=t}answerConfirm(e){const t=this.confirmAnswer;this.confirmAnswer=void 0,this.confirmOverlay.hidden=!0,e&&t?.()}offsetDefaultBounds(e){const t=this.defaultBounds(),n=24;return{...t,x:t.x+e*n,y:t.y+e*n}}refreshSourceList(){const e=this.ufoElement.sighting.timeline,t=[...new Set([...e.sourceIds,this.currentSourceId])];this.sourceSelect.innerHTML="";for(const n of t){const i=document.createElement("option");i.value=n,i.textContent=this.shapeLabel(n),this.sourceSelect.appendChild(i)}this.sourceSelect.value=this.currentSourceId}decorLabel(e){const t=this.said.read(e.title);if(t)return t;const i=this.ufoElement.sighting.decor.filter(r=>r.kind===e.kind).indexOf(e)+1;return`${this.decorKindSelect.querySelector(`option[value="${e.kind}"]`)?.textContent??e.kind} ${i}`}addDecor(e=this.decorKindSelect.value){const t=this.ufoElement.sighting,i={id:`decor-${t.decor.length+1}`,kind:e,title:this.nextDecorLabel(e),eastM:8*t.decor.length,northM:15,headingDeg:0,lit:!1,...e==="aircraft"?this.defaultAircraft():{},...e==="building"?{floors:Ba}:{},windows:_m(e)};t.decor=[...t.decor,i],this.currentDecorId=i.id,this.refreshDecorList(),this.ufoElement.refresh()}defaultAircraft(){const e=2*Rh,t=Math.round(e/pA*1e3);return{lights:uc.byId("airliner")?.create(),track:[{t:0,eastM:-Rh,northM:1e3,altitudeM:1500,headingDeg:90},{t,eastM:Rh,northM:1e3,altitudeM:1500,headingDeg:90}]}}nextDecorLabel(e){const t=this.ufoElement.sighting.decor.filter(i=>i.kind===e).length;return`${this.decorKindSelect.querySelector(`option[value="${e}"]`)?.textContent??e} ${t+1}`}deleteDecor(){if(this.currentDecorId===void 0)return;const e=this.ufoElement.sighting;e.decor=e.decor.filter(t=>t.id!==this.currentDecorId),this.currentDecorId=e.decor[0]?.id,this.refreshDecorList(),this.ufoElement.refresh()}selectDecor(e){this.currentDecorId=e,this.decorSelect.value=e,this.syncDecorFields()}updateDecor(){if(this.currentDecorId===void 0)return;const e=this.ufoElement.sighting,t=this.wrapDegrees(Number(this.decorHeadingInput.value),this.decorHeadingInput)??0,n=this.decorWitnessSideSelect.value;e.decor=e.decor.map(i=>{if(i.id!==this.currentDecorId)return i;const s=Na(i.kind)&&n!==""?n:void 0,r=Number(this.decorEastInput.value),o=Number(this.decorNorthInput.value),l=Number(this.decorAltitudeInput.value),c=i.track??(l!==0?[]:void 0);if(c){const h=this.ufoElement.currentTime,d={t:h,eastM:r,northM:o,altitudeM:l,headingDeg:t},u=c.filter(f=>f.t!==h);return{...i,title:this.said.write(i.title,this.decorTitleInput.value,this.writingLanguage),color:this.statedDecorColor(i),track:[...u,d].sort((f,p)=>f.t-p.t),sightingUrl:this.stringOrUndefined(this.decorSightingUrlInput.value),witnessSide:s,sizeM:this.statedDecorSize(),model:this.statedDecorModel(),floors:i.kind==="building"?Number(this.decorFloorsInput.value):void 0,occupiedFloor:i.kind==="building"?Number(this.decorOccupiedFloorInput.value):void 0}}return{...i,title:this.said.write(void 0,this.decorTitleInput.value,this.writingLanguage),color:this.statedDecorColor(i),eastM:r,northM:o,headingDeg:t,sightingUrl:this.stringOrUndefined(this.decorSightingUrlInput.value),witnessSide:s,sizeM:this.statedDecorSize(),model:this.statedDecorModel(),floors:i.kind==="building"?Number(this.decorFloorsInput.value):void 0,occupiedFloor:i.kind==="building"?Number(this.decorOccupiedFloorInput.value):void 0}}),this.decorSelect.options[this.decorSelect.selectedIndex].textContent=this.decorLabel(e.decor.find(i=>i.id===this.currentDecorId)),this.syncDecorVisibility(),this.updateDecorTitleValidity(),this.ufoElement.refresh()}syncDecorSizeFields(e){const t=e?tn.naturalSize(e.kind,e.floors):void 0,n=[[this.decorWidthInput,e?.sizeM?.widthM,t?.widthM],[this.decorLengthInput,e?.sizeM?.lengthM,t?.lengthM],[this.decorHeightInput,e?.sizeM?.heightM,t?.heightM]];for(const[i,s,r]of n)i.value=s===void 0?"":String(this.roundedMeters(s)),i.placeholder=r===void 0?"":String(this.roundedMeters(r))}syncDecorModelFields(e){this.refreshDecorModelOptions(e),this.decorModelSelect.value=e?.model?.id??"",this.decorModelUrlInput.value=e?.model?.url??"",this.decorModelTitleInput.value=e?.model?.credit?.title??"",this.decorModelAuthorInput.value=e?.model?.credit?.author??"",this.decorModelLicenseInput.value=e?.model?.credit?.license??"",this.decorModelSourceInput.value=e?.model?.credit?.sourceUrl??"",this.decorModelAdvanced.open=e?.model?.url!==void 0}async refreshDecorModelOptions(e){const t=e??this.ufoElement.sighting.decor.find(r=>r.id===this.currentDecorId),n=t?await this.decorModelProvider.entries(t.kind).catch(()=>[]):[],i=t?.model?.id??"",s=document.createElement("option");s.value="",s.textContent=this.messages.decorModelNone,this.decorModelSelect.replaceChildren(s,...n.map(r=>{const o=document.createElement("option");return o.value=r.id,o.textContent=r.name,o.title=`${r.credit.title}${r.credit.author?` — ${r.credit.author}`:""} (${r.credit.license})`,o})),this.decorModelSelect.value=i}updateDecorModelChoice(){const e=this.decorModelSelect.value;(async()=>{const t=e?await this.decorModelProvider.entry(e).catch(()=>{}):void 0,n=this.ufoElement.sighting.decor.find(i=>i.id===this.currentDecorId);if(t?.sizeM&&n&&!n.sizeM){const i=[[this.decorWidthInput,t.sizeM.widthM],[this.decorLengthInput,t.sizeM.lengthM],[this.decorHeightInput,t.sizeM.heightM]];for(const[s,r]of i)r!==void 0&&(s.value=String(this.roundedMeters(r)))}this.updateDecor()})()}roundedMeters(e){return Math.round(e*100)/100}positiveMeters(e){const t=Number(e);return e.trim()===""||!Number.isFinite(t)||t<=0?void 0:t}statedDecorColor(e){const t=this.decorColorInput.value;return t==="#808080"&&e.color===void 0?void 0:t}statedDecorSize(){const e=this.positiveMeters(this.decorWidthInput.value),t=this.positiveMeters(this.decorLengthInput.value),n=this.positiveMeters(this.decorHeightInput.value);return e===void 0&&t===void 0&&n===void 0?void 0:{widthM:e,lengthM:t,heightM:n}}statedDecorModel(){const e=this.stringOrUndefined(this.decorModelUrlInput.value);if(e){const n=this.stringOrUndefined(this.decorModelTitleInput.value),i=this.stringOrUndefined(this.decorModelLicenseInput.value);return{url:e,credit:n!==void 0&&i!==void 0?{title:n,license:i,author:this.stringOrUndefined(this.decorModelAuthorInput.value),sourceUrl:this.stringOrUndefined(this.decorModelSourceInput.value)}:void 0}}const t=this.stringOrUndefined(this.decorModelSelect.value);return t===void 0?void 0:{id:t}}addMilestone(){const e=Math.round(this.ufoElement.currentTime),t=this.ufoElement.sighting;t.milestones.find(i=>i.t===e)||(t.milestones=er([...t.milestones,{t:e,label:this.nextMilestoneLabel()}])),this.currentMilestoneT=e,this.refreshMilestoneList(),this.ufoElement.refresh()}nextMilestoneLabel(){const e=new Set(this.ufoElement.sighting.milestones.map(t=>t.label));for(let t=0;t<26;t++){const n=String.fromCharCode(65+t);if(!e.has(n))return n}return String(this.ufoElement.sighting.milestones.length+1)}deleteMilestone(){const e=this.currentMilestoneT;if(e===void 0)return;const t=this.ufoElement.sighting,n=t.milestones.find(i=>i.t===e);n&&this.askConfirm(this.messages.confirmDeleteMilestone.replace("{name}",this.said.read(n.label)??""),()=>{t.milestones=t.milestones.filter(i=>i.t!==e),this.currentMilestoneT=t.milestones[0]?.t,this.refreshMilestoneList(),this.ufoElement.refresh()})}selectMilestone(e){this.currentMilestoneT=e,this.syncMilestoneFields(),this.ufoElement.currentTime=e}updateMilestone(){const e=this.currentMilestoneT;if(e===void 0)return;const t=this.ufoElement.sighting;t.milestones=t.milestones.map(n=>n.t===e?{...n,label:this.said.write(n.label,this.milestoneLabelInput.value,this.writingLanguage)??"",note:this.said.write(n.note,this.milestoneNoteInput.value,this.writingLanguage)}:n),this.refreshMilestoneList(),this.ufoElement.refresh()}refreshMilestoneList(){const e=er(this.ufoElement.sighting.milestones);e.some(t=>t.t===this.currentMilestoneT)||(this.currentMilestoneT=e[0]?.t),this.milestoneSelect.replaceChildren(...e.map(t=>{const n=document.createElement("option");return n.value=String(t.t),n.textContent=`${this.said.read(t.label)??""} — ${this.formatSeconds(t.t)}`,n.title=this.said.read(t.note)??"",n})),this.currentMilestoneT!==void 0&&(this.milestoneSelect.value=String(this.currentMilestoneT)),this.syncMilestoneFields()}formatSeconds(e){return`${(e/1e3).toFixed(1)} s`}syncMilestoneFields(){const e=this.ufoElement.sighting.milestones.find(n=>n.t===this.currentMilestoneT),t=e!==void 0;for(const n of[this.milestoneSelect,this.milestoneLabelInput,this.milestoneNoteInput,this.deleteMilestoneButton])n.disabled=!t,this.setRowVisible(n,t);this.milestoneLabelInput.value=this.said.read(e?.label)??"",this.milestoneNoteInput.value=this.said.read(e?.note)??""}updateDecorTitleValidity(){const e=this.currentDecorId!==void 0&&this.decorTitleInput.value==="";this.decorTitleInput.classList.toggle("invalid",e),this.decorTitleInput.setAttribute("aria-invalid",String(e))}updateDecorWindows(){if(this.currentDecorId===void 0)return;const e=this.ufoElement.sighting;e.decor=e.decor.map(t=>{if(t.id!==this.currentDecorId)return t;const n={};for(const i of ia){const s=this.decorWindowInputs[i];if(s.value==="")continue;const r=Fh(t.kind,i)?0:kh,o=Math.max(r,Math.min(100,Number(s.value)));n[i]=o,String(o)!==s.value&&(s.value=String(o))}return{...t,windows:n}}),this.ufoElement.refresh()}updateDecorLit(){if(this.currentDecorId===void 0||this.ufoElement.playbackState==="playing")return;const e=this.ufoElement.sighting,t=this.ufoElement.currentTime,n=this.decorLitInput.checked;e.decor=e.decor.map(i=>{if(i.id!==this.currentDecorId)return i;const s=[...(i.litKeyframes??[]).filter(r=>r.t!==t),{t,lit:n}].sort((r,o)=>r.t-o.t);return{...i,litKeyframes:s}}),this.ufoElement.refresh()}refreshDecorList(){const e=this.ufoElement.sighting.decor;this.decorSelect.innerHTML="";for(const t of e){const n=document.createElement("option");n.value=t.id,n.textContent=this.decorLabel(t),this.decorSelect.appendChild(n)}this.currentDecorId!==void 0&&(this.decorSelect.value=this.currentDecorId),this.syncDecorFields()}syncDecorFields(){const e=this.ufoElement.sighting.decor.find(n=>n.id===this.currentDecorId),t=e!==void 0;this.deleteDecorButton.disabled=!t;for(const n of[this.decorSelect,this.decorTitleInput,this.decorEastInput,this.decorNorthInput,this.decorHeadingInput,this.decorLitInput,this.decorSightingUrlInput,this.decorWidthInput,this.decorLengthInput,this.decorHeightInput,this.decorModelSelect,this.decorModelUrlInput,this.decorModelTitleInput,this.decorModelAuthorInput,this.decorModelLicenseInput,this.decorModelSourceInput,this.decorFloorsInput,this.decorOccupiedFloorInput,this.decorWitnessSideSelect,this.decorLightRigSelect,this.decorAltitudeInput,this.lookAtDecorButton])n.disabled=!t;this.decorTitleInput.value=this.said.read(e?.title)??"",this.decorColorInput.value=e?.color??"#808080",this.showDecorPlacement(e),this.decorLitInput.checked=e?Rl(e,this.ufoElement.currentTime):!1,this.refreshDecorLightRigOptions(e),this.decorSightingUrlInput.value=e?.sightingUrl??"",this.syncDecorSizeFields(e),this.syncDecorModelFields(e),this.decorFloorsInput.value=String(e?.floors??Ba),this.decorOccupiedFloorInput.value=String(e?.occupiedFloor??0),this.decorWitnessSideSelect.value=e?.witnessSide??"";for(const n of ia){const i=e?.windows?.[n];this.decorWindowInputs[n].value=i===void 0?"":String(i)}this.syncDecorVisibility(),this.updateDecorTitleValidity()}setRowVisible(e,t){const n=e.closest("label")??e;n.hidden=!t}syncDecorVisibility(){const e=this.ufoElement.sighting.decor.find(c=>c.id===this.currentDecorId),t=e!==void 0,n=e?.kind;this.setRowVisible(this.decorSelect,t),this.setRowVisible(this.deleteDecorButton,t),this.setRowVisible(this.decorTitleInput,t),this.setRowVisible(this.decorEastInput,t),this.setRowVisible(this.decorNorthInput,t),this.setRowVisible(this.decorAltitudeInput,t),this.setRowVisible(this.decorHeadingInput,t),this.setRowVisible(this.decorWidthInput,t),this.setRowVisible(this.decorLengthInput,t),this.setRowVisible(this.decorHeightInput,t),this.setRowVisible(this.decorModelSelect,t),this.decorModelAdvanced.hidden=!t,this.setRowVisible(this.decorLitInput,t&&e?.kind!=="aircraft");const i=t&&n!==void 0&&mu(n);this.setRowVisible(this.labelDecorWindows,i);const s=n!==void 0?pu(n):[];for(const c of ia)this.decorWindowInputs[c].disabled=!t,this.decorWindowInputs[c].min=String(n!==void 0&&Fh(n,c)?0:kh),this.setRowVisible(this.decorWindowInputs[c],i&&s.includes(c));const r=t&&n!==void 0&&Na(n);this.setRowVisible(this.decorWitnessSideSelect,r);const o=n!==void 0?Jv(n):[];for(const c of ia)this.optionWitnessSide[c].hidden=!o.includes(c);const l=t&&n==="building";this.setRowVisible(this.decorFloorsInput,l),this.setRowVisible(this.decorOccupiedFloorInput,l),this.decorOccupiedFloorInput.max=String(e?.floors??Ba)}showDecorPlacement(e){const t=e?Qa(e,this.ufoElement.currentTime):void 0,n=[[this.decorEastInput,t?.eastM??0],[this.decorNorthInput,t?.northM??0],[this.decorAltitudeInput,t?.altitudeM??0],[this.decorHeadingInput,t?.headingDeg??0]];for(const[i,s]of n)this.shadow.activeElement!==i&&(i.value=String(this.rounded(s)))}syncDecorPlacementFromTimeline(){this.ufoElement.playbackState!=="playing"&&this.showDecorPlacement(this.ufoElement.sighting.decor.find(e=>e.id===this.currentDecorId))}showNextMeteor(){const e=this.sceneElement.meteorByRank(this.meteorRank++);e&&(this.ufoElement.playbackState==="playing"&&this.ufoElement.togglePlayPause(),this.ufoElement.currentTime=e.t,this.headingInput.value=String(Math.round(e.azimuthDeg*10)/10),this.pitchInput.value=String(Math.round(e.altitudeDeg*10)/10),this.updateObserver())}resetMeteorRankIfSkyChanged(){const e=this.sceneElement.meteorByRank(0),t=e?`${e.t}`:"";t!==this.meteorRankFor&&(this.meteorRankFor=t,this.meteorRank=0)}meteorRankFor;meteorRank=0;showerLanguage(){return za(vs.preferencesFor(this),["en","fr"])}get said(){return this.saidTexts??=new Gi(vs.preferencesFor(this))}saidTexts;tagNames=new Bh({});get writingLanguage(){return this.showerLanguage()}refreshSkyCandidates(){this.resetMeteorRankIfSkyChanged();const e=this.ufoElement.sighting,t=e.event.place?.[0],n=e.event.time,i=t&&t.lat!==void 0&&t.lng!==void 0&&n?.year!==void 0?Ka(n,t.lng,e.event.utcOffsetHours):void 0;if(!i||!t||t.lat===void 0||t.lng===void 0){this.showMeteorButton.hidden=!0,this.showCometButton.hidden=!0,this.skyCandidatesOutput.textContent=this.messages.skyLine.replace("{parts}",this.messages.skyUnknown);return}const s={lat:t.lat,lng:t.lng,elevationM:this.groundElevationM??0},r=[this.starsClause(i,s),this.showerClause(i,s),this.cometClause(i,s),this.satelliteClause(i,s),this.opticsClause(i,s),this.rainbowClause(i,s),this.glowClause(i,s)].filter(o=>o!==void 0);this.skyCandidatesOutput.textContent=this.messages.skyLine.replace("{parts}",r.join(" · "))}instrumentGain(){const e=this.ufoElement.sighting;return hn.gainFor(e.instrument,{fNumber:at(e,0)?.fNumber,fieldOfViewDeg:an.fovOf(e,0),exposureSeconds:e.exposure})}starsClause(e,t){const n=Un("Sun",e,t).altitudeDeg,i=this.instrumentGain(),s=Hr(n,i),r=c=>c.toLocaleString(void 0,{maximumFractionDigits:1});if(s<hA)return this.messages.skyStarsNone;const o=this.ufoElement.sighting.instrument,l=Math.abs(i)<.1?this.messages.skyStarsEye.replace("{limit}",r(s)):(i>0?this.messages.skyStarsDeeper:this.messages.skyStarsShallower).replace("{limit}",r(s)).replace("{device}",o.name[this.showerLanguage()]).replace("{gain}",r(Math.abs(i))).replace("{eye}",r(Hr(n)));return s<=Xr?l:l+this.messages.skyStarsCatalogue.replace("{catalogue}",r(Xr))}showerClause(e,t){const n=Et.observedRatePerHour(Et.apexPosition(e,t).altitudeDeg).toLocaleString(void 0,{maximumFractionDigits:1}),i=Za.activeAt(e);if(i.length===0)return this.showMeteorButton.hidden=!this.sceneElement.meteorByRank(0),this.messages.skyNothingActive.replace("{sporadic}",n);const s=i.map(r=>{const o=Za.radiantPosition(r.shower,e,t);return{entry:r,position:o,rate:Za.observedRatePerHour(r.zhr,o.altitudeDeg,r.shower.populationIndex)}}).sort((r,o)=>o.rate-r.rate)[0];return s.rate<=0?(this.showMeteorButton.hidden=!this.sceneElement.meteorByRank(0),this.messages.skyShowerBelowHorizon.replace("{name}",s.entry.shower.name[this.showerLanguage()])):(this.showMeteorButton.hidden=!this.sceneElement.meteorByRank(0),this.messages.skyShowerActive.replace("{name}",s.entry.shower.name[this.showerLanguage()]).replace("{altitude}",String(Math.round(s.position.altitudeDeg))).replace("{bearing}",qs.towards(s.position.azimuthDeg,this.showerLanguage())).replace("{rate}",s.rate.toLocaleString(void 0,{maximumFractionDigits:s.rate<10?1:0})).replace("{sporadic}",n))}cometClause(e,t){const n=Tl.brightestAt(e,t);if(!n||n.magnitude>io){this.showCometButton.hidden=!0;return}return this.showCometButton.hidden=n.position.altitudeDeg<=0,this.cometText(n)}satelliteClause(e,t){const n=vi.visibilityAt(e,t);if(!n.anythingInOrbit)return n.sunAltitudeDeg<0?this.messages.skySatellitesNotYet:void 0;const i=Hr(n.sunAltitudeDeg,this.instrumentGain()),s=n.classes.filter(h=>h.peakMagnitude<=i),r=this.listed(s.map(h=>h.name[this.showerLanguage()]));if(n.sunAltitudeDeg>=0)return s.length===0?void 0:(s.length===1?this.messages.skySatellitesDaylightOne:this.messages.skySatellitesDaylight).replace("{eras}",r);const o=Math.round(n.shadowHeightKm).toLocaleString(),l=(n.trackedObjects??0).toLocaleString(),c=h=>h.replace("{height}",o).replace("{count}",l);return n.lowOrbitLit?s.length===0?c(this.messages.skySatellitesLit):c(this.messages.skySatellitesLitWith).replace("{eras}",r):c(this.messages.skySatellitesShadowed)}opticsClause(e,t){const n=Ht(this.ufoElement.sighting,0),i=Un("Sun",e,t),s=Un("Moon",e,t),r=je.deckLitUntilDeg(je.DECK_HEIGHT_M),o=i.altitudeDeg>-r,l=o?i:s;if(l.altitudeDeg<=-r)return;const c=n.highCloudCover;if(c===void 0||c<=0)return this.messages.skyOpticsNoIce;if(je.strength(c,n.lowerCloudCover??n.cloudCover,l.altitudeDeg,r)<=0)return this.messages.skyOpticsHidden;const h=o?this.messages.skyOpticsSun:this.messages.skyOpticsMoon,d=this.listed(je.formsAt(l.altitudeDeg,r).map(f=>this.opticsFormName(f))),u=n.iceCrystalAlignment??.65;return this.messages.skyOpticsPossible.replace("{forms}",d).replace("{source}",h)+this.messages.skyOpticsAlignment.replace("{alignment}",String(Math.round(u*100)))}rainbowClause(e,t){const n=Ht(this.ufoElement.sighting,0);if(n.precipitationType!=="rain"||n.precipitationIntensity<=0)return;const i=Un("Sun",e,t),s=Un("Moon",e,t),r=i.altitudeDeg>0,o=r?i:s;if(o.altitudeDeg<=0)return this.messages.skyBowNoSource;const l=n.lowerCloudCover??n.cloudCover;if(sn.strength(n.precipitationIntensity,l,o.altitudeDeg)<=0)return this.messages.skyBowHidden;const c=sn.formsAt(o.altitudeDeg);if(c.length===0)return this.messages.skyBowSourceTooHigh.replace("{altitude}",String(Math.round(o.altitudeDeg))).replace("{radius}",String(Math.round(sn.primary().radiusDeg)));const h=this.listed(c.map(u=>this.bowFormName(u)));if(r)return this.messages.skyBowPossible.replace("{forms}",h);const d=Math.round(Kl(e).illuminatedFraction*100);return this.messages.skyBowMoon.replace("{forms}",h).replace("{lit}",String(d))}glowClause(e,t){if(Un("Sun",e,t).altitudeDeg>vA)return;const i=this.glows.assess(e,t),s=this.showerLanguage(),r=[];if(i.milkyWay&&r.push(this.messages.skyGlowBand.replace("{contrast}",this.decimal(i.milkyWay.contrast,1)).replace("{altitude}",String(Math.round(i.milkyWay.altitudeDeg))).replace("{bearing}",qs.towards(i.milkyWay.azimuthDeg,s))),i.zodiacal){const h=i.zodiacal.sunSeparationDeg<=nt.CONE_SEPARATION_DEG;r.push((h?this.messages.skyGlowCone:this.messages.skyGlowZodiacalBand).replace("{contrast}",this.decimal(i.zodiacal.contrast,1)).replace("{altitude}",String(Math.round(i.zodiacal.altitudeDeg))).replace("{bearing}",qs.towards(i.zodiacal.azimuthDeg,s)).replace("{elongation}",String(Math.round(i.zodiacal.sunSeparationDeg))))}if(r.length>0)return this.listed(r);const o=this.decimal(i.darkestSkyMagPerArcsec2,1),l=Un("Moon",e,t),c=i.darkestSkyMagPerArcsec2<yA;if(c&&l.altitudeDeg>0){const h=Math.round(Kl(e).illuminatedFraction*100);return this.messages.skyGlowMoon.replace("{lit}",String(h)).replace("{sky}",o)}return c?this.messages.skyGlowTwilight.replace("{sky}",o):this.messages.skyGlowNothingUp.replace("{sky}",o)}glows=new nt;bowFormName(e){return(e.id==="primary"?this.messages.skyBowPrimary:this.messages.skyBowSecondary).replace("{radius}",String(Math.round(e.radiusDeg))).replace("{top}",String(Math.round(e.topAltitudeDeg)))}opticsFormName(e){const t=n=>String(Math.round(n??0));switch(e.id){case"halo22":return this.messages.skyOpticsHalo22.replace("{angle}",t(e.angleDeg));case"halo46":return this.messages.skyOpticsHalo46.replace("{angle}",t(e.angleDeg));case"parhelia":return this.messages.skyOpticsParhelia.replace("{angle}",t(e.angleDeg));case"tangentArc":return this.messages.skyOpticsTangentArc;case"parhelicCircle":return this.messages.skyOpticsParhelicCircle;case"circumzenithal":return this.messages.skyOpticsCircumzenithal.replace("{angle}",t(e.angleDeg));case"circumhorizontal":return this.messages.skyOpticsCircumhorizontal;case"pillar":return this.messages.skyOpticsPillar}}listed(e){return new Intl.ListFormat(this.showerLanguage(),{style:"long",type:"conjunction"}).format(e)}cometText(e){const t=e.apparition.name[this.showerLanguage()],n=e.magnitude.toLocaleString(void 0,{maximumFractionDigits:1});return e.position.altitudeDeg<=0?this.messages.skyCometBelowHorizon.replace("{name}",t).replace("{magnitude}",n):(e.elongationDeg<Tl.TWILIGHT_ELONGATION_DEG?this.messages.skyCometInDaylight:e.tailLengthDeg===void 0?this.messages.skyCometNoTail:this.messages.skyComet).replace("{name}",t).replace("{magnitude}",n).replace("{altitude}",String(Math.round(e.position.altitudeDeg))).replace("{bearing}",qs.towards(e.position.azimuthDeg,this.showerLanguage())).replace("{tail}",String(Math.round(e.tailLengthDeg??0))).replace("{elongation}",String(Math.round(e.elongationDeg)))}lookAtComet(){const e=this.ufoElement.sighting,t=e.event.place?.[0],n=e.event.time;if(!t||t.lat===void 0||t.lng===void 0||n?.year===void 0)return;const i=Ka(n,t.lng,e.event.utcOffsetHours);if(!i)return;const s=Tl.brightestAt(i,{lat:t.lat,lng:t.lng,elevationM:this.groundElevationM??0});s&&(this.headingInput.value=String(this.rounded(s.position.azimuthDeg)),this.pitchInput.value=String(this.rounded(s.position.altitudeDeg)),this.updateObserver())}rounded(e){return Math.round(e*10)/10}lookAtDecor(){const e=this.ufoElement.sighting.decor.find(l=>l.id===this.currentDecorId);if(!e)return;const{eastM:t,northM:n,altitudeM:i}=Qa(e,this.ufoElement.currentTime),s=Math.hypot(t,n);if(s===0&&i===0)return;const r=Math.atan2(t,n)*180/Math.PI,o=Math.atan2(i-fA,s)*180/Math.PI;this.headingInput.value=String(Math.round(r*10)/10),this.pitchInput.value=String(Math.round(o*10)/10),this.updateObserver()}refreshDecorLightRigOptions(e){const t=e?uc.forKind(e.kind):[],n=document.createElement("option");n.value="",n.textContent=this.messages.decorLightsNone,this.decorLightRigSelect.replaceChildren(n,...t.map(s=>{const r=document.createElement("option");return r.value=s.id,r.textContent=s.name,r}));const i=e?.lights?.map(s=>s.id).join()??"";this.decorLightRigSelect.value=t.find(s=>s.create().map(r=>r.id).join()===i)?.id??""}updateDecorLightRig(){const e=this.ufoElement.sighting,t=e.decor.find(i=>i.id===this.currentDecorId);if(!t)return;const n=uc.byId(this.decorLightRigSelect.value);e.decor=e.decor.map(i=>i.id===t.id?{...i,lights:n?n.create():void 0}:i),this.ufoElement.refresh(),this.dispatchEvent(new CustomEvent("sightingchange"))}syncDecorLitFromTimeline(){if(this.ufoElement.playbackState==="playing"||this.shadow.activeElement===this.decorLitInput)return;const e=this.ufoElement.sighting.decor.find(t=>t.id===this.currentDecorId);e&&(this.decorLitInput.checked=Rl(e,this.ufoElement.currentTime))}updatePresetButtons(){for(const e of mm)this.presetButtons[e]?.setAttribute("aria-pressed",String(e===this.currentAppearance.presetId))}get samplingRate(){return Number(this.samplingRateInput.value)}buildPrototype(e=this.defaultBounds()){return nf(e,this.currentAppearance)}defaultBounds(){const e=this.ufoElement.canvasElement;return{x:e.width/2-Da.width/2,y:e.height/2-Da.height/2,width:Da.width,height:Da.height}}toggleRecording(){this.endDrag();const e=this.ufoElement.canvasElement;this.isRecording?(this.recorder?.stop(),this.isRecording=!1,this.setRecordButtonLabel(!1),this.setCanvasCursor(void 0),e.style.touchAction="",this.sourceSelect.disabled=!1,this.addShapeButton.disabled=!1,this.ufoElement.refresh(),this.refreshSourceList()):(this.recorder=new RT(this.ufoElement.sighting.timeline,new PT(this.samplingRate)),this.recorder.start(this.currentSourceId,this.buildPrototype()),this.isRecording=!0,this.setRecordButtonLabel(!0),this.setCanvasCursor("record"),e.style.touchAction="none",this.sourceSelect.disabled=!0,this.addShapeButton.disabled=!0,this.deleteShapeButton.disabled=!0)}setRecordButtonLabel(e){this.recordButton.textContent=e?"⏹":"⏺";const t=e?this.messages.stop:this.messages.record;this.recordButton.title=t,this.recordButton.setAttribute("aria-label",t)}async loadLocaleMessages(){const e=za(vs.preferencesFor(this),Hh);e!=="en"&&(this.tagNames=new Bh(await v1(e)),this.showTags(),this.applyMessages(await g1(e)))}showTags(){this.tagsInput.value=this.ufoElement.sighting.event.tags?.map(e=>this.tagNames.name(e)).join(", ")??""}applyMessages(e){this.currentSourceId===ml&&this.shapeTitleInput.value===`${this.messages.shape} 1`?(this.messages=e,this.shapeTitleInput.value=`${this.messages.shape} 1`,this.updateShapeTitle()):this.messages=e,this.presetButtons.oval.textContent=e.oval,this.presetButtons.polygon.textContent=e.polygon,this.contextAddVertexButton.textContent=e.addVertex,this.contextDeleteVertexButton.textContent=e.deleteVertex,this.labelColor.textContent=e.color,this.labelTransparency.textContent=e.transparency,this.labelHalo.textContent=e.halo,this.labelBlur.textContent=e.blur,this.labelBrightness.textContent=e.brightness,this.labelShape.textContent=e.shape,this.labelShapeTitle.textContent=e.shapeTitle,this.labelUtcOffset.textContent=e.utcOffset,this.utcOffsetInput.placeholder=e.utcOffsetPlaceholder,this.labelApparentWidth.textContent=e.apparentWidth,this.labelRealWidth.textContent=e.realWidth,this.labelObjectDistance.textContent=e.distance,this.labelSizeLock.textContent=e.sizeLock;for(const[i,s]of[["option-lock-none",e.lockNone],["option-lock-apparent",e.lockApparent],["option-lock-real",e.lockReal],["option-lock-distance",e.lockDistance]])this.shadow.getElementById(i).textContent=s;this.clearDistanceHypothesisButton.textContent=e.clearDistanceHypothesis,this.clearDistanceHypothesisButton.title=e.clearDistanceHypothesisTitle,this.refreshApparentSize(),this.labelSamplingRate.textContent=e.samplingRate,this.labelDuration.textContent=e.duration,this.durationInput.placeholder=e.durationPlaceholder,this.addShapeButton.title=e.addShape,this.addShapeButton.setAttribute("aria-label",e.addShape),this.deleteShapeButton.title=e.deleteShape,this.deleteShapeButton.setAttribute("aria-label",e.deleteShape),this.contextGroupButton.textContent=e.group,this.contextUngroupButton.textContent=e.ungroup,this.contextBringToFrontButton.textContent=e.bringToFront,this.contextSendToBackButton.textContent=e.sendToBack,this.contextDeleteButton.textContent=e.contextMenuDelete,this.exportButton.textContent=e.export,this.labelImportFile.textContent=e.importFile,this.labelImportUrl.textContent=e.importUrl,this.importUrlInput.placeholder=e.importUrlPlaceholder,this.importUrlButton.textContent=e.importButton,this.labelWitnessAge.textContent=e.witnessAge,this.labelWitnessOccupation.textContent=e.witnessOccupation,this.labelTestimonySource.textContent=e.testimonySource,this.labelTestimonyFollowedUp.textContent=e.testimonyFollowedUp;for(const[i,s]of[["option-source-unknown",e.testimonySourceUnknown],["option-source-on-site",e.testimonySourceOnSite],["option-source-interview",e.testimonySourceInterview],["option-source-telephone",e.testimonySourceTelephone],["option-source-questionnaire",e.testimonySourceQuestionnaire],["option-source-letter",e.testimonySourceLetter],["option-source-press",e.testimonySourcePress],["option-followed-unknown",e.testimonyUnknown],["option-followed-yes",e.testimonyYes],["option-followed-no",e.testimonyNo]]){const r=this.shadow.getElementById(i);r&&(r.textContent=s)}this.labelNarrativeKey.textContent=e.narrativeKey.replace("{source}",Ts[0].name),this.labelNarrativeWorkspace.textContent=e.narrativeWorkspace,this.narrativeWorkspaceInput.placeholder=e.narrativeWorkspacePlaceholder,this.narrativeWorkspaceInput.title=e.narrativeWorkspaceHint,this.labelNarrativeRemember.textContent=e.narrativeRemember,this.narrativeStopButton.textContent=e.narrativeStop,this.narrativeDraftButton.textContent=e.narrativeDraft,this.descriptionInput.placeholder=e.narrativePlaceholder,this.syncNarrativeEnabled(),this.refreshSourceRows(),this.refreshTimeZoneOptions(),this.labelPlaceName.textContent=e.placeName,this.placeNameInput.placeholder=e.placeNamePlaceholder,this.searchPlaceButton.textContent=e.searchPlace,this.labelPlaceMatch.textContent=e.placeMatch,this.labelLatitude.textContent=e.latitude,this.labelLongitude.textContent=e.longitude,this.labelHeading.textContent=e.heading,this.headingInput.placeholder=e.headingPlaceholder,this.labelPitch.textContent=e.pitch,this.labelRoll.textContent=e.roll,this.labelElevation.textContent=e.elevation,this.labelObservationTime.textContent=e.observationTime,this.labelObservationEndTime.textContent=e.observationEndTime,this.obsTimeInput.placeholder=e.edtfPlaceholder,this.obsTimeInput.title=e.observationTimeHint,this.obsEndTimeInput.placeholder=e.edtfPlaceholder,this.obsEndTimeInput.title=e.observationEndTimeHint,this.presetsGroup.setAttribute("aria-label",e.presetsGroupLabel),this.labelDecor.textContent=e.decor,this.labelDecorGroup.textContent=e.decor,this.optionDecorBuilding.textContent=e.decorBuilding,this.optionDecorTree.textContent=e.decorTree,this.optionDecorCrop.textContent=e.decorCrop,this.optionDecorMound.textContent=e.decorMound,this.optionDecorStreetlight.textContent=e.decorStreetlight,this.optionDecorVehicle.textContent=e.decorVehicle,this.optionDecorAircraft.textContent=e.decorAircraft,this.optionDecorEntity.textContent=e.decorEntity,this.labelDecorLights.textContent=e.decorLights,this.labelDecorAltitude.textContent=e.decorAltitude,this.showMeteorButton.title=e.showMeteor,this.showMeteorButton.setAttribute("aria-label",e.showMeteor),this.showCometButton.title=e.showComet,this.showCometButton.setAttribute("aria-label",e.showComet),this.lookAtDecorButton.title=e.lookAtDecor,this.lookAtDecorButton.setAttribute("aria-label",e.lookAtDecor),this.optionDecorWitness.textContent=e.decorWitness,this.deleteDecorButton.title=e.deleteDecor,this.deleteDecorButton.setAttribute("aria-label",e.deleteDecor),this.labelDecorTitle.textContent=e.decorTitle,this.labelDecorEast.textContent=e.decorEast,this.labelDecorNorth.textContent=e.decorNorth,this.labelDecorHeading.textContent=e.decorHeading,this.labelDecorColor.textContent=e.decorColor,this.labelDecorLit.textContent=e.decorLit,this.labelDecorSightingUrl.textContent=e.decorSightingUrl,this.contextViewTestimonyButton.textContent=e.viewTestimony,this.labelContextMasks.textContent=`${e.masks} ▸`,this.addDecorWitnessButton.textContent=e.addWitness,this.addDecorBuildingButton.title=e.addDecor,this.addDecorBuildingButton.setAttribute("aria-label",e.addDecor),this.confirmAcceptButton.textContent=e.confirmAccept,this.confirmDeclineButton.textContent=e.confirmDecline,this.labelMilestones.textContent=e.milestones,this.labelMilestoneLabel.textContent=e.milestoneLabel,this.labelMilestoneNote.textContent=e.milestoneNote;for(const[i,s]of[[this.addMilestoneButton,e.addMilestone],[this.deleteMilestoneButton,e.deleteMilestone]])i.title=s,i.setAttribute("aria-label",s);this.labelDecorWidth.textContent=e.decorWidth,this.labelDecorLength.textContent=e.decorLength,this.labelDecorHeight.textContent=e.decorHeight,this.labelDecorModel.textContent=e.decorModel,this.labelDecorModelAdvanced.textContent=e.decorModelAdvanced,this.labelDecorModelUrl.textContent=e.decorModelUrl,this.labelDecorModelTitle.textContent=e.decorModelTitle,this.labelDecorModelAuthor.textContent=e.decorModelAuthor,this.labelDecorModelLicense.textContent=e.decorModelLicense,this.labelDecorModelSource.textContent=e.decorModelSource,this.labelDecorFloors.textContent=e.decorFloors,this.labelDecorOccupiedFloor.textContent=e.decorOccupiedFloor,this.labelDecorWitnessSide.textContent=e.decorWitnessSide,this.labelDecorWindows.textContent=e.decorWindows,this.optionWitnessSideNone.textContent=e.decorWitnessSideNone;const t={front:e.decorSideFront,behind:e.decorSideBehind,left:e.decorSideLeft,right:e.decorSideRight,"front-left":e.decorSideFrontLeft,"front-right":e.decorSideFrontRight,"behind-left":e.decorSideBehindLeft,"behind-right":e.decorSideBehindRight};for(const i of ia)this.labelDecorSide[i].textContent=t[i],this.optionWitnessSide[i].textContent=t[i];this.refreshDecorList(),this.labelWitnessId.textContent=e.witnessId,this.labelWitnessDirName.textContent=e.witnessDirName,this.labelWitnessTitle.textContent=e.witnessTitle,this.labelWitnessLastName.textContent=e.witnessLastName,this.labelWitnessFirstNames.textContent=e.witnessFirstNames,this.witnessFirstNamesInput.placeholder=e.tagsPlaceholder,this.labelCaseId.textContent=e.caseId,this.labelDescription.textContent=e.description,this.labelTags.textContent=e.tags,this.tagsInput.placeholder=e.tagsPlaceholder,this.labelShapeGroup.textContent=e.shapeGroup,this.labelTemporalGroup.textContent=e.temporalGroup,this.labelLocationGroup.textContent=e.locationGroup,this.labelObservationGroup.textContent=e.observationGroup,this.labelWitnessGroup.textContent=e.witnessGroup,this.labelWeatherGroup.textContent=e.weather,this.refreshTimeQualifierOptions(),this.edtfModeButton.title=e.edtfModeTitle,this.edtfModeButton.setAttribute("aria-label",e.edtfModeTitle),this.paramSummaryBuilder=new bf(e,this.showerLanguage(),this.said,this.tagNames),this.refreshParamSummary();const n=this.skyDetailsButton.getAttribute("aria-expanded")==="true";this.skyDetailsButton.title=n?e.skyDetailsHide:e.skyDetails,this.skyDetailsButton.setAttribute("aria-label",this.skyDetailsButton.title),this.labelCloudCover.textContent=e.cloudCover,this.labelHighCloud.textContent=e.highCloudCover,this.labelIceAlignment.textContent=e.iceCrystalAlignment,this.labelFNumber.textContent=e.aperture,this.labelExposure.textContent=e.exposure,this.labelFocusDistance.textContent=e.focusDistance,this.syncOpticsFromInstrument(),this.labelCloudDarkness.textContent=e.cloudDarkness,this.labelCloudBase.textContent=e.cloudBase,this.labelPrecipitationType.textContent=e.precipitationType,this.optionPrecipitationNone.textContent=e.precipitationNone,this.optionPrecipitationRain.textContent=e.precipitationRain,this.optionPrecipitationSnow.textContent=e.precipitationSnow,this.optionPrecipitationHail.textContent=e.precipitationHail,this.labelPrecipitationIntensity.textContent=e.precipitationIntensity,this.labelWindDirection.textContent=e.windDirection,this.labelWindSpeed.textContent=e.windSpeed,this.labelStorm.textContent=e.storm,this.labelWeatherInferred.textContent=e.weatherInferred,this.syncWeatherSourceState(),this.labelSoundGroup.textContent=e.soundGroup,this.labelSoundKind.textContent=e.soundKind,this.labelSoundVolume.textContent=e.soundVolume,this.labelSoundPitch.textContent=e.soundPitch,this.labelSoundSrc.textContent=e.soundSrc,this.soundSrcInput.placeholder=e.soundSrcPlaceholder;for(const[i,s]of this.soundKindOptions)s.textContent=this.soundKindLabel(i,e);this.labelInstrument.textContent=e.instrument,this.loopButton.title=e.autoReplay,this.loopButton.setAttribute("aria-label",e.autoReplay),this.setRecordButtonLabel(this.isRecording),this.syncPlaybackControls()}onPointerDown(e){if(this.isRecording){this.onPointerMove(e);return}const t=this.canvasPointFromEvent(e);if(!t)return;const n=this.ufoElement.sighting.timeline,i=this.ufoElement.currentTime,s=this.ufoElement.playbackState==="playing";if(this.selectedSourceIds.size>1){const l=new dc(this.selectedMembers()),c=it.hitTestHandle({bounds:l.bounds(),angle:0},t);if(c==="rotate"){if(s)return;this.dragState={kind:"group-rotate",group:l,startPointer:t},this.startDragListening();return}if(c){if(s)return;this.dragState={kind:"group-resize",group:l,handle:c},this.startDragListening();return}}else{const l=n.getInterpolatedShapeAt(i,this.currentSourceId),c=l?.kind==="polygon"?it.hitTestVertex(l,t):void 0;if(l?.kind==="polygon"&&c!==void 0){if(s)return;this.dragState={kind:"vertex",sourceId:this.currentSourceId,original:l,vertexIndex:c},this.startDragListening();return}const h=l&&it.hitTestHandle(l,t);if(l&&h){if(s)return;this.beginDrag(h==="rotate"?"rotate":"resize",this.currentSourceId,l,t,h);return}}const r=this.ufoElement.shapeAt(t.x,t.y,dm);if(!r){const l=this.pickDecorAt(e);if(l!==void 0){this.selectDecor(l);return}s||this.beginCameraDrag(t);return}if(this.revealShapePanel(),e.shiftKey?this.toggleUnitSelection(r.sourceId):this.selectedSourceIds.has(r.sourceId)||this.selectUnit(r.sourceId),s)return;const o=[...this.selectedSourceIds].map(l=>({sourceId:l,original:l===r.sourceId?r.shape:n.getInterpolatedShapeAt(i,l)??r.shape}));this.dragState={kind:"move",sources:o,startPointer:t},this.startDragListening()}revealShapePanel(){const e=this.groupTabs.find(t=>t.getAttribute("aria-controls")==="group-shape");e&&this.toggleGroup(e,!0)}selectedMembers(){const e=this.ufoElement.sighting.timeline,t=this.ufoElement.currentTime;return[...this.selectedSourceIds].map(n=>({sourceId:n,shape:e.getInterpolatedShapeAt(t,n)})).filter(n=>!!n.shape)}selectUnit(e){const t=this.ufoElement.sighting.timeline.groupMembers(e)??[e];t.length===this.selectedSourceIds.size&&t.every(n=>this.selectedSourceIds.has(n))&&e===this.currentSourceId||(this.selectedSourceIds=new Set(t),this.currentSourceId=e,this.refreshSourceList(),this.onSelectionOrTimeChanged())}toggleUnitSelection(e){const t=this.ufoElement.sighting.timeline,n=t.groupMembers(e)??[e];if(n.every(s=>this.selectedSourceIds.has(s))){if(n.length>=this.selectedSourceIds.size)return;for(const s of n)this.selectedSourceIds.delete(s);if(!this.selectedSourceIds.has(this.currentSourceId)){const s=t.sourceIds;this.currentSourceId=[...this.selectedSourceIds].sort((r,o)=>s.indexOf(r)-s.indexOf(o)).pop()}}else{for(const s of n)this.selectedSourceIds.add(s);this.currentSourceId=e}this.refreshSourceList(),this.onSelectionOrTimeChanged()}onContextMenu(e){if(e.preventDefault(),this.isRecording||this.ufoElement.playbackState==="playing")return;this.hideContextMenu(),this.hideDecorContextMenu();const t=this.canvasPointFromEvent(e);if(!t)return;const n=this.ufoElement.sighting.timeline,i=this.ufoElement.currentTime,s=this.selectedSourceIds.size===1?n.getInterpolatedShapeAt(i,this.currentSourceId):void 0,o=s?.kind==="polygon"&&it.hitTestVertex(s,t)!==void 0?{sourceId:this.currentSourceId}:this.ufoElement.shapeAt(t.x,t.y,dm);if(o){this.selectedSourceIds.has(o.sourceId)||this.selectUnit(o.sourceId),this.currentSourceId=o.sourceId,this.contextMenuPoint=t,this.showContextMenu(e.clientX,e.clientY);return}const l=this.pickDecorAt(e),c=l?this.ufoElement.sighting.decor.find(h=>h.id===l):void 0;c&&this.showDecorContextMenu(e.clientX,e.clientY,c)}pickDecorAt(e){const n=this.ufoElement.canvasElement.getBoundingClientRect();if(n.width===0||n.height===0)return;const i=(e.clientX-n.left)/n.width*2-1,s=-((e.clientY-n.top)/n.height*2-1);return this.sceneElement.pickDecorAt(i,s)}showContextMenu(e,t){this.contextMenu.style.left=`${e}px`,this.contextMenu.style.top=`${t}px`,this.contextMenu.hidden=!1;const n=this.ufoElement.sighting.timeline.sourceIds,i=n.filter(f=>this.selectedSourceIds.has(f)),s=n.length<=i.length,r=i.length>0&&n.slice(n.length-i.length).every(f=>this.selectedSourceIds.has(f)),o=i.length>0&&n.slice(0,i.length).every(f=>this.selectedSourceIds.has(f));this.contextBringToFrontButton.disabled=s||r,this.contextSendToBackButton.disabled=s||o,this.contextBringToFrontButton.title=s?this.messages.onlyOneShape:r?this.messages.alreadyAtFront:"",this.contextSendToBackButton.title=s?this.messages.onlyOneShape:o?this.messages.alreadyAtBack:"",this.contextGroupButton.disabled=this.selectedSourceIds.size<2,this.contextGroupButton.title=this.contextGroupButton.disabled?this.messages.needTwoShapesToGroup:"";const l=this.ufoElement.sighting.timeline.groupMembers(this.currentSourceId)!==void 0;this.contextUngroupButton.disabled=!l,this.contextUngroupButton.title=l?"":this.messages.notGrouped,this.contextDeleteButton.disabled=this.deleteShapeButton.disabled,this.contextDeleteButton.title=this.contextDeleteButton.disabled?this.messages.onlyOneShape:"";const c=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,this.currentSourceId),h=this.selectedSourceIds.size===1&&c?.kind==="polygon";this.contextAddVertexButton.disabled=!h,this.contextAddVertexButton.title=h?"":this.messages.notAPolygon;const d=h&&this.contextMenuPoint?it.hitTestVertex(c,this.contextMenuPoint):void 0,u=h&&c.points.length<=Sm;this.contextDeleteVertexButton.disabled=!h||d===void 0||u,this.contextDeleteVertexButton.title=h?u?this.messages.tooFewVertices:"":this.messages.notAPolygon,document.addEventListener("click",this.handleOutsideContextMenuClick)}hideContextMenu(){this.contextMenu.hidden=!0,this.contextMenuPoint=void 0,document.removeEventListener("click",this.handleOutsideContextMenuClick)}handleOutsideContextMenuClick=e=>{e.composedPath().includes(this.contextMenu)||e.composedPath().includes(this.decorContextMenu)||(this.hideContextMenu(),this.hideDecorContextMenu())};showDecorContextMenu(e,t,n){this.contextMenuDecorId=n.id,this.decorContextMenu.style.left=`${e}px`,this.decorContextMenu.style.top=`${t}px`,this.decorContextMenu.hidden=!1,this.contextViewTestimonyButton.disabled=!n.sightingUrl,this.contextViewTestimonyButton.title=n.sightingUrl?"":this.messages.noWitnessRecording,this.refreshContextMasksSubmenu(n),document.addEventListener("click",this.handleOutsideContextMenuClick)}hideDecorContextMenu(){this.decorContextMenu.hidden=!0,this.contextMenuDecorId=void 0,document.removeEventListener("click",this.handleOutsideContextMenuClick)}refreshContextMasksSubmenu(e){this.contextMasksSubmenu.innerHTML="";for(const t of this.ufoElement.sighting.timeline.sourceIds){const n=document.createElement("label"),i=document.createElement("input");i.type="checkbox",i.checked=e.occludesSourceIds?.includes(t)??!1,i.addEventListener("change",()=>this.updateDecorOccludesShape(e.id,t,i.checked)),n.appendChild(i),n.appendChild(document.createTextNode(this.shapeLabel(t))),this.contextMasksSubmenu.appendChild(n)}}updateDecorOccludesShape(e,t,n){const i=this.ufoElement.sighting;i.decor=i.decor.map(s=>{if(s.id!==e)return s;const r=n?[...new Set([...s.occludesSourceIds??[],t])]:(s.occludesSourceIds??[]).filter(o=>o!==t);return{...s,occludesSourceIds:r.length>0?r:void 0}}),this.ufoElement.refresh()}viewWitnessTestimony(){const e=this.ufoElement.sighting.decor.find(t=>t.id===this.contextMenuDecorId);this.hideDecorContextMenu(),e?.sightingUrl&&this.importFromUrl(e.sightingUrl)}addVertexAtContextMenu(){const e=this.contextMenuPoint;if(this.hideContextMenu(),!e)return;const t=this.ufoElement.currentTime,n=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(t,this.currentSourceId);if(n?.kind!=="polygon")return;const i=it.insertVertexNear(n,e);this.commitShapes(t,[{sourceId:this.currentSourceId,shape:i}]),this.ufoElement.refresh()}deleteVertexAtContextMenu(){const e=this.contextMenuPoint;if(this.hideContextMenu(),!e)return;const t=this.ufoElement.currentTime,n=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(t,this.currentSourceId);if(n?.kind!=="polygon")return;const i=it.hitTestVertex(n,e);if(i===void 0)return;const s=it.deleteVertex(n,i);this.commitShapes(t,[{sourceId:this.currentSourceId,shape:s}]),this.ufoElement.refresh()}bringSelectedToFront(){const e=this.ufoElement.sighting.timeline;for(const t of e.sourceIds.filter(n=>this.selectedSourceIds.has(n)))e.bringToFront(t);this.hideContextMenu(),this.ufoElement.refresh()}sendSelectedToBack(){const e=this.ufoElement.sighting.timeline;for(const t of e.sourceIds.filter(n=>this.selectedSourceIds.has(n)).reverse())e.sendToBack(t);this.hideContextMenu(),this.ufoElement.refresh()}groupSelected(){this.selectedSourceIds.size<2||(this.ufoElement.sighting.timeline.group([...this.selectedSourceIds]),this.hideContextMenu(),this.ufoElement.refresh())}ungroupSelected(){this.ufoElement.sighting.timeline.ungroup(this.currentSourceId),this.selectedSourceIds=new Set([this.currentSourceId]),this.hideContextMenu(),this.ufoElement.refresh()}beginDrag(e,t,n,i,s){this.dragState={kind:e,sourceId:t,original:n,handle:s,startPointer:i},this.startDragListening()}beginCameraDrag(e){const t=this.isWitnessInsideDecor();this.cameraDragState={startPointer:e,startHeadingDeg:t?this.indoorLookYawDeg:this.numberOrUndefined(this.headingInput.value)??0,startPitchDeg:t?this.indoorLookPitchDeg:this.numberOrUndefined(this.pitchInput.value)??0,insideDecor:t},t||this.sceneElement.setCompassForced(!0),this.setCanvasCursor("panning"),this.startDragListening()}isWitnessInsideDecor(){return this.ufoElement.sighting.decor.some(e=>e.witnessSide!==void 0&&Na(e.kind))}syncIndoorLookReset(){const e=this.ufoElement.sighting.decor.find(n=>n.witnessSide!==void 0&&Na(n.kind)),t=e?`${e.id}:${e.witnessSide}`:void 0;t!==this.lastInhabitedKey&&(this.lastInhabitedKey=t,this.indoorLookYawDeg=0,this.indoorLookPitchDeg=0,this.sceneElement.setIndoorLook(0,0))}startDragListening(){document.addEventListener("pointermove",this.handleDragPointerMove),document.addEventListener("pointerup",this.handleDragPointerUp)}onDragPointerMove(e){if(this.cameraDragState){this.onCameraDragPointerMove(e);return}if(!this.dragState)return;const t=this.canvasPointFromEvent(e);if(!t)return;const n=this.ufoElement.currentTime;if(this.dragState.kind==="move"){const{sources:i,startPointer:s}=this.dragState,r=t.x-s.x,o=t.y-s.y,l=i.map(({sourceId:c,original:h})=>({sourceId:c,shape:{...h,bounds:{...h.bounds,x:h.bounds.x+r,y:h.bounds.y+o}}}));this.commitShapes(n,l)}else if(this.dragState.kind==="group-resize"){const{group:i,handle:s}=this.dragState;this.commitShapes(n,i.resize(s,t))}else if(this.dragState.kind==="group-rotate"){const{group:i,startPointer:s}=this.dragState;this.commitShapes(n,i.rotate(t,s))}else if(this.dragState.kind==="vertex"){const{sourceId:i,original:s,vertexIndex:r}=this.dragState,o=it.moveVertex(s,r,t);this.commitShapes(n,[{sourceId:i,shape:o}])}else{const{kind:i,sourceId:s,original:r,handle:o}=this.dragState,l=i==="resize"?it.resizeShape(r,o,t):it.rotateShape(r,t);this.commitShapes(n,[{sourceId:s,shape:l}])}this.ufoElement.refresh()}onCameraDragPointerMove(e){if(!this.cameraDragState)return;const t=this.canvasPointFromEvent(e);if(!t)return;const{startPointer:n,startHeadingDeg:i,startPitchDeg:s,insideDecor:r}=this.cameraDragState,o=i+(t.x-n.x)*fm,l=Math.max(-90,Math.min(90,s-(t.y-n.y)*fm));if(r){this.indoorLookYawDeg=o,this.indoorLookPitchDeg=l,this.sceneElement.setIndoorLook(o,l),this.ufoElement.refresh();return}this.headingInput.value=String(this.rounded(o)),this.pitchInput.value=String(this.rounded(l)),this.updateObserver()}endDrag(){!this.dragState&&!this.cameraDragState||(this.cameraDragState&&!this.cameraDragState.insideDecor&&this.sceneElement.setCompassForced(!1),this.dragState=void 0,this.cameraDragState=void 0,this.setCanvasCursor(this.hoverCursor),document.removeEventListener("pointermove",this.handleDragPointerMove),document.removeEventListener("pointerup",this.handleDragPointerUp))}nudgeBounds(e,t){const n={...e};if(t.shiftKey){switch(t.key){case"ArrowLeft":n.width=Math.max(gs,n.width-us);break;case"ArrowRight":n.width+=us;break;case"ArrowUp":n.height=Math.max(gs,n.height-us);break;case"ArrowDown":n.height+=us;break}n.x-=(n.width-e.width)/2,n.y-=(n.height-e.height)/2}else switch(t.key){case"ArrowLeft":n.x-=us;break;case"ArrowRight":n.x+=us;break;case"ArrowUp":n.y-=us;break;case"ArrowDown":n.y+=us;break}return n}moveOrResizeSelectedShapes(e){if(this.isRecording||this.ufoElement.playbackState==="playing")return;const t=this.ufoElement.currentTime,n=this.selectedMembers();if(n.length!==0){if(e.preventDefault(),n.length===1){const{sourceId:i,shape:s}=n[0];this.commitShapes(t,[{sourceId:i,shape:{...s,bounds:this.nudgeBounds(s.bounds,e)}}])}else{const i=new dc(n),s=this.nudgeBounds(i.bounds(),e);this.commitShapes(t,i.scaleTo(s))}this.ufoElement.refresh()}}updateHoverCursor(e){this.isRecording||this.dragState||this.cameraDragState||(this.hoverCursor=this.hoverCursorAt(e),this.setCanvasCursor(this.hoverCursor))}hoverCursorAt(e){const t=this.canvasPointFromEvent(e);if(!t)return;const n=this.ufoElement.sighting.timeline,i=this.ufoElement.currentTime,s=this.ufoElement.playbackState!=="playing";if(s)if(this.selectedSourceIds.size>1){const r=it.hitTestHandle({bounds:new dc(this.selectedMembers()).bounds(),angle:0},t);if(r)return this.cursorForHandle(r,0)}else{const r=n.getInterpolatedShapeAt(i,this.currentSourceId);if(r?.kind==="polygon"&&it.hitTestVertex(r,t)!==void 0)return"vertex";const o=r&&it.hitTestHandle(r,t);if(r&&o)return this.cursorForHandle(o,r.angle)}return n.hitTest(i,t.x,t.y)?s?"move":"select":this.pickDecorAt(e)!==void 0?"select":s?"pan":void 0}cursorForHandle(e,t){return e==="rotate"?"rotate":`resize-${it.resizeAxisFor(e,t)}`}setCanvasCursor(e){const t=this.ufoElement.canvasElement;e?t.dataset.cursor=e:delete t.dataset.cursor}onPointerMove(e){if(!this.isRecording){this.updateHoverCursor(e);return}const t=this.ufoElement.canvasElement,n=t.getBoundingClientRect(),i=e.clientX-n.left,s=e.clientY-n.top;this.recorder?.onPointerMove(i,s),this.ufoElement.renderer.clear(t.width,t.height),this.ufoElement.renderer.paintShape(wm(this.buildPrototype({x:0,y:0,width:Da.width,height:Da.height}),i,s))}canvasPointFromEvent(e){const t=this.ufoElement.canvasElement,n=t.getBoundingClientRect();if(!(n.width===0||n.height===0))return{x:(e.clientX-n.left)/n.width*t.width,y:(e.clientY-n.top)/n.height*t.height}}}const bA={stated:"narrativeStated",derived:"narrativeDerived",assumed:"narrativeAssumed"},gm="rr0-sighting-editor",vm="rr0-ufo-recorder";class xA extends Mt{}function wA(){Ql(),customElements.get(gm)||customElements.define(gm,Mt),customElements.get(vm)||customElements.define(vm,xA)}wA();export{An as $,Qn as A,vt as B,le as C,Nb as D,Yi as E,PA as F,ft as G,Ct as H,AA as I,TA as J,Ke as K,lo as L,CA as M,bo as N,It as O,Pb as P,_s as Q,Jr as R,qr as S,MA as T,IA as U,Re as V,ig as W,DA as X,wl as Y,fn as Z,ii as _,_A as a,EA as a0,hr as a1,ng as a2,RA as a3,eb as a4,Ol as a5,Dd as a6,zl as a7,rn as a8,cg as a9,Lu as aa,Nu as ab,Qe as ac,Ms as ad,oo as ae,Ci as af,Ji as ag,SA as b,Un as c,OA as d,Fl as e,Fn as f,NA as g,qe as h,P as i,cp as j,LA as k,kA as l,Zy as m,Vs as n,vc as o,zh as p,ty as q,At as r,Ka as s,Yt as t,jh as u,wn as v,sg as w,ji as x,rb as y,fb as z};
|
|
7402
|
+
`);let s=gi.cache.get(i);return s||(s=Promise.all(n.map(r=>gi.load(r.url))).then(r=>r.reduce((o,l)=>gi.concat(o,l))),gi.cache.set(i,s)),s}static parse(e){const t=e.byteLength/(4*Float32Array.BYTES_PER_ELEMENT),n=t*Float32Array.BYTES_PER_ELEMENT;return{count:t,ra:new Float32Array(e,0*n,t),dec:new Float32Array(e,1*n,t),mag:new Float32Array(e,2*n,t),ci:new Float32Array(e,3*n,t)}}static concat(e,t){const n=(i,s)=>{const r=new Float32Array(i.length+s.length);return r.set(i,0),r.set(s,i.length),r};return{count:e.count+t.count,ra:n(e.ra,t.ra),dec:n(e.dec,t.dec),mag:n(e.mag,t.mag),ci:n(e.ci,t.ci)}}}const hT=new URL(""+new URL("rain-BvWZrB9h.ogg",import.meta.url).href,import.meta.url).href,dT=new URL(""+new URL("wind-BjklexY7.ogg",import.meta.url).href,import.meta.url).href,uT=new URL(""+new URL("thunder-DA48qs_v.wav",import.meta.url).href,import.meta.url).href,fT=20,pT=1;class mT{context;buffers=new Map;ambientSource;ambientGain;ambientKey="none";ambientToken=0;ambientVolume=0;windSource;windGain;windActive=!1;windToken=0;windVolume=0;paused=!0;requested={type:"none",intensity:0,windSpeed:0};resume(){if(!this.context){if(typeof AudioContext>"u")return;try{this.context=new AudioContext}catch(e){console.warn("WeatherAudio: Web Audio unavailable, weather sounds disabled:",e);return}}this.context.state==="suspended"&&this.context.resume()}setAmbient(e,t,n){if(this.requested={type:e,intensity:t,windSpeed:n},!this.context)return;this.paused&&(e="none",t=0,n=0);const i=e==="rain"||e==="hail"?e:"none";if(this.ambientVolume=i==="hail"?Math.min(1,t*1.3+.2):i==="rain"?t:0,i!==this.ambientKey){this.ambientKey=i;const r=++this.ambientToken;this.stopSource(this.ambientSource,this.ambientGain),this.ambientSource=void 0,this.ambientGain=void 0,i!=="none"&&this.startLoop(hT,this.ambientVolume).then(o=>this.applyIfCurrent(o,r,()=>this.ambientToken,l=>{this.ambientSource=l?.source,this.ambientGain=l?.gain,l&&(l.gain.gain.value=this.ambientVolume)}))}else this.ambientGain&&(this.ambientGain.gain.value=this.ambientVolume);this.windVolume=Math.min(n/fT,1);const s=n>pT;if(s!==this.windActive){this.windActive=s;const r=++this.windToken;this.stopSource(this.windSource,this.windGain),this.windSource=void 0,this.windGain=void 0,s&&this.startLoop(dT,this.windVolume).then(o=>this.applyIfCurrent(o,r,()=>this.windToken,l=>{this.windSource=l?.source,this.windGain=l?.gain,l&&(l.gain.gain.value=this.windVolume)}))}else this.windGain&&(this.windGain.gain.value=this.windVolume)}setPaused(e){if(e===this.paused)return;this.paused=e;const{type:t,intensity:n,windSpeed:i}=this.requested;this.setAmbient(t,n,i)}playThunder(){!this.context||this.paused||this.playOneShot(uT,.9)}dispose(){this.ambientToken++,this.windToken++,this.stopSource(this.ambientSource,this.ambientGain),this.stopSource(this.windSource,this.windGain),this.ambientSource=void 0,this.ambientGain=void 0,this.windSource=void 0,this.windGain=void 0,this.context?.close(),this.context=void 0,this.buffers.clear()}applyIfCurrent(e,t,n,i){if(t!==n()){e?.source.stop();return}i(e)}async startLoop(e,t){const n=this.context;if(n)try{const i=await this.getBuffer(e),s=n.createBufferSource();s.buffer=i,s.loop=!0;const r=n.createGain();return r.gain.value=t,s.connect(r).connect(n.destination),s.start(),{source:s,gain:r}}catch(i){console.warn("Weather ambient sound failed to load, staying silent:",i);return}}async playOneShot(e,t){const n=this.context;if(n)try{const i=await this.getBuffer(e),s=n.createBufferSource();s.buffer=i;const r=n.createGain();r.gain.value=t,s.connect(r).connect(n.destination),s.start()}catch(i){console.warn("Thunder sound failed to load:",i)}}async getBuffer(e){const t=this.context;if(!t)throw new Error("WeatherAudio: AudioContext not ready — resume() must be called first");let n=this.buffers.get(e);return n||(n=fetch(e).then(i=>{if(!i.ok)throw new Error(`Audio fetch failed (${i.status}): ${e}`);return i.arrayBuffer()}).then(i=>t.decodeAudioData(i)),this.buffers.set(e,n)),n}stopSource(e,t){try{e?.stop()}catch{}e?.disconnect(),t?.disconnect()}}class zi{constructor(e){this.elements=e;const{eccentricity:t,perihelionAu:n}=e,[i,s]=this.perifocalAxes(),r=Math.sqrt(zi.SUN_GM_AU3_PER_DAY2*(1+t)/n);this.perihelionPosition=this.scale(i,n),this.perihelionVelocity=this.scale(s,r),this.inverseSemiMajorAxis=(1-t)/n}static SUN_GM_AU3_PER_DAY2=.0002959122082855911;static MAX_ITERATIONS=200;perihelionPosition;perihelionVelocity;inverseSemiMajorAxis;positionAt(e){const t=e-this.elements.perihelionJd,n=this.universalAnomaly(t),i=this.inverseSemiMajorAxis*n*n,s=this.elements.perihelionAu,r=1-n*n/s*zi.stumpffC(i),o=t-n*n*n/Math.sqrt(zi.SUN_GM_AU3_PER_DAY2)*zi.stumpffS(i);return{x:r*this.perihelionPosition.x+o*this.perihelionVelocity.x,y:r*this.perihelionPosition.y+o*this.perihelionVelocity.y,z:r*this.perihelionPosition.z+o*this.perihelionVelocity.z}}heliocentricDistanceAt(e){const t=this.positionAt(e);return Math.hypot(t.x,t.y,t.z)}universalAnomaly(e){if(e===0)return 0;const t=Math.sign(e),n=Math.sqrt(zi.SUN_GM_AU3_PER_DAY2)*Math.abs(e),i=o=>{const l=this.inverseSemiMajorAxis*o*o,c=this.elements.perihelionAu;return(1-this.inverseSemiMajorAxis*c)*o*o*o*zi.stumpffS(l)+c*o};let s=Math.max(1,n/this.elements.perihelionAu);for(;i(s)<n;)s*=2;let r=0;for(let o=0;o<zi.MAX_ITERATIONS&&s-r>1e-13*Math.max(1,s);o++){const l=(r+s)/2;i(l)<n?r=l:s=l}return t*(r+s)/2}perifocalAxes(){const e=this.elements.ascendingNodeDeg*Math.PI/180,t=this.elements.argumentOfPerihelionDeg*Math.PI/180,n=this.elements.inclinationDeg*Math.PI/180,i=Math.cos(e),s=Math.sin(e),r=Math.cos(t),o=Math.sin(t),l=Math.cos(n),c=Math.sin(n);return[{x:i*r-s*o*l,y:s*r+i*o*l,z:o*c},{x:-i*o-s*r*l,y:-s*o+i*r*l,z:r*c}]}scale(e,t){return{x:e.x*t,y:e.y*t,z:e.z*t}}static stumpffC(e){if(Math.abs(e)<1e-6)return 1/2-e/24+e*e/720;if(e>0)return(1-Math.cos(Math.sqrt(e)))/e;const t=Math.sqrt(-e);return(Math.cosh(t)-1)/-e}static stumpffS(e){if(Math.abs(e)<1e-6)return 1/6-e/120+e*e/5040;if(e>0){const n=Math.sqrt(e);return(n-Math.sin(n))/(n*n*n)}const t=Math.sqrt(-e);return(Math.sinh(t)-t)/(t*t*t)}}const iv=[{id:"halley-1910",designation:"1P/Halley",name:{en:"Halley's Comet",fr:"comète de Halley"},orbit:{eccentricity:.9672960498922706,perihelionAu:.5872100477652511,inclinationDeg:162.218798367122,ascendingNodeDeg:58.56208298700436,argumentOfPerihelionDeg:111.7366940639061,perihelionJd:2.4187816784171113e6},peakMagnitude:0,peakOn:"1910-05-20",absoluteMagnitude:4.72,activityExponent:4,tailLengthDeg:100,tailLengthAu:.1638,note:"Passed 0.15 au from Earth on 20 May 1910, and the Earth crossed the outer tail the day before — the apparition that produced a genuine public panic."},{id:"brooks-1911",designation:"C/1911 O1",name:{en:"Comet Brooks",fr:"comète Brooks"},orbit:{eccentricity:.9876404970138669,perihelionAu:.4898172916113738,inclinationDeg:33.34043866978714,ascendingNodeDeg:293.7022074981857,argumentOfPerihelionDeg:153.5578007321686,perihelionJd:2.4193378856140426e6},peakMagnitude:2,peakOn:"1911-10-25",absoluteMagnitude:5.59,activityExponent:4},{id:"skjellerup-maristany-1927",designation:"C/1927 X1",name:{en:"Comet Skjellerup-Maristany",fr:"comète Skjellerup-Maristany"},orbit:{eccentricity:.999839726885059,perihelionAu:.1761569619628186,inclinationDeg:85.1125991950808,ascendingNodeDeg:78.24360172472711,argumentOfPerihelionDeg:47.15877857390136,perihelionJd:2.4252326808989984e6},peakMagnitude:-6,peakOn:"1927-12-15",absoluteMagnitude:1.19,activityExponent:4,note:"One of the few comets of the century seen in full daylight."},{id:"de-kock-paraskevopoulos-1941",designation:"C/1941 B2",name:{en:"Comet de Kock-Paraskevopoulos",fr:"comète de Kock-Paraskevopoulos"},orbit:{eccentricity:.9991026715181549,perihelionAu:.7900329662827822,inclinationDeg:168.2039226531089,ascendingNodeDeg:43.10609347214336,argumentOfPerihelionDeg:268.6990344196369,perihelionJd:2430022157765061e-9},peakMagnitude:2,peakOn:"1941-02-05",absoluteMagnitude:5.01,activityExponent:4},{id:"southern-1947",designation:"C/1947 X1",name:{en:"the Southern Comet",fr:"comète australe"},orbit:{eccentricity:.9998424430916737,perihelionAu:.1100045955093761,inclinationDeg:138.5113919632757,ascendingNodeDeg:337.3114969669252,argumentOfPerihelionDeg:196.1820121395961,perihelionJd:2.4325220864727003e6},peakMagnitude:-3,peakOn:"1947-12-08",absoluteMagnitude:3.01,activityExponent:4,note:"A bright southern-hemisphere comet of December 1947, the month the American sighting wave of that year was still being argued over."},{id:"eclipse-1948",designation:"C/1948 V1",name:{en:"the Eclipse Comet",fr:"comète de l'éclipse"},orbit:{eccentricity:.9999130678247334,perihelionAu:.1354437057263306,inclinationDeg:23.11668597152911,ascendingNodeDeg:211.0454985994762,argumentOfPerihelionDeg:107.2474157073104,perihelionJd:2.4328519265329437e6},peakMagnitude:-2,peakOn:"1948-11-01",absoluteMagnitude:4.79,activityExponent:4,note:"Found during the total solar eclipse of 1 November 1948, which is how a comet that bright had gone unnoticed: it had been hidden in the Sun's glare."},{id:"arend-roland-1957",designation:"C/1956 R1",name:{en:"Comet Arend-Roland",fr:"comète Arend-Roland"},orbit:{eccentricity:1.0002570255357,perihelionAu:.3160532361485914,inclinationDeg:119.9440863251822,ascendingNodeDeg:215.8548157717755,argumentOfPerihelionDeg:308.775920364167,perihelionJd:2.4359365327396123e6},peakMagnitude:.5,peakOn:"1957-04-25",absoluteMagnitude:3.96,activityExponent:4,note:"Showed a spike pointing back TOWARD the Sun in late April 1957 — a real anti-tail, and much reported at the time."},{id:"mrkos-1957",designation:"C/1957 P1",name:{en:"Comet Mrkos",fr:"comète Mrkos"},orbit:{eccentricity:.9993521583504134,perihelionAu:.3549238508212375,inclinationDeg:93.9433042053929,ascendingNodeDeg:68.32441518619923,argumentOfPerihelionDeg:40.31823675802871,perihelionJd:243605193752228e-8},peakMagnitude:1,peakOn:"1957-08-05",absoluteMagnitude:5.07,activityExponent:4,note:"The second bright naked-eye comet of 1957, four months after Arend-Roland."},{id:"seki-lines-1962",designation:"C/1962 C1",name:{en:"Comet Seki-Lines",fr:"comète Seki-Lines"},orbit:{eccentricity:1.000003791331562,perihelionAu:.03139689112215131,inclinationDeg:65.01487186102287,ascendingNodeDeg:304.6776602796538,argumentOfPerihelionDeg:11.47295326312573,perihelionJd:2437756163010178e-9},peakMagnitude:-2.5,peakOn:"1962-04-01",absoluteMagnitude:9.3,activityExponent:4},{id:"ikeya-seki-1965",designation:"C/1965 S1",name:{en:"Comet Ikeya-Seki",fr:"comète Ikeya-Seki"},orbit:{eccentricity:.9999141178248997,perihelionAu:.007785966366889336,inclinationDeg:141.8642315267051,ascendingNodeDeg:346.9951764632611,argumentOfPerihelionDeg:69.04909813996062,perihelionJd:2.4390546837018197e6},peakMagnitude:-10,peakOn:"1965-10-21",alsoRecordedMagnitude:2,alsoRecordedOn:"1965-10-30",absoluteMagnitude:5.26,activityExponent:4.002,tailLengthDeg:25,tailLengthAu:.5048,note:"A sungrazer that passed 450 000 km above the Sun's surface and was seen beside it in broad daylight — the brightest comet of the twentieth century. It then stood in the dawn sky for a fortnight with a tail some 25 degrees long, which is the second magnitude recorded here."},{id:"bennett-1970",designation:"C/1969 Y1",name:{en:"Comet Bennett",fr:"comète Bennett"},orbit:{eccentricity:.9962979048768408,perihelionAu:.5376209981502136,inclinationDeg:90.03975717147327,ascendingNodeDeg:224.6576652531314,argumentOfPerihelionDeg:354.1494209173161,perihelionJd:2.4406655455270996e6},peakMagnitude:0,peakOn:"1970-03-26",absoluteMagnitude:3.36,activityExponent:4},{id:"white-ortiz-bolelli-1970",designation:"C/1970 K1",name:{en:"Comet White-Ortiz-Bolelli",fr:"comète White-Ortiz-Bolelli"},orbit:{eccentricity:.9999488875801225,perihelionAu:.00884411465256722,inclinationDeg:138.9520738221631,ascendingNodeDeg:336.8194095816687,argumentOfPerihelionDeg:61.10224765396615,perihelionJd:2.4407209807728203e6},peakMagnitude:1,peakOn:"1970-05-22",absoluteMagnitude:4.35,activityExponent:4},{id:"kohoutek-1973",designation:"C/1973 E1",name:{en:"Comet Kohoutek",fr:"comète Kohoutek"},orbit:{eccentricity:1.000007152175185,perihelionAu:.1424250377812859,inclinationDeg:14.30414984159355,ascendingNodeDeg:258.4893339663974,argumentOfPerihelionDeg:37.79772760699667,perihelionJd:2442044930687027e-9},peakMagnitude:0,peakOn:"1974-01-05",absoluteMagnitude:4.89,activityExponent:4,note:"Announced in advance as the comet of the century and remembered for disappointing: it was an ordinary naked-eye object, not the spectacle the press had promised."},{id:"west-1976",designation:"C/1975 V1",name:{en:"Comet West",fr:"comète West"},orbit:{eccentricity:1.000017859625611,perihelionAu:.1966006188461085,inclinationDeg:43.07319920579427,ascendingNodeDeg:118.9189245655447,argumentOfPerihelionDeg:358.4315101259072,perihelionJd:2442833721841768e-9},peakMagnitude:-3,peakOn:"1976-02-25",absoluteMagnitude:4.41,activityExponent:4,tailLengthDeg:30,tailLengthAu:.4325,note:"Broke into four pieces at perihelion. Barely reported at the time — the press had been burned by Kohoutek two years earlier."},{id:"iras-araki-alcock-1983",designation:"C/1983 H1",name:{en:"Comet IRAS-Araki-Alcock",fr:"comète IRAS-Araki-Alcock"},orbit:{eccentricity:.9898409731606003,perihelionAu:.9913412593828502,inclinationDeg:73.25000846947029,ascendingNodeDeg:49.10235754476374,argumentOfPerihelionDeg:192.8506176754439,perihelionJd:2.4454757545235856e6},peakMagnitude:1.7,peakOn:"1983-05-11",absoluteMagnitude:9.04,activityExponent:4,note:"Passed 0.031 au from Earth on 11 May 1983, one of the closest cometary approaches on record: it crossed a quarter of the sky in a night, which no other comet in this list did."},{id:"halley-1986",designation:"1P/Halley",name:{en:"Halley's Comet",fr:"comète de Halley"},orbit:{eccentricity:.9672792271749998,perihelionAu:.5871034488173393,inclinationDeg:162.2422242700916,ascendingNodeDeg:58.85993640671803,argumentOfPerihelionDeg:111.8655480539208,perihelionJd:2.4464709589610207e6},peakMagnitude:2.1,peakOn:"1986-03-10",absoluteMagnitude:2.71,activityExponent:4,note:"The worst-placed return in two thousand years — famous, expected, and for most observers a faint smudge."},{id:"hyakutake-1996",designation:"C/1996 B2",name:{en:"Comet Hyakutake",fr:"comète Hyakutake"},orbit:{eccentricity:.9997295133739305,perihelionAu:.2302272039470452,inclinationDeg:124.923592343765,ascendingNodeDeg:188.0454295899424,argumentOfPerihelionDeg:130.1724036582639,perihelionJd:2.4502048946148166e6},peakMagnitude:0,peakOn:"1996-03-25",absoluteMagnitude:4.75,activityExponent:4,tailLengthDeg:80,tailLengthAu:1,note:"Passed 0.10 au from Earth in March 1996, five weeks BEFORE perihelion, with a tail measured at some 80 degrees — the longest of the modern era."},{id:"hale-bopp-1997",designation:"C/1995 O1",name:{en:"Comet Hale-Bopp",fr:"comète Hale-Bopp"},orbit:{eccentricity:.9951314746156615,perihelionAu:.9141695067003724,inclinationDeg:89.43017155012492,ascendingNodeDeg:282.470602866853,argumentOfPerihelionDeg:130.5872524854533,perihelionJd:2450539633099368e-9},peakMagnitude:-.8,peakOn:"1997-04-01",absoluteMagnitude:-1.06,activityExponent:4,tailLengthDeg:20,tailLengthAu:.9938,note:"Visible to the naked eye for about eighteen months, longer than any comet on record."},{id:"mcnaught-2007",designation:"C/2006 P1",name:{en:"Comet McNaught",fr:"comète McNaught"},orbit:{eccentricity:1.00001811603225,perihelionAu:.1707325614080681,inclinationDeg:77.83726446452654,ascendingNodeDeg:267.4149080498975,argumentOfPerihelionDeg:155.9756130642756,perihelionJd:2454113298753579e-9},peakMagnitude:-5.5,peakOn:"2007-01-13",absoluteMagnitude:2.53,activityExponent:4,tailLengthDeg:35,tailLengthAu:.5009,note:"The brightest comet since Ikeya-Seki, seen in daylight beside the Sun in January 2007."},{id:"lovejoy-2011",designation:"C/2011 W3",name:{en:"Comet Lovejoy",fr:"comète Lovejoy"},orbit:{eccentricity:.999915056276912,perihelionAu:.005553783989325053,inclinationDeg:134.3558712062691,ascendingNodeDeg:326.3693517957772,argumentOfPerihelionDeg:53.50991655176601,perihelionJd:2455911511809431e-9},peakMagnitude:-3,peakOn:"2011-12-16",alsoRecordedMagnitude:1.5,alsoRecordedOn:"2011-12-22",absoluteMagnitude:3.51,activityExponent:1.194,note:"A sungrazer that was expected to be destroyed at perihelion and came out the other side, to stand in the southern dawn sky for the rest of December — which is the second magnitude recorded here."},{id:"panstarrs-2013",designation:"C/2011 L4",name:{en:"Comet PANSTARRS",fr:"comète PANSTARRS"},orbit:{eccentricity:1.000032542889696,perihelionAu:.301544229714915,inclinationDeg:84.2081978367921,ascendingNodeDeg:65.66588626213694,argumentOfPerihelionDeg:333.6516444379993,perihelionJd:2456361669960698e-9},peakMagnitude:1,peakOn:"2013-03-10",absoluteMagnitude:5.98,activityExponent:4},{id:"neowise-2020",designation:"C/2020 F3",name:{en:"Comet NEOWISE",fr:"comète NEOWISE"},orbit:{eccentricity:.9991782081129224,perihelionAu:.2946512466331692,inclinationDeg:128.9375043020912,ascendingNodeDeg:61.01042991771634,argumentOfPerihelionDeg:37.2786526292898,perihelionJd:2.4590341788972816e6},peakMagnitude:.9,peakOn:"2020-07-08",absoluteMagnitude:5.79,activityExponent:4,tailLengthDeg:10,tailLengthAu:.1808,note:"The first comet since Hale-Bopp that ordinary observers in the northern hemisphere saw without being told where to look."},{id:"tsuchinshan-atlas-2024",designation:"C/2023 A3",name:{en:"Comet Tsuchinshan-ATLAS",fr:"comète Tsuchinshan-ATLAS"},orbit:{eccentricity:1.000020192843226,perihelionAu:.3914228969475176,inclinationDeg:139.1105462619479,ascendingNodeDeg:21.55945689078845,argumentOfPerihelionDeg:308.4913086299446,perihelionJd:2460581242087108e-9},peakMagnitude:0,peakOn:"2024-10-14",absoluteMagnitude:3.97,activityExponent:4,tailLengthDeg:20,tailLengthAu:.1902,note:"Briefly reported far brighter around 9 October 2024, when it stood almost between the observer and the Sun and forward-scattered the light through its own dust — a geometry this catalog's brightness model does not attempt, so what is stored is the ordinary evening-sky peak a few days later."}];class Tl{static WINDOW_DAYS=200;static TWILIGHT_ELONGATION_DEG=15;static LIGHT_SPEED_AU_PER_DAY=173.144632674;static orbits=new Map;static aroundDate(e){const t=this.julianDayOf(e);return iv.filter(n=>Math.abs(t-n.orbit.perihelionJd)<=this.WINDOW_DAYS)}static brightestAt(e,t){return this.aroundDate(e).map(n=>this.appearanceOf(n,e,t)).sort((n,i)=>n.magnitude-i.magnitude)[0]}static appearanceOf(e,t,n){const i=Zt(t),s=this.earthPositionAt(i),r=this.apparentPositionOf(e,2451545+i.tt,s),o=this.subtract(r,s),l=this.length(r),c=this.length(o),h=this.tailEndAt(e,r,s,l,i,t,n),d=this.horizontalOf(o,i,t,n);return{apparition:e,position:d,...h,heliocentricDistanceAu:l,earthDistanceAu:c,elongationDeg:this.angleBetween(o,this.subtract({x:0,y:0,z:0},s)),magnitude:this.magnitudeAt(e,l,c)}}static magnitudeAt(e,t,n){const i=e.absoluteMagnitude+5*Math.log10(n)+2.5*e.activityExponent*Math.log10(t);return Math.max(i,e.peakMagnitude)}static tailEndAt(e,t,n,i,s,r,o){if(e.tailLengthAu===void 0)return{};const l=1+e.tailLengthAu/i,c=this.subtract({x:t.x*l,y:t.y*l,z:t.z*l},n),h=this.subtract(t,n);return{tailEnd:this.horizontalOf(c,s,r,o),tailLengthDeg:this.angleBetween(h,c)}}static apparentPositionOf(e,t,n){const i=this.orbitOf(e);let s=i.positionAt(t);for(let r=0;r<2;r++){const o=this.length(this.subtract(s,n))/this.LIGHT_SPEED_AU_PER_DAY;s=i.positionAt(t-o)}return s}static horizontalOf(e,t,n,i){const s=_l(yE(),new xt(e.x,e.y,e.z,t)),r=_l(bE(t),s),o=$_(t,new Xu(i.lat,i.lng,i.elevationM)),l=new xt(r.x-o.x,r.y-o.y,r.z-o.z,t),c=Vg(l);return rr(c.ra,c.dec,n,i)}static earthPositionAt(e){return _l(vE(),ws(Me.Earth,e))}static julianDayOf(e){return 2451545+Zt(e).tt}static orbitOf(e){const t=this.orbits.get(e.id);if(t)return t;const n=new zi(e.orbit);return this.orbits.set(e.id,n),n}static subtract(e,t){return{x:e.x-t.x,y:e.y-t.y,z:e.z-t.z}}static length(e){return Math.hypot(e.x,e.y,e.z)}static angleBetween(e,t){const n=(e.x*t.x+e.y*t.y+e.z*t.z)/(this.length(e)*this.length(t)||1);return Math.acos(Math.min(1,Math.max(-1,n)))*180/Math.PI}}const gT=[{id:"quadrantids",code:"QUA",name:{en:"Quadrantids",fr:"Quadrantides"},radiantRaHours:15.33,radiantDecDeg:49.7,start:{month:12,day:28},peak:{month:1,day:3},end:{month:1,day:12},peakZhr:110,velocityKmS:41,populationIndex:2.1},{id:"lyrids",code:"LYR",name:{en:"April Lyrids",fr:"Lyrides d'avril"},radiantRaHours:18.13,radiantDecDeg:33.3,start:{month:4,day:16},peak:{month:4,day:22},end:{month:4,day:25},peakZhr:18,velocityKmS:49,populationIndex:2.1},{id:"eta-aquariids",code:"ETA",name:{en:"eta Aquariids",fr:"Êta Aquarides"},radiantRaHours:22.53,radiantDecDeg:-1,start:{month:4,day:19},peak:{month:5,day:6},end:{month:5,day:28},peakZhr:50,velocityKmS:66,populationIndex:2.4},{id:"alpha-capricornids",code:"CAP",name:{en:"alpha Capricornids",fr:"Alpha Capricornides"},radiantRaHours:20.47,radiantDecDeg:-9.2,start:{month:7,day:3},peak:{month:7,day:30},end:{month:8,day:15},peakZhr:5,velocityKmS:23,populationIndex:2.5},{id:"southern-delta-aquariids",code:"SDA",name:{en:"Southern delta Aquariids",fr:"Delta Aquarides du Sud"},radiantRaHours:22.67,radiantDecDeg:-16.4,start:{month:7,day:12},peak:{month:7,day:30},end:{month:8,day:23},peakZhr:25,velocityKmS:41,populationIndex:3.2},{id:"perseids",code:"PER",name:{en:"Perseids",fr:"Perséides"},radiantRaHours:3.22,radiantDecDeg:58,start:{month:7,day:17},peak:{month:8,day:12},end:{month:8,day:24},peakZhr:100,velocityKmS:59,populationIndex:2.2},{id:"southern-taurids",code:"STA",name:{en:"Southern Taurids",fr:"Taurides du Sud"},radiantRaHours:3.47,radiantDecDeg:13,start:{month:9,day:10},peak:{month:10,day:10},end:{month:11,day:20},peakZhr:5,velocityKmS:27,populationIndex:2.3},{id:"draconids",code:"DRA",name:{en:"October Draconids",fr:"Draconides d'octobre"},radiantRaHours:17.47,radiantDecDeg:54,start:{month:10,day:6},peak:{month:10,day:8},end:{month:10,day:10},peakZhr:10,velocityKmS:20,populationIndex:2.6},{id:"orionids",code:"ORI",name:{en:"Orionids",fr:"Orionides"},radiantRaHours:6.35,radiantDecDeg:15.6,start:{month:10,day:2},peak:{month:10,day:21},end:{month:11,day:7},peakZhr:20,velocityKmS:66,populationIndex:2.5},{id:"northern-taurids",code:"NTA",name:{en:"Northern Taurids",fr:"Taurides du Nord"},radiantRaHours:3.87,radiantDecDeg:22,start:{month:10,day:20},peak:{month:11,day:12},end:{month:12,day:10},peakZhr:5,velocityKmS:29,populationIndex:2.3},{id:"leonids",code:"LEO",name:{en:"Leonids",fr:"Léonides"},radiantRaHours:10.13,radiantDecDeg:21.6,start:{month:11,day:6},peak:{month:11,day:17},end:{month:11,day:30},peakZhr:15,velocityKmS:71,populationIndex:2.5},{id:"geminids",code:"GEM",name:{en:"Geminids",fr:"Géminides"},radiantRaHours:7.47,radiantDecDeg:32.3,start:{month:12,day:4},peak:{month:12,day:14},end:{month:12,day:17},peakZhr:150,velocityKmS:35,populationIndex:2.6},{id:"ursids",code:"URS",name:{en:"Ursids",fr:"Ursides"},radiantRaHours:14.47,radiantDecDeg:75.3,start:{month:12,day:17},peak:{month:12,day:22},end:{month:12,day:26},peakZhr:10,velocityKmS:33,populationIndex:3}],io=6.5;class Za{static activeAt(e){return gT.flatMap(t=>{const n=this.nearness(t,e);return n<=0?[]:[{shower:t,zhr:t.peakZhr*n,nearness:n}]})}static nearness(e,t){const n=this.dayOfYear(t),i=this.dayOfYear(this.asDate(e.start)),s=this.dayOfYear(this.asDate(e.peak)),r=this.dayOfYear(this.asDate(e.end)),o=this.wrappedDelta(n,s),l=this.wrappedDelta(s,i),c=this.wrappedDelta(r,s);return o<0?o<-l?0:1+o/l:o>0?o>c?0:1-o/c:1}static observedRatePerHour(e,t,n,i=io){if(t<=0)return 0;const s=io-i;return e*Math.sin(t*Math.PI/180)/Math.pow(n,s)}static radiantPosition(e,t,n){return rr(e.radiantRaHours,e.radiantDecDeg,t,n)}static dayOfYear(e){const t=Date.UTC(e.getUTCFullYear(),0,1);return Math.floor((Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate())-t)/864e5)+1}static asDate(e){return new Date(Date.UTC(2001,e.month-1,e.day))}static wrappedDelta(e,t){const n=e-t;return n>182?n-365:n<-182?n+365:n}}class Et{static QUIET_RATE_PER_HOUR=2;static APEX_RATE_PER_HOUR=8;static POPULATION_INDEX=3;static apexPosition(e,t){const n=Zt(e),i=new Vu(0,Y_(e).elon-90,1),s=_l(xE(n),Gg(i,n)),r=Vg(s);return rr(r.ra,r.dec,e,t)}static observedRatePerHour(e,t=io){const n=Et.APEX_RATE_PER_HOUR*Math.max(0,Math.sin(e*Math.PI/180)),i=io-t;return(Et.QUIET_RATE_PER_HOUR+n)/Math.pow(Et.POPULATION_INDEX,i)}static schedule(e){const t=new Xg(e.seed^1542469173);return Ks.schedule(e).map(n=>{const i=Et.toCartesian({altitudeDeg:Math.asin(t.next())*180/Math.PI,azimuthDeg:t.between(0,360)}),s=n.fromRadiantDeg*Math.PI/180,r=Et.turnAround(i,t.between(0,360)),o={x:i.x*Math.cos(s)+r.x*Math.sin(s),y:i.y*Math.cos(s)+r.y*Math.sin(s),z:i.z*Math.cos(s)+r.z*Math.sin(s)};return{...n,radiant:Et.toHorizontal(o),bearingDeg:Et.bearingFrom(o,i)}})}static turnAround(e,t){const[n,i]=Et.basisAround(e),s=t*Math.PI/180;return{x:n.x*Math.cos(s)+i.x*Math.sin(s),y:n.y*Math.cos(s)+i.y*Math.sin(s),z:n.z*Math.cos(s)+i.z*Math.sin(s)}}static bearingFrom(e,t){const[n,i]=Et.basisAround(e),s=e.x*t.x+e.y*t.y+e.z*t.z,r=Et.normalise({x:t.x-e.x*s,y:t.y-e.y*s,z:t.z-e.z*s});return(Math.atan2(r.x*i.x+r.y*i.y+r.z*i.z,r.x*n.x+r.y*n.y+r.z*n.z)*180/Math.PI%360+360)%360}static basisAround(e){const t=Math.abs(e.y)<.9?{x:0,y:1,z:0}:{x:1,y:0,z:0},n=Et.normalise(Et.cross(e,t));return[n,Et.normalise(Et.cross(e,n))]}static toHorizontal(e){const t=Math.hypot(e.x,e.y,e.z)||1;return{altitudeDeg:Math.asin(Math.min(1,Math.max(-1,e.y/t)))*180/Math.PI,azimuthDeg:(Math.atan2(e.x,-e.z)*180/Math.PI%360+360)%360}}static appearanceOf(e){const t=Et.toCartesian(e.radiant??{altitudeDeg:90,azimuthDeg:0}),n=Et.turnAround(t,e.bearingDeg),i=e.fromRadiantDeg*Math.PI/180;return Et.toHorizontal({x:t.x*Math.cos(i)+n.x*Math.sin(i),y:t.y*Math.cos(i)+n.y*Math.sin(i),z:t.z*Math.cos(i)+n.z*Math.sin(i)})}static toCartesian(e){const t=e.altitudeDeg*Math.PI/180,n=e.azimuthDeg*Math.PI/180,i=Math.cos(t);return{x:i*Math.sin(n),y:Math.sin(t),z:-i*Math.cos(n)}}static cross(e,t){return{x:e.y*t.z-e.z*t.y,y:e.z*t.x-e.x*t.z,z:e.x*t.y-e.y*t.x}}static normalise(e){const t=Math.hypot(e.x,e.y,e.z)||1;return{x:e.x/t,y:e.y/t,z:e.z/t}}static TYPICAL_VELOCITY_KM_S=40}class vT{lowerM;upperM;add(e,t){if(!(e<=0)){if(t.behindM!==void 0){const n=et.sizeMAt(t.behindM,e);this.lowerM=this.lowerM===void 0?n:Math.max(this.lowerM,n)}if(t.inFrontM!==void 0){const n=et.sizeMAt(t.inFrontM,e);this.upperM=this.upperM===void 0?n:Math.min(this.upperM,n)}}}get sizeRange(){return{minM:this.lowerM,maxM:this.upperM}}get empty(){return this.lowerM===void 0&&this.upperM===void 0}get contradictory(){return this.lowerM!==void 0&&this.upperM!==void 0&&this.lowerM>this.upperM}distanceRangeAt(e){return e<=0?{}:{minM:this.lowerM===void 0?void 0:et.distanceMAt(this.lowerM,e),maxM:this.upperM===void 0?void 0:et.distanceMAt(this.upperM,e)}}clear(){this.lowerM=void 0,this.upperM=void 0}}class Ja{static DEG_PER_SECOND=360/86164.0905;static degOver(e){return Math.max(0,e)*Ja.DEG_PER_SECOND}static instants(e,t){if(!(t>0))return 1;const n=Ja.degOver(e)/t;return n<1?1:Math.min(Ja.MAX_INSTANTS,Math.max(2,Math.ceil(n)))}static MAX_INSTANTS=64}class hn{static EYE={apertureMm:7,exposureSeconds:.1,resolutionArcsec:60};static WAVELENGTH_M=55e-8;static ARCSEC_PER_RADIAN=180*3600/Math.PI;static UNKNOWN_CAMERA_FOCAL_MM=50;static UNKNOWN_CAMERA_DETAIL_UM=20;static get skyDriftArcsecPerSecond(){return Ja.DEG_PER_SECOND*3600}static graspOf(e,t={}){const n=t.exposureSeconds??e.exposureSeconds,i=t.fNumber??e.fNumber;if(n===void 0||i===void 0||!(n>0)||!(i>0))return hn.EYE;const s=t.focalLengthMm??e.frame?.focalLengthMm??hn.UNKNOWN_CAMERA_FOCAL_MM,r=s/i,o=hn.resolutionArcsec(e,s,r);return{apertureMm:r,exposureSeconds:Math.min(n,hn.trailLimitedSeconds(o)),resolutionArcsec:o}}static resolutionArcsec(e,t,n){const s=(e.detailUm??hn.UNKNOWN_CAMERA_DETAIL_UM)/1e3/t*hn.ARCSEC_PER_RADIAN,r=1.22*hn.WAVELENGTH_M/(n/1e3)*hn.ARCSEC_PER_RADIAN;return Math.max(s,r)}static trailLimitedSeconds(e){return e/hn.skyDriftArcsecPerSecond}static gainOverEye(e,t={}){const n=hn.graspOf(e,t),i=hn.EYE,s=(n.apertureMm/i.apertureMm)**2,r=n.exposureSeconds/i.exposureSeconds,o=(i.resolutionArcsec/n.resolutionArcsec)**2;return 1.25*Math.log10(s*r*o)}static gainFor(e,t){const n=t.fieldOfViewDeg===void 0?void 0:st.focalLengthMmFor(e,t.fieldOfViewDeg);return hn.gainOverEye(e,{fNumber:t.fNumber,focalLengthMm:n,exposureSeconds:t.exposureSeconds})}}class Hi{static PIXELS_PER_INSTANT=2;static INSTANTS_PER_FLASH=2;static MAX_INSTANTS=512;static instants(e,t,n,i,s){if(!(i>0))return 1;const r=s>0?Hi.travelDegOver(e,t,n,n+i*1e3)/s/Hi.PIXELS_PER_INSTANT:0,o=Hi.flashesOver(e,i)*Hi.INSTANTS_PER_FLASH,l=Math.ceil(Math.max(r,o));return l<2?1:Math.min(Hi.MAX_INSTANTS,l)}static travelDegOver(e,t,n,i){let s=0;for(const r of e){if(!r.track||r.track.length<2)continue;const o=Hi.directionAt(r,t,n),l=Hi.directionAt(r,t,i),c=Math.min(1,Math.max(-1,o.x*l.x+o.y*l.y+o.z*l.z));s=Math.max(s,Math.acos(c)*180/Math.PI)}return s}static flashesOver(e,t){let n=0;for(const i of e)for(const s of i.lights??[])s.pattern.kind==="flash"&&(n=Math.max(n,s.pattern.perMinute));return n/60*t}static directionAt(e,t,n){const i=Qa(e,n),s=i.eastM,r=i.altitudeM-t,o=i.northM,l=Math.hypot(s,r,o);return l===0?{x:0,y:1,z:0}:{x:s/l,y:r/l,z:o/l}}}const tm=111320,Cr=Math.PI/180,yT=1.02,bT=1;class qr{static of(e,t){const n=qr.sightings(e,t);if(n.length<2)return;const i=qr.baseline(n);if(!i)return;const{near:s,far:r,closedM:o}=i,l=Math.tan(r.widthDeg/2*Cr)===0?0:Math.tan(s.widthDeg/2*Cr)/Math.tan(r.widthDeg/2*Cr);if(l<yT)return;const c=o/(l-1),h=et.sizeMAt(c,s.widthDeg),d=n.map(u=>({t:u.t,m:et.distanceMAt(h,u.widthDeg)}));return{widthM:h,distanceM:d,nearestM:Math.min(...d.map(u=>u.m)),fromT:r.t,toT:s.t,closedM:o}}static sightings(e,t){return e.timeline.allKeyframes.flatMap(n=>{const i=n.shapes.find(o=>o.sourceId===t)?.shape,s=i?.angular?.widthDeg,r=at(e,n.t);return s===void 0||s<=0||r?.lat===void 0||r.lng===void 0?[]:[{t:n.t,widthDeg:s,lat:r.lat,lng:r.lng,sightAzimuthDeg:i?.aim?.azimuthDeg??r.headingDeg}]}).sort((n,i)=>n.t-i.t)}static baseline(e){let t;for(const n of e)for(const i of e){if(n.t>=i.t)continue;const s=qr.closedAlongSight(n,i),[r,o,l]=s>=0?[i,n,s]:[n,i,-s];l<bT||r.widthDeg<=o.widthDeg||(!t||l>t.closedM)&&(t={near:r,far:o,closedM:l})}return t}static closedAlongSight(e,t){const n=(t.lat-e.lat)*tm,i=(t.lng-e.lng)*tm*Math.cos(e.lat*Cr),s=(e.sightAzimuthDeg??0)*Cr;return n*Math.cos(s)+i*Math.sin(s)}}class yn{static CONVENTIONAL_M=5;static NEAREST_M=.2;static MARGIN=1.1;static resolve(e){if(e.statedM!==void 0&&e.statedM>0)return{distanceM:yn.atLeastNearest(e.statedM),basis:"stated"};if(e.hypothesisM!==void 0&&e.hypothesisM>0)return{distanceM:yn.atLeastNearest(e.hypothesisM),basis:"hypothesis"};if(e.derivedM!==void 0&&e.derivedM>0)return{distanceM:yn.atLeastNearest(e.derivedM),basis:"derived"};const t=yn.largest(e.range?.minM,e.crossing?.behindM),n=yn.smallest(e.range?.maxM,e.crossing?.inFrontM),i=t===void 0?void 0:t*yn.MARGIN,s=n===void 0?void 0:n/yn.MARGIN;return i!==void 0&&s!==void 0?{distanceM:yn.atLeastNearest(i<=s?Math.sqrt(i*s):i),basis:"bounded"}:i!==void 0?{distanceM:yn.atLeastNearest(i),basis:"bounded"}:s!==void 0&&s<yn.CONVENTIONAL_M?{distanceM:yn.atLeastNearest(s),basis:"bounded"}:{distanceM:yn.CONVENTIONAL_M,basis:"conventional"}}static atLeastNearest(e){return Math.max(yn.NEAREST_M,e)}static largest(...e){const t=e.filter(n=>n!==void 0&&n>0);return t.length===0?void 0:Math.max(...t)}static smallest(...e){const t=e.filter(n=>n!==void 0&&n>0);return t.length===0?void 0:Math.min(...t)}}Ql();const xT={sun:{en:"Sun",fr:"Soleil"},moon:{en:"Moon",fr:"Lune"},Venus:{en:"Venus",fr:"Vénus"},Mars:{en:"Mars",fr:"Mars"},Jupiter:{en:"Jupiter",fr:"Jupiter"},Saturn:{en:"Saturn",fr:"Saturne"}},wT=["en","fr"],MT={en:"{name} — mag {mag}, {alt}° above the horizon",fr:"{name} — mag {mag}, {alt}° au-dessus de l'horizon"},ST={en:"{name} — mag {mag}, {alt}° below the horizontal",fr:"{name} — mag {mag}, {alt}° sous l'horizontale"},nm="comet:",_T={building:{en:"Building",fr:"Bâtiment"},tree:{en:"Tree",fr:"Arbre"},crop:{en:"Crop row",fr:"Rang de culture"},mound:{en:"Stone heap",fr:"Tas de pierres"},streetlight:{en:"Streetlight",fr:"Lampadaire"},vehicle:{en:"Vehicle",fr:"Véhicule"},witness:{en:"Witness",fr:"Témoin"},aircraft:{en:"Aircraft",fr:"Aéronef"},entity:{en:"Being",fr:"Être"}},ET=new URL(""+new URL("stars-mag7.5-B43R6Wvg.bin",import.meta.url).href,import.meta.url).href,TT=new URL(""+new URL("stars-mag7.5-9-BLV2tFmZ.bin",import.meta.url).href,import.meta.url).href,AT=-18,IT={sun:{altitudeDeg:-3,azimuthDeg:180,magnitude:-26.7},moon:{altitudeDeg:-90,azimuthDeg:0,phase:{phaseFraction:0,illuminatedFraction:0},magnitude:-12.7},planets:[]},Eh={lat:0,lng:0,elevationM:0,headingDeg:void 0,pitchDeg:0,fovDeg:60};class DT extends HTMLElement{static get observedAttributes(){return["src","star-catalog-src","deep-star-catalog-src","show-compass",Ys,Ha]}shadow;stageElement;frameElement;sceneCanvas;ufoElement;sceneRenderer;hoverTooltip;resizeObserver;sizeEstimates=new Map;sizeEstimatesFor;distanceHypotheses=new Map;depths=new Map;directionScratch=new P;meteorScheduleFor;lastTimeMs=0;lastSkyKey;starCatalog;starCatalogRequest=0;starCatalogDepth=0;weatherAudio=new mT;animateWhilePausedValue=!1;set animateWhilePaused(e){e!==this.animateWhilePausedValue&&(this.animateWhilePausedValue=e,this.syncAnimationsToPlayback())}get animateWhilePaused(){return this.animateWhilePausedValue}thunderTimeoutId;handleFullscreenChange=()=>this.resizeToStage();handlePointerMove=e=>{this.sceneRenderer.setCompassHovered(!0);const t=this.ufoElement.canvasElement,n=t.getBoundingClientRect();if(n.width===0||n.height===0)return;const i=(e.clientX-n.left)/n.width*t.width,s=(e.clientY-n.top)/n.height*t.height;if(this.ufoElement.hasVisibleShapeAt(i,s)){this.hoverTooltip.hidden=!0;return}const r=(e.clientX-n.left)/n.width*2-1,o=-((e.clientY-n.top)/n.height*2-1),l=za(vs.preferencesFor(this),wT),c=this.sceneRenderer.pickBodyAt(r,o);if(c){this.showHoverTooltip(e,this.bodyName(c,l));return}const h=this.sceneRenderer.pickDecorAt(r,o),d=h?this.ufoElement.sighting.decor.find(f=>f.id===h):void 0;if(d){this.showHoverTooltip(e,this.said.read(d.title)||_T[d.kind][l]);return}const u=this.sceneRenderer.pickStarAt(r,o);if(u){const f=u.star.mag,p=u.altitudeDeg,v=(p<0?ST:MT)[l];this.showHoverTooltip(e,v.replace("{name}",u.star.name[l]).replace("{mag}",f.toLocaleString(void 0,{maximumFractionDigits:Math.abs(f)<1?2:1})).replace("{alt}",String(Math.round(Math.abs(p)))));return}this.hoverTooltip.hidden=!0};bodyName(e,t){const n=e.startsWith(nm)?e.slice(nm.length):void 0;return(n?iv.find(s=>s.id===n):void 0)?.name[t]??xT[e]?.[t]??e}showHoverTooltip(e,t){this.hoverTooltip.textContent=t,this.hoverTooltip.hidden=!1;const n=this.stageElement.getBoundingClientRect();this.hoverTooltip.style.left=`${e.clientX-n.left+12}px`,this.hoverTooltip.style.top=`${e.clientY-n.top+12}px`}handlePointerLeave=()=>{this.hoverTooltip.hidden=!0,this.sceneRenderer.setCompassHovered(!1)};handleLightningFlash=()=>{clearTimeout(this.thunderTimeoutId);const e=(.5+Math.random()*3.5)*1e3;this.thunderTimeoutId=window.setTimeout(()=>this.weatherAudio.playThunder(),e)};handleFirstInteraction=()=>{this.weatherAudio.resume(),this.setWeather(Ft(this.ufoElement.sighting,this.lastTimeMs))};handleTimeUpdate=e=>{this.lastTimeMs=e.detail.time,this.syncAnimationsToPlayback(),this.updateAstronomy(this.lastTimeMs)};syncAnimationsToPlayback(){const e=this.ufoElement.playbackState==="playing"||this.animateWhilePaused;this.sceneRenderer.setAnimationsRunning(e),this.weatherAudio.setPaused(!e),e||clearTimeout(this.thunderTimeoutId)}constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${C1}</style>${D1}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.stageElement=this.shadow.getElementById("stage"),this.frameElement=this.shadow.getElementById("frame"),this.sceneCanvas=this.shadow.getElementById("scene-canvas"),this.sceneRenderer=new mi(this.sceneCanvas,void 0,this.handleLightningFlash),this.hoverTooltip=this.shadow.getElementById("hover-tooltip"),this.ufoElement=document.createElement(Gh),this.ufoElement.classList.add("ufo-overlay"),this.ufoElement.paintsShapes=!1,this.forwardPlayerAttributes(),this.ufoElement.addEventListener("lookat",t=>this.lookToward(t.detail)),this.ufoElement.style.setProperty("--ufo-canvas-background","transparent"),this.ufoElement.style.setProperty("--ufo-canvas-border","none"),this.ufoElement.fullscreenTarget=this.stageElement,this.shadow.getElementById("ufo-slot").replaceWith(this.ufoElement),this.ufoElement.addEventListener("timeupdate",this.handleTimeUpdate),this.ufoElement.canvasElement.addEventListener("pointermove",this.handlePointerMove),this.ufoElement.canvasElement.addEventListener("pointerleave",this.handlePointerLeave),this.ufoElement.canvasElement.addEventListener("pointerdown",this.handleFirstInteraction,{once:!0})}get said(){return this.saidTexts??=new Gi(vs.preferencesFor(this))}saidTexts;connectedCallback(){this.saidTexts=void 0,this.resizeToStage(),this.updateAstronomy(this.lastTimeMs),this.loadStars(),this.resizeObserver=new ResizeObserver(()=>this.resizeToStage()),this.resizeObserver.observe(this.frameElement),document.addEventListener("fullscreenchange",this.handleFullscreenChange);const e=this.getAttribute("src");e&&this.loadFromSrc(e)}disconnectedCallback(){this.resizeObserver?.disconnect(),document.removeEventListener("fullscreenchange",this.handleFullscreenChange),this.sceneRenderer.stopTwinkle(),clearTimeout(this.thunderTimeoutId),this.weatherAudio.dispose()}attributeChangedCallback(e,t,n){e==="src"&&n&&n!==t&&this.isConnected&&this.loadFromSrc(n),(e==="star-catalog-src"||e==="deep-star-catalog-src")&&n!==t&&this.isConnected&&this.loadStars(),e==="show-compass"&&n!==t&&this.sceneRenderer.setShowCompass(this.hasAttribute("show-compass")),(e===Ys||e===Ha)&&n!==t&&this.forwardPlayerAttributes()}forwardPlayerAttributes(){for(const e of[Ys,Ha])this.ufoElement.toggleAttribute(e,this.hasAttribute(e))}setCompassForced(e){this.sceneRenderer.setCompassForced(e)}lookToward(e){const t=at(this.ufoElement.sighting,this.lastTimeMs);if(e.kind==="witness"||t?.lat===void 0||t.lng===void 0||t.headingDeg===void 0){this.setLookOffset(0,0);return}const{x:n,z:i}=un(e.lat,e.lng,t.lat,t.lng);if(Math.hypot(n,i)<1)return this.setLookOffset(0,0);const s=(Math.atan2(n,-i)*180/Math.PI+360)%360;this.setLookOffset(((s-t.headingDeg)%360+540)%360-180,-t.pitchDeg)}setLookOffset(e,t){this.sceneRenderer.setLookOffset(e,t),this.ufoElement.setLookOffset(e,t),this.updateAstronomy(this.lastTimeMs)}setIndoorLook(e,t){this.sceneRenderer.setIndoorLook(e,t)}setCloudRendering(e){this.sceneRenderer.setCloudRendering(e)}setWeather(e){this.sceneRenderer.setWeather(e),this.weatherAudio.setAmbient(e.precipitationType,e.precipitationIntensity,e.windSpeed)}pickCloudAt(e,t){return this.sceneRenderer.pickCloudAt(e,t)}cloudDirectionAt(e,t){return this.sceneRenderer.cloudDirectionAt(e,t)}pickDecorAt(e,t){return this.sceneRenderer.pickDecorAt(e,t)}resumeWeatherAudio(){this.weatherAudio.resume()}async loadFromSrc(e){this.sightingData=await fu.json(e)}get sightingData(){return this.ufoElement.sightingData}set sightingData(e){this.ufoElement.sightingData=e,this.applyFrameFormat(),this.lastTimeMs=0,this.updateAstronomy(0)}get currentTerrainAttribution(){return this.sceneRenderer.currentTerrainAttribution}setTerrainProviders(e){this.sceneRenderer.setTerrainProviders(e)}setDecorModelProvider(e){this.sceneRenderer.setDecorModelProvider(e)}get decorModelCredits(){return this.sceneRenderer.currentDecorModelCredits}applyFrameFormat(){const e=this.ufoElement.sighting.instrument,t=et.CANVAS_HEIGHT_PX,n=st.frameWidthPx(e,t);this.frameElement.style.setProperty("--frame-aspect",`${n} / ${t}`)}resizeToStage(){const e=this.frameElement.getBoundingClientRect(),t=Math.max(1,Math.round(e.width)),n=Math.max(1,Math.round(e.height));this.sceneCanvas.width=t,this.sceneCanvas.height=n,this.sceneRenderer.resize(t,n)}async loadStars(){const e=[{magnitudeLimit:_h,url:this.getAttribute("star-catalog-src")??ET},{magnitudeLimit:Xr,url:this.getAttribute("deep-star-catalog-src")??TT}],t=this.instrumentReach(),n=++this.starCatalogRequest;this.starCatalogDepth=t>_h?Xr:_h;const i=await gi.upTo(e,t);n===this.starCatalogRequest&&(this.starCatalog=i,this.updateAstronomy(this.lastTimeMs))}ensureStarsDeepEnough(){!this.starCatalog||this.starCatalogDepth>=Xr||this.instrumentReach()<=this.starCatalogDepth||this.loadStars()}instrumentReach(){const e=this.ufoElement.sighting,t=hn.gainFor(e.instrument,{fNumber:at(e,0)?.fNumber,fieldOfViewDeg:an.fovOf(e,0),exposureSeconds:e.exposure});return Hr(AT,t)}updateAstronomy(e){this.ensureStarsDeepEnough(),this.applySceneAt(e);const t=this.exposureSeconds(),n=this.degreesPerPixelAt(e),i=Ja.instants(t,n),s=Math.max(i,this.ufoElement.exposureTimes(e).length,Hi.instants(this.ufoElement.sighting.decor,at(this.ufoElement.sighting,e)?.elevationM??0,e,t,n));if(s<=1){this.sceneRenderer.setExposure(1);return}const r=t*1e3;this.sceneRenderer.setExposure(s,o=>this.applySceneAt(e+r*o/s,{sky:Math.floor(o*i/s)!==Math.floor((o-1)*i/s),stepMs:r/s}))}exposureSeconds(){return this.ufoElement.sighting.exposure??0}degreesPerPixelAt(e){const t=this.sceneCanvas.height;return t<=0?0:an.fovOf(this.ufoElement.sighting,e)/t}applySceneAt(e,t){const n=this.ufoElement.sighting;this.setWeather(Ft(n,e)),this.sceneRenderer.setInstrument(n.instrument),this.updateMeteorShower(n,e),this.sceneRenderer.setDecor(n.decor);const i=at(n,e),s=at(n,0),r=Ft(n,0),o=Object.fromEntries(_i(Ft(n,e)).map(g=>[g.id,Il(e,n.weatherTrack,r,s,i,g.id)]));if(this.sceneRenderer.setCloudOffset(Il(e,n.weatherTrack,r,s,i),o),this.sceneRenderer.setObserverPose(i??Eh),this.sceneRenderer.setLensOptics(this.lensOpticsAt(e)),this.sceneRenderer.setInstrumentGain(hn.gainFor(n.instrument,{fNumber:i?.fNumber,fieldOfViewDeg:an.fovOf(n,e),exposureSeconds:n.exposure})),this.sceneRenderer.setGait(qt.of(n)?.offsetAt(e)??qt.STILL),this.sceneRenderer.updateDecorAnchoring(at(n,0),i,e),this.sceneRenderer.updateDecorLitState(e,t?.stepMs??0),this.sceneRenderer.setTerrainOrigin(i?.lat,i?.lng),this.pushPhenomenaAt(e),t&&!t.sky)return;const l=i?.lat??Eh.lat,c=i?.lng??Eh.lng,h=Ka(n.event.time??{},c,n.event.utcOffsetHours);if(!h){this.sceneRenderer.setAstronomy(IT);return}const d=new Date(h.getTime()+e),u={lat:l,lng:c,elevationM:i?.elevationM??0},f=`${d.getTime()}|${l}|${c}|${u.elevationM}|${this.starCatalog?this.starCatalogDepth:0}`;if(f===this.lastSkyKey){this.sceneRenderer.render();return}this.lastSkyKey=f;const p={...Un("Sun",d,u),magnitude:rh("Sun",d)},v={...Un("Moon",d,u),phase:Kl(d),magnitude:rh("Moon",d)},m=wE.map(g=>({body:g,position:Un(g,d,u),magnitude:rh(g,d)}));this.sceneRenderer.setAstronomy({sun:p,moon:v,planets:m,comet:this.cometAt(d,u),stars:this.starCatalog?{catalog:this.starCatalog,date:d,observer:u}:void 0,frame:{date:d,observer:u}}),this.ufoElement.setSunAltitude(p.altitudeDeg)}cometAt(e,t){const n=Tl.brightestAt(e,t);if(n)return{id:n.apparition.id,position:n.position,tailEnd:n.tailEnd,magnitude:n.magnitude}}pushPhenomenaAt(e){const t=this.ufoElement.sighting;t!==this.sizeEstimatesFor&&(this.sizeEstimates.clear(),this.distanceHypotheses.clear(),this.sizeEstimatesFor=t);const n=t.timeline,i=this.ufoElement.canvasElement,s=this.ufoElement.frameShiftPx,r=this.projectionAt(e),o=new Map,l=new Map,c=new Set;for(const p of n.sourceIds){const v=n.getInterpolatedShapeAt(e,p);if(!v)continue;const m={...v,bounds:{...v.bounds,x:v.bounds.x+s.x,y:v.bounds.y+s.y}};o.set(p,m);const g=v.aim?this.sceneRenderer.screenPointOf(jn.directionOf(v.aim,this.directionScratch)):{ndcX:(m.bounds.x+m.bounds.width/2)/i.width*2-1,ndcY:-((m.bounds.y+m.bounds.height/2)/i.height*2-1)},_=g!==void 0&&Math.abs(g.ndcX)<=1&&Math.abs(g.ndcY)<=1,M=_?this.sceneRenderer.decorDistancesAt(g.ndcX,g.ndcY,p):{};c.add(p),(_||v.aim)&&c.delete(p);const x=v.angular?.widthDeg??r.pxToDeg(v.bounds.width),w=this.sizeEstimateOf(p);w.add(x,M);const E=qr.of(t,p);l.set(p,yn.resolve({hypothesisM:this.distanceHypotheses.get(p),derivedM:E&&x>0?et.distanceMAt(E.widthM,x):void 0,range:w.distanceRangeAt(x),crossing:M}))}for(const[p,v]of o)for(const[m,g]of o){if(m===p||g.transparency>=1||g.bounds.width*g.bounds.height<=v.bounds.width*v.bounds.height||!(v.bounds.x>=g.bounds.x&&v.bounds.y>=g.bounds.y&&v.bounds.x+v.bounds.width<=g.bounds.x+g.bounds.width&&v.bounds.y+v.bounds.height<=g.bounds.y+g.bounds.height))continue;const M=l.get(m);M&&l.set(p,{distanceM:M.distanceM*.999,basis:M.basis});break}this.depths=l;const h=n.sourceIds,d=[];for(const[p,v]of o)d.push({sourceId:p,shape:v,distanceM:l.get(p).distanceM,renderOrder:h.indexOf(p),aim:v.aim,hidden:c.has(p)});const f=(at(t,e)?.rollDeg??0)+(qt.of(t)?.offsetAt(e)??qt.STILL).rollDeg;this.sceneRenderer.setPhenomena(d,{projection:r,canvasWidthPx:i.width,canvasHeightPx:i.height,scale:Math.max(1,this.sceneCanvas.height/Math.max(1,i.height)),starPoints:st.starPointsOf(t.instrument),rollRad:f*Math.PI/180})}setDistanceHypothesis(e,t){t===void 0||!(t>0)?this.distanceHypotheses.delete(e):this.distanceHypotheses.set(e,t),this.updateAstronomy(this.lastTimeMs)}depthOf(e){return this.depths.get(e)}sizeRangeOf(e){return this.sizeEstimateOf(e).sizeRange}distanceRangeAt(e,t){const n=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(t,e);if(!n)return{};const i=n.angular?.widthDeg??this.projectionAt(t).pxToDeg(n.bounds.width);return this.sizeEstimateOf(e).distanceRangeAt(i)}sizeContradictory(e){return this.sizeEstimateOf(e).contradictory}updateMeteorShower(e,t){this.ensureMeteorSchedule(e),this.sceneRenderer.updateMeteors(t)}ensureMeteorSchedule(e){const t=this.meteorInputsOf(e);t!==this.meteorScheduleFor&&(this.meteorScheduleFor=t,this.scheduleMeteors(e))}meteorInputsOf(e){const t=e.event.place?.[0],n=e.event.time;return JSON.stringify([t?.lat,t?.lng,n?.year,n?.month,n?.day,n?.hour,n?.minute,e.event.utcOffsetHours,e.event.durationSeconds,e.timeline.duration])}scheduleMeteors(e){const t=e.event.place?.[0],n=e.event.time,i=t?.lat!==void 0&&t.lng!==void 0&&n?.year!==void 0?Ka(n,t.lng,e.event.utcOffsetHours):void 0;if(!i||t?.lat===void 0||t.lng===void 0){this.sceneRenderer.setMeteorShower([],0,0);return}const s={lat:t.lat,lng:t.lng,elevationM:0},r=(e.event.durationSeconds??0)*1e3||e.timeline.duration||2e4,o=Math.round(i.getTime()/1e3)+Math.round(t.lat*1e3),l=Et.schedule({ratePerHour:Et.observedRatePerHour(Et.apexPosition(i,s).altitudeDeg),durationMs:r,velocityKmS:Et.TYPICAL_VELOCITY_KM_S,seed:o}),c=Za.activeAt(i).map(d=>{const u=Za.radiantPosition(d.shower,i,s);return{entry:d,position:u,rate:Za.observedRatePerHour(d.zhr,u.altitudeDeg,d.shower.populationIndex)}}).sort((d,u)=>u.rate-d.rate)[0];if(!c||c.rate<=0){this.sceneRenderer.setMeteorShower(l,0,0);return}const h=Ks.schedule({ratePerHour:c.rate,durationMs:r,velocityKmS:c.entry.shower.velocityKmS,seed:o+1});this.sceneRenderer.setMeteorShower([...h,...l],c.position.altitudeDeg,c.position.azimuthDeg)}meteorByRank(e){this.ensureMeteorSchedule(this.ufoElement.sighting);const t=[...this.sceneRenderer.meteorSchedule].filter(s=>s.t+s.durationMs<=this.ufoElement.seekableDuration).sort((s,r)=>r.brightness-s.brightness);if(t.length===0)return;const n=t[e%t.length],i=this.sceneRenderer.meteorMidpoint(n);if(i)return{t:Math.round(n.t+n.durationMs*.45),...i}}lensOpticsAt(e){const t=this.ufoElement.sighting,n=t.instrument,i=n.frame,s=at(t,e),r=s?.fNumber??n.fNumber;if(!i||r===void 0)return;const o=st.focalLengthMmFor(n,an.fovOf(t,e));if(o!==void 0)return{focalLengthMm:o,fNumber:r,focusDistance:s?.focusDistanceM??0,frameHeightMm:i.heightMm}}projectionAt(e){const t=this.ufoElement.sighting;return ni.of(t.instrument,et.CANVAS_HEIGHT_PX,an.fovOf(t,e))}sizeEstimateOf(e){let t=this.sizeEstimates.get(e);return t||(t=new vT,this.sizeEstimates.set(e,t)),t}}const hu="rr0-scene";function CT(){Ql(),customElements.get(hu)||customElements.define(hu,DT)}class RT{constructor(e,t){this.timeline=e,this.clock=t}currentPointer=null;shapePrototype=null;sourceId="";start(e,t){this.sourceId=e,this.shapePrototype=t,this.currentPointer=null,this.clock.start(n=>this.recordSample(n))}onPointerMove(e,t){this.currentPointer={x:e,y:t}}stop(){this.clock.stop()}recordSample(e){if(!this.currentPointer||!this.shapePrototype)return;const t=wm(this.shapePrototype,this.currentPointer.x,this.currentPointer.y);this.timeline.addKeyframe(e,[{sourceId:this.sourceId,shape:t}])}}class PT{constructor(e){this.intervalMs=e}rafId=null;startTime=0;lastTick=0;start(e){this.startTime=performance.now(),this.lastTick=0;const t=()=>{const n=performance.now()-this.startTime;n-this.lastTick>=this.intervalMs&&(this.lastTick=n,e(n)),this.rafId=requestAnimationFrame(t)};this.rafId=requestAnimationFrame(t)}stop(){this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null)}}const LT=[{id:"echo",name:{en:"the Echo balloons",fr:"les ballons Echo"},from:"1960-08-12",to:"1969-06-07",peakMagnitude:-1,note:"Echo 1 and 2 were 30- and 40-metre reflective balloons, as bright as the brightest stars and moving slowly enough to be watched — deliberately visible, widely announced in newspapers, and the first objects most people ever saw crossing the night sky. They fall squarely inside the sighting waves this project reconstructs."},{id:"iridium-flares",name:{en:"the Iridium flares",fr:"les flashes d'Iridium"},from:"1997-05-05",to:"2019-12-27",peakMagnitude:-8,note:"The original Iridium satellites carried flat, mirror-finish antennas that threw a sunbeam a few kilometres wide across the ground: a still point of sky flaring to magnitude -8 over five seconds and vanishing again. Nothing else in the sky does that."},{id:"iss",name:{en:"the International Space Station",fr:"la Station spatiale internationale"},from:"1998-11-20",peakMagnitude:-5.9,note:"Since its first module, and much brighter as it grew: at its best it outshines everything in the sky but the Sun and the Moon, crossing in a straight silent line in about four minutes."},{id:"starlink-trains",name:{en:"the Starlink trains",fr:"les trains de Starlink"},from:"2019-05-24",peakMagnitude:1,note:"In the days after a launch, satellites still bunched in their deployment string cross as an evenly spaced line of lights — the most reported 'formation of UFOs' of the era. They spread out within weeks, so a train is a fact about the days after a launch rather than about the year."}],NT=23493,im=[2,3,2,1,2,5,4,6,5,6,6,6,6,6,6,6,9,9,9,9,9,9,14,14,15,16,16,16,16,16,18,22,25,24,29,28,29,33,34,35,40,40,42,42,43,46,48,48,49,53,53,54,58,61,70,70,74,78,79,83,92,92,99,97,101,102,109,115,126,125,123,125,127,130,139,153,157,156,161,156,165,174,193,193,201,203,212,215,224,244,255,263,262,281,293,307,312,327,339,336,343,353,359,369,386,396,405,410,421,419,424,434,443,450,460,480,492,504,509,516,519,524,527,530,527,535,543,549,564,571,573,576,582,584,600,600,608,618,625,632,637,642,648,654,661,667,669,667,671,671,697,692,703,697,710,714,724,731,747,755,764,770,782,802,801,815,819,837,846,856,878,881,877,900,906,907,917,932,932,936,954,973,989,986,991,990,1002,1009,1021,1024,1040,1038,1058,1078,1098,1092,1094,1099,1122,1132,1140,1151,1154,1161,1176,1185,1202,1206,1227,1228,1243,1265,1281,1288,1296,1325,1328,1336,1354,1373,1375,1393,1398,1411,1432,1457,1462,1476,1487,1485,1506,1509,1521,1524,1537,1543,1563,1586,1598,1614,1621,1620,1640,1658,1660,1673,1670,1686,1708,1715,1726,1726,1745,1749,1767,1774,1790,1798,1803,1805,1815,1818,1819,1820,1833,1822,1821,1819,1838,1835,1845,1841,1851,1869,1865,1868,1871,1870,1879,1882,1886,1900,1899,1908,1921,1928,1954,1966,1976,1986,1999,2007,2015,2030,2036,2057,2067,2072,2077,2088,2101,2106,2112,2119,2127,2142,2171,2176,2203,2226,2242,2241,2244,2254,2263,2284,2300,2320,2327,2345,2364,2367,2402,2423,2425,2434,2443,2461,2476,2495,2505,2520,2531,2535,2556,2567,2599,2608,2625,2639,2660,2663,2668,2681,2695,2702,2709,2719,2720,2738,2746,2763,2778,2788,2796,2807,2822,2831,2831,2853,2863,2866,2883,2892,2895,2921,2919,2937,2941,2947,2964,2987,2992,2987,2995,3002,3021,3025,3026,3036,3052,3049,3059,3077,3075,3083,3086,3107,3123,3124,3146,3155,3168,3179,3204,3205,3211,3233,3252,3253,3276,3287,3294,3293,3297,3314,3326,3335,3338,3355,3362,3358,3365,3364,3376,3375,3382,3418,3429,3432,3455,3463,3483,3490,3502,3509,3521,3532,3542,3544,3553,3571,3580,3588,3596,3603,3633,3639,3649,3655,3660,3670,3699,3699,3707,3723,3747,3752,3754,3766,3772,3778,3781,3798,3815,3814,3824,3832,3853,3859,3879,3885,3899,3912,3910,3924,3937,3951,3951,3961,3963,3961,3976,3977,3988,4004,4018,4025,4047,4074,4086,4108,4133,4136,4159,4168,4182,4192,4200,4215,4230,4239,4257,4678,4698,4694,4713,4719,4739,4750,4756,4764,4771,4788,4792,4790,4809,4821,4829,4834,4836,4843,4853,4863,4872,4881,4890,4898,4901,4897,4895,4884,4886,4886,4894,4897,4905,4905,4909,4907,4925,4918,4920,4929,4925,4928,4936,4943,4944,4951,4955,4952,4974,4976,4975,4981,4994,4997,5022,5023,5032,5043,5048,5051,5066,5062,5068,5075,5082,5082,5098,5102,5110,5113,5119,5123,5138,5138,5145,5149,5157,5165,5166,5169,5178,5183,5190,5192,5203,5204,5207,5214,5228,5234,5245,5249,5256,5262,5275,5278,5305,5303,5315,5321,5348,5358,5369,5369,5372,5385,5402,5409,5427,5429,5429,5439,5456,5464,5481,5485,5494,5509,5520,5526,5543,5555,5568,5575,5585,5596,5602,5620,5627,5644,5647,5660,5678,5680,5684,5692,5700,5711,5727,5733,5736,5756,5776,5797,5805,5804,5807,5800,5808,5814,5822,5839,5856,5869,5889,5902,5919,5921,5936,5937,5936,5957,5961,5975,5981,6002,6015,6027,6035,6042,6059,6062,6080,6081,6092,6097,6106,6127,6129,6198,6227,6231,6243,6249,6262,6255,6279,6304,6315,6326,6330,6334,6361,6358,6359,6379,6381,6389,6388,6404,6404,6443,6465,6473,6497,6500,6513,6524,6532,6538,6578,6572,6576,6584,6582,6608,6639,6656,6761,6764,6768,6772,6836,6905,6916,6925,6951,6984,7009,7072,7092,7110,7122,7140,7148,7170,7168,7180,7194,7247,7374,7391,7393,7382,7425,7485,7530,7568,7587,7602,7602,7715,7771,7900,8004,8103,8153,8162,8296,8319,8437,8566,8746,8860,8913,9128,9275,9585,9739,10014,10123,10167,10203,10288,10323,10398,10544,10721,10883,11044,11157,11442,11515,11787,12070,12269,12468,12484,12619,12883,13008,13264,13317,13549,13859,14049,14175,14360,14498,14687,14843,14984,15093,15279,15431,15623,15741,15788,15966,16025,16132,16419,16568,16791,16892,17060,17269,17598,17959,18194,18482,18804,19136,19564,19990,20249,20509,20943,21248,21539,21845,22196,22412];class vi{static FIRST_ORBIT="1957-10-04";static EARTH_RADIUS_KM=6371;static LOW_ORBIT_KM=500;static shadowHeightKm(e){if(e>=0)return 0;const t=-e*Math.PI/180;return vi.EARTH_RADIUS_KM*(1/Math.cos(t)-1)}static isLitOverhead(e,t){return e>vi.shadowHeightKm(t)}static classesAt(e){const t=e.getTime();return LT.filter(n=>{const i=Date.parse(`${n.from}T00:00:00Z`),s=n.to===void 0?1/0:Date.parse(`${n.to}T23:59:59Z`);return t>=i&&t<=s})}static trackedInOrbitAt(e){const t=e.getUTCFullYear()*12+e.getUTCMonth()-NT;if(!(t<0))return im[Math.min(t,im.length-1)]}static visibilityAt(e,t){const n=Un("Sun",e,t).altitudeDeg;return{sunAltitudeDeg:n,shadowHeightKm:vi.shadowHeightKm(n),lowOrbitLit:vi.isLitOverhead(vi.LOW_ORBIT_KM,n),classes:vi.classesAt(e),trackedObjects:vi.trackedInOrbitAt(e),anythingInOrbit:e.getTime()>=Date.parse(`${vi.FIRST_ORBIT}T00:00:00Z`)}}}const OT={en:["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW"],fr:["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSO","SO","OSO","O","ONO","NO","NNO"]};class qs{static POINT_DEG=360/16;static point(e,t){const n=(e%360+360)%360,i=Math.round(n/qs.POINT_DEG)%16;return OT[t][i]}static towards(e,t){const n=qs.point(e,t);return t==="en"?`to the ${n}`:kT.test(n)?`à l'${n}`:`au ${n}`}}const kT=/^[EO]/;class nt{static COARSE_STEP_DEG=10;static FINE_STEP_DEG=2;static FINE_SPAN_DEG=10;static LOWEST_DEG=5;static THRESHOLD_CONTRAST=.5;static CONE_SEPARATION_DEG=60;galaxy=new Je;dust=new _t;assess(e,t){const n=Un("Sun",e,t),i=Un("Moon",e,t),s={altitudeDeg:i.altitudeDeg,phaseAngleDeg:We.phaseAngleOf(Kl(e).illuminatedFraction)},r=kn.galactic(e,t),o=nt.unit(r.centre),l=nt.unit(r.rotation),c=nt.unit(r.pole),h=nt.unit(kn.eclipticPole(e,t)),d=nt.unit(n),u=nt.unit(i),f=nt.normalize(nt.reject(d,h));let p,v,m=0;const g=(_,M)=>{const x=nt.unit({altitudeDeg:_,azimuthDeg:M}),w=nt.between(x,d),E=We.magPerArcsec2({altitudeDeg:n.altitudeDeg,separationDeg:w},{...s,separationDeg:nt.between(x,u)},_);E>m&&(m=E);const D=Zi.fromMagPerArcsec2(E),y=10**(-.4*We.EXTINCTION_PER_AIR_MASS*(We.airMass(_)-1)),T=this.galaxy.surfaceBrightnessS10(Math.atan2(nt.dot(x,l),nt.dot(x,o))*180/Math.PI,Math.asin(Math.max(-1,Math.min(1,nt.dot(x,c))))*180/Math.PI)*y;p=nt.better(p,T,D,E,_,M,w);const A=Math.max(-1,Math.min(1,nt.dot(x,h))),I=nt.normalize(nt.reject(x,h)),R=this.dust.surfaceBrightnessS10(nt.between(I,f),Math.asin(A)*180/Math.PI)*y;v=nt.better(v,R,D,E,_,M,w)};for(let _=nt.LOWEST_DEG;_<=90;_+=nt.COARSE_STEP_DEG)for(let M=0;M<360;M+=nt.COARSE_STEP_DEG)g(_,M);for(const _ of[p,v]){if(!_)continue;const M=nt.FINE_SPAN_DEG,x=nt.FINE_STEP_DEG;for(let w=_.altitudeDeg-M;w<=_.altitudeDeg+M;w+=x)if(!(w<nt.LOWEST_DEG||w>90))for(let E=_.azimuthDeg-M;E<=_.azimuthDeg+M;E+=x)g(w,(E+360)%360)}return{milkyWay:p&&p.contrast>=nt.THRESHOLD_CONTRAST?p:void 0,zodiacal:v&&v.contrast>=nt.THRESHOLD_CONTRAST?v:void 0,darkestSkyMagPerArcsec2:m}}static better(e,t,n,i,s,r,o){const l=t/n;return e&&e.contrast>=l?e:{contrast:l,altitudeDeg:s,azimuthDeg:r,magPerArcsec2:Zi.toMagPerArcsec2(t),skyMagPerArcsec2:i,sunSeparationDeg:o}}static unit(e){const t=e.altitudeDeg*Math.PI/180,n=e.azimuthDeg*Math.PI/180,i=Math.cos(t);return[i*Math.sin(n),Math.sin(t),-i*Math.cos(n)]}static dot(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]}static between(e,t){return Math.acos(Math.max(-1,Math.min(1,nt.dot(e,t))))*180/Math.PI}static reject(e,t){const n=nt.dot(e,t);return[e[0]-n*t[0],e[1]-n*t[1],e[2]-n*t[2]]}static normalize(e){const t=Math.hypot(...e)||1;return[e[0]/t,e[1]/t,e[2]/t]}}const pl=36e5,sm=25;class Th{constructor(e){this.provider=e}async infer(e){const t=this.questionOf(e);if(!t)return{status:"incomplete"};const{origin:n,start:i}=t,s=ja(e.event)??0,r=this.sampleTimings(e,i,s);let o;try{o=await this.provider.getWeather({points:r.map(l=>this.pointAt(e,l,n))})}catch{return{status:"failed",at:i}}return o?{status:"inferred",at:i,source:o.source,keyframes:o.samples.map((l,c)=>({t:r[c].t,weather:l.weather}))}:{status:"unavailable",at:i}}applyTo(e,t){if(!(t.status!=="inferred"||!t.keyframes||!t.source)){e.weatherTrack.clear();for(const n of t.keyframes)e.weatherTrack.addKeyframe(n.t,n.weather);e.weatherSource=t.source}}sampleTimes(e,t){const n=[e],i=e.getTime()+t;let s=Math.floor(e.getTime()/pl)*pl+pl;for(;s<=i&&n.length<sm;)n.push(new Date(s)),s+=pl;return t>0&&n[n.length-1].getTime()!==i&&n.length<sm&&n.push(new Date(i)),n}sampleTimings(e,t,n){const i=e.timeline.duration>0?e.timeline.duration:n;return n<=0||i<=0?[{time:t,t:0}]:this.sampleTimes(t,n).map(s=>{const r=(s.getTime()-t.getTime())/n;return{time:s,t:Math.round(i*Math.max(0,Math.min(1,r)))}})}canInfer(e){return this.questionOf(e)!==void 0}questionOf(e){const t=this.originOf(e);if(!t)return;const n=e.event.time;if(n?.year===void 0||n.month===void 0||n.day===void 0)return;const i=Ka(n,t.lng,e.event.utcOffsetHours);return i?{origin:t,start:i}:void 0}originOf(e){const t=at(e,0),n=e.event.place?.[0],i=t?.lat??n?.lat,s=t?.lng??n?.lng;return i===void 0||s===void 0?void 0:{lat:i,lng:s}}pointAt(e,t,n){const i=at(e,t.t);return{lat:i?.lat??n.lat,lng:i?.lng??n.lng,time:t.time}}}const FT=Date.UTC(1940,0,1),am=36e5,rm=.25,UT=.7,BT=.45,zT=.1,HT=2,GT=.3,VT=.2,WT=8,Ah=.125,XT=.05,om=125,lm=100,cm=2500,Ih=3500,Dh=8e3,qT=95,YT=99,KT=[96,99],$T=["cloud_cover","cloud_cover_low","cloud_cover_mid","cloud_cover_high","precipitation","snowfall","weather_code","wind_speed_10m","wind_direction_10m","temperature_2m","dew_point_2m"];class sv{fetchImpl;baseUrl;cache=new Map;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.baseUrl=e.baseUrl??"https://archive-api.open-meteo.com/v1/archive"}async getWeather(e){if(e.points.length===0)return;const t=e.points.map(f=>f.time.getTime()),n=Math.min(...t);if(n<FT)return;const i=new Map;for(const f of e.points){const p=this.cellKey(f);i.has(p)||i.set(p,{lat:f.lat,lng:f.lng,index:i.size})}const s=this.requestUrl([...i.values()],new Date(n),new Date(Math.max(...t))),r=this.cache.get(s);if(r)return r;const o=await this.fetchImpl(s);if(!o.ok)throw new Error(`Open-Meteo HTTP ${o.status}`);const l=await o.json(),c=Array.isArray(l)?l:[l];if(c.length<i.size||c.some(f=>f.error||!f.hourly))return;const h={id:"era5",name:"ERA5 (Open-Meteo)",url:s},d=e.points.map(f=>this.sampleAt(c[i.get(this.cellKey(f)).index].hourly,f.time));if(d.some(f=>f===void 0))return;const u={samples:d,source:h};return this.cache.set(s,u),u}cellKey(e){return`${Math.round(e.lat/rm)},${Math.round(e.lng/rm)}`}requestUrl(e,t,n){const i=new URLSearchParams({latitude:e.map(s=>s.lat).join(","),longitude:e.map(s=>s.lng).join(","),start_date:this.isoDate(t),end_date:this.isoDate(n),hourly:$T.join(","),wind_speed_unit:"ms",timezone:"UTC"});return`${this.baseUrl}?${i}`}isoDate(e){return e.toISOString().slice(0,10)}sampleAt(e,t){const n=this.recordAt(e,t);return n&&{time:t,weather:this.toWeather(n)}}recordAt(e,t){const n=e.time.map(o=>Date.parse(`${o}Z`)),i=t.getTime();if(n.length===0||i<n[0]-am||i>n[n.length-1]+am)return;if(i<=n[0])return this.recordFrom(e,0);if(i>=n[n.length-1])return this.recordFrom(e,n.length-1);let s=0;for(;s+1<n.length&&n[s+1]<=i;)s++;const r=n[s+1]-n[s];return this.blendRecords(this.recordFrom(e,s),this.recordFrom(e,s+1),r>0?(i-n[s])/r:0)}recordFrom(e,t){const n={cloudCover:e.cloud_cover[t]/100,cloudCoverLow:e.cloud_cover_low[t]/100,cloudCoverMid:e.cloud_cover_mid[t]/100,cloudCoverHigh:e.cloud_cover_high[t]/100,precipitationMm:e.precipitation[t],snowfallCm:e.snowfall[t],weatherCode:e.weather_code[t],windSpeedMs:e.wind_speed_10m[t],windFromDeg:e.wind_direction_10m[t],temperatureC:e.temperature_2m[t],dewPointC:e.dew_point_2m[t]};return Object.values(n).some(i=>i===void 0||Number.isNaN(i))?void 0:n}blendRecords(e,t,n){if(!e||!t)return e??t;const i=(r,o)=>r+(o-r)*n,s=((t.windFromDeg-e.windFromDeg)%360+540)%360-180;return{cloudCover:i(e.cloudCover,t.cloudCover),cloudCoverLow:i(e.cloudCoverLow,t.cloudCoverLow),cloudCoverMid:i(e.cloudCoverMid,t.cloudCoverMid),cloudCoverHigh:i(e.cloudCoverHigh,t.cloudCoverHigh),precipitationMm:i(e.precipitationMm,t.precipitationMm),snowfallCm:i(e.snowfallCm,t.snowfallCm),weatherCode:n<.5?e.weatherCode:t.weatherCode,windSpeedMs:i(e.windSpeedMs,t.windSpeedMs),windFromDeg:((e.windFromDeg+s*n)%360+360)%360,temperatureC:i(e.temperatureC,t.temperatureC),dewPointC:i(e.dewPointC,t.dewPointC)}}cloudLayersFrom(e){return[{id:"record-low",type:"unknown",baseM:Math.round(this.clamp(om*(e.temperatureC-e.dewPointC),lm,cm)),thicknessM:650,coverage:this.clamp(e.cloudCoverLow,0,1),sizeM:1400,density:1},{id:"record-mid",type:"unknown",baseM:Ih,thicknessM:800,coverage:this.clamp(e.cloudCoverMid,0,1),sizeM:2500,density:1},{id:"record-high",type:"cirrus",baseM:Dh,thicknessM:400,coverage:this.clamp(e.cloudCoverHigh,0,1),sizeM:2200,density:.35}]}toWeather(e){const t=e.weatherCode>=qT&&e.weatherCode<=YT,n=this.precipitationTypeFrom(e);return{cloudLayers:this.cloudLayersFrom(e),cloudCover:this.clamp(e.cloudCover,0,1),cloudDarkness:this.cloudDarknessFrom(e,t),cloudBaseM:this.cloudBaseFrom(e),highCloudCover:e.cloudCoverHigh,lowerCloudCover:Math.max(e.cloudCoverLow,e.cloudCoverMid),precipitationType:n,precipitationIntensity:n==="none"?0:this.clamp(Math.sqrt(e.precipitationMm/WT),0,1),windDirectionDeg:(e.windFromDeg+180)%360,windSpeed:e.windSpeedMs,storm:t}}precipitationTypeFrom(e){return e.snowfallCm>0?"snow":KT.includes(e.weatherCode)?"hail":e.precipitationMm>0?"rain":"none"}cloudDarknessFrom(e,t){const n=e.cloudCoverLow+e.cloudCoverMid+e.cloudCoverHigh;if(n<=0)return 0;const i=(UT*e.cloudCoverLow+BT*e.cloudCoverMid+zT*e.cloudCoverHigh)/n,s=Math.min(1,e.precipitationMm/HT);return this.clamp(i+GT*s+(t?VT:0),0,1)}cloudBaseFrom(e){if(e.cloudCover<XT)return;const t=this.clamp(om*(e.temperatureC-e.dewPointC),lm,cm);if(e.cloudCoverLow>=Ah)return Math.round(t);if(e.cloudCoverMid>=Ah)return Ih;if(e.cloudCoverHigh>=Ah)return Dh;const n=Math.max(e.cloudCoverLow,e.cloudCoverMid,e.cloudCoverHigh);if(!(n<=0))return n===e.cloudCoverLow?Math.round(t):n===e.cloudCoverMid?Ih:Dh}clamp(e,t,n){return Math.max(t,Math.min(n,e))}}function ZT(){return new sv}const JT=5;class av{attribution={text:"© OpenStreetMap",url:"https://osm.org/copyright"};fetchImpl;baseUrl;reverseUrl;cache=new Map;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis),this.baseUrl=e.baseUrl??"https://nominatim.openstreetmap.org/search",this.reverseUrl=e.reverseUrl??"https://nominatim.openstreetmap.org/reverse"}async reverse(e,t,n={}){const i=new URLSearchParams({lat:String(e),lon:String(t),format:"jsonv2"});n.language&&i.set("accept-language",n.language);const s=`${this.reverseUrl}?${i}`,r=this.cache.get(s);if(r)return r[0];const o=await this.fetchImpl(s,{signal:n.signal});if(!o.ok)throw new Error(`Nominatim HTTP ${o.status}`);const l=await o.json(),c=l.error?void 0:this.toMatch(l);return this.cache.set(s,c?[c]:[]),c}async search(e,t={}){const n=e.trim();if(n==="")return[];const i=this.requestUrl(n,t),s=this.cache.get(i);if(s)return s;const r=await this.fetchImpl(i,{signal:t.signal});if(!r.ok)throw new Error(`Nominatim HTTP ${r.status}`);const o=await r.json(),l=(Array.isArray(o)?o:[]).map(c=>this.toMatch(c)).filter(c=>c!==void 0);return this.cache.set(i,l),l}requestUrl(e,t){const n=new URLSearchParams({q:e,format:"jsonv2",limit:String(t.limit??JT)});return t.language&&n.set("accept-language",t.language),`${this.baseUrl}?${n}`}toMatch(e){const t=e.display_name??e.name,n=this.coordinate(e.lat),i=this.coordinate(e.lon);return t&&n!==void 0&&i!==void 0?{name:t,lat:n,lng:i}:void 0}coordinate(e){if(e===void 0||e.trim()==="")return;const t=Number(e);return Number.isFinite(t)?t:void 0}}function jT(){return new av}const QT=[{id:"nominatim",name:"Nominatim",credit:"© OpenStreetMap",creditUrl:"https://osm.org/copyright",create:()=>new av}],eA=[{id:"era5",name:"ERA5 (Open-Meteo)",credit:"© Copernicus/ECMWF",creditUrl:"https://open-meteo.com/en/docs/historical-weather-api",create:()=>new sv}];class tA{attribution;fetchImpl;tileUrlTemplate;constructor(e={}){this.fetchImpl=e.fetchImpl??fetch.bind(globalThis);const t=e.year??2024;this.tileUrlTemplate=`https://tiles.maps.eox.at/wmts/1.0.0/s2cloudless-${t}_3857/default/g/{z}/{y}/{x}.jpg`,this.attribution=`EOxCloudless https://cloudless.eox.at by EOX IT Services GmbH (Contains modified Copernicus Sentinel data ${t})`}async getImageryTexture(e,t){return Lm(e,t,n=>this.tileUrlTemplate.replace("{z}",String(n.z)).replace("{y}",String(n.y)).replace("{x}",String(n.x)),this.fetchImpl)}}const Ch=[{id:"aws-terrarium",name:"AWS Terrain Tiles",credit:"© AWS Open Data (SRTM, ETOPO1)",creditUrl:"https://registry.opendata.aws/terrain-tiles/",create:()=>new Pm}],hm=[{id:"esri-world",name:"Esri World Imagery",credit:"Imagery © Esri, Maxar, Earthstar Geographics, and the GIS User Community",creditUrl:"https://www.arcgis.com/home/item.html?id=10df2279f9684e4a9f6a7f08febac2a9",create:()=>new Nm},{id:"eox-s2cloudless",name:"EOX Sentinel-2 cloudless",credit:"EOxCloudless by EOX IT Services GmbH (contains modified Copernicus Sentinel data)",creditUrl:"https://cloudless.eox.at",create:()=>new tA}];class qu{constructor(e){this.provider=e}static SPAN_DEG=.002;async at(e,t){const n=qu.SPAN_DEG;try{const s=(await this.provider.getElevationGrid({south:e-n,north:e+n,west:t-n,east:t+n},{width:2,height:2})).heights[0];return Number.isFinite(s)?s:void 0}catch{return}}}class nA{available(){const e=Intl.supportedValuesOf;return e?[...e.call(Intl,"timeZone")].sort():[]}offsetHoursAt(e,t){if(t.year===void 0)return;const n=Date.UTC(t.year,(t.month??1)-1,t.day??1,t.hour??12,t.minute??0,t.second??0),i=this.zoneOffsetHours(e,new Date(n));if(i!==void 0)return this.zoneOffsetHours(e,new Date(n-i*36e5))??i}zoneOffsetHours(e,t){let n;try{n=new Intl.DateTimeFormat("en-US",{timeZone:e,timeZoneName:"longOffset"}).formatToParts(t).find(s=>s.type==="timeZoneName")?.value??""}catch{return}const i=/^GMT(?:([+-])(\d{2}):(\d{2}))?$/.exec(n);if(i)return i[1]?(i[1]==="-"?-1:1)*(Number(i[2])+Number(i[3])/60):0}}function Ia(a,e){return a.find(t=>t.id===e)??a[0]}class iA{constructor(e="https://api.open-meteo.com/v1/forecast"){this.endpoint=e}async zoneAt(e,t){const n=new URL(this.endpoint);n.searchParams.set("latitude",String(e)),n.searchParams.set("longitude",String(t)),n.searchParams.set("timezone","auto"),n.searchParams.set("forecast_days","1");try{const i=await fetch(n.toString());if(!i.ok)return;const s=await i.json();return s.timezone&&s.timezone!=="GMT"?s.timezone:void 0}catch{return}}}const sA=[{id:"open-meteo",name:"Open-Meteo",credit:"© Open-Meteo",creditUrl:"https://open-meteo.com/en/docs",create:()=>new iA}],aA={color:"Color",transparency:"Transparency",halo:"Halo",blur:"Blur",brightness:"Brilliance",shapeTitle:"Name",utcOffset:"Time zone",cloudBase:"Cloud base",elevation:"Altitude",heightAboveGround:"Height above ground",duration:"Duration",placeName:"Place",latitude:"Latitude",longitude:"Longitude",heading:"Heading",pitch:"Tilt",roll:"Roll",observationTime:"Observation start",observationEndTime:"Observation end",assessmentGroup:"Assessment",assessmentNames:{coverage:"Witness info"},assessmentVerdicts:{"hynek.nl":"NL — nocturnal light","hynek.dd":"DD — daylight disc","hynek.rv":"RV — radar-visual","hynek.ce1":"CE1 — close encounter","hynek.ce2":"CE2 — with a physical trace","hynek.ce3":"CE3 — with entities"},witnessGroup:"Witness",witnessId:"ID",witnessTitle:"Title",witnessLastName:"Last name",witnessFirstNames:"First names",caseId:"Case ID",tags:"Tags",cloudCover:"Cloud cover",highCloudCover:"Ice cloud (cirrus)",focalLength:"Focal length",fieldOfView:"Field of view",aperture:"Aperture",exposure:"Exposure",focusDistance:"Focused at",iceCrystalAlignment:"Crystal alignment",cloudDarkness:"Cloud darkness",precipitationType:"Precipitation",precipitationNone:"None",precipitationRain:"Rain",precipitationSnow:"Snow",precipitationHail:"Hail",precipitationIntensity:"Intensity",windDirection:"Wind direction",windSpeed:"Wind speed",storm:"Storm",precipitationGroup:"Precipitation",windGroup:"Wind",soundKind:"Sound",soundNone:"None (silent)",soundHum:"Hum",soundWhistle:"Whistle",soundRumble:"Rumble",soundCrackle:"Crackle",soundVolume:"Loudness",soundPitch:"Pitch",soundSrc:"Recording",instrument:"Observed through",decorAircraft:"Aircraft",decorEntity:"Being",decorAltitude:"Altitude",decorLights:"Lights",decorLightsNone:"none",decor:"Environment",decorBuilding:"Building",decorTree:"Tree",decorCrop:"Crop row",decorMound:"Stone heap",decorStreetlight:"Streetlight",decorVehicle:"Vehicle",decorWitness:"Other witness",decorEast:"Distance east",decorNorth:"Distance north",decorHeading:"Heading",decorColor:"Colour",decorLit:"Lit",decorTitle:"Name",milestones:"Moments",milestoneLabel:"Label",milestoneNote:"What happens",addMilestone:"Name this moment",deleteMilestone:"Delete moment",confirmAccept:"Delete",confirmDecline:"Cancel",decorWidth:"Width",decorLength:"Length",decorHeight:"Height",decorModel:"3D model",decorModelNone:"Built-in shape",decorModelAdvanced:"Model from an address",decorModelUrl:"glTF/GLB address",decorModelTitle:"Model name",decorModelAuthor:"Author",decorModelLicense:"Licence",decorModelSource:"Where it came from",decorFloors:"Floors",decorOccupiedFloor:"Occupied floor",decorWitnessSide:"Witness location",decorWitnessSideNone:"Not present",decorWindows:"Windows",decorSideFront:"Front",decorSideBehind:"Behind",decorSideLeft:"Left",decorSideRight:"Right",decorSideFrontLeft:"Front-left",decorSideFrontRight:"Front-right",decorSideBehindLeft:"Behind-left",decorSideBehindRight:"Behind-right"},rv={...aA,oval:"Oval",polygon:"Polygon",addVertex:"Add vertex",deleteVertex:"Delete vertex",notAPolygon:"Select a single polygon shape",tooFewVertices:"A shape needs at least 3 points",shape:"Shape",apparentWidth:"Apparent width",realWidth:"Real width",distance:"Distance",sizeLock:"Hold",lockNone:"nothing",lockApparent:"the apparent width",lockReal:"the real width",lockDistance:"the distance",apparentSize:"{moons}× the Moon",utcOffsetPlaceholder:"from longitude",realSizeBetween:"The scene bounds that width: between {min} and {max} m, from what it crosses",realSizeAtLeast:"The scene bounds that width: at least {min} m, from what it passes behind",realSizeAtMost:"The scene bounds that width: at most {max} m, from what it passes in front of",realSizeUnknown:"Nothing in the scene bounds that width: it is only what the distance implies",realSizeOutside:" — the width above is outside that",blurBound:"Blurred through this lens: nearer than {max} m",blurBoundNoInstrument:"Blur through the naked eye bounds no distance — an eye has no aperture to be out of focus with",blurBoundNotAtInfinity:"Blur bounds a distance only for a lens focused at infinity: this one is focused at {focus} m, which blurs on both sides of it",realSizeContradiction:"Contradiction: the declared crossings cannot all be true",realDistanceHere:" — i.e. between {min} and {max} m here",clearDistanceHypothesis:"Withdraw the distance hypothesis",clearDistanceHypothesisTitle:"Back to what the recording establishes",depthStated:"Drawn at {m} m, as the recording states",depthHypothesis:"Drawn at {m} m: your hypothesis — what the decor hides of it is what a thing that far would lose",depthDerived:"Drawn at {m} m, from the witness's own walk",depthBounded:"Drawn at {m} m, from what it passes behind and in front of",depthConventional:"Drawn at {m} m by convention: nothing in the recording establishes a distance",addShape:"Add shape",deleteShape:"Delete shape",play:"Play",pause:"Pause",noDuration:"No observation duration",autoReplay:"Auto-replay",group:"Group",ungroup:"Ungroup",bringToFront:"Bring to front",sendToBack:"Send to back",contextMenuDelete:"Delete",confirmDeleteShape:"Delete {name}? This can't be undone.",confirmDeleteShapes:"Delete {count} shapes? This can't be undone.",confirmDeleteMilestone:"Stop naming moment {name}? The recording itself is unchanged.",onlyOneShape:"There is only one shape",alreadyAtFront:"This shape is already at the front",alreadyAtBack:"This shape is already at the back",needTwoShapesToGroup:"Select at least two shapes to group them",notGrouped:"This shape isn't part of a group",multipleShapesSelected:"Multiple shapes selected — select just one to edit this",samplingRate:"Sampling rate",currentPosition:"Current position",switchToElapsed:"click to show elapsed time",switchToClockTime:"click to show the time of day",durationPlaceholder:"observation length",durationImprecise:"These dates don't precisely enough determine a duration — enter it manually.",export:"Export",importFile:"Load JSON file",importUrl:"Or load from URL",importUrlPlaceholder:"https://…/sighting.json",importButton:"Load",importError:"Couldn't load that recording — check the file or URL and try again.",importErrorCors:'That address answers, but the browser is not allowed to read it from this page. The file itself is fine — its server needs to send the header "Access-Control-Allow-Origin: *" with it. If it is not your server, that is what to ask its administrator for.',importErrorMixedContent:"A secure page cannot load an address starting with http://. Use https:// if that server offers it.",importErrorUnreachable:"Nothing answered at that address. Check the spelling, and that you are online.",importErrorStatus:"That server answered with an error ({status}). The address is probably wrong, or the file has moved.",importErrorMalformed:"That address answered, but what came back is not a recording.",record:"Record",stop:"Stop",according:"according to",sourceElevation:"Relief",sourceImagery:"Imagery",placeNamePlaceholder:"Valensole, France",searchPlace:"Locate",placeMatch:"Matches",placeSearching:"Looking up the place…",placeMatchFound:"place found",placeMatchesFound:"places found",placeNotFound:"No place by that name",placeSearchFailed:"Place search temporarily unavailable",utcOffsetImplausible:"This time zone doesn't match the longitude entered, whose own solar time is UTC{solar} — yet the scene and the weather record both obey what is declared here. Clear the field to derive it from the longitude.",timeZoneManual:"offset entered",altitudeAboveSeaLevel:"The witness's altitude above sea level — the ground at the location entered sets its floor: a witness in the Alps is not at 0 m.",groundAt:"ground at {m} m",headingPlaceholder:"unknown",edtfInvalid:"Not a valid EDTF date/time (e.g. 1965-07-01T05:00, 2025-06?, 2025~).",edtfPlaceholder:"YYYY-MM-DDThh:mm[?~%] or hh:mm",observationTimeHint:"EDTF — e.g. 1965-07-01T05:00, 2025-06? (uncertain), 2025~ (approximate), or just 05:00 if the date isn't known",observationEndTimeHint:"EDTF — e.g. 1965-07-01T05:10, 2025-06? (uncertain), 2025~ (approximate), or just 05:10 if the date isn't known",presetsGroupLabel:"UFO shape",witnessDirName:"Dir name",description:"Description",tagsPlaceholder:"comma-separated",weather:"Weather",shapeGroup:"Phenomenon",soundGroup:"Sound",temporalGroup:"Moment",timeQualifierExact:"Exact",timeQualifierApproximate:"Approximate",timeQualifierUncertain:"Uncertain",timeQualifierBoth:"Uncertain and approximate",edtfModeTitle:"Type an imprecise date instead: a year alone, a month, a time with no date",locationGroup:"Location",observationGroup:"Observation",weatherWhilePlaying:"Pause the recording to state the weather — while it plays, the instant these would be written at is moving",weatherInferred:"From weather records",weatherInferredTitle:"Weather isn't testimony: it's a measurable fact, on record for the observation's own date, time and place. Uncheck to state the conditions the witness reported, which then override the record.",weatherLookingUp:"Looking up the record…",weatherNeedsDateAndPlace:"A full date and a place are needed to look up the record",weatherNoRecord:"No record for this date and place",weatherLookupFailed:"Weather records temporarily unreachable",instrumentOutOfPeriod:"{name} — not of this date",unitMillimetres:"mm",unitDegrees:"°",soundSrcPlaceholder:"URL of a real recording",skyLine:"Sky: {parts}",skyStarsEye:"stars down to magnitude {limit}, which is as faint as an eye went under this sky",skyStarsDeeper:"stars down to magnitude {limit} through a {device} — {gain} magnitudes past the {eye} the witness's own eyes reached",skyStarsShallower:"stars down to magnitude {limit} through a {device} — {gain} magnitudes short of the {eye} the witness's own eyes reached",skyStarsCatalogue:", drawn to {catalogue}, where this project's catalogue stops",skyStarsNone:"no star could be picked out of a sky this bright",skyDetails:"Show the records in full",skyDetailsHide:"Hide the records",skyShowerActive:"{name} — radiant {altitude}° above the horizon, {bearing} — about {rate}/h under this sky, over a sporadic background of {sporadic}/h",skyShowerBelowHorizon:"{name} is active, but its radiant is below the horizon — it can have produced nothing",skyNothingActive:"no meteor shower active on this date — a sporadic background of about {sporadic}/h",showMeteor:"Show me one",skyComet:"{name}, magnitude {magnitude}, {altitude}° above the horizon {bearing}, tail {tail}° long",skyCometNoTail:"{name}, magnitude {magnitude}, {altitude}° above the horizon {bearing}",skyCometBelowHorizon:"{name} was there at magnitude {magnitude}, but below the horizon — nobody here saw it",skyCometInDaylight:"{name}, magnitude {magnitude}, {altitude}° above the horizon {bearing} — but only {elongation}° from the Sun",showComet:"Show me the comet",skyOpticsPossible:"ice cloud enough, around the {source}, for {forms}",skyOpticsAlignment:" — everything but the rings needs crystals falling level, stated here at {alignment}% since no record holds it",skyOpticsHalo22:"a {angle}° ring",skyOpticsHalo46:"a {angle}° ring",skyOpticsParhelia:"sundogs {angle}° to either side",skyOpticsTangentArc:"an arc tangent on top of it",skyOpticsParhelicCircle:"a white circle right round the sky at its own height",skyOpticsCircumzenithal:"a circumzenithal arc {angle}° up",skyOpticsCircumhorizontal:"a circumhorizontal arc far below it",skyOpticsPillar:"a pillar standing over it",skyOpticsNoIce:"no ice cloud: no halo and no sundogs",skyOpticsHidden:"ice cloud above, but a lower deck between it and the witness",skyOpticsSun:"Sun",skyOpticsMoon:"Moon",skyBowPossible:"rain and sunlight enough for {forms}",skyBowMoon:"rain under a Moon {lit}% lit, enough for {forms} — a moonbow, which the eye sees as a white arc",skyGlowBand:"the Milky Way {contrast}× the sky behind it, {altitude}° up {bearing}",skyGlowCone:"the zodiacal light {contrast}× the sky behind it, {altitude}° up {bearing}, {elongation}° from the Sun — a leaning cone with no edge, gone within the hour",skyGlowZodiacalBand:"the zodiacal band {contrast}× the sky behind it, {altitude}° up {bearing} — the whole ecliptic faintly alight, which is not the sight people report",skyGlowMoon:"no Milky Way and no zodiacal light: a Moon {lit}% lit held the sky at {sky} magnitudes a square arcsecond, where they need 22",skyGlowTwilight:"no Milky Way and no zodiacal light: twilight still held the sky at {sky} magnitudes a square arcsecond, where they need 22",skyGlowNothingUp:"sky dark enough ({sky} magnitudes a square arcsecond) but neither the galactic plane nor the ecliptic stood high enough in it",skyBowPrimary:"a bow {radius}° across, its top {top}° up",skyBowSecondary:"a second, fainter one at {radius}° with its colours reversed",skyBowSourceTooHigh:"rain, but with the source {altitude}° up no bow could clear the horizon: they stand {radius}° from the point opposite it",skyBowHidden:"rain, but an unbroken deck between it and the light: no bow",skyBowNoSource:"rain, and nothing lit to make a bow of it",skySatellitesLit:"the Earth's shadow stood {height} km above the witness, so low orbit was still in sunlight — {count} tracked objects were in orbit that month",skySatellitesLitWith:"the Earth's shadow stood {height} km above the witness, so low orbit was still in sunlight — {count} tracked objects were in orbit that month, among them {eras}",skySatellitesShadowed:"the Earth's shadow stood {height} km above the witness: of the {count} tracked objects in orbit that month, nothing in low orbit was lit",skySatellitesNotYet:"nothing had been put in orbit yet",skySatellitesDaylight:"everything in orbit was sunlit, as it always is by day, and {eras} could outshine even this sky",skySatellitesDaylightOne:"everything in orbit was sunlit, as it always is by day, and {eras} could outshine even this sky",skyUnknown:"cannot be worked out without a date and a place",lookAtDecor:"Look at it",addDecor:"Add",deleteDecor:"Delete decor",decorSightingUrl:"Their own recording URL",viewTestimony:"View testimony",noWitnessRecording:"No recording URL set for this witness",masks:"Masks",addWitness:"Add witness",narrativePlaceholder:"What the witness reported, in their own words",narrativeKey:"{source} API key",narrativeNeedsKey:"Enter your own {source} API key to generate a reconstruction from the account",narrativeKeyUnlikely:"This does not look like a Claude API key: they begin with sk-ant-",narrativeWorkspace:"Workspace ID",narrativeWorkspacePlaceholder:"only if your key spans several",narrativeWorkspaceHint:"Only for a key whose scope is the whole organisation. Simpler: leave this empty and create a key scoped to one workspace instead.",narrativeNeedsAsk:"Nothing to send yet",narrativeRemember:"Remember on this device",narrativeDraft:"Generate reconstruction",narrativeStop:"Stop",narrativeWorking:"Reading the account…",narrativeApplied:"{count} fields written into the editor",narrativeUnchanged:"The account states nothing the recording can hold yet",narrativeStated:"What the witness said",narrativeDerived:"Worked out from the account",narrativeAssumed:"Guessed, so the reconstruction runs — check these",narrativeGaps:"What nothing could settle",narrativeErrorCredential:"No key, or one that was refused — check it at console.anthropic.com",narrativeErrorRateLimited:"Too many requests on your account: wait a moment and ask again",narrativeErrorRefused:"The account was not answered. Rephrasing may help; asking again will not",narrativeErrorMalformed:"The answer was not a usable draft — worth asking once more",narrativeErrorUnreachable:"Nothing answered: check the connection",narrativeErrorRejected:"Refused: {detail}",witnessAge:"Age then",witnessOccupation:"Occupation",testimonySource:"Account obtained",testimonySourceUnknown:"unknown",testimonySourceOnSite:"on-site investigation",testimonySourceInterview:"interview in person",testimonySourceTelephone:"by telephone",testimonySourceQuestionnaire:"questionnaire",testimonySourceLetter:"the witness wrote it",testimonySourcePress:"press or broadcast",testimonyFollowedUp:"Followed up",testimonyUnknown:"unknown",testimonyYes:"yes",testimonyNo:"no",questionUnanswered:"Nothing in this recording answers one of the questions a reconstruction needs settled",durationRequired:"The observation needs a length to be replayed at all — state one, or an end time, which may be approximate",questionsUnanswered:"{count} of the questions a full reconstruction answers are unanswered here"},rA=Object.freeze(Object.defineProperty({__proto__:null,sightingEditorMessages_en:rv},Symbol.toStringTag,{value:"Module"})),dm=new Set;Ql();CT();const Da={width:48,height:28},oA=2500,lA=600,um=900,Ca=2e-4,cA=900,hA=-1.46,dA=3,fm=.2,uA=.01,fA=1.6,Rh=2e3,pA=250,pm=new Set(["ArrowLeft","ArrowRight","ArrowUp","ArrowDown"]),us=4,ml="ufo-1",mm=["oval","polygon"],mA={presetId:"oval",color:"#39ff14",transparency:0,haloScale:1.5,blur:0,brightness:0};function gA(a){return a.kind==="oval"?"oval":"polygon"}const vA=-6,yA=21;class Mt extends HTMLElement{shadow;sceneElement;ufoElement;recordButton;samplingRateInput;presetButtons;presetsGroup;colorInput;transparencyInput;haloScaleInput;blurInput;brightnessInput;blurBoundOutput;sourceSelect;shapeTitleInput;utcOffsetInput;timeZoneSelect;timeZoneProvider=sA[0].create();timeZoneLookupTimer;timeZoneLookedUpAt;autoFilledTimeZone;timeZones=new nA;apparentWidthInput;realWidthInput;objectDistanceInput;sizeLockSelect;apparentSizeOutput;realSizeOutput;clearDistanceHypothesisButton;depthBasisOutput;addShapeButton;deleteShapeButton;contextMenu;contextGroupButton;contextUngroupButton;contextBringToFrontButton;contextSendToBackButton;contextDeleteButton;contextAddVertexButton;contextDeleteVertexButton;decorContextMenu;contextViewTestimonyButton;contextMasksSubmenu;labelContextMasks;playPauseButton;seekInput;timeStartLabel;timeEndLabel;loopButton;durationInput;exportButton;importFileInput;importUrlInput;importUrlButton;narrativeKeyInput;narrativeWorkspaceInput;narrativeRememberInput;narrativeDraftButton;narrativeStopButton;narrativeCreditLink;narrativeStatus;narrativeReport;placeNameInput;searchPlaceButton;placeMatchRow;placeMatchSelect;placeStatusText;placeProvider=jT();placeMatches=[];placeSearchToken=0;placeReverseTimer;namedCoordinates;latInput;lngInput;headingInput;pitchInput;rollInput;elevationInput;groundElevationOutput;weatherFromRecords=!0;groundElevationM;groundElevationFor;groundElevationTimer;groundElevationToken=0;obsTimeInput;obsTimeNativeInput;obsEndTimeNativeInput;obsTimeQualifier;obsEndTimeQualifier;edtfModeButton;edtfMode=!1;obsEndTimeInput;witnessIdInput;witnessDirNameInput;witnessTitleInput;witnessLastNameInput;witnessFirstNamesInput;witnessAgeInput;witnessOccupationInput;testimonySourceSelect;testimonyFollowedUpSelect;caseIdInput;descriptionInput;tagsInput;cloudEditor;cloudCoverInput;cloudDarknessInput;cloudBaseInput;precipitationTypeSelect;precipitationIntensityInput;windDirectionInput;windSpeedInput;stormInput;weatherInferredInput;weatherSourceText;skyCandidatesOutput;showMeteorButton;showCometButton;weatherSourceLink;weatherFields;weatherInference=new Th(ZT());weatherLookupTimer;weatherLookupToken=0;weatherLookupPending=!1;weatherLookupResult;weatherTrackSpan;soundKindSelect;soundVolumeInput;soundPitchInput;soundPitchValue;soundSrcInput;soundFields;soundKindOptions=new Map;soundPreviewTimer;instrumentSelect;focalLengthInput;labelFocalLength;unitFocalLength;labelFNumber;labelExposure;labelFocusDistance;fNumberInput;exposureInput;focusDistanceInput;labelColor;labelTransparency;labelHalo;labelBlur;labelBrightness;labelShape;labelShapeTitle;labelUtcOffset;labelApparentWidth;labelRealWidth;labelObjectDistance;labelSizeLock;labelSamplingRate;labelDuration;placeSourceRow;weatherSourceRow;terrainSourceRows;chosenSourceId=new Map;labelPlaceName;labelPlaceMatch;labelLatitude;labelLongitude;labelHeading;labelPitch;labelRoll;labelElevation;labelObservationTime;labelObservationEndTime;labelWitnessId;labelWitnessDirName;labelWitnessTitle;labelWitnessLastName;labelWitnessFirstNames;labelWitnessAge;labelWitnessOccupation;labelTestimonySource;labelTestimonyFollowedUp;labelCaseId;labelDescription;labelTags;labelImportFile;labelImportUrl;labelNarrativeKey;labelNarrativeWorkspace;labelNarrativeRemember;groupTabs;groupPanels;paramSummary;paramSummaryBuilder;paramSummarySignature="";labelShapeGroup;labelTemporalGroup;labelLocationGroup;labelObservationGroup;labelWitnessGroup;skyDetailsButton;clampedLines;labelWeatherGroup;labelCloudCover;labelHighCloud;labelIceAlignment;highCloudCoverInput;iceCrystalAlignmentInput;labelCloudDarkness;labelCloudBase;labelPrecipitationType;labelPrecipitationIntensity;labelWindDirection;labelWindSpeed;labelStorm;labelPrecipitationGroup;labelWindGroup;labelWeatherInferred;labelSoundGroup;labelSoundKind;labelSoundVolume;labelSoundPitch;labelSoundSrc;labelInstrument;optionPrecipitationNone;optionPrecipitationRain;optionPrecipitationSnow;optionPrecipitationHail;decorKindSelect;addDecorWitnessButton;addDecorBuildingButton;deleteDecorButton;decorSelect;decorTitleInput;decorEastInput;decorNorthInput;decorHeadingInput;decorColorInput;decorLitInput;decorLightRigSelect;lookAtDecorButton;decorAltitudeInput;labelDecorAltitude;decorSightingUrlInput;decorModelProvider=El[0].create();confirmOverlay;confirmMessage;confirmAcceptButton;confirmDeclineButton;confirmAnswer;milestoneSelect;milestoneLabelInput;milestoneNoteInput;addMilestoneButton;deleteMilestoneButton;currentMilestoneT;decorWidthInput;decorLengthInput;decorHeightInput;decorModelSelect;decorModelAdvanced;decorModelUrlInput;decorModelTitleInput;decorModelAuthorInput;decorModelLicenseInput;decorModelSourceInput;decorFloorsInput;decorOccupiedFloorInput;decorWitnessSideSelect;decorWindowInputs;labelDecorSide;optionWitnessSide;labelDecor;labelDecorGroup;labelDecorTitle;labelDecorEast;labelDecorNorth;labelDecorHeading;labelDecorColor;labelDecorLit;labelDecorSightingUrl;labelMilestones;labelMilestoneLabel;labelMilestoneNote;labelDecorWidth;labelDecorLength;labelDecorHeight;labelDecorModel;labelDecorModelAdvanced;labelDecorModelUrl;labelDecorModelTitle;labelDecorModelAuthor;labelDecorModelLicense;labelDecorModelSource;labelDecorFloors;labelDecorOccupiedFloor;labelDecorWitnessSide;labelDecorWindows;optionWitnessSideNone;optionDecorBuilding;optionDecorTree;optionDecorCrop;optionDecorMound;optionDecorStreetlight;optionDecorVehicle;optionDecorAircraft;optionDecorEntity;labelDecorLights;optionDecorWitness;recorder;isRecording=!1;messages=rv;currentAppearance={...mA};currentSourceId=ml;selectedSourceIds=new Set([ml]);currentDecorId;contextMenuDecorId;contextMenuPoint;dragState;cameraDragState;hoverCursor;indoorLookYawDeg=0;indoorLookPitchDeg=0;lastInhabitedKey;handleKeyDown=e=>{if(e.key==="Escape"&&(this.isRecording&&this.toggleRecording(),this.confirmOverlay.hidden||this.answerConfirm(!1),this.contextMenu.hidden||this.hideContextMenu(),this.decorContextMenu.hidden||this.hideDecorContextMenu()),pm.has(e.key)||e.key==="Delete"||e.key==="Backspace"){const t=e.composedPath()[0];if(t instanceof HTMLInputElement||t instanceof HTMLSelectElement||t instanceof HTMLTextAreaElement)return;pm.has(e.key)?this.moveOrResizeSelectedShapes(e):this.deleteShape()}};handleDragPointerMove=e=>this.onDragPointerMove(e);handleDragPointerUp=()=>this.endDrag();constructor(){super(),this.shadow=this.attachShadow({mode:"open"});const e=document.createElement("template");e.innerHTML=`<style>${n1}</style>${t1}`,this.shadow.appendChild(e.content.cloneNode(!0)),this.sceneElement=document.createElement(hu),this.sceneElement.setAttribute("show-compass",""),this.sceneElement.setAttribute(Ys,""),this.sceneElement.animateWhilePaused=!0,this.ufoElement=this.sceneElement.ufoElement,this.ufoElement.enableClickToPlay=!1,this.ufoElement.showToolbar=!1,this.shadow.getElementById("ufo-slot").replaceWith(this.sceneElement),this.recordButton=this.shadow.getElementById("record"),this.samplingRateInput=this.shadow.getElementById("samplingRate"),this.presetsGroup=this.shadow.getElementById("presets-group"),this.presetButtons={oval:this.shadow.getElementById("preset-oval"),polygon:this.shadow.getElementById("preset-polygon")},this.colorInput=this.shadow.getElementById("color"),this.transparencyInput=this.shadow.getElementById("transparency"),this.haloScaleInput=this.shadow.getElementById("haloScale"),this.blurInput=this.shadow.getElementById("blur"),this.brightnessInput=this.shadow.getElementById("brightness"),this.blurBoundOutput=this.shadow.getElementById("blur-bound"),this.sourceSelect=this.shadow.getElementById("source"),this.shapeTitleInput=this.shadow.getElementById("shapeTitle"),this.utcOffsetInput=this.shadow.getElementById("utcOffsetHours"),this.timeZoneSelect=this.shadow.getElementById("timeZone"),this.apparentWidthInput=this.shadow.getElementById("apparentWidth"),this.realWidthInput=this.shadow.getElementById("realWidth"),this.objectDistanceInput=this.shadow.getElementById("objectDistance"),this.sizeLockSelect=this.shadow.getElementById("sizeLock"),this.apparentSizeOutput=this.shadow.getElementById("apparent-size"),this.realSizeOutput=this.shadow.getElementById("real-size"),this.clearDistanceHypothesisButton=this.shadow.getElementById("clear-distance-hypothesis"),this.depthBasisOutput=this.shadow.getElementById("depth-basis"),this.addShapeButton=this.shadow.getElementById("add-shape"),this.deleteShapeButton=this.shadow.getElementById("delete-shape"),this.contextMenu=this.shadow.getElementById("context-menu"),this.contextGroupButton=this.shadow.getElementById("context-group"),this.contextUngroupButton=this.shadow.getElementById("context-ungroup"),this.contextBringToFrontButton=this.shadow.getElementById("context-bring-to-front"),this.contextSendToBackButton=this.shadow.getElementById("context-send-to-back"),this.contextDeleteButton=this.shadow.getElementById("context-delete"),this.contextAddVertexButton=this.shadow.getElementById("context-add-vertex"),this.contextDeleteVertexButton=this.shadow.getElementById("context-delete-vertex"),this.decorContextMenu=this.shadow.getElementById("decor-context-menu"),this.contextViewTestimonyButton=this.shadow.getElementById("context-view-testimony"),this.contextMasksSubmenu=this.shadow.getElementById("context-masks-submenu"),this.labelContextMasks=this.shadow.getElementById("label-context-masks"),this.playPauseButton=this.shadow.getElementById("play-pause"),this.seekInput=this.shadow.getElementById("seek"),this.timeStartLabel=this.shadow.getElementById("time-start"),this.timeEndLabel=this.shadow.getElementById("time-end");for(const t of[this.timeStartLabel,this.timeEndLabel])t.addEventListener("click",()=>this.switchTimeDisplay()),t.addEventListener("keydown",n=>{n.key!=="Enter"&&n.key!==" "||(n.preventDefault(),this.switchTimeDisplay())});this.loopButton=this.shadow.getElementById("loop"),this.durationInput=this.shadow.getElementById("durationSeconds"),this.exportButton=this.shadow.getElementById("export"),this.importFileInput=this.shadow.getElementById("import-file"),this.importUrlInput=this.shadow.getElementById("import-url"),this.importUrlButton=this.shadow.getElementById("import-url-button"),this.narrativeKeyInput=this.shadow.getElementById("narrativeKey"),this.narrativeWorkspaceInput=this.shadow.getElementById("narrativeWorkspace"),this.narrativeRememberInput=this.shadow.getElementById("narrativeRemember"),this.narrativeDraftButton=this.shadow.getElementById("narrative-draft"),this.narrativeStopButton=this.shadow.getElementById("narrative-stop"),this.narrativeCreditLink=this.shadow.getElementById("narrative-credit"),this.narrativeStatus=this.shadow.getElementById("narrative-status"),this.narrativeReport=this.shadow.getElementById("narrative-report"),this.placeNameInput=this.shadow.getElementById("placeName"),this.searchPlaceButton=this.shadow.getElementById("search-place"),this.placeMatchRow=this.shadow.getElementById("place-match-row"),this.placeMatchSelect=this.shadow.getElementById("placeMatch"),this.placeStatusText=this.shadow.getElementById("place-status-text"),this.latInput=this.shadow.getElementById("lat"),this.lngInput=this.shadow.getElementById("lng"),this.headingInput=this.shadow.getElementById("heading"),this.pitchInput=this.shadow.getElementById("pitch"),this.rollInput=this.shadow.getElementById("roll"),this.elevationInput=this.shadow.getElementById("elevation"),this.groundElevationOutput=this.shadow.getElementById("ground-elevation"),this.obsTimeInput=this.shadow.getElementById("obs-time"),this.obsEndTimeInput=this.shadow.getElementById("obs-end-time"),this.obsTimeNativeInput=this.shadow.getElementById("obs-time-native"),this.obsEndTimeNativeInput=this.shadow.getElementById("obs-end-time-native"),this.obsTimeQualifier=this.shadow.getElementById("obs-time-qualifier"),this.obsEndTimeQualifier=this.shadow.getElementById("obs-end-time-qualifier"),this.edtfModeButton=this.shadow.getElementById("edtf-mode"),this.witnessIdInput=this.shadow.getElementById("witnessId"),this.witnessDirNameInput=this.shadow.getElementById("witnessDirName"),this.witnessTitleInput=this.shadow.getElementById("witnessTitle"),this.witnessLastNameInput=this.shadow.getElementById("witnessLastName"),this.witnessFirstNamesInput=this.shadow.getElementById("witnessFirstNames"),this.witnessAgeInput=this.shadow.getElementById("witnessAge"),this.witnessOccupationInput=this.shadow.getElementById("witnessOccupation"),this.testimonySourceSelect=this.shadow.getElementById("testimonySource"),this.testimonyFollowedUpSelect=this.shadow.getElementById("testimonyFollowedUp"),this.caseIdInput=this.shadow.getElementById("caseId"),this.descriptionInput=this.shadow.getElementById("description"),this.tagsInput=this.shadow.getElementById("tags"),this.cloudCoverInput=this.shadow.getElementById("cloudCover"),this.highCloudCoverInput=this.shadow.getElementById("highCloudCover"),this.iceCrystalAlignmentInput=this.shadow.getElementById("iceCrystalAlignment"),this.cloudDarknessInput=this.shadow.getElementById("cloudDarkness"),this.cloudBaseInput=this.shadow.getElementById("cloudBase"),this.precipitationTypeSelect=this.shadow.getElementById("precipitationType"),this.precipitationIntensityInput=this.shadow.getElementById("precipitationIntensity"),this.windDirectionInput=this.shadow.getElementById("windDirection"),this.windSpeedInput=this.shadow.getElementById("windSpeed"),this.stormInput=this.shadow.getElementById("storm"),this.weatherInferredInput=this.shadow.getElementById("weatherInferred"),this.weatherSourceText=this.shadow.getElementById("weather-source-text"),this.skyCandidatesOutput=this.shadow.getElementById("sky-candidates"),this.showMeteorButton=this.shadow.getElementById("show-meteor"),this.showCometButton=this.shadow.getElementById("show-comet"),this.weatherSourceLink=this.shadow.getElementById("weather-source-link"),this.weatherFields=[this.cloudCoverInput,this.highCloudCoverInput,this.iceCrystalAlignmentInput,this.cloudDarknessInput,this.cloudBaseInput,this.precipitationTypeSelect,this.precipitationIntensityInput,this.windDirectionInput,this.windSpeedInput,this.stormInput],this.soundKindSelect=this.shadow.getElementById("soundKind"),this.soundVolumeInput=this.shadow.getElementById("soundVolume"),this.soundPitchInput=this.shadow.getElementById("soundPitch"),this.soundPitchValue=this.shadow.getElementById("sound-pitch-value"),this.soundSrcInput=this.shadow.getElementById("soundSrc"),this.soundFields=[this.soundKindSelect,this.soundVolumeInput,this.soundPitchInput,this.soundSrcInput],this.buildSoundKindOptions(),this.instrumentSelect=this.shadow.getElementById("instrument"),this.focalLengthInput=this.shadow.getElementById("focalLength"),this.labelFocalLength=this.shadow.getElementById("label-focal-length"),this.unitFocalLength=this.shadow.getElementById("unit-focal-length"),this.labelFNumber=this.shadow.getElementById("label-f-number"),this.labelExposure=this.shadow.getElementById("label-exposure"),this.fNumberInput=this.shadow.getElementById("fNumber"),this.exposureInput=this.shadow.getElementById("exposureSeconds"),this.focusDistanceInput=this.shadow.getElementById("focusDistance"),this.labelFocusDistance=this.shadow.getElementById("label-focus-distance"),this.refreshInstrumentOptions(),this.labelColor=this.shadow.getElementById("label-color"),this.labelTransparency=this.shadow.getElementById("label-transparency"),this.labelHalo=this.shadow.getElementById("label-halo"),this.labelBlur=this.shadow.getElementById("label-blur"),this.labelBrightness=this.shadow.getElementById("label-brightness"),this.labelShape=this.shadow.getElementById("label-shape"),this.labelShapeTitle=this.shadow.getElementById("label-shape-title"),this.labelUtcOffset=this.shadow.getElementById("label-utc-offset"),this.labelApparentWidth=this.shadow.getElementById("label-apparent-width"),this.labelRealWidth=this.shadow.getElementById("label-real-width"),this.labelObjectDistance=this.shadow.getElementById("label-object-distance"),this.labelSizeLock=this.shadow.getElementById("label-size-lock"),this.labelSamplingRate=this.shadow.getElementById("label-sampling-rate"),this.labelSoundGroup=this.shadow.getElementById("label-sound-group"),this.labelSoundKind=this.shadow.getElementById("label-sound-kind"),this.labelSoundVolume=this.shadow.getElementById("label-sound-volume"),this.labelSoundPitch=this.shadow.getElementById("label-sound-pitch"),this.labelSoundSrc=this.shadow.getElementById("label-sound-src"),this.labelDuration=this.shadow.getElementById("label-duration"),this.placeSourceRow=this.shadow.getElementById("place-source-row"),this.weatherSourceRow=this.shadow.getElementById("weather-source-row"),this.terrainSourceRows=this.shadow.getElementById("terrain-source-rows"),this.labelPlaceName=this.shadow.getElementById("label-place-name"),this.labelPlaceMatch=this.shadow.getElementById("label-place-match"),this.labelLatitude=this.shadow.getElementById("label-lat"),this.labelLongitude=this.shadow.getElementById("label-lng"),this.labelHeading=this.shadow.getElementById("label-heading"),this.labelPitch=this.shadow.getElementById("label-pitch"),this.labelRoll=this.shadow.getElementById("label-roll"),this.labelElevation=this.shadow.getElementById("label-elevation"),this.labelObservationTime=this.shadow.getElementById("label-observation-time"),this.labelObservationEndTime=this.shadow.getElementById("label-observation-end-time"),this.labelWitnessId=this.shadow.getElementById("label-witness-id"),this.labelWitnessDirName=this.shadow.getElementById("label-witness-dir-name"),this.labelWitnessTitle=this.shadow.getElementById("label-witness-title"),this.labelWitnessLastName=this.shadow.getElementById("label-witness-last-name"),this.labelWitnessFirstNames=this.shadow.getElementById("label-witness-first-names"),this.labelWitnessAge=this.shadow.getElementById("label-witness-age"),this.labelWitnessOccupation=this.shadow.getElementById("label-witness-occupation"),this.labelTestimonySource=this.shadow.getElementById("label-testimony-source"),this.labelTestimonyFollowedUp=this.shadow.getElementById("label-testimony-followed-up"),this.labelCaseId=this.shadow.getElementById("label-case-id"),this.labelDescription=this.shadow.getElementById("label-description"),this.labelTags=this.shadow.getElementById("label-tags"),this.labelImportFile=this.shadow.getElementById("label-import-file"),this.labelImportUrl=this.shadow.getElementById("label-import-url"),this.labelNarrativeKey=this.shadow.getElementById("label-narrative-key"),this.labelNarrativeWorkspace=this.shadow.getElementById("label-narrative-workspace"),this.labelNarrativeRemember=this.shadow.getElementById("label-narrative-remember"),this.labelShapeGroup=this.shadow.getElementById("label-shape-group"),this.labelTemporalGroup=this.shadow.getElementById("label-temporal-group"),this.labelLocationGroup=this.shadow.getElementById("label-location-group"),this.labelObservationGroup=this.shadow.getElementById("label-observation-group"),this.labelWitnessGroup=this.shadow.getElementById("label-witness-group"),this.labelWeatherGroup=this.shadow.getElementById("label-weather-group"),this.labelCloudCover=this.shadow.getElementById("label-cloud-cover"),this.labelHighCloud=this.shadow.getElementById("label-high-cloud"),this.labelIceAlignment=this.shadow.getElementById("label-ice-alignment"),this.labelCloudDarkness=this.shadow.getElementById("label-cloud-darkness"),this.labelCloudBase=this.shadow.getElementById("label-cloud-base"),this.labelPrecipitationType=this.shadow.getElementById("label-precipitation-type"),this.labelPrecipitationIntensity=this.shadow.getElementById("label-precipitation-intensity"),this.labelWindDirection=this.shadow.getElementById("label-wind-direction"),this.labelWindSpeed=this.shadow.getElementById("label-wind-speed"),this.labelStorm=this.shadow.getElementById("label-storm"),this.labelPrecipitationGroup=this.shadow.getElementById("label-precipitation-group"),this.labelWindGroup=this.shadow.getElementById("label-wind-group"),this.labelWeatherInferred=this.shadow.getElementById("label-weather-inferred"),this.labelInstrument=this.shadow.getElementById("label-instrument"),this.optionPrecipitationNone=this.shadow.getElementById("option-precipitation-none"),this.optionPrecipitationRain=this.shadow.getElementById("option-precipitation-rain"),this.optionPrecipitationSnow=this.shadow.getElementById("option-precipitation-snow"),this.optionPrecipitationHail=this.shadow.getElementById("option-precipitation-hail"),this.decorKindSelect=this.shadow.getElementById("decorKind"),this.addDecorWitnessButton=this.shadow.getElementById("add-decor-witness"),this.addDecorBuildingButton=this.shadow.getElementById("add-decor-building"),this.deleteDecorButton=this.shadow.getElementById("delete-decor"),this.decorSelect=this.shadow.getElementById("decor"),this.decorTitleInput=this.shadow.getElementById("decorTitle"),this.decorEastInput=this.shadow.getElementById("decorEast"),this.decorNorthInput=this.shadow.getElementById("decorNorth"),this.decorHeadingInput=this.shadow.getElementById("decorHeading"),this.decorColorInput=this.shadow.getElementById("decorColor"),this.decorLitInput=this.shadow.getElementById("decorLit"),this.decorLightRigSelect=this.shadow.getElementById("decorLightRig"),this.lookAtDecorButton=this.shadow.getElementById("look-at-decor"),this.decorAltitudeInput=this.shadow.getElementById("decorAltitude"),this.labelDecorAltitude=this.shadow.getElementById("label-decor-altitude"),this.decorSightingUrlInput=this.shadow.getElementById("decorSightingUrl"),this.confirmOverlay=this.shadow.getElementById("confirm-overlay"),this.confirmMessage=this.shadow.getElementById("confirm-message"),this.confirmAcceptButton=this.shadow.getElementById("confirm-ok"),this.confirmDeclineButton=this.shadow.getElementById("confirm-cancel"),this.milestoneSelect=this.shadow.getElementById("milestone"),this.milestoneLabelInput=this.shadow.getElementById("milestoneLabel"),this.milestoneNoteInput=this.shadow.getElementById("milestoneNote"),this.addMilestoneButton=this.shadow.getElementById("add-milestone"),this.deleteMilestoneButton=this.shadow.getElementById("delete-milestone"),this.decorWidthInput=this.shadow.getElementById("decorWidth"),this.decorLengthInput=this.shadow.getElementById("decorLength"),this.decorHeightInput=this.shadow.getElementById("decorHeight"),this.decorModelSelect=this.shadow.getElementById("decorModel"),this.decorModelAdvanced=this.shadow.getElementById("decor-model-advanced"),this.decorModelUrlInput=this.shadow.getElementById("decorModelUrl"),this.decorModelTitleInput=this.shadow.getElementById("decorModelTitle"),this.decorModelAuthorInput=this.shadow.getElementById("decorModelAuthor"),this.decorModelLicenseInput=this.shadow.getElementById("decorModelLicense"),this.decorModelSourceInput=this.shadow.getElementById("decorModelSource"),this.decorFloorsInput=this.shadow.getElementById("decorFloors"),this.decorOccupiedFloorInput=this.shadow.getElementById("decorOccupiedFloor"),this.decorWitnessSideSelect=this.shadow.getElementById("decorWitnessSide"),this.decorWindowInputs={front:this.shadow.getElementById("decorWindowFront"),behind:this.shadow.getElementById("decorWindowBehind"),left:this.shadow.getElementById("decorWindowLeft"),right:this.shadow.getElementById("decorWindowRight"),"front-left":this.shadow.getElementById("decorWindowFrontLeft"),"front-right":this.shadow.getElementById("decorWindowFrontRight"),"behind-left":this.shadow.getElementById("decorWindowBehindLeft"),"behind-right":this.shadow.getElementById("decorWindowBehindRight")},this.labelDecorSide={front:this.shadow.getElementById("label-decor-window-front"),behind:this.shadow.getElementById("label-decor-window-behind"),left:this.shadow.getElementById("label-decor-window-left"),right:this.shadow.getElementById("label-decor-window-right"),"front-left":this.shadow.getElementById("label-decor-window-front-left"),"front-right":this.shadow.getElementById("label-decor-window-front-right"),"behind-left":this.shadow.getElementById("label-decor-window-behind-left"),"behind-right":this.shadow.getElementById("label-decor-window-behind-right")},this.optionWitnessSide={front:this.shadow.getElementById("option-witness-side-front"),behind:this.shadow.getElementById("option-witness-side-behind"),left:this.shadow.getElementById("option-witness-side-left"),right:this.shadow.getElementById("option-witness-side-right"),"front-left":this.shadow.getElementById("option-witness-side-front-left"),"front-right":this.shadow.getElementById("option-witness-side-front-right"),"behind-left":this.shadow.getElementById("option-witness-side-behind-left"),"behind-right":this.shadow.getElementById("option-witness-side-behind-right")},this.optionWitnessSideNone=this.shadow.getElementById("option-witness-side-none"),this.labelDecor=this.shadow.getElementById("label-decor"),this.labelDecorGroup=this.shadow.getElementById("label-decor-group"),this.labelDecorTitle=this.shadow.getElementById("label-decor-title"),this.labelDecorEast=this.shadow.getElementById("label-decor-east"),this.labelDecorNorth=this.shadow.getElementById("label-decor-north"),this.labelDecorHeading=this.shadow.getElementById("label-decor-heading"),this.labelDecorColor=this.shadow.getElementById("label-decor-color"),this.labelDecorLit=this.shadow.getElementById("label-decor-lit"),this.labelDecorSightingUrl=this.shadow.getElementById("label-decor-sighting-url"),this.labelMilestones=this.shadow.getElementById("label-milestones"),this.labelMilestoneLabel=this.shadow.getElementById("label-milestone-label"),this.labelMilestoneNote=this.shadow.getElementById("label-milestone-note"),this.labelDecorWidth=this.shadow.getElementById("label-decor-width"),this.labelDecorLength=this.shadow.getElementById("label-decor-length"),this.labelDecorHeight=this.shadow.getElementById("label-decor-height"),this.labelDecorModel=this.shadow.getElementById("label-decor-model"),this.labelDecorModelAdvanced=this.shadow.getElementById("label-decor-model-advanced"),this.labelDecorModelUrl=this.shadow.getElementById("label-decor-model-url"),this.labelDecorModelTitle=this.shadow.getElementById("label-decor-model-title"),this.labelDecorModelAuthor=this.shadow.getElementById("label-decor-model-author"),this.labelDecorModelLicense=this.shadow.getElementById("label-decor-model-license"),this.labelDecorModelSource=this.shadow.getElementById("label-decor-model-source"),this.labelDecorFloors=this.shadow.getElementById("label-decor-floors"),this.labelDecorOccupiedFloor=this.shadow.getElementById("label-decor-occupied-floor"),this.labelDecorWitnessSide=this.shadow.getElementById("label-decor-witness-side"),this.labelDecorWindows=this.shadow.getElementById("label-decor-windows"),this.optionDecorBuilding=this.shadow.getElementById("option-decor-building"),this.optionDecorTree=this.shadow.getElementById("option-decor-tree"),this.optionDecorCrop=this.shadow.getElementById("option-decor-crop"),this.optionDecorMound=this.shadow.getElementById("option-decor-mound"),this.optionDecorStreetlight=this.shadow.getElementById("option-decor-streetlight"),this.optionDecorVehicle=this.shadow.getElementById("option-decor-vehicle"),this.optionDecorAircraft=this.shadow.getElementById("option-decor-aircraft"),this.optionDecorEntity=this.shadow.getElementById("option-decor-entity"),this.labelDecorLights=this.shadow.getElementById("label-decor-lights"),this.optionDecorWitness=this.shadow.getElementById("option-decor-witness"),this.ufoElement.canvasElement.addEventListener("pointerdown",t=>{this.focus({preventScroll:!0}),this.onPointerDown(t)}),this.ufoElement.canvasElement.addEventListener("pointermove",t=>this.onPointerMove(t)),this.ufoElement.canvasElement.addEventListener("contextmenu",t=>this.onContextMenu(t)),this.contextGroupButton.addEventListener("click",()=>this.groupSelected()),this.contextUngroupButton.addEventListener("click",()=>this.ungroupSelected()),this.contextBringToFrontButton.addEventListener("click",()=>this.bringSelectedToFront()),this.contextSendToBackButton.addEventListener("click",()=>this.sendSelectedToBack()),this.contextDeleteButton.addEventListener("click",()=>{this.hideContextMenu(),this.deleteShape()}),this.contextAddVertexButton.addEventListener("click",()=>this.addVertexAtContextMenu()),this.contextDeleteVertexButton.addEventListener("click",()=>this.deleteVertexAtContextMenu()),this.contextViewTestimonyButton.addEventListener("click",()=>this.viewWitnessTestimony()),this.playPauseButton.addEventListener("click",()=>{this.ufoElement.togglePlayPause(),this.syncPlaybackControls()}),this.loopButton.addEventListener("click",()=>{this.ufoElement.toggleLoop(),this.syncPlaybackControls()}),this.seekInput.addEventListener("input",()=>this.ufoElement.currentTime=Number(this.seekInput.value)),this.recordButton.addEventListener("click",()=>this.toggleRecording()),this.addShapeButton.addEventListener("click",()=>this.addShape()),this.deleteShapeButton.addEventListener("click",()=>this.deleteShape()),this.exportButton.addEventListener("click",()=>this.exportJson()),this.importFileInput.addEventListener("change",()=>this.importFromFile()),this.importUrlButton.addEventListener("click",()=>this.importFromUrl()),this.testimonySourceSelect.addEventListener("change",()=>this.updateWitnessMetadata()),this.testimonyFollowedUpSelect.addEventListener("change",()=>this.updateWitnessMetadata()),this.narrativeDraftButton.addEventListener("click",()=>this.draftFromDescription()),this.narrativeStopButton.addEventListener("click",()=>this.narrativeAbort?.abort()),this.narrativeRememberInput.addEventListener("change",()=>this.rememberNarrativeKey()),this.narrativeWorkspaceInput.addEventListener("input",()=>this.rememberNarrativeKey()),this.narrativeKeyInput.addEventListener("input",()=>{this.rememberNarrativeKey(),this.syncNarrativeEnabled()}),this.narrativeCreditLink.textContent=`${Ts[0].name} — ${Ts[0].credit}`,this.narrativeCreditLink.href=Ts[0].creditUrl,this.labelNarrativeKey.textContent=this.messages.narrativeKey.replace("{source}",Ts[0].name),this.narrativeWorkspaceInput.title=this.messages.narrativeWorkspaceHint,this.restoreNarrativeKey(),this.syncNarrativeEnabled(),this.durationInput.addEventListener("input",()=>{this.ufoElement.durationSeconds=this.durationInput.value===""?void 0:Number(this.durationInput.value),this.ufoElement.refresh(),this.updateDurationValidity(),this.scheduleWeatherLookup()}),this.sourceSelect.addEventListener("change",()=>this.selectUnit(this.sourceSelect.value)),this.shapeTitleInput.addEventListener("input",()=>this.updateShapeTitle()),this.apparentWidthInput.addEventListener("input",()=>this.typing(this.apparentWidthInput,()=>this.onApparentWidthInput())),this.realWidthInput.addEventListener("input",()=>this.typing(this.realWidthInput,()=>this.onRealWidthInput())),this.objectDistanceInput.addEventListener("input",()=>this.typing(this.objectDistanceInput,()=>this.onDistanceInput())),this.sizeLockSelect.addEventListener("change",()=>this.applySizeLock()),this.clearDistanceHypothesisButton.addEventListener("click",()=>this.clearDistanceHypothesis()),this.addDecorWitnessButton.addEventListener("click",()=>this.addDecor("witness")),this.addDecorBuildingButton.addEventListener("click",()=>this.addDecor()),this.deleteDecorButton.addEventListener("click",()=>this.deleteDecor()),this.decorSelect.addEventListener("change",()=>this.selectDecor(this.decorSelect.value));for(const t of[this.decorTitleInput,this.decorEastInput,this.decorNorthInput,this.decorAltitudeInput,this.decorHeadingInput,this.decorColorInput,this.decorSightingUrlInput,this.decorWidthInput,this.decorLengthInput,this.decorHeightInput,this.decorModelUrlInput,this.decorModelTitleInput,this.decorModelAuthorInput,this.decorModelLicenseInput,this.decorModelSourceInput,this.decorFloorsInput,this.decorOccupiedFloorInput])t.addEventListener("input",()=>this.updateDecor());this.decorWitnessSideSelect.addEventListener("change",()=>this.updateDecor()),this.decorModelSelect.addEventListener("change",()=>this.updateDecorModelChoice()),this.addMilestoneButton.addEventListener("click",()=>this.addMilestone()),this.deleteMilestoneButton.addEventListener("click",()=>this.deleteMilestone()),this.milestoneSelect.addEventListener("change",()=>this.selectMilestone(Number(this.milestoneSelect.value)));for(const t of[this.milestoneLabelInput,this.milestoneNoteInput])t.addEventListener("input",()=>this.updateMilestone());this.confirmAcceptButton.addEventListener("click",()=>this.answerConfirm(!0)),this.confirmDeclineButton.addEventListener("click",()=>this.answerConfirm(!1)),this.confirmOverlay.addEventListener("click",t=>{t.target===this.confirmOverlay&&this.answerConfirm(!1)});for(const t of ia)this.decorWindowInputs[t].addEventListener("input",()=>this.updateDecorWindows());this.decorLitInput.addEventListener("input",()=>this.updateDecorLit()),this.decorLightRigSelect.addEventListener("change",()=>this.updateDecorLightRig()),this.lookAtDecorButton.addEventListener("click",()=>this.lookAtDecor()),this.showMeteorButton.addEventListener("click",()=>this.showNextMeteor()),this.showCometButton.addEventListener("click",()=>this.lookAtComet()),this.ufoElement.addEventListener("timeupdate",()=>{this.onSelectionOrTimeChanged(),this.syncPlaybackControls(),this.dispatchEvent(new CustomEvent("sightingchange"))}),this.addEventListener("keydown",this.handleKeyDown);for(const t of mm)this.presetButtons[t].addEventListener("click",()=>this.setAppearance({presetId:t}));this.colorInput.addEventListener("input",()=>this.setAppearance({color:this.colorInput.value})),this.transparencyInput.addEventListener("input",()=>this.setAppearance({transparency:Number(this.transparencyInput.value)})),this.brightnessInput.addEventListener("input",()=>this.setAppearance({brightness:Number(this.brightnessInput.value)})),this.blurInput.addEventListener("input",()=>{this.setAppearance({blur:Number(this.blurInput.value)}),this.refreshBlurDistanceBound()}),this.haloScaleInput.addEventListener("input",()=>this.setAppearance({haloScale:Number(this.haloScaleInput.value)}));for(const t of[this.latInput,this.lngInput,this.headingInput,this.pitchInput,this.rollInput,this.elevationInput])t.addEventListener("input",()=>this.updateObserver());for(const t of[this.focalLengthInput,this.fNumberInput,this.exposureInput,this.focusDistanceInput])t.addEventListener("input",()=>this.updateObserver());this.searchPlaceButton.addEventListener("click",()=>void this.searchPlace()),this.placeNameInput.addEventListener("keydown",t=>{t.key==="Enter"&&(t.preventDefault(),this.searchPlace())}),this.placeMatchSelect.addEventListener("change",()=>this.applyPlaceMatch(this.placeMatchSelect.selectedIndex)),this.placeNameInput.addEventListener("input",()=>this.updatePlaceName()),this.headingInput.addEventListener("focus",()=>this.sceneElement.setCompassForced(!0)),this.headingInput.addEventListener("blur",()=>this.sceneElement.setCompassForced(!1)),this.instrumentSelect.addEventListener("change",()=>{const t=this.ufoElement.sighting.instrument;this.ufoElement.sighting.instrumentId=this.instrumentSelect.value;const n=new Map(this.ufoElement.sighting.timeline.allKeyframes.map(i=>[i.t,an.fovOf(this.ufoElement.sighting,i.t)]));this.retuneFieldOfView(t),this.retuneExposure(t),an.reproject(this.ufoElement.sighting,t,n),this.sceneElement.applyFrameFormat(),this.syncOpticsFromInstrument(),this.ufoElement.refresh(),this.dispatchEvent(new CustomEvent("sightingchange"))}),this.utcOffsetInput.addEventListener("input",()=>this.updateUtcOffset()),this.timeZoneSelect.addEventListener("change",()=>{this.autoFilledTimeZone=void 0,this.updateTimeZone()}),this.obsTimeInput.addEventListener("input",()=>this.updateObservationTime()),this.obsEndTimeInput.addEventListener("input",()=>this.updateObservationEndTime()),this.obsTimeNativeInput.addEventListener("change",()=>this.writeFromPicker(this.obsTimeNativeInput,this.obsTimeQualifier,this.obsTimeInput,()=>this.updateObservationTime())),this.obsEndTimeNativeInput.addEventListener("change",()=>this.writeFromPicker(this.obsEndTimeNativeInput,this.obsEndTimeQualifier,this.obsEndTimeInput,()=>this.updateObservationEndTime())),this.obsTimeQualifier.addEventListener("change",()=>this.writeFromPicker(this.obsTimeNativeInput,this.obsTimeQualifier,this.obsTimeInput,()=>this.updateObservationTime())),this.obsEndTimeQualifier.addEventListener("change",()=>this.writeFromPicker(this.obsEndTimeNativeInput,this.obsEndTimeQualifier,this.obsEndTimeInput,()=>this.updateObservationEndTime())),this.edtfModeButton.addEventListener("click",()=>this.setEdtfMode(!this.edtfMode)),this.obsTimeInput.addEventListener("blur",()=>this.validateEdtfTimeInput(this.obsTimeInput)),this.obsEndTimeInput.addEventListener("blur",()=>this.validateEdtfTimeInput(this.obsEndTimeInput));for(const t of[this.witnessIdInput,this.witnessDirNameInput,this.witnessTitleInput,this.witnessLastNameInput,this.witnessFirstNamesInput,this.witnessAgeInput,this.witnessOccupationInput,this.caseIdInput])t.addEventListener("input",()=>this.updateWitnessMetadata());this.descriptionInput.addEventListener("input",()=>{this.updateDescription(),this.syncNarrativeEnabled()}),this.tagsInput.addEventListener("input",()=>this.updateTags());for(const t of this.weatherFields){if(t===this.iceCrystalAlignmentInput){t.addEventListener("input",()=>this.applyIceAlignmentAtPlayhead());continue}t.addEventListener("input",()=>this.applyWeatherAtPlayhead())}for(const t of this.soundFields)t.addEventListener("input",()=>this.applySoundAtPlayhead());this.weatherInferredInput.addEventListener("change",()=>this.onWeatherInferredToggled()),this.skyDetailsButton=this.shadow.getElementById("sky-details"),this.clampedLines=[this.shadow.getElementById("weather-source"),this.shadow.getElementById("sky-candidates")],this.skyDetailsButton.addEventListener("click",()=>this.toggleSkyDetails()),this.groupTabs=[...this.shadow.querySelectorAll(".group-tab")],this.groupPanels=this.groupTabs.map(t=>this.shadow.getElementById(t.getAttribute("aria-controls")));for(const t of this.groupTabs)t.addEventListener("click",()=>this.toggleGroup(t,!this.isGroupOpen(t)));this.paramSummary=this.shadow.getElementById("param-summary"),this.paramSummaryBuilder=new bf(this.messages,this.showerLanguage(),this.said,this.tagNames),this.paramSummary.addEventListener("click",t=>this.onParamSummaryClick(t)),this.toggleGroup(this.groupTabs[this.groupTabs.length-1],!0),this.updatePresetButtons(),this.setRecordButtonLabel(!1),this.applyAppearanceAtPlayhead(),this.shapeTitleInput.value=this.shapeLabel(this.currentSourceId),this.updateShapeTitle(),this.currentDecorId=this.ufoElement.sighting.decor[0]?.id,this.refreshDecorList(),this.sceneElement.setCloudRendering("volume"),this.cloudEditor=Gv(this.shadow.getElementById("cloud-editor"),this.sceneElement,(t=!0)=>{t&&(this.weatherFromRecords=!1,this.cancelWeatherLookup(),this.ufoElement.sighting.weatherSource=void 0,this.syncWeatherSourceState())},(t,n)=>{this.headingInput.value=String(this.rounded(t)),this.pitchInput.value=String(this.rounded(n)),this.updateObserver()},za(vs.preferencesFor(this),Hh)),this.currentMilestoneT=this.ufoElement.sighting.milestones[0]?.t,this.refreshMilestoneList(),this.onSelectionOrTimeChanged(),this.syncDurationField(),this.syncPlaybackControls(),this.refreshSourceRows(),this.refreshTimeQualifierOptions(),this.refreshTimeZoneOptions(),this.syncWeatherSourceState(),this.loadLocaleMessages()}static get observedAttributes(){return["src"]}connectedCallback(){this.hasAttribute("tabindex")||(this.tabIndex=-1);const e=this.getAttribute("src");e&&this.importFromUrl(e)}attributeChangedCallback(e,t,n){e==="src"&&n&&n!==t&&this.isConnected&&this.importFromUrl(n)}disconnectedCallback(){this.cloudEditor.stopManipulation(),document.removeEventListener("click",this.handleOutsideContextMenuClick),this.endDrag()}setCloudRendering(e){this.sceneElement.setCloudRendering(e)}showWeatherEditor(){const e=this.groupPanels.findIndex(t=>t.id==="group-weather");e>=0&&this.toggleGroup(this.groupTabs[e],!0)}get sightingData(){return this.ufoElement.sightingData}set sightingData(e){this.endDrag(),this.ufoElement.sightingData=e,this.cloudEditor.reset(),this.currentSourceId=this.ufoElement.sighting.timeline.sourceIds[0]??ml,this.selectedSourceIds=new Set([this.currentSourceId]),this.refreshSourceList(),this.currentDecorId=this.ufoElement.sighting.decor[0]?.id,this.refreshDecorList(),this.currentMilestoneT=this.ufoElement.sighting.milestones[0]?.t,this.refreshMilestoneList(),this.onSelectionOrTimeChanged(),this.syncDurationField(),this.syncObservationTimeFields(),this.syncObservationEndTimeFields(),this.chooseTimeInputMode(),this.syncWitnessMetadataFields(),this.refreshTimeZoneOptions(),this.utcOffsetInput.readOnly=this.ufoElement.sighting.event.timeZone!==void 0,this.syncUtcOffsetField(),this.syncPlaceNameField(),this.syncGroundElevationField(),this.syncWeatherOwnership()}exportJson(){const e=this.sightingData,t=`${e.witness?.id??"sighting"}-sighting.json`,n=new Blob([JSON.stringify(e,null,2)],{type:"application/json"}),i=URL.createObjectURL(n),s=document.createElement("a");s.href=i,s.download=t,s.click(),URL.revokeObjectURL(i)}async importFromFile(){const e=this.importFileInput.files?.[0];if(e)try{const t=await new Promise((n,i)=>{const s=new FileReader;s.onload=()=>n(s.result),s.onerror=()=>i(s.error),s.readAsText(e)});this.sightingData=JSON.parse(t)}catch{window.alert(this.messages.importError)}finally{this.importFileInput.value=""}}async importFromUrl(e=this.importUrlInput.value.trim()){if(e)try{this.sightingData=await fu.json(e)}catch(t){window.alert(this.importErrorFor(t))}}importErrorFor(e){if(!(e instanceof Os))return this.messages.importError;switch(e.kind){case"cors":return this.messages.importErrorCors;case"mixed-content":return this.messages.importErrorMixedContent;case"unreachable":return this.messages.importErrorUnreachable;case"status":return this.messages.importErrorStatus.replace("{status}",String(e.status??""));case"malformed":return this.messages.importErrorMalformed;default:return this.messages.importError}}static NARRATIVE_KEY_STORAGE="rr0-sighting-editor.narrative-key";static NARRATIVE_SCOPE_STORAGE="rr0-sighting-editor.narrative-workspace";narrativeProvider=Ts[0].create();narrativeAbort;async draftFromDescription(){const e=this.descriptionInput.value.trim();if(e===""||this.narrativeAbort)return;const t=this.narrativeAbort=new AbortController;this.setNarrativeBusy(!0);try{const n=await this.narrativeProvider.draft({ask:e,current:this.sightingData,language:this.showerLanguage()==="fr"?"French":"English",credential:this.narrativeKeyInput.value.trim()||void 0,credentialScope:this.narrativeWorkspaceInput.value.trim()||void 0},t.signal);this.applyNarrativeDraft(n)}catch(n){const i=n instanceof Ln&&n.kind==="cancelled";this.narrativeStatus.textContent=i?"":this.narrativeErrorFor(n),this.narrativeStatus.classList.toggle("error",!i)}finally{this.narrativeAbort=void 0,this.setNarrativeBusy(!1)}}applyNarrativeDraft(e){const{description:t,...n}=e.recording,{utcOffsetHours:i,...s}=n,r=n.timeZone?s:n,o=yi.stated(r);if(o.length>0){const l=this.ufoElement.sighting.provenance,c=zh(this.ufoElement.sighting);this.sightingData=yi.apply(c,Pl.loadable(r),o),this.ufoElement.sighting.provenance=l,this.recordNarrativeProvenance(e,o),this.ufoElement.sighting.event.timeZone&&this.applyTimeZoneOffset()}this.narrativeStatus.textContent=o.length>0?this.messages.narrativeApplied.replace("{count}",String(o.length)):this.messages.narrativeUnchanged,this.narrativeStatus.classList.remove("error"),this.showNarrativeReport(e),this.syncNarrativeEnabled()}recordNarrativeProvenance(e,t){const n=this.ufoElement.sighting,i=new Set(t);for(const s of e.claims)!i.has(s.path)&&!t.some(r=>s.path.startsWith(`${r}.`))||n.provenance.set(s.path,{basis:s.basis,rationale:s.rationale,of:Mt.valueAt(zh(this.ufoElement.sighting),s.path)})}static valueAt(e,t){let n=e;for(const i of t.split(".")){if(typeof n!="object"||n===null)return;n=n[i]}return n}showNarrativeReport(e){this.narrativeReport.replaceChildren();for(const t of["assumed","derived","stated"]){const n=e.claims.filter(i=>i.basis===t);if(n.length!==0){this.narrativeReport.append(this.narrativeHeading(this.messages[bA[t]]));for(const i of n){const s=document.createElement("div");s.className=`claim ${t}`;const r=document.createElement("code");r.textContent=i.path;const o=document.createElement(t==="stated"?"q":"span");o.textContent=i.rationale,s.append(r,o),this.narrativeReport.append(s)}}}if(e.gaps.length>0){this.narrativeReport.append(this.narrativeHeading(this.messages.narrativeGaps));const t=document.createElement("ul");t.className="gaps";for(const n of e.gaps){const i=document.createElement("li");i.textContent=n,t.append(i)}this.narrativeReport.append(t)}this.narrativeReport.hidden=this.narrativeReport.childElementCount===0}narrativeHeading(e){const t=document.createElement("h4");return t.textContent=e,t}setNarrativeBusy(e){this.descriptionInput.disabled=e,this.narrativeStopButton.hidden=!e,e&&(this.narrativeStatus.textContent=this.messages.narrativeWorking,this.narrativeStatus.classList.remove("error")),this.syncNarrativeEnabled()}syncNarrativeEnabled(){const e=Ts[0].name,t=this.narrativeProvider.needsCredential&&this.narrativeKeyInput.value.trim()==="",n=this.descriptionInput.value.trim()==="";this.narrativeDraftButton.disabled=!!this.narrativeAbort||t||n,this.narrativeDraftButton.title=t?this.messages.narrativeNeedsKey.replace("{source}",e):n?this.messages.narrativeNeedsAsk:"",this.narrativeKeyInput.parentElement.hidden=!this.narrativeProvider.needsCredential,this.narrativeRememberInput.parentElement.hidden=!this.narrativeProvider.needsCredential,this.narrativeWorkspaceInput.parentElement.hidden=!this.narrativeProvider.acceptsCredentialScope;const i=this.narrativeKeyInput.value.trim(),s=i!==""&&!i.startsWith("sk-ant-");this.narrativeKeyInput.classList.toggle("invalid",s),this.narrativeKeyInput.title=s?this.messages.narrativeKeyUnlikely:""}narrativeErrorFor(e){if(!(e instanceof Ln))return this.messages.narrativeErrorMalformed;switch(e.kind){case"rejected":return this.messages.narrativeErrorRejected.replace("{detail}",e.detail??"");case"credential":return this.messages.narrativeErrorCredential;case"rate-limited":return this.messages.narrativeErrorRateLimited;case"refused":return this.messages.narrativeErrorRefused;case"unreachable":return this.messages.narrativeErrorUnreachable;default:return this.messages.narrativeErrorMalformed}}rememberNarrativeKey(){try{this.narrativeRememberInput.checked?(localStorage.setItem(Mt.NARRATIVE_KEY_STORAGE,this.narrativeKeyInput.value),localStorage.setItem(Mt.NARRATIVE_SCOPE_STORAGE,this.narrativeWorkspaceInput.value)):(localStorage.removeItem(Mt.NARRATIVE_KEY_STORAGE),localStorage.removeItem(Mt.NARRATIVE_SCOPE_STORAGE))}catch{}}restoreNarrativeKey(){let e=null;try{e=localStorage.getItem(Mt.NARRATIVE_KEY_STORAGE)}catch{return}e!==null&&(this.narrativeKeyInput.value=e,this.narrativeWorkspaceInput.value=localStorage.getItem(Mt.NARRATIVE_SCOPE_STORAGE)??"",this.narrativeRememberInput.checked=!0)}numberOrUndefined(e){return e===""?void 0:Number(e)}stringOrUndefined(e){return e===""?void 0:e}wrapDegrees(e,t){if(e===void 0)return;const n=(e%360+360)%360;return String(n)!==t.value&&(t.value=String(n)),n}refreshSourceRows(){this.placeSourceRow.replaceChildren(document.createTextNode(`${this.messages.according} `),this.sourcePicker("place",QT,e=>{this.placeProvider=e.create()})),this.weatherSourceRow.replaceChildren(this.sourcePicker("weather",eA,e=>{this.weatherInference=new Th(e.create()),this.scheduleWeatherLookup()})),this.terrainSourceRows.replaceChildren(this.labelledPicker("elevation",this.messages.sourceElevation,Ch,()=>this.applyTerrainSources()),this.labelledPicker("imagery",this.messages.sourceImagery,hm,()=>this.applyTerrainSources()),this.labelledPicker("decor-model",this.messages.decorModel,El,()=>this.applyDecorModelSource()))}sourcePicker(e,t,n){const i=document.createDocumentFragment(),s=document.createElement("select");s.id=`${e}Source`;for(const l of t){const c=document.createElement("option");c.value=l.id,c.textContent=l.name,c.title=l.credit,s.appendChild(c)}s.value=this.chosenSourceId.get(e)??t[0].id;const r=document.createElement("a");r.className="source-credit",r.target="_blank",r.rel="noopener noreferrer";const o=()=>{const l=Ia(t,s.value);s.title=l.credit,r.href=l.creditUrl,r.textContent=l.credit};return o(),s.addEventListener("change",()=>{this.chosenSourceId.set(e,s.value),o(),n(Ia(t,s.value))}),i.append(s,document.createTextNode(" "),r),i}labelledPicker(e,t,n,i){const s=document.createElement("label"),r=document.createElement("span");return r.textContent=t,s.append(r,this.sourcePicker(e,n,i)),s}applyTerrainSources(){this.sceneElement.setTerrainProviders({elevation:Ia(Ch,this.chosenSourceId.get("elevation")).create(),imagery:Ia(hm,this.chosenSourceId.get("imagery")).create()}),this.ufoElement.refresh()}applyDecorModelSource(){this.decorModelProvider=Ia(El,this.chosenSourceId.get("decor-model")).create(),this.sceneElement.setDecorModelProvider(this.decorModelProvider),this.refreshDecorModelOptions(),this.ufoElement.refresh()}get placeSearchLanguage(){return navigator.languages?.[0]}set placeSearchProvider(e){this.placeProvider=e}async searchPlace(){const e=this.placeNameInput.value.trim();if(e==="")return;const t=++this.placeSearchToken;this.placeStatusText.textContent=this.messages.placeSearching;let n;try{n=await this.placeProvider.search(e,{language:this.placeSearchLanguage})}catch{if(t!==this.placeSearchToken)return;this.placeStatusText.textContent=this.messages.placeSearchFailed;return}t===this.placeSearchToken&&(this.placeMatches=n,this.refreshPlaceMatches(),n.length>0&&this.applyPlaceMatch(0))}refreshPlaceMatches(){this.placeMatchSelect.replaceChildren(...this.placeMatches.map(t=>{const n=document.createElement("option");return n.textContent=t.name,n.title=t.name,n})),this.placeMatchRow.hidden=this.placeMatches.length===0;const e=this.placeMatches.length===1?this.messages.placeMatchFound:this.messages.placeMatchesFound;this.placeStatusText.textContent=this.placeMatches.length===0?this.messages.placeNotFound:`${this.placeMatches.length} ${e} `,this.placeSourceRow.hidden=this.placeMatches.length===0}applyPlaceMatch(e){const t=this.placeMatches[e];t&&(this.placeMatchSelect.selectedIndex=e,this.placeNameInput.value=t.name,this.placeNameInput.title=t.name,this.latInput.value=String(t.lat),this.lngInput.value=String(t.lng),this.namedCoordinates={lat:t.lat,lng:t.lng},this.updateObserver())}updatePlaceName(){this.placeMatches=[],this.placeMatchRow.hidden=!0,this.placeStatusText.textContent="",this.placeSourceRow.hidden=!0,this.placeNameInput.title=this.placeNameInput.value,this.namedCoordinates=void 0,this.updateObserver()}schedulePlaceReverse(){if(!this.namedCoordinates)return;const e=this.numberOrUndefined(this.latInput.value),t=this.numberOrUndefined(this.lngInput.value);e===void 0||t===void 0||Math.abs(e-this.namedCoordinates.lat)<Ca&&Math.abs(t-this.namedCoordinates.lng)<Ca||(clearTimeout(this.placeReverseTimer),this.placeReverseTimer=setTimeout(()=>void this.reversePlace(e,t),um))}scheduleTimeZoneLookup(){const e=this.numberOrUndefined(this.latInput.value),t=this.numberOrUndefined(this.lngInput.value);if(e===void 0||t===void 0)return;const n=this.ufoElement.sighting.event.timeZone;if(n&&n!==this.autoFilledTimeZone)return;const i=this.timeZoneLookedUpAt;i&&Math.abs(e-i.lat)<Ca&&Math.abs(t-i.lng)<Ca||(clearTimeout(this.timeZoneLookupTimer),this.timeZoneLookupTimer=setTimeout(()=>void this.lookUpTimeZone(e,t),um))}async lookUpTimeZone(e,t){this.timeZoneLookedUpAt={lat:e,lng:t};const n=await this.timeZoneProvider.zoneAt(e,t),i=this.ufoElement.sighting.event.timeZone;!n||i&&i!==this.autoFilledTimeZone||this.timeZones.available().includes(n)&&(this.autoFilledTimeZone=n,this.timeZoneSelect.value=n,this.updateTimeZone(),this.dispatchEvent(new CustomEvent("sightingchange")))}async reversePlace(e,t){const n=++this.placeSearchToken;let i;try{i=await this.placeProvider.reverse(e,t,{language:this.placeSearchLanguage})}catch{return}n===this.placeSearchToken&&(this.namedCoordinates={lat:e,lng:t},this.placeNameInput.value=i?.name??"",this.placeNameInput.title=i?.name??"",this.placeMatches=[],this.placeMatchRow.hidden=!0,this.placeStatusText.textContent=i?"":this.messages.placeNotFound,this.placeSourceRow.hidden=!i,this.updateObserver())}updateObserver(){if(this.ufoElement.playbackState==="playing")return;const e=this.numberOrUndefined(this.latInput.value),t=this.numberOrUndefined(this.lngInput.value),n=this.wrapDegrees(this.numberOrUndefined(this.headingInput.value),this.headingInput),i=this.numberOrUndefined(this.pitchInput.value)??0,s=this.numberOrUndefined(this.rollInput.value)??0,r=this.numberOrUndefined(this.elevationInput.value)??this.groundElevationM??0,o=Math.max(0,r-(this.groundElevationM??0)),l=this.ufoElement.sighting.event,c=this.ufoElement.sighting.witnessTrack,h=this.ufoElement.currentTime,d=this.stringOrUndefined(this.placeNameInput.value.trim());l.place=e!==void 0&&t!==void 0?[{lat:e,lng:t,name:d}]:void 0;const u=this.ufoElement.sighting.instrument,f=this.numberOrUndefined(this.focalLengthInput.value),p=(u.frame&&f!==void 0?st.fieldOfViewDegAt(u,f):f)??this.currentFovDeg(),v=this.numberOrUndefined(this.fNumberInput.value),m=this.statedExposureSeconds(u);this.ufoElement.sighting.exposureSeconds=m===u.exposureSeconds?void 0:m;const g=this.numberOrUndefined(this.focusDistanceInput.value),_=Math.abs(p-st.fieldOfViewDeg(u))>.01||v!==u.fNumber||g!==void 0;e===void 0&&t===void 0&&n===void 0&&i===0&&s===0&&o===0&&!_?c.removeKeyframeAt(h):c.addKeyframe(h,{lat:e,lng:t,elevationM:o,headingDeg:n,pitchDeg:i,rollDeg:s===0?void 0:s,fovDeg:p,fNumber:v,focusDistanceM:g}),this.ufoElement.refresh(),this.scheduleWeatherLookup(),this.schedulePlaceReverse(),this.scheduleTimeZoneLookup(),this.scheduleGroundElevation(),this.updateUtcOffsetValidity()}applyEdtfTimeInput(e,t){const n=e.value.trim();if(n==="")t(void 0);else{const i=af(n);if(!i)return;t(i)}e.setCustomValidity(""),e.classList.remove("invalid"),this.dropDurationOutrankedByDates(),this.ufoElement.sighting.event.timeZone&&this.applyTimeZoneOffset(),this.ufoElement.refresh(),this.syncDurationField(),this.scheduleWeatherLookup()}dropDurationOutrankedByDates(){const e=this.ufoElement.sighting.event;e.durationSeconds!==void 0&&ja({...e,durationSeconds:void 0})!==void 0&&(this.ufoElement.durationSeconds=void 0)}validateEdtfTimeInput(e){const t=e.value.trim();t===""||af(t)||(e.setCustomValidity(this.messages.edtfInvalid),e.classList.add("invalid"))}refreshTimeZoneOptions(){const e=document.createElement("option");e.value="",e.textContent=this.messages.timeZoneManual,this.timeZoneSelect.replaceChildren(e,...this.timeZones.available().map(t=>{const n=document.createElement("option");return n.value=t,n.textContent=t,n})),this.timeZoneSelect.value=this.ufoElement.sighting.event.timeZone??""}updateTimeZone(){const e=this.stringOrUndefined(this.timeZoneSelect.value);this.ufoElement.sighting.event.timeZone=e,this.applyTimeZoneOffset()}applyTimeZoneOffset(){const e=this.ufoElement.sighting.event,t=e.timeZone&&e.time?this.timeZones.offsetHoursAt(e.timeZone,e.time):void 0;t!==void 0&&(e.utcOffsetHours=t),this.utcOffsetInput.readOnly=e.timeZone!==void 0,this.syncUtcOffsetField(),this.ufoElement.refresh(),this.scheduleWeatherLookup()}updateUtcOffset(){this.ufoElement.sighting.event.utcOffsetHours=this.numberOrUndefined(this.utcOffsetInput.value),this.updateUtcOffsetValidity(),this.ufoElement.refresh(),this.scheduleWeatherLookup()}updateObservationTime(){this.applyEdtfTimeInput(this.obsTimeInput,e=>{this.ufoElement.sighting.event.time=e})}updateObservationEndTime(){this.applyEdtfTimeInput(this.obsEndTimeInput,e=>{this.ufoElement.sighting.event.endTime=e})}updateWitnessMetadata(){const e=this.ufoElement.sighting,t=this.witnessFirstNamesInput.value.split(",").map(i=>i.trim()).filter(i=>i.length>0),n={id:this.stringOrUndefined(this.witnessIdInput.value),dirName:this.stringOrUndefined(this.witnessDirNameInput.value),title:this.stringOrUndefined(this.witnessTitleInput.value),lastName:this.stringOrUndefined(this.witnessLastNameInput.value),firstNames:t.length>0?t:void 0};e.witness=Object.values(n).some(i=>i!==void 0)?n:void 0,e.caseId=this.stringOrUndefined(this.caseIdInput.value),this.updateTestimony(),this.ufoElement.refresh()}updateTestimony(){const e=this.ufoElement.sighting,t=this.testimonyFollowedUpSelect.value,n={witnessAgeYears:this.numberOrUndefined(this.witnessAgeInput.value),witnessOccupation:this.witnessOccupationInput.value.trim()===""?void 0:this.said.write(e.testimony?.witnessOccupation,this.witnessOccupationInput.value,this.writingLanguage),source:this.stringOrUndefined(this.testimonySourceSelect.value),followedUp:t===""?void 0:t==="yes"};e.testimony=Object.values(n).some(i=>i!==void 0)?n:void 0}updateDescription(){this.ufoElement.sighting.event.description=this.said.write(this.ufoElement.sighting.event.description,this.descriptionInput.value,this.writingLanguage),this.ufoElement.refresh()}updateTags(){const e=this.tagsInput.value.split(",").map(t=>t.trim()).filter(t=>t.length>0).map(t=>this.tagNames.stored(t));this.ufoElement.sighting.event.tags=e.length>0?e:void 0,this.ufoElement.refresh()}applyWeatherAtPlayhead(){if(this.ufoElement.playbackState==="playing")return;this.sceneElement.resumeWeatherAudio(),this.weatherFromRecords&&(this.weatherFromRecords=!1,this.cancelWeatherLookup(),this.ufoElement.sighting.weatherSource=void 0,this.syncWeatherSourceState());const e={...Ft(this.ufoElement.sighting,this.ufoElement.currentTime),cloudCover:Number(this.cloudCoverInput.value),highCloudCover:Number(this.highCloudCoverInput.value),lowerCloudCover:Number(this.cloudCoverInput.value),cloudDarkness:Number(this.cloudDarknessInput.value),cloudBaseM:this.numberOrUndefined(this.cloudBaseInput.value),precipitationType:this.precipitationTypeSelect.value,precipitationIntensity:Number(this.precipitationIntensityInput.value),windDirectionDeg:this.wrapDegrees(this.numberOrUndefined(this.windDirectionInput.value),this.windDirectionInput)??0,windSpeed:Number(this.windSpeedInput.value),storm:this.stormInput.checked};this.ufoElement.sighting.weatherTrack.addKeyframe(this.ufoElement.currentTime,e),this.ufoElement.refresh()}applyIceAlignmentAtPlayhead(){if(this.ufoElement.playbackState==="playing")return;this.sceneElement.resumeWeatherAudio();const e={...Ft(this.ufoElement.sighting,this.ufoElement.currentTime),iceCrystalAlignment:Number(this.iceCrystalAlignmentInput.value)};this.ufoElement.sighting.weatherTrack.addKeyframe(this.ufoElement.currentTime,e),this.ufoElement.refresh()}buildSoundKindOptions(){for(const e of Rv){const t=document.createElement("option");t.value=e,t.textContent=this.soundKindLabel(e,this.messages),this.soundKindOptions.set(e,t),this.soundKindSelect.appendChild(t)}}soundKindLabel(e,t){switch(e){case"hum":return t.soundHum;case"whistle":return t.soundWhistle;case"rumble":return t.soundRumble;case"crackle":return t.soundCrackle;default:return t.soundNone}}applySoundAtPlayhead(){if(this.ufoElement.playbackState==="playing")return;const e=this.readSound();this.ufoElement.sighting.soundTrack.addKeyframe(this.ufoElement.currentTime,e),this.updateSoundPitchReadout(e.pitchHz),this.updateSoundFieldsDisabledState(e),this.ufoElement.refresh(),this.previewSound(e)}previewSound(e){clearTimeout(this.soundPreviewTimer),this.ufoElement.previewSound(e),this.soundPreviewTimer=setTimeout(()=>this.ufoElement.stopSoundPreview(),oA)}readSound(){return{kind:this.soundKindSelect.value,volume:Number(this.soundVolumeInput.value),pitchHz:Number(this.soundPitchInput.value),src:this.soundSrcInput.value.trim()||void 0}}syncSoundFromTimeline(){if(this.ufoElement.playbackState==="playing")return;const e=uu(this.ufoElement.sighting,this.ufoElement.currentTime),t=this.shadow.activeElement;t!==this.soundKindSelect&&(this.soundKindSelect.value=e.kind),t!==this.soundVolumeInput&&(this.soundVolumeInput.value=String(e.volume)),t!==this.soundPitchInput&&(this.soundPitchInput.value=String(e.pitchHz)),t!==this.soundSrcInput&&(this.soundSrcInput.value=e.src??""),this.updateSoundPitchReadout(e.pitchHz),this.updateSoundFieldsDisabledState(e)}updateSoundPitchReadout(e){this.soundPitchValue.textContent=`${Math.round(e)} Hz`}updateSoundFieldsDisabledState(e){const t=e.kind==="none"&&!e.src;this.soundVolumeInput.disabled=t,this.soundSrcInput.disabled=t,this.soundPitchInput.disabled=t||e.src!==void 0}set weatherProvider(e){this.weatherInference=new Th(e),this.scheduleWeatherLookup()}onWeatherInferredToggled(){this.weatherFromRecords=this.weatherInferredInput.checked,this.weatherFromRecords?this.scheduleWeatherLookup():(this.cancelWeatherLookup(),this.ufoElement.sighting.weatherSource=void 0,this.syncWeatherSourceState())}scheduleWeatherLookup(){this.weatherFromRecords&&(clearTimeout(this.weatherLookupTimer),this.weatherLookupTimer=setTimeout(()=>void this.inferWeather(),lA))}cancelWeatherLookup(){clearTimeout(this.weatherLookupTimer),this.weatherLookupToken++,this.weatherLookupPending=!1}async inferWeather(){if(!this.weatherFromRecords)return;const e=++this.weatherLookupToken;this.weatherLookupPending=!0,this.syncWeatherSourceState();const t=await this.weatherInference.infer(this.ufoElement.sighting);e!==this.weatherLookupToken||!this.weatherFromRecords||(this.weatherLookupPending=!1,this.weatherLookupResult=t,t.status==="inferred"?(this.weatherInference.applyTo(this.ufoElement.sighting,t),this.weatherTrackSpan=this.ufoElement.seekableDuration,this.ufoElement.refresh(),this.syncWeatherFromTimeline()):this.ufoElement.sighting.weatherSource=void 0,this.syncWeatherSourceState())}ensureWeatherTrackSpan(){if(!this.weatherFromRecords||this.ufoElement.sighting.weatherSource===void 0)return;const e=this.ufoElement.seekableDuration;this.weatherTrackSpan===void 0||e===this.weatherTrackSpan||(this.weatherTrackSpan=e,this.scheduleWeatherLookup())}syncWeatherSourceState(){const e=this.ufoElement.sighting.weatherSource,t=this.weatherFromRecords;for(const o of this.weatherFields)o.disabled=t&&e!==void 0&&o!==this.iceCrystalAlignmentInput||this.ufoElement.playbackState==="playing",this.ufoElement.playbackState==="playing"?o.title=this.messages.weatherWhilePlaying:o.title===this.messages.weatherWhilePlaying&&(o.title="");const n=this.weatherInference.canInfer(this.ufoElement.sighting);this.weatherInferredInput.disabled=!n,this.weatherInferredInput.checked=n&&this.weatherFromRecords;const i=n?this.messages.weatherInferredTitle:this.messages.weatherNeedsDateAndPlace;this.weatherInferredInput.title=i,this.labelWeatherInferred.title=i;const s=t&&e!==void 0;if(this.weatherSourceLink.hidden=!s,s){this.weatherSourceRow.hidden=!1,this.weatherSourceText.textContent="",this.weatherSourceLink.href=e.url,this.weatherSourceLink.textContent=this.observationInstantLabel();return}const r=t?this.weatherStatusMessage():"";this.weatherSourceText.textContent=r===""?"":`${r} `,this.weatherSourceRow.hidden=r===""}weatherStatusMessage(){if(this.weatherLookupPending)return this.messages.weatherLookingUp;switch(this.weatherLookupResult?.status){case"unavailable":return this.messages.weatherNoRecord;case"failed":return this.messages.weatherLookupFailed;default:return""}}observationInstantLabel(){const e=this.ufoElement.sighting.event,t=e.time&&Ka(e.time,e.place?.[0]?.lng??0,e.utcOffsetHours);return t?`, ${t.toISOString().slice(0,16).replace("T"," ")} UTC`:""}syncWeatherOwnership(){const e=this.ufoElement.sighting;this.cancelWeatherLookup(),this.weatherLookupResult=void 0,this.weatherFromRecords=e.weatherSource!==void 0||e.weatherTrack.allKeyframes.length===0,this.syncWeatherSourceState(),this.weatherFromRecords&&e.weatherSource===void 0&&this.scheduleWeatherLookup()}syncDurationField(){if(this.shadow.activeElement!==this.durationInput){const e=ja(this.ufoElement.sighting.event);this.durationInput.value=e!==void 0?String(e/1e3):""}this.updateDurationValidity()}updateDurationValidity(){const e=this.durationInput.value==="";this.durationInput.classList.toggle("missing-required",e),this.markUnansweredQuestions(),this.durationInput.setAttribute("aria-invalid",String(e));const t=Fv(this.ufoElement.sighting.event);this.durationInput.title=t==="imprecise"?this.messages.durationImprecise:""}syncPlaybackControls(){this.ensureWeatherTrackSpan();const e=this.ufoElement.playbackState==="playing",t=this.ufoElement.seekableDuration>0;this.playPauseButton.textContent=e?"⏸":"▶",this.playPauseButton.disabled=!t;const n=t?e?this.messages.pause:this.messages.play:this.messages.noDuration;this.playPauseButton.title=n,this.playPauseButton.setAttribute("aria-label",n),this.loopButton.setAttribute("aria-pressed",String(this.ufoElement.autoReplayEnabled)),this.seekInput.max=String(this.ufoElement.seekableDuration),this.shadow.activeElement!==this.seekInput&&(this.seekInput.value=String(this.ufoElement.currentTime)),this.timeStartLabel.textContent=this.ufoElement.positionLabel,this.timeEndLabel.textContent=this.ufoElement.durationLabel,this.syncTimeDisplaySwitch()}switchTimeDisplay(){this.ufoElement.toggleTimeDisplay(),this.timeStartLabel.textContent=this.ufoElement.positionLabel,this.timeEndLabel.textContent=this.ufoElement.durationLabel,this.syncTimeDisplaySwitch()}syncTimeDisplaySwitch(){const e=this.ufoElement.canSwitchTimeDisplay,t=this.ufoElement.showingClockTime?this.messages.switchToElapsed:this.messages.switchToClockTime;for(const[n,i]of[[this.timeStartLabel,this.messages.currentPosition],[this.timeEndLabel,this.messages.duration]])n.title=e?`${i} — ${t}`:i,n.classList.toggle("switchable",e),e?(n.setAttribute("role","button"),n.setAttribute("tabindex","0")):(n.removeAttribute("role"),n.removeAttribute("tabindex"))}static TIME_QUALIFIERS=[{value:"",key:"timeQualifierExact"},{value:"~",key:"timeQualifierApproximate"},{value:"?",key:"timeQualifierUncertain"},{value:"%",key:"timeQualifierBoth"}];refreshTimeQualifierOptions(){for(const e of[this.obsTimeQualifier,this.obsEndTimeQualifier]){const t=e.value;e.replaceChildren(...Mt.TIME_QUALIFIERS.map(n=>{const i=document.createElement("option");return i.value=n.value,i.textContent=this.messages[n.key],i})),e.value=t}}qualifierOf(e){const t=e.trim().slice(-1);return"?~%".includes(t)?t:""}isPickable(e){return e?e.year!==void 0&&e.month!==void 0&&e.day!==void 0&&e.hour!==void 0&&e.minute!==void 0&&(e.second===void 0||e.second===0):!1}pickerValueOf(e){if(!this.isPickable(e))return"";const t=(n,i=2)=>String(n).padStart(i,"0");return`${t(e.year,4)}-${t(e.month)}-${t(e.day)}T${t(e.hour)}:${t(e.minute)}`}writeFromPicker(e,t,n,i){e.value===""&&e.validity.badInput||(n.value=e.value===""?"":`${e.value}${t.value}`,i())}chooseTimeInputMode(){const e=this.ufoElement.sighting.event,t=n=>n===void 0||this.isPickable(n);this.setEdtfMode(!(t(e.time)&&t(e.endTime)))}setEdtfMode(e){this.edtfMode=e,this.edtfModeButton.setAttribute("aria-pressed",String(e));for(const[t,n,i]of[[this.obsTimeInput,this.obsTimeNativeInput,this.obsTimeQualifier],[this.obsEndTimeInput,this.obsEndTimeNativeInput,this.obsEndTimeQualifier]])t.hidden=!e,n.hidden=e,i.hidden=e}syncObservationTimeFields(){const e=this.ufoElement.sighting.event.time;this.obsTimeInput.value=e?Dl(e):"",this.obsTimeNativeInput.value=this.pickerValueOf(e),this.obsTimeQualifier.value=this.qualifierOf(this.obsTimeInput.value),this.obsTimeInput.setCustomValidity(""),this.obsTimeInput.classList.remove("invalid")}syncObservationEndTimeFields(){const e=this.ufoElement.sighting.event.endTime;this.obsEndTimeInput.value=e?Dl(e):"",this.obsEndTimeNativeInput.value=this.pickerValueOf(e),this.obsEndTimeQualifier.value=this.qualifierOf(this.obsEndTimeInput.value),this.obsEndTimeInput.setCustomValidity(""),this.obsEndTimeInput.classList.remove("invalid")}syncUtcOffsetField(){const e=this.ufoElement.sighting.event.utcOffsetHours;this.utcOffsetInput.value=e===void 0?"":String(e),this.updateUtcOffsetValidity()}updateUtcOffsetValidity(){const e=this.ufoElement.sighting.event.utcOffsetHours,t=this.ufoElement.sighting.event.place?.[0]?.lng,n=t===void 0?void 0:Math.round(t/15),i=e!==void 0&&n!==void 0&&Math.abs(e-n)>dA;this.utcOffsetInput.classList.toggle("invalid",i),this.utcOffsetInput.title=i?this.messages.utcOffsetImplausible.replace("{solar}",n>=0?`+${n}`:String(n)):""}scheduleGroundElevation(){const e=this.numberOrUndefined(this.latInput.value),t=this.numberOrUndefined(this.lngInput.value);e===void 0||t===void 0||this.groundElevationFor&&this.isSamePlace(this.groundElevationFor,e,t)||(clearTimeout(this.groundElevationTimer),this.groundElevationTimer=setTimeout(()=>void this.applyGroundElevation(e,t),cA))}isSamePlace(e,t,n){return Math.abs(e.lat-t)<Ca&&Math.abs(e.lng-n)<Ca}async applyGroundElevation(e,t){const n=++this.groundElevationToken,i=Ia(Ch,this.chosenSourceId.get("elevation")),s=await new qu(i.create()).at(e,t);if(n!==this.groundElevationToken||s===void 0)return;this.groundElevationFor={lat:e,lng:t};const r=Math.max(0,(this.numberOrUndefined(this.elevationInput.value)??0)-(this.groundElevationM??0));this.groundElevationM=Math.round(s),this.syncElevationField(r),this.updateObserver()}syncElevationField(e){const t=this.groundElevationM;this.elevationInput.value=String(Math.round((t??0)+e)),this.elevationInput.min=t===void 0?"":String(t),this.elevationInput.title=t===void 0?"":this.messages.altitudeAboveSeaLevel,this.groundElevationOutput.textContent=t===void 0?"":this.messages.groundAt.replace("{m}",String(t))}syncGroundElevationField(){this.groundElevationToken++,clearTimeout(this.groundElevationTimer),this.groundElevationM=void 0,this.groundElevationFor=void 0,this.syncElevationField(at(this.ufoElement.sighting,0)?.elevationM??0),this.scheduleGroundElevation()}syncPlaceNameField(){const e=this.ufoElement.sighting.event.place?.[0],t=e?.name??"";this.placeNameInput.value=t,this.placeNameInput.title=t,this.namedCoordinates=e&&t?{lat:e.lat,lng:e.lng}:void 0,this.placeMatches=[],this.placeMatchRow.hidden=!0,this.placeStatusText.textContent=""}syncWitnessMetadataFields(){const e=this.ufoElement.sighting;this.witnessIdInput.value=e.witness?.id??"",this.witnessDirNameInput.value=e.witness?.dirName??"",this.witnessTitleInput.value=e.witness?.title??"",this.witnessLastNameInput.value=e.witness?.lastName??"",this.witnessFirstNamesInput.value=e.witness?.firstNames?.join(", ")??"",this.caseIdInput.value=e.caseId??"",this.witnessAgeInput.value=e.testimony?.witnessAgeYears?.toString()??"",this.witnessOccupationInput.value=this.said.read(e.testimony?.witnessOccupation)??"",this.testimonySourceSelect.value=e.testimony?.source??"",this.testimonyFollowedUpSelect.value=e.testimony?.followedUp===void 0?"":e.testimony.followedUp?"yes":"no",this.descriptionInput.value=this.said.read(e.event.description)??"",this.showTags(),this.instrumentSelect.value=e.instrument.id}syncWeatherFromTimeline(){if(this.cloudEditor?.sync(),this.ufoElement.playbackState==="playing")return;const e=Ft(this.ufoElement.sighting,this.ufoElement.currentTime),t=this.shadow.activeElement;t!==this.cloudCoverInput&&(this.cloudCoverInput.value=String(e.cloudCover)),t!==this.highCloudCoverInput&&(this.highCloudCoverInput.value=String(e.highCloudCover??0)),t!==this.iceCrystalAlignmentInput&&(this.iceCrystalAlignmentInput.value=String(e.iceCrystalAlignment??.65)),t!==this.cloudDarknessInput&&(this.cloudDarknessInput.value=String(e.cloudDarkness)),t!==this.cloudBaseInput&&(this.cloudBaseInput.value=e.cloudBaseM===void 0?"":String(e.cloudBaseM)),t!==this.precipitationTypeSelect&&(this.precipitationTypeSelect.value=e.precipitationType),t!==this.precipitationIntensityInput&&(this.precipitationIntensityInput.value=String(e.precipitationIntensity)),t!==this.windDirectionInput&&(this.windDirectionInput.value=String(e.windDirectionDeg)),t!==this.windSpeedInput&&(this.windSpeedInput.value=String(e.windSpeed)),t!==this.stormInput&&(this.stormInput.checked=e.storm)}syncObserverFromTimeline(){if(this.ufoElement.playbackState==="playing")return;const e=this.ufoElement.sighting,t=e.witnessTrack.getInterpolatedPoseAt(this.ufoElement.currentTime),n=e.event.place?.[0],i=this.shadow.activeElement;i!==this.latInput&&(this.latInput.value=t?.lat!==void 0?String(t.lat):n?String(n.lat):""),i!==this.lngInput&&(this.lngInput.value=t?.lng!==void 0?String(t.lng):n?String(n.lng):""),i!==this.headingInput&&(this.headingInput.value=t?.headingDeg!==void 0?String(this.rounded(t.headingDeg)):""),i!==this.pitchInput&&(this.pitchInput.value=String(this.rounded(t?.pitchDeg??0)),this.rollInput.value=String(this.rounded(t?.rollDeg??0))),i!==this.elevationInput&&this.syncElevationField(t?.elevationM??0)}get appearance(){return{...this.currentAppearance}}set appearance(e){this.setAppearance(e)}setAppearance(e){const t="presetId"in e;this.currentAppearance={...this.currentAppearance,...e},this.updatePresetButtons(),!(this.isRecording||this.ufoElement.playbackState==="playing")&&this.applyAppearanceAtPlayhead(void 0,t)}applyAppearanceAtPlayhead(e,t=!0){const n=this.ufoElement.sighting.timeline,i=this.ufoElement.currentTime,s=n.getInterpolatedShapeAt(i,this.currentSourceId),r=this.buildAppearanceShape(e??s?.bounds??this.defaultBounds(),s,t);this.commitShapes(i,[{sourceId:this.currentSourceId,shape:r}]),this.ufoElement.refresh()}buildAppearanceShape(e,t,n=!0){if(t&&!n)return{...t,color:this.currentAppearance.color,transparency:this.currentAppearance.transparency,haloScale:this.currentAppearance.haloScale,blur:this.currentAppearance.blur,brightness:this.currentAppearance.brightness};const i=nf(e,this.currentAppearance);return t?{...i,angle:t.angle,title:t.title,selected:t.selected}:i}toggleSkyDetails(){const e=this.skyDetailsButton.getAttribute("aria-expanded")!=="true";this.skyDetailsButton.setAttribute("aria-expanded",String(e)),this.skyDetailsButton.textContent=e?"▴":"▾",this.skyDetailsButton.title=e?this.messages.skyDetailsHide:this.messages.skyDetails,this.skyDetailsButton.setAttribute("aria-label",this.skyDetailsButton.title);for(const t of this.clampedLines)t.classList.toggle("clamped",!e)}isGroupOpen(e){return e.getAttribute("aria-expanded")==="true"}toggleGroup(e,t){this.cloudEditor?.stopManipulation();for(const[n,i]of this.groupTabs.entries()){const s=i===e&&t;i.setAttribute("aria-expanded",String(s)),this.groupPanels[n].hidden=!s}}static SUMMARY_GROUPS=["observation","witness","location","decor","temporal","weather","sound"];static PANEL_ORDER=["observation","witness","location","decor","temporal","weather","sound","shape"];refreshParamSummary(){const t=this.paramSummaryBuilder.entriesFor(this.ufoElement.sighting,this.ufoElement.currentTime,{decorId:this.currentDecorId,decorPicker:!0,groundElevationM:this.groundElevationM??0}).map(i=>({...i,panel:Mt.SUMMARY_GROUPS.indexOf(i.group)})),n=t.map(i=>`${i.field}=${i.label}=${i.value}${i.unit}${i.fromSource?"*":""}`).join("|");n!==this.paramSummarySignature&&(this.paramSummarySignature=n,this.paramChips=t,this.renderParamSummary(),this.runAssessments())}paramChips=[];renderParamSummary(){const e=Mt.NESTED_GROUPS,t=[];let n;for(const i of[...this.paramChips,...this.assessmentChips]){if(n&&n.group!==i.group&&(n=void 0),e.includes(i.group)&&!n){const r=document.createElement("span");r.className="param-nest",r.dataset.group=i.group;const o=document.createElement("span");o.className="param-nest-label",o.textContent=i.group==="assessment"?this.messages.assessmentGroup:Mt.tabLabel(this.groupTabs[Mt.SUMMARY_GROUPS.indexOf(i.group)]),r.append(o),n={group:i.group,element:r},t.push(r)}const s=this.paramChip(i);n?n.element.append(s):t.push(s)}this.paramSummary.replaceChildren(...t)}static NESTED_GROUPS=["witness","decor","assessment"];static QUESTION_FIELDS={when:{panel:"temporal",fields:["obs-time","obs-time-native"]},where:{panel:"location",fields:["lat","lng"]},facing:{panel:"location",fields:["heading"]},"apparent-size":{panel:"shape",fields:[]},"sky-position":{panel:"shape",fields:[]},"how-long":{panel:"temporal",fields:["durationSeconds","obs-end-time","obs-end-time-native"]},appearance:{panel:"shape",fields:["shapeTitle","color"]},movement:{panel:"shape",fields:[]},sound:{panel:"sound",fields:["soundKind"]},conditions:{panel:"weather",fields:["cloudCover"]}};assessmentChips=[];assessmentToken=0;async runAssessments(){const e=++this.assessmentToken,t=await new Zv(this.messages).read(this.ufoElement.sighting);e===this.assessmentToken&&(this.assessmentChips=t.entries.map(n=>({...n,panel:Mt.PANEL_ORDER.indexOf(n.about??"")})),this.markUnansweredQuestions(t.unanswered),this.renderParamSummary())}static tabLabel(e){return(e.querySelector("span:not(.tab-badge)")??e).textContent.trim()}static badgeOn(e){const t=e.querySelector(".tab-badge");if(t)return t;const n=document.createElement("span");return n.className="tab-badge",n.hidden=!0,e.append(n),n}unansweredQuestions=new Set;markUnansweredQuestions(e=this.unansweredQuestions){this.unansweredQuestions=e;const t=new Set;for(const s of e){const r=Mt.QUESTION_FIELDS[s];if(r&&!r.fields.some(o=>this.shadow.getElementById(o)?.classList.contains("missing-required")))for(const o of r.fields){const l=this.shadow.getElementById(o);l&&!l.hidden&&l.value===""&&t.add(o)}}for(const[s,r]of Object.entries(Mt.QUESTION_FIELDS))for(const o of Mt.QUESTION_FIELDS[s].fields){const l=this.shadow.getElementById(o);if(!l)continue;const c=t.has(o)&&!l.classList.contains("missing-required");l.classList.toggle("wanted",c),(c||l.title===this.messages.questionUnanswered)&&(l.title=c?this.messages.questionUnanswered:"")}const n=new Map;let i;for(const[s,r]of Object.entries(Mt.QUESTION_FIELDS))for(const o of r.fields){const l=this.shadow.getElementById(o);if(!l)continue;const c=l.classList.contains("missing-required");!c&&!l.classList.contains("wanted")||(c&&(i=r.panel),n.set(r.panel,(n.get(r.panel)??0)+1))}for(const[s,r]of this.groupTabs.entries()){const o=Mt.PANEL_ORDER[s],l=n.get(o)??0,c=o===i,h=Mt.badgeOn(r);h.hidden=l===0,h.textContent=String(l),h.classList.toggle("optional",!c),r.title=l===0?"":c?this.messages.durationRequired:this.messages.questionsUnanswered.replace("{count}",String(l))}}paramChip(e){const t=document.createElement("button");t.type="button",t.className=e.fromSource?"param-chip from-source":"param-chip",t.dataset.panel=String(e.panel),t.dataset.field=e.field;const n=document.createElement("span");if(n.className="param-chip-label",n.textContent=`${e.label} `,t.append(n),e.color!==void 0){const s=document.createElement("span");s.className="param-chip-swatch",s.style.background=e.color,t.append(s)}const i=document.createElement("span");return i.className="param-chip-value",i.textContent=e.unit===""?e.value:`${e.value} ${e.unit}`,t.append(i),t}onParamSummaryClick(e){const t=e.target.closest(".param-chip");if(t==null)return;const n=Number(t.dataset.panel);if(n<0)return;const i=this.groupPanels[n];this.toggleGroup(this.groupTabs[n],!0);const s=t.dataset.field;if(s.startsWith("decor:")){this.currentDecorId=s.slice(6),this.refreshDecorList(),this.decorSelect.focus();return}const r=this.shadow.getElementById(s);r===null||!i.contains(r)||(r.focus(),r instanceof HTMLInputElement&&r.type!=="checkbox"&&r.type!=="color"&&r.type!=="range"&&r.select(),r.scrollIntoView?.({block:"center"}))}onSelectionOrTimeChanged(){this.syncAppearanceFromTimeline(),this.syncObserverFromTimeline(),this.syncWeatherFromTimeline(),this.syncWeatherSourceState(),this.syncSoundFromTimeline(),this.syncDecorLitFromTimeline(),this.syncDecorPlacementFromTimeline(),this.syncIndoorLookReset(),this.updateAppearanceFieldsDisabledState(),this.updateShapeTitleValidity(),this.refreshRealSize(),this.refreshBlurDistanceBound(),this.refreshSkyCandidates(),this.refreshInstrumentOptions(),this.syncOpticsFromInstrument(),this.ufoElement.selectedSourceIds=this.selectedSourceIds;const e=this.ufoElement.sighting.timeline.sourceIds,t=e.filter(n=>this.selectedSourceIds.has(n)).length;this.deleteShapeButton.disabled=this.isRecording||this.ufoElement.playbackState==="playing"||t===0||e.length-t<1,this.refreshParamSummary()}updateAppearanceFieldsDisabledState(){const e=this.selectedSourceIds.size>1,t=e?this.messages.multipleShapesSelected:"";for(const n of[this.shapeTitleInput,this.colorInput,this.transparencyInput,this.haloScaleInput,this.blurInput,this.brightnessInput,this.apparentWidthInput,this.realWidthInput,this.objectDistanceInput,this.sizeLockSelect,this.clearDistanceHypothesisButton,this.sourceSelect,...Object.values(this.presetButtons)])n.disabled=e,n.title=t}syncAppearanceFromTimeline(){if(this.ufoElement.playbackState==="playing"||this.selectedSourceIds.size>1)return;const e=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,this.currentSourceId);e&&(this.currentAppearance={presetId:gA(e),color:e.color,transparency:e.transparency,haloScale:e.haloScale,blur:e.blur??0,brightness:e.brightness??0},this.updatePresetButtons(),this.colorInput.value=this.currentAppearance.color,this.transparencyInput.value=String(this.currentAppearance.transparency),this.haloScaleInput.value=String(this.currentAppearance.haloScale),this.blurInput.value=String(this.currentAppearance.blur),this.brightnessInput.value=String(this.currentAppearance.brightness),this.shadow.activeElement!==this.shapeTitleInput&&(this.shapeTitleInput.value=this.said.read(e.title)??""),this.refreshApparentSize())}updateShapeTitle(){const e=this.ufoElement.sighting.timeline,t=this.ufoElement.currentTime,n=e.getInterpolatedShapeAt(t,this.currentSourceId);n&&(this.commitShapes(t,[{sourceId:this.currentSourceId,shape:{...n,title:this.said.write(n.title,this.shapeTitleInput.value,this.writingLanguage)}}]),this.ufoElement.refresh(),this.refreshSourceList(),this.updateShapeTitleValidity())}sizeLock="none";onApparentWidthInput(){const e=this.numberOrUndefined(this.apparentWidthInput.value);if(!(e===void 0||e<=0||this.selectedSourceIds.size!==1)){if(this.sizeLock==="real"){const t=this.numberOrUndefined(this.realWidthInput.value);t!==void 0&&t>0&&this.sceneElement.setDistanceHypothesis(this.currentSourceId,et.distanceMAt(t,e))}this.applyApparentWidth(e)}}onRealWidthInput(){const e=this.numberOrUndefined(this.realWidthInput.value);if(e===void 0||e<=0||this.selectedSourceIds.size!==1)return;if(this.sizeLock==="apparent"){const n=this.currentApparentWidthDeg();n!==void 0&&n>0&&(this.sceneElement.setDistanceHypothesis(this.currentSourceId,et.distanceMAt(e,n)),this.refreshDepth());return}const t=this.currentDistanceM();t!==void 0&&t>0&&this.applyApparentWidth(et.angularWidthDeg({sizeM:e,distanceM:t}))}onDistanceInput(){const e=this.numberOrUndefined(this.objectDistanceInput.value);e===void 0||e<=0||this.applyDistance(e)}applyDistance(e){if(this.selectedSourceIds.size===1){if(this.sizeLock!=="apparent"){const t=this.numberOrUndefined(this.realWidthInput.value);t!==void 0&&t>0&&this.applyApparentWidth(et.angularWidthDeg({sizeM:t,distanceM:e}))}this.sceneElement.setDistanceHypothesis(this.currentSourceId,e),this.refreshDepth()}}applySizeLock(){this.sizeLock=this.sizeLockSelect.value,this.apparentWidthInput.readOnly=this.sizeLock==="apparent",this.realWidthInput.readOnly=this.sizeLock==="real",this.objectDistanceInput.readOnly=this.sizeLock==="distance"}currentApparentWidthDeg(){const e=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,this.currentSourceId);if(e)return e.angular?.widthDeg??this.currentProjection().pxToDeg(e.bounds.width)}currentDistanceM(){return this.sceneElement.depthOf(this.currentSourceId)?.distanceM}applyApparentWidth(e){const t=this.ufoElement.sighting.timeline,n=this.ufoElement.currentTime,i=t.getInterpolatedShapeAt(n,this.currentSourceId);if(!i)return;const s=this.currentProjection(),r=s.degToPx(e),o=i.bounds.height*(i.bounds.width===0?1:r/i.bounds.width),l={x:i.bounds.x+(i.bounds.width-r)/2,y:i.bounds.y+(i.bounds.height-o)/2,width:r,height:o},c=s.ofBounds(l),h=i.kind==="oval"?{...i,bounds:l,angular:c}:{...i,bounds:l,angular:c,points:this.scalePoints(i,l)};this.commitShapes(n,[{sourceId:this.currentSourceId,shape:h}]),this.ufoElement.refresh(),this.refreshApparentSize()}scalePoints(e,t){const n=e.bounds.width===0?1:t.width/e.bounds.width,i=e.bounds.height===0?1:t.height/e.bounds.height;return e.points.map(s=>({x:s.x*n,y:s.y*i}))}refreshInstrumentOptions(){const e=this.ufoElement.sighting,t=e.event.time?.year,n=st.availableAt(t),i=e.instrument,s=n.includes(i)?n:[...n,i],r=this.instrumentSelect.value||i.id;this.instrumentSelect.replaceChildren();for(const o of s){const l=document.createElement("option");l.value=o.id;const c=o.name[this.showerLanguage()];l.textContent=n.includes(o)?c:this.messages.instrumentOutOfPeriod.replace("{name}",c),this.instrumentSelect.appendChild(l)}this.instrumentSelect.value=s.some(o=>o.id===r)?r:i.id}static exposureText(e){return e>=1?String(Math.round(e*100)/100):`1/${Math.round(1/e)}`}statedExposureSeconds(e){const t=Mt.exposureSeconds(this.exposureInput.value),n=e.exposureRangeSeconds;if(!n)return e.exposureSeconds??t;if(t!==void 0)return Math.min(n.max,Math.max(n.min,t))}static exposureSeconds(e){const t=e.trim();if(!t)return;const n=/^(\d*\.?\d+)\s*\/\s*(\d*\.?\d+)$/.exec(t);if(n){const s=Number(n[1]),r=Number(n[2]);return r>0?s/r:void 0}const i=Number(t);return Number.isFinite(i)&&i>0?i:void 0}syncOpticsFromInstrument(){const e=this.ufoElement.sighting,t=e.instrument,n=at(e,this.ufoElement.currentTime),i=t.frame,s=n?.fovDeg??st.fieldOfViewDeg(t),r=i?st.focalLengthMmFor(t,s):s;this.focalLengthInput!==this.shadow.activeElement&&(this.focalLengthInput.value=r===void 0?"":String(Math.round(r*10)/10)),this.unitFocalLength.textContent=i?this.messages.unitMillimetres:this.messages.unitDegrees,this.labelFocalLength.textContent=i?this.messages.focalLength:this.messages.fieldOfView,this.focalLengthInput.disabled=i!==void 0&&i.focalRangeMm===void 0,this.focalLengthInput.min=String(i?.focalRangeMm?.minMm??1),this.focalLengthInput.max=String(i?.focalRangeMm?.maxMm??2e3);const o=n?.fNumber??t.fNumber;this.fNumberInput!==this.shadow.activeElement&&(this.fNumberInput.value=o===void 0?"":String(o)),this.setRowVisible(this.fNumberInput,t.fNumber!==void 0),this.fNumberInput.disabled=t.fNumberRange===void 0,this.fNumberInput.min=String(t.fNumberRange?.min??.7),this.fNumberInput.max=String(t.fNumberRange?.max??64);const l=e.exposure;this.exposureInput!==this.shadow.activeElement&&(this.exposureInput.value=l===void 0?"":Mt.exposureText(l)),this.setRowVisible(this.exposureInput,t.exposureSeconds!==void 0),this.exposureInput.disabled=t.exposureRangeSeconds===void 0,this.focusDistanceInput!==this.shadow.activeElement&&(this.focusDistanceInput.value=n?.focusDistanceM===void 0?"":String(n.focusDistanceM)),this.setRowVisible(this.focusDistanceInput,i!==void 0&&t.fNumber!==void 0)}retuneFieldOfView(e){const t=this.ufoElement.sighting,n=st.fieldOfViewDeg(e),i=st.fieldOfViewDeg(t.instrument);for(const s of[...t.witnessTrack.allKeyframes])Math.abs(s.pose.fovDeg-n)>uA||t.witnessTrack.addKeyframe(s.t,{...s.pose,fovDeg:i})}retuneExposure(e){const t=this.ufoElement.sighting,n=t.exposureSeconds,i=t.instrument.exposureRangeSeconds;if(n===void 0||n===e.exposureSeconds||!i){t.exposureSeconds=void 0;return}t.exposureSeconds=Math.min(i.max,Math.max(i.min,n))}currentFovDeg(){const e=this.ufoElement.sighting;return at(e,this.ufoElement.currentTime)?.fovDeg??st.fieldOfViewDeg(e.instrument)}currentProjection(){return ni.of(this.ufoElement.sighting.instrument,this.ufoElement.canvasElement.height,this.currentFovDeg())}refreshApparentSize(){const e=this.selectedSourceIds.size===1?this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,this.currentSourceId):void 0;if(!e){this.apparentSizeOutput.textContent="",this.hasFocus(this.apparentWidthInput)||(this.apparentWidthInput.value=""),this.refreshRealSize();return}const t=e.angular?.widthDeg??this.currentProjection().pxToDeg(e.bounds.width),n=et.inMoons(t);this.hasFocus(this.apparentWidthInput)||(this.apparentWidthInput.value=this.plain(t,t<1?2:1)),this.apparentSizeOutput.textContent=this.messages.apparentSize.replace("{moons}",n.toLocaleString(void 0,{maximumFractionDigits:n<10?1:0})),this.refreshRealSize()}hasFocus(e){return this.typingIn===e}typingIn;typing(e,t){this.typingIn=e;try{t()}finally{this.typingIn=void 0}}plain(e,t){return String(Number(e.toFixed(t)))}refreshBlurDistanceBound(){const e=this.currentAppearance.blur;if(e<=0||this.selectedSourceIds.size!==1){this.blurBoundOutput.textContent="";return}const t=this.ufoElement.sighting.instrument,n=t.frame;if(!n){this.blurBoundOutput.textContent=this.messages.blurBoundNoInstrument;return}const i=at(this.ufoElement.sighting,this.ufoElement.currentTime),s=i?.focusDistanceM;if(s!==void 0){this.blurBoundOutput.textContent=this.messages.blurBoundNotAtInfinity.replace("{focus}",this.meters(s));return}const r=(i?st.focalLengthMmFor(t,i.fovDeg):void 0)??n.focalLengthMm,o=i?.fNumber??t.fNumber;if(o===void 0||r<=0){this.blurBoundOutput.textContent="";return}const l=this.ufoElement.canvasElement.height;if(l<=0)return;const c=2*Nh*e/l*n.heightMm,h=r*r/(o*c)/1e3;this.blurBoundOutput.textContent=this.messages.blurBound.replace("{max}",this.meters(h))}refreshRealSize(){if(this.refreshDepth(),this.selectedSourceIds.size!==1){this.realSizeOutput.textContent="";return}const e=this.currentSourceId;if(this.sceneElement.sizeContradictory(e)){this.realSizeOutput.textContent=this.messages.realSizeContradiction;return}const{minM:t,maxM:n}=this.sceneElement.sizeRangeOf(e);if(t===void 0&&n===void 0){this.realSizeOutput.textContent=this.messages.realSizeUnknown;return}const i=this.numberOrUndefined(this.realWidthInput.value),s=i!==void 0&&(t!==void 0&&i<t||n!==void 0&&i>n)?this.messages.realSizeOutside:"";if(t!==void 0&&n!==void 0){const r=this.sceneElement.distanceRangeAt(e,this.ufoElement.currentTime),o=r.minM===void 0||r.maxM===void 0?"":this.messages.realDistanceHere.replace("{min}",this.meters(r.minM)).replace("{max}",this.meters(r.maxM));this.realSizeOutput.textContent=this.messages.realSizeBetween.replace("{min}",this.meters(t)).replace("{max}",this.meters(n))+o+s;return}this.realSizeOutput.textContent=(t!==void 0?this.messages.realSizeAtLeast.replace("{min}",this.meters(t)):this.messages.realSizeAtMost.replace("{max}",this.meters(n)))+s}decimal(e,t){return e.toLocaleString(void 0,{minimumFractionDigits:t,maximumFractionDigits:t})}clearDistanceHypothesis(){this.selectedSourceIds.size===1&&(this.sceneElement.setDistanceHypothesis(this.currentSourceId,void 0),this.refreshDepth())}refreshDepth(){const e=this.selectedSourceIds.size===1?this.sceneElement.depthOf(this.currentSourceId):void 0;if(!e){this.depthBasisOutput.textContent="",this.hasFocus(this.objectDistanceInput)||(this.objectDistanceInput.value=""),this.hasFocus(this.realWidthInput)||(this.realWidthInput.value="");return}const t=this.meters(e.distanceM);this.hasFocus(this.objectDistanceInput)||(this.objectDistanceInput.value=this.plain(e.distanceM,e.distanceM<10?1:0));const n=this.currentApparentWidthDeg();if(!this.hasFocus(this.realWidthInput)){const s=n===void 0||n<=0?void 0:et.sizeMAt(e.distanceM,n);this.realWidthInput.value=s===void 0?"":this.plain(s,s<1?2:s<10?1:0)}this.clearDistanceHypothesisButton.hidden=e.basis!=="hypothesis";const i={stated:this.messages.depthStated,hypothesis:this.messages.depthHypothesis,derived:this.messages.depthDerived,bounded:this.messages.depthBounded,conventional:this.messages.depthConventional}[e.basis];this.depthBasisOutput.textContent=i.replace("{m}",t)}commitShapes(e,t){const n=this.ufoElement.sighting,i=ni.of(n.instrument,et.CANVAS_HEIGHT_PX,an.fovOf(n,e));n.timeline.addKeyframe(e,t.map(s=>{const r=an.aimOf(n,e,s.shape.bounds),o=i.ofBounds(s.shape.bounds);return{...s,shape:r?{...s.shape,aim:r,angular:o}:{...s.shape,angular:o}}}))}meters(e){const t=e<1?2:e<10?1:0;return e.toLocaleString(void 0,{maximumFractionDigits:t})}updateShapeTitleValidity(){const e=this.selectedSourceIds.size===1&&this.shapeTitleInput.value==="";this.shapeTitleInput.classList.toggle("invalid",e),this.shapeTitleInput.setAttribute("aria-invalid",String(e))}shapeLabel(e){const t=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,e),n=this.said.read(t?.title);if(n)return n;const i=/^ufo-(\d+)$/.exec(e);return i?`${this.messages.shape} ${i[1]}`:e}addShape(){if(this.isRecording)return;const e=this.ufoElement.sighting.timeline,t=new Set([...e.sourceIds,this.currentSourceId]);let n=t.size+1;for(;t.has(`ufo-${n}`);)n++;this.currentSourceId=`ufo-${n}`,this.selectedSourceIds=new Set([this.currentSourceId]),this.applyAppearanceAtPlayhead(this.offsetDefaultBounds(e.sourceIds.length)),this.shapeTitleInput.value=this.shapeLabel(this.currentSourceId),this.updateShapeTitle()}deleteShape(){if(this.isRecording||this.ufoElement.playbackState==="playing")return;const e=this.ufoElement.sighting.timeline,t=e.sourceIds.filter(i=>this.selectedSourceIds.has(i));if(t.length===0||e.sourceIds.length-t.length<1)return;const n=t.length===1?this.messages.confirmDeleteShape.replace("{name}",this.shapeLabel(t[0])):this.messages.confirmDeleteShapes.replace("{count}",String(t.length));this.askConfirm(n,()=>this.removeShapes(t))}removeShapes(e){const t=this.ufoElement.sighting.timeline;for(const n of e)t.removeSource(n);this.currentSourceId=t.sourceIds[0],this.selectedSourceIds=new Set([this.currentSourceId]),this.refreshSourceList(),this.ufoElement.refresh()}askConfirm(e,t){this.answerConfirm(!1),this.confirmMessage.textContent=e,this.confirmOverlay.hidden=!1,this.confirmAcceptButton.focus(),this.confirmAnswer=t}answerConfirm(e){const t=this.confirmAnswer;this.confirmAnswer=void 0,this.confirmOverlay.hidden=!0,e&&t?.()}offsetDefaultBounds(e){const t=this.defaultBounds(),n=24;return{...t,x:t.x+e*n,y:t.y+e*n}}refreshSourceList(){const e=this.ufoElement.sighting.timeline,t=[...new Set([...e.sourceIds,this.currentSourceId])];this.sourceSelect.innerHTML="";for(const n of t){const i=document.createElement("option");i.value=n,i.textContent=this.shapeLabel(n),this.sourceSelect.appendChild(i)}this.sourceSelect.value=this.currentSourceId}decorLabel(e){const t=this.said.read(e.title);if(t)return t;const i=this.ufoElement.sighting.decor.filter(r=>r.kind===e.kind).indexOf(e)+1;return`${this.decorKindSelect.querySelector(`option[value="${e.kind}"]`)?.textContent??e.kind} ${i}`}addDecor(e=this.decorKindSelect.value){const t=this.ufoElement.sighting,i={id:`decor-${t.decor.length+1}`,kind:e,title:this.nextDecorLabel(e),eastM:8*t.decor.length,northM:15,headingDeg:0,lit:!1,...e==="aircraft"?this.defaultAircraft():{},...e==="building"?{floors:Ba}:{},windows:_m(e)};t.decor=[...t.decor,i],this.currentDecorId=i.id,this.refreshDecorList(),this.ufoElement.refresh()}defaultAircraft(){const e=2*Rh,t=Math.round(e/pA*1e3);return{lights:uc.byId("airliner")?.create(),track:[{t:0,eastM:-Rh,northM:1e3,altitudeM:1500,headingDeg:90},{t,eastM:Rh,northM:1e3,altitudeM:1500,headingDeg:90}]}}nextDecorLabel(e){const t=this.ufoElement.sighting.decor.filter(i=>i.kind===e).length;return`${this.decorKindSelect.querySelector(`option[value="${e}"]`)?.textContent??e} ${t+1}`}deleteDecor(){if(this.currentDecorId===void 0)return;const e=this.ufoElement.sighting;e.decor=e.decor.filter(t=>t.id!==this.currentDecorId),this.currentDecorId=e.decor[0]?.id,this.refreshDecorList(),this.ufoElement.refresh()}selectDecor(e){this.currentDecorId=e,this.decorSelect.value=e,this.syncDecorFields()}updateDecor(){if(this.currentDecorId===void 0)return;const e=this.ufoElement.sighting,t=this.wrapDegrees(Number(this.decorHeadingInput.value),this.decorHeadingInput)??0,n=this.decorWitnessSideSelect.value;e.decor=e.decor.map(i=>{if(i.id!==this.currentDecorId)return i;const s=Na(i.kind)&&n!==""?n:void 0,r=Number(this.decorEastInput.value),o=Number(this.decorNorthInput.value),l=Number(this.decorAltitudeInput.value),c=i.track??(l!==0?[]:void 0);if(c){const h=this.ufoElement.currentTime,d={t:h,eastM:r,northM:o,altitudeM:l,headingDeg:t},u=c.filter(f=>f.t!==h);return{...i,title:this.said.write(i.title,this.decorTitleInput.value,this.writingLanguage),color:this.statedDecorColor(i),track:[...u,d].sort((f,p)=>f.t-p.t),sightingUrl:this.stringOrUndefined(this.decorSightingUrlInput.value),witnessSide:s,sizeM:this.statedDecorSize(),model:this.statedDecorModel(),floors:i.kind==="building"?Number(this.decorFloorsInput.value):void 0,occupiedFloor:i.kind==="building"?Number(this.decorOccupiedFloorInput.value):void 0}}return{...i,title:this.said.write(void 0,this.decorTitleInput.value,this.writingLanguage),color:this.statedDecorColor(i),eastM:r,northM:o,headingDeg:t,sightingUrl:this.stringOrUndefined(this.decorSightingUrlInput.value),witnessSide:s,sizeM:this.statedDecorSize(),model:this.statedDecorModel(),floors:i.kind==="building"?Number(this.decorFloorsInput.value):void 0,occupiedFloor:i.kind==="building"?Number(this.decorOccupiedFloorInput.value):void 0}}),this.decorSelect.options[this.decorSelect.selectedIndex].textContent=this.decorLabel(e.decor.find(i=>i.id===this.currentDecorId)),this.syncDecorVisibility(),this.updateDecorTitleValidity(),this.ufoElement.refresh()}syncDecorSizeFields(e){const t=e?tn.naturalSize(e.kind,e.floors):void 0,n=[[this.decorWidthInput,e?.sizeM?.widthM,t?.widthM],[this.decorLengthInput,e?.sizeM?.lengthM,t?.lengthM],[this.decorHeightInput,e?.sizeM?.heightM,t?.heightM]];for(const[i,s,r]of n)i.value=s===void 0?"":String(this.roundedMeters(s)),i.placeholder=r===void 0?"":String(this.roundedMeters(r))}syncDecorModelFields(e){this.refreshDecorModelOptions(e),this.decorModelSelect.value=e?.model?.id??"",this.decorModelUrlInput.value=e?.model?.url??"",this.decorModelTitleInput.value=e?.model?.credit?.title??"",this.decorModelAuthorInput.value=e?.model?.credit?.author??"",this.decorModelLicenseInput.value=e?.model?.credit?.license??"",this.decorModelSourceInput.value=e?.model?.credit?.sourceUrl??"",this.decorModelAdvanced.open=e?.model?.url!==void 0}async refreshDecorModelOptions(e){const t=e??this.ufoElement.sighting.decor.find(r=>r.id===this.currentDecorId),n=t?await this.decorModelProvider.entries(t.kind).catch(()=>[]):[],i=t?.model?.id??"",s=document.createElement("option");s.value="",s.textContent=this.messages.decorModelNone,this.decorModelSelect.replaceChildren(s,...n.map(r=>{const o=document.createElement("option");return o.value=r.id,o.textContent=r.name,o.title=`${r.credit.title}${r.credit.author?` — ${r.credit.author}`:""} (${r.credit.license})`,o})),this.decorModelSelect.value=i}updateDecorModelChoice(){const e=this.decorModelSelect.value;(async()=>{const t=e?await this.decorModelProvider.entry(e).catch(()=>{}):void 0,n=this.ufoElement.sighting.decor.find(i=>i.id===this.currentDecorId);if(t?.sizeM&&n&&!n.sizeM){const i=[[this.decorWidthInput,t.sizeM.widthM],[this.decorLengthInput,t.sizeM.lengthM],[this.decorHeightInput,t.sizeM.heightM]];for(const[s,r]of i)r!==void 0&&(s.value=String(this.roundedMeters(r)))}this.updateDecor()})()}roundedMeters(e){return Math.round(e*100)/100}positiveMeters(e){const t=Number(e);return e.trim()===""||!Number.isFinite(t)||t<=0?void 0:t}statedDecorColor(e){const t=this.decorColorInput.value;return t==="#808080"&&e.color===void 0?void 0:t}statedDecorSize(){const e=this.positiveMeters(this.decorWidthInput.value),t=this.positiveMeters(this.decorLengthInput.value),n=this.positiveMeters(this.decorHeightInput.value);return e===void 0&&t===void 0&&n===void 0?void 0:{widthM:e,lengthM:t,heightM:n}}statedDecorModel(){const e=this.stringOrUndefined(this.decorModelUrlInput.value);if(e){const n=this.stringOrUndefined(this.decorModelTitleInput.value),i=this.stringOrUndefined(this.decorModelLicenseInput.value);return{url:e,credit:n!==void 0&&i!==void 0?{title:n,license:i,author:this.stringOrUndefined(this.decorModelAuthorInput.value),sourceUrl:this.stringOrUndefined(this.decorModelSourceInput.value)}:void 0}}const t=this.stringOrUndefined(this.decorModelSelect.value);return t===void 0?void 0:{id:t}}addMilestone(){const e=Math.round(this.ufoElement.currentTime),t=this.ufoElement.sighting;t.milestones.find(i=>i.t===e)||(t.milestones=er([...t.milestones,{t:e,label:this.nextMilestoneLabel()}])),this.currentMilestoneT=e,this.refreshMilestoneList(),this.ufoElement.refresh()}nextMilestoneLabel(){const e=new Set(this.ufoElement.sighting.milestones.map(t=>t.label));for(let t=0;t<26;t++){const n=String.fromCharCode(65+t);if(!e.has(n))return n}return String(this.ufoElement.sighting.milestones.length+1)}deleteMilestone(){const e=this.currentMilestoneT;if(e===void 0)return;const t=this.ufoElement.sighting,n=t.milestones.find(i=>i.t===e);n&&this.askConfirm(this.messages.confirmDeleteMilestone.replace("{name}",this.said.read(n.label)??""),()=>{t.milestones=t.milestones.filter(i=>i.t!==e),this.currentMilestoneT=t.milestones[0]?.t,this.refreshMilestoneList(),this.ufoElement.refresh()})}selectMilestone(e){this.currentMilestoneT=e,this.syncMilestoneFields(),this.ufoElement.currentTime=e}updateMilestone(){const e=this.currentMilestoneT;if(e===void 0)return;const t=this.ufoElement.sighting;t.milestones=t.milestones.map(n=>n.t===e?{...n,label:this.said.write(n.label,this.milestoneLabelInput.value,this.writingLanguage)??"",note:this.said.write(n.note,this.milestoneNoteInput.value,this.writingLanguage)}:n),this.refreshMilestoneList(),this.ufoElement.refresh()}refreshMilestoneList(){const e=er(this.ufoElement.sighting.milestones);e.some(t=>t.t===this.currentMilestoneT)||(this.currentMilestoneT=e[0]?.t),this.milestoneSelect.replaceChildren(...e.map(t=>{const n=document.createElement("option");return n.value=String(t.t),n.textContent=`${this.said.read(t.label)??""} — ${this.formatSeconds(t.t)}`,n.title=this.said.read(t.note)??"",n})),this.currentMilestoneT!==void 0&&(this.milestoneSelect.value=String(this.currentMilestoneT)),this.syncMilestoneFields()}formatSeconds(e){return`${(e/1e3).toFixed(1)} s`}syncMilestoneFields(){const e=this.ufoElement.sighting.milestones.find(n=>n.t===this.currentMilestoneT),t=e!==void 0;for(const n of[this.milestoneSelect,this.milestoneLabelInput,this.milestoneNoteInput,this.deleteMilestoneButton])n.disabled=!t,this.setRowVisible(n,t);this.milestoneLabelInput.value=this.said.read(e?.label)??"",this.milestoneNoteInput.value=this.said.read(e?.note)??""}updateDecorTitleValidity(){const e=this.currentDecorId!==void 0&&this.decorTitleInput.value==="";this.decorTitleInput.classList.toggle("invalid",e),this.decorTitleInput.setAttribute("aria-invalid",String(e))}updateDecorWindows(){if(this.currentDecorId===void 0)return;const e=this.ufoElement.sighting;e.decor=e.decor.map(t=>{if(t.id!==this.currentDecorId)return t;const n={};for(const i of ia){const s=this.decorWindowInputs[i];if(s.value==="")continue;const r=Fh(t.kind,i)?0:kh,o=Math.max(r,Math.min(100,Number(s.value)));n[i]=o,String(o)!==s.value&&(s.value=String(o))}return{...t,windows:n}}),this.ufoElement.refresh()}updateDecorLit(){if(this.currentDecorId===void 0||this.ufoElement.playbackState==="playing")return;const e=this.ufoElement.sighting,t=this.ufoElement.currentTime,n=this.decorLitInput.checked;e.decor=e.decor.map(i=>{if(i.id!==this.currentDecorId)return i;const s=[...(i.litKeyframes??[]).filter(r=>r.t!==t),{t,lit:n}].sort((r,o)=>r.t-o.t);return{...i,litKeyframes:s}}),this.ufoElement.refresh()}refreshDecorList(){const e=this.ufoElement.sighting.decor;this.decorSelect.innerHTML="";for(const t of e){const n=document.createElement("option");n.value=t.id,n.textContent=this.decorLabel(t),this.decorSelect.appendChild(n)}this.currentDecorId!==void 0&&(this.decorSelect.value=this.currentDecorId),this.syncDecorFields()}syncDecorFields(){const e=this.ufoElement.sighting.decor.find(n=>n.id===this.currentDecorId),t=e!==void 0;this.deleteDecorButton.disabled=!t;for(const n of[this.decorSelect,this.decorTitleInput,this.decorEastInput,this.decorNorthInput,this.decorHeadingInput,this.decorLitInput,this.decorSightingUrlInput,this.decorWidthInput,this.decorLengthInput,this.decorHeightInput,this.decorModelSelect,this.decorModelUrlInput,this.decorModelTitleInput,this.decorModelAuthorInput,this.decorModelLicenseInput,this.decorModelSourceInput,this.decorFloorsInput,this.decorOccupiedFloorInput,this.decorWitnessSideSelect,this.decorLightRigSelect,this.decorAltitudeInput,this.lookAtDecorButton])n.disabled=!t;this.decorTitleInput.value=this.said.read(e?.title)??"",this.decorColorInput.value=e?.color??"#808080",this.showDecorPlacement(e),this.decorLitInput.checked=e?Rl(e,this.ufoElement.currentTime):!1,this.refreshDecorLightRigOptions(e),this.decorSightingUrlInput.value=e?.sightingUrl??"",this.syncDecorSizeFields(e),this.syncDecorModelFields(e),this.decorFloorsInput.value=String(e?.floors??Ba),this.decorOccupiedFloorInput.value=String(e?.occupiedFloor??0),this.decorWitnessSideSelect.value=e?.witnessSide??"";for(const n of ia){const i=e?.windows?.[n];this.decorWindowInputs[n].value=i===void 0?"":String(i)}this.syncDecorVisibility(),this.updateDecorTitleValidity()}setRowVisible(e,t){const n=e.closest("label")??e;n.hidden=!t}syncDecorVisibility(){const e=this.ufoElement.sighting.decor.find(c=>c.id===this.currentDecorId),t=e!==void 0,n=e?.kind;this.setRowVisible(this.decorSelect,t),this.setRowVisible(this.deleteDecorButton,t),this.setRowVisible(this.decorTitleInput,t),this.setRowVisible(this.decorEastInput,t),this.setRowVisible(this.decorNorthInput,t),this.setRowVisible(this.decorAltitudeInput,t),this.setRowVisible(this.decorHeadingInput,t),this.setRowVisible(this.decorWidthInput,t),this.setRowVisible(this.decorLengthInput,t),this.setRowVisible(this.decorHeightInput,t),this.setRowVisible(this.decorModelSelect,t),this.decorModelAdvanced.hidden=!t,this.setRowVisible(this.decorLitInput,t&&e?.kind!=="aircraft");const i=t&&n!==void 0&&mu(n);this.setRowVisible(this.labelDecorWindows,i);const s=n!==void 0?pu(n):[];for(const c of ia)this.decorWindowInputs[c].disabled=!t,this.decorWindowInputs[c].min=String(n!==void 0&&Fh(n,c)?0:kh),this.setRowVisible(this.decorWindowInputs[c],i&&s.includes(c));const r=t&&n!==void 0&&Na(n);this.setRowVisible(this.decorWitnessSideSelect,r);const o=n!==void 0?Jv(n):[];for(const c of ia)this.optionWitnessSide[c].hidden=!o.includes(c);const l=t&&n==="building";this.setRowVisible(this.decorFloorsInput,l),this.setRowVisible(this.decorOccupiedFloorInput,l),this.decorOccupiedFloorInput.max=String(e?.floors??Ba)}showDecorPlacement(e){const t=e?Qa(e,this.ufoElement.currentTime):void 0,n=[[this.decorEastInput,t?.eastM??0],[this.decorNorthInput,t?.northM??0],[this.decorAltitudeInput,t?.altitudeM??0],[this.decorHeadingInput,t?.headingDeg??0]];for(const[i,s]of n)this.shadow.activeElement!==i&&(i.value=String(this.rounded(s)))}syncDecorPlacementFromTimeline(){this.ufoElement.playbackState!=="playing"&&this.showDecorPlacement(this.ufoElement.sighting.decor.find(e=>e.id===this.currentDecorId))}showNextMeteor(){const e=this.sceneElement.meteorByRank(this.meteorRank++);e&&(this.ufoElement.playbackState==="playing"&&this.ufoElement.togglePlayPause(),this.ufoElement.currentTime=e.t,this.headingInput.value=String(Math.round(e.azimuthDeg*10)/10),this.pitchInput.value=String(Math.round(e.altitudeDeg*10)/10),this.updateObserver())}resetMeteorRankIfSkyChanged(){const e=this.sceneElement.meteorByRank(0),t=e?`${e.t}`:"";t!==this.meteorRankFor&&(this.meteorRankFor=t,this.meteorRank=0)}meteorRankFor;skyCandidatesKey;meteorRank=0;showerLanguage(){return za(vs.preferencesFor(this),["en","fr"])}get said(){return this.saidTexts??=new Gi(vs.preferencesFor(this))}saidTexts;tagNames=new Bh({});get writingLanguage(){return this.showerLanguage()}refreshSkyCandidates(){this.resetMeteorRankIfSkyChanged();const e=this.ufoElement.sighting,t=e.event.place?.[0],n=e.event.time,i=t&&t.lat!==void 0&&t.lng!==void 0&&n?.year!==void 0?Ka(n,t.lng,e.event.utcOffsetHours):void 0,s=JSON.stringify([i?.getTime(),t?.lat,t?.lng,this.groundElevationM,e.instrumentId,e.exposureSeconds,Ft(e,0),this.messages.skyLine,this.meteorRankFor]);if(s===this.skyCandidatesKey)return;if(this.skyCandidatesKey=s,!i||!t||t.lat===void 0||t.lng===void 0){this.showMeteorButton.hidden=!0,this.showCometButton.hidden=!0,this.skyCandidatesOutput.textContent=this.messages.skyLine.replace("{parts}",this.messages.skyUnknown);return}const r={lat:t.lat,lng:t.lng,elevationM:this.groundElevationM??0},o=[this.starsClause(i,r),this.showerClause(i,r),this.cometClause(i,r),this.satelliteClause(i,r),this.opticsClause(i,r),this.rainbowClause(i,r),this.glowClause(i,r)].filter(l=>l!==void 0);this.skyCandidatesOutput.textContent=this.messages.skyLine.replace("{parts}",o.join(" · "))}instrumentGain(){const e=this.ufoElement.sighting;return hn.gainFor(e.instrument,{fNumber:at(e,0)?.fNumber,fieldOfViewDeg:an.fovOf(e,0),exposureSeconds:e.exposure})}starsClause(e,t){const n=Un("Sun",e,t).altitudeDeg,i=this.instrumentGain(),s=Hr(n,i),r=c=>c.toLocaleString(void 0,{maximumFractionDigits:1});if(s<hA)return this.messages.skyStarsNone;const o=this.ufoElement.sighting.instrument,l=Math.abs(i)<.1?this.messages.skyStarsEye.replace("{limit}",r(s)):(i>0?this.messages.skyStarsDeeper:this.messages.skyStarsShallower).replace("{limit}",r(s)).replace("{device}",o.name[this.showerLanguage()]).replace("{gain}",r(Math.abs(i))).replace("{eye}",r(Hr(n)));return s<=Xr?l:l+this.messages.skyStarsCatalogue.replace("{catalogue}",r(Xr))}showerClause(e,t){const n=Et.observedRatePerHour(Et.apexPosition(e,t).altitudeDeg).toLocaleString(void 0,{maximumFractionDigits:1}),i=Za.activeAt(e);if(i.length===0)return this.showMeteorButton.hidden=!this.sceneElement.meteorByRank(0),this.messages.skyNothingActive.replace("{sporadic}",n);const s=i.map(r=>{const o=Za.radiantPosition(r.shower,e,t);return{entry:r,position:o,rate:Za.observedRatePerHour(r.zhr,o.altitudeDeg,r.shower.populationIndex)}}).sort((r,o)=>o.rate-r.rate)[0];return s.rate<=0?(this.showMeteorButton.hidden=!this.sceneElement.meteorByRank(0),this.messages.skyShowerBelowHorizon.replace("{name}",s.entry.shower.name[this.showerLanguage()])):(this.showMeteorButton.hidden=!this.sceneElement.meteorByRank(0),this.messages.skyShowerActive.replace("{name}",s.entry.shower.name[this.showerLanguage()]).replace("{altitude}",String(Math.round(s.position.altitudeDeg))).replace("{bearing}",qs.towards(s.position.azimuthDeg,this.showerLanguage())).replace("{rate}",s.rate.toLocaleString(void 0,{maximumFractionDigits:s.rate<10?1:0})).replace("{sporadic}",n))}cometClause(e,t){const n=Tl.brightestAt(e,t);if(!n||n.magnitude>io){this.showCometButton.hidden=!0;return}return this.showCometButton.hidden=n.position.altitudeDeg<=0,this.cometText(n)}satelliteClause(e,t){const n=vi.visibilityAt(e,t);if(!n.anythingInOrbit)return n.sunAltitudeDeg<0?this.messages.skySatellitesNotYet:void 0;const i=Hr(n.sunAltitudeDeg,this.instrumentGain()),s=n.classes.filter(h=>h.peakMagnitude<=i),r=this.listed(s.map(h=>h.name[this.showerLanguage()]));if(n.sunAltitudeDeg>=0)return s.length===0?void 0:(s.length===1?this.messages.skySatellitesDaylightOne:this.messages.skySatellitesDaylight).replace("{eras}",r);const o=Math.round(n.shadowHeightKm).toLocaleString(),l=(n.trackedObjects??0).toLocaleString(),c=h=>h.replace("{height}",o).replace("{count}",l);return n.lowOrbitLit?s.length===0?c(this.messages.skySatellitesLit):c(this.messages.skySatellitesLitWith).replace("{eras}",r):c(this.messages.skySatellitesShadowed)}opticsClause(e,t){const n=Ft(this.ufoElement.sighting,0),i=Un("Sun",e,t),s=Un("Moon",e,t),r=je.deckLitUntilDeg(je.DECK_HEIGHT_M),o=i.altitudeDeg>-r,l=o?i:s;if(l.altitudeDeg<=-r)return;const c=n.highCloudCover;if(c===void 0||c<=0)return this.messages.skyOpticsNoIce;if(je.strength(c,n.lowerCloudCover??n.cloudCover,l.altitudeDeg,r)<=0)return this.messages.skyOpticsHidden;const h=o?this.messages.skyOpticsSun:this.messages.skyOpticsMoon,d=this.listed(je.formsAt(l.altitudeDeg,r).map(f=>this.opticsFormName(f))),u=n.iceCrystalAlignment??.65;return this.messages.skyOpticsPossible.replace("{forms}",d).replace("{source}",h)+this.messages.skyOpticsAlignment.replace("{alignment}",String(Math.round(u*100)))}rainbowClause(e,t){const n=Ft(this.ufoElement.sighting,0);if(n.precipitationType!=="rain"||n.precipitationIntensity<=0)return;const i=Un("Sun",e,t),s=Un("Moon",e,t),r=i.altitudeDeg>0,o=r?i:s;if(o.altitudeDeg<=0)return this.messages.skyBowNoSource;const l=n.lowerCloudCover??n.cloudCover;if(sn.strength(n.precipitationIntensity,l,o.altitudeDeg)<=0)return this.messages.skyBowHidden;const c=sn.formsAt(o.altitudeDeg);if(c.length===0)return this.messages.skyBowSourceTooHigh.replace("{altitude}",String(Math.round(o.altitudeDeg))).replace("{radius}",String(Math.round(sn.primary().radiusDeg)));const h=this.listed(c.map(u=>this.bowFormName(u)));if(r)return this.messages.skyBowPossible.replace("{forms}",h);const d=Math.round(Kl(e).illuminatedFraction*100);return this.messages.skyBowMoon.replace("{forms}",h).replace("{lit}",String(d))}glowClause(e,t){if(Un("Sun",e,t).altitudeDeg>vA)return;const i=this.glows.assess(e,t),s=this.showerLanguage(),r=[];if(i.milkyWay&&r.push(this.messages.skyGlowBand.replace("{contrast}",this.decimal(i.milkyWay.contrast,1)).replace("{altitude}",String(Math.round(i.milkyWay.altitudeDeg))).replace("{bearing}",qs.towards(i.milkyWay.azimuthDeg,s))),i.zodiacal){const h=i.zodiacal.sunSeparationDeg<=nt.CONE_SEPARATION_DEG;r.push((h?this.messages.skyGlowCone:this.messages.skyGlowZodiacalBand).replace("{contrast}",this.decimal(i.zodiacal.contrast,1)).replace("{altitude}",String(Math.round(i.zodiacal.altitudeDeg))).replace("{bearing}",qs.towards(i.zodiacal.azimuthDeg,s)).replace("{elongation}",String(Math.round(i.zodiacal.sunSeparationDeg))))}if(r.length>0)return this.listed(r);const o=this.decimal(i.darkestSkyMagPerArcsec2,1),l=Un("Moon",e,t),c=i.darkestSkyMagPerArcsec2<yA;if(c&&l.altitudeDeg>0){const h=Math.round(Kl(e).illuminatedFraction*100);return this.messages.skyGlowMoon.replace("{lit}",String(h)).replace("{sky}",o)}return c?this.messages.skyGlowTwilight.replace("{sky}",o):this.messages.skyGlowNothingUp.replace("{sky}",o)}glows=new nt;bowFormName(e){return(e.id==="primary"?this.messages.skyBowPrimary:this.messages.skyBowSecondary).replace("{radius}",String(Math.round(e.radiusDeg))).replace("{top}",String(Math.round(e.topAltitudeDeg)))}opticsFormName(e){const t=n=>String(Math.round(n??0));switch(e.id){case"halo22":return this.messages.skyOpticsHalo22.replace("{angle}",t(e.angleDeg));case"halo46":return this.messages.skyOpticsHalo46.replace("{angle}",t(e.angleDeg));case"parhelia":return this.messages.skyOpticsParhelia.replace("{angle}",t(e.angleDeg));case"tangentArc":return this.messages.skyOpticsTangentArc;case"parhelicCircle":return this.messages.skyOpticsParhelicCircle;case"circumzenithal":return this.messages.skyOpticsCircumzenithal.replace("{angle}",t(e.angleDeg));case"circumhorizontal":return this.messages.skyOpticsCircumhorizontal;case"pillar":return this.messages.skyOpticsPillar}}listed(e){return new Intl.ListFormat(this.showerLanguage(),{style:"long",type:"conjunction"}).format(e)}cometText(e){const t=e.apparition.name[this.showerLanguage()],n=e.magnitude.toLocaleString(void 0,{maximumFractionDigits:1});return e.position.altitudeDeg<=0?this.messages.skyCometBelowHorizon.replace("{name}",t).replace("{magnitude}",n):(e.elongationDeg<Tl.TWILIGHT_ELONGATION_DEG?this.messages.skyCometInDaylight:e.tailLengthDeg===void 0?this.messages.skyCometNoTail:this.messages.skyComet).replace("{name}",t).replace("{magnitude}",n).replace("{altitude}",String(Math.round(e.position.altitudeDeg))).replace("{bearing}",qs.towards(e.position.azimuthDeg,this.showerLanguage())).replace("{tail}",String(Math.round(e.tailLengthDeg??0))).replace("{elongation}",String(Math.round(e.elongationDeg)))}lookAtComet(){const e=this.ufoElement.sighting,t=e.event.place?.[0],n=e.event.time;if(!t||t.lat===void 0||t.lng===void 0||n?.year===void 0)return;const i=Ka(n,t.lng,e.event.utcOffsetHours);if(!i)return;const s=Tl.brightestAt(i,{lat:t.lat,lng:t.lng,elevationM:this.groundElevationM??0});s&&(this.headingInput.value=String(this.rounded(s.position.azimuthDeg)),this.pitchInput.value=String(this.rounded(s.position.altitudeDeg)),this.updateObserver())}rounded(e){return Math.round(e*10)/10}lookAtDecor(){const e=this.ufoElement.sighting.decor.find(l=>l.id===this.currentDecorId);if(!e)return;const{eastM:t,northM:n,altitudeM:i}=Qa(e,this.ufoElement.currentTime),s=Math.hypot(t,n);if(s===0&&i===0)return;const r=Math.atan2(t,n)*180/Math.PI,o=Math.atan2(i-fA,s)*180/Math.PI;this.headingInput.value=String(Math.round(r*10)/10),this.pitchInput.value=String(Math.round(o*10)/10),this.updateObserver()}refreshDecorLightRigOptions(e){const t=e?uc.forKind(e.kind):[],n=document.createElement("option");n.value="",n.textContent=this.messages.decorLightsNone,this.decorLightRigSelect.replaceChildren(n,...t.map(s=>{const r=document.createElement("option");return r.value=s.id,r.textContent=s.name,r}));const i=e?.lights?.map(s=>s.id).join()??"";this.decorLightRigSelect.value=t.find(s=>s.create().map(r=>r.id).join()===i)?.id??""}updateDecorLightRig(){const e=this.ufoElement.sighting,t=e.decor.find(i=>i.id===this.currentDecorId);if(!t)return;const n=uc.byId(this.decorLightRigSelect.value);e.decor=e.decor.map(i=>i.id===t.id?{...i,lights:n?n.create():void 0}:i),this.ufoElement.refresh(),this.dispatchEvent(new CustomEvent("sightingchange"))}syncDecorLitFromTimeline(){if(this.ufoElement.playbackState==="playing"||this.shadow.activeElement===this.decorLitInput)return;const e=this.ufoElement.sighting.decor.find(t=>t.id===this.currentDecorId);e&&(this.decorLitInput.checked=Rl(e,this.ufoElement.currentTime))}updatePresetButtons(){for(const e of mm)this.presetButtons[e]?.setAttribute("aria-pressed",String(e===this.currentAppearance.presetId))}get samplingRate(){return Number(this.samplingRateInput.value)}buildPrototype(e=this.defaultBounds()){return nf(e,this.currentAppearance)}defaultBounds(){const e=this.ufoElement.canvasElement;return{x:e.width/2-Da.width/2,y:e.height/2-Da.height/2,width:Da.width,height:Da.height}}toggleRecording(){this.endDrag();const e=this.ufoElement.canvasElement;this.isRecording?(this.recorder?.stop(),this.isRecording=!1,this.setRecordButtonLabel(!1),this.setCanvasCursor(void 0),e.style.touchAction="",this.sourceSelect.disabled=!1,this.addShapeButton.disabled=!1,this.ufoElement.refresh(),this.refreshSourceList()):(this.recorder=new RT(this.ufoElement.sighting.timeline,new PT(this.samplingRate)),this.recorder.start(this.currentSourceId,this.buildPrototype()),this.isRecording=!0,this.setRecordButtonLabel(!0),this.setCanvasCursor("record"),e.style.touchAction="none",this.sourceSelect.disabled=!0,this.addShapeButton.disabled=!0,this.deleteShapeButton.disabled=!0)}setRecordButtonLabel(e){this.recordButton.textContent=e?"⏹":"⏺";const t=e?this.messages.stop:this.messages.record;this.recordButton.title=t,this.recordButton.setAttribute("aria-label",t)}async loadLocaleMessages(){const e=za(vs.preferencesFor(this),Hh);e!=="en"&&(this.tagNames=new Bh(await v1(e)),this.showTags(),this.applyMessages(await g1(e)))}showTags(){this.tagsInput.value=this.ufoElement.sighting.event.tags?.map(e=>this.tagNames.name(e)).join(", ")??""}applyMessages(e){this.currentSourceId===ml&&this.shapeTitleInput.value===`${this.messages.shape} 1`?(this.messages=e,this.shapeTitleInput.value=`${this.messages.shape} 1`,this.updateShapeTitle()):this.messages=e,this.presetButtons.oval.textContent=e.oval,this.presetButtons.polygon.textContent=e.polygon,this.contextAddVertexButton.textContent=e.addVertex,this.contextDeleteVertexButton.textContent=e.deleteVertex,this.labelColor.textContent=e.color,this.labelTransparency.textContent=e.transparency,this.labelHalo.textContent=e.halo,this.labelBlur.textContent=e.blur,this.labelBrightness.textContent=e.brightness,this.labelShape.textContent=e.shape,this.labelShapeTitle.textContent=e.shapeTitle,this.labelUtcOffset.textContent=e.utcOffset,this.utcOffsetInput.placeholder=e.utcOffsetPlaceholder,this.labelApparentWidth.textContent=e.apparentWidth,this.labelRealWidth.textContent=e.realWidth,this.labelObjectDistance.textContent=e.distance,this.labelSizeLock.textContent=e.sizeLock;for(const[i,s]of[["option-lock-none",e.lockNone],["option-lock-apparent",e.lockApparent],["option-lock-real",e.lockReal],["option-lock-distance",e.lockDistance]])this.shadow.getElementById(i).textContent=s;this.clearDistanceHypothesisButton.textContent=e.clearDistanceHypothesis,this.clearDistanceHypothesisButton.title=e.clearDistanceHypothesisTitle,this.refreshApparentSize(),this.labelSamplingRate.textContent=e.samplingRate,this.labelDuration.textContent=e.duration,this.durationInput.placeholder=e.durationPlaceholder,this.addShapeButton.title=e.addShape,this.addShapeButton.setAttribute("aria-label",e.addShape),this.deleteShapeButton.title=e.deleteShape,this.deleteShapeButton.setAttribute("aria-label",e.deleteShape),this.contextGroupButton.textContent=e.group,this.contextUngroupButton.textContent=e.ungroup,this.contextBringToFrontButton.textContent=e.bringToFront,this.contextSendToBackButton.textContent=e.sendToBack,this.contextDeleteButton.textContent=e.contextMenuDelete,this.exportButton.textContent=e.export,this.labelImportFile.textContent=e.importFile,this.labelImportUrl.textContent=e.importUrl,this.importUrlInput.placeholder=e.importUrlPlaceholder,this.importUrlButton.textContent=e.importButton,this.labelWitnessAge.textContent=e.witnessAge,this.labelWitnessOccupation.textContent=e.witnessOccupation,this.labelTestimonySource.textContent=e.testimonySource,this.labelTestimonyFollowedUp.textContent=e.testimonyFollowedUp;for(const[i,s]of[["option-source-unknown",e.testimonySourceUnknown],["option-source-on-site",e.testimonySourceOnSite],["option-source-interview",e.testimonySourceInterview],["option-source-telephone",e.testimonySourceTelephone],["option-source-questionnaire",e.testimonySourceQuestionnaire],["option-source-letter",e.testimonySourceLetter],["option-source-press",e.testimonySourcePress],["option-followed-unknown",e.testimonyUnknown],["option-followed-yes",e.testimonyYes],["option-followed-no",e.testimonyNo]]){const r=this.shadow.getElementById(i);r&&(r.textContent=s)}this.labelNarrativeKey.textContent=e.narrativeKey.replace("{source}",Ts[0].name),this.labelNarrativeWorkspace.textContent=e.narrativeWorkspace,this.narrativeWorkspaceInput.placeholder=e.narrativeWorkspacePlaceholder,this.narrativeWorkspaceInput.title=e.narrativeWorkspaceHint,this.labelNarrativeRemember.textContent=e.narrativeRemember,this.narrativeStopButton.textContent=e.narrativeStop,this.narrativeDraftButton.textContent=e.narrativeDraft,this.descriptionInput.placeholder=e.narrativePlaceholder,this.syncNarrativeEnabled(),this.refreshSourceRows(),this.refreshTimeZoneOptions(),this.labelPlaceName.textContent=e.placeName,this.placeNameInput.placeholder=e.placeNamePlaceholder,this.searchPlaceButton.textContent=e.searchPlace,this.labelPlaceMatch.textContent=e.placeMatch,this.labelLatitude.textContent=e.latitude,this.labelLongitude.textContent=e.longitude,this.labelHeading.textContent=e.heading,this.headingInput.placeholder=e.headingPlaceholder,this.labelPitch.textContent=e.pitch,this.labelRoll.textContent=e.roll,this.labelElevation.textContent=e.elevation,this.labelObservationTime.textContent=e.observationTime,this.labelObservationEndTime.textContent=e.observationEndTime,this.obsTimeInput.placeholder=e.edtfPlaceholder,this.obsTimeInput.title=e.observationTimeHint,this.obsEndTimeInput.placeholder=e.edtfPlaceholder,this.obsEndTimeInput.title=e.observationEndTimeHint,this.presetsGroup.setAttribute("aria-label",e.presetsGroupLabel),this.labelDecor.textContent=e.decor,this.labelDecorGroup.textContent=e.decor,this.optionDecorBuilding.textContent=e.decorBuilding,this.optionDecorTree.textContent=e.decorTree,this.optionDecorCrop.textContent=e.decorCrop,this.optionDecorMound.textContent=e.decorMound,this.optionDecorStreetlight.textContent=e.decorStreetlight,this.optionDecorVehicle.textContent=e.decorVehicle,this.optionDecorAircraft.textContent=e.decorAircraft,this.optionDecorEntity.textContent=e.decorEntity,this.labelDecorLights.textContent=e.decorLights,this.labelDecorAltitude.textContent=e.decorAltitude,this.showMeteorButton.title=e.showMeteor,this.showMeteorButton.setAttribute("aria-label",e.showMeteor),this.showCometButton.title=e.showComet,this.showCometButton.setAttribute("aria-label",e.showComet),this.lookAtDecorButton.title=e.lookAtDecor,this.lookAtDecorButton.setAttribute("aria-label",e.lookAtDecor),this.optionDecorWitness.textContent=e.decorWitness,this.deleteDecorButton.title=e.deleteDecor,this.deleteDecorButton.setAttribute("aria-label",e.deleteDecor),this.labelDecorTitle.textContent=e.decorTitle,this.labelDecorEast.textContent=e.decorEast,this.labelDecorNorth.textContent=e.decorNorth,this.labelDecorHeading.textContent=e.decorHeading,this.labelDecorColor.textContent=e.decorColor,this.labelDecorLit.textContent=e.decorLit,this.labelDecorSightingUrl.textContent=e.decorSightingUrl,this.contextViewTestimonyButton.textContent=e.viewTestimony,this.labelContextMasks.textContent=`${e.masks} ▸`,this.addDecorWitnessButton.textContent=e.addWitness,this.addDecorBuildingButton.title=e.addDecor,this.addDecorBuildingButton.setAttribute("aria-label",e.addDecor),this.confirmAcceptButton.textContent=e.confirmAccept,this.confirmDeclineButton.textContent=e.confirmDecline,this.labelMilestones.textContent=e.milestones,this.labelMilestoneLabel.textContent=e.milestoneLabel,this.labelMilestoneNote.textContent=e.milestoneNote;for(const[i,s]of[[this.addMilestoneButton,e.addMilestone],[this.deleteMilestoneButton,e.deleteMilestone]])i.title=s,i.setAttribute("aria-label",s);this.labelDecorWidth.textContent=e.decorWidth,this.labelDecorLength.textContent=e.decorLength,this.labelDecorHeight.textContent=e.decorHeight,this.labelDecorModel.textContent=e.decorModel,this.labelDecorModelAdvanced.textContent=e.decorModelAdvanced,this.labelDecorModelUrl.textContent=e.decorModelUrl,this.labelDecorModelTitle.textContent=e.decorModelTitle,this.labelDecorModelAuthor.textContent=e.decorModelAuthor,this.labelDecorModelLicense.textContent=e.decorModelLicense,this.labelDecorModelSource.textContent=e.decorModelSource,this.labelDecorFloors.textContent=e.decorFloors,this.labelDecorOccupiedFloor.textContent=e.decorOccupiedFloor,this.labelDecorWitnessSide.textContent=e.decorWitnessSide,this.labelDecorWindows.textContent=e.decorWindows,this.optionWitnessSideNone.textContent=e.decorWitnessSideNone;const t={front:e.decorSideFront,behind:e.decorSideBehind,left:e.decorSideLeft,right:e.decorSideRight,"front-left":e.decorSideFrontLeft,"front-right":e.decorSideFrontRight,"behind-left":e.decorSideBehindLeft,"behind-right":e.decorSideBehindRight};for(const i of ia)this.labelDecorSide[i].textContent=t[i],this.optionWitnessSide[i].textContent=t[i];this.refreshDecorList(),this.labelWitnessId.textContent=e.witnessId,this.labelWitnessDirName.textContent=e.witnessDirName,this.labelWitnessTitle.textContent=e.witnessTitle,this.labelWitnessLastName.textContent=e.witnessLastName,this.labelWitnessFirstNames.textContent=e.witnessFirstNames,this.witnessFirstNamesInput.placeholder=e.tagsPlaceholder,this.labelCaseId.textContent=e.caseId,this.labelDescription.textContent=e.description,this.labelTags.textContent=e.tags,this.tagsInput.placeholder=e.tagsPlaceholder,this.labelShapeGroup.textContent=e.shapeGroup,this.labelTemporalGroup.textContent=e.temporalGroup,this.labelLocationGroup.textContent=e.locationGroup,this.labelObservationGroup.textContent=e.observationGroup,this.labelWitnessGroup.textContent=e.witnessGroup,this.labelWeatherGroup.textContent=e.weather,this.refreshTimeQualifierOptions(),this.edtfModeButton.title=e.edtfModeTitle,this.edtfModeButton.setAttribute("aria-label",e.edtfModeTitle),this.paramSummaryBuilder=new bf(e,this.showerLanguage(),this.said,this.tagNames),this.refreshParamSummary();const n=this.skyDetailsButton.getAttribute("aria-expanded")==="true";this.skyDetailsButton.title=n?e.skyDetailsHide:e.skyDetails,this.skyDetailsButton.setAttribute("aria-label",this.skyDetailsButton.title),this.labelCloudCover.textContent=e.cloudCover,this.labelHighCloud.textContent=e.highCloudCover,this.labelIceAlignment.textContent=e.iceCrystalAlignment,this.labelFNumber.textContent=e.aperture,this.labelExposure.textContent=e.exposure,this.labelFocusDistance.textContent=e.focusDistance,this.syncOpticsFromInstrument(),this.labelCloudDarkness.textContent=e.cloudDarkness,this.labelCloudBase.textContent=e.cloudBase,this.labelPrecipitationType.textContent=e.precipitationType,this.optionPrecipitationNone.textContent=e.precipitationNone,this.optionPrecipitationRain.textContent=e.precipitationRain,this.optionPrecipitationSnow.textContent=e.precipitationSnow,this.optionPrecipitationHail.textContent=e.precipitationHail,this.labelPrecipitationIntensity.textContent=e.precipitationIntensity,this.labelWindDirection.textContent=e.windDirection,this.labelWindSpeed.textContent=e.windSpeed,this.labelStorm.textContent=e.storm,this.labelPrecipitationGroup.textContent=e.precipitationGroup,this.labelWindGroup.textContent=e.windGroup,this.labelWeatherInferred.textContent=e.weatherInferred,this.syncWeatherSourceState(),this.labelSoundGroup.textContent=e.soundGroup,this.labelSoundKind.textContent=e.soundKind,this.labelSoundVolume.textContent=e.soundVolume,this.labelSoundPitch.textContent=e.soundPitch,this.labelSoundSrc.textContent=e.soundSrc,this.soundSrcInput.placeholder=e.soundSrcPlaceholder;for(const[i,s]of this.soundKindOptions)s.textContent=this.soundKindLabel(i,e);this.labelInstrument.textContent=e.instrument,this.loopButton.title=e.autoReplay,this.loopButton.setAttribute("aria-label",e.autoReplay),this.setRecordButtonLabel(this.isRecording),this.syncPlaybackControls()}onPointerDown(e){if(this.isRecording){this.onPointerMove(e);return}const t=this.canvasPointFromEvent(e);if(!t)return;const n=this.ufoElement.sighting.timeline,i=this.ufoElement.currentTime,s=this.ufoElement.playbackState==="playing";if(this.selectedSourceIds.size>1){const l=new dc(this.selectedMembers()),c=it.hitTestHandle({bounds:l.bounds(),angle:0},t);if(c==="rotate"){if(s)return;this.dragState={kind:"group-rotate",group:l,startPointer:t},this.startDragListening();return}if(c){if(s)return;this.dragState={kind:"group-resize",group:l,handle:c},this.startDragListening();return}}else{const l=n.getInterpolatedShapeAt(i,this.currentSourceId),c=l?.kind==="polygon"?it.hitTestVertex(l,t):void 0;if(l?.kind==="polygon"&&c!==void 0){if(s)return;this.dragState={kind:"vertex",sourceId:this.currentSourceId,original:l,vertexIndex:c},this.startDragListening();return}const h=l&&it.hitTestHandle(l,t);if(l&&h){if(s)return;this.beginDrag(h==="rotate"?"rotate":"resize",this.currentSourceId,l,t,h);return}}const r=this.ufoElement.shapeAt(t.x,t.y,dm);if(!r){const l=this.pickDecorAt(e);if(l!==void 0){this.selectDecor(l);return}s||this.beginCameraDrag(t);return}if(this.revealShapePanel(),e.shiftKey?this.toggleUnitSelection(r.sourceId):this.selectedSourceIds.has(r.sourceId)||this.selectUnit(r.sourceId),s)return;const o=[...this.selectedSourceIds].map(l=>({sourceId:l,original:l===r.sourceId?r.shape:n.getInterpolatedShapeAt(i,l)??r.shape}));this.dragState={kind:"move",sources:o,startPointer:t},this.startDragListening()}revealShapePanel(){const e=this.groupTabs.find(t=>t.getAttribute("aria-controls")==="group-shape");e&&this.toggleGroup(e,!0)}selectedMembers(){const e=this.ufoElement.sighting.timeline,t=this.ufoElement.currentTime;return[...this.selectedSourceIds].map(n=>({sourceId:n,shape:e.getInterpolatedShapeAt(t,n)})).filter(n=>!!n.shape)}selectUnit(e){const t=this.ufoElement.sighting.timeline.groupMembers(e)??[e];t.length===this.selectedSourceIds.size&&t.every(n=>this.selectedSourceIds.has(n))&&e===this.currentSourceId||(this.selectedSourceIds=new Set(t),this.currentSourceId=e,this.refreshSourceList(),this.onSelectionOrTimeChanged())}toggleUnitSelection(e){const t=this.ufoElement.sighting.timeline,n=t.groupMembers(e)??[e];if(n.every(s=>this.selectedSourceIds.has(s))){if(n.length>=this.selectedSourceIds.size)return;for(const s of n)this.selectedSourceIds.delete(s);if(!this.selectedSourceIds.has(this.currentSourceId)){const s=t.sourceIds;this.currentSourceId=[...this.selectedSourceIds].sort((r,o)=>s.indexOf(r)-s.indexOf(o)).pop()}}else{for(const s of n)this.selectedSourceIds.add(s);this.currentSourceId=e}this.refreshSourceList(),this.onSelectionOrTimeChanged()}onContextMenu(e){if(e.preventDefault(),this.isRecording||this.ufoElement.playbackState==="playing")return;this.hideContextMenu(),this.hideDecorContextMenu();const t=this.canvasPointFromEvent(e);if(!t)return;const n=this.ufoElement.sighting.timeline,i=this.ufoElement.currentTime,s=this.selectedSourceIds.size===1?n.getInterpolatedShapeAt(i,this.currentSourceId):void 0,o=s?.kind==="polygon"&&it.hitTestVertex(s,t)!==void 0?{sourceId:this.currentSourceId}:this.ufoElement.shapeAt(t.x,t.y,dm);if(o){this.selectedSourceIds.has(o.sourceId)||this.selectUnit(o.sourceId),this.currentSourceId=o.sourceId,this.contextMenuPoint=t,this.showContextMenu(e.clientX,e.clientY);return}const l=this.pickDecorAt(e),c=l?this.ufoElement.sighting.decor.find(h=>h.id===l):void 0;c&&this.showDecorContextMenu(e.clientX,e.clientY,c)}pickDecorAt(e){const n=this.ufoElement.canvasElement.getBoundingClientRect();if(n.width===0||n.height===0)return;const i=(e.clientX-n.left)/n.width*2-1,s=-((e.clientY-n.top)/n.height*2-1);return this.sceneElement.pickDecorAt(i,s)}showContextMenu(e,t){this.contextMenu.style.left=`${e}px`,this.contextMenu.style.top=`${t}px`,this.contextMenu.hidden=!1;const n=this.ufoElement.sighting.timeline.sourceIds,i=n.filter(f=>this.selectedSourceIds.has(f)),s=n.length<=i.length,r=i.length>0&&n.slice(n.length-i.length).every(f=>this.selectedSourceIds.has(f)),o=i.length>0&&n.slice(0,i.length).every(f=>this.selectedSourceIds.has(f));this.contextBringToFrontButton.disabled=s||r,this.contextSendToBackButton.disabled=s||o,this.contextBringToFrontButton.title=s?this.messages.onlyOneShape:r?this.messages.alreadyAtFront:"",this.contextSendToBackButton.title=s?this.messages.onlyOneShape:o?this.messages.alreadyAtBack:"",this.contextGroupButton.disabled=this.selectedSourceIds.size<2,this.contextGroupButton.title=this.contextGroupButton.disabled?this.messages.needTwoShapesToGroup:"";const l=this.ufoElement.sighting.timeline.groupMembers(this.currentSourceId)!==void 0;this.contextUngroupButton.disabled=!l,this.contextUngroupButton.title=l?"":this.messages.notGrouped,this.contextDeleteButton.disabled=this.deleteShapeButton.disabled,this.contextDeleteButton.title=this.contextDeleteButton.disabled?this.messages.onlyOneShape:"";const c=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(this.ufoElement.currentTime,this.currentSourceId),h=this.selectedSourceIds.size===1&&c?.kind==="polygon";this.contextAddVertexButton.disabled=!h,this.contextAddVertexButton.title=h?"":this.messages.notAPolygon;const d=h&&this.contextMenuPoint?it.hitTestVertex(c,this.contextMenuPoint):void 0,u=h&&c.points.length<=Sm;this.contextDeleteVertexButton.disabled=!h||d===void 0||u,this.contextDeleteVertexButton.title=h?u?this.messages.tooFewVertices:"":this.messages.notAPolygon,document.addEventListener("click",this.handleOutsideContextMenuClick)}hideContextMenu(){this.contextMenu.hidden=!0,this.contextMenuPoint=void 0,document.removeEventListener("click",this.handleOutsideContextMenuClick)}handleOutsideContextMenuClick=e=>{e.composedPath().includes(this.contextMenu)||e.composedPath().includes(this.decorContextMenu)||(this.hideContextMenu(),this.hideDecorContextMenu())};showDecorContextMenu(e,t,n){this.contextMenuDecorId=n.id,this.decorContextMenu.style.left=`${e}px`,this.decorContextMenu.style.top=`${t}px`,this.decorContextMenu.hidden=!1,this.contextViewTestimonyButton.disabled=!n.sightingUrl,this.contextViewTestimonyButton.title=n.sightingUrl?"":this.messages.noWitnessRecording,this.refreshContextMasksSubmenu(n),document.addEventListener("click",this.handleOutsideContextMenuClick)}hideDecorContextMenu(){this.decorContextMenu.hidden=!0,this.contextMenuDecorId=void 0,document.removeEventListener("click",this.handleOutsideContextMenuClick)}refreshContextMasksSubmenu(e){this.contextMasksSubmenu.innerHTML="";for(const t of this.ufoElement.sighting.timeline.sourceIds){const n=document.createElement("label"),i=document.createElement("input");i.type="checkbox",i.checked=e.occludesSourceIds?.includes(t)??!1,i.addEventListener("change",()=>this.updateDecorOccludesShape(e.id,t,i.checked)),n.appendChild(i),n.appendChild(document.createTextNode(this.shapeLabel(t))),this.contextMasksSubmenu.appendChild(n)}}updateDecorOccludesShape(e,t,n){const i=this.ufoElement.sighting;i.decor=i.decor.map(s=>{if(s.id!==e)return s;const r=n?[...new Set([...s.occludesSourceIds??[],t])]:(s.occludesSourceIds??[]).filter(o=>o!==t);return{...s,occludesSourceIds:r.length>0?r:void 0}}),this.ufoElement.refresh()}viewWitnessTestimony(){const e=this.ufoElement.sighting.decor.find(t=>t.id===this.contextMenuDecorId);this.hideDecorContextMenu(),e?.sightingUrl&&this.importFromUrl(e.sightingUrl)}addVertexAtContextMenu(){const e=this.contextMenuPoint;if(this.hideContextMenu(),!e)return;const t=this.ufoElement.currentTime,n=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(t,this.currentSourceId);if(n?.kind!=="polygon")return;const i=it.insertVertexNear(n,e);this.commitShapes(t,[{sourceId:this.currentSourceId,shape:i}]),this.ufoElement.refresh()}deleteVertexAtContextMenu(){const e=this.contextMenuPoint;if(this.hideContextMenu(),!e)return;const t=this.ufoElement.currentTime,n=this.ufoElement.sighting.timeline.getInterpolatedShapeAt(t,this.currentSourceId);if(n?.kind!=="polygon")return;const i=it.hitTestVertex(n,e);if(i===void 0)return;const s=it.deleteVertex(n,i);this.commitShapes(t,[{sourceId:this.currentSourceId,shape:s}]),this.ufoElement.refresh()}bringSelectedToFront(){const e=this.ufoElement.sighting.timeline;for(const t of e.sourceIds.filter(n=>this.selectedSourceIds.has(n)))e.bringToFront(t);this.hideContextMenu(),this.ufoElement.refresh()}sendSelectedToBack(){const e=this.ufoElement.sighting.timeline;for(const t of e.sourceIds.filter(n=>this.selectedSourceIds.has(n)).reverse())e.sendToBack(t);this.hideContextMenu(),this.ufoElement.refresh()}groupSelected(){this.selectedSourceIds.size<2||(this.ufoElement.sighting.timeline.group([...this.selectedSourceIds]),this.hideContextMenu(),this.ufoElement.refresh())}ungroupSelected(){this.ufoElement.sighting.timeline.ungroup(this.currentSourceId),this.selectedSourceIds=new Set([this.currentSourceId]),this.hideContextMenu(),this.ufoElement.refresh()}beginDrag(e,t,n,i,s){this.dragState={kind:e,sourceId:t,original:n,handle:s,startPointer:i},this.startDragListening()}beginCameraDrag(e){const t=this.isWitnessInsideDecor();this.cameraDragState={startPointer:e,startHeadingDeg:t?this.indoorLookYawDeg:this.numberOrUndefined(this.headingInput.value)??0,startPitchDeg:t?this.indoorLookPitchDeg:this.numberOrUndefined(this.pitchInput.value)??0,insideDecor:t},t||this.sceneElement.setCompassForced(!0),this.setCanvasCursor("panning"),this.startDragListening()}isWitnessInsideDecor(){return this.ufoElement.sighting.decor.some(e=>e.witnessSide!==void 0&&Na(e.kind))}syncIndoorLookReset(){const e=this.ufoElement.sighting.decor.find(n=>n.witnessSide!==void 0&&Na(n.kind)),t=e?`${e.id}:${e.witnessSide}`:void 0;t!==this.lastInhabitedKey&&(this.lastInhabitedKey=t,this.indoorLookYawDeg=0,this.indoorLookPitchDeg=0,this.sceneElement.setIndoorLook(0,0))}startDragListening(){document.addEventListener("pointermove",this.handleDragPointerMove),document.addEventListener("pointerup",this.handleDragPointerUp)}onDragPointerMove(e){if(this.cameraDragState){this.onCameraDragPointerMove(e);return}if(!this.dragState)return;const t=this.canvasPointFromEvent(e);if(!t)return;const n=this.ufoElement.currentTime;if(this.dragState.kind==="move"){const{sources:i,startPointer:s}=this.dragState,r=t.x-s.x,o=t.y-s.y,l=i.map(({sourceId:c,original:h})=>({sourceId:c,shape:{...h,bounds:{...h.bounds,x:h.bounds.x+r,y:h.bounds.y+o}}}));this.commitShapes(n,l)}else if(this.dragState.kind==="group-resize"){const{group:i,handle:s}=this.dragState;this.commitShapes(n,i.resize(s,t))}else if(this.dragState.kind==="group-rotate"){const{group:i,startPointer:s}=this.dragState;this.commitShapes(n,i.rotate(t,s))}else if(this.dragState.kind==="vertex"){const{sourceId:i,original:s,vertexIndex:r}=this.dragState,o=it.moveVertex(s,r,t);this.commitShapes(n,[{sourceId:i,shape:o}])}else{const{kind:i,sourceId:s,original:r,handle:o}=this.dragState,l=i==="resize"?it.resizeShape(r,o,t):it.rotateShape(r,t);this.commitShapes(n,[{sourceId:s,shape:l}])}this.ufoElement.refresh()}onCameraDragPointerMove(e){if(!this.cameraDragState)return;const t=this.canvasPointFromEvent(e);if(!t)return;const{startPointer:n,startHeadingDeg:i,startPitchDeg:s,insideDecor:r}=this.cameraDragState,o=i+(t.x-n.x)*fm,l=Math.max(-90,Math.min(90,s-(t.y-n.y)*fm));if(r){this.indoorLookYawDeg=o,this.indoorLookPitchDeg=l,this.sceneElement.setIndoorLook(o,l),this.ufoElement.refresh();return}this.headingInput.value=String(this.rounded(o)),this.pitchInput.value=String(this.rounded(l)),this.updateObserver()}endDrag(){!this.dragState&&!this.cameraDragState||(this.cameraDragState&&!this.cameraDragState.insideDecor&&this.sceneElement.setCompassForced(!1),this.dragState=void 0,this.cameraDragState=void 0,this.setCanvasCursor(this.hoverCursor),document.removeEventListener("pointermove",this.handleDragPointerMove),document.removeEventListener("pointerup",this.handleDragPointerUp))}nudgeBounds(e,t){const n={...e};if(t.shiftKey){switch(t.key){case"ArrowLeft":n.width=Math.max(gs,n.width-us);break;case"ArrowRight":n.width+=us;break;case"ArrowUp":n.height=Math.max(gs,n.height-us);break;case"ArrowDown":n.height+=us;break}n.x-=(n.width-e.width)/2,n.y-=(n.height-e.height)/2}else switch(t.key){case"ArrowLeft":n.x-=us;break;case"ArrowRight":n.x+=us;break;case"ArrowUp":n.y-=us;break;case"ArrowDown":n.y+=us;break}return n}moveOrResizeSelectedShapes(e){if(this.isRecording||this.ufoElement.playbackState==="playing")return;const t=this.ufoElement.currentTime,n=this.selectedMembers();if(n.length!==0){if(e.preventDefault(),n.length===1){const{sourceId:i,shape:s}=n[0];this.commitShapes(t,[{sourceId:i,shape:{...s,bounds:this.nudgeBounds(s.bounds,e)}}])}else{const i=new dc(n),s=this.nudgeBounds(i.bounds(),e);this.commitShapes(t,i.scaleTo(s))}this.ufoElement.refresh()}}updateHoverCursor(e){this.isRecording||this.dragState||this.cameraDragState||(this.hoverCursor=this.hoverCursorAt(e),this.setCanvasCursor(this.hoverCursor))}hoverCursorAt(e){const t=this.canvasPointFromEvent(e);if(!t)return;const n=this.ufoElement.sighting.timeline,i=this.ufoElement.currentTime,s=this.ufoElement.playbackState!=="playing";if(s)if(this.selectedSourceIds.size>1){const r=it.hitTestHandle({bounds:new dc(this.selectedMembers()).bounds(),angle:0},t);if(r)return this.cursorForHandle(r,0)}else{const r=n.getInterpolatedShapeAt(i,this.currentSourceId);if(r?.kind==="polygon"&&it.hitTestVertex(r,t)!==void 0)return"vertex";const o=r&&it.hitTestHandle(r,t);if(r&&o)return this.cursorForHandle(o,r.angle)}return n.hitTest(i,t.x,t.y)?s?"move":"select":this.pickDecorAt(e)!==void 0?"select":s?"pan":void 0}cursorForHandle(e,t){return e==="rotate"?"rotate":`resize-${it.resizeAxisFor(e,t)}`}setCanvasCursor(e){const t=this.ufoElement.canvasElement;e?t.dataset.cursor=e:delete t.dataset.cursor}onPointerMove(e){if(!this.isRecording){this.updateHoverCursor(e);return}const t=this.ufoElement.canvasElement,n=t.getBoundingClientRect(),i=e.clientX-n.left,s=e.clientY-n.top;this.recorder?.onPointerMove(i,s),this.ufoElement.renderer.clear(t.width,t.height),this.ufoElement.renderer.paintShape(wm(this.buildPrototype({x:0,y:0,width:Da.width,height:Da.height}),i,s))}canvasPointFromEvent(e){const t=this.ufoElement.canvasElement,n=t.getBoundingClientRect();if(!(n.width===0||n.height===0))return{x:(e.clientX-n.left)/n.width*t.width,y:(e.clientY-n.top)/n.height*t.height}}}const bA={stated:"narrativeStated",derived:"narrativeDerived",assumed:"narrativeAssumed"},gm="rr0-sighting-editor",vm="rr0-ufo-recorder";class xA extends Mt{}function wA(){Ql(),customElements.get(gm)||customElements.define(gm,Mt),customElements.get(vm)||customElements.define(vm,xA)}wA();export{An as $,Qn as A,vt as B,le as C,Nb as D,Yi as E,PA as F,ft as G,Ct as H,AA as I,TA as J,Ke as K,lo as L,CA as M,bo as N,It as O,Pb as P,_s as Q,Jr as R,qr as S,MA as T,IA as U,Re as V,ig as W,DA as X,wl as Y,fn as Z,ii as _,_A as a,EA as a0,hr as a1,ng as a2,RA as a3,eb as a4,Ol as a5,Dd as a6,zl as a7,rn as a8,cg as a9,Lu as aa,Nu as ab,Qe as ac,Ms as ad,oo as ae,Ci as af,Ji as ag,SA as b,Un as c,OA as d,Fl as e,Fn as f,NA as g,qe as h,P as i,cp as j,LA as k,kA as l,Zy as m,Vs as n,vc as o,zh as p,ty as q,At as r,Ka as s,Yt as t,jh as u,wn as v,sg as w,ji as x,rb as y,fb as z};
|