@rr0/ufoathome 0.127.3 → 0.128.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist-embed-interview/InterviewMessages_es-CNKjrohj.js +1 -0
  2. package/dist-embed-interview/InterviewMessages_fr-BP99Pg7g.js +1 -0
  3. package/dist-embed-interview/InterviewMessages_it-DTIrw8wW.js +1 -0
  4. package/dist-embed-interview/rr0-interview.mjs +5 -5
  5. package/dist-embed-scene/RailwaySystem-IcloRjw9.js +41 -0
  6. package/dist-embed-scene/{SceneNames_es-B9tudMDH.js → SceneNames_es-BITaYGB1.js} +1 -1
  7. package/dist-embed-scene/{SceneNames_fr-DAd-g0yB.js → SceneNames_fr-Bdk_h-Pr.js} +1 -1
  8. package/dist-embed-scene/{SceneNames_it-BLLX--oG.js → SceneNames_it-DhE0SScp.js} +1 -1
  9. package/dist-embed-scene/browser-_Ncw3Jhn.js +1 -0
  10. package/dist-embed-scene/rr0-scene.mjs +303 -300
  11. package/dist-embed-scene/{sightingSchema-v2l1p6Ld.js → sightingSchema-W7ivL-LH.js} +1 -1
  12. package/dist-embed-sighting/RailwaySystem-SElJhlLh.js +41 -0
  13. package/dist-embed-sighting/{SceneNames_es-VHJ-mGWu.js → SceneNames_es-Zb4vw-Vp.js} +1 -1
  14. package/dist-embed-sighting/{SceneNames_fr-BtjbcaRx.js → SceneNames_fr-C6_IIN2c.js} +1 -1
  15. package/dist-embed-sighting/{SceneNames_it-Ck8f90Z6.js → SceneNames_it-D7GivBq2.js} +1 -1
  16. package/dist-embed-sighting/browser-_Ncw3Jhn.js +1 -0
  17. package/dist-embed-sighting/rr0-sighting.mjs +296 -293
  18. package/dist-embed-sighting/{sightingSchema-v2l1p6Ld.js → sightingSchema-W7ivL-LH.js} +1 -1
  19. package/dist-embed-sighting-editor/{AdsbLolArchiveProvider-BtbGVTLo.js → AdsbLolArchiveProvider-DAFMMxZ9.js} +1 -1
  20. package/dist-embed-sighting-editor/{BodyEditor-BAT3yx6v.js → BodyEditor-T_1Jhs5n.js} +1 -1
  21. package/dist-embed-sighting-editor/CaseEditorMessages_es-DwO2w2Vc.js +1 -0
  22. package/dist-embed-sighting-editor/CaseEditorMessages_fr-iFzha0wM.js +1 -0
  23. package/dist-embed-sighting-editor/CaseEditorMessages_it-CjdJSAvo.js +1 -0
  24. package/dist-embed-sighting-editor/{ContrailSystem-B24rkkhS.js → ContrailSystem-DAHnNwJY.js} +1 -1
  25. package/dist-embed-sighting-editor/CoverageAssessor-24x89QSu.js +1 -0
  26. package/dist-embed-sighting-editor/GLTFLoader-BrlMonfv.js +1 -0
  27. package/dist-embed-sighting-editor/HeadlightSystem-9Ve6quO7.js +34 -0
  28. package/dist-embed-sighting-editor/{HynekAssessor-DVFjzROZ.js → HynekAssessor-CspF0udm.js} +1 -1
  29. package/dist-embed-sighting-editor/{InterviewEditorElement-CcEomZL0.js → InterviewEditorElement-Dm-ghjgg.js} +7 -9
  30. package/dist-embed-sighting-editor/InterviewMessages_en-yw5Qfw-6.js +1 -0
  31. package/dist-embed-sighting-editor/InterviewMessages_es-CNKjrohj.js +1 -0
  32. package/dist-embed-sighting-editor/InterviewMessages_fr-BP99Pg7g.js +1 -0
  33. package/dist-embed-sighting-editor/InterviewMessages_it-DTIrw8wW.js +1 -0
  34. package/dist-embed-sighting-editor/{LaunchEditor-BXDWiKWm.js → LaunchEditor-DfbahkM1.js} +1 -1
  35. package/dist-embed-sighting-editor/ModelSource-BjAOa9Br.js +1 -0
  36. package/dist-embed-sighting-editor/{ModelThumbnails-CGklRkoB.js → ModelThumbnails-B8ONo6Zq.js} +1 -1
  37. package/dist-embed-sighting-editor/{ModelViewer-Bg9kN_Zq.js → ModelViewer-BRBnm1f4.js} +1 -1
  38. package/dist-embed-sighting-editor/RailwaySystem-CO0S5Tvo.js +41 -0
  39. package/dist-embed-sighting-editor/{RoadMarkings-CVibbxgC.js → RoadMarkings-ysQVkGP6.js} +1 -1
  40. package/dist-embed-sighting-editor/{SceneNames_es-4pppn42v.js → SceneNames_es-BJhUPnW8.js} +1 -1
  41. package/dist-embed-sighting-editor/{SceneNames_fr-odZ6uYWU.js → SceneNames_fr-DXA1PSOW.js} +1 -1
  42. package/dist-embed-sighting-editor/{SceneNames_it-lXfB7y6i.js → SceneNames_it-CKVqa3DF.js} +1 -1
  43. package/dist-embed-sighting-editor/{SightingEditorMessages_es-C2q5UZrw.js → SightingEditorMessages_es-j9jNoZ69.js} +2 -2
  44. package/dist-embed-sighting-editor/SightingEditorMessages_fr-ClasHdht.js +12 -0
  45. package/dist-embed-sighting-editor/SightingEditorMessages_it-CgRkHcvD.js +12 -0
  46. package/dist-embed-sighting-editor/{SightingFileEditor-7inIgp24.js → SightingFileEditor-CEjimNPM.js} +1 -1
  47. package/dist-embed-sighting-editor/{TraceSystem-CZSZY6ZM.js → TraceSystem-BJbyw7Wf.js} +2 -2
  48. package/dist-embed-sighting-editor/{WaterSystem-Bd010I79.js → WaterSystem-DprmGdDo.js} +1 -1
  49. package/dist-embed-sighting-editor/rr0-sighting-editor.mjs +430 -358
  50. package/dist-embed-sighting-editor/{sightingSchema-v2l1p6Ld.js → sightingSchema-W7ivL-LH.js} +1 -1
  51. package/dist-embed-sighting-editor/surroundingsSources-C67enaVE.js +1 -0
  52. package/dist-embed-sighting-editor/trafficRuntime-oYuU__pd.js +2 -0
  53. package/package.json +1 -1
  54. package/dist-embed-interview/InterviewMessages_es-D5d2JVA3.js +0 -1
  55. package/dist-embed-interview/InterviewMessages_fr-CmScqfza.js +0 -1
  56. package/dist-embed-interview/InterviewMessages_it-2SNw5xMp.js +0 -1
  57. package/dist-embed-scene/RailwaySystem-BSqu6iHY.js +0 -41
  58. package/dist-embed-sighting/RailwaySystem-BXRi4IAz.js +0 -41
  59. package/dist-embed-sighting-editor/CaseEditorMessages_es-CNLEMPjy.js +0 -1
  60. package/dist-embed-sighting-editor/CaseEditorMessages_fr-DN3xxn9o.js +0 -1
  61. package/dist-embed-sighting-editor/CaseEditorMessages_it-B6aG-baK.js +0 -1
  62. package/dist-embed-sighting-editor/CoverageAssessor-BPhdv7QL.js +0 -1
  63. package/dist-embed-sighting-editor/GLTFLoader-C7miE2gT.js +0 -1
  64. package/dist-embed-sighting-editor/HeadlightSystem-DaWqNslK.js +0 -34
  65. package/dist-embed-sighting-editor/InterviewMessages_en-cs-wWpmz.js +0 -1
  66. package/dist-embed-sighting-editor/InterviewMessages_es-D5d2JVA3.js +0 -1
  67. package/dist-embed-sighting-editor/InterviewMessages_fr-CmScqfza.js +0 -1
  68. package/dist-embed-sighting-editor/InterviewMessages_it-2SNw5xMp.js +0 -1
  69. package/dist-embed-sighting-editor/ModelSource-gIw80dOv.js +0 -1
  70. package/dist-embed-sighting-editor/RailwaySystem-BCDMPAEx.js +0 -41
  71. package/dist-embed-sighting-editor/SightingEditorMessages_fr-DyELrz-P.js +0 -12
  72. package/dist-embed-sighting-editor/SightingEditorMessages_it-CUKdtgr1.js +0 -12
  73. package/dist-embed-sighting-editor/surroundingsSources-98rSCu2Y.js +0 -1
  74. package/dist-embed-sighting-editor/trafficRuntime-Dk4XdgcY.js +0 -2
@@ -0,0 +1,34 @@
1
+ import{ay as b,F as g,a0 as P,az as m,aa as C,ac as x,ai as E,a6 as L,ax as R,aA as I}from"./rr0-sighting-editor.mjs";class i{constructor(e){this.scene=e}static REAL_BEAMS=4;static LAMPS=2;static DISTANCE_M=500;static AIR_LENGTH_M=90;static CLEAR_AIR_SCATTER_PER_M=2e-4;static SHADOW_MAP_PX=1024;beams=new Map;static airGeometry;has(e){return this.beams.has(e)}get size(){return this.beams.size}lamps(e){return this.beams.get(e)?.lamps??[]}airMeshes(e){return this.beams.get(e)?.air??[]}add(e){if(this.beams.has(e))return!0;if(this.beams.size>=i.REAL_BEAMS)return!1;const t=[],r=[];for(let n=0;n<i.LAMPS;n++){const a=new b(16777215,0,i.DISTANCE_M,Math.PI/8,.5,2);a.castShadow=e==="observer",a.shadow.mapSize.set(i.SHADOW_MAP_PX,i.SHADOW_MAP_PX),a.shadow.camera.near=.4,a.shadow.camera.far=110,a.shadow.bias=-4e-4,a.shadow.normalBias=.04,a.shadow.radius=2,this.scene.add(a),this.scene.add(a.target),t.push(a);const o=new g(i.airCone(),i.airMaterial());o.visible=!1,o.frustumCulled=!1,o.renderOrder=8,o.castShadow=!1,o.receiveShadow=!1,o.name="headlight air",this.scene.add(o),r.push(o)}return this.beams.set(e,{lamps:t,air:r}),!0}remove(e){const t=this.beams.get(e);if(t){for(const r of t.lamps)r.removeFromParent(),r.target.removeFromParent(),r.dispose();for(const r of t.air)r.removeFromParent(),r.material.dispose();this.beams.delete(e)}}clear(e){for(const t of[...this.beams.keys()])e&&t==="observer"||this.remove(t)}dispose(){this.clear(!1),i.airGeometry?.dispose(),i.airGeometry=void 0}aim(e,t,r,n,a,o,u){const c=this.beams.get(e),w=Math.max(u,i.CLEAR_AIR_SCATTER_PER_M);if(!c)return;const l=m.BEAMS[t],v=new P(-n.z,0,n.x),A=e==="observer"&&l!==void 0;c.lamps.forEach((s,d)=>{if(!l){s.intensity=0,c.air[d].visible=!1,s.shadow.autoUpdate=!1;return}const f=d===0?-1:1,h=l.pitchDeg*Math.PI/180,p=l.candela*m.DISPLAY_GAIN*o/c.lamps.length;s.color.set(l.color),s.intensity=p,s.angle=l.halfAngleDeg*Math.PI/180,s.penumbra=l.penumbra,A?(s.shadow.autoUpdate||(s.shadow.needsUpdate=!0),s.shadow.autoUpdate=!0):s.shadow.autoUpdate=!1,s.position.copy(r).addScaledVector(v,f*a);const M=n.clone().addScaledVector(v,-f*Math.tan(m.TOE_IN_DEG*Math.PI/180)).normalize();s.target.position.set(s.position.x+M.x*Math.cos(h)*50,s.position.y-Math.sin(h)*50,s.position.z+M.z*Math.cos(h)*50),s.target.updateMatrixWorld(),this.aimAir(c.air[d],s,l.color,p,w)})}aimAir(e,t,r,n,a){if(e.visible=a*n>1e-4,!e.visible)return;const o=i.AIR_LENGTH_M,u=o*Math.tan(t.angle);e.position.copy(t.position),e.scale.set(u,u,o),e.lookAt(t.target.position),e.updateMatrixWorld();const c=e.material.uniforms;c.uColor.value.set(r),c.uCandela.value=n,c.uScatter.value=a,c.uLength.value=o,c.uRadius.value=u}static airCone(){if(i.airGeometry)return i.airGeometry;const e=24,t=new Float32Array((e+1)*3);for(let a=0;a<e;a++){const o=a/e*Math.PI*2;t.set([Math.cos(o),Math.sin(o),1],(a+1)*3)}const r=[];for(let a=0;a<e;a++)r.push(0,1+a,1+(a+1)%e);const n=new C;return n.setAttribute("position",new x(t,3)),n.setIndex(r),i.airGeometry=n,n}static airMaterial(){return new E({transparent:!0,depthWrite:!1,depthTest:!0,blending:I,side:R,uniforms:{uColor:{value:new L(1,1,1)},uCandela:{value:0},uScatter:{value:0},uLength:{value:90},uRadius:{value:20}},vertexShader:`
2
+ varying vec3 vLocal;
3
+ varying vec3 vNormalView;
4
+ varying vec3 vViewDir;
5
+ void main() {
6
+ vLocal = position;
7
+ vec4 viewPosition = modelViewMatrix * vec4(position, 1.0);
8
+ // The side's normal, out of the axis: the apex has none (its length is nought), and a normal of nought there would spread NaN over the whole cone.
9
+ float ring = length(position.xy);
10
+ vec3 outward = ring > 1e-5 ? vec3(position.xy / ring, 0.0) : vec3(0.0, 0.0, 1.0);
11
+ vNormalView = normalize(normalMatrix * outward);
12
+ vViewDir = -viewPosition.xyz;
13
+ gl_Position = projectionMatrix * viewPosition;
14
+ }`,fragmentShader:`
15
+ uniform vec3 uColor;
16
+ uniform float uCandela;
17
+ uniform float uScatter;
18
+ uniform float uLength;
19
+ uniform float uRadius;
20
+ varying vec3 vLocal;
21
+ varying vec3 vNormalView;
22
+ varying vec3 vViewDir;
23
+ void main() {
24
+ float t = clamp(vLocal.z, 0.0, 1.0);
25
+ float distanceM = max(t * uLength, 1.5);
26
+ // The chord a ray makes through a cone of this thickness: long going along the beam, short going across its edge.
27
+ float facing = abs(dot(normalize(vNormalView), normalize(vViewDir + vec3(0.0, 0.0, 1e-4))));
28
+ float chord = 2.0 * uRadius * t * (0.25 + 0.75 * facing);
29
+ // The beam's own profile averaged over the chord: strongest on the axis, none at the edge of the cone.
30
+ float profile = 0.55;
31
+ float radiance = uScatter * uCandela * chord * profile / (distanceM * distanceM + 9.0);
32
+ float ends = (1.0 - smoothstep(0.75, 1.0, t)) * smoothstep(0.0, 0.04, t);
33
+ gl_FragColor = vec4(uColor * radiance * ends, 1.0);
34
+ }`})}}export{i as HeadlightSystem};
@@ -1 +1 @@
1
- import{a0 as r,a1 as c,a2 as l}from"./rr0-sighting-editor.mjs";const v=-6,p=150;class o{about="temporal";async assess(e){const t=o.daylight(e),i=e.decor.map((s,n)=>({object:s,index:n})).filter(({object:s})=>s.kind==="entity"),a=o.nearest(e),d=a!==void 0&&a<=p;return{verdict:i.length>0?"ce3":d?"ce1":t===void 0?void 0:t?"dd":"nl",criteria:[{id:"entities",basis:i.length>0?"stated":void 0,paths:i.map(({index:s})=>`decor.${s}`)},{id:"traces",paths:[],unsupported:!0},{id:"proximity",basis:a===void 0?void 0:"derived",paths:a===void 0?[]:["timeline","observerTrack"]},{id:"radar",paths:[],unsupported:!0},{id:"daylight",basis:t===void 0?void 0:"derived",paths:t===void 0?[]:["time","place"]}]}}static nearest(e){const t=e.timeline.sourceIds.map(i=>r.of(e,i)?.nearestM).filter(i=>i!==void 0);return t.length>0?Math.min(...t):void 0}static daylight(e){const t=e.event.place?.[0],i=e.event.time;if(!t||!i)return;const a=c(i,t.lng,e.event.utcOffsetHours);if(a)return l("Sun",a,{lat:t.lat,lng:t.lng,elevationM:0}).altitudeDeg>v}}export{o as HynekAssessor};
1
+ import{a2 as r,a3 as c,a4 as l}from"./rr0-sighting-editor.mjs";const v=-6,p=150;class o{about="temporal";async assess(e){const t=o.daylight(e),i=e.decor.map((s,n)=>({object:s,index:n})).filter(({object:s})=>s.kind==="entity"),a=o.nearest(e),d=a!==void 0&&a<=p;return{verdict:i.length>0?"ce3":d?"ce1":t===void 0?void 0:t?"dd":"nl",criteria:[{id:"entities",basis:i.length>0?"stated":void 0,paths:i.map(({index:s})=>`decor.${s}`)},{id:"traces",paths:[],unsupported:!0},{id:"proximity",basis:a===void 0?void 0:"derived",paths:a===void 0?[]:["timeline","observerTrack"]},{id:"radar",paths:[],unsupported:!0},{id:"daylight",basis:t===void 0?void 0:"derived",paths:t===void 0?[]:["time","place"]}]}}static nearest(e){const t=e.timeline.sourceIds.map(i=>r.of(e,i)?.nearestM).filter(i=>i!==void 0);return t.length>0?Math.min(...t):void 0}static daylight(e){const t=e.event.place?.[0],i=e.event.time;if(!t||!i)return;const a=c(i,t.lng,e.event.utcOffsetHours);if(a)return l("Sun",a,{lat:t.lat,lng:t.lng,elevationM:0}).altitudeDeg>v}}export{o as HynekAssessor};
@@ -1,5 +1,5 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./SightingFileEditor-7inIgp24.js","./sightingSchema-v2l1p6Ld.js"])))=>i.map(i=>d[i]);
2
- import{S as x,a as y,H as O,s as R,U as j,l as I,I as B,P as M,b as P,c as g,M as U,_ as T,d as H}from"./rr0-sighting-editor.mjs";import{interviewMessages_en as k}from"./InterviewMessages_en-cs-wWpmz.js";import{InterviewMedia as A}from"./InterviewMedia-CvAxC62V.js";import{InterviewFile as v}from"./interviewJson-CfwBPiuG.js";const N="rr0-interview",D=`
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./SightingFileEditor-CEjimNPM.js","./sightingSchema-W7ivL-LH.js"])))=>i.map(i=>d[i]);
2
+ import{S as x,a as y,H as O,s as R,U as j,l as I,I as M,P as B,r as P,b as H,c as b,M as U,_ as T,d as D}from"./rr0-sighting-editor.mjs";import{interviewMessages_en as E}from"./InterviewMessages_en-yw5Qfw-6.js";import{InterviewMedia as A}from"./InterviewMedia-CvAxC62V.js";import{InterviewFile as v}from"./interviewJson-CfwBPiuG.js";const F="rr0-interview",$=`
3
3
  rr0-interview { display: block; --rr0-interview-line: color-mix(in srgb, currentColor 35%, transparent); }
4
4
  rr0-interview [hidden] { display: none !important; }
5
5
  rr0-interview .rr0-interview-status { font-size: .85em; opacity: .85; margin: 0 0 .5em; }
@@ -26,7 +26,7 @@ rr0-interview .turn .refs { display: flex; flex-wrap: wrap; gap: .25em; }
26
26
  rr0-interview .turn .ref { font: inherit; font-size: .8em; cursor: pointer; border: 1px solid var(--rr0-interview-line); border-radius: 999px; background: transparent; color: inherit;
27
27
  padding: 0 .35em; font-variant-numeric: tabular-nums; white-space: nowrap; display: inline-flex; align-items: center; gap: .15em; }
28
28
  rr0-interview .turn .ref svg { width: 1.1em; height: 1.1em; }
29
- `;class L extends HTMLElement{messages=k;said=new x(["en"]);localeToken=0;loadToken=0;json;loading;base;status=document.createElement("p");turns=document.createElement("div");blocks=new Map;constructor(){super(),this.status.className="rr0-interview-status",this.status.setAttribute("role","status"),this.turns.className="rr0-interview-turns"}static get observedAttributes(){return["src"]}attributeChangedCallback(e,t,i){e==="src"&&i!==t&&this.isConnected&&this.load()}connectedCallback(){L.styleRoot(this.getRootNode()),this.contains(this.turns)||this.replaceChildren(this.status,this.turns),this.loadLocale(),this.hasAttribute("src")&&this.json===void 0&&this.loading!==this.getAttribute("src")&&this.load()}get interview(){return this.json}set interview(e){this.loadToken++,this.json=e,this.draw()}set documentUrl(e){this.base=e}static styleRoot(e){const t=e instanceof ShadowRoot?e:document.head;if(t.querySelector("style[data-rr0-interview]"))return;const i=document.createElement("style");i.dataset.rr0Interview="",i.textContent=D,t.append(i)}async load(){const e=this.getAttribute("src"),t=++this.loadToken;if(this.loading=e??void 0,!e)return;const i=new URL(e,location.href).href;let s;try{s=await y.json(i)}catch{s=void 0}t===this.loadToken&&(this.base=i,this.json=s,this.draw())}async loadLocale(){const e=++this.localeToken,t=O.preferencesFor(this),i=R(t,j),s=i==="en"?k:await I(i);e===this.localeToken&&(this.said=new x(t),this.messages=s,this.draw())}speakerName(e,t){const i=v.speakerName(e,t),s=e.speakers?.[t]?.role;return i===s&&s in this.messages.roles?this.messages.roles[s]:i}seek(e){const t=this.json,i={sighting:e.sighting??v.sightingsOf(t)[0],at:e.at};this.dispatchEvent(new CustomEvent(B,{bubbles:!0,composed:!0,detail:i}));const s=this.getAttribute("player");if(!s)return;const c=this.getRootNode().getElementById?.(s);typeof c?.seekTo=="function"&&(c.scrollIntoView?.({block:"center",behavior:"smooth"}),c.seekTo(i.at,i.sighting))}gap(e,t){const i=document.createElement(t),s=document.createElement("span");s.className="bar";const r=`${this.messages.redacted} : ${this.said.read(e)??""}`;return s.dataset.tip=r,s.tabIndex=0,s.setAttribute("role","img"),s.setAttribute("aria-label",r),i.append(s),i}saidNodes(e){if(!/[<&]/.test(e))return[document.createTextNode(e)];const t=document.createElement("template");t.innerHTML=e;for(const i of t.content.querySelectorAll("*")){if(["SCRIPT","STYLE","IFRAME","OBJECT","EMBED"].includes(i.tagName)){i.remove();continue}for(const s of[...i.attributes])if(/^on/i.test(s.name)||/^\s*javascript:/i.test(s.value))i.removeAttribute(s.name);else if(["href","src"].includes(s.name))try{s.value=new URL(s.value,this.base??location.href).href}catch{}}return[...t.content.childNodes]}draw(){const e=this.messages,t=this.json;this.blocks.clear();const i=Array.isArray(t?.segments)?t.segments:[];if(!t||i.length===0){this.status.hidden=!0;const n=document.createElement("p");n.textContent=e.exchangesEmpty,this.turns.replaceChildren(n);return}const s=t.speakers??{},r=Object.keys(s);if(t.proofreading){const n=r.filter(h=>!["approved","covered"].includes(t.proofreading?.[h]?.status??""));this.status.textContent=n.length===0?e.proofreadAll:e.proofreadPending.replace("{names}",n.map(h=>this.speakerName(t,h)).join(", ")),this.status.hidden=!1}else this.status.hidden=!0;const c=[];let a,p=!1,l,o;i.forEach((n,h)=>{const E=n.redacted?JSON.stringify(n.redacted.reason):void 0;if(E!==void 0&&l?.reason===E){this.blocks.set(h,l.block),n.speaker!==o&&(o=void 0);return}const f=document.createElement("div");f.className="turn",f.dataset.segment=String(h);const w=document.createElement("div");w.className="who";const S=document.createElement("span");if(S.textContent=n.redacted?"":this.speakerName(t,n.speaker),n.start!==void 0&&(f.dataset.time=v.clock(n.start,!0)),o!==n.speaker&&(a=document.createElement("div"),a.className="intervention",a.style.setProperty("--speaker-hue",String((Math.max(0,r.indexOf(n.speaker))*67+210)%360)),c.push(a),p=!1),n.redacted||(p&&f.classList.add("goes-on"),p=!0),a.append(f),o=n.speaker,w.append(S),n.redacted){f.classList.add("is-redacted");const u=this.gap(n.redacted.reason,"p");u.className="redacted",l={block:f,reason:E},f.append(w,u)}else{const u=document.createElement("p");if(u.className="said",n.parts){let b="";for(const m of n.parts){const C="redacted"in m?"▮":v.plain(m.text);/[\p{L}\p{N}.,;:!?)»”…▮]$/u.test(b)&&/^[\p{L}\p{N}(«“▮]/u.test(C)&&u.append(" "),"redacted"in m?u.append(this.gap(m.redacted.reason,"span")):u.append(...this.saidNodes(m.text)),b=C}}else u.append(...this.saidNodes(n.text??""));l=void 0,f.append(w,u)}if(n.refs?.length){const u=document.createElement("div");u.className="refs";for(const b of n.refs){const m=document.createElement("button");m.type="button",m.className="ref",m.innerHTML=M.PLAY,m.append(v.clock(b.at,!0)),m.addEventListener("click",()=>this.seek(b)),u.append(m)}f.append(u)}this.blocks.set(h,f)}),this.turns.replaceChildren(...c)}revealSegment(e){const t=this.blocks.get(e);t&&(t.scrollIntoView?.({block:"center"}),t.classList.add("flash"),window.setTimeout(()=>t.classList.remove("flash"),1600))}}function J(){customElements.get(N)||customElements.define(N,L)}const F="rr0-interview-editor",$=`
29
+ `;class S extends HTMLElement{messages=E;said=new x(["en"]);localeToken=0;loadToken=0;json;loading;base;status=document.createElement("p");turns=document.createElement("div");blocks=new Map;constructor(){super(),this.status.className="rr0-interview-status",this.status.setAttribute("role","status"),this.turns.className="rr0-interview-turns"}static get observedAttributes(){return["src"]}attributeChangedCallback(e,t,i){e==="src"&&i!==t&&this.isConnected&&this.load()}connectedCallback(){S.styleRoot(this.getRootNode()),this.contains(this.turns)||this.replaceChildren(this.status,this.turns),this.loadLocale(),this.hasAttribute("src")&&this.json===void 0&&this.loading!==this.getAttribute("src")&&this.load()}get interview(){return this.json}set interview(e){this.loadToken++,this.json=e,this.draw()}set documentUrl(e){this.base=e}static styleRoot(e){const t=e instanceof ShadowRoot?e:document.head;if(t.querySelector("style[data-rr0-interview]"))return;const i=document.createElement("style");i.dataset.rr0Interview="",i.textContent=$,t.append(i)}async load(){const e=this.getAttribute("src"),t=++this.loadToken;if(this.loading=e??void 0,!e)return;const i=new URL(e,location.href).href;let s;try{s=await y.json(i)}catch{s=void 0}t===this.loadToken&&(this.base=i,this.json=s,this.draw())}async loadLocale(){const e=++this.localeToken,t=O.preferencesFor(this),i=R(t,j),s=i==="en"?E:await I(i);e===this.localeToken&&(this.said=new x(t),this.messages=s,this.draw())}speakerName(e,t){const i=v.speakerName(e,t),s=e.speakers?.[t]?.role;return i===s&&s in this.messages.roles?this.messages.roles[s]:i}seek(e){const t=this.json,i={sighting:e.sighting??v.sightingsOf(t)[0],at:e.at};this.dispatchEvent(new CustomEvent(M,{bubbles:!0,composed:!0,detail:i}));const s=this.getAttribute("player");if(!s)return;const c=this.getRootNode().getElementById?.(s);typeof c?.seekTo=="function"&&(c.scrollIntoView?.({block:"center",behavior:"smooth"}),c.seekTo(i.at,i.sighting))}gap(e,t){const i=document.createElement(t),s=document.createElement("span");s.className="bar";const r=`${this.messages.redacted} : ${this.said.read(e)??""}`;return s.dataset.tip=r,s.tabIndex=0,s.setAttribute("role","img"),s.setAttribute("aria-label",r),i.append(s),i}saidNodes(e){if(!/[<&]/.test(e))return[document.createTextNode(e)];const t=document.createElement("template");t.innerHTML=e;for(const i of t.content.querySelectorAll("*")){if(["SCRIPT","STYLE","IFRAME","OBJECT","EMBED"].includes(i.tagName)){i.remove();continue}for(const s of[...i.attributes])if(/^on/i.test(s.name)||/^\s*javascript:/i.test(s.value))i.removeAttribute(s.name);else if(["href","src"].includes(s.name))try{s.value=new URL(s.value,this.base??location.href).href}catch{}}return[...t.content.childNodes]}draw(){const e=this.messages,t=this.json;this.blocks.clear();const i=Array.isArray(t?.segments)?t.segments:[];if(!t||i.length===0){this.status.hidden=!0;const n=document.createElement("p");n.textContent=e.exchangesEmpty,this.turns.replaceChildren(n);return}const s=t.speakers??{},r=Object.keys(s);if(t.proofreading){const n=r.filter(h=>!["approved","covered"].includes(t.proofreading?.[h]?.status??""));this.status.textContent=n.length===0?e.proofreadAll:e.proofreadPending.replace("{names}",n.map(h=>this.speakerName(t,h)).join(", ")),this.status.hidden=!1}else this.status.hidden=!0;const c=[];let a,l=!1,m,o;i.forEach((n,h)=>{const k=n.redacted?JSON.stringify(n.redacted.reason):void 0;if(k!==void 0&&m?.reason===k){this.blocks.set(h,m.block),n.speaker!==o&&(o=void 0);return}const f=document.createElement("div");f.className="turn",f.dataset.segment=String(h);const w=document.createElement("div");w.className="who";const L=document.createElement("span");if(L.textContent=n.redacted?"":this.speakerName(t,n.speaker),n.start!==void 0&&(f.dataset.time=v.clock(n.start,!0)),o!==n.speaker&&(a=document.createElement("div"),a.className="intervention",a.style.setProperty("--speaker-hue",String((Math.max(0,r.indexOf(n.speaker))*67+210)%360)),c.push(a),l=!1),n.redacted||(l&&f.classList.add("goes-on"),l=!0),a.append(f),o=n.speaker,w.append(L),n.redacted){f.classList.add("is-redacted");const p=this.gap(n.redacted.reason,"p");p.className="redacted",m={block:f,reason:k},f.append(w,p)}else{const p=document.createElement("p");if(p.className="said",n.parts){let g="";for(const u of n.parts){const C="redacted"in u?"▮":v.plain(u.text);/[\p{L}\p{N}.,;:!?)»”…▮]$/u.test(g)&&/^[\p{L}\p{N}(«“▮]/u.test(C)&&p.append(" "),"redacted"in u?p.append(this.gap(u.redacted.reason,"span")):p.append(...this.saidNodes(u.text)),g=C}}else p.append(...this.saidNodes(n.text??""));m=void 0,f.append(w,p)}if(n.refs?.length){const p=document.createElement("div");p.className="refs";for(const g of n.refs){const u=document.createElement("button");u.type="button",u.className="ref",u.innerHTML=B.PLAY,u.append(v.clock(g.at,!0)),u.addEventListener("click",()=>this.seek(g)),p.append(u)}f.append(p)}this.blocks.set(h,f)}),this.turns.replaceChildren(...c)}revealSegment(e){const t=this.blocks.get(e);t&&(t.scrollIntoView?.({block:"center"}),t.classList.add("flash"),window.setTimeout(()=>t.classList.remove("flash"),1600))}}function J(){customElements.get(F)||customElements.define(F,S)}const N="rr0-interview-editor",V=`
30
30
  <style>
31
31
  :host { display: block; }
32
32
  /* The colours of the transcript's text editor (see SightingFileEditor): a key, a string, a number or a word, and a mistake. Dark mode redefines them. */
@@ -54,7 +54,7 @@ rr0-interview .turn .ref svg { width: 1.1em; height: 1.1em; }
54
54
  input[type="text"] { min-width: 0; }
55
55
  #by { width: 16em; }
56
56
  input[type="url"] { width: 18em; max-width: 100%; }
57
- ${P.CSS}
57
+ ${H.CSS}
58
58
  select { min-width: 0; max-width: 100%; text-overflow: ellipsis; }
59
59
  fieldset.witnesses { display: flex; flex-wrap: wrap; align-items: center; gap: .25em .75em; border: 0; margin: 0; padding: 0; min-width: 0; }
60
60
  fieldset.witnesses legend { float: left; padding: 0; margin-right: .4em; }
@@ -90,13 +90,11 @@ rr0-interview .turn .ref svg { width: 1.1em; height: 1.1em; }
90
90
  <label class="fill"><span id="label-url">Transcript</span> <input id="url" type="text" autocomplete="off" spellcheck="false" placeholder="interview-….json"/></label>
91
91
  </div>
92
92
  <div class="row toolbar">
93
- <label><span id="label-import-file">Load JSON file</span> <input id="import-file" type="file" accept="application/json,.json,.txt,.md,.vtt,.srt,text/*"/></label>
94
- <label><span id="label-import-url">Or load from URL</span> <input id="import-url" type="url" placeholder="https://…/interview.json"/></label>
95
- <button id="import-url-button" type="button">Load</button>
93
+ <span class="input-file-row"><span id="label-import-file">Load a file (JSON, text, WebVTT, SRT)</span> <rr0-input-file id="import" name="import" accept="application/json,.json,.txt,.md,.vtt,.srt,text/*" placeholder="https://…/interview.json"></rr0-input-file></span>
96
94
  <button id="save" type="button">Save</button>
97
95
  </div>
98
96
  <p id="file-note" class="file-note" hidden role="status"></p>
99
97
  <div id="file-editor" class="file-editor"></div>
100
98
  </section>
101
- `;class d extends HTMLElement{shadow=this.attachShadow({mode:"open"});messages=k;said=new x(["en"]);language="en";localeToken=0;current;options=[];group="summary";base;text;fileEditor;fileEditorLoading;shownFor;constructor(){super(),this.shadow.innerHTML=$;for(const e of["title","time","by","url","summary","witness","medium"])this.shadow.getElementById(e).addEventListener(e==="witness"||e==="medium"?"change":"input",()=>this.write(e));for(const e of this.shadow.querySelectorAll("#tabs .group-tab"))e.addEventListener("click",()=>this.openGroup(d.GROUPS[e.getAttribute("aria-controls")]??"summary"));this.shadow.getElementById("url").addEventListener("change",()=>{this.shownFor=void 0,this.text===void 0&&this.group==="file"&&this.showTranscript()}),this.shadow.getElementById("import-file").addEventListener("change",()=>void this.importFromFile()),this.shadow.getElementById("import-url-button").addEventListener("click",()=>void this.importFromUrl()),this.shadow.getElementById("save").addEventListener("click",()=>this.save())}static GROUPS={"group-summary":"summary","group-exchanges":"exchanges","group-transcript":"file"};static get observedAttributes(){return["readonly"]}attributeChangedCallback(){this.applyReadonly()}connectedCallback(){this.loadLocale()}get event(){return this.current}set event(e){e!==this.current&&(this.shownFor=void 0),this.current=e,this.render(),this.group==="file"&&this.showTranscript(),this.group==="exchanges"&&this.showExchanges()}set witnesses(e){this.options=e,this.render()}set documentUrl(e){this.base=e}get transcriptText(){return this.text}set transcriptText(e){this.text=e,this.shownFor=void 0}field(e){return this.shadow.getElementById(e)}async loadLocale(){const e=++this.localeToken,t=O.preferencesFor(this),i=R(t,j),s=i==="en"?k:await I(i);e===this.localeToken&&(this.language=i,this.said=new x(t),this.messages=s,this.render())}applyReadonly(){const e=this.hasAttribute("readonly");for(const t of["title","time","by","url","summary"])this.field(t).readOnly=e;for(const t of this.shadow.querySelectorAll("#witness input"))t.disabled=e;this.field("medium").disabled=e;for(const t of["import-file","import-url","import-url-button"])this.field(t).disabled=e}static byText(e){return(e??[]).map(t=>"people"in t?t.people:"org"in t?t.org:t.title??"").filter(t=>t!=="").join(", ")}render(){const e=this.messages,t=(o,n)=>{this.shadow.getElementById(o).textContent=n};t("label-summary-group",e.summaryTab),t("label-file-group",e.fileTab),t("label-exchanges-group",e.exchangesTab),t("label-title",e.title),t("label-witness",e.witness),t("label-medium",e.medium),t("label-time",e.time),t("label-by",e.by),t("label-summary",e.summary),t("label-url",e.transcript),t("label-import-file",e.importFile),t("label-import-url",e.importUrl),t("import-url-button",e.importButton),t("save",e.saveButton),this.field("url").title=e.transcriptHint,this.field("by").title=e.byHint;const i=this.current,s=this.shadow.activeElement,r=(o,n)=>{this.field(o)!==s&&(this.field(o).value=n)};r("title",this.said.read(i?.title)??""),r("time",i?.time??""),r("by",d.byText(i?.by)),r("url",i?.url??""),r("summary",this.said.read(i?.summary)??"");const c=[i?.interviewOf].flat().filter(o=>typeof o=="string"),a=this.shadow.getElementById("witness"),p=[...this.options,...c.filter(o=>!this.options.some(n=>n.id===o)).map(o=>({id:o,label:o}))];a.replaceChildren(a.querySelector("legend"),...p.map(o=>{const n=document.createElement("label"),h=document.createElement("input");return h.type="checkbox",h.value=o.id,h.checked=c.includes(o.id),n.append(h,o.label),n}));const l=this.shadow.getElementById("medium");if(l.replaceChildren(...A.ALL.map(o=>new Option(A.label(o,this.language),o))),i?.medium!==void 0&&!A.ALL.includes(i.medium)&&l.append(new Option(String(i.medium),String(i.medium))),i?.medium===void 0){const o=new Option(e.witnessNone,"");o.disabled=!0,o.hidden=!0,l.prepend(o)}l.value=i?.medium??"",this.applyReadonly()}write(e){const t=this.current;if(!t)return;const i=e==="witness"?"":this.field(e).value;switch(e){case"title":{const s=this.said.write(t.title,i,this.language);s===void 0?delete t.title:t.title=s;break}case"summary":{const s=this.said.write(t.summary,i,this.language);s===void 0?delete t.summary:t.summary=s;break}case"time":i.trim()===""?delete t.time:t.time=i.trim();break;case"url":i.trim()===""?delete t.url:t.url=i.trim();break;case"by":{const s=i.split(",").map(r=>r.trim()).filter(r=>r!=="");s.length===0?delete t.by:t.by=s.map(r=>({people:r}));break}case"witness":{const s=[...this.shadow.querySelectorAll("#witness input:checked")].map(r=>r.value);if(s.length===0){this.render();return}t.interviewOf=s.length===1?s[0]:s;break}case"medium":i===""?delete t.medium:t.medium=i;break}this.dispatchEvent(new CustomEvent(g,{bubbles:!0,composed:!0,detail:{field:e,event:t}})),e==="medium"&&this.render(),e!=="url"&&this.syncFileFromEvent()}openGroup(e){this.group=e;const t={summary:"group-summary",exchanges:"group-exchanges",file:"group-transcript"};for(const i of this.shadow.querySelectorAll("#tabs .group-tab"))i.setAttribute("aria-expanded",String(i.getAttribute("aria-controls")===t[e]));for(const[i,s]of Object.entries(t))this.shadow.getElementById(s).hidden=i!==e;e==="file"&&this.showTranscript(),e==="exchanges"&&this.showExchanges()}exchangesToken=0;async transcriptJson(e){try{const t=this.fileEditor?.text??this.text;if(t!==void 0)return JSON.parse(t);const i=this.transcriptUrl(e);if(i!==void 0)return await y.json(i)}catch{}}async showExchanges(){const e=this.current;if(!e)return;const t=++this.exchangesToken,i=await this.transcriptJson(e);t!==this.exchangesToken||this.current!==e||this.drawExchanges(i)}drawExchanges(e){const t=this.shadow.getElementById("exchanges");t.documentUrl=this.current?this.transcriptUrl(this.current):void 0,t.interview=e}async revealSegment(e){this.openGroup("exchanges"),await this.showExchanges(),this.shadow.getElementById("exchanges").revealSegment(e)}note(e,t="info"){U.show(this.shadow.getElementById("file-note"),e,t)}transcriptUrl(e){return e.url?new URL(e.url,this.base??location.href).href:void 0}static pretty(e){return JSON.stringify(e,null,2)+`
102
- `}static SHARED=["title","time","medium","by","interviewOf","summary"];static ORDER=["version","id","language","title","time","medium","by","interviewOf","summary","speakers","transcription","proofreading","anonymization","segments"];static ordered(e){const t={};for(const i of d.ORDER)i in e&&(t[i]=e[i]);for(const i of Object.keys(e))i in t||(t[i]=e[i]);return t}static witnessesOf(e){return[e].flat().filter(t=>typeof t=="string")}static withEventFields(e,t){const i={...e};for(const r of d.SHARED)t[r]===void 0?delete i[r]:i[r]=structuredClone(t[r]);const s=i.speakers;if(typeof s=="object"&&s!==null){const r={...s},c=(a,p,l)=>{l.forEach((o,n)=>{const h=n===0?a:`${a}${n+1}`;r[h]?r[h]={...r[h],[p]:o}:n>0&&(r[h]={role:a,[p]:o})})};c("interviewer","by",t.by??[]),c("witness","of",d.witnessesOf(t.interviewOf)),i.speakers=r}return d.ordered(i)}applyFileToEvent(e,t){const i=this.current;if(!i)return!1;const s=JSON.stringify(d.SHARED.map(a=>i[a])),r=a=>typeof a=="string"||typeof a=="object"&&a!==null&&!Array.isArray(a),c={title:r,summary:r,time:a=>typeof a=="string",medium:a=>typeof a=="string",by:a=>Array.isArray(a),interviewOf:a=>typeof a=="string"||Array.isArray(a)};for(const a of d.SHARED){const p=e[a];p!==void 0&&c[a](p)?i[a]=structuredClone(p):t&&delete i[a]}return JSON.stringify(d.SHARED.map(a=>i[a]))!==s}syncFileFromEvent(){const e=this.current,t=this.fileEditor?.text??this.text;if(!e||t===void 0)return;let i;try{i=JSON.parse(t)}catch{return}if(typeof i!="object"||i===null||Array.isArray(i))return;const s=d.pretty(d.withEventFields(i,e));s!==t&&(this.text=s,this.fileEditor?.replaceText(s,!1),this.dispatchEvent(new CustomEvent(g,{bubbles:!0,composed:!0,detail:{field:"transcript",event:e,text:s}})))}template(e){return d.pretty(d.withEventFields({version:1,language:this.language,speakers:{interviewer:{role:"interviewer"},witness:{role:"witness"}},segments:[]},e))}loadFileEditor(e){return this.fileEditorLoading??=(async()=>{try{const[{SightingFileEditor:t},{default:i},s]=await Promise.all([T(()=>import("./SightingFileEditor-7inIgp24.js"),__vite__mapDeps([0,1]),import.meta.url),T(()=>import("./interviewSchema-m_h5f8H0.js"),[],import.meta.url),H(this.language)]);return this.fileEditor=new t(this.shadow.getElementById("file-editor"),e,r=>this.onEdited(r),this.messages.editorLabel,{baseline:e,phrases:s.fileSearchPhrases,schema:i}),this.fileEditor}catch(t){throw this.fileEditorLoading=void 0,t}})(),this.fileEditorLoading}async showTranscript(){const e=this.current;if(!e||this.shownFor===e)return;this.note(this.messages.loading);let t=this.text;if(t===void 0){const i=this.transcriptUrl(e);if(i!==void 0)try{const s=await y.json(i);this.current===e&&typeof s=="object"&&s!==null&&!Array.isArray(s)?(this.applyFileToEvent(s,!1)&&this.fileChangedEvent(),t=d.pretty(d.withEventFields(s,e))):t=d.pretty(s)}catch{this.note(this.messages.loadFailed,"error")}t??=this.template(e)}if(this.current===e)try{const i=await this.loadFileEditor(t);if(this.current!==e)return;i.replaceText(t,!1),this.shownFor=e,this.text!==void 0||this.transcriptUrl(e)===void 0?this.note(void 0):this.shadow.getElementById("file-note").textContent===this.messages.loading&&this.note(void 0)}catch{this.note(this.messages.loadFailed,"error")}}onEdited(e){this.text=e;let t,i=!0;try{t=JSON.parse(e)}catch{i=!1}this.note(i?void 0:this.messages.invalid,"error");const s=this.current;if(i&&s&&typeof t=="object"&&t!==null&&!Array.isArray(t)&&this.applyFileToEvent(t,!0)&&this.fileChangedEvent(),s&&!s.url&&e.trim()!==""){const r=s.id??"1";s.url=`${r.startsWith("interview")?r:`interview-${r}`}.json`,this.field("url").value=s.url,this.dispatchEvent(new CustomEvent(g,{bubbles:!0,composed:!0,detail:{field:"url",event:s}}))}this.dispatchEvent(new CustomEvent(g,{bubbles:!0,composed:!0,detail:{field:"transcript",event:s,text:e}})),this.group==="exchanges"&&this.showExchanges()}fileChangedEvent(){this.render(),this.dispatchEvent(new CustomEvent(g,{bubbles:!0,composed:!0,detail:{field:"file",event:this.current}}))}async take(e){if(typeof e!="object"||e===null||!Array.isArray(e.segments)){this.note(this.messages.notATranscript,"error");return}const t=this.current;t&&this.applyFileToEvent(e,!1)&&this.fileChangedEvent();const i=d.pretty(t?d.withEventFields(e,t):e);await this.loadFileEditor(i).then(s=>s.replaceText(i,!1),()=>{}),this.shownFor=this.current,this.note(void 0),this.onEdited(i)}async importFromFile(){const e=this.field("import-file"),t=e.files?.[0];if(t){try{const i=await t.text();let s;try{s=JSON.parse(i)}catch{s=void 0}if(typeof s!="object"||s===null){const{InterviewImport:r}=await T(async()=>{const{InterviewImport:l}=await import("./interviewImport-C-TiARLK.js");return{InterviewImport:l}},[],import.meta.url),c=this.current,a=[c?.interviewOf].flat().filter(l=>typeof l=="string"),p=r.parse(i,{by:(c?.by??[]).map(l=>d.byText([l])).filter(l=>l!==""),witnesses:this.options.filter(l=>a.length===0||a.includes(l.id))});s=p&&{...p,transcription:{note:`Imported from ${t.name}: who speaks and when are as the file gave them, to be checked.`}}}s===void 0?this.note(this.messages.notATranscript,"error"):await this.take(s)}catch{this.note(this.messages.loadFailed,"error")}e.value=""}}async importFromUrl(){const e=this.field("import-url").value.trim();if(e!=="")try{await this.take(await y.json(new URL(e,this.base??location.href).href))}catch{this.note(this.messages.loadFailed,"error")}}save(){const e=this.fileEditor?.text??this.text;if(e===void 0)return;const t=(this.current?.url??"").split("/").pop()||`${this.current?.id??"interview"}.json`,i=URL.createObjectURL(new Blob([e],{type:"application/json"})),s=document.createElement("a");s.href=i,s.download=t,s.click(),URL.revokeObjectURL(i)}}function W(){J(),customElements.get(F)||customElements.define(F,d)}export{g as INTERVIEW_CHANGE_EVENT,F as INTERVIEW_EDITOR_ELEMENT_NAME,B as INTERVIEW_SEEK_EVENT,d as InterviewEditorElement,W as register};
99
+ `;class d extends HTMLElement{shadow=this.attachShadow({mode:"open"});get importInput(){return this.shadow.getElementById("import")}messages=E;said=new x(["en"]);language="en";localeToken=0;current;options=[];group="summary";base;text;fileEditor;fileEditorLoading;shownFor;constructor(){super(),this.shadow.innerHTML=V,customElements.upgrade(this.shadow),this.importInput.build();for(const e of["title","time","by","url","summary","witness","medium"])this.shadow.getElementById(e).addEventListener(e==="witness"||e==="medium"?"change":"input",()=>this.write(e));for(const e of this.shadow.querySelectorAll("#tabs .group-tab"))e.addEventListener("click",()=>this.openGroup(d.GROUPS[e.getAttribute("aria-controls")]??"summary"));this.shadow.getElementById("url").addEventListener("change",()=>{this.shownFor=void 0,this.text===void 0&&this.group==="file"&&this.showTranscript()}),this.importInput.addEventListener("filepick",e=>{const t=e.detail;t.file?this.importFromFile(t.file):this.importFromUrl(t.url)}),this.shadow.getElementById("save").addEventListener("click",()=>this.save())}static GROUPS={"group-summary":"summary","group-exchanges":"exchanges","group-transcript":"file"};static get observedAttributes(){return["readonly"]}attributeChangedCallback(){this.applyReadonly()}connectedCallback(){this.loadLocale()}disconnectedCallback(){queueMicrotask(()=>{this.isConnected||this.releaseFileEditor()})}releaseFileEditor(){this.fileEditor&&(this.text=this.fileEditor.text,this.fileEditor.destroy(),this.fileEditor=void 0,this.fileEditorLoading=void 0,this.shownFor=void 0)}get event(){return this.current}set event(e){e!==this.current&&(this.shownFor=void 0),this.current=e,this.render(),this.group==="file"&&this.showTranscript(),this.group==="exchanges"&&this.showExchanges()}set witnesses(e){this.options=e,this.render()}set documentUrl(e){this.base=e}get transcriptText(){return this.text}set transcriptText(e){this.text=e,this.shownFor=void 0}field(e){return this.shadow.getElementById(e)}async loadLocale(){const e=++this.localeToken,t=O.preferencesFor(this),i=R(t,j),s=i==="en"?E:await I(i);e===this.localeToken&&(this.language=i,this.said=new x(t),this.messages=s,this.render())}applyReadonly(){const e=this.hasAttribute("readonly");for(const t of["title","time","by","url","summary"])this.field(t).readOnly=e;for(const t of this.shadow.querySelectorAll("#witness input"))t.disabled=e;this.field("medium").disabled=e,this.importInput.disabled=e}static byText(e){return(e??[]).map(t=>"people"in t?t.people:"org"in t?t.org:t.title??"").filter(t=>t!=="").join(", ")}render(){const e=this.messages,t=(o,n)=>{this.shadow.getElementById(o).textContent=n};t("label-summary-group",e.summaryTab),t("label-file-group",e.fileTab),t("label-exchanges-group",e.exchangesTab),t("label-title",e.title),t("label-witness",e.witness),t("label-medium",e.medium),t("label-time",e.time),t("label-by",e.by),t("label-summary",e.summary),t("label-url",e.transcript),t("label-import-file",e.importFile),this.importInput.messages=e,t("save",e.saveButton),this.field("url").title=e.transcriptHint,this.field("by").title=e.byHint;const i=this.current,s=this.shadow.activeElement,r=(o,n)=>{this.field(o)!==s&&(this.field(o).value=n)};r("title",this.said.read(i?.title)??""),r("time",i?.time??""),r("by",d.byText(i?.by)),r("url",i?.url??""),r("summary",this.said.read(i?.summary)??"");const c=[i?.interviewOf].flat().filter(o=>typeof o=="string"),a=this.shadow.getElementById("witness"),l=[...this.options,...c.filter(o=>!this.options.some(n=>n.id===o)).map(o=>({id:o,label:o}))];a.replaceChildren(a.querySelector("legend"),...l.map(o=>{const n=document.createElement("label"),h=document.createElement("input");return h.type="checkbox",h.value=o.id,h.checked=c.includes(o.id),n.append(h,o.label),n}));const m=this.shadow.getElementById("medium");if(m.replaceChildren(...A.ALL.map(o=>new Option(A.label(o,this.language),o))),i?.medium!==void 0&&!A.ALL.includes(i.medium)&&m.append(new Option(String(i.medium),String(i.medium))),i?.medium===void 0){const o=new Option(e.witnessNone,"");o.disabled=!0,o.hidden=!0,m.prepend(o)}m.value=i?.medium??"",this.applyReadonly()}write(e){const t=this.current;if(!t)return;const i=e==="witness"?"":this.field(e).value;switch(e){case"title":{const s=this.said.write(t.title,i,this.language);s===void 0?delete t.title:t.title=s;break}case"summary":{const s=this.said.write(t.summary,i,this.language);s===void 0?delete t.summary:t.summary=s;break}case"time":i.trim()===""?delete t.time:t.time=i.trim();break;case"url":i.trim()===""?delete t.url:t.url=i.trim();break;case"by":{const s=i.split(",").map(r=>r.trim()).filter(r=>r!=="");s.length===0?delete t.by:t.by=s.map(r=>({people:r}));break}case"witness":{const s=[...this.shadow.querySelectorAll("#witness input:checked")].map(r=>r.value);if(s.length===0){this.render();return}t.interviewOf=s.length===1?s[0]:s;break}case"medium":i===""?delete t.medium:t.medium=i;break}this.dispatchEvent(new CustomEvent(b,{bubbles:!0,composed:!0,detail:{field:e,event:t}})),e==="medium"&&this.render(),e!=="url"&&this.syncFileFromEvent()}openGroup(e){this.group=e;const t={summary:"group-summary",exchanges:"group-exchanges",file:"group-transcript"};for(const i of this.shadow.querySelectorAll("#tabs .group-tab"))i.setAttribute("aria-expanded",String(i.getAttribute("aria-controls")===t[e]));for(const[i,s]of Object.entries(t))this.shadow.getElementById(s).hidden=i!==e;e==="file"&&this.showTranscript(),e==="exchanges"&&this.showExchanges()}exchangesToken=0;async transcriptJson(e){try{const t=this.fileEditor?.text??this.text;if(t!==void 0)return JSON.parse(t);const i=this.transcriptUrl(e);if(i!==void 0)return await y.json(i)}catch{}}async showExchanges(){const e=this.current;if(!e)return;const t=++this.exchangesToken,i=await this.transcriptJson(e);t!==this.exchangesToken||this.current!==e||this.drawExchanges(i)}drawExchanges(e){const t=this.shadow.getElementById("exchanges");t.documentUrl=this.current?this.transcriptUrl(this.current):void 0,t.interview=e}async revealSegment(e){this.openGroup("exchanges"),await this.showExchanges(),this.shadow.getElementById("exchanges").revealSegment(e)}note(e,t="info"){U.show(this.shadow.getElementById("file-note"),e,t)}transcriptUrl(e){return e.url?new URL(e.url,this.base??location.href).href:void 0}static pretty(e){return JSON.stringify(e,null,2)+`
100
+ `}static SHARED=["title","time","medium","by","interviewOf","summary"];static ORDER=["version","id","language","title","time","medium","by","interviewOf","summary","speakers","transcription","proofreading","anonymization","segments"];static ordered(e){const t={};for(const i of d.ORDER)i in e&&(t[i]=e[i]);for(const i of Object.keys(e))i in t||(t[i]=e[i]);return t}static witnessesOf(e){return[e].flat().filter(t=>typeof t=="string")}static withEventFields(e,t){const i={...e};for(const r of d.SHARED)t[r]===void 0?delete i[r]:i[r]=structuredClone(t[r]);const s=i.speakers;if(typeof s=="object"&&s!==null){const r={...s},c=(a,l,m)=>{m.forEach((o,n)=>{const h=n===0?a:`${a}${n+1}`;r[h]?r[h]={...r[h],[l]:o}:n>0&&(r[h]={role:a,[l]:o})})};c("interviewer","by",t.by??[]),c("witness","of",d.witnessesOf(t.interviewOf)),i.speakers=r}return d.ordered(i)}applyFileToEvent(e,t){const i=this.current;if(!i)return!1;const s=JSON.stringify(d.SHARED.map(a=>i[a])),r=a=>typeof a=="string"||typeof a=="object"&&a!==null&&!Array.isArray(a),c={title:r,summary:r,time:a=>typeof a=="string",medium:a=>typeof a=="string",by:a=>Array.isArray(a),interviewOf:a=>typeof a=="string"||Array.isArray(a)};for(const a of d.SHARED){const l=e[a];l!==void 0&&c[a](l)?i[a]=structuredClone(l):t&&delete i[a]}return JSON.stringify(d.SHARED.map(a=>i[a]))!==s}syncFileFromEvent(){const e=this.current,t=this.fileEditor?.text??this.text;if(!e||t===void 0)return;let i;try{i=JSON.parse(t)}catch{return}if(typeof i!="object"||i===null||Array.isArray(i))return;const s=d.pretty(d.withEventFields(i,e));s!==t&&(this.text=s,this.fileEditor?.replaceText(s,!1),this.dispatchEvent(new CustomEvent(b,{bubbles:!0,composed:!0,detail:{field:"transcript",event:e,text:s}})))}template(e){return d.pretty(d.withEventFields({version:1,language:this.language,speakers:{interviewer:{role:"interviewer"},witness:{role:"witness"}},segments:[]},e))}loadFileEditor(e){return this.fileEditorLoading??=(async()=>{try{const[{SightingFileEditor:t},{default:i},s]=await Promise.all([T(()=>import("./SightingFileEditor-CEjimNPM.js"),__vite__mapDeps([0,1]),import.meta.url),T(()=>import("./interviewSchema-m_h5f8H0.js"),[],import.meta.url),D(this.language)]);return this.fileEditor=new t(this.shadow.getElementById("file-editor"),e,r=>this.onEdited(r),this.messages.editorLabel,{baseline:e,phrases:s.fileSearchPhrases,schema:i}),this.fileEditor}catch(t){throw this.fileEditorLoading=void 0,t}})(),this.fileEditorLoading}async showTranscript(){const e=this.current;if(!e||this.shownFor===e)return;this.note(this.messages.loading);let t=this.text;if(t===void 0){const i=this.transcriptUrl(e);if(i!==void 0)try{const s=await y.json(i);this.current===e&&typeof s=="object"&&s!==null&&!Array.isArray(s)?(this.applyFileToEvent(s,!1)&&this.fileChangedEvent(),t=d.pretty(d.withEventFields(s,e))):t=d.pretty(s)}catch{this.note(this.messages.loadFailed,"error")}t??=this.template(e)}if(this.current===e)try{const i=await this.loadFileEditor(t);if(this.current!==e)return;i.replaceText(t,!1),this.shownFor=e,this.text!==void 0||this.transcriptUrl(e)===void 0?this.note(void 0):this.shadow.getElementById("file-note").textContent===this.messages.loading&&this.note(void 0)}catch{this.note(this.messages.loadFailed,"error")}}onEdited(e){this.text=e;let t,i=!0;try{t=JSON.parse(e)}catch{i=!1}this.note(i?void 0:this.messages.invalid,"error");const s=this.current;if(i&&s&&typeof t=="object"&&t!==null&&!Array.isArray(t)&&this.applyFileToEvent(t,!0)&&this.fileChangedEvent(),s&&!s.url&&e.trim()!==""){const r=s.id??"1";s.url=`${r.startsWith("interview")?r:`interview-${r}`}.json`,this.field("url").value=s.url,this.dispatchEvent(new CustomEvent(b,{bubbles:!0,composed:!0,detail:{field:"url",event:s}}))}this.dispatchEvent(new CustomEvent(b,{bubbles:!0,composed:!0,detail:{field:"transcript",event:s,text:e}})),this.group==="exchanges"&&this.showExchanges()}fileChangedEvent(){this.render(),this.dispatchEvent(new CustomEvent(b,{bubbles:!0,composed:!0,detail:{field:"file",event:this.current}}))}async take(e){if(typeof e!="object"||e===null||!Array.isArray(e.segments)){this.note(this.messages.notATranscript,"error");return}const t=this.current;t&&this.applyFileToEvent(e,!1)&&this.fileChangedEvent();const i=d.pretty(t?d.withEventFields(e,t):e);await this.loadFileEditor(i).then(s=>s.replaceText(i,!1),()=>{}),this.shownFor=this.current,this.note(void 0),this.onEdited(i)}async importFromFile(e){try{const t=await e.text();let i;try{i=JSON.parse(t)}catch{i=void 0}if(typeof i!="object"||i===null){const{InterviewImport:s}=await T(async()=>{const{InterviewImport:l}=await import("./interviewImport-C-TiARLK.js");return{InterviewImport:l}},[],import.meta.url),r=this.current,c=[r?.interviewOf].flat().filter(l=>typeof l=="string"),a=s.parse(t,{by:(r?.by??[]).map(l=>d.byText([l])).filter(l=>l!==""),witnesses:this.options.filter(l=>c.length===0||c.includes(l.id))});i=a&&{...a,transcription:{note:`Imported from ${e.name}: who speaks and when are as the file gave them, to be checked.`}}}i===void 0?this.note(this.messages.notATranscript,"error"):await this.take(i)}catch{this.note(this.messages.loadFailed,"error")}}async importFromUrl(e){try{await this.take(await y.json(new URL(e,this.base??location.href).href))}catch{this.note(this.messages.loadFailed,"error")}}save(){const e=this.fileEditor?.text??this.text;if(e===void 0)return;const t=(this.current?.url??"").split("/").pop()||`${this.current?.id??"interview"}.json`,i=URL.createObjectURL(new Blob([e],{type:"application/json"})),s=document.createElement("a");s.href=i,s.download=t,s.click(),URL.revokeObjectURL(i)}}function G(){J(),P(),customElements.get(N)||customElements.define(N,d)}export{b as INTERVIEW_CHANGE_EVENT,N as INTERVIEW_EDITOR_ELEMENT_NAME,M as INTERVIEW_SEEK_EVENT,d as InterviewEditorElement,G as register};
@@ -0,0 +1 @@
1
+ const e={title:"Title",time:"When",by:"Interviewer",medium:"Medium",witness:"Witness",witnessNone:"—",summary:"Description",transcript:"Transcript",transcriptHint:"Address of the anonymised transcript file (optional)",summaryTab:"Summary",fileTab:"File",importFile:"Load a file (JSON, text, WebVTT, SRT)",inputFileFromFile:"from your disk",inputFileFromUrl:"from an address",inputFileModeHint:"Click to give it the other way: a file of yours, or an address",inputFileLoad:"Load",saveButton:"Save",loading:"Loading the transcript…",invalid:"This text is not valid JSON yet: the interview keeps the last transcript it understood.",notATranscript:"That file is not an interview transcript (it has no segments).",loadFailed:"That transcript could not be read.",editorLabel:"Interview transcript as JSON",byHint:"RR0 people ids, separated by commas",exchangesTab:"Exchanges",exchangesEmpty:"Nothing was said yet.",redacted:"Passage removed",proofreadAll:"Proofread by everyone.",proofreadPending:"Not proofread yet by: {names}",roles:{interviewer:"Interviewer",interviewee:"Interviewee",witness:"Witness"}};export{e as interviewMessages_en};
@@ -0,0 +1 @@
1
+ const e={title:"Título",time:"Fecha",by:"Entrevistador",medium:"Medio",witness:"Testigo",witnessNone:"—",summary:"Descripción",transcript:"Transcripción",transcriptHint:"Dirección del archivo de transcripción anonimizada (opcional)",summaryTab:"Resumen",fileTab:"Archivo",importFile:"Cargar un archivo (JSON, texto, WebVTT, SRT)",inputFileFromFile:"desde su disco",inputFileFromUrl:"desde una dirección",inputFileModeHint:"Pulsar para darlo de la otra forma: un archivo suyo o una dirección",inputFileLoad:"Cargar",saveButton:"Guardar",loading:"Cargando la transcripción…",invalid:"Este texto aún no es JSON válido: la entrevista conserva la última transcripción que entendió.",notATranscript:"Ese archivo no es una transcripción de entrevista (no tiene turnos de palabra).",loadFailed:"No se pudo leer esa transcripción.",editorLabel:"Transcripción de la entrevista en JSON",byHint:"Identificadores de personas de RR0, separados por comas",exchangesTab:"Intercambios",exchangesEmpty:"Todavía no se ha dicho nada.",redacted:"Pasaje eliminado",proofreadAll:"Revisado por todos.",proofreadPending:"Aún no revisado por: {names}",roles:{interviewer:"Entrevistador",interviewee:"Entrevistado",witness:"Testigo"}};export{e as interviewMessages_es};
@@ -0,0 +1 @@
1
+ const e={title:"Titre",time:"Date",by:"Enquêteur",medium:"Moyen",witness:"Témoin",witnessNone:"—",summary:"Description",transcript:"Transcription",transcriptHint:"Adresse du fichier de transcription anonymisée (facultative)",summaryTab:"Résumé",fileTab:"Fichier",importFile:"Charger un fichier (JSON, texte, WebVTT, SRT)",inputFileFromFile:"depuis votre disque",inputFileFromUrl:"depuis une adresse",inputFileModeHint:"Cliquer pour le donner autrement : un fichier à vous, ou une adresse",inputFileLoad:"Charger",saveButton:"Sauver",loading:"Chargement de la transcription…",invalid:"Ce texte n'est pas encore du JSON valide : l'interview garde la dernière transcription qu'elle a comprise.",notATranscript:"Ce fichier n'est pas une transcription d'interview (il n'a pas de tours de parole).",loadFailed:"Cette transcription n'a pas pu être lue.",editorLabel:"Transcription de l'interview en JSON",byHint:"Identifiants de personnes RR0, séparés par des virgules",exchangesTab:"Échanges",exchangesEmpty:"Rien n'a encore été dit.",redacted:"Passage retiré",proofreadAll:"Relu par tous les participants.",proofreadPending:"Pas encore relu par : {names}",roles:{interviewer:"Intervieweur",interviewee:"Interviewé",witness:"Témoin"}};export{e as interviewMessages_fr};
@@ -0,0 +1 @@
1
+ const i={title:"Titolo",time:"Data",by:"Intervistatore",medium:"Mezzo",witness:"Testimone",witnessNone:"—",summary:"Descrizione",transcript:"Trascrizione",transcriptHint:"Indirizzo del file di trascrizione anonimizzata (facoltativo)",summaryTab:"Riepilogo",fileTab:"File",importFile:"Carica un file (JSON, testo, WebVTT, SRT)",inputFileFromFile:"dal proprio disco",inputFileFromUrl:"da un indirizzo",inputFileModeHint:"Fare clic per darlo nell'altro modo: un proprio file o un indirizzo",inputFileLoad:"Carica",saveButton:"Salva",loading:"Caricamento della trascrizione…",invalid:"Questo testo non è ancora JSON valido: l'intervista conserva l'ultima trascrizione che ha capito.",notATranscript:"Quel file non è una trascrizione di intervista (non ha turni di parola).",loadFailed:"Impossibile leggere quella trascrizione.",editorLabel:"Trascrizione dell'intervista in JSON",byHint:"Identificatori di persone RR0, separati da virgole",exchangesTab:"Scambi",exchangesEmpty:"Non è stato ancora detto nulla.",redacted:"Passaggio rimosso",proofreadAll:"Rivisto da tutti.",proofreadPending:"Non ancora rivisto da: {names}",roles:{interviewer:"Intervistatore",interviewee:"Intervistato",witness:"Testimone"}};export{i as interviewMessages_it};
@@ -1,4 +1,4 @@
1
- import{L as h,n as r,U as p,o as m,k as c,E as u,m as g}from"./rr0-sighting-editor.mjs";import{launchEditorMessages_en as d}from"./LaunchEditorMessages_en-j4RgQPZu.js";class n{static plumeValue(e){return t=>h.plumeOf(t)[e]}static plume(e,t){return{type:"number",key:`plume.${e}`,effective:n.plumeValue(e),...t}}static burn(e,t){return{type:"number",key:e,min:-3600,max:36e3,step:.1,unit:"s",scale:.001,label:t.label,hint:t.hint,group:{en:"Engine",fr:"Moteur",es:"Motor",it:"Motore"},effective:i=>t.ends(i.track??[])?.t}}static nextPlace(e){const t=e[e.length-1]??{t:0,lat:0,lng:0,altitudeKm:0},i=e[e.length-2]??t,a=(s,l=0)=>e.length>1?t[s]-i[s]:l;return{t:t.t+(e.length>1?a("t"):1e4),lat:t.lat+a("lat"),lng:t.lng+a("lng"),altitudeKm:Math.max(0,t.altitudeKm+a("altitudeKm"))}}static SET={kind:"launch",title:{en:"Launch",fr:"Lancement",es:"Lanzamiento",it:"Lancio"},parameters:[{type:"said",key:"title",label:{en:"Name",fr:"Nom",es:"Nombre",it:"Nome"},group:{en:"Vehicle",fr:"Lanceur",es:"Lanzador",it:"Lanciatore"}},{type:"text",key:"vehicle.name",label:{en:"Vehicle",fr:"Lanceur",es:"Lanzador",it:"Lanciatore"},placeholder:"Falcon 9",group:{en:"Vehicle",fr:"Lanceur",es:"Lanzador",it:"Lanciatore"}},{type:"text",key:"vehicle.mission",label:{en:"Mission",fr:"Mission",es:"Misión",it:"Missione"},placeholder:"Starlink Group 10-49",group:{en:"Vehicle",fr:"Lanceur",es:"Lanzador",it:"Lanciatore"}},{type:"number",key:"vehicle.engine.thrustKN",min:1,max:1e5,step:1,unit:"kN",label:{en:"Thrust (vacuum)",fr:"Poussée (dans le vide)",es:"Empuje (en el vacío)",it:"Spinta (nel vuoto)"},hint:{en:"Merlin Vacuum 934, RL10 110, a solid booster several thousand. With the specific impulse, it sets how much exhaust leaves each second.",fr:"Merlin Vacuum 934, RL10 110, un booster à poudre plusieurs milliers. Avec l'impulsion spécifique, elle fixe le débit d'échappement.",es:"Merlin Vacuum 934, RL10 110, un propulsor sólido varios miles. Con el impulso específico, fija el caudal de escape.",it:"Merlin Vacuum 934, RL10 110, un booster solido diverse migliaia. Con l'impulso specifico, fissa la portata dello scarico."},group:{en:"Engine",fr:"Moteur",es:"Motor",it:"Motore"}},{type:"number",key:"vehicle.engine.specificImpulseS",min:100,max:500,step:1,unit:"s",label:{en:"Specific impulse (vacuum)",fr:"Impulsion spécifique (dans le vide)",es:"Impulso específico (en el vacío)",it:"Impulso specifico (nel vuoto)"},hint:{en:"Times 9.81 m/s² it is the exhaust velocity, which sets how fast the exhaust spreads round the stage: 348 s is 3.4 km/s.",fr:"Multipliée par 9,81 m/s², c'est la vitesse d'éjection, qui fixe la vitesse à laquelle l'échappement s'étale autour de l'étage : 348 s font 3,4 km/s.",es:"Multiplicado por 9,81 m/s² es la velocidad de escape, que fija la rapidez con que el escape se extiende alrededor de la etapa: 348 s son 3,4 km/s.",it:"Moltiplicato per 9,81 m/s² è la velocità di scarico, che fissa quanto in fretta lo scarico si allarga attorno allo stadio: 348 s sono 3,4 km/s."},group:{en:"Engine",fr:"Moteur",es:"Motor",it:"Motore"}},{type:"choice",key:"vehicle.engine.propellant",label:{en:"Propellant",fr:"Ergols",es:"Propelentes",it:"Propellenti"},hint:{en:"What the exhaust is made of decides how much of it turns into particles that scatter light.",fr:"Ce dont l'échappement est fait décide quelle part devient des particules qui diffusent la lumière.",es:"De qué está hecho el escape decide qué parte se vuelve partículas que difunden la luz.",it:"Di cosa è fatto lo scarico decide quanta parte diventa particelle che diffondono la luce."},choices:[{value:"rp1-lox",label:{en:"Kerosene and oxygen",fr:"Kérosène et oxygène",es:"Queroseno y oxígeno",it:"Cherosene e ossigeno"}},{value:"methane-lox",label:{en:"Methane and oxygen",fr:"Méthane et oxygène",es:"Metano y oxígeno",it:"Metano e ossigeno"}},{value:"hydrogen-lox",label:{en:"Hydrogen and oxygen",fr:"Hydrogène et oxygène",es:"Hidrógeno y oxígeno",it:"Idrogeno e ossigeno"}},{value:"hypergolic",label:{en:"Hypergolic",fr:"Hypergolique",es:"Hipergólico",it:"Ipergolico"}},{value:"solid",label:{en:"Solid",fr:"Poudre",es:"Sólido",it:"Solido"}}],group:{en:"Engine",fr:"Moteur",es:"Motor",it:"Motore"}},n.burn("burnFromT",{label:{en:"Engine start",fr:"Allumage du moteur",es:"Encendido del motor",it:"Accensione del motore"},hint:{en:"When the engine started, in seconds of the recording; it may be before it. Empty: the first point of the path.",fr:"Quand le moteur s'est allumé, en secondes de l'enregistrement ; avant lui si besoin. Vide : le premier point du chemin.",es:"Cuándo se encendió el motor, en segundos de la grabación; puede ser antes. Vacío: el primer punto de la trayectoria.",it:"Quando si è acceso il motore, in secondi della registrazione; può essere prima. Vuoto: il primo punto del percorso."},ends:e=>e[0]}),n.burn("burnUntilT",{label:{en:"Engine cut-off",fr:"Extinction du moteur",es:"Apagado del motor",it:"Spegnimento del motore"},hint:{en:"When the engine stopped, in seconds of the recording. Empty: the last point of the path. Nothing is let go after it.",fr:"Quand le moteur s'est éteint, en secondes de l'enregistrement. Vide : le dernier point du chemin. Rien n'est lâché après.",es:"Cuándo se apagó el motor, en segundos de la grabación. Vacío: el último punto de la trayectoria. Nada se suelta después.",it:"Quando si è spento il motore, in secondi della registrazione. Vuoto: l'ultimo punto del percorso. Dopo non si rilascia nulla."},ends:e=>e[e.length-1]}),n.plume("exhaustKgPerS",{min:.1,max:1e5,step:.1,unit:"kg/s",label:{en:"Exhaust flow",fr:"Débit d'échappement",es:"Caudal de escape",it:"Portata di scarico"},hint:{en:"How much exhaust leaves the engine each second: how bright the plume is. Thrust over exhaust velocity when the engine is stated.",fr:"La masse d'échappement qui sort du moteur chaque seconde : la luminosité du panache. La poussée sur la vitesse d'éjection quand le moteur est donné.",es:"La masa de escape que sale del motor cada segundo: el brillo de la estela. El empuje sobre la velocidad de escape cuando se da el motor.",it:"La massa di scarico che esce dal motore ogni secondo: la luminosità della scia. La spinta sulla velocità di scarico quando il motore è dato."},group:{en:"Plume",fr:"Panache",es:"Estela",it:"Scia"}}),n.plume("condensedShare",{min:0,max:1,step:.01,label:{en:"Share that scatters",fr:"Part qui diffuse",es:"Parte que difunde",it:"Parte che diffonde"},hint:{en:"The share of the exhaust that ends up as particles that scatter the Sun's light. Nobody has measured it for a launch: the one number to fit against a photograph.",fr:"La part de l'échappement qui devient des particules diffusant la lumière du Soleil. Personne ne l'a mesurée pour un lancement : le seul nombre à caler sur une photographie.",es:"La parte del escape que acaba como partículas que difunden la luz del Sol. Nadie la ha medido para un lanzamiento: el único número que ajustar con una fotografía.",it:"La parte dello scarico che diventa particelle che diffondono la luce del Sole. Nessuno l'ha misurata per un lancio: l'unico numero da tarare su una fotografia."},group:{en:"Plume",fr:"Panache",es:"Estela",it:"Scia"}}),n.plume("particleRadiusUm",{min:.05,max:5,step:.05,unit:"µm",label:{en:"Particle radius",fr:"Rayon des particules",es:"Radio de las partículas",it:"Raggio delle particelle"},group:{en:"Plume",fr:"Panache",es:"Estela",it:"Scia"}}),n.plume("lifetimeS",{min:10,max:3600,step:10,unit:"s",label:{en:"Trail lifetime",fr:"Durée de la traînée",es:"Duración de la estela",it:"Durata della scia"},hint:{en:"How long the narrow trail lasts before the particles have gone.",fr:"Combien de temps la traînée étroite dure avant que les particules aient disparu.",es:"Cuánto dura la estela estrecha antes de que las partículas hayan desaparecido.",it:"Quanto dura la scia stretta prima che le particelle siano sparite."},group:{en:"Plume",fr:"Panache",es:"Estela",it:"Scia"}}),n.plume("expansionKmPerS",{min:0,max:5,step:.01,unit:"km/s",label:{en:"Trail spreading",fr:"Étalement de la traînée",es:"Expansión de la estela",it:"Espansione della scia"},group:{en:"Plume",fr:"Panache",es:"Estela",it:"Scia"}}),n.plume("initialRadiusKm",{min:0,max:50,step:.1,unit:"km",label:{en:"Radius at release",fr:"Rayon au lâcher",es:"Radio al soltar",it:"Raggio al rilascio"},group:{en:"Plume",fr:"Panache",es:"Estela",it:"Scia"}}),n.plume("collarShare",{min:0,max:1,step:.01,label:{en:"Share in the collar",fr:"Part dans la collerette",es:"Parte en el collar",it:"Parte nel collare"},hint:{en:"The collar is the exhaust just let go, which spreads fast into a wide short-lived shell round the stage; the rest stays behind as the narrow trail.",fr:"La collerette est l'échappement qui vient d'être lâché, qui s'étale vite en une coque large et brève autour de l'étage ; le reste demeure derrière en traînée étroite.",es:"El collar es el escape recién soltado, que se extiende rápido en una envoltura ancha y breve alrededor de la etapa; el resto queda detrás como estela estrecha.",it:"Il collare è lo scarico appena rilasciato, che si allarga in fretta in un guscio largo e breve attorno allo stadio; il resto resta dietro come scia stretta."},group:{en:"Collar",fr:"Collerette",es:"Collar",it:"Collare"}}),n.plume("collarExpansionKmPerS",{min:0,max:10,step:.05,unit:"km/s",label:{en:"Collar spreading",fr:"Étalement de la collerette",es:"Expansión del collar",it:"Espansione del collare"},hint:{en:"How fast the collar widens: three quarters of the exhaust velocity when the engine is stated.",fr:"La vitesse à laquelle la collerette s'élargit : les trois quarts de la vitesse d'éjection quand le moteur est donné.",es:"La rapidez con que el collar se ensancha: tres cuartos de la velocidad de escape cuando se da el motor.",it:"Quanto in fretta il collare si allarga: tre quarti della velocità di scarico quando il motore è dato."},group:{en:"Collar",fr:"Collerette",es:"Collar",it:"Collare"}}),n.plume("collarLifetimeS",{min:1,max:300,step:1,unit:"s",label:{en:"Collar lifetime",fr:"Durée de la collerette",es:"Duración del collar",it:"Durata del collare"},group:{en:"Collar",fr:"Collerette",es:"Collar",it:"Collare"}})]};static PLACE={kind:"launch-place",title:{en:"Place of the path",fr:"Point du chemin",es:"Punto de la trayectoria",it:"Punto del percorso"},parameters:[{type:"number",key:"t",min:-3600,max:36e3,step:.1,unit:"s",scale:.001,required:!0,label:{en:"Time",fr:"Instant",es:"Instante",it:"Istante"},hint:{en:"Seconds of the recording; negative before it began: a stage seen minutes after its launch was already high when the recording started.",fr:"Secondes de l'enregistrement ; négatives avant son début : un étage vu des minutes après son lancement était déjà haut quand l'enregistrement a commencé.",es:"Segundos de la grabación; negativos antes de que empezara: una etapa vista minutos después de su lanzamiento ya estaba alta cuando empezó la grabación.",it:"Secondi della registrazione; negativi prima del suo inizio: uno stadio visto minuti dopo il lancio era già alto quando la registrazione è iniziata."}},{type:"number",key:"lat",min:-90,max:90,step:1e-4,unit:"°",required:!0,label:{en:"Latitude",fr:"Latitude",es:"Latitud",it:"Latitudine"}},{type:"number",key:"lng",min:-180,max:180,step:1e-4,unit:"°",required:!0,label:{en:"Longitude",fr:"Longitude",es:"Longitud",it:"Longitudine"}},{type:"number",key:"altitudeKm",min:0,max:2e3,step:.1,unit:"km",required:!0,label:{en:"Altitude",fr:"Altitude",es:"Altitud",it:"Altitudine"}}]};static publish(){r.publish(n.SET)}}class o{constructor(e,t,i){this.container=e,this.host=t,this.language=i,r.of("launch")||n.publish(),this.render(),this.setLanguage(i)}messages=d;languageToken=0;currentId;form;list;places;placeForm;placeIndex=0;language;shown=[];async setLanguage(e){const t=++this.languageToken;this.language=e;const i=p.includes(e)?e:"en",a=i==="en"?d:await m(i);t===this.languageToken&&(this.messages=a,this.render(),this.sync())}sync(){const e=this.launches;this.shown=[...e],e.some(a=>a.id===this.currentId)||(this.currentId=e[0]?.id),this.list?.setItems(e.map(a=>({id:a.id,label:this.labelOf(a)})),this.currentId),this.syncAddState();const t=this.current;if(this.element("launch-fields").hidden=t===void 0,!t)return;this.syncPlaces(t);const i=r.of("launch");this.form??=new c(this.element("launch-parameters"),this.language,"",{said:()=>this.host.said(),writingLanguage:()=>this.host.writingLanguage()}),this.form.show(i,t,()=>this.written())}refresh(){this.syncAddState();const e=this.launches;e.length===this.shown.length&&e.every((t,i)=>t===this.shown[i])||this.sync()}syncAddState(){const e=this.startOfNew()!==void 0;this.list?.setAddState(e,e?void 0:this.messages.addLaunchNowhere)}get current(){return this.launches.find(e=>e.id===this.currentId)}show(e){this.currentId=e,this.placeIndex=0,this.sync()}render(){const e=this.messages;this.form=void 0,this.container.innerHTML=`<div class="launch-editor">
1
+ import{L as h,o as r,U as p,p as m,m as c,E as u,n as g}from"./rr0-sighting-editor.mjs";import{launchEditorMessages_en as d}from"./LaunchEditorMessages_en-j4RgQPZu.js";class n{static plumeValue(e){return t=>h.plumeOf(t)[e]}static plume(e,t){return{type:"number",key:`plume.${e}`,effective:n.plumeValue(e),...t}}static burn(e,t){return{type:"number",key:e,min:-3600,max:36e3,step:.1,unit:"s",scale:.001,label:t.label,hint:t.hint,group:{en:"Engine",fr:"Moteur",es:"Motor",it:"Motore"},effective:i=>t.ends(i.track??[])?.t}}static nextPlace(e){const t=e[e.length-1]??{t:0,lat:0,lng:0,altitudeKm:0},i=e[e.length-2]??t,a=(s,l=0)=>e.length>1?t[s]-i[s]:l;return{t:t.t+(e.length>1?a("t"):1e4),lat:t.lat+a("lat"),lng:t.lng+a("lng"),altitudeKm:Math.max(0,t.altitudeKm+a("altitudeKm"))}}static SET={kind:"launch",title:{en:"Launch",fr:"Lancement",es:"Lanzamiento",it:"Lancio"},parameters:[{type:"said",key:"title",label:{en:"Name",fr:"Nom",es:"Nombre",it:"Nome"},group:{en:"Vehicle",fr:"Lanceur",es:"Lanzador",it:"Lanciatore"}},{type:"text",key:"vehicle.name",label:{en:"Vehicle",fr:"Lanceur",es:"Lanzador",it:"Lanciatore"},placeholder:"Falcon 9",group:{en:"Vehicle",fr:"Lanceur",es:"Lanzador",it:"Lanciatore"}},{type:"text",key:"vehicle.mission",label:{en:"Mission",fr:"Mission",es:"Misión",it:"Missione"},placeholder:"Starlink Group 10-49",group:{en:"Vehicle",fr:"Lanceur",es:"Lanzador",it:"Lanciatore"}},{type:"number",key:"vehicle.engine.thrustKN",min:1,max:1e5,step:1,unit:"kN",label:{en:"Thrust (vacuum)",fr:"Poussée (dans le vide)",es:"Empuje (en el vacío)",it:"Spinta (nel vuoto)"},hint:{en:"Merlin Vacuum 934, RL10 110, a solid booster several thousand. With the specific impulse, it sets how much exhaust leaves each second.",fr:"Merlin Vacuum 934, RL10 110, un booster à poudre plusieurs milliers. Avec l'impulsion spécifique, elle fixe le débit d'échappement.",es:"Merlin Vacuum 934, RL10 110, un propulsor sólido varios miles. Con el impulso específico, fija el caudal de escape.",it:"Merlin Vacuum 934, RL10 110, un booster solido diverse migliaia. Con l'impulso specifico, fissa la portata dello scarico."},group:{en:"Engine",fr:"Moteur",es:"Motor",it:"Motore"}},{type:"number",key:"vehicle.engine.specificImpulseS",min:100,max:500,step:1,unit:"s",label:{en:"Specific impulse (vacuum)",fr:"Impulsion spécifique (dans le vide)",es:"Impulso específico (en el vacío)",it:"Impulso specifico (nel vuoto)"},hint:{en:"Times 9.81 m/s² it is the exhaust velocity, which sets how fast the exhaust spreads round the stage: 348 s is 3.4 km/s.",fr:"Multipliée par 9,81 m/s², c'est la vitesse d'éjection, qui fixe la vitesse à laquelle l'échappement s'étale autour de l'étage : 348 s font 3,4 km/s.",es:"Multiplicado por 9,81 m/s² es la velocidad de escape, que fija la rapidez con que el escape se extiende alrededor de la etapa: 348 s son 3,4 km/s.",it:"Moltiplicato per 9,81 m/s² è la velocità di scarico, che fissa quanto in fretta lo scarico si allarga attorno allo stadio: 348 s sono 3,4 km/s."},group:{en:"Engine",fr:"Moteur",es:"Motor",it:"Motore"}},{type:"choice",key:"vehicle.engine.propellant",label:{en:"Propellant",fr:"Ergols",es:"Propelentes",it:"Propellenti"},hint:{en:"What the exhaust is made of decides how much of it turns into particles that scatter light.",fr:"Ce dont l'échappement est fait décide quelle part devient des particules qui diffusent la lumière.",es:"De qué está hecho el escape decide qué parte se vuelve partículas que difunden la luz.",it:"Di cosa è fatto lo scarico decide quanta parte diventa particelle che diffondono la luce."},choices:[{value:"rp1-lox",label:{en:"Kerosene and oxygen",fr:"Kérosène et oxygène",es:"Queroseno y oxígeno",it:"Cherosene e ossigeno"}},{value:"methane-lox",label:{en:"Methane and oxygen",fr:"Méthane et oxygène",es:"Metano y oxígeno",it:"Metano e ossigeno"}},{value:"hydrogen-lox",label:{en:"Hydrogen and oxygen",fr:"Hydrogène et oxygène",es:"Hidrógeno y oxígeno",it:"Idrogeno e ossigeno"}},{value:"hypergolic",label:{en:"Hypergolic",fr:"Hypergolique",es:"Hipergólico",it:"Ipergolico"}},{value:"solid",label:{en:"Solid",fr:"Poudre",es:"Sólido",it:"Solido"}}],group:{en:"Engine",fr:"Moteur",es:"Motor",it:"Motore"}},n.burn("burnFromT",{label:{en:"Engine start",fr:"Allumage du moteur",es:"Encendido del motor",it:"Accensione del motore"},hint:{en:"When the engine started, in seconds of the recording; it may be before it. Empty: the first point of the path.",fr:"Quand le moteur s'est allumé, en secondes de l'enregistrement ; avant lui si besoin. Vide : le premier point du chemin.",es:"Cuándo se encendió el motor, en segundos de la grabación; puede ser antes. Vacío: el primer punto de la trayectoria.",it:"Quando si è acceso il motore, in secondi della registrazione; può essere prima. Vuoto: il primo punto del percorso."},ends:e=>e[0]}),n.burn("burnUntilT",{label:{en:"Engine cut-off",fr:"Extinction du moteur",es:"Apagado del motor",it:"Spegnimento del motore"},hint:{en:"When the engine stopped, in seconds of the recording. Empty: the last point of the path. Nothing is let go after it.",fr:"Quand le moteur s'est éteint, en secondes de l'enregistrement. Vide : le dernier point du chemin. Rien n'est lâché après.",es:"Cuándo se apagó el motor, en segundos de la grabación. Vacío: el último punto de la trayectoria. Nada se suelta después.",it:"Quando si è spento il motore, in secondi della registrazione. Vuoto: l'ultimo punto del percorso. Dopo non si rilascia nulla."},ends:e=>e[e.length-1]}),n.plume("exhaustKgPerS",{min:.1,max:1e5,step:.1,unit:"kg/s",label:{en:"Exhaust flow",fr:"Débit d'échappement",es:"Caudal de escape",it:"Portata di scarico"},hint:{en:"How much exhaust leaves the engine each second: how bright the plume is. Thrust over exhaust velocity when the engine is stated.",fr:"La masse d'échappement qui sort du moteur chaque seconde : la luminosité du panache. La poussée sur la vitesse d'éjection quand le moteur est donné.",es:"La masa de escape que sale del motor cada segundo: el brillo de la estela. El empuje sobre la velocidad de escape cuando se da el motor.",it:"La massa di scarico che esce dal motore ogni secondo: la luminosità della scia. La spinta sulla velocità di scarico quando il motore è dato."},group:{en:"Plume",fr:"Panache",es:"Estela",it:"Scia"}}),n.plume("condensedShare",{min:0,max:1,step:.01,label:{en:"Share that scatters",fr:"Part qui diffuse",es:"Parte que difunde",it:"Parte che diffonde"},hint:{en:"The share of the exhaust that ends up as particles that scatter the Sun's light. Nobody has measured it for a launch: the one number to fit against a photograph.",fr:"La part de l'échappement qui devient des particules diffusant la lumière du Soleil. Personne ne l'a mesurée pour un lancement : le seul nombre à caler sur une photographie.",es:"La parte del escape que acaba como partículas que difunden la luz del Sol. Nadie la ha medido para un lanzamiento: el único número que ajustar con una fotografía.",it:"La parte dello scarico che diventa particelle che diffondono la luce del Sole. Nessuno l'ha misurata per un lancio: l'unico numero da tarare su una fotografia."},group:{en:"Plume",fr:"Panache",es:"Estela",it:"Scia"}}),n.plume("particleRadiusUm",{min:.05,max:5,step:.05,unit:"µm",label:{en:"Particle radius",fr:"Rayon des particules",es:"Radio de las partículas",it:"Raggio delle particelle"},group:{en:"Plume",fr:"Panache",es:"Estela",it:"Scia"}}),n.plume("lifetimeS",{min:10,max:3600,step:10,unit:"s",label:{en:"Trail lifetime",fr:"Durée de la traînée",es:"Duración de la estela",it:"Durata della scia"},hint:{en:"How long the narrow trail lasts before the particles have gone.",fr:"Combien de temps la traînée étroite dure avant que les particules aient disparu.",es:"Cuánto dura la estela estrecha antes de que las partículas hayan desaparecido.",it:"Quanto dura la scia stretta prima che le particelle siano sparite."},group:{en:"Plume",fr:"Panache",es:"Estela",it:"Scia"}}),n.plume("expansionKmPerS",{min:0,max:5,step:.01,unit:"km/s",label:{en:"Trail spreading",fr:"Étalement de la traînée",es:"Expansión de la estela",it:"Espansione della scia"},group:{en:"Plume",fr:"Panache",es:"Estela",it:"Scia"}}),n.plume("initialRadiusKm",{min:0,max:50,step:.1,unit:"km",label:{en:"Radius at release",fr:"Rayon au lâcher",es:"Radio al soltar",it:"Raggio al rilascio"},group:{en:"Plume",fr:"Panache",es:"Estela",it:"Scia"}}),n.plume("collarShare",{min:0,max:1,step:.01,label:{en:"Share in the collar",fr:"Part dans la collerette",es:"Parte en el collar",it:"Parte nel collare"},hint:{en:"The collar is the exhaust just let go, which spreads fast into a wide short-lived shell round the stage; the rest stays behind as the narrow trail.",fr:"La collerette est l'échappement qui vient d'être lâché, qui s'étale vite en une coque large et brève autour de l'étage ; le reste demeure derrière en traînée étroite.",es:"El collar es el escape recién soltado, que se extiende rápido en una envoltura ancha y breve alrededor de la etapa; el resto queda detrás como estela estrecha.",it:"Il collare è lo scarico appena rilasciato, che si allarga in fretta in un guscio largo e breve attorno allo stadio; il resto resta dietro come scia stretta."},group:{en:"Collar",fr:"Collerette",es:"Collar",it:"Collare"}}),n.plume("collarExpansionKmPerS",{min:0,max:10,step:.05,unit:"km/s",label:{en:"Collar spreading",fr:"Étalement de la collerette",es:"Expansión del collar",it:"Espansione del collare"},hint:{en:"How fast the collar widens: three quarters of the exhaust velocity when the engine is stated.",fr:"La vitesse à laquelle la collerette s'élargit : les trois quarts de la vitesse d'éjection quand le moteur est donné.",es:"La rapidez con que el collar se ensancha: tres cuartos de la velocidad de escape cuando se da el motor.",it:"Quanto in fretta il collare si allarga: tre quarti della velocità di scarico quando il motore è dato."},group:{en:"Collar",fr:"Collerette",es:"Collar",it:"Collare"}}),n.plume("collarLifetimeS",{min:1,max:300,step:1,unit:"s",label:{en:"Collar lifetime",fr:"Durée de la collerette",es:"Duración del collar",it:"Durata del collare"},group:{en:"Collar",fr:"Collerette",es:"Collar",it:"Collare"}})]};static PLACE={kind:"launch-place",title:{en:"Place of the path",fr:"Point du chemin",es:"Punto de la trayectoria",it:"Punto del percorso"},parameters:[{type:"number",key:"t",min:-3600,max:36e3,step:.1,unit:"s",scale:.001,required:!0,label:{en:"Time",fr:"Instant",es:"Instante",it:"Istante"},hint:{en:"Seconds of the recording; negative before it began: a stage seen minutes after its launch was already high when the recording started.",fr:"Secondes de l'enregistrement ; négatives avant son début : un étage vu des minutes après son lancement était déjà haut quand l'enregistrement a commencé.",es:"Segundos de la grabación; negativos antes de que empezara: una etapa vista minutos después de su lanzamiento ya estaba alta cuando empezó la grabación.",it:"Secondi della registrazione; negativi prima del suo inizio: uno stadio visto minuti dopo il lancio era già alto quando la registrazione è iniziata."}},{type:"number",key:"lat",min:-90,max:90,step:1e-4,unit:"°",required:!0,label:{en:"Latitude",fr:"Latitude",es:"Latitud",it:"Latitudine"}},{type:"number",key:"lng",min:-180,max:180,step:1e-4,unit:"°",required:!0,label:{en:"Longitude",fr:"Longitude",es:"Longitud",it:"Longitudine"}},{type:"number",key:"altitudeKm",min:0,max:2e3,step:.1,unit:"km",required:!0,label:{en:"Altitude",fr:"Altitude",es:"Altitud",it:"Altitudine"}}]};static publish(){r.publish(n.SET)}}class o{constructor(e,t,i){this.container=e,this.host=t,this.language=i,r.of("launch")||n.publish(),this.render(),this.setLanguage(i)}messages=d;languageToken=0;currentId;form;list;places;placeForm;placeIndex=0;language;shown=[];async setLanguage(e){const t=++this.languageToken;this.language=e;const i=p.includes(e)?e:"en",a=i==="en"?d:await m(i);t===this.languageToken&&(this.messages=a,this.render(),this.sync())}sync(){const e=this.launches;this.shown=[...e],e.some(a=>a.id===this.currentId)||(this.currentId=e[0]?.id),this.list?.setItems(e.map(a=>({id:a.id,label:this.labelOf(a)})),this.currentId),this.syncAddState();const t=this.current;if(this.element("launch-fields").hidden=t===void 0,!t)return;this.syncPlaces(t);const i=r.of("launch");this.form??=new c(this.element("launch-parameters"),this.language,"",{said:()=>this.host.said(),writingLanguage:()=>this.host.writingLanguage()}),this.form.show(i,t,()=>this.written())}refresh(){this.syncAddState();const e=this.launches;e.length===this.shown.length&&e.every((t,i)=>t===this.shown[i])||this.sync()}syncAddState(){const e=this.startOfNew()!==void 0;this.list?.setAddState(e,e?void 0:this.messages.addLaunchNowhere)}get current(){return this.launches.find(e=>e.id===this.currentId)}show(e){this.currentId=e,this.placeIndex=0,this.sync()}render(){const e=this.messages;this.form=void 0,this.container.innerHTML=`<div class="launch-editor">
2
2
  <p class="launch-intro">${e.intro}</p>
3
3
  <div id="launch-list"></div>
4
4
  <div id="launch-fields" class="launch-fields">
@@ -0,0 +1 @@
1
+ import{G as d,z as c,C as l,F as f,J as m,K as u,N as w,Q as g,X as y,Y as M,Z as S,$ as v,a0 as O}from"./rr0-sighting-editor.mjs";class h{static key(e){return"url"in e?`url:${e.url}|${e.headingOffsetDeg??0}`:"shape"in e?`shape:${e.shape}`:`decor:${e.decorKind}`}static async build(e){const s=new d;if("url"in e){const a=await c(e.url);a.rotation.y=-(e.headingOffsetDeg??0)*Math.PI/180,s.add(a)}else"shape"in e?s.add(h.shapeOf(e.shape)):s.add(l.build({id:"preview",kind:e.decorKind,eastM:0,northM:0},!1));return s}static shapeOf(e){if(e==="figure")return l.build({id:"preview",kind:"entity",eastM:0,northM:0},!1);const s=new f(m.unitGeometry(e),new u({color:13158608,roughness:.5,metalness:0}));return e==="ellipsoid"&&s.scale.set(1,.55,1),s}static dispose(e){e.traverse(s=>{const a=s;if(a.isMesh){a.geometry?.dispose();for(const t of[a.material].flat())t.dispose()}})}static stage(e,s){const a=new w().setFromObject(e);if(a.isEmpty())return;const t=a.getBoundingSphere(new g),r=new d;e.position.sub(t.center),r.add(e);const n=new y;n.add(r),n.add(new M(16777215,6715272,1.6));const o=new S(16777215,2.5);o.position.set(1,2,1.5),n.add(o);const i=new v(30,s,t.radius*.05,t.radius*20),p=t.radius/Math.sin(i.fov*Math.PI/360)*1.05;return i.position.copy(new O(.55,.3,-.78).normalize().multiplyScalar(p)),i.lookAt(0,0,0),{scene:n,camera:i,pivot:r}}}export{h as M};
@@ -1 +1 @@
1
- import{W as c}from"./rr0-sighting-editor.mjs";import{M as i}from"./ModelSource-gIw80dOv.js";class l{static SIZE_PX={width:192,height:144};static cache=new Map;static queue=Promise.resolve();static pending=0;static renderer;static of(r){const t=i.key(r);let e=this.cache.get(t);return e||(this.pending++,e=this.queue.then(()=>this.draw(r)).catch(()=>{}).finally(()=>{--this.pending===0&&this.release()}),this.queue=e,this.cache.set(t,e)),e}static async draw(r){const t=await i.build(r);try{const{width:e,height:n}=this.SIZE_PX,a=i.stage(t,e/n);if(!a)return;const s=this.renderer??=new c({antialias:!0,alpha:!0,preserveDrawingBuffer:!0});return s.setSize(e,n,!1),s.setClearColor(0,0),s.render(a.scene,a.camera),s.domElement.toDataURL("image/png")}finally{i.dispose(t)}}static release(){this.renderer?.dispose(),this.renderer?.forceContextLoss(),this.renderer=void 0}}export{l as ModelThumbnails};
1
+ import{W as c}from"./rr0-sighting-editor.mjs";import{M as i}from"./ModelSource-BjAOa9Br.js";class l{static SIZE_PX={width:192,height:144};static cache=new Map;static queue=Promise.resolve();static pending=0;static renderer;static of(r){const t=i.key(r);let e=this.cache.get(t);return e||(this.pending++,e=this.queue.then(()=>this.draw(r)).catch(()=>{}).finally(()=>{--this.pending===0&&this.release()}),this.queue=e,this.cache.set(t,e)),e}static async draw(r){const t=await i.build(r);try{const{width:e,height:n}=this.SIZE_PX,a=i.stage(t,e/n);if(!a)return;const s=this.renderer??=new c({antialias:!0,alpha:!0,preserveDrawingBuffer:!0});return s.setSize(e,n,!1),s.setClearColor(0,0),s.render(a.scene,a.camera),s.domElement.toDataURL("image/png")}finally{i.dispose(t)}}static release(){this.renderer?.dispose(),this.renderer?.forceContextLoss(),this.renderer=void 0}}export{l as ModelThumbnails};
@@ -1 +1 @@
1
- import{W as h}from"./rr0-sighting-editor.mjs";import{M as c}from"./ModelSource-gIw80dOv.js";class a{constructor(t,e){this.container=t,this.source=e,this.canvas=document.createElement("canvas"),this.canvas.className="model-live",this.canvas.style.cssText="position:absolute;inset:0;width:100%;height:100%;touch-action:none;cursor:grab;display:none",this.canvas.addEventListener("pointerdown",s=>this.press(s)),this.canvas.addEventListener("pointermove",s=>this.move(s)),this.canvas.addEventListener("pointerup",()=>this.release()),this.canvas.addEventListener("pointercancel",()=>this.release())}static renderer;static SPIN_RAD_PER_S=.7;static DRAG_RAD_PER_PX=.012;static CLICK_TOLERANCE_PX=4;static current;object;stage;frame=0;stopped=!1;last=0;dragging;draggedPastClick=!1;canvas;static show(t,e){a.current?.stop();const s=new a(t,e);return a.current=s,s.start(),s}static end(){a.current?.stop(),a.current=void 0,a.renderer?.dispose(),a.renderer?.forceContextLoss(),a.renderer=void 0}consumeDrag(){const t=this.draggedPastClick;return this.draggedPastClick=!1,t}get active(){return!this.stopped}stop(){this.stopped=!0,cancelAnimationFrame(this.frame),this.canvas.remove(),this.object&&c.dispose(this.object),this.object=void 0,a.current===this&&(a.current=void 0)}async start(){try{const t=await c.build(this.source);if(this.stopped){c.dispose(t);return}this.object=t;const{width:e,height:s}=this.container.getBoundingClientRect(),i=e>0&&s>0?e/s:4/3;if(this.stage=c.stage(t,i),!this.stage)return;(a.renderer??=new h({antialias:!0,alpha:!0})).setClearColor(0,0),this.container.append(this.canvas),this.canvas.style.display="block",this.last=performance.now(),this.tick()}catch{}}tick=()=>{if(this.stopped||!this.stage)return;const t=performance.now(),e=Math.min(.1,(t-this.last)/1e3);this.last=t,this.dragging||(this.stage.pivot.rotation.y+=a.SPIN_RAD_PER_S*e);const s=a.renderer,{width:i,height:n}=this.canvas.getBoundingClientRect(),r=Math.min(2,window.devicePixelRatio||1);(this.canvas.width!==Math.round(i*r)||this.canvas.height!==Math.round(n*r))&&(s.setPixelRatio(r),s.setSize(i,n,!1),this.canvas.width=Math.round(i*r),this.canvas.height=Math.round(n*r),this.stage.camera.aspect=i/Math.max(1,n),this.stage.camera.updateProjectionMatrix()),s.render(this.stage.scene,this.stage.camera);const o=this.canvas.getContext("2d");o?.clearRect(0,0,this.canvas.width,this.canvas.height),o?.drawImage(s.domElement,0,0,this.canvas.width,this.canvas.height),this.frame=requestAnimationFrame(this.tick)};press(t){this.dragging={x:t.clientX,y:t.clientY,moved:!1},this.canvas.setPointerCapture(t.pointerId),this.canvas.style.cursor="grabbing"}move(t){const e=this.dragging;if(!e||!this.stage)return;const s=t.clientX-e.x,i=t.clientY-e.y;!e.moved&&Math.hypot(s,i)<a.CLICK_TOLERANCE_PX||(e.moved=!0,this.draggedPastClick=!0,this.stage.pivot.rotation.y+=s*a.DRAG_RAD_PER_PX,this.stage.pivot.rotation.x=Math.max(-1.4,Math.min(1.4,this.stage.pivot.rotation.x-i*a.DRAG_RAD_PER_PX)),e.x=t.clientX,e.y=t.clientY)}release(){this.dragging=void 0,this.canvas.style.cursor="grab"}}export{a as ModelViewer};
1
+ import{W as h}from"./rr0-sighting-editor.mjs";import{M as c}from"./ModelSource-BjAOa9Br.js";class a{constructor(t,e){this.container=t,this.source=e,this.canvas=document.createElement("canvas"),this.canvas.className="model-live",this.canvas.style.cssText="position:absolute;inset:0;width:100%;height:100%;touch-action:none;cursor:grab;display:none",this.canvas.addEventListener("pointerdown",s=>this.press(s)),this.canvas.addEventListener("pointermove",s=>this.move(s)),this.canvas.addEventListener("pointerup",()=>this.release()),this.canvas.addEventListener("pointercancel",()=>this.release())}static renderer;static SPIN_RAD_PER_S=.7;static DRAG_RAD_PER_PX=.012;static CLICK_TOLERANCE_PX=4;static current;object;stage;frame=0;stopped=!1;last=0;dragging;draggedPastClick=!1;canvas;static show(t,e){a.current?.stop();const s=new a(t,e);return a.current=s,s.start(),s}static end(){a.current?.stop(),a.current=void 0,a.renderer?.dispose(),a.renderer?.forceContextLoss(),a.renderer=void 0}consumeDrag(){const t=this.draggedPastClick;return this.draggedPastClick=!1,t}get active(){return!this.stopped}stop(){this.stopped=!0,cancelAnimationFrame(this.frame),this.canvas.remove(),this.object&&c.dispose(this.object),this.object=void 0,a.current===this&&(a.current=void 0)}async start(){try{const t=await c.build(this.source);if(this.stopped){c.dispose(t);return}this.object=t;const{width:e,height:s}=this.container.getBoundingClientRect(),i=e>0&&s>0?e/s:4/3;if(this.stage=c.stage(t,i),!this.stage)return;(a.renderer??=new h({antialias:!0,alpha:!0})).setClearColor(0,0),this.container.append(this.canvas),this.canvas.style.display="block",this.last=performance.now(),this.tick()}catch{}}tick=()=>{if(this.stopped||!this.stage)return;const t=performance.now(),e=Math.min(.1,(t-this.last)/1e3);this.last=t,this.dragging||(this.stage.pivot.rotation.y+=a.SPIN_RAD_PER_S*e);const s=a.renderer,{width:i,height:n}=this.canvas.getBoundingClientRect(),r=Math.min(2,window.devicePixelRatio||1);(this.canvas.width!==Math.round(i*r)||this.canvas.height!==Math.round(n*r))&&(s.setPixelRatio(r),s.setSize(i,n,!1),this.canvas.width=Math.round(i*r),this.canvas.height=Math.round(n*r),this.stage.camera.aspect=i/Math.max(1,n),this.stage.camera.updateProjectionMatrix()),s.render(this.stage.scene,this.stage.camera);const o=this.canvas.getContext("2d");o?.clearRect(0,0,this.canvas.width,this.canvas.height),o?.drawImage(s.domElement,0,0,this.canvas.width,this.canvas.height),this.frame=requestAnimationFrame(this.tick)};press(t){this.dragging={x:t.clientX,y:t.clientY,moved:!1},this.canvas.setPointerCapture(t.pointerId),this.canvas.style.cursor="grabbing"}move(t){const e=this.dragging;if(!e||!this.stage)return;const s=t.clientX-e.x,i=t.clientY-e.y;!e.moved&&Math.hypot(s,i)<a.CLICK_TOLERANCE_PX||(e.moved=!0,this.draggedPastClick=!0,this.stage.pivot.rotation.y+=s*a.DRAG_RAD_PER_PX,this.stage.pivot.rotation.x=Math.max(-1.4,Math.min(1.4,this.stage.pivot.rotation.x-i*a.DRAG_RAD_PER_PX)),e.x=t.clientX,e.y=t.clientY)}release(){this.dragging=void 0,this.canvas.style.cursor="grab"}}export{a as ModelViewer};
@@ -0,0 +1,41 @@
1
+ import{G as F,K as P,a6 as H,a7 as K,aa as w,ac as N,F as U,ad as k}from"./rr0-sighting-editor.mjs";class b{static HOLLOW_M=1;static COVERED_M=3;static WINDOW_M=30;static SAMPLE_M=4;static MAX_GRADE={rail:.025,highSpeed:.035,subway:.04,light_rail:.06,tram:.08,funicular:1/0};static heights(t,n,e){const s=t.map(a=>a.level===0),o=t.map((a,l)=>s[l]?b.targets(a,n,e):[]),c=t.map((a,l)=>s[l]?b.samples(a,o[l]):[]),r=new Map;t.forEach((a,l)=>{if(s[l])for(const M of b.ends(a)){const h=b.key(M),d=r.get(h);d?d.push(l):r.set(h,[l])}});const p=a=>{const l=r.get(b.key(a));if(l)return b.median(l.flatMap(M=>c[M]),a)};return t.map((a,l)=>{if(s[l]){const M=[...new Set([l,...b.ends(a).flatMap(g=>r.get(b.key(g))??[])])].flatMap(g=>c[g]),h=a.centre.map((g,D)=>b.median(M,g)??o[l][D]),[d,L]=b.ends(a);return h[0]=p(d)??h[0],h[h.length-1]=p(L)??h[h.length-1],b.graded(h,a.along,a.highSpeed?b.MAX_GRADE.highSpeed:b.MAX_GRADE[a.kind])}return b.carried(a,n,e,p)})}static targets(t,n,e){return t.centre.map(s=>{const o=n(s.x,s.z);if(e===void 0||s.altitudeM===void 0)return o;const c=s.altitudeM+e;return c-o>b.HOLLOW_M||o-c>b.COVERED_M?c:o})}static samples(t,n){const e=[];let s=0;return t.centre.forEach((o,c)=>{t.along[c]+1e-6<s&&c<t.centre.length-1||(e.push({x:o.x,z:o.z,y:n[c]}),s=t.along[c]+b.SAMPLE_M)}),e}static median(t,n){const e=[];for(const o of t)Math.hypot(o.x-n.x,o.z-n.z)<=b.WINDOW_M&&e.push(o.y);if(e.length===0)return;e.sort((o,c)=>o-c);const s=e.length>>1;return e.length%2===1?e[s]:(e[s-1]+e[s])/2}static graded(t,n,e){if(!Number.isFinite(e)||t.length<3)return t;const s=[...t],o=s.length-1,c=n[o];if(Math.abs(s[o]-s[0])>e*c)return n.map(r=>s[0]+(s[o]-s[0])*r/c);for(let r=1;r<o;r++){const p=e*(n[r]-n[r-1]);s[r]=Math.min(s[r-1]+p,Math.max(s[r-1]-p,s[r]))}for(let r=o-1;r>0;r--){const p=e*(n[r+1]-n[r]);s[r]=Math.min(s[r+1]+p,Math.max(s[r+1]-p,s[r]))}return s}static carried(t,n,e,s){const[o,c]=b.ends(t),r=t.along[t.along.length-1],p=s(o),a=s(c);if(e!==void 0&&t.centre.every(h=>h.altitudeM!==void 0)){const h=t.centre.map(g=>g.altitudeM+e),d=p!==void 0?p-h[0]:0,L=a!==void 0?a-h[h.length-1]:0;return h.map((g,D)=>g+d+(L-d)*t.along[D]/r)}const l=p??n(o.x,o.z),M=a??n(c.x,c.z);return t.along.map(h=>l+(M-l)*h/r)}static ends(t){return[t.centre[0],t.centre[t.centre.length-1]]}static key(t){return`${Math.round(t.x*2)},${Math.round(t.z*2)}`}}class B{positions=[];indices=[];along=[];get vertexCount(){return this.positions.length/3}strip(t,n,e){const s=this.vertexCount;for(let o=0;o<t.length;o++)this.positions.push(t[o].x,t[o].y,t[o].z,n[o].x,n[o].y,n[o].z),e&&this.along.push(e[o],e[o]);for(let o=0;o<t.length-1;o++){const c=s+o*2;this.indices.push(c,c+2,c+1,c+1,c+2,c+3)}}beam(t,n,e,s=!0){const o=n.x-t.x,c=n.y-t.y,r=n.z-t.z,p=Math.hypot(o,c,r);if(p<1e-6)return;const a={x:o/p,y:c/p,z:r/p},l=Math.abs(a.y)>.9?{x:1,y:0,z:0}:{x:0,y:1,z:0},M=a.y*l.z-a.z*l.y,h=a.z*l.x-a.x*l.z,d=a.x*l.y-a.y*l.x,L=Math.hypot(M,h,d),g={x:M/L*e/2,y:h/L*e/2,z:d/L*e/2},D={x:a.y*g.z-a.z*g.y,y:a.z*g.x-a.x*g.z,z:a.x*g.y-a.y*g.x},E=(u,A,f)=>({x:u.x+g.x*A+D.x*f,y:u.y+g.y*A+D.y*f,z:u.z+g.z*A+D.z*f}),O=[[1,1],[-1,1],[-1,-1],[1,-1]];for(let u=0;u<4;u++){const[A,f]=O[u],[v,x]=O[(u+1)%4];this.quad(E(t,A,f),E(t,v,x),E(n,v,x),E(n,A,f))}s&&(this.quad(...[...O].reverse().map(([u,A])=>E(t,u,A))),this.quad(...O.map(([u,A])=>E(n,u,A))))}quad(t,n,e,s){const o=this.vertexCount;this.positions.push(t.x,t.y,t.z,n.x,n.y,n.z,e.x,e.y,e.z,s.x,s.y,s.z),this.indices.push(o,o+1,o+2,o,o+2,o+3)}}class i{static STEP_M=6;static BALLAST_HEIGHT_M=.5;static BALLAST_SLOPE=1.5;static BALLAST_SHOULDER_M=.45;static DECK_DEPTH_M=.8;static BANK_SLOPE=1.5;static SLEEPER_LENGTH_M=2.4;static SLEEPER_WIDTH_M=.29;static SLEEPER_SPACING_M=.6;static RAIL_HEAD_M=.072;static RAIL_HEIGHT_M=.18;static TRAM_RAIL_HEIGHT_M=.03;static LIFT_M=.06;static CATENARY={rail:{contactM:5.5,systemM:1.4,spanM:54,staggerM:.2},highSpeed:{contactM:5.08,systemM:1.4,spanM:63,staggerM:.2},service:{contactM:5.5,systemM:1.2,spanM:45,staggerM:.2},tram:{contactM:6,systemM:0,spanM:30,staggerM:.2}};static MESSENGER_SAG_M=.55;static MAST_SIDE_M=.26;static MAST_OFFSET_M=3.1;static MAST_ABOVE_M=.6;static CONTACT_DIAMETER_M=.012;static MESSENGER_DIAMETER_M=.011;static ARM_SIDE_M=.06;static TRACK_SPACING_M={rail:3.7,highSpeed:4.5,tram:3.1,subway:3.4,light_rail:3.4,funicular:3.2};static BALLAST_ALBEDO=[.17,.16,.15];static BANK_ALBEDO=[.085,.09,.05];static DECK_ALBEDO=[.26,.255,.24];static CONCRETE_ALBEDO=[.36,.35,.33];static WOOD_ALBEDO=[.07,.055,.045];static RUST_ALBEDO=[.085,.068,.058];static STEEL_ALBEDO=[.3,.31,.32];static COPPER_ALBEDO=[.09,.085,.07];static LINE_REACH_M=20;group=new F;stepM=i.STEP_M;drawn=0;laid=[];ballastMaterial=i.pebbled(i.lambert(i.BALLAST_ALBEDO,!0));earthMaterial=i.lambert(i.BANK_ALBEDO,!0);deckMaterial=i.lambert(i.DECK_ALBEDO,!1);concreteSleepers=i.sleeperMaterial(i.CONCRETE_ALBEDO);woodSleepers=i.sleeperMaterial(i.WOOD_ALBEDO);rustMaterial=i.lambert(i.RUST_ALBEDO,!0);headMaterial=new P({color:new H(.62,.62,.62),metalness:1,roughness:.28,polygonOffset:!0,polygonOffsetFactor:-2,polygonOffsetUnits:-2});steelMaterial=i.lambert(i.STEEL_ALBEDO,!1);wireMaterial=i.lambert(i.COPPER_ALBEDO,!1);constructor(){this.group.name="railways"}get count(){return this.drawn}setGroundSpacing(t){this.stepM=Number.isFinite(t)&&t>0?Math.min(i.STEP_M,Math.max(1.5,t/2)):i.STEP_M}set(t,n,e,s,o=1/0){this.clear();const r=t.map(d=>({line:d,path:d.points.map(L=>({...K(L.lat,L.lng,n,e),altitudeM:L.altitudeM}))})).filter(({line:d,path:L})=>d.level>=0&&i.within(L,o)),p=i.altitudeOffset(r,s),a=r.flatMap(({line:d,path:L})=>{const g=this.layoutOf(d,L);return g?[{line:d,layout:g}]:[]}),l=b.heights(a.map(({layout:d})=>d),s,p),M={ballast:new B,earth:new B,deck:new B,concrete:new B,wood:new B,rust:new B,head:new B,steel:new B,wire:new B};a.forEach(({line:d,layout:L},g)=>{this.lay(d,{...L,y:l[g]},s,M),this.laid.push({line:d,centre:L.centre}),this.drawn++});const h=[[M.ballast,this.ballastMaterial,"ballast",!1],[M.earth,this.earthMaterial,"embankments",!1],[M.deck,this.deckMaterial,"decks",!0],[M.concrete,this.concreteSleepers,"sleepers",!1],[M.wood,this.woodSleepers,"sleepers wood",!1],[M.rust,this.rustMaterial,"rails",!1],[M.head,this.headMaterial,"rail heads",!1],[M.steel,this.steelMaterial,"catenary masts",!0],[M.wire,this.wireMaterial,"catenary wires",!1]];for(const[d,L,g,D]of h){const E=i.meshOf(d,L);E&&(E.name=`railways ${g}`,E.castShadow=D,E.receiveShadow=!0,this.group.add(E))}}clear(){for(const t of[...this.group.children])this.group.remove(t),t.geometry?.dispose();this.drawn=0,this.laid=[]}lineAt(t,n){let e;for(const{line:s,centre:o}of this.laid)for(let c=0;c<o.length-1;c++){const r=o[c],p=o[c+1],a=p.x-r.x,l=p.z-r.z,M=a*a+l*l,h=M===0?0:Math.max(0,Math.min(1,((t-r.x)*a+(n-r.z)*l)/M)),d=Math.hypot(t-(r.x+a*h),n-(r.z+l*h));d<=i.LINE_REACH_M&&(!e||d<e.distance)&&(e={line:s,distance:d})}return e?.line}contactHeightM(t){if(!(t.electrification!=="overhead"||t.kind==="subway"||t.kind==="funicular"))return i.catenaryOf(t).contactM}static catenaryOf(t){return t.kind==="tram"?i.CATENARY.tram:t.highSpeed?i.CATENARY.highSpeed:t.service?i.CATENARY.service:i.CATENARY.rail}dispose(){this.clear();for(const t of[this.ballastMaterial,this.earthMaterial,this.deckMaterial,this.concreteSleepers,this.woodSleepers,this.rustMaterial,this.headMaterial,this.steelMaterial,this.wireMaterial])t.dispose()}static within(t,n){if(!Number.isFinite(n))return!0;const e=n*1.1+100;return t.some((s,o)=>Math.hypot(s.x,s.z)<=e||o>0&&Math.hypot((s.x+t[o-1].x)/2,(s.z+t[o-1].z)/2)<=e)}static altitudeOffset(t,n){const e=[];for(const{line:s,path:o}of t)if(s.level===0)for(const c of o)c.altitudeM!==void 0&&e.push(n(c.x,c.z)-c.altitudeM);if(!(e.length<5))return e.sort((s,o)=>s-o),e[Math.floor(e.length/2)]}layoutOf(t,n){const e=[];for(let c=0;c<n.length-1;c++){const r=n[c],p=n[c+1],a=Math.max(1,Math.ceil(Math.hypot(p.x-r.x,p.z-r.z)/this.stepM));for(let l=0;l<a;l++){const M=l/a,h=r.altitudeM!==void 0&&p.altitudeM!==void 0?r.altitudeM+(p.altitudeM-r.altitudeM)*M:void 0;e.push({x:r.x+(p.x-r.x)*M,z:r.z+(p.z-r.z)*M,altitudeM:h})}}if(e.push(n[n.length-1]),e.length<2)return;const s=[0];for(let c=1;c<e.length;c++)s.push(s[c-1]+Math.hypot(e[c].x-e[c-1].x,e[c].z-e[c-1].z));if(s[s.length-1]<.5)return;const o=e.map((c,r)=>{const p=e[Math.max(0,r-1)],a=e[Math.min(e.length-1,r+1)],l=a.x-p.x,M=a.z-p.z,h=Math.hypot(l,M);return h<1e-6?{x:1,z:0}:{x:l/h,z:M/h}});return{kind:t.kind,...t.highSpeed?{highSpeed:!0}:{},level:t.level,centre:e,along:s,dir:o}}lay(t,n,e,s){const o=t.highSpeed?i.TRACK_SPACING_M.highSpeed:i.TRACK_SPACING_M[t.kind],c=Math.min(8,Math.max(1,t.tracks)),r=Array.from({length:c},(E,O)=>(O-(c-1)/2)*o),p=t.kind==="tram",a=p?0:i.BALLAST_HEIGHT_M,l=i.LIFT_M,M=(E,O,u)=>({x:n.centre[E].x-n.dir[E].z*O,y:n.y[E]+u,z:n.centre[E].z+n.dir[E].x*O}),h=n.centre.map((E,O)=>O);if(!p){const E=i.SLEEPER_LENGTH_M/2+i.BALLAST_SHOULDER_M+(r[r.length-1]??0),O=h.map(A=>M(A,E,a+l)),u=h.map(A=>M(A,-E,a+l));if(s.ballast.strip(O,u),t.level===0){const A=E+a*i.BALLAST_SLOPE;for(const f of[1,-1]){const v=[],x=[];let m=!1;for(const z of h){const S=M(z,f*A,l),C=e(S.x,S.z)+l,T=S.y-C;T<0&&(S.y=Math.min(C,n.y[z]+a-.05+l)),v.push(S);const I=M(z,f*(A+Math.max(0,T)*i.BANK_SLOPE),l);I.y=Math.min(e(I.x,I.z)+l,S.y),S.y-I.y>.02&&(m=!0),x.push(I)}const _=f>0?O:u;f>0?s.ballast.strip(v,_):s.ballast.strip(_,v),m&&(f>0?s.earth.strip(x,v):s.earth.strip(v,x))}}else{const A=-i.DECK_DEPTH_M,f=E+.15,v=h.map(z=>M(z,f,a+l+.1)),x=h.map(z=>M(z,-f,a+l+.1)),m=h.map(z=>M(z,f,A)),_=h.map(z=>M(z,-f,A));s.deck.strip(m,v),s.deck.strip(x,_),s.deck.strip(_,m),s.deck.strip(v,h.map(z=>M(z,E,a+l+.1))),s.deck.strip(h.map(z=>M(z,-E,a+l+.1)),x)}}const d=t.service?s.wood:s.concrete,L=t.gaugeMm/2e3+i.RAIL_HEAD_M/2,g=p?i.TRAM_RAIL_HEIGHT_M:i.RAIL_HEIGHT_M,D=a+l;for(const E of r){if(!p){const O=i.SLEEPER_LENGTH_M/2;d.strip(h.map(u=>M(u,E+O,D+.004)),h.map(u=>M(u,E-O,D+.004)),n.along)}for(const O of[1,-1]){const u=E+O*L,A=i.RAIL_HEAD_M/2,f=h.map(x=>M(x,u+A,D+g)),v=h.map(x=>M(x,u-A,D+g));s.head.strip(f,v),s.rust.strip(h.map(x=>M(x,u+A,D)),f),s.rust.strip(v,h.map(x=>M(x,u-A,D)))}}t.electrification==="overhead"&&t.kind!=="subway"&&t.kind!=="funicular"&&this.catenary(t,n,r,D+g,M,e,s)}catenary(t,n,e,s,o,c,r){const p=i.catenaryOf(t),a=n.along[n.along.length-1],l=Math.max(1,Math.round(a/p.spanM)),M=a/l,h=Array.from({length:l},(f,v)=>(v+.5)*M),d=s+p.contactM,L=d+p.systemM,g=(p.systemM>0?L:d)+i.MAST_ABOVE_M,D=e[e.length-1],E=e.length>2,O=e.length===1?[1]:[1,-1],u=(f,v,x)=>{let m=0,_=n.along.length-2;for(;m<_;){const T=m+_+1>>1;n.along[T]<=f?m=T:_=T-1}const z=Math.min(1,Math.max(0,(f-n.along[m])/Math.max(1e-6,n.along[m+1]-n.along[m]))),S=o(m,v,x),C=o(m+1,v,x);return{x:S.x+(C.x-S.x)*z,y:S.y+(C.y-S.y)*z,z:S.z+(C.z-S.z)*z}};for(const f of h){const v=u(f,0,d);if(!(t.level===0&&c(v.x,v.z)>v.y)){for(const x of O){const m=x*(D+i.MAST_OFFSET_M),_=u(f,m,0);t.level===0&&(_.y=Math.min(_.y,c(_.x,_.z)));const z=u(f,m,g);if(r.steel.beam(_,z,i.MAST_SIDE_M),E)continue;const C=(O.length===1?e[0]:x*D)-x*.6,T=p.systemM>0?L:d+.3;r.steel.beam(u(f,m,T),u(f,C,T),i.ARM_SIDE_M),r.steel.beam(u(f,m,d-.4),u(f,C,T),i.ARM_SIDE_M)}if(E){const x=D+i.MAST_OFFSET_M;r.steel.beam(u(f,x,g-.2),u(f,-x,g-.2),i.MAST_SIDE_M*.8)}}}const A=[0,...h,a];for(const[f,v]of e.entries()){const x=m=>m===0||m===A.length-1?0:((m+f)%2===0?1:-1)*p.staggerM;for(let m=0;m<A.length-1;m++){const _=A[m],z=A[m+1];if(z-_<.1||(r.wire.beam(u(_,v+x(m),d),u(z,v+x(m+1),d),i.CONTACT_DIAMETER_M,!1),p.systemM<=0))continue;const S=4,C=T=>{const I=m===0?.5+T/2:m===A.length-2?T/2:T;return L-i.MESSENGER_SAG_M*4*I*(1-I)};for(let T=0;T<S;T++){const I=T/S,G=(T+1)/S;r.wire.beam(u(_+(z-_)*I,v,C(I)),u(_+(z-_)*G,v,C(G)),i.MESSENGER_DIAMETER_M,!1)}}}}static meshOf(t,n){if(t.indices.length===0)return;const e=new w;return e.setAttribute("position",new N(new Float32Array(t.positions),3)),t.along.length>0&&e.setAttribute("aAlong",new N(new Float32Array(t.along),1)),e.setIndex(new N(new Uint32Array(t.indices),1)),e.computeVertexNormals(),new U(e,n)}static lambert(t,n){return new k({color:new H(...t),...n?{polygonOffset:!0,polygonOffsetFactor:-2,polygonOffsetUnits:-2}:{}})}static pebbled(t){return t.onBeforeCompile=n=>{n.vertexShader=n.vertexShader.replace("#include <common>",`#include <common>
2
+ varying vec3 vBallast;`).replace("#include <begin_vertex>",`#include <begin_vertex>
3
+ vBallast = position;`),n.fragmentShader=n.fragmentShader.replace("#include <common>",`#include <common>
4
+ varying vec3 vBallast;
5
+ float ballastHash(vec2 p) {
6
+ p = fract(p * vec2(127.1, 311.7));
7
+ p += dot(p, p + 34.5);
8
+ return fract(p.x * p.y);
9
+ }
10
+ float ballastNoise(vec2 p) {
11
+ vec2 i = floor(p);
12
+ vec2 f = fract(p);
13
+ f = f * f * (3.0 - 2.0 * f);
14
+ return mix(mix(ballastHash(i), ballastHash(i + vec2(1.0, 0.0)), f.x), mix(ballastHash(i + vec2(0.0, 1.0)), ballastHash(i + vec2(1.0, 1.0)), f.x), f.y);
15
+ }`).replace("#include <map_fragment>",`#include <map_fragment>
16
+ {
17
+ float eye = length(vViewPosition);
18
+ vec2 at = vBallast.xz + vec2(0.0, vBallast.y);
19
+ float stones = (ballastHash(floor(at * 22.0)) - 0.5) * 0.9 * (1.0 - smoothstep(4.0, 18.0, eye))
20
+ + (ballastNoise(at * 6.0) - 0.5) * 0.5 * (1.0 - smoothstep(15.0, 60.0, eye))
21
+ + (ballastNoise(at * 0.7) - 0.5) * 0.35 * (1.0 - smoothstep(80.0, 300.0, eye));
22
+ diffuseColor.rgb *= 1.0 + stones;
23
+ }`)},t.customProgramCacheKey=()=>"rr0-railway-ballast",t}static sleeperMaterial(t){const n=new k({color:new H(1,1,1),polygonOffset:!0,polygonOffsetFactor:-3,polygonOffsetUnits:-3}),e=new H(...t),s=new H(...i.BALLAST_ALBEDO);return n.onBeforeCompile=o=>{o.uniforms.uSleeper={value:e},o.uniforms.uCrib={value:s},o.uniforms.uSpacing={value:i.SLEEPER_SPACING_M},o.uniforms.uDuty={value:i.SLEEPER_WIDTH_M/i.SLEEPER_SPACING_M},o.vertexShader=o.vertexShader.replace("#include <common>",`#include <common>
24
+ attribute float aAlong;
25
+ varying float vAlong;`).replace("#include <begin_vertex>",`#include <begin_vertex>
26
+ vAlong = aAlong;`),o.fragmentShader=o.fragmentShader.replace("#include <common>",`#include <common>
27
+ varying float vAlong;
28
+ uniform vec3 uSleeper;
29
+ uniform vec3 uCrib;
30
+ uniform float uSpacing;
31
+ uniform float uDuty;
32
+ // How much of [0, x] periods is sleeper: the integral of a pulse of width uDuty at the start of each period.
33
+ float sleeperIntegral(float x) {
34
+ return floor(x) * uDuty + min(fract(x), uDuty);
35
+ }`).replace("#include <map_fragment>",`#include <map_fragment>
36
+ {
37
+ float u = vAlong / uSpacing;
38
+ float w = max(fwidth(u), 1e-4);
39
+ float cover = (sleeperIntegral(u + 0.5 * w) - sleeperIntegral(u - 0.5 * w)) / w;
40
+ diffuseColor.rgb *= mix(uCrib, uSleeper, clamp(cover, 0.0, 1.0));
41
+ }`)},n.customProgramCacheKey=()=>"rr0-railway-sleepers",n}}export{i as RailwaySystem};
@@ -1 +1 @@
1
- import{a5 as D}from"./rr0-sighting-editor.mjs";class M{static MIN_ROAD_M=5.5;static WIDE_ROAD_M=9;static LINE_WIDTH_M=.12;static DASH_M=3;static GAP_M=10;static RIVE_DASH_M=2.5;static RIVE_GAP_M=3.5;static MIN_DASH_M=.5;static LANE_M=3.5;static SHOULDER_MIN_M=1.5;static SOLID_EDGE_FROM_M=7;static SOLID_EDGE_FROM_KMH=80;static BEND_RADIUS_M=300;static EDGE_SETBACK_M=.4;static PAINT_RADIUS_M=450;static LIFT_M=.015;static BARRIER_MAX_AXES_M=40;static BARRIER_MIN_AXES_M=5;static BARRIER_HEIGHT_M=.8;static BARRIER_HALF_WIDTH_M=.2;static BARRIER_STEP_M=4;static painted(t){return t.surface==="paved"&&t.widthM>=M.MIN_ROAD_M&&t.kind!=="roundabout"}static plan(t){if(!M.painted(t))return[];const u=t.widthM,l=u/2,i=M.EDGE_SETBACK_M;if(!(t.direction!==void 0&&t.lanes!==void 0)){const I=[{offsetM:l-i,pattern:"solid"},{offsetM:-(l-i),pattern:"solid"}],A=u>=M.WIDE_ROAD_M?[-u/4,u/4]:[0];for(const x of A)I.push({offsetM:x,pattern:"dashed"});return I}const s=t.lanes,n=u>=M.SOLID_EDGE_FROM_M||(t.speedKmh??0)>=M.SOLID_EDGE_FROM_KMH?"solid":"rive";if(t.direction==="both"){if(s<2)return[];const I=[{offsetM:l-i,pattern:n},{offsetM:-(l-i),pattern:n}];if(s>=4){I.push({offsetM:.1,pattern:"solid"},{offsetM:-.1,pattern:"solid"});const A=Math.floor(s/2),x=u/s;for(let z=1;z<A;z++)I.push({offsetM:z*x,pattern:"dashed"},{offsetM:-z*x,pattern:"dashed"})}else I.push({offsetM:0,pattern:"dashed",solidInBends:!0});return I}const r=t.direction==="backward"?-1:1,o=I=>r*(l-I),c=Math.min(M.LANE_M,u/Math.max(s,1)),h=s*c,d=u-h,_=(t.kind==="motorway"||t.kind==="dual")&&d>=M.SHOULDER_MIN_M,E=[{offsetM:o(i),pattern:t.kind==="motorway"||t.kind==="dual"?"solid":n}];E.push({offsetM:o(_?h:u-i),pattern:t.kind==="motorway"||t.kind==="dual"?"solid":n});for(let I=1;I<s;I++)E.push({offsetM:o(I*c),pattern:"dashed"});return E}static lay(t,u,l,i){let e=0;const s=(f,n)=>{i(f,M.LINE_WIDTH_M,{offsetM:n,liftM:M.LIFT_M,minHalfM:M.LINE_WIDTH_M/2}),e++};for(const f of t){const n=M.plan(f);if(n.length===0)continue;const r=f.points.map(o=>D(o.lat,o.lng,u,l));for(const o of M.near(r,M.PAINT_RADIUS_M))for(const c of n){if(c.pattern==="solid"){s(o,c.offsetM);continue}const[h,d]=c.pattern==="dashed"?[M.DASH_M,M.GAP_M]:[M.RIVE_DASH_M,M.RIVE_GAP_M];for(const _ of c.solidInBends?M.byBends(o):[{path:o,bend:!1}])if(_.bend)s(_.path,c.offsetM);else for(const E of M.dashes(_.path,h,d))s(E,c.offsetM)}}return e}static byBends(t){if(t.length<3)return[{path:t,bend:!1}];const u=(e,s)=>Math.atan2(s.x-e.x,-(s.z-e.z)),l=new Array(t.length-1).fill(!1);for(let e=1;e<t.length-1;e++){const s=Math.hypot(t[e].x-t[e-1].x,t[e].z-t[e-1].z),f=Math.hypot(t[e+1].x-t[e].x,t[e+1].z-t[e].z);if(s<1e-6||f<1e-6)continue;let n=Math.abs(u(t[e],t[e+1])-u(t[e-1],t[e]));n>Math.PI&&(n=2*Math.PI-n),(s+f)/2/Math.max(n,1e-6)<M.BEND_RADIUS_M&&(l[e-1]=!0,l[e]=!0)}const i=[];for(let e=0;e<l.length;e++){const s=i.at(-1);s&&s.bend===l[e]?s.path.push(t[e+1]):i.push({path:[t[e],t[e+1]],bend:l[e]})}return i}static barriers(t,u,l){const i=t.filter(n=>(n.kind==="motorway"||n.kind==="dual")&&(n.direction==="forward"||n.direction==="backward")),e=i.map(n=>{const r=n.points.map(o=>D(o.lat,o.lng,u,l));return n.direction==="backward"?[...r].reverse():r}),s=[],f=M.BARRIER_STEP_M;return i.forEach((n,r)=>{for(const o of M.near(e[r],M.PAINT_RADIUS_M)){let c=[];for(const h of M.resample(o,f)){const d=M.midwayToOpposite(h,r,i,e);d?c.push(d):c.length>0&&(c.length>=2&&s.push(c),c=[])}c.length>=2&&s.push(c)}}),s}static midwayToOpposite(t,u,l,i){let e;for(let s=0;s<i.length;s++){if(s===u||l[s].id<l[u].id)continue;const f=i[s];for(let n=0;n<f.length-1;n++){const r=f[n+1].x-f[n].x,o=f[n+1].z-f[n].z,c=r*r+o*o;if(c<1e-9||(r*t.dx+o*t.dz)/Math.sqrt(c)>-.9)continue;const h=Math.max(0,Math.min(1,((t.x-f[n].x)*r+(t.z-f[n].z)*o)/c)),d={x:f[n].x+r*h,z:f[n].z+o*h},_=Math.hypot(t.x-d.x,t.z-d.z);_<M.BARRIER_MIN_AXES_M||_>M.BARRIER_MAX_AXES_M||(!e||_<e.distance)&&(e={distance:_,point:d})}}return e?{x:(t.x+e.point.x)/2,z:(t.z+e.point.z)/2}:void 0}static resample(t,u){const l=[];for(let e=0;e<t.length-1;e++){const s=Math.hypot(t[e+1].x-t[e].x,t[e+1].z-t[e].z);if(s<1e-6)continue;const f=(t[e+1].x-t[e].x)/s,n=(t[e+1].z-t[e].z)/s;for(let r=0;r<s;r+=u)l.push({x:t[e].x+f*r,z:t[e].z+n*r,dx:f,dz:n})}const i=l.at(-1);return i&&l.push({...t[t.length-1],dx:i.dx,dz:i.dz}),l}static barrierGeometry(t,u){const l=[],i=[],e=M.BARRIER_HALF_WIDTH_M;for(const s of t){if(s.length<2)continue;const f=l.length/3;for(let n=0;n<s.length;n++){const r=s[Math.max(0,n-1)],o=s[Math.min(s.length-1,n+1)],c=Math.hypot(o.x-r.x,o.z-r.z)||1,h=-(o.z-r.z)/c*e,d=(o.x-r.x)/c*e,_=u(s[n].x,s[n].z);l.push(s[n].x+h,_,s[n].z+d,s[n].x+h,_+M.BARRIER_HEIGHT_M,s[n].z+d,s[n].x-h,_+M.BARRIER_HEIGHT_M,s[n].z-d,s[n].x-h,_,s[n].z-d)}for(let n=0;n<s.length-1;n++){const r=f+n*4,o=r+4;for(let c=0;c<3;c++)i.push(r+c,o+c,r+c+1,r+c+1,o+c,o+c+1)}}return{positions:l,indices:i}}static near(t,u){const l=[];let i;for(let e=0;e<t.length-1;e++)Math.min(Math.hypot(t[e].x,t[e].z),Math.hypot(t[e+1].x,t[e+1].z))<=u||Math.hypot((t[e].x+t[e+1].x)/2,(t[e].z+t[e+1].z)/2)<=u?(i||(i=[t[e]]),i.push(t[e+1])):i&&(l.push(i),i=void 0);return i&&l.push(i),l}static dashes(t,u,l){const i=[],e=u+l;let s=0,f;const n=(o,c)=>({x:t[o].x+(t[o+1].x-t[o].x)*c,z:t[o].z+(t[o+1].z-t[o].z)*c});for(let o=0;o<t.length-1;o++){const c=Math.hypot(t[o+1].x-t[o].x,t[o+1].z-t[o].z);if(c<1e-6)continue;let h=0;for(;h<c;){const d=(s+h)%e,_=d<u,E=_?u-d:e-d,I=Math.min(c,h+E);_&&(f||(f=[n(o,h/c)]),f.push(n(o,I/c)),I-h>=E-1e-9&&(i.push(f),f=void 0)),h=I}s+=c}f&&f.length>=2&&i.push(f);const r=o=>o.slice(1).reduce((c,h,d)=>c+Math.hypot(h.x-o[d].x,h.z-o[d].z),0);return i.filter(o=>o.length>=2&&r(o)>=M.MIN_DASH_M)}}export{M as RoadMarkings};
1
+ import{a7 as D}from"./rr0-sighting-editor.mjs";class M{static MIN_ROAD_M=5.5;static WIDE_ROAD_M=9;static LINE_WIDTH_M=.12;static DASH_M=3;static GAP_M=10;static RIVE_DASH_M=2.5;static RIVE_GAP_M=3.5;static MIN_DASH_M=.5;static LANE_M=3.5;static SHOULDER_MIN_M=1.5;static SOLID_EDGE_FROM_M=7;static SOLID_EDGE_FROM_KMH=80;static BEND_RADIUS_M=300;static EDGE_SETBACK_M=.4;static PAINT_RADIUS_M=450;static LIFT_M=.015;static BARRIER_MAX_AXES_M=40;static BARRIER_MIN_AXES_M=5;static BARRIER_HEIGHT_M=.8;static BARRIER_HALF_WIDTH_M=.2;static BARRIER_STEP_M=4;static painted(t){return t.surface==="paved"&&t.widthM>=M.MIN_ROAD_M&&t.kind!=="roundabout"}static plan(t){if(!M.painted(t))return[];const u=t.widthM,l=u/2,i=M.EDGE_SETBACK_M;if(!(t.direction!==void 0&&t.lanes!==void 0)){const I=[{offsetM:l-i,pattern:"solid"},{offsetM:-(l-i),pattern:"solid"}],A=u>=M.WIDE_ROAD_M?[-u/4,u/4]:[0];for(const x of A)I.push({offsetM:x,pattern:"dashed"});return I}const s=t.lanes,n=u>=M.SOLID_EDGE_FROM_M||(t.speedKmh??0)>=M.SOLID_EDGE_FROM_KMH?"solid":"rive";if(t.direction==="both"){if(s<2)return[];const I=[{offsetM:l-i,pattern:n},{offsetM:-(l-i),pattern:n}];if(s>=4){I.push({offsetM:.1,pattern:"solid"},{offsetM:-.1,pattern:"solid"});const A=Math.floor(s/2),x=u/s;for(let z=1;z<A;z++)I.push({offsetM:z*x,pattern:"dashed"},{offsetM:-z*x,pattern:"dashed"})}else I.push({offsetM:0,pattern:"dashed",solidInBends:!0});return I}const r=t.direction==="backward"?-1:1,o=I=>r*(l-I),c=Math.min(M.LANE_M,u/Math.max(s,1)),h=s*c,d=u-h,_=(t.kind==="motorway"||t.kind==="dual")&&d>=M.SHOULDER_MIN_M,E=[{offsetM:o(i),pattern:t.kind==="motorway"||t.kind==="dual"?"solid":n}];E.push({offsetM:o(_?h:u-i),pattern:t.kind==="motorway"||t.kind==="dual"?"solid":n});for(let I=1;I<s;I++)E.push({offsetM:o(I*c),pattern:"dashed"});return E}static lay(t,u,l,i){let e=0;const s=(f,n)=>{i(f,M.LINE_WIDTH_M,{offsetM:n,liftM:M.LIFT_M,minHalfM:M.LINE_WIDTH_M/2}),e++};for(const f of t){const n=M.plan(f);if(n.length===0)continue;const r=f.points.map(o=>D(o.lat,o.lng,u,l));for(const o of M.near(r,M.PAINT_RADIUS_M))for(const c of n){if(c.pattern==="solid"){s(o,c.offsetM);continue}const[h,d]=c.pattern==="dashed"?[M.DASH_M,M.GAP_M]:[M.RIVE_DASH_M,M.RIVE_GAP_M];for(const _ of c.solidInBends?M.byBends(o):[{path:o,bend:!1}])if(_.bend)s(_.path,c.offsetM);else for(const E of M.dashes(_.path,h,d))s(E,c.offsetM)}}return e}static byBends(t){if(t.length<3)return[{path:t,bend:!1}];const u=(e,s)=>Math.atan2(s.x-e.x,-(s.z-e.z)),l=new Array(t.length-1).fill(!1);for(let e=1;e<t.length-1;e++){const s=Math.hypot(t[e].x-t[e-1].x,t[e].z-t[e-1].z),f=Math.hypot(t[e+1].x-t[e].x,t[e+1].z-t[e].z);if(s<1e-6||f<1e-6)continue;let n=Math.abs(u(t[e],t[e+1])-u(t[e-1],t[e]));n>Math.PI&&(n=2*Math.PI-n),(s+f)/2/Math.max(n,1e-6)<M.BEND_RADIUS_M&&(l[e-1]=!0,l[e]=!0)}const i=[];for(let e=0;e<l.length;e++){const s=i.at(-1);s&&s.bend===l[e]?s.path.push(t[e+1]):i.push({path:[t[e],t[e+1]],bend:l[e]})}return i}static barriers(t,u,l){const i=t.filter(n=>(n.kind==="motorway"||n.kind==="dual")&&(n.direction==="forward"||n.direction==="backward")),e=i.map(n=>{const r=n.points.map(o=>D(o.lat,o.lng,u,l));return n.direction==="backward"?[...r].reverse():r}),s=[],f=M.BARRIER_STEP_M;return i.forEach((n,r)=>{for(const o of M.near(e[r],M.PAINT_RADIUS_M)){let c=[];for(const h of M.resample(o,f)){const d=M.midwayToOpposite(h,r,i,e);d?c.push(d):c.length>0&&(c.length>=2&&s.push(c),c=[])}c.length>=2&&s.push(c)}}),s}static midwayToOpposite(t,u,l,i){let e;for(let s=0;s<i.length;s++){if(s===u||l[s].id<l[u].id)continue;const f=i[s];for(let n=0;n<f.length-1;n++){const r=f[n+1].x-f[n].x,o=f[n+1].z-f[n].z,c=r*r+o*o;if(c<1e-9||(r*t.dx+o*t.dz)/Math.sqrt(c)>-.9)continue;const h=Math.max(0,Math.min(1,((t.x-f[n].x)*r+(t.z-f[n].z)*o)/c)),d={x:f[n].x+r*h,z:f[n].z+o*h},_=Math.hypot(t.x-d.x,t.z-d.z);_<M.BARRIER_MIN_AXES_M||_>M.BARRIER_MAX_AXES_M||(!e||_<e.distance)&&(e={distance:_,point:d})}}return e?{x:(t.x+e.point.x)/2,z:(t.z+e.point.z)/2}:void 0}static resample(t,u){const l=[];for(let e=0;e<t.length-1;e++){const s=Math.hypot(t[e+1].x-t[e].x,t[e+1].z-t[e].z);if(s<1e-6)continue;const f=(t[e+1].x-t[e].x)/s,n=(t[e+1].z-t[e].z)/s;for(let r=0;r<s;r+=u)l.push({x:t[e].x+f*r,z:t[e].z+n*r,dx:f,dz:n})}const i=l.at(-1);return i&&l.push({...t[t.length-1],dx:i.dx,dz:i.dz}),l}static barrierGeometry(t,u){const l=[],i=[],e=M.BARRIER_HALF_WIDTH_M;for(const s of t){if(s.length<2)continue;const f=l.length/3;for(let n=0;n<s.length;n++){const r=s[Math.max(0,n-1)],o=s[Math.min(s.length-1,n+1)],c=Math.hypot(o.x-r.x,o.z-r.z)||1,h=-(o.z-r.z)/c*e,d=(o.x-r.x)/c*e,_=u(s[n].x,s[n].z);l.push(s[n].x+h,_,s[n].z+d,s[n].x+h,_+M.BARRIER_HEIGHT_M,s[n].z+d,s[n].x-h,_+M.BARRIER_HEIGHT_M,s[n].z-d,s[n].x-h,_,s[n].z-d)}for(let n=0;n<s.length-1;n++){const r=f+n*4,o=r+4;for(let c=0;c<3;c++)i.push(r+c,o+c,r+c+1,r+c+1,o+c,o+c+1)}}return{positions:l,indices:i}}static near(t,u){const l=[];let i;for(let e=0;e<t.length-1;e++)Math.min(Math.hypot(t[e].x,t[e].z),Math.hypot(t[e+1].x,t[e+1].z))<=u||Math.hypot((t[e].x+t[e+1].x)/2,(t[e].z+t[e+1].z)/2)<=u?(i||(i=[t[e]]),i.push(t[e+1])):i&&(l.push(i),i=void 0);return i&&l.push(i),l}static dashes(t,u,l){const i=[],e=u+l;let s=0,f;const n=(o,c)=>({x:t[o].x+(t[o+1].x-t[o].x)*c,z:t[o].z+(t[o+1].z-t[o].z)*c});for(let o=0;o<t.length-1;o++){const c=Math.hypot(t[o+1].x-t[o].x,t[o+1].z-t[o].z);if(c<1e-6)continue;let h=0;for(;h<c;){const d=(s+h)%e,_=d<u,E=_?u-d:e-d,I=Math.min(c,h+E);_&&(f||(f=[n(o,h/c)]),f.push(n(o,I/c)),I-h>=E-1e-9&&(i.push(f),f=void 0)),h=I}s+=c}f&&f.length>=2&&i.push(f);const r=o=>o.slice(1).reduce((c,h,d)=>c+Math.hypot(h.x-o[d].x,h.z-o[d].z),0);return i.filter(o=>o.length>=2&&r(o)>=M.MIN_DASH_M)}}export{M as RoadMarkings};
@@ -1 +1 @@
1
- import{V as a,D as o}from"./rr0-sighting-editor.mjs";const l={bodies:{sun:"Sol",moon:"Luna",Venus:"Venus",Mars:"Marte",Jupiter:"Júpiter",Saturn:"Saturno"},stars:{Sirius:"Sirio",Canopus:"Canopo",Arcturus:"Arturo",Capella:"Capela",Procyon:"Proción",Aldebaran:"Aldebarán",Spica:"Espiga",Pollux:"Pólux",Castor:"Cástor",Regulus:"Régulo"},comets:{"halley-1910":"cometa Halley","brooks-1911":"cometa Brooks","skjellerup-maristany-1927":"cometa Skjellerup-Maristany","de-kock-paraskevopoulos-1941":"cometa de Kock-Paraskevopoulos","southern-1947":"cometa austral","eclipse-1948":"cometa del eclipse","arend-roland-1957":"cometa Arend-Roland","mrkos-1957":"cometa Mrkos","seki-lines-1962":"cometa Seki-Lines","ikeya-seki-1965":"cometa Ikeya-Seki","bennett-1970":"cometa Bennett","white-ortiz-bolelli-1970":"cometa White-Ortiz-Bolelli","kohoutek-1973":"cometa Kohoutek","west-1976":"cometa West","iras-araki-alcock-1983":"cometa IRAS-Araki-Alcock","halley-1986":"cometa Halley","hyakutake-1996":"cometa Hyakutake","hale-bopp-1997":"cometa Hale-Bopp","mcnaught-2007":"cometa McNaught","lovejoy-2011":"cometa Lovejoy","panstarrs-2013":"cometa PANSTARRS","neowise-2020":"cometa NEOWISE","tsuchinshan-atlas-2024":"cometa Tsuchinshan-ATLAS"},novae:{"sn-1006":"supernova de 1006","sn-1054":"supernova de 1054","sn-1181":"supernova de 1181","sn-1572":"supernova de Tycho","sn-1604":"supernova de Kepler","t-crb-1866":"nova de la Corona Boreal 1866","t-aur-1891":"nova de Auriga 1891","gk-per-1901":"nova de Perseo 1901","dn-gem-1912":"nova de Géminis 1912","v603-aql-1918":"nova del Águila 1918","v476-cyg-1920":"nova del Cisne 1920","rr-pic-1925":"nova del Pintor 1925","dq-her-1934":"nova de Hércules 1934","cp-lac-1936":"nova del Lagarto 1936","cp-pup-1942":"nova de la Popa 1942","t-crb-1946":"nova de la Corona Boreal 1946","v446-her-1960":"nova de Hércules 1960","v533-her-1963":"nova de Hércules 1963","hr-del-1967":"nova del Delfín 1967","lv-vul-1968":"nova de la Zorra 1968","fh-ser-1970":"nova de la Serpiente 1970","v1500-cyg-1975":"nova del Cisne 1975","v842-cen-1986":"nova del Centauro 1986","sn-1987a":"supernova 1987A","v1974-cyg-1992":"nova del Cisne 1992","v382-vel-1999":"nova de las Velas 1999","v1494-aql-1999":"nova del Águila 1999","v4743-sgr-2002":"nova de Sagitario 2002","rs-oph-2006":"nova de Ofiuco 2006","v1280-sco-2007":"nova de Escorpio 2007","v339-del-2013":"nova del Delfín 2013","v1369-cen-2013":"nova del Centauro 2013","rs-oph-2021":"nova de Ofiuco 2021"},satelliteClasses:{echo:"los globos Echo","iridium-flares":"los destellos de los Iridium",iss:"la Estación Espacial Internacional","starlink-trains":"los trenes de Starlink"},showers:{quadrantids:"Cuadrántidas",lyrids:"Líridas de abril","eta-aquariids":"Eta Acuáridas","alpha-capricornids":"Alfa Capricórnidas","southern-delta-aquariids":"Delta Acuáridas del Sur",perseids:"Perseidas","southern-taurids":"Táuridas del Sur",draconids:"Dracónidas de octubre",orionids:"Oriónidas","northern-taurids":"Táuridas del Norte",leonids:"Leónidas",geminids:"Gemínidas",ursids:"Úrsidas"},lightRigs:{airliner:"Avión de pasajeros",helicopter:"Helicóptero","car-headlights":"Coche, faros encendidos","car-hazards":"Coche, luces de emergencia","emergency-beacons":"Rotativos de vehículo de emergencia","traffic-signal":"Semáforo","pedestrian-signal":"Semáforo peatonal",streetlamp:"Farola"},instruments:{eye:"A simple vista","rectilinear-lens":"Cámara, modelo desconocido","roamer-1-120":"Roamer 1, película 120","instamatic-126":"Instamatic, película 126","slr-35mm-50":"Réflex 35 mm, objetivo 50 mm","slr-35mm-zoom":"Réflex 35 mm, zoom 70-210 mm","phone-landscape":"Teléfono, en horizontal","phone-portrait":"Teléfono, en vertical",...o.names(),...a.names()},decorKinds:{building:"Edificio",tree:"Árbol",shrub:"Arbusto",bridge:"Puente",wire:"Línea aérea",crop:"Hilera de cultivo",terrace:"Bancal (terraza)",mound:"Montón de piedras",wall:"Muro de piedra seca",streetlight:"Farola",trafficlight:"Semáforo",crossing:"Paso de peatones",roadsign:"Señal de tráfico",vehicle:"Vehículo",observer:"Observador",aircraft:"Aeronave",entity:"Ser"},compassPoints:["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSO","SO","OSO","O","ONO","NO","NNO"],towards:e=>`al ${e}`,starTooltip:"{name} — mag {mag}, {alt}° sobre el horizonte",starTooltipBelow:"{name} — mag {mag}, {alt}° bajo la horizontal",decorTooltip:"{name} — {size}, a {distance}",satelliteTooltip:"{name} — satélite, mag {mag}, a {height} km de altitud",opticsTooltips:{halo22:"Halo de 22° — un anillo alrededor del Sol, por luz desviada en cristales de hielo hexagonales de los cirros; su borde interior es rojo, a 21,7°",halo46:"Halo de 46° — un anillo más raro y débil: la luz entra por una cara lateral del cristal y sale por una cara del extremo",oddRadius:"Halo de {angle}° — un anillo de radio impar, raro y débil, hecho por cristales de hielo con extremos piramidales",parhelion:"Parhelio — una mancha brillante de colores junto al Sol, a su altura, por placas de hielo que caen planas; rojo hacia el Sol",parhelion120:"Parhelio de 120° — una mancha blanca débil a 120° del Sol, por luz reflejada dentro de placas planas",upperTangentArc:"Arco tangente superior — un arco brillante apoyado sobre el halo de 22°, por columnas tumbadas en horizontal",lowerTangentArc:"Arco tangente inferior — un arco que toca la base del halo de 22°, por columnas tumbadas en horizontal",circumzenithal:"Arco circuncenital — una banda de colores vivos cerca del cenit, por luz que entra por la cara superior de placas planas (solo con el Sol bajo 32°)",circumhorizontal:"Arco circunhorizontal — una banda de colores baja en el cielo, por luz que entra por la cara lateral de placas planas (solo con el Sol sobre 58°)",parhelicCircle:"Círculo parhélico — un círculo blanco alrededor de todo el cielo a la altura del Sol, por reflejos en las caras verticales de placas planas",pillar:"Pilar de luz — una columna de luz sobre el Sol, por reflejos en placas planas ligeramente inclinadas",subsun:"Subsol — una imagen del Sol bajo el horizonte, por reflejos en las caras planas de las placas"},trafficTooltip:{unnamed:"Aeronave {hex}",altitude:"{value} ft",speed:"{value} kt",heading:"rumbo {value}°",position:"a {distance} km, {elevation}° sobre el horizonte, {bearing}",heard:"Se oye a {level} dB(A), salió del avión hace {delay} s, {lag}° detrás de él: {character}{pitch}",rumble:"un rumor grave, nada por encima de {cutoff} Hz",muffled:"un ruido sordo, nada por encima de {cutoff} Hz",broad:"un rugido ancho",pitchHigher:", sonido {percent} % más agudo",pitchLower:", sonido {percent} % más grave",inaudible:"Inaudible aquí: {level} dB(A) frente a {ambient} dB(A) de ruido ambiente",soundUnknown:"Sonido no calculable: el avión aún no estaba registrado cuando salió",contrailPersistent:"Deja una estela que dura: el aire está sobresaturado respecto al hielo ({rhi} % respecto al hielo)",contrailShort:"Deja una estela breve: el aire está seco respecto al hielo ({rhi} % respecto al hielo)",military:"militar",restricted:"identidad oculta por su propietario",candidate:"Un candidato compatible, no una identificación"},credits:"Créditos",notAVideo:"Esto no es un vídeo",isASimulation:"Es una simulación en tiempo real."};export{l as sceneNames_es};
1
+ import{V as a,D as o}from"./rr0-sighting-editor.mjs";const l={bodies:{sun:"Sol",moon:"Luna",Venus:"Venus",Mars:"Marte",Jupiter:"Júpiter",Saturn:"Saturno"},stars:{Sirius:"Sirio",Canopus:"Canopo",Arcturus:"Arturo",Capella:"Capela",Procyon:"Proción",Aldebaran:"Aldebarán",Spica:"Espiga",Pollux:"Pólux",Castor:"Cástor",Regulus:"Régulo"},comets:{"halley-1910":"cometa Halley","brooks-1911":"cometa Brooks","skjellerup-maristany-1927":"cometa Skjellerup-Maristany","de-kock-paraskevopoulos-1941":"cometa de Kock-Paraskevopoulos","southern-1947":"cometa austral","eclipse-1948":"cometa del eclipse","arend-roland-1957":"cometa Arend-Roland","mrkos-1957":"cometa Mrkos","seki-lines-1962":"cometa Seki-Lines","ikeya-seki-1965":"cometa Ikeya-Seki","bennett-1970":"cometa Bennett","white-ortiz-bolelli-1970":"cometa White-Ortiz-Bolelli","kohoutek-1973":"cometa Kohoutek","west-1976":"cometa West","iras-araki-alcock-1983":"cometa IRAS-Araki-Alcock","halley-1986":"cometa Halley","hyakutake-1996":"cometa Hyakutake","hale-bopp-1997":"cometa Hale-Bopp","mcnaught-2007":"cometa McNaught","lovejoy-2011":"cometa Lovejoy","panstarrs-2013":"cometa PANSTARRS","neowise-2020":"cometa NEOWISE","tsuchinshan-atlas-2024":"cometa Tsuchinshan-ATLAS"},novae:{"sn-1006":"supernova de 1006","sn-1054":"supernova de 1054","sn-1181":"supernova de 1181","sn-1572":"supernova de Tycho","sn-1604":"supernova de Kepler","t-crb-1866":"nova de la Corona Boreal 1866","t-aur-1891":"nova de Auriga 1891","gk-per-1901":"nova de Perseo 1901","dn-gem-1912":"nova de Géminis 1912","v603-aql-1918":"nova del Águila 1918","v476-cyg-1920":"nova del Cisne 1920","rr-pic-1925":"nova del Pintor 1925","dq-her-1934":"nova de Hércules 1934","cp-lac-1936":"nova del Lagarto 1936","cp-pup-1942":"nova de la Popa 1942","t-crb-1946":"nova de la Corona Boreal 1946","v446-her-1960":"nova de Hércules 1960","v533-her-1963":"nova de Hércules 1963","hr-del-1967":"nova del Delfín 1967","lv-vul-1968":"nova de la Zorra 1968","fh-ser-1970":"nova de la Serpiente 1970","v1500-cyg-1975":"nova del Cisne 1975","v842-cen-1986":"nova del Centauro 1986","sn-1987a":"supernova 1987A","v1974-cyg-1992":"nova del Cisne 1992","v382-vel-1999":"nova de las Velas 1999","v1494-aql-1999":"nova del Águila 1999","v4743-sgr-2002":"nova de Sagitario 2002","rs-oph-2006":"nova de Ofiuco 2006","v1280-sco-2007":"nova de Escorpio 2007","v339-del-2013":"nova del Delfín 2013","v1369-cen-2013":"nova del Centauro 2013","rs-oph-2021":"nova de Ofiuco 2021"},satelliteClasses:{echo:"los globos Echo","iridium-flares":"los destellos de los Iridium",iss:"la Estación Espacial Internacional","starlink-trains":"los trenes de Starlink"},showers:{quadrantids:"Cuadrántidas",lyrids:"Líridas de abril","eta-aquariids":"Eta Acuáridas","alpha-capricornids":"Alfa Capricórnidas","southern-delta-aquariids":"Delta Acuáridas del Sur",perseids:"Perseidas","southern-taurids":"Táuridas del Sur",draconids:"Dracónidas de octubre",orionids:"Oriónidas","northern-taurids":"Táuridas del Norte",leonids:"Leónidas",geminids:"Gemínidas",ursids:"Úrsidas"},lightRigs:{airliner:"Avión de pasajeros",helicopter:"Helicóptero","car-headlights":"Coche, faros encendidos","car-hazards":"Coche, luces de emergencia","emergency-beacons":"Rotativos de vehículo de emergencia","traffic-signal":"Semáforo","pedestrian-signal":"Semáforo peatonal",streetlamp:"Farola"},instruments:{eye:"A simple vista","rectilinear-lens":"Cámara, modelo desconocido","roamer-1-120":"Roamer 1, película 120","instamatic-126":"Instamatic, película 126","slr-35mm-50":"Réflex 35 mm, objetivo 50 mm","slr-35mm-zoom":"Réflex 35 mm, zoom 70-210 mm","phone-landscape":"Teléfono, en horizontal","phone-portrait":"Teléfono, en vertical",...o.names(),...a.names()},decorKinds:{building:"Edificio",tree:"Árbol",shrub:"Arbusto",bridge:"Puente",wire:"Línea aérea",crop:"Hilera de cultivo",terrace:"Bancal (terraza)",mound:"Montón de piedras",wall:"Muro de piedra seca",streetlight:"Farola",trafficlight:"Semáforo",crossing:"Paso de peatones",roadsign:"Señal de tráfico",vehicle:"Vehículo",observer:"Observador",aircraft:"Aeronave",entity:"Ser"},compassPoints:["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSO","SO","OSO","O","ONO","NO","NNO"],towards:e=>`al ${e}`,starTooltip:"{name} — mag {mag}, {alt}° sobre el horizonte",starTooltipBelow:"{name} — mag {mag}, {alt}° bajo la horizontal",decorTooltip:"{name} — {size}, a {distance}",satelliteTooltip:"{name} — satélite, mag {mag}, a {height} km de altitud",opticsTooltips:{halo22:"Halo de 22° — un anillo alrededor del Sol, por luz desviada en cristales de hielo hexagonales de los cirros; su borde interior es rojo, a 21,7°",halo46:"Halo de 46° — un anillo más raro y débil: la luz entra por una cara lateral del cristal y sale por una cara del extremo",oddRadius:"Halo de {angle}° — un anillo de radio impar, raro y débil, hecho por cristales de hielo con extremos piramidales",parhelion:"Parhelio — una mancha brillante de colores junto al Sol, a su altura, por placas de hielo que caen planas; rojo hacia el Sol",parhelion120:"Parhelio de 120° — una mancha blanca débil a 120° del Sol, por luz reflejada dentro de placas planas",upperTangentArc:"Arco tangente superior — un arco brillante apoyado sobre el halo de 22°, por columnas tumbadas en horizontal",lowerTangentArc:"Arco tangente inferior — un arco que toca la base del halo de 22°, por columnas tumbadas en horizontal",circumzenithal:"Arco circuncenital — una banda de colores vivos cerca del cenit, por luz que entra por la cara superior de placas planas (solo con el Sol bajo 32°)",circumhorizontal:"Arco circunhorizontal — una banda de colores baja en el cielo, por luz que entra por la cara lateral de placas planas (solo con el Sol sobre 58°)",parhelicCircle:"Círculo parhélico — un círculo blanco alrededor de todo el cielo a la altura del Sol, por reflejos en las caras verticales de placas planas",pillar:"Pilar de luz — una columna de luz sobre el Sol, por reflejos en placas planas ligeramente inclinadas",subsun:"Subsol — una imagen del Sol bajo el horizonte, por reflejos en las caras planas de las placas"},trafficTooltip:{unnamed:"Aeronave {hex}",altitude:"{value} ft",speed:"{value} kt",heading:"rumbo {value}°",position:"a {distance} km, {elevation}° sobre el horizonte, {bearing}",heard:"Se oye a {level} dB(A), salió del avión hace {delay} s, {lag}° detrás de él: {character}{pitch}",rumble:"un rumor grave, nada por encima de {cutoff} Hz",muffled:"un ruido sordo, nada por encima de {cutoff} Hz",broad:"un rugido ancho",pitchHigher:", sonido {percent} % más agudo",pitchLower:", sonido {percent} % más grave",inaudible:"Inaudible aquí: {level} dB(A) frente a {ambient} dB(A) de ruido ambiente",soundUnknown:"Sonido no calculable: el avión aún no estaba registrado cuando salió",contrailPersistent:"Deja una estela que dura: el aire está sobresaturado respecto al hielo ({rhi} % respecto al hielo)",contrailShort:"Deja una estela breve: el aire está seco respecto al hielo ({rhi} % respecto al hielo)",military:"militar",restricted:"identidad oculta por su propietario",candidate:"Un candidato compatible, no una identificación"},railwayTooltip:{kinds:{rail:"Vía férrea",light_rail:"Metro ligero",tram:"Tranvía",subway:"Metro",funicular:"Funicular"},highSpeed:"Línea de alta velocidad",service:"Vía de servicio",singleTrack:"vía única",tracks:"{count} vías",overhead:"catenaria, hilo de contacto a {height} m sobre el carril",overheadVoltage:"catenaria a {voltage}, hilo de contacto a {height} m sobre el carril",thirdRail:"tercer carril",thirdRailVoltage:"tercer carril a {voltage}",notElectrified:"sin electrificar",gauge:"ancho de {mm} mm",metreGauge:"vía métrica",distance:"a {distance}"},credits:"Créditos",notAVideo:"Esto no es un vídeo",isASimulation:"Es una simulación en tiempo real."};export{l as sceneNames_es};
@@ -1 +1 @@
1
- import{V as a,D as r}from"./rr0-sighting-editor.mjs";const n={bodies:{sun:"Soleil",moon:"Lune",Venus:"Vénus",Saturn:"Saturne"},stars:{Betelgeuse:"Bételgeuse",Vega:"Véga",Altair:"Altaïr",Aldebaran:"Aldébaran",Regulus:"Régulus",Antares:"Antarès"},comets:{"halley-1910":"comète de Halley","brooks-1911":"comète Brooks","skjellerup-maristany-1927":"comète Skjellerup-Maristany","de-kock-paraskevopoulos-1941":"comète de Kock-Paraskevopoulos","southern-1947":"comète australe","eclipse-1948":"comète de l'éclipse","arend-roland-1957":"comète Arend-Roland","mrkos-1957":"comète Mrkos","seki-lines-1962":"comète Seki-Lines","ikeya-seki-1965":"comète Ikeya-Seki","bennett-1970":"comète Bennett","white-ortiz-bolelli-1970":"comète White-Ortiz-Bolelli","kohoutek-1973":"comète Kohoutek","west-1976":"comète West","iras-araki-alcock-1983":"comète IRAS-Araki-Alcock","halley-1986":"comète de Halley","hyakutake-1996":"comète Hyakutake","hale-bopp-1997":"comète Hale-Bopp","mcnaught-2007":"comète McNaught","lovejoy-2011":"comète Lovejoy","panstarrs-2013":"comète PANSTARRS","neowise-2020":"comète NEOWISE","tsuchinshan-atlas-2024":"comète Tsuchinshan-ATLAS"},novae:{"sn-1006":"supernova de 1006","sn-1054":"supernova de 1054","sn-1181":"supernova de 1181","sn-1572":"supernova de Tycho","sn-1604":"supernova de Kepler","t-crb-1866":"nova de la Couronne boréale 1866","t-aur-1891":"nova du Cocher 1891","gk-per-1901":"nova de Persée 1901","dn-gem-1912":"nova des Gémeaux 1912","v603-aql-1918":"nova de l'Aigle 1918","v476-cyg-1920":"nova du Cygne 1920","rr-pic-1925":"nova du Peintre 1925","dq-her-1934":"nova d'Hercule 1934","cp-lac-1936":"nova du Lézard 1936","cp-pup-1942":"nova de la Poupe 1942","t-crb-1946":"nova de la Couronne boréale 1946","v446-her-1960":"nova d'Hercule 1960","v533-her-1963":"nova d'Hercule 1963","hr-del-1967":"nova du Dauphin 1967","lv-vul-1968":"nova du Petit Renard 1968","fh-ser-1970":"nova du Serpent 1970","v1500-cyg-1975":"nova du Cygne 1975","v842-cen-1986":"nova du Centaure 1986","sn-1987a":"supernova 1987A","v1974-cyg-1992":"nova du Cygne 1992","v382-vel-1999":"nova des Voiles 1999","v1494-aql-1999":"nova de l'Aigle 1999","v4743-sgr-2002":"nova du Sagittaire 2002","rs-oph-2006":"nova d'Ophiuchus 2006","v1280-sco-2007":"nova du Scorpion 2007","v339-del-2013":"nova du Dauphin 2013","v1369-cen-2013":"nova du Centaure 2013","rs-oph-2021":"nova d'Ophiuchus 2021"},satelliteClasses:{echo:"les ballons Echo","iridium-flares":"les flashes d'Iridium",iss:"la Station spatiale internationale","starlink-trains":"les trains de Starlink"},showers:{quadrantids:"Quadrantides",lyrids:"Lyrides d'avril","eta-aquariids":"Êta Aquarides","alpha-capricornids":"Alpha Capricornides","southern-delta-aquariids":"Delta Aquarides du Sud",perseids:"Perséides","southern-taurids":"Taurides du Sud",draconids:"Draconides d'octobre",orionids:"Orionides","northern-taurids":"Taurides du Nord",leonids:"Léonides",geminids:"Géminides",ursids:"Ursides"},lightRigs:{airliner:"Avion de ligne",helicopter:"Hélicoptère","car-headlights":"Voiture, phares allumés","car-hazards":"Voiture, feux de détresse","emergency-beacons":"Gyrophares de véhicule d'urgence","traffic-signal":"Feu de circulation","pedestrian-signal":"Feu piéton",streetlamp:"Lampadaire"},instruments:{eye:"Œil nu","rectilinear-lens":"Appareil, modèle inconnu","roamer-1-120":"Roamer 1, film 120","instamatic-126":"Instamatic, film 126","slr-35mm-50":"Reflex 35 mm, objectif 50 mm","slr-35mm-zoom":"Reflex 35 mm, zoom 70-210 mm","phone-landscape":"Téléphone, tenu couché","phone-portrait":"Téléphone, tenu debout",...r.names(),...a.names()},decorKinds:{building:"Bâtiment",tree:"Arbre",shrub:"Buisson",bridge:"Pont",wire:"Ligne aérienne",crop:"Rang de culture",terrace:"Restanque (terrasse)",mound:"Tas de pierres",wall:"Muret de pierres sèches",streetlight:"Lampadaire",trafficlight:"Feu de circulation",crossing:"Passage piéton",roadsign:"Panneau de signalisation",vehicle:"Véhicule",observer:"Observateur",aircraft:"Aéronef",entity:"Être"},compassPoints:["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSO","SO","OSO","O","ONO","NO","NNO"],towards:e=>/^[EO]/.test(e)?`à l'${e}`:`au ${e}`,starTooltip:"{name} — mag {mag}, {alt}° au-dessus de l'horizon",starTooltipBelow:"{name} — mag {mag}, {alt}° sous l'horizontale",decorTooltip:"{name} — {size}, à {distance}",satelliteTooltip:"{name} — satellite, mag {mag}, à {height} km d'altitude",opticsTooltips:{halo22:"Halo de 22° — un anneau autour du Soleil, dû à la lumière déviée par des cristaux de glace hexagonaux dans les cirrus ; son bord interne est rouge, à 21,7°",halo46:"Halo de 46° — un anneau plus rare et plus faible : la lumière entre par une face latérale d'un cristal et sort par une face de bout",oddRadius:"Halo de {angle}° — un anneau à rayon impair, rare et faible, dû à des cristaux de glace à bouts pyramidaux",parhelion:"Parhélie — une tache brillante colorée à côté du Soleil, à sa hauteur, due à des plaquettes de glace tombant à plat ; rouge côté Soleil",parhelion120:"Parhélie à 120° — une faible tache blanche à 120° du Soleil, due à la lumière réfléchie à l'intérieur de plaquettes à plat",upperTangentArc:"Arc tangent supérieur — un arc brillant posé sur le haut du halo de 22°, dû à des colonnes couchées à l'horizontale",lowerTangentArc:"Arc tangent inférieur — un arc touchant le bas du halo de 22°, dû à des colonnes couchées à l'horizontale",circumzenithal:"Arc circumzénithal — une bande vivement colorée près du zénith, due à la lumière entrant par la face du dessus de plaquettes à plat (seulement Soleil sous 32°)",circumhorizontal:"Arc circumhorizontal — une bande colorée basse dans le ciel, due à la lumière entrant par la face latérale de plaquettes à plat (seulement Soleil au-dessus de 58°)",parhelicCircle:"Cercle parhélique — un cercle blanc faisant tout le tour du ciel à la hauteur du Soleil, dû aux reflets sur les faces verticales de plaquettes à plat",pillar:"Pilier de lumière — une colonne de lumière dressée au-dessus du Soleil, due aux reflets sur des plaquettes à plat légèrement inclinées",subsun:"Sous-soleil — une image du Soleil sous l'horizon, due aux reflets sur les faces plates de plaquettes"},trafficTooltip:{unnamed:"Aéronef {hex}",altitude:"{value} ft",speed:"{value} kt",heading:"cap {value}°",position:"à {distance} km, {elevation}° au-dessus de l'horizon, {bearing}",heard:"Entendu à {level} dB(A), parti de l'avion il y a {delay} s, {lag}° derrière lui : {character}{pitch}",rumble:"un grondement grave, rien au-delà de {cutoff} Hz",muffled:"un bruit sourd, rien au-delà de {cutoff} Hz",broad:"un souffle large",pitchHigher:", son plus aigu de {percent} %",pitchLower:", son plus grave de {percent} %",inaudible:"Inaudible ici : {level} dB(A) contre {ambient} dB(A) de bruit ambiant",soundUnknown:"Son non calculable : l'avion n'était pas encore enregistré quand il est parti",contrailPersistent:"Laisse une traînée qui dure : l'air est sursaturé en glace ({rhi} % par rapport à la glace)",contrailShort:"Laisse une traînée brève : l'air est sec par rapport à la glace ({rhi} % par rapport à la glace)",military:"militaire",restricted:"identité masquée par son propriétaire",candidate:"Un candidat compatible, pas une identification"},credits:"Crédits",notAVideo:"Ceci n'est pas une vidéo",isASimulation:"C'est une simulation en temps réel."};export{n as sceneNames_fr};
1
+ import{V as a,D as r}from"./rr0-sighting-editor.mjs";const l={bodies:{sun:"Soleil",moon:"Lune",Venus:"Vénus",Saturn:"Saturne"},stars:{Betelgeuse:"Bételgeuse",Vega:"Véga",Altair:"Altaïr",Aldebaran:"Aldébaran",Regulus:"Régulus",Antares:"Antarès"},comets:{"halley-1910":"comète de Halley","brooks-1911":"comète Brooks","skjellerup-maristany-1927":"comète Skjellerup-Maristany","de-kock-paraskevopoulos-1941":"comète de Kock-Paraskevopoulos","southern-1947":"comète australe","eclipse-1948":"comète de l'éclipse","arend-roland-1957":"comète Arend-Roland","mrkos-1957":"comète Mrkos","seki-lines-1962":"comète Seki-Lines","ikeya-seki-1965":"comète Ikeya-Seki","bennett-1970":"comète Bennett","white-ortiz-bolelli-1970":"comète White-Ortiz-Bolelli","kohoutek-1973":"comète Kohoutek","west-1976":"comète West","iras-araki-alcock-1983":"comète IRAS-Araki-Alcock","halley-1986":"comète de Halley","hyakutake-1996":"comète Hyakutake","hale-bopp-1997":"comète Hale-Bopp","mcnaught-2007":"comète McNaught","lovejoy-2011":"comète Lovejoy","panstarrs-2013":"comète PANSTARRS","neowise-2020":"comète NEOWISE","tsuchinshan-atlas-2024":"comète Tsuchinshan-ATLAS"},novae:{"sn-1006":"supernova de 1006","sn-1054":"supernova de 1054","sn-1181":"supernova de 1181","sn-1572":"supernova de Tycho","sn-1604":"supernova de Kepler","t-crb-1866":"nova de la Couronne boréale 1866","t-aur-1891":"nova du Cocher 1891","gk-per-1901":"nova de Persée 1901","dn-gem-1912":"nova des Gémeaux 1912","v603-aql-1918":"nova de l'Aigle 1918","v476-cyg-1920":"nova du Cygne 1920","rr-pic-1925":"nova du Peintre 1925","dq-her-1934":"nova d'Hercule 1934","cp-lac-1936":"nova du Lézard 1936","cp-pup-1942":"nova de la Poupe 1942","t-crb-1946":"nova de la Couronne boréale 1946","v446-her-1960":"nova d'Hercule 1960","v533-her-1963":"nova d'Hercule 1963","hr-del-1967":"nova du Dauphin 1967","lv-vul-1968":"nova du Petit Renard 1968","fh-ser-1970":"nova du Serpent 1970","v1500-cyg-1975":"nova du Cygne 1975","v842-cen-1986":"nova du Centaure 1986","sn-1987a":"supernova 1987A","v1974-cyg-1992":"nova du Cygne 1992","v382-vel-1999":"nova des Voiles 1999","v1494-aql-1999":"nova de l'Aigle 1999","v4743-sgr-2002":"nova du Sagittaire 2002","rs-oph-2006":"nova d'Ophiuchus 2006","v1280-sco-2007":"nova du Scorpion 2007","v339-del-2013":"nova du Dauphin 2013","v1369-cen-2013":"nova du Centaure 2013","rs-oph-2021":"nova d'Ophiuchus 2021"},satelliteClasses:{echo:"les ballons Echo","iridium-flares":"les flashes d'Iridium",iss:"la Station spatiale internationale","starlink-trains":"les trains de Starlink"},showers:{quadrantids:"Quadrantides",lyrids:"Lyrides d'avril","eta-aquariids":"Êta Aquarides","alpha-capricornids":"Alpha Capricornides","southern-delta-aquariids":"Delta Aquarides du Sud",perseids:"Perséides","southern-taurids":"Taurides du Sud",draconids:"Draconides d'octobre",orionids:"Orionides","northern-taurids":"Taurides du Nord",leonids:"Léonides",geminids:"Géminides",ursids:"Ursides"},lightRigs:{airliner:"Avion de ligne",helicopter:"Hélicoptère","car-headlights":"Voiture, phares allumés","car-hazards":"Voiture, feux de détresse","emergency-beacons":"Gyrophares de véhicule d'urgence","traffic-signal":"Feu de circulation","pedestrian-signal":"Feu piéton",streetlamp:"Lampadaire"},instruments:{eye:"Œil nu","rectilinear-lens":"Appareil, modèle inconnu","roamer-1-120":"Roamer 1, film 120","instamatic-126":"Instamatic, film 126","slr-35mm-50":"Reflex 35 mm, objectif 50 mm","slr-35mm-zoom":"Reflex 35 mm, zoom 70-210 mm","phone-landscape":"Téléphone, tenu couché","phone-portrait":"Téléphone, tenu debout",...r.names(),...a.names()},decorKinds:{building:"Bâtiment",tree:"Arbre",shrub:"Buisson",bridge:"Pont",wire:"Ligne aérienne",crop:"Rang de culture",terrace:"Restanque (terrasse)",mound:"Tas de pierres",wall:"Muret de pierres sèches",streetlight:"Lampadaire",trafficlight:"Feu de circulation",crossing:"Passage piéton",roadsign:"Panneau de signalisation",vehicle:"Véhicule",observer:"Observateur",aircraft:"Aéronef",entity:"Être"},compassPoints:["N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSO","SO","OSO","O","ONO","NO","NNO"],towards:e=>/^[EO]/.test(e)?`à l'${e}`:`au ${e}`,starTooltip:"{name} — mag {mag}, {alt}° au-dessus de l'horizon",starTooltipBelow:"{name} — mag {mag}, {alt}° sous l'horizontale",decorTooltip:"{name} — {size}, à {distance}",satelliteTooltip:"{name} — satellite, mag {mag}, à {height} km d'altitude",opticsTooltips:{halo22:"Halo de 22° — un anneau autour du Soleil, dû à la lumière déviée par des cristaux de glace hexagonaux dans les cirrus ; son bord interne est rouge, à 21,7°",halo46:"Halo de 46° — un anneau plus rare et plus faible : la lumière entre par une face latérale d'un cristal et sort par une face de bout",oddRadius:"Halo de {angle}° — un anneau à rayon impair, rare et faible, dû à des cristaux de glace à bouts pyramidaux",parhelion:"Parhélie — une tache brillante colorée à côté du Soleil, à sa hauteur, due à des plaquettes de glace tombant à plat ; rouge côté Soleil",parhelion120:"Parhélie à 120° — une faible tache blanche à 120° du Soleil, due à la lumière réfléchie à l'intérieur de plaquettes à plat",upperTangentArc:"Arc tangent supérieur — un arc brillant posé sur le haut du halo de 22°, dû à des colonnes couchées à l'horizontale",lowerTangentArc:"Arc tangent inférieur — un arc touchant le bas du halo de 22°, dû à des colonnes couchées à l'horizontale",circumzenithal:"Arc circumzénithal — une bande vivement colorée près du zénith, due à la lumière entrant par la face du dessus de plaquettes à plat (seulement Soleil sous 32°)",circumhorizontal:"Arc circumhorizontal — une bande colorée basse dans le ciel, due à la lumière entrant par la face latérale de plaquettes à plat (seulement Soleil au-dessus de 58°)",parhelicCircle:"Cercle parhélique — un cercle blanc faisant tout le tour du ciel à la hauteur du Soleil, dû aux reflets sur les faces verticales de plaquettes à plat",pillar:"Pilier de lumière — une colonne de lumière dressée au-dessus du Soleil, due aux reflets sur des plaquettes à plat légèrement inclinées",subsun:"Sous-soleil — une image du Soleil sous l'horizon, due aux reflets sur les faces plates de plaquettes"},trafficTooltip:{unnamed:"Aéronef {hex}",altitude:"{value} ft",speed:"{value} kt",heading:"cap {value}°",position:"à {distance} km, {elevation}° au-dessus de l'horizon, {bearing}",heard:"Entendu à {level} dB(A), parti de l'avion il y a {delay} s, {lag}° derrière lui : {character}{pitch}",rumble:"un grondement grave, rien au-delà de {cutoff} Hz",muffled:"un bruit sourd, rien au-delà de {cutoff} Hz",broad:"un souffle large",pitchHigher:", son plus aigu de {percent} %",pitchLower:", son plus grave de {percent} %",inaudible:"Inaudible ici : {level} dB(A) contre {ambient} dB(A) de bruit ambiant",soundUnknown:"Son non calculable : l'avion n'était pas encore enregistré quand il est parti",contrailPersistent:"Laisse une traînée qui dure : l'air est sursaturé en glace ({rhi} % par rapport à la glace)",contrailShort:"Laisse une traînée brève : l'air est sec par rapport à la glace ({rhi} % par rapport à la glace)",military:"militaire",restricted:"identité masquée par son propriétaire",candidate:"Un candidat compatible, pas une identification"},railwayTooltip:{kinds:{rail:"Voie ferrée",light_rail:"Métro léger",tram:"Tramway",subway:"Métro",funicular:"Funiculaire"},highSpeed:"Ligne à grande vitesse",service:"Voie de service",singleTrack:"voie unique",tracks:"{count} voies",overhead:"caténaire, fil de contact à {height} m au-dessus du rail",overheadVoltage:"caténaire en {voltage}, fil de contact à {height} m au-dessus du rail",thirdRail:"troisième rail",thirdRailVoltage:"troisième rail en {voltage}",notElectrified:"non électrifiée",gauge:"écartement de {mm} mm",metreGauge:"voie métrique",distance:"à {distance}"},credits:"Crédits",notAVideo:"Ceci n'est pas une vidéo",isASimulation:"C'est une simulation en temps réel."};export{l as sceneNames_fr};