diff --git a/content/posts/2026-07-05-exploring-the-fpv-drone-strike-dataset.md b/content/posts/2026-07-05-exploring-the-fpv-drone-strike-dataset.md index 4448690..9478f45 100644 --- a/content/posts/2026-07-05-exploring-the-fpv-drone-strike-dataset.md +++ b/content/posts/2026-07-05-exploring-the-fpv-drone-strike-dataset.md @@ -13,17 +13,17 @@ image: /img/fpv-viewer/social.png ![Explore the FPV strike dataset — a reconstructed 3-D attack path on the "Biranit" Iron Dome platform, in the viewer](/img/fpv-viewer/social.png) -A few weeks ago I [opened up a dataset of Hezbollah FPV drone-strike videos](/blog/fpv-drone-strikes-open-dataset/) — every clip I could pull out of OSINT, labelled and kept in one place so anyone building a defense could start from real footage instead of a press release. It worked as a *dataset*: a repo, a manifest, download links, files in S3. It was miserable as something to actually *look at*. To answer a simple question — "show me the strikes on air-defense sites near the border, and skip the propaganda intros" — you were downloading MP4s and scrubbing through them by hand. +A few weeks ago I [opened up a dataset of Hezbollah FPV drone-strike videos](/blog/fpv-drone-strikes-open-dataset/) — every clip I could pull out of OSINT, labelled and kept in one place so anyone building a defense could start from real footage instead of a press release. It worked as a *dataset*, but it was miserable as something to actually *look at*. To answer a simple question — "show me the strikes on air-defense sites near the border" — you were downloading MP4s and scrubbing through them by hand. -So I built the thing that was missing: **a viewer that turns the folder-of-links into something you can browse, read, and fly through, right in the browser.** It's live at **[itamar-weiss.com/fpv](/fpv)**. This post is what it does and the two ideas behind it that I think are worth stealing for any video-forensics collection. +So I built the thing that was missing: **a viewer that makes the dataset accessible to the community — something you can browse, read, and learn from, right in the browser.** It's live at **[itamar-weiss.com/fpv](/fpv)**. This post is what it does and the two ideas behind it that I think are worth stealing for any video-forensics collection. ## Three ways to look at the same clip The viewer is small on purpose — one dataset, three views, each answering a different question. -![The viewer gives you three views of every clip: a searchable gallery, an auto-annotated flight timeline, and an orbitable 3-D scene](/img/fpv-viewer/tool_flow.png) +![The viewer gives you three views of every clip: a searchable gallery, an auto-annotated flight timeline, and a reconstructed 3-D scene you can explore](/img/fpv-viewer/tool_flow.png) -The **gallery** is the front door: every clip as a card with a first-frame thumbnail, searchable by description, town or date, sortable, and filterable down to just the ones that have a reconstructed 3-D scene. The **player** adds a flight-annotation timeline underneath the video. And the **scene view** — for the clips I've reconstructed — lets you orbit the actual 3-D geometry of the strike and measure distances in it. +The **gallery** is the front door: every clip as a card with a first-frame thumbnail, searchable by description, town or date, sortable, and filterable down to just the ones that have a reconstructed 3-D scene. The **player** adds a flight-annotation timeline underneath the video. And the **scene view** — for the clips I've reconstructed — lets you orbit the actual 3-D geometry of the strike. Here's the whole thing in one pass — browsing the gallery, reading a clip's flight-annotated player, and orbiting its reconstructed 3-D scene (the strike on the "Biranit" Iron Dome platform): @@ -31,9 +31,9 @@ Here's the whole thing in one pass — browsing the gallery, reading a clip's fl It's the same catalog as the repo, just alive — and it grows as new footage surfaces. It's best experienced full-screen at **[itamar-weiss.com/fpv](/fpv)**. -## The clips are propaganda, so I annotate them +## Annotations: extracting the flight segments -Here's the first idea that shaped the tool. These videos are *edited* — they're published as propaganda, not as evidence. A single clip opens on a title-card banner, cuts between flight segments, freezes on the moment of impact, and ends on a slow-motion replay with a branded outro. If you're a human trying to study tactics, or a model trying to learn from the footage, **most of the runtime is noise the editor added on top.** The camera is the weapon's eye, but only for part of the clip. +Here's the first idea that shaped the tool. These videos are *edited*. A single clip opens on a title-card banner, cuts between flight segments, freezes on the moment of impact, and ends on a slow-motion replay. If you're a human trying to study tactics, or a model trying to learn from the footage, **only part of the runtime is the drone actually flying** — and that part is what you're after. The camera is the weapon's eye, but only for part of the clip. The annotations exist to extract exactly those flight segments. So every video in the viewer gets a **flight-annotation timeline**: the footage is segmented into *flight*, *banner*, *pause / freeze* and *replay*, and the player lets you jump straight to the parts that are genuinely the drone flying. Here's one clip, annotated — the 2026-06-06 Merkava-tank strike near Blat: @@ -45,16 +45,32 @@ And this isn't a one-off. Once every clip is annotated, you can add it up across ![Across all annotated footage, barely half the seconds are actual flight; the rest is banners, freezes and replays](/img/fpv-viewer/footage_breakdown.png) -Of the roughly 2.4 hours of annotated footage, **only about half is real flight.** The other half is banners, freeze-frames and replays. That's the concrete argument for annotating: if you feed a reconstruction pipeline or a training set the raw clips, half your data is title cards and slow-motion — and, worse, the freezes and replays look like camera motion to a naive algorithm and quietly poison the geometry. The timeline is how you keep only the signal. (The segment boundaries here are auto-generated; they're a starting point, not hand-verified ground truth.) +Of the roughly 2.4 hours of annotated footage, **only about half is real flight.** The other half is banners, freeze-frames and replays. That's the concrete argument for annotating: if you feed a reconstruction pipeline or a training set the raw clips, half your data is title cards and slow-motion — and, worse, the freezes and replays look like camera motion to a naive algorithm and quietly poison the geometry. The timeline is how you keep only the signal. -## The clips you can fly +One honest caveat: **some of these annotations were generated automatically and haven't been manually reviewed yet**, so expect occasional boundaries that are a little off. I'm reviewing and correcting them gradually — treat them as a strong starting point, not hand-verified ground truth. + +## Explore the strike in 3-D The second idea is the payoff from the [last post](/blog/fpv-drone-strikes-open-dataset/), made interactive. There I took a *single* clip and recovered the drone's real 3-D attack path straight from the pixels — no telemetry, just [VGGT](https://arxiv.org/abs/2503.11651) run over the isolated flight frames. Since then I've run that pipeline across the dataset, and **a growing share of the clips now have a full 3-D reconstruction** you can open in the browser. -Each scene is the recovered point cloud of the terrain plus the drone's flight path — the ordered camera centers — drawn from the launch camera along the approach to the terminal pose over the target, with a corner panel that plays the real footage in step with the reconstruction. You orbit it with the mouse, and there's a **measure tool**: click two points and it reads back the distance between them, so you can eyeball a standoff range or the size of a targeted vehicle in the reconstruction's own units. Filter the gallery to **3D scenes** and click any card's *3D scene* button to open one. +Every scene goes through the same pipeline. It starts from the raw clip, and the flight annotations from the previous section make the first cut: they extract the segments where the drone is actually flying. Those frames then get some image processing — equalization and cleanup, to squeeze the most out of heavily compressed footage. From what's left I keep just the relevant part of the attack flight, and that goes into the model, which recovers the camera position for every frame — the flight path — together with the point cloud of the terrain around it. That's the scene you open in the viewer. + +![The reconstruction pipeline: raw clip → extract the flight → enhance the frames → select the attack run → recover the camera path and point cloud](/img/fpv-viewer/scene_pipeline.png) + +Each scene is the recovered point cloud of the terrain plus the drone's flight path — the ordered camera centers — drawn from the launch camera along the approach to the terminal pose over the target, with a corner panel that plays the real footage in step with the reconstruction. You orbit it with the mouse. Filter the gallery to **3D scenes** and click any card's *3D scene* button to open one. (A measure tool — click two points, read back the distance, eyeball a standoff range or the size of a targeted vehicle — is coming, but I'm holding it back for now; the scale problem below explains why.) + +The point isn't a pretty render — it's that you get to **explore the strike**. An attack you could only watch happen once, through the attacker's camera, becomes a scene you can stand in after the fact: replay the approach, see what the drone saw at every moment, and reflect on how the flight actually unfolded — and where along it a defense could have broken it. Do that across the whole collection and the anecdotes start turning into distributions: approach corridors, dive angles, standoff distances — the geometry of how these attacks actually unfold, browsable one clip at a time. +This is the hardest, least finished part of the project, and it's worth being upfront about the challenges. **Not every clip has a 3-D scene yet, and some of the reconstructions that do exist aren't the highest quality.** A lot of the source footage is heavily compressed, and when the video quality drops the recovered geometry gets noisy. The model also sometimes tries to map the *sky* — which has no geometry to recover — and that shows up as a haze of stray points that makes the scene hard to decompose and read. Smoke is another hard case: the moments around impact are often full of it, and no reconstruction handles that well. And since the flight annotations that feed the pipeline are partly auto-generated and not yet manually reviewed, a bad boundary upstream can become a bad scene downstream. + +There's a subtler challenge too: **the reconstruction doesn't know its own scale.** From pixels alone, a small house up close and a big house far away look exactly the same — the model recovers the shape of the scene, but not its size. The only way to pin it down is to find something in the scene whose real-world size you know — a vehicle, a doorway, a road — measure it inside the 3-D world, and scale the entire model to match. Get that right and heights, distances and speeds all become real numbers — and that's the point at which a measure tool becomes genuinely useful, which is why I'm holding it back until scenes are anchored to real-world scale. + +![Scale ambiguity: a small house nearby and a large house far away project onto the same pixels — only an object of known real-world size can anchor the scale](/img/fpv-viewer/scale_ambiguity.png) + +All of it is a work in progress — I'll keep extracting scenes for the remaining clips, improving the existing ones, and working the scale problem, gradually. + ## Why bother building the viewer I could have left it as a repo. But a dataset you can't *see* barely gets used, and the whole reason I opened this one up was for it to get used — by anyone trying to understand how the threat behaves, or to build and evaluate the sensors and algorithms that stop it. It's the same instinct behind [designing a microphone array to hear these drones](/blog/designing-a-mic-array-for-acoustic-drone-detection/): the tools only get you so far without representative data you can actually put your hands on. diff --git a/public/fpv/assets/SceneView-B3r-Nscl.js b/public/fpv/assets/SceneView-B3r-Nscl.js index 2e3570e..8a6d07a 100644 --- a/public/fpv/assets/SceneView-B3r-Nscl.js +++ b/public/fpv/assets/SceneView-B3r-Nscl.js @@ -3800,4 +3800,4 @@ void main() { } -}`;class up{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(e,t,n){if(this.texture===null){const r=new wt,s=e.properties.get(r);s.__webglTexture=t.texture,(t.depthNear!=n.depthNear||t.depthFar!=n.depthFar)&&(this.depthNear=t.depthNear,this.depthFar=t.depthFar),this.texture=r}}render(e,t){if(this.texture!==null){if(this.mesh===null){const n=t.cameras[0].viewport,r=new Mn({extensions:{fragDepth:!0},vertexShader:lp,fragmentShader:cp,uniforms:{depthColor:{value:this.texture},depthWidth:{value:n.z},depthHeight:{value:n.w}}});this.mesh=new It(new _r(20,20),r)}e.render(this.mesh,t)}}reset(){this.texture=null,this.mesh=null}}class hp extends zn{constructor(e,t){super();const n=this;let r=null,s=1,o=null,a="local-floor",l=1,c=null,h=null,f=null,p=null,m=null,g=null;const M=new up,d=t.getContextAttributes();let u=null,T=null;const _=[],R=[],L=new Ue;let w=null;const E=new Ut;E.layers.enable(1),E.viewport=new pt;const F=new Ut;F.layers.enable(2),F.viewport=new pt;const $=[E,F],x=new ap;x.layers.enable(1),x.layers.enable(2);let A=null,te=null;this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(B){let Q=_[B];return Q===void 0&&(Q=new es,_[B]=Q),Q.getTargetRaySpace()},this.getControllerGrip=function(B){let Q=_[B];return Q===void 0&&(Q=new es,_[B]=Q),Q.getGripSpace()},this.getHand=function(B){let Q=_[B];return Q===void 0&&(Q=new es,_[B]=Q),Q.getHandSpace()};function Z(B){const Q=R.indexOf(B.inputSource);if(Q===-1)return;const de=_[Q];de!==void 0&&(de.update(B.inputSource,B.frame,c||o),de.dispatchEvent({type:B.type,data:B.inputSource}))}function D(){r.removeEventListener("select",Z),r.removeEventListener("selectstart",Z),r.removeEventListener("selectend",Z),r.removeEventListener("squeeze",Z),r.removeEventListener("squeezestart",Z),r.removeEventListener("squeezeend",Z),r.removeEventListener("end",D),r.removeEventListener("inputsourceschange",q);for(let B=0;B<_.length;B++){const Q=R[B];Q!==null&&(R[B]=null,_[B].disconnect(Q))}A=null,te=null,M.reset(),e.setRenderTarget(u),m=null,p=null,f=null,r=null,T=null,Ee.stop(),n.isPresenting=!1,e.setPixelRatio(w),e.setSize(L.width,L.height,!1),n.dispatchEvent({type:"sessionend"})}this.setFramebufferScaleFactor=function(B){s=B,n.isPresenting===!0&&console.warn("THREE.WebXRManager: Cannot change framebuffer scale while presenting.")},this.setReferenceSpaceType=function(B){a=B,n.isPresenting===!0&&console.warn("THREE.WebXRManager: Cannot change reference space type while presenting.")},this.getReferenceSpace=function(){return c||o},this.setReferenceSpace=function(B){c=B},this.getBaseLayer=function(){return p!==null?p:m},this.getBinding=function(){return f},this.getFrame=function(){return g},this.getSession=function(){return r},this.setSession=async function(B){if(r=B,r!==null){if(u=e.getRenderTarget(),r.addEventListener("select",Z),r.addEventListener("selectstart",Z),r.addEventListener("selectend",Z),r.addEventListener("squeeze",Z),r.addEventListener("squeezestart",Z),r.addEventListener("squeezeend",Z),r.addEventListener("end",D),r.addEventListener("inputsourceschange",q),d.xrCompatible!==!0&&await t.makeXRCompatible(),w=e.getPixelRatio(),e.getSize(L),r.renderState.layers===void 0||e.capabilities.isWebGL2===!1){const Q={antialias:r.renderState.layers===void 0?d.antialias:!0,alpha:!0,depth:d.depth,stencil:d.stencil,framebufferScaleFactor:s};m=new XRWebGLLayer(r,t,Q),r.updateRenderState({baseLayer:m}),e.setPixelRatio(1),e.setSize(m.framebufferWidth,m.framebufferHeight,!1),T=new Bn(m.framebufferWidth,m.framebufferHeight,{format:Ht,type:vn,colorSpace:e.outputColorSpace,stencilBuffer:d.stencil})}else{let Q=null,de=null,Re=null;d.depth&&(Re=d.stencil?t.DEPTH24_STENCIL8:t.DEPTH_COMPONENT24,Q=d.stencil?hi:On,de=d.stencil?Fn:mn);const ve={colorFormat:t.RGBA8,depthFormat:Re,scaleFactor:s};f=new XRWebGLBinding(r,t),p=f.createProjectionLayer(ve),r.updateRenderState({layers:[p]}),e.setPixelRatio(1),e.setSize(p.textureWidth,p.textureHeight,!1),T=new Bn(p.textureWidth,p.textureHeight,{format:Ht,type:vn,depthTexture:new Oo(p.textureWidth,p.textureHeight,de,void 0,void 0,void 0,void 0,void 0,void 0,Q),stencilBuffer:d.stencil,colorSpace:e.outputColorSpace,samples:d.antialias?4:0});const fe=e.properties.get(T);fe.__ignoreDepthValues=p.ignoreDepthValues}T.isXRRenderTarget=!0,this.setFoveation(l),c=null,o=await r.requestReferenceSpace(a),Ee.setContext(r),Ee.start(),n.isPresenting=!0,n.dispatchEvent({type:"sessionstart"})}},this.getEnvironmentBlendMode=function(){if(r!==null)return r.environmentBlendMode};function q(B){for(let Q=0;Q=0&&(R[Re]=null,_[Re].disconnect(de))}for(let Q=0;Q=R.length){R.push(de),Re=fe;break}else if(R[fe]===null){R[fe]=de,Re=fe;break}if(Re===-1)break}const ve=_[Re];ve&&ve.connect(de)}}const H=new U,Y=new U;function W(B,Q,de){H.setFromMatrixPosition(Q.matrixWorld),Y.setFromMatrixPosition(de.matrixWorld);const Re=H.distanceTo(Y),ve=Q.projectionMatrix.elements,fe=de.projectionMatrix.elements,qe=ve[14]/(ve[10]-1),k=ve[14]/(ve[10]+1),P=(ve[9]+1)/ve[5],ye=(ve[9]-1)/ve[5],le=(ve[8]-1)/ve[0],Ce=(fe[8]+1)/fe[0],Te=qe*le,Ve=qe*Ce,Ne=Re/(-le+Ce),Be=Ne*-le;Q.matrixWorld.decompose(B.position,B.quaternion,B.scale),B.translateX(Be),B.translateZ(Ne),B.matrixWorld.compose(B.position,B.quaternion,B.scale),B.matrixWorldInverse.copy(B.matrixWorld).invert();const Qe=qe+Ne,y=k+Ne,v=Te-Be,V=Ve+(Re-Be),j=P*k/y*Qe,ne=ye*k/y*Qe;B.projectionMatrix.makePerspective(v,V,j,ne,Qe,y),B.projectionMatrixInverse.copy(B.projectionMatrix).invert()}function X(B,Q){Q===null?B.matrixWorld.copy(B.matrix):B.matrixWorld.multiplyMatrices(Q.matrixWorld,B.matrix),B.matrixWorldInverse.copy(B.matrixWorld).invert()}this.updateCamera=function(B){if(r===null)return;M.texture!==null&&(B.near=M.depthNear,B.far=M.depthFar),x.near=F.near=E.near=B.near,x.far=F.far=E.far=B.far,(A!==x.near||te!==x.far)&&(r.updateRenderState({depthNear:x.near,depthFar:x.far}),A=x.near,te=x.far,E.near=A,E.far=te,F.near=A,F.far=te,E.updateProjectionMatrix(),F.updateProjectionMatrix(),B.updateProjectionMatrix());const Q=B.parent,de=x.cameras;X(x,Q);for(let Re=0;Re0&&(d.alphaTest.value=u.alphaTest);const T=e.get(u),_=T.envMap,R=T.envMapRotation;if(_&&(d.envMap.value=_,Pn.copy(R),Pn.x*=-1,Pn.y*=-1,Pn.z*=-1,_.isCubeTexture&&_.isRenderTargetTexture===!1&&(Pn.y*=-1,Pn.z*=-1),d.envMapRotation.value.setFromMatrix4(dp.makeRotationFromEuler(Pn)),d.flipEnvMap.value=_.isCubeTexture&&_.isRenderTargetTexture===!1?-1:1,d.reflectivity.value=u.reflectivity,d.ior.value=u.ior,d.refractionRatio.value=u.refractionRatio),u.lightMap){d.lightMap.value=u.lightMap;const L=i._useLegacyLights===!0?Math.PI:1;d.lightMapIntensity.value=u.lightMapIntensity*L,t(u.lightMap,d.lightMapTransform)}u.aoMap&&(d.aoMap.value=u.aoMap,d.aoMapIntensity.value=u.aoMapIntensity,t(u.aoMap,d.aoMapTransform))}function o(d,u){d.diffuse.value.copy(u.color),d.opacity.value=u.opacity,u.map&&(d.map.value=u.map,t(u.map,d.mapTransform))}function a(d,u){d.dashSize.value=u.dashSize,d.totalSize.value=u.dashSize+u.gapSize,d.scale.value=u.scale}function l(d,u,T,_){d.diffuse.value.copy(u.color),d.opacity.value=u.opacity,d.size.value=u.size*T,d.scale.value=_*.5,u.map&&(d.map.value=u.map,t(u.map,d.uvTransform)),u.alphaMap&&(d.alphaMap.value=u.alphaMap,t(u.alphaMap,d.alphaMapTransform)),u.alphaTest>0&&(d.alphaTest.value=u.alphaTest)}function c(d,u){d.diffuse.value.copy(u.color),d.opacity.value=u.opacity,d.rotation.value=u.rotation,u.map&&(d.map.value=u.map,t(u.map,d.mapTransform)),u.alphaMap&&(d.alphaMap.value=u.alphaMap,t(u.alphaMap,d.alphaMapTransform)),u.alphaTest>0&&(d.alphaTest.value=u.alphaTest)}function h(d,u){d.specular.value.copy(u.specular),d.shininess.value=Math.max(u.shininess,1e-4)}function f(d,u){u.gradientMap&&(d.gradientMap.value=u.gradientMap)}function p(d,u){d.metalness.value=u.metalness,u.metalnessMap&&(d.metalnessMap.value=u.metalnessMap,t(u.metalnessMap,d.metalnessMapTransform)),d.roughness.value=u.roughness,u.roughnessMap&&(d.roughnessMap.value=u.roughnessMap,t(u.roughnessMap,d.roughnessMapTransform)),e.get(u).envMap&&(d.envMapIntensity.value=u.envMapIntensity)}function m(d,u,T){d.ior.value=u.ior,u.sheen>0&&(d.sheenColor.value.copy(u.sheenColor).multiplyScalar(u.sheen),d.sheenRoughness.value=u.sheenRoughness,u.sheenColorMap&&(d.sheenColorMap.value=u.sheenColorMap,t(u.sheenColorMap,d.sheenColorMapTransform)),u.sheenRoughnessMap&&(d.sheenRoughnessMap.value=u.sheenRoughnessMap,t(u.sheenRoughnessMap,d.sheenRoughnessMapTransform))),u.clearcoat>0&&(d.clearcoat.value=u.clearcoat,d.clearcoatRoughness.value=u.clearcoatRoughness,u.clearcoatMap&&(d.clearcoatMap.value=u.clearcoatMap,t(u.clearcoatMap,d.clearcoatMapTransform)),u.clearcoatRoughnessMap&&(d.clearcoatRoughnessMap.value=u.clearcoatRoughnessMap,t(u.clearcoatRoughnessMap,d.clearcoatRoughnessMapTransform)),u.clearcoatNormalMap&&(d.clearcoatNormalMap.value=u.clearcoatNormalMap,t(u.clearcoatNormalMap,d.clearcoatNormalMapTransform),d.clearcoatNormalScale.value.copy(u.clearcoatNormalScale),u.side===At&&d.clearcoatNormalScale.value.negate())),u.iridescence>0&&(d.iridescence.value=u.iridescence,d.iridescenceIOR.value=u.iridescenceIOR,d.iridescenceThicknessMinimum.value=u.iridescenceThicknessRange[0],d.iridescenceThicknessMaximum.value=u.iridescenceThicknessRange[1],u.iridescenceMap&&(d.iridescenceMap.value=u.iridescenceMap,t(u.iridescenceMap,d.iridescenceMapTransform)),u.iridescenceThicknessMap&&(d.iridescenceThicknessMap.value=u.iridescenceThicknessMap,t(u.iridescenceThicknessMap,d.iridescenceThicknessMapTransform))),u.transmission>0&&(d.transmission.value=u.transmission,d.transmissionSamplerMap.value=T.texture,d.transmissionSamplerSize.value.set(T.width,T.height),u.transmissionMap&&(d.transmissionMap.value=u.transmissionMap,t(u.transmissionMap,d.transmissionMapTransform)),d.thickness.value=u.thickness,u.thicknessMap&&(d.thicknessMap.value=u.thicknessMap,t(u.thicknessMap,d.thicknessMapTransform)),d.attenuationDistance.value=u.attenuationDistance,d.attenuationColor.value.copy(u.attenuationColor)),u.anisotropy>0&&(d.anisotropyVector.value.set(u.anisotropy*Math.cos(u.anisotropyRotation),u.anisotropy*Math.sin(u.anisotropyRotation)),u.anisotropyMap&&(d.anisotropyMap.value=u.anisotropyMap,t(u.anisotropyMap,d.anisotropyMapTransform))),d.specularIntensity.value=u.specularIntensity,d.specularColor.value.copy(u.specularColor),u.specularColorMap&&(d.specularColorMap.value=u.specularColorMap,t(u.specularColorMap,d.specularColorMapTransform)),u.specularIntensityMap&&(d.specularIntensityMap.value=u.specularIntensityMap,t(u.specularIntensityMap,d.specularIntensityMapTransform))}function g(d,u){u.matcap&&(d.matcap.value=u.matcap)}function M(d,u){const T=e.get(u).light;d.referencePosition.value.setFromMatrixPosition(T.matrixWorld),d.nearDistance.value=T.shadow.camera.near,d.farDistance.value=T.shadow.camera.far}return{refreshFogUniforms:n,refreshMaterialUniforms:r}}function pp(i,e,t,n){let r={},s={},o=[];const a=t.isWebGL2?i.getParameter(i.MAX_UNIFORM_BUFFER_BINDINGS):0;function l(T,_){const R=_.program;n.uniformBlockBinding(T,R)}function c(T,_){let R=r[T.id];R===void 0&&(g(T),R=h(T),r[T.id]=R,T.addEventListener("dispose",d));const L=_.program;n.updateUBOMapping(T,L);const w=e.render.frame;s[T.id]!==w&&(p(T),s[T.id]=w)}function h(T){const _=f();T.__bindingPointIndex=_;const R=i.createBuffer(),L=T.__size,w=T.usage;return i.bindBuffer(i.UNIFORM_BUFFER,R),i.bufferData(i.UNIFORM_BUFFER,L,w),i.bindBuffer(i.UNIFORM_BUFFER,null),i.bindBufferBase(i.UNIFORM_BUFFER,_,R),R}function f(){for(let T=0;T0&&(R+=L-w),T.__size=R,T.__cache={},this}function M(T){const _={boundary:0,storage:0};return typeof T=="number"||typeof T=="boolean"?(_.boundary=4,_.storage=4):T.isVector2?(_.boundary=8,_.storage=8):T.isVector3||T.isColor?(_.boundary=16,_.storage=12):T.isVector4?(_.boundary=16,_.storage=16):T.isMatrix3?(_.boundary=48,_.storage=48):T.isMatrix4?(_.boundary=64,_.storage=64):T.isTexture?console.warn("THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group."):console.warn("THREE.WebGLRenderer: Unsupported uniform value type.",T),_}function d(T){const _=T.target;_.removeEventListener("dispose",d);const R=o.indexOf(_.__bindingPointIndex);o.splice(R,1),i.deleteBuffer(r[_.id]),delete r[_.id],delete s[_.id]}function u(){for(const T in r)i.deleteBuffer(r[T]);o=[],r={},s={}}return{bind:l,update:c,dispose:u}}class ko{constructor(e={}){const{canvas:t=tc(),context:n=null,depth:r=!0,stencil:s=!0,alpha:o=!1,antialias:a=!1,premultipliedAlpha:l=!0,preserveDrawingBuffer:c=!1,powerPreference:h="default",failIfMajorPerformanceCaveat:f=!1}=e;this.isWebGLRenderer=!0;let p;n!==null?p=n.getContextAttributes().alpha:p=o;const m=new Uint32Array(4),g=new Int32Array(4);let M=null,d=null;const u=[],T=[];this.domElement=t,this.debug={checkShaderErrors:!0,onShaderError:null},this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.clippingPlanes=[],this.localClippingEnabled=!1,this._outputColorSpace=Vt,this._useLegacyLights=!1,this.toneMapping=_n,this.toneMappingExposure=1;const _=this;let R=!1,L=0,w=0,E=null,F=-1,$=null;const x=new pt,A=new pt;let te=null;const Z=new je(0);let D=0,q=t.width,H=t.height,Y=1,W=null,X=null;const re=new pt(0,0,q,H),ae=new pt(0,0,q,H);let pe=!1;const Ee=new No;let B=!1,Q=!1,de=null;const Re=new rt,ve=new Ue,fe=new U,qe={background:null,fog:null,environment:null,overrideMaterial:null,isScene:!0};function k(){return E===null?Y:1}let P=n;function ye(S,I){for(let z=0;z{function me(){if(G.forEach(function(Me){Ne.get(Me).currentProgram.isReady()&&G.delete(Me)}),G.size===0){O(S);return}setTimeout(me,10)}le.get("KHR_parallel_shader_compile")!==null?me():setTimeout(me,10)})};let Ke=null;function Je(S){Ke&&Ke(S)}function at(){et.stop()}function Ye(){et.start()}const et=new Fo;et.setAnimationLoop(Je),typeof self<"u"&&et.setContext(self),this.setAnimationLoop=function(S){Ke=S,K.setAnimationLoop(S),S===null?et.stop():et.start()},K.addEventListener("sessionstart",at),K.addEventListener("sessionend",Ye),this.render=function(S,I){if(I!==void 0&&I.isCamera!==!0){console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.");return}if(R===!0)return;S.matrixWorldAutoUpdate===!0&&S.updateMatrixWorld(),I.parent===null&&I.matrixWorldAutoUpdate===!0&&I.updateMatrixWorld(),K.enabled===!0&&K.isPresenting===!0&&(K.cameraAutoUpdate===!0&&K.updateCamera(I),I=K.getCamera()),S.isScene===!0&&S.onBeforeRender(_,S,I,E),d=be.get(S,T.length),d.init(),T.push(d),Re.multiplyMatrices(I.projectionMatrix,I.matrixWorldInverse),Ee.setFromProjectionMatrix(Re),Q=this.localClippingEnabled,B=oe.init(this.clippingPlanes,Q),M=Le.get(S,u.length),M.init(),u.push(M),mt(S,I,0,_.sortObjects),M.finish(),_.sortObjects===!0&&M.sort(W,X),this.info.render.frame++,B===!0&&oe.beginShadows();const z=d.state.shadowsArray;if(ue.render(z,S,I),B===!0&&oe.endShadows(),this.info.autoReset===!0&&this.info.reset(),(K.enabled===!1||K.isPresenting===!1||K.hasDepthSensing()===!1)&&De.render(M,S),d.setupLights(_._useLegacyLights),I.isArrayCamera){const G=I.cameras;for(let O=0,me=G.length;O0?d=T[T.length-1]:d=null,u.pop(),u.length>0?M=u[u.length-1]:M=null};function mt(S,I,z,G){if(S.visible===!1)return;if(S.layers.test(I.layers)){if(S.isGroup)z=S.renderOrder;else if(S.isLOD)S.autoUpdate===!0&&S.update(I);else if(S.isLight)d.pushLight(S),S.castShadow&&d.pushShadow(S);else if(S.isSprite){if(!S.frustumCulled||Ee.intersectsSprite(S)){G&&fe.setFromMatrixPosition(S.matrixWorld).applyMatrix4(Re);const Me=j.update(S),Ae=S.material;Ae.visible&&M.push(S,Me,Ae,z,fe.z,null)}}else if((S.isMesh||S.isLine||S.isPoints)&&(!S.frustumCulled||Ee.intersectsObject(S))){const Me=j.update(S),Ae=S.material;if(G&&(S.boundingSphere!==void 0?(S.boundingSphere===null&&S.computeBoundingSphere(),fe.copy(S.boundingSphere.center)):(Me.boundingSphere===null&&Me.computeBoundingSphere(),fe.copy(Me.boundingSphere.center)),fe.applyMatrix4(S.matrixWorld).applyMatrix4(Re)),Array.isArray(Ae)){const Pe=Me.groups;for(let We=0,Ie=Pe.length;We0&&Di(O,me,I,z),G&&Te.viewport(x.copy(G)),O.length>0&&Ui(O,I,z),me.length>0&&Ui(me,I,z),Me.length>0&&Ui(Me,I,z),Te.buffers.depth.setTest(!0),Te.buffers.depth.setMask(!0),Te.buffers.color.setMask(!0),Te.setPolygonOffset(!1)}function Di(S,I,z,G){if((z.isScene===!0?z.overrideMaterial:null)!==null)return;const me=Ce.isWebGL2;de===null&&(de=new Bn(1,1,{generateMipmaps:!0,type:le.has("EXT_color_buffer_half_float")?wi:vn,minFilter:In,samples:me?4:0})),_.getDrawingBufferSize(ve),me?de.setSize(ve.x,ve.y):de.setSize(ds(ve.x),ds(ve.y));const Me=_.getRenderTarget();_.setRenderTarget(de),_.getClearColor(Z),D=_.getClearAlpha(),D<1&&_.setClearColor(16777215,.5),_.clear();const Ae=_.toneMapping;_.toneMapping=_n,Ui(S,z,G),Be.updateMultisampleRenderTarget(de),Be.updateRenderTargetMipmap(de);let Pe=!1;for(let We=0,Ie=I.length;We0),Fe=!!z.morphAttributes.position,ot=!!z.morphAttributes.normal,Rt=!!z.morphAttributes.color;let dt=_n;G.toneMapped&&(E===null||E.isXRRenderTarget===!0)&&(dt=_.toneMapping);const jt=z.morphAttributes.position||z.morphAttributes.normal||z.morphAttributes.color,it=jt!==void 0?jt.length:0,ze=Ne.get(G),xr=d.state.lights;if(B===!0&&(Q===!0||S!==$)){const Lt=S===$&&G.id===F;oe.setState(G,S,Lt)}let nt=!1;G.version===ze.__version?(ze.needsLights&&ze.lightsStateVersion!==xr.state.version||ze.outputColorSpace!==Ae||O.isBatchedMesh&&ze.batching===!1||!O.isBatchedMesh&&ze.batching===!0||O.isInstancedMesh&&ze.instancing===!1||!O.isInstancedMesh&&ze.instancing===!0||O.isSkinnedMesh&&ze.skinning===!1||!O.isSkinnedMesh&&ze.skinning===!0||O.isInstancedMesh&&ze.instancingColor===!0&&O.instanceColor===null||O.isInstancedMesh&&ze.instancingColor===!1&&O.instanceColor!==null||O.isInstancedMesh&&ze.instancingMorph===!0&&O.morphTexture===null||O.isInstancedMesh&&ze.instancingMorph===!1&&O.morphTexture!==null||ze.envMap!==Pe||G.fog===!0&&ze.fog!==me||ze.numClippingPlanes!==void 0&&(ze.numClippingPlanes!==oe.numPlanes||ze.numIntersection!==oe.numIntersection)||ze.vertexAlphas!==We||ze.vertexTangents!==Ie||ze.morphTargets!==Fe||ze.morphNormals!==ot||ze.morphColors!==Rt||ze.toneMapping!==dt||Ce.isWebGL2===!0&&ze.morphTargetsCount!==it)&&(nt=!0):(nt=!0,ze.__version=G.version);let yn=ze.currentProgram;nt===!0&&(yn=Ii(G,I,O));let Ts=!1,gi=!1,Mr=!1;const gt=yn.getUniforms(),Tn=ze.uniforms;if(Te.useProgram(yn.program)&&(Ts=!0,gi=!0,Mr=!0),G.id!==F&&(F=G.id,gi=!0),Ts||$!==S){gt.setValue(P,"projectionMatrix",S.projectionMatrix),gt.setValue(P,"viewMatrix",S.matrixWorldInverse);const Lt=gt.map.cameraPosition;Lt!==void 0&&Lt.setValue(P,fe.setFromMatrixPosition(S.matrixWorld)),Ce.logarithmicDepthBuffer&>.setValue(P,"logDepthBufFC",2/(Math.log(S.far+1)/Math.LN2)),(G.isMeshPhongMaterial||G.isMeshToonMaterial||G.isMeshLambertMaterial||G.isMeshBasicMaterial||G.isMeshStandardMaterial||G.isShaderMaterial)&>.setValue(P,"isOrthographic",S.isOrthographicCamera===!0),$!==S&&($=S,gi=!0,Mr=!0)}if(O.isSkinnedMesh){gt.setOptional(P,O,"bindMatrix"),gt.setOptional(P,O,"bindMatrixInverse");const Lt=O.skeleton;Lt&&(Ce.floatVertexTextures?(Lt.boneTexture===null&&Lt.computeBoneTexture(),gt.setValue(P,"boneTexture",Lt.boneTexture,Be)):console.warn("THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required."))}O.isBatchedMesh&&(gt.setOptional(P,O,"batchingTexture"),gt.setValue(P,"batchingTexture",O._matricesTexture,Be));const Sr=z.morphAttributes;if((Sr.position!==void 0||Sr.normal!==void 0||Sr.color!==void 0&&Ce.isWebGL2===!0)&&se.update(O,z,yn),(gi||ze.receiveShadow!==O.receiveShadow)&&(ze.receiveShadow=O.receiveShadow,gt.setValue(P,"receiveShadow",O.receiveShadow)),G.isMeshGouraudMaterial&&G.envMap!==null&&(Tn.envMap.value=Pe,Tn.flipEnvMap.value=Pe.isCubeTexture&&Pe.isRenderTargetTexture===!1?-1:1),gi&&(gt.setValue(P,"toneMappingExposure",_.toneMappingExposure),ze.needsLights&&qo(Tn,Mr),me&&G.fog===!0&&J.refreshFogUniforms(Tn,me),J.refreshMaterialUniforms(Tn,G,Y,H,de),or.upload(P,Es(ze),Tn,Be)),G.isShaderMaterial&&G.uniformsNeedUpdate===!0&&(or.upload(P,Es(ze),Tn,Be),G.uniformsNeedUpdate=!1),G.isSpriteMaterial&>.setValue(P,"center",O.center),gt.setValue(P,"modelViewMatrix",O.modelViewMatrix),gt.setValue(P,"normalMatrix",O.normalMatrix),gt.setValue(P,"modelMatrix",O.matrixWorld),G.isShaderMaterial||G.isRawShaderMaterial){const Lt=G.uniformsGroups;for(let Er=0,jo=Lt.length;Er0&&Be.useMultisampledRTT(S)===!1?O=Ne.get(S).__webglMultisampledFramebuffer:Array.isArray(Ie)?O=Ie[z]:O=Ie,x.copy(S.viewport),A.copy(S.scissor),te=S.scissorTest}else x.copy(re).multiplyScalar(Y).floor(),A.copy(ae).multiplyScalar(Y).floor(),te=pe;if(Te.bindFramebuffer(P.FRAMEBUFFER,O)&&Ce.drawBuffers&&G&&Te.drawBuffers(S,O),Te.viewport(x),Te.scissor(A),Te.setScissorTest(te),me){const Pe=Ne.get(S.texture);P.framebufferTexture2D(P.FRAMEBUFFER,P.COLOR_ATTACHMENT0,P.TEXTURE_CUBE_MAP_POSITIVE_X+I,Pe.__webglTexture,z)}else if(Me){const Pe=Ne.get(S.texture),We=I||0;P.framebufferTextureLayer(P.FRAMEBUFFER,P.COLOR_ATTACHMENT0,Pe.__webglTexture,z||0,We)}F=-1},this.readRenderTargetPixels=function(S,I,z,G,O,me,Me){if(!(S&&S.isWebGLRenderTarget)){console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");return}let Ae=Ne.get(S).__webglFramebuffer;if(S.isWebGLCubeRenderTarget&&Me!==void 0&&(Ae=Ae[Me]),Ae){Te.bindFramebuffer(P.FRAMEBUFFER,Ae);try{const Pe=S.texture,We=Pe.format,Ie=Pe.type;if(We!==Ht&&Se.convert(We)!==P.getParameter(P.IMPLEMENTATION_COLOR_READ_FORMAT)){console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.");return}const Fe=Ie===wi&&(le.has("EXT_color_buffer_half_float")||Ce.isWebGL2&&le.has("EXT_color_buffer_float"));if(Ie!==vn&&Se.convert(Ie)!==P.getParameter(P.IMPLEMENTATION_COLOR_READ_TYPE)&&!(Ie===nn&&(Ce.isWebGL2||le.has("OES_texture_float")||le.has("WEBGL_color_buffer_float")))&&!Fe){console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.");return}I>=0&&I<=S.width-G&&z>=0&&z<=S.height-O&&P.readPixels(I,z,G,O,Se.convert(We),Se.convert(Ie),me)}finally{const Pe=E!==null?Ne.get(E).__webglFramebuffer:null;Te.bindFramebuffer(P.FRAMEBUFFER,Pe)}}},this.copyFramebufferToTexture=function(S,I,z=0){const G=Math.pow(2,-z),O=Math.floor(I.image.width*G),me=Math.floor(I.image.height*G);Be.setTexture2D(I,0),P.copyTexSubImage2D(P.TEXTURE_2D,z,0,0,S.x,S.y,O,me),Te.unbindTexture()},this.copyTextureToTexture=function(S,I,z,G=0){const O=I.image.width,me=I.image.height,Me=Se.convert(z.format),Ae=Se.convert(z.type);Be.setTexture2D(z,0),P.pixelStorei(P.UNPACK_FLIP_Y_WEBGL,z.flipY),P.pixelStorei(P.UNPACK_PREMULTIPLY_ALPHA_WEBGL,z.premultiplyAlpha),P.pixelStorei(P.UNPACK_ALIGNMENT,z.unpackAlignment),I.isDataTexture?P.texSubImage2D(P.TEXTURE_2D,G,S.x,S.y,O,me,Me,Ae,I.image.data):I.isCompressedTexture?P.compressedTexSubImage2D(P.TEXTURE_2D,G,S.x,S.y,I.mipmaps[0].width,I.mipmaps[0].height,Me,I.mipmaps[0].data):P.texSubImage2D(P.TEXTURE_2D,G,S.x,S.y,Me,Ae,I.image),G===0&&z.generateMipmaps&&P.generateMipmap(P.TEXTURE_2D),Te.unbindTexture()},this.copyTextureToTexture3D=function(S,I,z,G,O=0){if(_.isWebGL1Renderer){console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.");return}const me=Math.round(S.max.x-S.min.x),Me=Math.round(S.max.y-S.min.y),Ae=S.max.z-S.min.z+1,Pe=Se.convert(G.format),We=Se.convert(G.type);let Ie;if(G.isData3DTexture)Be.setTexture3D(G,0),Ie=P.TEXTURE_3D;else if(G.isDataArrayTexture||G.isCompressedArrayTexture)Be.setTexture2DArray(G,0),Ie=P.TEXTURE_2D_ARRAY;else{console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.");return}P.pixelStorei(P.UNPACK_FLIP_Y_WEBGL,G.flipY),P.pixelStorei(P.UNPACK_PREMULTIPLY_ALPHA_WEBGL,G.premultiplyAlpha),P.pixelStorei(P.UNPACK_ALIGNMENT,G.unpackAlignment);const Fe=P.getParameter(P.UNPACK_ROW_LENGTH),ot=P.getParameter(P.UNPACK_IMAGE_HEIGHT),Rt=P.getParameter(P.UNPACK_SKIP_PIXELS),dt=P.getParameter(P.UNPACK_SKIP_ROWS),jt=P.getParameter(P.UNPACK_SKIP_IMAGES),it=z.isCompressedTexture?z.mipmaps[O]:z.image;P.pixelStorei(P.UNPACK_ROW_LENGTH,it.width),P.pixelStorei(P.UNPACK_IMAGE_HEIGHT,it.height),P.pixelStorei(P.UNPACK_SKIP_PIXELS,S.min.x),P.pixelStorei(P.UNPACK_SKIP_ROWS,S.min.y),P.pixelStorei(P.UNPACK_SKIP_IMAGES,S.min.z),z.isDataTexture||z.isData3DTexture?P.texSubImage3D(Ie,O,I.x,I.y,I.z,me,Me,Ae,Pe,We,it.data):G.isCompressedArrayTexture?P.compressedTexSubImage3D(Ie,O,I.x,I.y,I.z,me,Me,Ae,Pe,it.data):P.texSubImage3D(Ie,O,I.x,I.y,I.z,me,Me,Ae,Pe,We,it),P.pixelStorei(P.UNPACK_ROW_LENGTH,Fe),P.pixelStorei(P.UNPACK_IMAGE_HEIGHT,ot),P.pixelStorei(P.UNPACK_SKIP_PIXELS,Rt),P.pixelStorei(P.UNPACK_SKIP_ROWS,dt),P.pixelStorei(P.UNPACK_SKIP_IMAGES,jt),O===0&&G.generateMipmaps&&P.generateMipmap(Ie),Te.unbindTexture()},this.initTexture=function(S){S.isCubeTexture?Be.setTextureCube(S,0):S.isData3DTexture?Be.setTexture3D(S,0):S.isDataArrayTexture||S.isCompressedArrayTexture?Be.setTexture2DArray(S,0):Be.setTexture2D(S,0),Te.unbindTexture()},this.resetState=function(){L=0,w=0,E=null,Te.reset(),ge.reset()},typeof __THREE_DEVTOOLS__<"u"&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}get coordinateSystem(){return rn}get outputColorSpace(){return this._outputColorSpace}set outputColorSpace(e){this._outputColorSpace=e;const t=this.getContext();t.drawingBufferColorSpace=e===vs?"display-p3":"srgb",t.unpackColorSpace=Ze.workingColorSpace===gr?"display-p3":"srgb"}get useLegacyLights(){return console.warn("THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733."),this._useLegacyLights}set useLegacyLights(e){console.warn("THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733."),this._useLegacyLights=e}}class mp extends ko{}mp.prototype.isWebGL1Renderer=!0;class gp extends yt{constructor(){super(),this.isScene=!0,this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.backgroundBlurriness=0,this.backgroundIntensity=1,this.backgroundRotation=new an,this.environmentRotation=new an,this.overrideMaterial=null,typeof __THREE_DEVTOOLS__<"u"&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}copy(e,t){return super.copy(e,t),e.background!==null&&(this.background=e.background.clone()),e.environment!==null&&(this.environment=e.environment.clone()),e.fog!==null&&(this.fog=e.fog.clone()),this.backgroundBlurriness=e.backgroundBlurriness,this.backgroundIntensity=e.backgroundIntensity,this.backgroundRotation.copy(e.backgroundRotation),this.environmentRotation.copy(e.environmentRotation),e.overrideMaterial!==null&&(this.overrideMaterial=e.overrideMaterial.clone()),this.matrixAutoUpdate=e.matrixAutoUpdate,this}toJSON(e){const t=super.toJSON(e);return this.fog!==null&&(t.object.fog=this.fog.toJSON()),this.backgroundBlurriness>0&&(t.object.backgroundBlurriness=this.backgroundBlurriness),this.backgroundIntensity!==1&&(t.object.backgroundIntensity=this.backgroundIntensity),t.object.backgroundRotation=this.backgroundRotation.toArray(),t.object.environmentRotation=this.environmentRotation.toArray(),t}}class yi extends pi{constructor(e){super(),this.isLineBasicMaterial=!0,this.type="LineBasicMaterial",this.color=new je(16777215),this.map=null,this.linewidth=1,this.linecap="round",this.linejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.linewidth=e.linewidth,this.linecap=e.linecap,this.linejoin=e.linejoin,this.fog=e.fog,this}}const ja=new U,Ka=new U,$a=new rt,ts=new Pi,nr=new Ci;class Ti extends yt{constructor(e=new xt,t=new yi){super(),this.isLine=!0,this.type="Line",this.geometry=e,this.material=t,this.updateMorphTargets()}copy(e,t){return super.copy(e,t),this.material=Array.isArray(e.material)?e.material.slice():e.material,this.geometry=e.geometry,this}computeLineDistances(){const e=this.geometry;if(e.index===null){const t=e.attributes.position,n=[0];for(let r=1,s=t.count;rl)continue;p.applyMatrix4(this.matrixWorld);const F=e.ray.origin.distanceTo(p);Fe.far||t.push({distance:F,point:f.clone().applyMatrix4(this.matrixWorld),index:_,face:null,faceIndex:null,object:this})}}else{const u=Math.max(0,o.start),T=Math.min(d.count,o.start+o.count);for(let _=u,R=T-1;_l)continue;p.applyMatrix4(this.matrixWorld);const w=e.ray.origin.distanceTo(p);we.far||t.push({distance:w,point:f.clone().applyMatrix4(this.matrixWorld),index:_,face:null,faceIndex:null,object:this})}}}updateMorphTargets(){const t=this.geometry.morphAttributes,n=Object.keys(t);if(n.length>0){const r=t[n[0]];if(r!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let s=0,o=r.length;s0){const r=t[n[0]];if(r!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let s=0,o=r.length;sr.far)return;s.push({distance:c,distanceToRay:Math.sqrt(a),point:l,index:e,face:null,object:o})}}class Ai extends xt{constructor(e=1,t=32,n=16,r=0,s=Math.PI*2,o=0,a=Math.PI){super(),this.type="SphereGeometry",this.parameters={radius:e,widthSegments:t,heightSegments:n,phiStart:r,phiLength:s,thetaStart:o,thetaLength:a},t=Math.max(3,Math.floor(t)),n=Math.max(2,Math.floor(n));const l=Math.min(o+a,Math.PI);let c=0;const h=[],f=new U,p=new U,m=[],g=[],M=[],d=[];for(let u=0;u<=n;u++){const T=[],_=u/n;let R=0;u===0&&o===0?R=.5/t:u===n&&l===Math.PI&&(R=-.5/t);for(let L=0;L<=t;L++){const w=L/t;f.x=-e*Math.cos(r+w*s)*Math.sin(o+_*a),f.y=e*Math.cos(o+_*a),f.z=e*Math.sin(r+w*s)*Math.sin(o+_*a),g.push(f.x,f.y,f.z),p.copy(f).normalize(),M.push(p.x,p.y,p.z),d.push(w+R,1-_),T.push(c++)}h.push(T)}for(let u=0;u0)&&m.push(_,R,w),(u!==n-1||lMath.PI&&(Je-=ee),at<-Math.PI?at+=ee:at>Math.PI&&(at-=ee),Je<=at?a.theta=Math.max(Je,Math.min(at,a.theta)):a.theta=a.theta>(Je+at)/2?Math.max(Je,a.theta):Math.min(at,a.theta)),a.phi=Math.max(n.minPolarAngle,Math.min(n.maxPolarAngle,a.phi)),a.makeSafe(),n.enableDamping===!0?n.target.addScaledVector(h,n.dampingFactor):n.target.add(h),n.target.sub(n.cursor),n.target.clampLength(n.minTargetRadius,n.maxTargetRadius),n.target.add(n.cursor);let Ye=!1;if(n.zoomToCursor&&w||n.object.isOrthographicCamera)a.radius=re(a.radius);else{const et=a.radius;a.radius=re(a.radius*c),Ye=et!=a.radius}if(b.setFromSpherical(a),b.applyQuaternion(_e),Ke.copy(n.target).add(b),n.object.lookAt(n.target),n.enableDamping===!0?(l.theta*=1-n.dampingFactor,l.phi*=1-n.dampingFactor,h.multiplyScalar(1-n.dampingFactor)):(l.set(0,0,0),h.set(0,0,0)),n.zoomToCursor&&w){let et=null;if(n.object.isPerspectiveCamera){const mt=b.length();et=re(mt*c);const En=mt-et;n.object.position.addScaledVector(R,En),n.object.updateMatrixWorld(),Ye=!!En}else if(n.object.isOrthographicCamera){const mt=new U(L.x,L.y,0);mt.unproject(n.object);const En=n.object.zoom;n.object.zoom=Math.max(n.minZoom,Math.min(n.maxZoom,n.object.zoom/c)),n.object.updateProjectionMatrix(),Ye=En!==n.object.zoom;const Di=new U(L.x,L.y,0);Di.unproject(n.object),n.object.position.sub(Di).add(mt),n.object.updateMatrixWorld(),et=b.length()}else console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."),n.zoomToCursor=!1;et!==null&&(this.screenSpacePanning?n.target.set(0,0,-1).transformDirection(n.object.matrix).multiplyScalar(et).add(n.object.position):(sr.origin.copy(n.object.position),sr.direction.set(0,0,-1).transformDirection(n.object.matrix),Math.abs(n.object.up.dot(sr.direction))o||8*(1-ie.dot(n.object.quaternion))>o||N.distanceToSquared(n.target)>o?(n.dispatchEvent(ro),C.copy(n.object.position),ie.copy(n.object.quaternion),N.copy(n.target),!0):!1}}(),this.dispose=function(){n.domElement.removeEventListener("contextmenu",De),n.domElement.removeEventListener("pointerdown",Be),n.domElement.removeEventListener("pointercancel",y),n.domElement.removeEventListener("wheel",j),n.domElement.removeEventListener("pointermove",Qe),n.domElement.removeEventListener("pointerup",y),n.domElement.getRootNode().removeEventListener("keydown",J,{capture:!0}),n._domElementKeyEvents!==null&&(n._domElementKeyEvents.removeEventListener("keydown",be),n._domElementKeyEvents=null)};const n=this,r={NONE:-1,ROTATE:0,DOLLY:1,PAN:2,TOUCH_ROTATE:3,TOUCH_PAN:4,TOUCH_DOLLY_PAN:5,TOUCH_DOLLY_ROTATE:6};let s=r.NONE;const o=1e-6,a=new io,l=new io;let c=1;const h=new U,f=new Ue,p=new Ue,m=new Ue,g=new Ue,M=new Ue,d=new Ue,u=new Ue,T=new Ue,_=new Ue,R=new U,L=new Ue;let w=!1;const E=[],F={};let $=!1;function x(b){return b!==null?2*Math.PI/60*n.autoRotateSpeed*b:2*Math.PI/60/60*n.autoRotateSpeed}function A(b){const K=Math.abs(b*.01);return Math.pow(.95,n.zoomSpeed*K)}function te(b){l.theta-=b}function Z(b){l.phi-=b}const D=function(){const b=new U;return function(_e,C){b.setFromMatrixColumn(C,0),b.multiplyScalar(-_e),h.add(b)}}(),q=function(){const b=new U;return function(_e,C){n.screenSpacePanning===!0?b.setFromMatrixColumn(C,1):(b.setFromMatrixColumn(C,0),b.crossVectors(n.object.up,b)),b.multiplyScalar(_e),h.add(b)}}(),H=function(){const b=new U;return function(_e,C){const ie=n.domElement;if(n.object.isPerspectiveCamera){const N=n.object.position;b.copy(N).sub(n.target);let ee=b.length();ee*=Math.tan(n.object.fov/2*Math.PI/180),D(2*_e*ee/ie.clientHeight,n.object.matrix),q(2*C*ee/ie.clientHeight,n.object.matrix)}else n.object.isOrthographicCamera?(D(_e*(n.object.right-n.object.left)/n.object.zoom/ie.clientWidth,n.object.matrix),q(C*(n.object.top-n.object.bottom)/n.object.zoom/ie.clientHeight,n.object.matrix)):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."),n.enablePan=!1)}}();function Y(b){n.object.isPerspectiveCamera||n.object.isOrthographicCamera?c/=b:(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),n.enableZoom=!1)}function W(b){n.object.isPerspectiveCamera||n.object.isOrthographicCamera?c*=b:(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),n.enableZoom=!1)}function X(b,K){if(!n.zoomToCursor)return;w=!0;const _e=n.domElement.getBoundingClientRect(),C=b-_e.left,ie=K-_e.top,N=_e.width,ee=_e.height;L.x=C/N*2-1,L.y=-(ie/ee)*2+1,R.set(L.x,L.y,1).unproject(n.object).sub(n.object.position).normalize()}function re(b){return Math.max(n.minDistance,Math.min(n.maxDistance,b))}function ae(b){f.set(b.clientX,b.clientY)}function pe(b){X(b.clientX,b.clientX),u.set(b.clientX,b.clientY)}function Ee(b){g.set(b.clientX,b.clientY)}function B(b){p.set(b.clientX,b.clientY),m.subVectors(p,f).multiplyScalar(n.rotateSpeed);const K=n.domElement;te(2*Math.PI*m.x/K.clientHeight),Z(2*Math.PI*m.y/K.clientHeight),f.copy(p),n.update()}function Q(b){T.set(b.clientX,b.clientY),_.subVectors(T,u),_.y>0?Y(A(_.y)):_.y<0&&W(A(_.y)),u.copy(T),n.update()}function de(b){M.set(b.clientX,b.clientY),d.subVectors(M,g).multiplyScalar(n.panSpeed),H(d.x,d.y),g.copy(M),n.update()}function Re(b){X(b.clientX,b.clientY),b.deltaY<0?W(A(b.deltaY)):b.deltaY>0&&Y(A(b.deltaY)),n.update()}function ve(b){let K=!1;switch(b.code){case n.keys.UP:b.ctrlKey||b.metaKey||b.shiftKey?Z(2*Math.PI*n.rotateSpeed/n.domElement.clientHeight):H(0,n.keyPanSpeed),K=!0;break;case n.keys.BOTTOM:b.ctrlKey||b.metaKey||b.shiftKey?Z(-2*Math.PI*n.rotateSpeed/n.domElement.clientHeight):H(0,-n.keyPanSpeed),K=!0;break;case n.keys.LEFT:b.ctrlKey||b.metaKey||b.shiftKey?te(2*Math.PI*n.rotateSpeed/n.domElement.clientHeight):H(n.keyPanSpeed,0),K=!0;break;case n.keys.RIGHT:b.ctrlKey||b.metaKey||b.shiftKey?te(-2*Math.PI*n.rotateSpeed/n.domElement.clientHeight):H(-n.keyPanSpeed,0),K=!0;break}K&&(b.preventDefault(),n.update())}function fe(b){if(E.length===1)f.set(b.pageX,b.pageY);else{const K=ge(b),_e=.5*(b.pageX+K.x),C=.5*(b.pageY+K.y);f.set(_e,C)}}function qe(b){if(E.length===1)g.set(b.pageX,b.pageY);else{const K=ge(b),_e=.5*(b.pageX+K.x),C=.5*(b.pageY+K.y);g.set(_e,C)}}function k(b){const K=ge(b),_e=b.pageX-K.x,C=b.pageY-K.y,ie=Math.sqrt(_e*_e+C*C);u.set(0,ie)}function P(b){n.enableZoom&&k(b),n.enablePan&&qe(b)}function ye(b){n.enableZoom&&k(b),n.enableRotate&&fe(b)}function le(b){if(E.length==1)p.set(b.pageX,b.pageY);else{const _e=ge(b),C=.5*(b.pageX+_e.x),ie=.5*(b.pageY+_e.y);p.set(C,ie)}m.subVectors(p,f).multiplyScalar(n.rotateSpeed);const K=n.domElement;te(2*Math.PI*m.x/K.clientHeight),Z(2*Math.PI*m.y/K.clientHeight),f.copy(p)}function Ce(b){if(E.length===1)M.set(b.pageX,b.pageY);else{const K=ge(b),_e=.5*(b.pageX+K.x),C=.5*(b.pageY+K.y);M.set(_e,C)}d.subVectors(M,g).multiplyScalar(n.panSpeed),H(d.x,d.y),g.copy(M)}function Te(b){const K=ge(b),_e=b.pageX-K.x,C=b.pageY-K.y,ie=Math.sqrt(_e*_e+C*C);T.set(0,ie),_.set(0,Math.pow(T.y/u.y,n.zoomSpeed)),Y(_.y),u.copy(T);const N=(b.pageX+K.x)*.5,ee=(b.pageY+K.y)*.5;X(N,ee)}function Ve(b){n.enableZoom&&Te(b),n.enablePan&&Ce(b)}function Ne(b){n.enableZoom&&Te(b),n.enableRotate&&le(b)}function Be(b){n.enabled!==!1&&(E.length===0&&(n.domElement.setPointerCapture(b.pointerId),n.domElement.addEventListener("pointermove",Qe),n.domElement.addEventListener("pointerup",y)),!ke(b)&&(se(b),b.pointerType==="touch"?oe(b):v(b)))}function Qe(b){n.enabled!==!1&&(b.pointerType==="touch"?ue(b):V(b))}function y(b){switch(st(b),E.length){case 0:n.domElement.releasePointerCapture(b.pointerId),n.domElement.removeEventListener("pointermove",Qe),n.domElement.removeEventListener("pointerup",y),n.dispatchEvent(so),s=r.NONE;break;case 1:const K=E[0],_e=F[K];oe({pointerId:K,pageX:_e.x,pageY:_e.y});break}}function v(b){let K;switch(b.button){case 0:K=n.mouseButtons.LEFT;break;case 1:K=n.mouseButtons.MIDDLE;break;case 2:K=n.mouseButtons.RIGHT;break;default:K=-1}switch(K){case Gn.DOLLY:if(n.enableZoom===!1)return;pe(b),s=r.DOLLY;break;case Gn.ROTATE:if(b.ctrlKey||b.metaKey||b.shiftKey){if(n.enablePan===!1)return;Ee(b),s=r.PAN}else{if(n.enableRotate===!1)return;ae(b),s=r.ROTATE}break;case Gn.PAN:if(b.ctrlKey||b.metaKey||b.shiftKey){if(n.enableRotate===!1)return;ae(b),s=r.ROTATE}else{if(n.enablePan===!1)return;Ee(b),s=r.PAN}break;default:s=r.NONE}s!==r.NONE&&n.dispatchEvent(ns)}function V(b){switch(s){case r.ROTATE:if(n.enableRotate===!1)return;B(b);break;case r.DOLLY:if(n.enableZoom===!1)return;Q(b);break;case r.PAN:if(n.enablePan===!1)return;de(b);break}}function j(b){n.enabled===!1||n.enableZoom===!1||s!==r.NONE||(b.preventDefault(),n.dispatchEvent(ns),Re(ne(b)),n.dispatchEvent(so))}function ne(b){const K=b.deltaMode,_e={clientX:b.clientX,clientY:b.clientY,deltaY:b.deltaY};switch(K){case 1:_e.deltaY*=16;break;case 2:_e.deltaY*=100;break}return b.ctrlKey&&!$&&(_e.deltaY*=10),_e}function J(b){b.key==="Control"&&($=!0,n.domElement.getRootNode().addEventListener("keyup",Le,{passive:!0,capture:!0}))}function Le(b){b.key==="Control"&&($=!1,n.domElement.getRootNode().removeEventListener("keyup",Le,{passive:!0,capture:!0}))}function be(b){n.enabled===!1||n.enablePan===!1||ve(b)}function oe(b){switch(Se(b),E.length){case 1:switch(n.touches.ONE){case Hn.ROTATE:if(n.enableRotate===!1)return;fe(b),s=r.TOUCH_ROTATE;break;case Hn.PAN:if(n.enablePan===!1)return;qe(b),s=r.TOUCH_PAN;break;default:s=r.NONE}break;case 2:switch(n.touches.TWO){case Hn.DOLLY_PAN:if(n.enableZoom===!1&&n.enablePan===!1)return;P(b),s=r.TOUCH_DOLLY_PAN;break;case Hn.DOLLY_ROTATE:if(n.enableZoom===!1&&n.enableRotate===!1)return;ye(b),s=r.TOUCH_DOLLY_ROTATE;break;default:s=r.NONE}break;default:s=r.NONE}s!==r.NONE&&n.dispatchEvent(ns)}function ue(b){switch(Se(b),s){case r.TOUCH_ROTATE:if(n.enableRotate===!1)return;le(b),n.update();break;case r.TOUCH_PAN:if(n.enablePan===!1)return;Ce(b),n.update();break;case r.TOUCH_DOLLY_PAN:if(n.enableZoom===!1&&n.enablePan===!1)return;Ve(b),n.update();break;case r.TOUCH_DOLLY_ROTATE:if(n.enableZoom===!1&&n.enableRotate===!1)return;Ne(b),n.update();break;default:s=r.NONE}}function De(b){n.enabled!==!1&&b.preventDefault()}function se(b){E.push(b.pointerId)}function st(b){delete F[b.pointerId];for(let K=0;Knew U(i[0],i[1],i[2]);class Ep{constructor(e){$e(this,"renderer");$e(this,"scene",new gp);$e(this,"root",new Wt);$e(this,"camera");$e(this,"controls");$e(this,"pointsMaterial",new Wo({size:.004,vertexColors:!0}));$e(this,"pathGroup",new Wt);$e(this,"gridGroup",new Wt);$e(this,"markerGroup",new Wt);$e(this,"frustaGroup",new Wt);$e(this,"measureGroup",new Wt);$e(this,"marker",null);$e(this,"frustum",null);$e(this,"pointsObject",null);$e(this,"meta",null);$e(this,"viewerBase",null);$e(this,"radius",1);$e(this,"disposed",!1);$e(this,"animationHandle",0);$e(this,"measureMode",!1);$e(this,"measurePoints",[]);$e(this,"onMeasure",null);$e(this,"raycaster",new xp);$e(this,"pointerNdc",new Ue);$e(this,"resizeObserver");$e(this,"pickPoint",e=>{var l;if(!this.measureMode||!this.pointsObject)return;const t=this.renderer.domElement.getBoundingClientRect();this.pointerNdc.x=(e.clientX-t.left)/t.width*2-1,this.pointerNdc.y=-((e.clientY-t.top)/t.height)*2+1,this.raycaster.setFromCamera(this.pointerNdc,this.camera),this.raycaster.params.Points.threshold=Math.max(this.pointsMaterial.size*2.5,.012);const n=this.raycaster.intersectObject(this.pointsObject,!1);let r=null;for(const c of n)c.index==null||c.distanceToRay==null||(r===null||c.distanceToRay<(r.distanceToRay??1/0))&&(r=c);if(r===null||r.index==null)return;const s=new U().fromBufferAttribute(this.pointsObject.geometry.getAttribute("position"),r.index);this.measurePoints.length>=2&&this.clearMeasurement(),this.measurePoints.push(s.clone());const o=Math.max(this.radius/220,.002),a=new It(new Ai(o,12,12),new bi({color:16777215}));if(a.position.copy(s),this.measureGroup.add(a),this.measurePoints.length===2){const[c,h]=this.measurePoints;this.measureGroup.add(new Ti(new xt().setFromPoints([c,h]),new yi({color:16777215,transparent:!0,opacity:.9})));const f=c.distanceTo(h);(l=this.onMeasure)==null||l.call(this,f*this.scaleMPerUnit(),f)}});$e(this,"resize",()=>{const e=this.holder.clientWidth||1,t=this.holder.clientHeight||1;this.renderer.setSize(e,t,!1),this.camera.aspect=e/t,this.camera.updateProjectionMatrix()});this.holder=e,this.renderer=new ko({antialias:!0,powerPreference:"high-performance"}),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2)),this.renderer.setClearColor(329223),e.appendChild(this.renderer.domElement),this.camera=new Ut(55,1,.001,100),this.controls=new Sp(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.root.add(this.pathGroup,this.gridGroup,this.markerGroup,this.frustaGroup,this.measureGroup),this.scene.add(this.root),this.renderer.domElement.addEventListener("pointerdown",this.pickPoint),this.resize(),this.resizeObserver=new ResizeObserver(this.resize),this.resizeObserver.observe(e);const t=()=>{this.disposed||(this.animationHandle=requestAnimationFrame(t),this.controls.update(),this.renderer.render(this.scene,this.camera))};t()}async load(e){var f;const t=await fetch(`${e}/scene_meta.json`).then(p=>{if(!p.ok)throw new Error(`scene_meta.json: HTTP ${p.status}`);return p.json()}),[n,r]=await Promise.all([fetch(`${e}/${t.assets.positions}`).then(p=>{if(!p.ok)throw new Error(`positions: HTTP ${p.status}`);return p.arrayBuffer()}),fetch(`${e}/${t.assets.colors}`).then(p=>{if(!p.ok)throw new Error(`colors: HTTP ${p.status}`);return p.arrayBuffer()})]);if(this.disposed)return{pointCount:0,frames:0};this.meta=t,this.viewerBase=e;const s=new Float32Array(n),o=new Uint8Array(r),a=new Float32Array(o.length);for(let p=0;p0)return e;const t=(s=this.meta)==null?void 0:s.default_scale_m_per_unit;return t&&t>0?t:117.6}timeline(){const e=this.meta,t=(e==null?void 0:e.path)??[];if(!e||t.length<2)return null;const n=this.scaleMPerUnit(),r=e.ground_grid,s=r?lt(r.fitted_normal??r.normal).normalize():null,o=[];for(let f=0;f0){const T=t[f-1],_=(p.sequence_time_s??0)-(T.sequence_time_s??0);_>1e-4&&(d=m.distanceTo(lt(T.position))*n/_)}const u=typeof p.distance_to_end_units=="number"?p.distance_to_end_units*n:null;o.push({t:g,heightM:M,speedRawMs:d,speedMs:d,distM:u})}const a=o.map((f,p)=>{if(p===0||p===o.length-1)return f.speedRawMs;const m=[o[p-1].speedRawMs,f.speedRawMs,o[p+1].speedRawMs].filter(g=>g!==null);return m.length===3?m.slice().sort((g,M)=>g-M)[1]:f.speedRawMs});for(let f=0;fm+g,0)/p.length:null}let l=0;for(let f=1;f1e-4?l*n/c:null;return{t0:o[0].t,t1:o[o.length-1].t,avgSpeedMs:h,points:o}}frames(){var r;const e=((r=this.meta)==null?void 0:r.path)??[],t=this.viewerBase;if(!t)return[];const n=s=>s?`${t}/${s}`:null;return e.map((s,o)=>({t:s.sequence_time_s??o,actual:n(s.actual_image??s.frame_image),render:n(s.render_image),overlay:n(s.overlay_image)}))}setTime(e){var p;const t=((p=this.meta)==null?void 0:p.path)??[];if(t.length===0||!this.marker)return;const n=t.map((m,g)=>m.sequence_time_s??g);let r=0;for(;r1e-6?Math.min(1,Math.max(0,(e-a)/c)):0,f=lt(s.position).lerp(lt(o.position),h);this.marker.position.copy(f),this.frustum&&(this.frustum.position.copy(f),this.orientByFrame(this.frustum,h<.5?s:o))}setPathVisible(e){this.pathGroup.visible=e}setGridVisible(e){this.gridGroup.visible=e}setPointsVisible(e){this.pointsObject&&(this.pointsObject.visible=e)}setFrustaVisible(e){this.frustaGroup.visible=e}setMeasureMode(e,t){this.measureMode=e,t&&(this.onMeasure=t),this.clearMeasurement()}clearMeasurement(){var e;this.measurePoints=[],this.measureGroup.clear(),(e=this.onMeasure)==null||e.call(this,null,null)}alignmentQuaternion(e){const t=e.scene_alignment_quaternion;if(Array.isArray(t)&&t.length===4)return new Yt(t[0],t[1],t[2],t[3]);const n=e.ground_grid;if(!n)return null;const r=lt(n.fitted_normal??n.normal).normalize(),s=new Yt().setFromUnitVectors(r,new U(0,1,0)),o=lt(n.u).applyQuaternion(s).normalize(),a=new U(o.x,0,o.z);return a.lengthSq()<1e-8?a.set(1,0,0):a.normalize(),new Yt().setFromUnitVectors(a,new U(1,0,0)).multiply(s)}buildPath(e){const t=e.path??[];if(t.length<2)return;const n=t.map(o=>lt(o.position)),r=new xt().setFromPoints(n);this.pathGroup.add(new Ti(r,new yi({color:3314175,transparent:!0,opacity:.85})));const s=(o,a,l)=>{const c=new It(new Ai(a,16,16),new bi({color:l}));c.position.copy(o),this.pathGroup.add(c)};s(n[0],Math.max(this.radius/110,.003),3314175),s(n[n.length-1],Math.max(this.radius/80,.004),16731501)}frustumWire(e,t,n){const r=this.radius/14*e,s=r*(368/720),o=this.radius/9*e,a=[new U(-r,-s,-o),new U(r,-s,-o),new U(r,s,-o),new U(-r,s,-o)],l=new U(0,0,0),c=[];for(let h=0;h<4;h+=1)c.push(l.clone(),a[h].clone()),c.push(a[h].clone(),a[(h+1)%4].clone());return new _p(new xt().setFromPoints(c),new yi({color:t,transparent:!0,opacity:n}))}orientByFrame(e,t){if(t.right&&t.down&&t.forward){const n=new rt().makeBasis(lt(t.right).normalize(),lt(t.down).normalize().multiplyScalar(-1),lt(t.forward).normalize().multiplyScalar(-1));e.setRotationFromMatrix(n)}}buildMarker(e){var n;if(!((n=e.path)!=null&&n.length))return;const t=Math.max(this.radius/130,.004);this.marker=new It(new Ai(t,16,16),new bi({color:16756736})),this.markerGroup.add(this.marker),this.frustum=this.frustumWire(1,16756736,.9),this.markerGroup.add(this.frustum)}buildFrusta(e){const t=e.path??[];for(let n=0;nE-F),h.sort((E,F)=>E-F);const p=(E,F)=>E[Math.min(E.length-1,Math.max(0,Math.round(F*(E.length-1))))],m=(p(c,.01)+p(c,.99))/2,g=(p(h,.01)+p(h,.99))/2,M=r.clone().add(s.clone().multiplyScalar(m)).add(o.clone().multiplyScalar(g)),d=Math.max(p(c,.99)-p(c,.01),p(h,.99)-p(h,.01)),u=n.major_step_units||1,T=Math.max(Math.ceil(d*1.25/u)*u,u*5)/2,_=n.minor_step_units||u/4,R=Math.max(1,Math.round(u/_)),L=Math.ceil(T/_),w=E=>new yi({color:E?4940914:2437434,transparent:!0,opacity:E?.85:.45});for(let E=-L;E<=L;E+=1){const F=E*_,$=E%R===0,x=new xt().setFromPoints([M.clone().add(s.clone().multiplyScalar(-T)).add(o.clone().multiplyScalar(F)),M.clone().add(s.clone().multiplyScalar(T)).add(o.clone().multiplyScalar(F))]),A=new xt().setFromPoints([M.clone().add(o.clone().multiplyScalar(-T)).add(s.clone().multiplyScalar(F)),M.clone().add(o.clone().multiplyScalar(T)).add(s.clone().multiplyScalar(F))]);this.gridGroup.add(new Ti(x,w($)),new Ti(A,w($)))}}fitView(e,t){const n=new fi;if(e.bbox_min&&e.bbox_max)n.set(lt(e.bbox_min),lt(e.bbox_max));else{const c=new U;for(let h=0;hc.clone().applyQuaternion(this.root.quaternion),l=a(r);this.camera.position.copy(a(o)),this.camera.near=Math.max(5e-4,s/3e3),this.camera.far=s*30,this.camera.updateProjectionMatrix(),this.controls.target.copy(l),this.controls.minDistance=s*.05,this.controls.maxDistance=s*12,this.controls.update(),this.pointsMaterial.size=s/260}dispose(){this.disposed=!0,cancelAnimationFrame(this.animationHandle),this.resizeObserver.disconnect(),this.renderer.domElement.removeEventListener("pointerdown",this.pickPoint),this.controls.dispose(),this.root.traverse(e=>{const t=e;t.geometry&&t.geometry.dispose();const n=t.material;Array.isArray(n)?n.forEach(r=>r.dispose()):n&&n.dispose()}),this.renderer.dispose(),this.renderer.domElement.remove()}}const qt=44,li=12,Nn=10,pr=18,sn={raw:"rgba(45, 106, 106, 0.9)",smooth:"#ffb000",avg:"rgba(255, 255, 255, 0.35)",height:"#7ee081",playhead:"#ffb000",grid:"rgba(255,255,255,0.08)",label:"#a1a1a1"};function yp(i,e){let t=i[0];for(const n of i)Math.abs(n.t-t.t)<1e-9&&(t=n),Math.abs(n.t-e){const n=t.current;if(!n)return;const r=()=>{const o=Math.min(window.devicePixelRatio||1,2),a=n.clientWidth,l=n.clientHeight;if(!a||!l)return;n.width=a*o,n.height=l*o;const c=n.getContext("2d");c&&(c.scale(o,o),c.clearRect(0,0,a,l),i(c,a,l))};r();const s=new ResizeObserver(r);return s.observe(n),()=>s.disconnect()},e),t}function lo(i,e,t,n,r,s,o){const a=t-Nn-pr;i.font="10px Geist, sans-serif",i.textBaseline="middle";for(let l=0;l<=3;l+=1){const c=Nn+a*l/3;i.strokeStyle=sn.grid,i.beginPath(),i.moveTo(qt,c),i.lineTo(e-li,c),i.stroke(),i.fillStyle=sn.label,i.textAlign="right",i.fillText(o(s*(1-l/3)),qt-6,c)}i.fillStyle=sn.label,i.textAlign="left",i.fillText("0.0s",qt,t-7),i.textAlign="right",i.fillText(`${(r-n).toFixed(1)}s`,e-li,t-7)}function is(i,e,t,n,r,s,o){i.strokeStyle=s,i.lineWidth=o,i.lineJoin="round",i.beginPath();let a=!1;for(const l of e){const c=t(l);c!==null&&(a?i.lineTo(n(l.t),r(c)):(i.moveTo(n(l.t),r(c)),a=!0))}i.stroke()}function co(i,e,t,n){i.strokeStyle=sn.playhead,i.lineWidth=1.4,i.beginPath(),i.moveTo(t,Nn-3),i.lineTo(t,e-pr+3),i.stroke(),n!==null&&(i.fillStyle=sn.playhead,i.beginPath(),i.arc(t,n,4,0,Math.PI*2),i.fill())}function uo({chartRef:i,t0:e,t1:t,onSeek:n}){const r=Oe.useRef(!1),s=o=>{const a=o.currentTarget.getBoundingClientRect(),l=(o.clientX-a.left-qt)/Math.max(a.width-qt-li,1);n(e+Math.min(1,Math.max(0,l))*(t-e))};return we.jsx("canvas",{className:"chart-canvas",ref:i,onPointerDown:o=>{r.current=!0,o.currentTarget.setPointerCapture(o.pointerId),s(o)},onPointerMove:o=>{r.current&&s(o)},onPointerUp:()=>{r.current=!1}})}function Tp({timeline:i,currentT:e,onSeek:t}){const{t0:n,t1:r,points:s,avgSpeedMs:o}=i,a=Math.max(r-n,1e-6),l=Math.min(Math.max(e,n),r),c=yp(s,l),h=s.map(d=>d.speedRawMs).filter(d=>d!==null),f=Math.max(1,...h)*1.12,p=s.map(d=>d.heightM).filter(d=>d!==null),m=Math.max(1,...p)*1.12,g=oo((d,u,T)=>{const _=u-qt-li,R=T-Nn-pr,L=E=>qt+(E-n)/a*_,w=E=>Nn+R-E/f*R;lo(d,u,T,n,r,f,E=>E.toFixed(0)),o!==null&&(d.strokeStyle=sn.avg,d.setLineDash([4,4]),d.beginPath(),d.moveTo(qt,w(o)),d.lineTo(u-li,w(o)),d.stroke(),d.setLineDash([])),is(d,s,E=>E.speedRawMs,L,w,sn.raw,1),is(d,s,E=>E.speedMs,L,w,sn.smooth,2),co(d,T,L(l),c.speedMs!==null?w(c.speedMs):null)},[i,l]),M=oo((d,u,T)=>{const _=u-qt-li,R=T-Nn-pr,L=E=>qt+(E-n)/a*_,w=E=>Nn+R-E/m*R;lo(d,u,T,n,r,m,E=>E.toFixed(0)),is(d,s,E=>E.heightM,L,w,sn.height,2),co(d,T,L(l),c.heightM!==null?w(c.heightM):null)},[i,l]);return we.jsxs("div",{className:"scene-charts",children:[we.jsxs("div",{className:"chart-card",children:[we.jsxs("header",{children:[we.jsx("span",{children:"Speed vs. Time"}),we.jsxs("span",{className:"chart-readout",children:[c.speedMs!==null?`${c.speedMs.toFixed(1)} m/s`:"--",o!==null?` · avg ${o.toFixed(1)}`:""]})]}),we.jsx(uo,{chartRef:g,t0:n,t1:r,onSeek:t})]}),we.jsxs("div",{className:"chart-card",children:[we.jsxs("header",{children:[we.jsx("span",{children:"Height Above Ground"}),we.jsxs("span",{className:"chart-readout",children:[c.heightM!==null?`${c.heightM.toFixed(1)}m AGL`:"--",c.distM!==null?` | ${c.distM.toFixed(0)}m tgt`:""]})]}),we.jsx(uo,{chartRef:M,t0:n,t1:r,onSeek:t})]})]})}function ho(i){const e=Math.floor(i/60),t=(i%60).toFixed(1).padStart(4,"0");return`${e}:${t}`}function fo(i,e){if(!i.length)return-1;let t=0;for(let n=1;n{if(!i.scenePath||!e.current)return;const k=new Ep(e.current);return n.current=k,p("Loading 3D scene…"),k.load(`${Zo}/${i.scenePath}/viewer`).then(P=>{if(n.current!==k)return;g(P);const ye=k.timeline();d(ye),o.current=ye,T(k.frames()),ye&&(r.current={playing:!1,last:0,t:ye.t0},w(ye.t0)),p(null)}).catch(P=>{n.current===k&&p(`Failed to load scene (${P.message??P})`)}),()=>{n.current=null,k.dispose()}},[i.scenePath]);const Ee=Oe.useCallback(k=>{const P=l.current,ye=fo(P,k);if(ye<0)return null;const le=P[ye];return le[c.current]??le.actual},[]),B=Oe.useCallback(k=>{const P=a.current;if(!P||!k)return;const ye=h.current.get(k);if(!ye||!ye.complete||ye.naturalWidth===0)return;(P.width!==ye.naturalWidth||P.height!==ye.naturalHeight)&&(P.width=ye.naturalWidth,P.height=ye.naturalHeight);const le=P.getContext("2d");le&&le.drawImage(ye,0,0)},[]);Oe.useEffect(()=>{l.current=u},[u]),Oe.useEffect(()=>{c.current=_},[_]),Oe.useEffect(()=>{const k=h.current;for(const P of u){const ye=P[_]??P.actual;if(!ye||k.has(ye))continue;const le=new Image;le.decoding="async",le.onload=()=>{Ee(r.current.t)===ye&&B(ye)},le.src=ye,k.set(ye,le)}B(Ee(r.current.t))},[u,_,Ee,B]),Oe.useEffect(()=>{B(Ee(r.current.t))},[L,_,Z,Ee,B]),Oe.useEffect(()=>{let k=0;const P=ye=>{var Ve;k=requestAnimationFrame(P);const le=r.current,Ce=o.current;if(!Ce||!le.playing)return;const Te=(ye-le.last)/1e3;le.last=ye,le.t=Math.min(le.t+Te,Ce.t1),le.t>=Ce.t1&&(le.playing=!1,F(!1)),Math.abs(le.t-s.current)>.02&&(s.current=le.t,(Ve=n.current)==null||Ve.setTime(le.t),B(Ee(le.t)),w(le.t))};return k=requestAnimationFrame(P),()=>cancelAnimationFrame(k)},[B,Ee]),Oe.useEffect(()=>{var k;return(k=n.current)==null?void 0:k.setPathVisible($)},[$]),Oe.useEffect(()=>{var k;return(k=n.current)==null?void 0:k.setGridVisible(A)},[A]),Oe.useEffect(()=>{var k;return(k=n.current)==null?void 0:k.setPointsVisible(q)},[q]),Oe.useEffect(()=>{var k;return(k=n.current)==null?void 0:k.setFrustaVisible(Y)},[Y]);const Q=k=>{var P;r.current.t=k,s.current=k,(P=n.current)==null||P.setTime(k),B(Ee(k)),w(k)},de=()=>{const k=r.current,P=o.current;P&&(!k.playing&&k.t>=P.t1-.05&&(k.t=P.t0),k.playing=!k.playing,k.last=performance.now(),F(k.playing))};Oe.useEffect(()=>{const k=P=>{var le;if(P.code!=="Space")return;const ye=((le=document.activeElement)==null?void 0:le.tagName)??"";["INPUT","SELECT","TEXTAREA","BUTTON"].includes(ye)||(P.preventDefault(),de())};return window.addEventListener("keydown",k),()=>window.removeEventListener("keydown",k)},[]);const Re=()=>{var P;const k=!X;re(k),pe(k?"Click two points in the scene":null),(P=n.current)==null||P.setMeasureMode(k,ye=>{ye!==null?pe(`Distance: ${ye.toFixed(1)} m`):k&&pe("Click two points in the scene")})},ve=()=>{const k=t.current;k&&(document.fullscreenElement?document.exitFullscreen():k.requestFullscreen().catch(()=>{}))},fe=Oe.useMemo(()=>fo(u,L),[u,L]),qe=fe>=0?u[fe][_]??u[fe].actual:null;return i.scenePath?we.jsxs("div",{className:"scene-view",children:[we.jsx("a",{className:"back-link",href:"#/",children:"← All videos"}),we.jsx("h1",{children:i.description||i.videoFile}),we.jsxs("p",{className:"view-meta",children:[i.date,i.town?` · ${i.town}`:""," · 3D reconstruction",m?` · ${m.pointCount.toLocaleString()} points · ${m.frames} camera poses`:""]}),we.jsxs("div",{className:"scene-stage",ref:t,children:[we.jsx("div",{className:"canvas-holder",ref:e}),f?we.jsx("div",{className:"scene-status",children:f}):null,Z&&qe?we.jsxs("div",{className:"scene-frame-panel",children:[we.jsxs("div",{className:"frame-tabs",children:[["overlay","render","actual"].map(k=>we.jsx("button",{type:"button",className:_===k?"active":"",onClick:()=>R(k),children:k==="overlay"?"Overlay":k==="render"?"Render":"Actual"},k)),we.jsxs("span",{className:"frame-counter",children:[fe+1,"/",u.length]})]}),we.jsx("canvas",{ref:a,"aria-label":`VGGT ${_} frame ${fe+1}`})]}):null,we.jsx("button",{type:"button",className:"stage-btn fullscreen-btn",onClick:ve,title:"Fullscreen",children:"⛶"})]}),M?we.jsxs("div",{className:"scene-controls",children:[we.jsx("button",{type:"button",className:"play-btn",onClick:de,"aria-label":E?"Pause":"Play",title:"Play/pause (space)",children:E?"❚❚":"▶"}),we.jsx("input",{type:"range",className:"scrubber",min:M.t0,max:M.t1,step:.01,value:Math.min(Math.max(L,M.t0),M.t1),onChange:k=>Q(Number(k.target.value)),"aria-label":"Timeline"}),we.jsxs("span",{className:"time-display",children:[ho(Math.max(L-M.t0,0))," / ",ho(M.t1-M.t0)]}),we.jsxs("span",{className:"scene-toggles",children:[we.jsxs("label",{children:[we.jsx("input",{type:"checkbox",checked:q,onChange:k=>H(k.target.checked)}),"Points"]}),we.jsxs("label",{children:[we.jsx("input",{type:"checkbox",checked:$,onChange:k=>x(k.target.checked)}),"Path"]}),we.jsxs("label",{children:[we.jsx("input",{type:"checkbox",checked:Y,onChange:k=>W(k.target.checked)}),"Cameras"]}),we.jsxs("label",{children:[we.jsx("input",{type:"checkbox",checked:A,onChange:k=>te(k.target.checked)}),"Grid"]}),we.jsxs("label",{children:[we.jsx("input",{type:"checkbox",checked:Z,onChange:k=>D(k.target.checked)}),"Frames"]}),we.jsx("button",{type:"button",className:`measure-btn${X?" active":""}`,onClick:Re,title:"Measure the distance between two points",children:"Measure"})]})]}):null,ae?we.jsx("p",{className:"measure-readout",children:ae}):null,M?we.jsx(Tp,{timeline:M,currentT:L,onSeek:Q}):null,we.jsx("div",{className:"view-actions",style:{marginTop:14},children:we.jsx("a",{href:Jo(i.videoFile),children:"← Watch the full video with annotations"})})]}):we.jsxs("div",{children:[we.jsx("a",{className:"back-link",href:"#/",children:"← All videos"}),we.jsx("p",{className:"not-found",children:"No 3D scene for this video."})]})}export{wp as SceneView}; +}`;class up{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(e,t,n){if(this.texture===null){const r=new wt,s=e.properties.get(r);s.__webglTexture=t.texture,(t.depthNear!=n.depthNear||t.depthFar!=n.depthFar)&&(this.depthNear=t.depthNear,this.depthFar=t.depthFar),this.texture=r}}render(e,t){if(this.texture!==null){if(this.mesh===null){const n=t.cameras[0].viewport,r=new Mn({extensions:{fragDepth:!0},vertexShader:lp,fragmentShader:cp,uniforms:{depthColor:{value:this.texture},depthWidth:{value:n.z},depthHeight:{value:n.w}}});this.mesh=new It(new _r(20,20),r)}e.render(this.mesh,t)}}reset(){this.texture=null,this.mesh=null}}class hp extends zn{constructor(e,t){super();const n=this;let r=null,s=1,o=null,a="local-floor",l=1,c=null,h=null,f=null,p=null,m=null,g=null;const M=new up,d=t.getContextAttributes();let u=null,T=null;const _=[],R=[],L=new Ue;let w=null;const E=new Ut;E.layers.enable(1),E.viewport=new pt;const F=new Ut;F.layers.enable(2),F.viewport=new pt;const $=[E,F],x=new ap;x.layers.enable(1),x.layers.enable(2);let A=null,te=null;this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(B){let Q=_[B];return Q===void 0&&(Q=new es,_[B]=Q),Q.getTargetRaySpace()},this.getControllerGrip=function(B){let Q=_[B];return Q===void 0&&(Q=new es,_[B]=Q),Q.getGripSpace()},this.getHand=function(B){let Q=_[B];return Q===void 0&&(Q=new es,_[B]=Q),Q.getHandSpace()};function Z(B){const Q=R.indexOf(B.inputSource);if(Q===-1)return;const de=_[Q];de!==void 0&&(de.update(B.inputSource,B.frame,c||o),de.dispatchEvent({type:B.type,data:B.inputSource}))}function D(){r.removeEventListener("select",Z),r.removeEventListener("selectstart",Z),r.removeEventListener("selectend",Z),r.removeEventListener("squeeze",Z),r.removeEventListener("squeezestart",Z),r.removeEventListener("squeezeend",Z),r.removeEventListener("end",D),r.removeEventListener("inputsourceschange",q);for(let B=0;B<_.length;B++){const Q=R[B];Q!==null&&(R[B]=null,_[B].disconnect(Q))}A=null,te=null,M.reset(),e.setRenderTarget(u),m=null,p=null,f=null,r=null,T=null,Ee.stop(),n.isPresenting=!1,e.setPixelRatio(w),e.setSize(L.width,L.height,!1),n.dispatchEvent({type:"sessionend"})}this.setFramebufferScaleFactor=function(B){s=B,n.isPresenting===!0&&console.warn("THREE.WebXRManager: Cannot change framebuffer scale while presenting.")},this.setReferenceSpaceType=function(B){a=B,n.isPresenting===!0&&console.warn("THREE.WebXRManager: Cannot change reference space type while presenting.")},this.getReferenceSpace=function(){return c||o},this.setReferenceSpace=function(B){c=B},this.getBaseLayer=function(){return p!==null?p:m},this.getBinding=function(){return f},this.getFrame=function(){return g},this.getSession=function(){return r},this.setSession=async function(B){if(r=B,r!==null){if(u=e.getRenderTarget(),r.addEventListener("select",Z),r.addEventListener("selectstart",Z),r.addEventListener("selectend",Z),r.addEventListener("squeeze",Z),r.addEventListener("squeezestart",Z),r.addEventListener("squeezeend",Z),r.addEventListener("end",D),r.addEventListener("inputsourceschange",q),d.xrCompatible!==!0&&await t.makeXRCompatible(),w=e.getPixelRatio(),e.getSize(L),r.renderState.layers===void 0||e.capabilities.isWebGL2===!1){const Q={antialias:r.renderState.layers===void 0?d.antialias:!0,alpha:!0,depth:d.depth,stencil:d.stencil,framebufferScaleFactor:s};m=new XRWebGLLayer(r,t,Q),r.updateRenderState({baseLayer:m}),e.setPixelRatio(1),e.setSize(m.framebufferWidth,m.framebufferHeight,!1),T=new Bn(m.framebufferWidth,m.framebufferHeight,{format:Ht,type:vn,colorSpace:e.outputColorSpace,stencilBuffer:d.stencil})}else{let Q=null,de=null,Re=null;d.depth&&(Re=d.stencil?t.DEPTH24_STENCIL8:t.DEPTH_COMPONENT24,Q=d.stencil?hi:On,de=d.stencil?Fn:mn);const ve={colorFormat:t.RGBA8,depthFormat:Re,scaleFactor:s};f=new XRWebGLBinding(r,t),p=f.createProjectionLayer(ve),r.updateRenderState({layers:[p]}),e.setPixelRatio(1),e.setSize(p.textureWidth,p.textureHeight,!1),T=new Bn(p.textureWidth,p.textureHeight,{format:Ht,type:vn,depthTexture:new Oo(p.textureWidth,p.textureHeight,de,void 0,void 0,void 0,void 0,void 0,void 0,Q),stencilBuffer:d.stencil,colorSpace:e.outputColorSpace,samples:d.antialias?4:0});const fe=e.properties.get(T);fe.__ignoreDepthValues=p.ignoreDepthValues}T.isXRRenderTarget=!0,this.setFoveation(l),c=null,o=await r.requestReferenceSpace(a),Ee.setContext(r),Ee.start(),n.isPresenting=!0,n.dispatchEvent({type:"sessionstart"})}},this.getEnvironmentBlendMode=function(){if(r!==null)return r.environmentBlendMode};function q(B){for(let Q=0;Q=0&&(R[Re]=null,_[Re].disconnect(de))}for(let Q=0;Q=R.length){R.push(de),Re=fe;break}else if(R[fe]===null){R[fe]=de,Re=fe;break}if(Re===-1)break}const ve=_[Re];ve&&ve.connect(de)}}const H=new U,Y=new U;function W(B,Q,de){H.setFromMatrixPosition(Q.matrixWorld),Y.setFromMatrixPosition(de.matrixWorld);const Re=H.distanceTo(Y),ve=Q.projectionMatrix.elements,fe=de.projectionMatrix.elements,qe=ve[14]/(ve[10]-1),k=ve[14]/(ve[10]+1),P=(ve[9]+1)/ve[5],ye=(ve[9]-1)/ve[5],le=(ve[8]-1)/ve[0],Ce=(fe[8]+1)/fe[0],Te=qe*le,Ve=qe*Ce,Ne=Re/(-le+Ce),Be=Ne*-le;Q.matrixWorld.decompose(B.position,B.quaternion,B.scale),B.translateX(Be),B.translateZ(Ne),B.matrixWorld.compose(B.position,B.quaternion,B.scale),B.matrixWorldInverse.copy(B.matrixWorld).invert();const Qe=qe+Ne,y=k+Ne,v=Te-Be,V=Ve+(Re-Be),j=P*k/y*Qe,ne=ye*k/y*Qe;B.projectionMatrix.makePerspective(v,V,j,ne,Qe,y),B.projectionMatrixInverse.copy(B.projectionMatrix).invert()}function X(B,Q){Q===null?B.matrixWorld.copy(B.matrix):B.matrixWorld.multiplyMatrices(Q.matrixWorld,B.matrix),B.matrixWorldInverse.copy(B.matrixWorld).invert()}this.updateCamera=function(B){if(r===null)return;M.texture!==null&&(B.near=M.depthNear,B.far=M.depthFar),x.near=F.near=E.near=B.near,x.far=F.far=E.far=B.far,(A!==x.near||te!==x.far)&&(r.updateRenderState({depthNear:x.near,depthFar:x.far}),A=x.near,te=x.far,E.near=A,E.far=te,F.near=A,F.far=te,E.updateProjectionMatrix(),F.updateProjectionMatrix(),B.updateProjectionMatrix());const Q=B.parent,de=x.cameras;X(x,Q);for(let Re=0;Re0&&(d.alphaTest.value=u.alphaTest);const T=e.get(u),_=T.envMap,R=T.envMapRotation;if(_&&(d.envMap.value=_,Pn.copy(R),Pn.x*=-1,Pn.y*=-1,Pn.z*=-1,_.isCubeTexture&&_.isRenderTargetTexture===!1&&(Pn.y*=-1,Pn.z*=-1),d.envMapRotation.value.setFromMatrix4(dp.makeRotationFromEuler(Pn)),d.flipEnvMap.value=_.isCubeTexture&&_.isRenderTargetTexture===!1?-1:1,d.reflectivity.value=u.reflectivity,d.ior.value=u.ior,d.refractionRatio.value=u.refractionRatio),u.lightMap){d.lightMap.value=u.lightMap;const L=i._useLegacyLights===!0?Math.PI:1;d.lightMapIntensity.value=u.lightMapIntensity*L,t(u.lightMap,d.lightMapTransform)}u.aoMap&&(d.aoMap.value=u.aoMap,d.aoMapIntensity.value=u.aoMapIntensity,t(u.aoMap,d.aoMapTransform))}function o(d,u){d.diffuse.value.copy(u.color),d.opacity.value=u.opacity,u.map&&(d.map.value=u.map,t(u.map,d.mapTransform))}function a(d,u){d.dashSize.value=u.dashSize,d.totalSize.value=u.dashSize+u.gapSize,d.scale.value=u.scale}function l(d,u,T,_){d.diffuse.value.copy(u.color),d.opacity.value=u.opacity,d.size.value=u.size*T,d.scale.value=_*.5,u.map&&(d.map.value=u.map,t(u.map,d.uvTransform)),u.alphaMap&&(d.alphaMap.value=u.alphaMap,t(u.alphaMap,d.alphaMapTransform)),u.alphaTest>0&&(d.alphaTest.value=u.alphaTest)}function c(d,u){d.diffuse.value.copy(u.color),d.opacity.value=u.opacity,d.rotation.value=u.rotation,u.map&&(d.map.value=u.map,t(u.map,d.mapTransform)),u.alphaMap&&(d.alphaMap.value=u.alphaMap,t(u.alphaMap,d.alphaMapTransform)),u.alphaTest>0&&(d.alphaTest.value=u.alphaTest)}function h(d,u){d.specular.value.copy(u.specular),d.shininess.value=Math.max(u.shininess,1e-4)}function f(d,u){u.gradientMap&&(d.gradientMap.value=u.gradientMap)}function p(d,u){d.metalness.value=u.metalness,u.metalnessMap&&(d.metalnessMap.value=u.metalnessMap,t(u.metalnessMap,d.metalnessMapTransform)),d.roughness.value=u.roughness,u.roughnessMap&&(d.roughnessMap.value=u.roughnessMap,t(u.roughnessMap,d.roughnessMapTransform)),e.get(u).envMap&&(d.envMapIntensity.value=u.envMapIntensity)}function m(d,u,T){d.ior.value=u.ior,u.sheen>0&&(d.sheenColor.value.copy(u.sheenColor).multiplyScalar(u.sheen),d.sheenRoughness.value=u.sheenRoughness,u.sheenColorMap&&(d.sheenColorMap.value=u.sheenColorMap,t(u.sheenColorMap,d.sheenColorMapTransform)),u.sheenRoughnessMap&&(d.sheenRoughnessMap.value=u.sheenRoughnessMap,t(u.sheenRoughnessMap,d.sheenRoughnessMapTransform))),u.clearcoat>0&&(d.clearcoat.value=u.clearcoat,d.clearcoatRoughness.value=u.clearcoatRoughness,u.clearcoatMap&&(d.clearcoatMap.value=u.clearcoatMap,t(u.clearcoatMap,d.clearcoatMapTransform)),u.clearcoatRoughnessMap&&(d.clearcoatRoughnessMap.value=u.clearcoatRoughnessMap,t(u.clearcoatRoughnessMap,d.clearcoatRoughnessMapTransform)),u.clearcoatNormalMap&&(d.clearcoatNormalMap.value=u.clearcoatNormalMap,t(u.clearcoatNormalMap,d.clearcoatNormalMapTransform),d.clearcoatNormalScale.value.copy(u.clearcoatNormalScale),u.side===At&&d.clearcoatNormalScale.value.negate())),u.iridescence>0&&(d.iridescence.value=u.iridescence,d.iridescenceIOR.value=u.iridescenceIOR,d.iridescenceThicknessMinimum.value=u.iridescenceThicknessRange[0],d.iridescenceThicknessMaximum.value=u.iridescenceThicknessRange[1],u.iridescenceMap&&(d.iridescenceMap.value=u.iridescenceMap,t(u.iridescenceMap,d.iridescenceMapTransform)),u.iridescenceThicknessMap&&(d.iridescenceThicknessMap.value=u.iridescenceThicknessMap,t(u.iridescenceThicknessMap,d.iridescenceThicknessMapTransform))),u.transmission>0&&(d.transmission.value=u.transmission,d.transmissionSamplerMap.value=T.texture,d.transmissionSamplerSize.value.set(T.width,T.height),u.transmissionMap&&(d.transmissionMap.value=u.transmissionMap,t(u.transmissionMap,d.transmissionMapTransform)),d.thickness.value=u.thickness,u.thicknessMap&&(d.thicknessMap.value=u.thicknessMap,t(u.thicknessMap,d.thicknessMapTransform)),d.attenuationDistance.value=u.attenuationDistance,d.attenuationColor.value.copy(u.attenuationColor)),u.anisotropy>0&&(d.anisotropyVector.value.set(u.anisotropy*Math.cos(u.anisotropyRotation),u.anisotropy*Math.sin(u.anisotropyRotation)),u.anisotropyMap&&(d.anisotropyMap.value=u.anisotropyMap,t(u.anisotropyMap,d.anisotropyMapTransform))),d.specularIntensity.value=u.specularIntensity,d.specularColor.value.copy(u.specularColor),u.specularColorMap&&(d.specularColorMap.value=u.specularColorMap,t(u.specularColorMap,d.specularColorMapTransform)),u.specularIntensityMap&&(d.specularIntensityMap.value=u.specularIntensityMap,t(u.specularIntensityMap,d.specularIntensityMapTransform))}function g(d,u){u.matcap&&(d.matcap.value=u.matcap)}function M(d,u){const T=e.get(u).light;d.referencePosition.value.setFromMatrixPosition(T.matrixWorld),d.nearDistance.value=T.shadow.camera.near,d.farDistance.value=T.shadow.camera.far}return{refreshFogUniforms:n,refreshMaterialUniforms:r}}function pp(i,e,t,n){let r={},s={},o=[];const a=t.isWebGL2?i.getParameter(i.MAX_UNIFORM_BUFFER_BINDINGS):0;function l(T,_){const R=_.program;n.uniformBlockBinding(T,R)}function c(T,_){let R=r[T.id];R===void 0&&(g(T),R=h(T),r[T.id]=R,T.addEventListener("dispose",d));const L=_.program;n.updateUBOMapping(T,L);const w=e.render.frame;s[T.id]!==w&&(p(T),s[T.id]=w)}function h(T){const _=f();T.__bindingPointIndex=_;const R=i.createBuffer(),L=T.__size,w=T.usage;return i.bindBuffer(i.UNIFORM_BUFFER,R),i.bufferData(i.UNIFORM_BUFFER,L,w),i.bindBuffer(i.UNIFORM_BUFFER,null),i.bindBufferBase(i.UNIFORM_BUFFER,_,R),R}function f(){for(let T=0;T0&&(R+=L-w),T.__size=R,T.__cache={},this}function M(T){const _={boundary:0,storage:0};return typeof T=="number"||typeof T=="boolean"?(_.boundary=4,_.storage=4):T.isVector2?(_.boundary=8,_.storage=8):T.isVector3||T.isColor?(_.boundary=16,_.storage=12):T.isVector4?(_.boundary=16,_.storage=16):T.isMatrix3?(_.boundary=48,_.storage=48):T.isMatrix4?(_.boundary=64,_.storage=64):T.isTexture?console.warn("THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group."):console.warn("THREE.WebGLRenderer: Unsupported uniform value type.",T),_}function d(T){const _=T.target;_.removeEventListener("dispose",d);const R=o.indexOf(_.__bindingPointIndex);o.splice(R,1),i.deleteBuffer(r[_.id]),delete r[_.id],delete s[_.id]}function u(){for(const T in r)i.deleteBuffer(r[T]);o=[],r={},s={}}return{bind:l,update:c,dispose:u}}class ko{constructor(e={}){const{canvas:t=tc(),context:n=null,depth:r=!0,stencil:s=!0,alpha:o=!1,antialias:a=!1,premultipliedAlpha:l=!0,preserveDrawingBuffer:c=!1,powerPreference:h="default",failIfMajorPerformanceCaveat:f=!1}=e;this.isWebGLRenderer=!0;let p;n!==null?p=n.getContextAttributes().alpha:p=o;const m=new Uint32Array(4),g=new Int32Array(4);let M=null,d=null;const u=[],T=[];this.domElement=t,this.debug={checkShaderErrors:!0,onShaderError:null},this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.clippingPlanes=[],this.localClippingEnabled=!1,this._outputColorSpace=Vt,this._useLegacyLights=!1,this.toneMapping=_n,this.toneMappingExposure=1;const _=this;let R=!1,L=0,w=0,E=null,F=-1,$=null;const x=new pt,A=new pt;let te=null;const Z=new je(0);let D=0,q=t.width,H=t.height,Y=1,W=null,X=null;const re=new pt(0,0,q,H),ae=new pt(0,0,q,H);let pe=!1;const Ee=new No;let B=!1,Q=!1,de=null;const Re=new rt,ve=new Ue,fe=new U,qe={background:null,fog:null,environment:null,overrideMaterial:null,isScene:!0};function k(){return E===null?Y:1}let P=n;function ye(S,I){for(let z=0;z{function me(){if(G.forEach(function(Me){Ne.get(Me).currentProgram.isReady()&&G.delete(Me)}),G.size===0){O(S);return}setTimeout(me,10)}le.get("KHR_parallel_shader_compile")!==null?me():setTimeout(me,10)})};let Ke=null;function Je(S){Ke&&Ke(S)}function at(){et.stop()}function Ye(){et.start()}const et=new Fo;et.setAnimationLoop(Je),typeof self<"u"&&et.setContext(self),this.setAnimationLoop=function(S){Ke=S,K.setAnimationLoop(S),S===null?et.stop():et.start()},K.addEventListener("sessionstart",at),K.addEventListener("sessionend",Ye),this.render=function(S,I){if(I!==void 0&&I.isCamera!==!0){console.error("THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.");return}if(R===!0)return;S.matrixWorldAutoUpdate===!0&&S.updateMatrixWorld(),I.parent===null&&I.matrixWorldAutoUpdate===!0&&I.updateMatrixWorld(),K.enabled===!0&&K.isPresenting===!0&&(K.cameraAutoUpdate===!0&&K.updateCamera(I),I=K.getCamera()),S.isScene===!0&&S.onBeforeRender(_,S,I,E),d=be.get(S,T.length),d.init(),T.push(d),Re.multiplyMatrices(I.projectionMatrix,I.matrixWorldInverse),Ee.setFromProjectionMatrix(Re),Q=this.localClippingEnabled,B=oe.init(this.clippingPlanes,Q),M=Le.get(S,u.length),M.init(),u.push(M),mt(S,I,0,_.sortObjects),M.finish(),_.sortObjects===!0&&M.sort(W,X),this.info.render.frame++,B===!0&&oe.beginShadows();const z=d.state.shadowsArray;if(ue.render(z,S,I),B===!0&&oe.endShadows(),this.info.autoReset===!0&&this.info.reset(),(K.enabled===!1||K.isPresenting===!1||K.hasDepthSensing()===!1)&&De.render(M,S),d.setupLights(_._useLegacyLights),I.isArrayCamera){const G=I.cameras;for(let O=0,me=G.length;O0?d=T[T.length-1]:d=null,u.pop(),u.length>0?M=u[u.length-1]:M=null};function mt(S,I,z,G){if(S.visible===!1)return;if(S.layers.test(I.layers)){if(S.isGroup)z=S.renderOrder;else if(S.isLOD)S.autoUpdate===!0&&S.update(I);else if(S.isLight)d.pushLight(S),S.castShadow&&d.pushShadow(S);else if(S.isSprite){if(!S.frustumCulled||Ee.intersectsSprite(S)){G&&fe.setFromMatrixPosition(S.matrixWorld).applyMatrix4(Re);const Me=j.update(S),Ae=S.material;Ae.visible&&M.push(S,Me,Ae,z,fe.z,null)}}else if((S.isMesh||S.isLine||S.isPoints)&&(!S.frustumCulled||Ee.intersectsObject(S))){const Me=j.update(S),Ae=S.material;if(G&&(S.boundingSphere!==void 0?(S.boundingSphere===null&&S.computeBoundingSphere(),fe.copy(S.boundingSphere.center)):(Me.boundingSphere===null&&Me.computeBoundingSphere(),fe.copy(Me.boundingSphere.center)),fe.applyMatrix4(S.matrixWorld).applyMatrix4(Re)),Array.isArray(Ae)){const Pe=Me.groups;for(let We=0,Ie=Pe.length;We0&&Di(O,me,I,z),G&&Te.viewport(x.copy(G)),O.length>0&&Ui(O,I,z),me.length>0&&Ui(me,I,z),Me.length>0&&Ui(Me,I,z),Te.buffers.depth.setTest(!0),Te.buffers.depth.setMask(!0),Te.buffers.color.setMask(!0),Te.setPolygonOffset(!1)}function Di(S,I,z,G){if((z.isScene===!0?z.overrideMaterial:null)!==null)return;const me=Ce.isWebGL2;de===null&&(de=new Bn(1,1,{generateMipmaps:!0,type:le.has("EXT_color_buffer_half_float")?wi:vn,minFilter:In,samples:me?4:0})),_.getDrawingBufferSize(ve),me?de.setSize(ve.x,ve.y):de.setSize(ds(ve.x),ds(ve.y));const Me=_.getRenderTarget();_.setRenderTarget(de),_.getClearColor(Z),D=_.getClearAlpha(),D<1&&_.setClearColor(16777215,.5),_.clear();const Ae=_.toneMapping;_.toneMapping=_n,Ui(S,z,G),Be.updateMultisampleRenderTarget(de),Be.updateRenderTargetMipmap(de);let Pe=!1;for(let We=0,Ie=I.length;We0),Fe=!!z.morphAttributes.position,ot=!!z.morphAttributes.normal,Rt=!!z.morphAttributes.color;let dt=_n;G.toneMapped&&(E===null||E.isXRRenderTarget===!0)&&(dt=_.toneMapping);const jt=z.morphAttributes.position||z.morphAttributes.normal||z.morphAttributes.color,it=jt!==void 0?jt.length:0,ze=Ne.get(G),xr=d.state.lights;if(B===!0&&(Q===!0||S!==$)){const Lt=S===$&&G.id===F;oe.setState(G,S,Lt)}let nt=!1;G.version===ze.__version?(ze.needsLights&&ze.lightsStateVersion!==xr.state.version||ze.outputColorSpace!==Ae||O.isBatchedMesh&&ze.batching===!1||!O.isBatchedMesh&&ze.batching===!0||O.isInstancedMesh&&ze.instancing===!1||!O.isInstancedMesh&&ze.instancing===!0||O.isSkinnedMesh&&ze.skinning===!1||!O.isSkinnedMesh&&ze.skinning===!0||O.isInstancedMesh&&ze.instancingColor===!0&&O.instanceColor===null||O.isInstancedMesh&&ze.instancingColor===!1&&O.instanceColor!==null||O.isInstancedMesh&&ze.instancingMorph===!0&&O.morphTexture===null||O.isInstancedMesh&&ze.instancingMorph===!1&&O.morphTexture!==null||ze.envMap!==Pe||G.fog===!0&&ze.fog!==me||ze.numClippingPlanes!==void 0&&(ze.numClippingPlanes!==oe.numPlanes||ze.numIntersection!==oe.numIntersection)||ze.vertexAlphas!==We||ze.vertexTangents!==Ie||ze.morphTargets!==Fe||ze.morphNormals!==ot||ze.morphColors!==Rt||ze.toneMapping!==dt||Ce.isWebGL2===!0&&ze.morphTargetsCount!==it)&&(nt=!0):(nt=!0,ze.__version=G.version);let yn=ze.currentProgram;nt===!0&&(yn=Ii(G,I,O));let Ts=!1,gi=!1,Mr=!1;const gt=yn.getUniforms(),Tn=ze.uniforms;if(Te.useProgram(yn.program)&&(Ts=!0,gi=!0,Mr=!0),G.id!==F&&(F=G.id,gi=!0),Ts||$!==S){gt.setValue(P,"projectionMatrix",S.projectionMatrix),gt.setValue(P,"viewMatrix",S.matrixWorldInverse);const Lt=gt.map.cameraPosition;Lt!==void 0&&Lt.setValue(P,fe.setFromMatrixPosition(S.matrixWorld)),Ce.logarithmicDepthBuffer&>.setValue(P,"logDepthBufFC",2/(Math.log(S.far+1)/Math.LN2)),(G.isMeshPhongMaterial||G.isMeshToonMaterial||G.isMeshLambertMaterial||G.isMeshBasicMaterial||G.isMeshStandardMaterial||G.isShaderMaterial)&>.setValue(P,"isOrthographic",S.isOrthographicCamera===!0),$!==S&&($=S,gi=!0,Mr=!0)}if(O.isSkinnedMesh){gt.setOptional(P,O,"bindMatrix"),gt.setOptional(P,O,"bindMatrixInverse");const Lt=O.skeleton;Lt&&(Ce.floatVertexTextures?(Lt.boneTexture===null&&Lt.computeBoneTexture(),gt.setValue(P,"boneTexture",Lt.boneTexture,Be)):console.warn("THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required."))}O.isBatchedMesh&&(gt.setOptional(P,O,"batchingTexture"),gt.setValue(P,"batchingTexture",O._matricesTexture,Be));const Sr=z.morphAttributes;if((Sr.position!==void 0||Sr.normal!==void 0||Sr.color!==void 0&&Ce.isWebGL2===!0)&&se.update(O,z,yn),(gi||ze.receiveShadow!==O.receiveShadow)&&(ze.receiveShadow=O.receiveShadow,gt.setValue(P,"receiveShadow",O.receiveShadow)),G.isMeshGouraudMaterial&&G.envMap!==null&&(Tn.envMap.value=Pe,Tn.flipEnvMap.value=Pe.isCubeTexture&&Pe.isRenderTargetTexture===!1?-1:1),gi&&(gt.setValue(P,"toneMappingExposure",_.toneMappingExposure),ze.needsLights&&qo(Tn,Mr),me&&G.fog===!0&&J.refreshFogUniforms(Tn,me),J.refreshMaterialUniforms(Tn,G,Y,H,de),or.upload(P,Es(ze),Tn,Be)),G.isShaderMaterial&&G.uniformsNeedUpdate===!0&&(or.upload(P,Es(ze),Tn,Be),G.uniformsNeedUpdate=!1),G.isSpriteMaterial&>.setValue(P,"center",O.center),gt.setValue(P,"modelViewMatrix",O.modelViewMatrix),gt.setValue(P,"normalMatrix",O.normalMatrix),gt.setValue(P,"modelMatrix",O.matrixWorld),G.isShaderMaterial||G.isRawShaderMaterial){const Lt=G.uniformsGroups;for(let Er=0,jo=Lt.length;Er0&&Be.useMultisampledRTT(S)===!1?O=Ne.get(S).__webglMultisampledFramebuffer:Array.isArray(Ie)?O=Ie[z]:O=Ie,x.copy(S.viewport),A.copy(S.scissor),te=S.scissorTest}else x.copy(re).multiplyScalar(Y).floor(),A.copy(ae).multiplyScalar(Y).floor(),te=pe;if(Te.bindFramebuffer(P.FRAMEBUFFER,O)&&Ce.drawBuffers&&G&&Te.drawBuffers(S,O),Te.viewport(x),Te.scissor(A),Te.setScissorTest(te),me){const Pe=Ne.get(S.texture);P.framebufferTexture2D(P.FRAMEBUFFER,P.COLOR_ATTACHMENT0,P.TEXTURE_CUBE_MAP_POSITIVE_X+I,Pe.__webglTexture,z)}else if(Me){const Pe=Ne.get(S.texture),We=I||0;P.framebufferTextureLayer(P.FRAMEBUFFER,P.COLOR_ATTACHMENT0,Pe.__webglTexture,z||0,We)}F=-1},this.readRenderTargetPixels=function(S,I,z,G,O,me,Me){if(!(S&&S.isWebGLRenderTarget)){console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");return}let Ae=Ne.get(S).__webglFramebuffer;if(S.isWebGLCubeRenderTarget&&Me!==void 0&&(Ae=Ae[Me]),Ae){Te.bindFramebuffer(P.FRAMEBUFFER,Ae);try{const Pe=S.texture,We=Pe.format,Ie=Pe.type;if(We!==Ht&&Se.convert(We)!==P.getParameter(P.IMPLEMENTATION_COLOR_READ_FORMAT)){console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.");return}const Fe=Ie===wi&&(le.has("EXT_color_buffer_half_float")||Ce.isWebGL2&&le.has("EXT_color_buffer_float"));if(Ie!==vn&&Se.convert(Ie)!==P.getParameter(P.IMPLEMENTATION_COLOR_READ_TYPE)&&!(Ie===nn&&(Ce.isWebGL2||le.has("OES_texture_float")||le.has("WEBGL_color_buffer_float")))&&!Fe){console.error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.");return}I>=0&&I<=S.width-G&&z>=0&&z<=S.height-O&&P.readPixels(I,z,G,O,Se.convert(We),Se.convert(Ie),me)}finally{const Pe=E!==null?Ne.get(E).__webglFramebuffer:null;Te.bindFramebuffer(P.FRAMEBUFFER,Pe)}}},this.copyFramebufferToTexture=function(S,I,z=0){const G=Math.pow(2,-z),O=Math.floor(I.image.width*G),me=Math.floor(I.image.height*G);Be.setTexture2D(I,0),P.copyTexSubImage2D(P.TEXTURE_2D,z,0,0,S.x,S.y,O,me),Te.unbindTexture()},this.copyTextureToTexture=function(S,I,z,G=0){const O=I.image.width,me=I.image.height,Me=Se.convert(z.format),Ae=Se.convert(z.type);Be.setTexture2D(z,0),P.pixelStorei(P.UNPACK_FLIP_Y_WEBGL,z.flipY),P.pixelStorei(P.UNPACK_PREMULTIPLY_ALPHA_WEBGL,z.premultiplyAlpha),P.pixelStorei(P.UNPACK_ALIGNMENT,z.unpackAlignment),I.isDataTexture?P.texSubImage2D(P.TEXTURE_2D,G,S.x,S.y,O,me,Me,Ae,I.image.data):I.isCompressedTexture?P.compressedTexSubImage2D(P.TEXTURE_2D,G,S.x,S.y,I.mipmaps[0].width,I.mipmaps[0].height,Me,I.mipmaps[0].data):P.texSubImage2D(P.TEXTURE_2D,G,S.x,S.y,Me,Ae,I.image),G===0&&z.generateMipmaps&&P.generateMipmap(P.TEXTURE_2D),Te.unbindTexture()},this.copyTextureToTexture3D=function(S,I,z,G,O=0){if(_.isWebGL1Renderer){console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.");return}const me=Math.round(S.max.x-S.min.x),Me=Math.round(S.max.y-S.min.y),Ae=S.max.z-S.min.z+1,Pe=Se.convert(G.format),We=Se.convert(G.type);let Ie;if(G.isData3DTexture)Be.setTexture3D(G,0),Ie=P.TEXTURE_3D;else if(G.isDataArrayTexture||G.isCompressedArrayTexture)Be.setTexture2DArray(G,0),Ie=P.TEXTURE_2D_ARRAY;else{console.warn("THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.");return}P.pixelStorei(P.UNPACK_FLIP_Y_WEBGL,G.flipY),P.pixelStorei(P.UNPACK_PREMULTIPLY_ALPHA_WEBGL,G.premultiplyAlpha),P.pixelStorei(P.UNPACK_ALIGNMENT,G.unpackAlignment);const Fe=P.getParameter(P.UNPACK_ROW_LENGTH),ot=P.getParameter(P.UNPACK_IMAGE_HEIGHT),Rt=P.getParameter(P.UNPACK_SKIP_PIXELS),dt=P.getParameter(P.UNPACK_SKIP_ROWS),jt=P.getParameter(P.UNPACK_SKIP_IMAGES),it=z.isCompressedTexture?z.mipmaps[O]:z.image;P.pixelStorei(P.UNPACK_ROW_LENGTH,it.width),P.pixelStorei(P.UNPACK_IMAGE_HEIGHT,it.height),P.pixelStorei(P.UNPACK_SKIP_PIXELS,S.min.x),P.pixelStorei(P.UNPACK_SKIP_ROWS,S.min.y),P.pixelStorei(P.UNPACK_SKIP_IMAGES,S.min.z),z.isDataTexture||z.isData3DTexture?P.texSubImage3D(Ie,O,I.x,I.y,I.z,me,Me,Ae,Pe,We,it.data):G.isCompressedArrayTexture?P.compressedTexSubImage3D(Ie,O,I.x,I.y,I.z,me,Me,Ae,Pe,it.data):P.texSubImage3D(Ie,O,I.x,I.y,I.z,me,Me,Ae,Pe,We,it),P.pixelStorei(P.UNPACK_ROW_LENGTH,Fe),P.pixelStorei(P.UNPACK_IMAGE_HEIGHT,ot),P.pixelStorei(P.UNPACK_SKIP_PIXELS,Rt),P.pixelStorei(P.UNPACK_SKIP_ROWS,dt),P.pixelStorei(P.UNPACK_SKIP_IMAGES,jt),O===0&&G.generateMipmaps&&P.generateMipmap(Ie),Te.unbindTexture()},this.initTexture=function(S){S.isCubeTexture?Be.setTextureCube(S,0):S.isData3DTexture?Be.setTexture3D(S,0):S.isDataArrayTexture||S.isCompressedArrayTexture?Be.setTexture2DArray(S,0):Be.setTexture2D(S,0),Te.unbindTexture()},this.resetState=function(){L=0,w=0,E=null,Te.reset(),ge.reset()},typeof __THREE_DEVTOOLS__<"u"&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}get coordinateSystem(){return rn}get outputColorSpace(){return this._outputColorSpace}set outputColorSpace(e){this._outputColorSpace=e;const t=this.getContext();t.drawingBufferColorSpace=e===vs?"display-p3":"srgb",t.unpackColorSpace=Ze.workingColorSpace===gr?"display-p3":"srgb"}get useLegacyLights(){return console.warn("THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733."),this._useLegacyLights}set useLegacyLights(e){console.warn("THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733."),this._useLegacyLights=e}}class mp extends ko{}mp.prototype.isWebGL1Renderer=!0;class gp extends yt{constructor(){super(),this.isScene=!0,this.type="Scene",this.background=null,this.environment=null,this.fog=null,this.backgroundBlurriness=0,this.backgroundIntensity=1,this.backgroundRotation=new an,this.environmentRotation=new an,this.overrideMaterial=null,typeof __THREE_DEVTOOLS__<"u"&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}copy(e,t){return super.copy(e,t),e.background!==null&&(this.background=e.background.clone()),e.environment!==null&&(this.environment=e.environment.clone()),e.fog!==null&&(this.fog=e.fog.clone()),this.backgroundBlurriness=e.backgroundBlurriness,this.backgroundIntensity=e.backgroundIntensity,this.backgroundRotation.copy(e.backgroundRotation),this.environmentRotation.copy(e.environmentRotation),e.overrideMaterial!==null&&(this.overrideMaterial=e.overrideMaterial.clone()),this.matrixAutoUpdate=e.matrixAutoUpdate,this}toJSON(e){const t=super.toJSON(e);return this.fog!==null&&(t.object.fog=this.fog.toJSON()),this.backgroundBlurriness>0&&(t.object.backgroundBlurriness=this.backgroundBlurriness),this.backgroundIntensity!==1&&(t.object.backgroundIntensity=this.backgroundIntensity),t.object.backgroundRotation=this.backgroundRotation.toArray(),t.object.environmentRotation=this.environmentRotation.toArray(),t}}class yi extends pi{constructor(e){super(),this.isLineBasicMaterial=!0,this.type="LineBasicMaterial",this.color=new je(16777215),this.map=null,this.linewidth=1,this.linecap="round",this.linejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.linewidth=e.linewidth,this.linecap=e.linecap,this.linejoin=e.linejoin,this.fog=e.fog,this}}const ja=new U,Ka=new U,$a=new rt,ts=new Pi,nr=new Ci;class Ti extends yt{constructor(e=new xt,t=new yi){super(),this.isLine=!0,this.type="Line",this.geometry=e,this.material=t,this.updateMorphTargets()}copy(e,t){return super.copy(e,t),this.material=Array.isArray(e.material)?e.material.slice():e.material,this.geometry=e.geometry,this}computeLineDistances(){const e=this.geometry;if(e.index===null){const t=e.attributes.position,n=[0];for(let r=1,s=t.count;rl)continue;p.applyMatrix4(this.matrixWorld);const F=e.ray.origin.distanceTo(p);Fe.far||t.push({distance:F,point:f.clone().applyMatrix4(this.matrixWorld),index:_,face:null,faceIndex:null,object:this})}}else{const u=Math.max(0,o.start),T=Math.min(d.count,o.start+o.count);for(let _=u,R=T-1;_l)continue;p.applyMatrix4(this.matrixWorld);const w=e.ray.origin.distanceTo(p);we.far||t.push({distance:w,point:f.clone().applyMatrix4(this.matrixWorld),index:_,face:null,faceIndex:null,object:this})}}}updateMorphTargets(){const t=this.geometry.morphAttributes,n=Object.keys(t);if(n.length>0){const r=t[n[0]];if(r!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let s=0,o=r.length;s0){const r=t[n[0]];if(r!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let s=0,o=r.length;sr.far)return;s.push({distance:c,distanceToRay:Math.sqrt(a),point:l,index:e,face:null,object:o})}}class Ai extends xt{constructor(e=1,t=32,n=16,r=0,s=Math.PI*2,o=0,a=Math.PI){super(),this.type="SphereGeometry",this.parameters={radius:e,widthSegments:t,heightSegments:n,phiStart:r,phiLength:s,thetaStart:o,thetaLength:a},t=Math.max(3,Math.floor(t)),n=Math.max(2,Math.floor(n));const l=Math.min(o+a,Math.PI);let c=0;const h=[],f=new U,p=new U,m=[],g=[],M=[],d=[];for(let u=0;u<=n;u++){const T=[],_=u/n;let R=0;u===0&&o===0?R=.5/t:u===n&&l===Math.PI&&(R=-.5/t);for(let L=0;L<=t;L++){const w=L/t;f.x=-e*Math.cos(r+w*s)*Math.sin(o+_*a),f.y=e*Math.cos(o+_*a),f.z=e*Math.sin(r+w*s)*Math.sin(o+_*a),g.push(f.x,f.y,f.z),p.copy(f).normalize(),M.push(p.x,p.y,p.z),d.push(w+R,1-_),T.push(c++)}h.push(T)}for(let u=0;u0)&&m.push(_,R,w),(u!==n-1||lMath.PI&&(Je-=ee),at<-Math.PI?at+=ee:at>Math.PI&&(at-=ee),Je<=at?a.theta=Math.max(Je,Math.min(at,a.theta)):a.theta=a.theta>(Je+at)/2?Math.max(Je,a.theta):Math.min(at,a.theta)),a.phi=Math.max(n.minPolarAngle,Math.min(n.maxPolarAngle,a.phi)),a.makeSafe(),n.enableDamping===!0?n.target.addScaledVector(h,n.dampingFactor):n.target.add(h),n.target.sub(n.cursor),n.target.clampLength(n.minTargetRadius,n.maxTargetRadius),n.target.add(n.cursor);let Ye=!1;if(n.zoomToCursor&&w||n.object.isOrthographicCamera)a.radius=re(a.radius);else{const et=a.radius;a.radius=re(a.radius*c),Ye=et!=a.radius}if(b.setFromSpherical(a),b.applyQuaternion(_e),Ke.copy(n.target).add(b),n.object.lookAt(n.target),n.enableDamping===!0?(l.theta*=1-n.dampingFactor,l.phi*=1-n.dampingFactor,h.multiplyScalar(1-n.dampingFactor)):(l.set(0,0,0),h.set(0,0,0)),n.zoomToCursor&&w){let et=null;if(n.object.isPerspectiveCamera){const mt=b.length();et=re(mt*c);const En=mt-et;n.object.position.addScaledVector(R,En),n.object.updateMatrixWorld(),Ye=!!En}else if(n.object.isOrthographicCamera){const mt=new U(L.x,L.y,0);mt.unproject(n.object);const En=n.object.zoom;n.object.zoom=Math.max(n.minZoom,Math.min(n.maxZoom,n.object.zoom/c)),n.object.updateProjectionMatrix(),Ye=En!==n.object.zoom;const Di=new U(L.x,L.y,0);Di.unproject(n.object),n.object.position.sub(Di).add(mt),n.object.updateMatrixWorld(),et=b.length()}else console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."),n.zoomToCursor=!1;et!==null&&(this.screenSpacePanning?n.target.set(0,0,-1).transformDirection(n.object.matrix).multiplyScalar(et).add(n.object.position):(sr.origin.copy(n.object.position),sr.direction.set(0,0,-1).transformDirection(n.object.matrix),Math.abs(n.object.up.dot(sr.direction))o||8*(1-ie.dot(n.object.quaternion))>o||N.distanceToSquared(n.target)>o?(n.dispatchEvent(ro),C.copy(n.object.position),ie.copy(n.object.quaternion),N.copy(n.target),!0):!1}}(),this.dispose=function(){n.domElement.removeEventListener("contextmenu",De),n.domElement.removeEventListener("pointerdown",Be),n.domElement.removeEventListener("pointercancel",y),n.domElement.removeEventListener("wheel",j),n.domElement.removeEventListener("pointermove",Qe),n.domElement.removeEventListener("pointerup",y),n.domElement.getRootNode().removeEventListener("keydown",J,{capture:!0}),n._domElementKeyEvents!==null&&(n._domElementKeyEvents.removeEventListener("keydown",be),n._domElementKeyEvents=null)};const n=this,r={NONE:-1,ROTATE:0,DOLLY:1,PAN:2,TOUCH_ROTATE:3,TOUCH_PAN:4,TOUCH_DOLLY_PAN:5,TOUCH_DOLLY_ROTATE:6};let s=r.NONE;const o=1e-6,a=new io,l=new io;let c=1;const h=new U,f=new Ue,p=new Ue,m=new Ue,g=new Ue,M=new Ue,d=new Ue,u=new Ue,T=new Ue,_=new Ue,R=new U,L=new Ue;let w=!1;const E=[],F={};let $=!1;function x(b){return b!==null?2*Math.PI/60*n.autoRotateSpeed*b:2*Math.PI/60/60*n.autoRotateSpeed}function A(b){const K=Math.abs(b*.01);return Math.pow(.95,n.zoomSpeed*K)}function te(b){l.theta-=b}function Z(b){l.phi-=b}const D=function(){const b=new U;return function(_e,C){b.setFromMatrixColumn(C,0),b.multiplyScalar(-_e),h.add(b)}}(),q=function(){const b=new U;return function(_e,C){n.screenSpacePanning===!0?b.setFromMatrixColumn(C,1):(b.setFromMatrixColumn(C,0),b.crossVectors(n.object.up,b)),b.multiplyScalar(_e),h.add(b)}}(),H=function(){const b=new U;return function(_e,C){const ie=n.domElement;if(n.object.isPerspectiveCamera){const N=n.object.position;b.copy(N).sub(n.target);let ee=b.length();ee*=Math.tan(n.object.fov/2*Math.PI/180),D(2*_e*ee/ie.clientHeight,n.object.matrix),q(2*C*ee/ie.clientHeight,n.object.matrix)}else n.object.isOrthographicCamera?(D(_e*(n.object.right-n.object.left)/n.object.zoom/ie.clientWidth,n.object.matrix),q(C*(n.object.top-n.object.bottom)/n.object.zoom/ie.clientHeight,n.object.matrix)):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."),n.enablePan=!1)}}();function Y(b){n.object.isPerspectiveCamera||n.object.isOrthographicCamera?c/=b:(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),n.enableZoom=!1)}function W(b){n.object.isPerspectiveCamera||n.object.isOrthographicCamera?c*=b:(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),n.enableZoom=!1)}function X(b,K){if(!n.zoomToCursor)return;w=!0;const _e=n.domElement.getBoundingClientRect(),C=b-_e.left,ie=K-_e.top,N=_e.width,ee=_e.height;L.x=C/N*2-1,L.y=-(ie/ee)*2+1,R.set(L.x,L.y,1).unproject(n.object).sub(n.object.position).normalize()}function re(b){return Math.max(n.minDistance,Math.min(n.maxDistance,b))}function ae(b){f.set(b.clientX,b.clientY)}function pe(b){X(b.clientX,b.clientX),u.set(b.clientX,b.clientY)}function Ee(b){g.set(b.clientX,b.clientY)}function B(b){p.set(b.clientX,b.clientY),m.subVectors(p,f).multiplyScalar(n.rotateSpeed);const K=n.domElement;te(2*Math.PI*m.x/K.clientHeight),Z(2*Math.PI*m.y/K.clientHeight),f.copy(p),n.update()}function Q(b){T.set(b.clientX,b.clientY),_.subVectors(T,u),_.y>0?Y(A(_.y)):_.y<0&&W(A(_.y)),u.copy(T),n.update()}function de(b){M.set(b.clientX,b.clientY),d.subVectors(M,g).multiplyScalar(n.panSpeed),H(d.x,d.y),g.copy(M),n.update()}function Re(b){X(b.clientX,b.clientY),b.deltaY<0?W(A(b.deltaY)):b.deltaY>0&&Y(A(b.deltaY)),n.update()}function ve(b){let K=!1;switch(b.code){case n.keys.UP:b.ctrlKey||b.metaKey||b.shiftKey?Z(2*Math.PI*n.rotateSpeed/n.domElement.clientHeight):H(0,n.keyPanSpeed),K=!0;break;case n.keys.BOTTOM:b.ctrlKey||b.metaKey||b.shiftKey?Z(-2*Math.PI*n.rotateSpeed/n.domElement.clientHeight):H(0,-n.keyPanSpeed),K=!0;break;case n.keys.LEFT:b.ctrlKey||b.metaKey||b.shiftKey?te(2*Math.PI*n.rotateSpeed/n.domElement.clientHeight):H(n.keyPanSpeed,0),K=!0;break;case n.keys.RIGHT:b.ctrlKey||b.metaKey||b.shiftKey?te(-2*Math.PI*n.rotateSpeed/n.domElement.clientHeight):H(-n.keyPanSpeed,0),K=!0;break}K&&(b.preventDefault(),n.update())}function fe(b){if(E.length===1)f.set(b.pageX,b.pageY);else{const K=ge(b),_e=.5*(b.pageX+K.x),C=.5*(b.pageY+K.y);f.set(_e,C)}}function qe(b){if(E.length===1)g.set(b.pageX,b.pageY);else{const K=ge(b),_e=.5*(b.pageX+K.x),C=.5*(b.pageY+K.y);g.set(_e,C)}}function k(b){const K=ge(b),_e=b.pageX-K.x,C=b.pageY-K.y,ie=Math.sqrt(_e*_e+C*C);u.set(0,ie)}function P(b){n.enableZoom&&k(b),n.enablePan&&qe(b)}function ye(b){n.enableZoom&&k(b),n.enableRotate&&fe(b)}function le(b){if(E.length==1)p.set(b.pageX,b.pageY);else{const _e=ge(b),C=.5*(b.pageX+_e.x),ie=.5*(b.pageY+_e.y);p.set(C,ie)}m.subVectors(p,f).multiplyScalar(n.rotateSpeed);const K=n.domElement;te(2*Math.PI*m.x/K.clientHeight),Z(2*Math.PI*m.y/K.clientHeight),f.copy(p)}function Ce(b){if(E.length===1)M.set(b.pageX,b.pageY);else{const K=ge(b),_e=.5*(b.pageX+K.x),C=.5*(b.pageY+K.y);M.set(_e,C)}d.subVectors(M,g).multiplyScalar(n.panSpeed),H(d.x,d.y),g.copy(M)}function Te(b){const K=ge(b),_e=b.pageX-K.x,C=b.pageY-K.y,ie=Math.sqrt(_e*_e+C*C);T.set(0,ie),_.set(0,Math.pow(T.y/u.y,n.zoomSpeed)),Y(_.y),u.copy(T);const N=(b.pageX+K.x)*.5,ee=(b.pageY+K.y)*.5;X(N,ee)}function Ve(b){n.enableZoom&&Te(b),n.enablePan&&Ce(b)}function Ne(b){n.enableZoom&&Te(b),n.enableRotate&&le(b)}function Be(b){n.enabled!==!1&&(E.length===0&&(n.domElement.setPointerCapture(b.pointerId),n.domElement.addEventListener("pointermove",Qe),n.domElement.addEventListener("pointerup",y)),!ke(b)&&(se(b),b.pointerType==="touch"?oe(b):v(b)))}function Qe(b){n.enabled!==!1&&(b.pointerType==="touch"?ue(b):V(b))}function y(b){switch(st(b),E.length){case 0:n.domElement.releasePointerCapture(b.pointerId),n.domElement.removeEventListener("pointermove",Qe),n.domElement.removeEventListener("pointerup",y),n.dispatchEvent(so),s=r.NONE;break;case 1:const K=E[0],_e=F[K];oe({pointerId:K,pageX:_e.x,pageY:_e.y});break}}function v(b){let K;switch(b.button){case 0:K=n.mouseButtons.LEFT;break;case 1:K=n.mouseButtons.MIDDLE;break;case 2:K=n.mouseButtons.RIGHT;break;default:K=-1}switch(K){case Gn.DOLLY:if(n.enableZoom===!1)return;pe(b),s=r.DOLLY;break;case Gn.ROTATE:if(b.ctrlKey||b.metaKey||b.shiftKey){if(n.enablePan===!1)return;Ee(b),s=r.PAN}else{if(n.enableRotate===!1)return;ae(b),s=r.ROTATE}break;case Gn.PAN:if(b.ctrlKey||b.metaKey||b.shiftKey){if(n.enableRotate===!1)return;ae(b),s=r.ROTATE}else{if(n.enablePan===!1)return;Ee(b),s=r.PAN}break;default:s=r.NONE}s!==r.NONE&&n.dispatchEvent(ns)}function V(b){switch(s){case r.ROTATE:if(n.enableRotate===!1)return;B(b);break;case r.DOLLY:if(n.enableZoom===!1)return;Q(b);break;case r.PAN:if(n.enablePan===!1)return;de(b);break}}function j(b){n.enabled===!1||n.enableZoom===!1||s!==r.NONE||(b.preventDefault(),n.dispatchEvent(ns),Re(ne(b)),n.dispatchEvent(so))}function ne(b){const K=b.deltaMode,_e={clientX:b.clientX,clientY:b.clientY,deltaY:b.deltaY};switch(K){case 1:_e.deltaY*=16;break;case 2:_e.deltaY*=100;break}return b.ctrlKey&&!$&&(_e.deltaY*=10),_e}function J(b){b.key==="Control"&&($=!0,n.domElement.getRootNode().addEventListener("keyup",Le,{passive:!0,capture:!0}))}function Le(b){b.key==="Control"&&($=!1,n.domElement.getRootNode().removeEventListener("keyup",Le,{passive:!0,capture:!0}))}function be(b){n.enabled===!1||n.enablePan===!1||ve(b)}function oe(b){switch(Se(b),E.length){case 1:switch(n.touches.ONE){case Hn.ROTATE:if(n.enableRotate===!1)return;fe(b),s=r.TOUCH_ROTATE;break;case Hn.PAN:if(n.enablePan===!1)return;qe(b),s=r.TOUCH_PAN;break;default:s=r.NONE}break;case 2:switch(n.touches.TWO){case Hn.DOLLY_PAN:if(n.enableZoom===!1&&n.enablePan===!1)return;P(b),s=r.TOUCH_DOLLY_PAN;break;case Hn.DOLLY_ROTATE:if(n.enableZoom===!1&&n.enableRotate===!1)return;ye(b),s=r.TOUCH_DOLLY_ROTATE;break;default:s=r.NONE}break;default:s=r.NONE}s!==r.NONE&&n.dispatchEvent(ns)}function ue(b){switch(Se(b),s){case r.TOUCH_ROTATE:if(n.enableRotate===!1)return;le(b),n.update();break;case r.TOUCH_PAN:if(n.enablePan===!1)return;Ce(b),n.update();break;case r.TOUCH_DOLLY_PAN:if(n.enableZoom===!1&&n.enablePan===!1)return;Ve(b),n.update();break;case r.TOUCH_DOLLY_ROTATE:if(n.enableZoom===!1&&n.enableRotate===!1)return;Ne(b),n.update();break;default:s=r.NONE}}function De(b){n.enabled!==!1&&b.preventDefault()}function se(b){E.push(b.pointerId)}function st(b){delete F[b.pointerId];for(let K=0;Knew U(i[0],i[1],i[2]);class Ep{constructor(e){$e(this,"renderer");$e(this,"scene",new gp);$e(this,"root",new Wt);$e(this,"camera");$e(this,"controls");$e(this,"pointsMaterial",new Wo({size:.004,vertexColors:!0}));$e(this,"pathGroup",new Wt);$e(this,"gridGroup",new Wt);$e(this,"markerGroup",new Wt);$e(this,"frustaGroup",new Wt);$e(this,"measureGroup",new Wt);$e(this,"marker",null);$e(this,"frustum",null);$e(this,"pointsObject",null);$e(this,"meta",null);$e(this,"viewerBase",null);$e(this,"radius",1);$e(this,"disposed",!1);$e(this,"animationHandle",0);$e(this,"measureMode",!1);$e(this,"measurePoints",[]);$e(this,"onMeasure",null);$e(this,"raycaster",new xp);$e(this,"pointerNdc",new Ue);$e(this,"resizeObserver");$e(this,"pickPoint",e=>{var l;if(!this.measureMode||!this.pointsObject)return;const t=this.renderer.domElement.getBoundingClientRect();this.pointerNdc.x=(e.clientX-t.left)/t.width*2-1,this.pointerNdc.y=-((e.clientY-t.top)/t.height)*2+1,this.raycaster.setFromCamera(this.pointerNdc,this.camera),this.raycaster.params.Points.threshold=Math.max(this.pointsMaterial.size*2.5,.012);const n=this.raycaster.intersectObject(this.pointsObject,!1);let r=null;for(const c of n)c.index==null||c.distanceToRay==null||(r===null||c.distanceToRay<(r.distanceToRay??1/0))&&(r=c);if(r===null||r.index==null)return;const s=new U().fromBufferAttribute(this.pointsObject.geometry.getAttribute("position"),r.index);this.measurePoints.length>=2&&this.clearMeasurement(),this.measurePoints.push(s.clone());const o=Math.max(this.radius/220,.002),a=new It(new Ai(o,12,12),new bi({color:16777215}));if(a.position.copy(s),this.measureGroup.add(a),this.measurePoints.length===2){const[c,h]=this.measurePoints;this.measureGroup.add(new Ti(new xt().setFromPoints([c,h]),new yi({color:16777215,transparent:!0,opacity:.9})));const f=c.distanceTo(h);(l=this.onMeasure)==null||l.call(this,f*this.scaleMPerUnit(),f)}});$e(this,"resize",()=>{const e=this.holder.clientWidth||1,t=this.holder.clientHeight||1;this.renderer.setSize(e,t,!1),this.camera.aspect=e/t,this.camera.updateProjectionMatrix()});this.holder=e,this.renderer=new ko({antialias:!0,powerPreference:"high-performance"}),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2)),this.renderer.setClearColor(329223),e.appendChild(this.renderer.domElement),this.camera=new Ut(55,1,.001,100),this.controls=new Sp(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.root.add(this.pathGroup,this.gridGroup,this.markerGroup,this.frustaGroup,this.measureGroup),this.scene.add(this.root),this.renderer.domElement.addEventListener("pointerdown",this.pickPoint),this.resize(),this.resizeObserver=new ResizeObserver(this.resize),this.resizeObserver.observe(e);const t=()=>{this.disposed||(this.animationHandle=requestAnimationFrame(t),this.controls.update(),this.renderer.render(this.scene,this.camera))};t()}async load(e){var f;const t=await fetch(`${e}/scene_meta.json`).then(p=>{if(!p.ok)throw new Error(`scene_meta.json: HTTP ${p.status}`);return p.json()}),[n,r]=await Promise.all([fetch(`${e}/${t.assets.positions}`).then(p=>{if(!p.ok)throw new Error(`positions: HTTP ${p.status}`);return p.arrayBuffer()}),fetch(`${e}/${t.assets.colors}`).then(p=>{if(!p.ok)throw new Error(`colors: HTTP ${p.status}`);return p.arrayBuffer()})]);if(this.disposed)return{pointCount:0,frames:0};this.meta=t,this.viewerBase=e;const s=new Float32Array(n),o=new Uint8Array(r),a=new Float32Array(o.length);for(let p=0;p0)return e;const t=(s=this.meta)==null?void 0:s.default_scale_m_per_unit;return t&&t>0?t:117.6}timeline(){const e=this.meta,t=(e==null?void 0:e.path)??[];if(!e||t.length<2)return null;const n=this.scaleMPerUnit(),r=e.ground_grid,s=r?lt(r.fitted_normal??r.normal).normalize():null,o=[];for(let f=0;f0){const T=t[f-1],_=(p.sequence_time_s??0)-(T.sequence_time_s??0);_>1e-4&&(d=m.distanceTo(lt(T.position))*n/_)}const u=typeof p.distance_to_end_units=="number"?p.distance_to_end_units*n:null;o.push({t:g,heightM:M,speedRawMs:d,speedMs:d,distM:u})}const a=o.map((f,p)=>{if(p===0||p===o.length-1)return f.speedRawMs;const m=[o[p-1].speedRawMs,f.speedRawMs,o[p+1].speedRawMs].filter(g=>g!==null);return m.length===3?m.slice().sort((g,M)=>g-M)[1]:f.speedRawMs});for(let f=0;fm+g,0)/p.length:null}let l=0;for(let f=1;f1e-4?l*n/c:null;return{t0:o[0].t,t1:o[o.length-1].t,avgSpeedMs:h,points:o}}frames(){var r;const e=((r=this.meta)==null?void 0:r.path)??[],t=this.viewerBase;if(!t)return[];const n=s=>s?`${t}/${s}`:null;return e.map((s,o)=>({t:s.sequence_time_s??o,actual:n(s.actual_image??s.frame_image),render:n(s.render_image),overlay:n(s.overlay_image)}))}setTime(e){var p;const t=((p=this.meta)==null?void 0:p.path)??[];if(t.length===0||!this.marker)return;const n=t.map((m,g)=>m.sequence_time_s??g);let r=0;for(;r1e-6?Math.min(1,Math.max(0,(e-a)/c)):0,f=lt(s.position).lerp(lt(o.position),h);this.marker.position.copy(f),this.frustum&&(this.frustum.position.copy(f),this.orientByFrame(this.frustum,h<.5?s:o))}setPathVisible(e){this.pathGroup.visible=e}setGridVisible(e){this.gridGroup.visible=e}setPointsVisible(e){this.pointsObject&&(this.pointsObject.visible=e)}setFrustaVisible(e){this.frustaGroup.visible=e}setMeasureMode(e,t){this.measureMode=e,t&&(this.onMeasure=t),this.clearMeasurement()}clearMeasurement(){var e;this.measurePoints=[],this.measureGroup.clear(),(e=this.onMeasure)==null||e.call(this,null,null)}alignmentQuaternion(e){const t=e.scene_alignment_quaternion;if(Array.isArray(t)&&t.length===4)return new Yt(t[0],t[1],t[2],t[3]);const n=e.ground_grid;if(!n)return null;const r=lt(n.fitted_normal??n.normal).normalize(),s=new Yt().setFromUnitVectors(r,new U(0,1,0)),o=lt(n.u).applyQuaternion(s).normalize(),a=new U(o.x,0,o.z);return a.lengthSq()<1e-8?a.set(1,0,0):a.normalize(),new Yt().setFromUnitVectors(a,new U(1,0,0)).multiply(s)}buildPath(e){const t=e.path??[];if(t.length<2)return;const n=t.map(o=>lt(o.position)),r=new xt().setFromPoints(n);this.pathGroup.add(new Ti(r,new yi({color:3314175,transparent:!0,opacity:.85})));const s=(o,a,l)=>{const c=new It(new Ai(a,16,16),new bi({color:l}));c.position.copy(o),this.pathGroup.add(c)};s(n[0],Math.max(this.radius/110,.003),3314175),s(n[n.length-1],Math.max(this.radius/80,.004),16731501)}frustumWire(e,t,n){const r=this.radius/14*e,s=r*(368/720),o=this.radius/9*e,a=[new U(-r,-s,-o),new U(r,-s,-o),new U(r,s,-o),new U(-r,s,-o)],l=new U(0,0,0),c=[];for(let h=0;h<4;h+=1)c.push(l.clone(),a[h].clone()),c.push(a[h].clone(),a[(h+1)%4].clone());return new _p(new xt().setFromPoints(c),new yi({color:t,transparent:!0,opacity:n}))}orientByFrame(e,t){if(t.right&&t.down&&t.forward){const n=new rt().makeBasis(lt(t.right).normalize(),lt(t.down).normalize().multiplyScalar(-1),lt(t.forward).normalize().multiplyScalar(-1));e.setRotationFromMatrix(n)}}buildMarker(e){var n;if(!((n=e.path)!=null&&n.length))return;const t=Math.max(this.radius/130,.004);this.marker=new It(new Ai(t,16,16),new bi({color:16756736})),this.markerGroup.add(this.marker),this.frustum=this.frustumWire(1,16756736,.9),this.markerGroup.add(this.frustum)}buildFrusta(e){const t=e.path??[];for(let n=0;nE-F),h.sort((E,F)=>E-F);const p=(E,F)=>E[Math.min(E.length-1,Math.max(0,Math.round(F*(E.length-1))))],m=(p(c,.01)+p(c,.99))/2,g=(p(h,.01)+p(h,.99))/2,M=r.clone().add(s.clone().multiplyScalar(m)).add(o.clone().multiplyScalar(g)),d=Math.max(p(c,.99)-p(c,.01),p(h,.99)-p(h,.01)),u=n.major_step_units||1,T=Math.max(Math.ceil(d*1.25/u)*u,u*5)/2,_=n.minor_step_units||u/4,R=Math.max(1,Math.round(u/_)),L=Math.ceil(T/_),w=E=>new yi({color:E?4940914:2437434,transparent:!0,opacity:E?.85:.45});for(let E=-L;E<=L;E+=1){const F=E*_,$=E%R===0,x=new xt().setFromPoints([M.clone().add(s.clone().multiplyScalar(-T)).add(o.clone().multiplyScalar(F)),M.clone().add(s.clone().multiplyScalar(T)).add(o.clone().multiplyScalar(F))]),A=new xt().setFromPoints([M.clone().add(o.clone().multiplyScalar(-T)).add(s.clone().multiplyScalar(F)),M.clone().add(o.clone().multiplyScalar(T)).add(s.clone().multiplyScalar(F))]);this.gridGroup.add(new Ti(x,w($)),new Ti(A,w($)))}}fitView(e,t){const n=new fi;if(e.bbox_min&&e.bbox_max)n.set(lt(e.bbox_min),lt(e.bbox_max));else{const c=new U;for(let h=0;hc.clone().applyQuaternion(this.root.quaternion),l=a(r);this.camera.position.copy(a(o)),this.camera.near=Math.max(5e-4,s/3e3),this.camera.far=s*30,this.camera.updateProjectionMatrix(),this.controls.target.copy(l),this.controls.minDistance=s*.05,this.controls.maxDistance=s*12,this.controls.update(),this.pointsMaterial.size=s/260}dispose(){this.disposed=!0,cancelAnimationFrame(this.animationHandle),this.resizeObserver.disconnect(),this.renderer.domElement.removeEventListener("pointerdown",this.pickPoint),this.controls.dispose(),this.root.traverse(e=>{const t=e;t.geometry&&t.geometry.dispose();const n=t.material;Array.isArray(n)?n.forEach(r=>r.dispose()):n&&n.dispose()}),this.renderer.dispose(),this.renderer.domElement.remove()}}const qt=44,li=12,Nn=10,pr=18,sn={raw:"rgba(45, 106, 106, 0.9)",smooth:"#ffb000",avg:"rgba(255, 255, 255, 0.35)",height:"#7ee081",playhead:"#ffb000",grid:"rgba(255,255,255,0.08)",label:"#a1a1a1"};function yp(i,e){let t=i[0];for(const n of i)Math.abs(n.t-t.t)<1e-9&&(t=n),Math.abs(n.t-e){const n=t.current;if(!n)return;const r=()=>{const o=Math.min(window.devicePixelRatio||1,2),a=n.clientWidth,l=n.clientHeight;if(!a||!l)return;n.width=a*o,n.height=l*o;const c=n.getContext("2d");c&&(c.scale(o,o),c.clearRect(0,0,a,l),i(c,a,l))};r();const s=new ResizeObserver(r);return s.observe(n),()=>s.disconnect()},e),t}function lo(i,e,t,n,r,s,o){const a=t-Nn-pr;i.font="10px Geist, sans-serif",i.textBaseline="middle";for(let l=0;l<=3;l+=1){const c=Nn+a*l/3;i.strokeStyle=sn.grid,i.beginPath(),i.moveTo(qt,c),i.lineTo(e-li,c),i.stroke(),i.fillStyle=sn.label,i.textAlign="right",i.fillText(o(s*(1-l/3)),qt-6,c)}i.fillStyle=sn.label,i.textAlign="left",i.fillText("0.0s",qt,t-7),i.textAlign="right",i.fillText(`${(r-n).toFixed(1)}s`,e-li,t-7)}function is(i,e,t,n,r,s,o){i.strokeStyle=s,i.lineWidth=o,i.lineJoin="round",i.beginPath();let a=!1;for(const l of e){const c=t(l);c!==null&&(a?i.lineTo(n(l.t),r(c)):(i.moveTo(n(l.t),r(c)),a=!0))}i.stroke()}function co(i,e,t,n){i.strokeStyle=sn.playhead,i.lineWidth=1.4,i.beginPath(),i.moveTo(t,Nn-3),i.lineTo(t,e-pr+3),i.stroke(),n!==null&&(i.fillStyle=sn.playhead,i.beginPath(),i.arc(t,n,4,0,Math.PI*2),i.fill())}function uo({chartRef:i,t0:e,t1:t,onSeek:n}){const r=Oe.useRef(!1),s=o=>{const a=o.currentTarget.getBoundingClientRect(),l=(o.clientX-a.left-qt)/Math.max(a.width-qt-li,1);n(e+Math.min(1,Math.max(0,l))*(t-e))};return we.jsx("canvas",{className:"chart-canvas",ref:i,onPointerDown:o=>{r.current=!0,o.currentTarget.setPointerCapture(o.pointerId),s(o)},onPointerMove:o=>{r.current&&s(o)},onPointerUp:()=>{r.current=!1}})}function Tp({timeline:i,currentT:e,onSeek:t}){const{t0:n,t1:r,points:s,avgSpeedMs:o}=i,a=Math.max(r-n,1e-6),l=Math.min(Math.max(e,n),r),c=yp(s,l),h=s.map(d=>d.speedRawMs).filter(d=>d!==null),f=Math.max(1,...h)*1.12,p=s.map(d=>d.heightM).filter(d=>d!==null),m=Math.max(1,...p)*1.12,g=oo((d,u,T)=>{const _=u-qt-li,R=T-Nn-pr,L=E=>qt+(E-n)/a*_,w=E=>Nn+R-E/f*R;lo(d,u,T,n,r,f,E=>E.toFixed(0)),o!==null&&(d.strokeStyle=sn.avg,d.setLineDash([4,4]),d.beginPath(),d.moveTo(qt,w(o)),d.lineTo(u-li,w(o)),d.stroke(),d.setLineDash([])),is(d,s,E=>E.speedRawMs,L,w,sn.raw,1),is(d,s,E=>E.speedMs,L,w,sn.smooth,2),co(d,T,L(l),c.speedMs!==null?w(c.speedMs):null)},[i,l]),M=oo((d,u,T)=>{const _=u-qt-li,R=T-Nn-pr,L=E=>qt+(E-n)/a*_,w=E=>Nn+R-E/m*R;lo(d,u,T,n,r,m,E=>E.toFixed(0)),is(d,s,E=>E.heightM,L,w,sn.height,2),co(d,T,L(l),c.heightM!==null?w(c.heightM):null)},[i,l]);return we.jsxs("div",{className:"scene-charts",children:[we.jsxs("div",{className:"chart-card",children:[we.jsxs("header",{children:[we.jsx("span",{children:"Speed vs. Time"}),we.jsxs("span",{className:"chart-readout",children:[c.speedMs!==null?`${c.speedMs.toFixed(1)} m/s`:"--",o!==null?` · avg ${o.toFixed(1)}`:""]})]}),we.jsx(uo,{chartRef:g,t0:n,t1:r,onSeek:t})]}),we.jsxs("div",{className:"chart-card",children:[we.jsxs("header",{children:[we.jsx("span",{children:"Height Above Ground"}),we.jsxs("span",{className:"chart-readout",children:[c.heightM!==null?`${c.heightM.toFixed(1)}m AGL`:"--",c.distM!==null?` | ${c.distM.toFixed(0)}m tgt`:""]})]}),we.jsx(uo,{chartRef:M,t0:n,t1:r,onSeek:t})]})]})}function ho(i){const e=Math.floor(i/60),t=(i%60).toFixed(1).padStart(4,"0");return`${e}:${t}`}function fo(i,e){if(!i.length)return-1;let t=0;for(let n=1;n{if(!i.scenePath||!e.current)return;const k=new Ep(e.current);return n.current=k,p("Loading 3D scene…"),k.load(`${Zo}/${i.scenePath}/viewer`).then(P=>{if(n.current!==k)return;g(P);const ye=k.timeline();d(ye),o.current=ye,T(k.frames()),ye&&(r.current={playing:!1,last:0,t:ye.t0},w(ye.t0)),p(null)}).catch(P=>{n.current===k&&p(`Failed to load scene (${P.message??P})`)}),()=>{n.current=null,k.dispose()}},[i.scenePath]);const Ee=Oe.useCallback(k=>{const P=l.current,ye=fo(P,k);if(ye<0)return null;const le=P[ye];return le[c.current]??le.actual},[]),B=Oe.useCallback(k=>{const P=a.current;if(!P||!k)return;const ye=h.current.get(k);if(!ye||!ye.complete||ye.naturalWidth===0)return;(P.width!==ye.naturalWidth||P.height!==ye.naturalHeight)&&(P.width=ye.naturalWidth,P.height=ye.naturalHeight);const le=P.getContext("2d");le&&le.drawImage(ye,0,0)},[]);Oe.useEffect(()=>{l.current=u},[u]),Oe.useEffect(()=>{c.current=_},[_]),Oe.useEffect(()=>{const k=h.current;for(const P of u){const ye=P[_]??P.actual;if(!ye||k.has(ye))continue;const le=new Image;le.decoding="async",le.onload=()=>{Ee(r.current.t)===ye&&B(ye)},le.src=ye,k.set(ye,le)}B(Ee(r.current.t))},[u,_,Ee,B]),Oe.useEffect(()=>{B(Ee(r.current.t))},[L,_,Z,Ee,B]),Oe.useEffect(()=>{let k=0;const P=ye=>{var Ve;k=requestAnimationFrame(P);const le=r.current,Ce=o.current;if(!Ce||!le.playing)return;const Te=(ye-le.last)/1e3;le.last=ye,le.t=Math.min(le.t+Te,Ce.t1),le.t>=Ce.t1&&(le.playing=!1,F(!1)),Math.abs(le.t-s.current)>.02&&(s.current=le.t,(Ve=n.current)==null||Ve.setTime(le.t),B(Ee(le.t)),w(le.t))};return k=requestAnimationFrame(P),()=>cancelAnimationFrame(k)},[B,Ee]),Oe.useEffect(()=>{var k;return(k=n.current)==null?void 0:k.setPathVisible($)},[$]),Oe.useEffect(()=>{var k;return(k=n.current)==null?void 0:k.setGridVisible(A)},[A]),Oe.useEffect(()=>{var k;return(k=n.current)==null?void 0:k.setPointsVisible(q)},[q]),Oe.useEffect(()=>{var k;return(k=n.current)==null?void 0:k.setFrustaVisible(Y)},[Y]);const Q=k=>{var P;r.current.t=k,s.current=k,(P=n.current)==null||P.setTime(k),B(Ee(k)),w(k)},de=()=>{const k=r.current,P=o.current;P&&(!k.playing&&k.t>=P.t1-.05&&(k.t=P.t0),k.playing=!k.playing,k.last=performance.now(),F(k.playing))};Oe.useEffect(()=>{const k=P=>{var le;if(P.code!=="Space")return;const ye=((le=document.activeElement)==null?void 0:le.tagName)??"";["INPUT","SELECT","TEXTAREA","BUTTON"].includes(ye)||(P.preventDefault(),de())};return window.addEventListener("keydown",k),()=>window.removeEventListener("keydown",k)},[]);const Re=()=>{var P;const k=!X;re(k),pe(k?"Click two points in the scene":null),(P=n.current)==null||P.setMeasureMode(k,ye=>{ye!==null?pe(`Distance: ${ye.toFixed(1)} m`):k&&pe("Click two points in the scene")})},ve=()=>{const k=t.current;k&&(document.fullscreenElement?document.exitFullscreen():k.requestFullscreen().catch(()=>{}))},fe=Oe.useMemo(()=>fo(u,L),[u,L]),qe=fe>=0?u[fe][_]??u[fe].actual:null;return i.scenePath?we.jsxs("div",{className:"scene-view",children:[we.jsx("a",{className:"back-link",href:"#/",children:"← All videos"}),we.jsx("h1",{children:i.description||i.videoFile}),we.jsxs("p",{className:"view-meta",children:[i.date,i.town?` · ${i.town}`:""," · 3D reconstruction",m?` · ${m.pointCount.toLocaleString()} points · ${m.frames} camera poses`:""]}),we.jsxs("div",{className:"scene-stage",ref:t,children:[we.jsx("div",{className:"canvas-holder",ref:e}),f?we.jsx("div",{className:"scene-status",children:f}):null,Z&&qe?we.jsxs("div",{className:"scene-frame-panel",children:[we.jsxs("div",{className:"frame-tabs",children:[["overlay","render","actual"].map(k=>we.jsx("button",{type:"button",className:_===k?"active":"",onClick:()=>R(k),children:k==="overlay"?"Overlay":k==="render"?"Render":"Actual"},k)),we.jsxs("span",{className:"frame-counter",children:[fe+1,"/",u.length]})]}),we.jsx("canvas",{ref:a,"aria-label":`VGGT ${_} frame ${fe+1}`})]}):null,null]}),M?we.jsxs("div",{className:"scene-controls",children:[we.jsx("button",{type:"button",className:"play-btn",onClick:de,"aria-label":E?"Pause":"Play",title:"Play/pause (space)",children:E?"❚❚":"▶"}),we.jsx("input",{type:"range",className:"scrubber",min:M.t0,max:M.t1,step:.01,value:Math.min(Math.max(L,M.t0),M.t1),onChange:k=>Q(Number(k.target.value)),"aria-label":"Timeline"}),we.jsxs("span",{className:"time-display",children:[ho(Math.max(L-M.t0,0))," / ",ho(M.t1-M.t0)]}),we.jsxs("span",{className:"scene-toggles",children:[we.jsxs("label",{children:[we.jsx("input",{type:"checkbox",checked:q,onChange:k=>H(k.target.checked)}),"Points"]}),we.jsxs("label",{children:[we.jsx("input",{type:"checkbox",checked:$,onChange:k=>x(k.target.checked)}),"Path"]}),we.jsxs("label",{children:[we.jsx("input",{type:"checkbox",checked:Y,onChange:k=>W(k.target.checked)}),"Cameras"]}),we.jsxs("label",{children:[we.jsx("input",{type:"checkbox",checked:A,onChange:k=>te(k.target.checked)}),"Grid"]}),we.jsxs("label",{children:[we.jsx("input",{type:"checkbox",checked:Z,onChange:k=>D(k.target.checked)}),"Frames"]}),null]})]}):null,ae?we.jsx("p",{className:"measure-readout",children:ae}):null,M?we.jsx(Tp,{timeline:M,currentT:L,onSeek:Q}):null,we.jsx("div",{className:"view-actions",style:{marginTop:14},children:we.jsx("a",{href:Jo(i.videoFile),children:"← Watch the full video with annotations"})})]}):we.jsxs("div",{children:[we.jsx("a",{className:"back-link",href:"#/",children:"← All videos"}),we.jsx("p",{className:"not-found",children:"No 3D scene for this video."})]})}export{wp as SceneView}; diff --git a/public/fpv/assets/index-D8wImrg-.css b/public/fpv/assets/index-D8wImrg-.css index 6329773..17576ca 100644 --- a/public/fpv/assets/index-D8wImrg-.css +++ b/public/fpv/assets/index-D8wImrg-.css @@ -1 +1 @@ -:root{color-scheme:dark;--bg: #000000;--text: #ededed;--brand: #3291ff;--brand-hover: #ffffff;--grey: #a1a1a1;--hairline: #333333;--surface: #111111;--font-sans: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;--font-doto: "Doto", var(--font-sans);--content-width: 1160px;--spacing: 30px}*{box-sizing:border-box}html,body{margin:0;padding:0}body{font:400 17px/1.65 var(--font-sans);color:var(--text);background-color:var(--bg);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-kerning:normal}::selection{background:#3291ff4d}h1,h2,h3{font-weight:600;color:#fff;letter-spacing:-.01em;margin:0 0 15px}a{color:var(--brand);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.15em;transition:color .15s ease}a:visited{color:var(--brand)}a:hover{color:var(--brand-hover);text-decoration-thickness:2px}.wrapper{max-width:calc(var(--content-width) - var(--spacing) * 2);margin:0 auto;padding:0 var(--spacing)}@media screen and (max-width: 800px){.wrapper{max-width:calc(var(--content-width) - var(--spacing));padding:0 calc(var(--spacing) / 2)}}.site-header{border-bottom:1px solid var(--hairline);min-height:56px}.site-header .wrapper{display:flex;align-items:center;justify-content:space-between}.site-title{font-family:var(--font-doto);font-size:clamp(17px,4.6vw,26px);font-weight:700;line-height:56px;letter-spacing:.02em;text-decoration:none;white-space:nowrap}.site-title,.site-title:visited{color:#ededed}.site-title:hover{color:#fff;text-decoration:none}.site-nav{line-height:56px}.site-nav a{color:var(--text);text-decoration:none}.site-nav a:hover{color:#fff}.site-nav a:not(:last-child){margin-right:20px}.page-content{padding:var(--spacing) 0}.page-lede{color:var(--grey);font-size:15px;margin:-6px 0 24px}.gallery-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:24px}.gallery-toolbar input[type=search]{flex:1;min-width:0;max-width:380px;background:var(--surface);color:var(--text);border:1px solid var(--hairline);border-radius:6px;padding:8px 12px;font:400 14px var(--font-sans);outline:none}.gallery-toolbar input[type=search]:focus{border-color:var(--brand)}.gallery-count{margin-left:auto;color:var(--grey);font-size:13px}.video-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:18px 16px}.video-card{display:flex;flex-direction:column;gap:8px;min-width:0}.video-card .thumb{display:block;aspect-ratio:16 / 9;overflow:hidden;border-radius:8px;background:var(--surface) center/cover no-repeat;border:1px solid var(--hairline);position:relative}.video-card .thumb img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .25s ease}.video-card .thumb:hover img{transform:scale(1.03)}.badge-3d{position:absolute;right:8px;bottom:8px;background:#000000bf;color:#fff;font-size:11px;font-weight:500;padding:2px 6px;border-radius:4px}.video-card .title{font-size:14.5px;font-weight:500;color:var(--text);line-height:1.35;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;text-decoration:none}.video-card .title:hover{color:#fff}.video-card .meta{color:var(--grey);font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.card-actions{display:flex;gap:8px;margin-top:2px}.card-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;flex:1;min-height:30px;padding:0 10px;border:1px solid var(--hairline);border-radius:6px;background:var(--surface);color:var(--text);font-size:13px;font-weight:500;text-decoration:none;transition:border-color .15s ease,color .15s ease}.card-btn:hover{color:#fff;border-color:#555;text-decoration:none}.card-btn.primary{border-color:#3291ff8c;color:var(--brand)}.card-btn.primary:hover{border-color:var(--brand);color:#fff}.card-btn.disabled{color:#555;pointer-events:none}.toolbar-btn{display:inline-flex;align-items:center;gap:6px;min-height:36px;padding:0 12px;border:1px solid var(--hairline);border-radius:6px;background:var(--surface);color:var(--text);font:500 13px var(--font-sans);cursor:pointer;transition:border-color .15s ease,color .15s ease}.toolbar-btn:hover{border-color:#555;color:#fff}.toolbar-btn.active{border-color:var(--brand);color:var(--brand)}.video-view video{width:100%;max-height:62vh;background:#000;border-radius:8px;border:1px solid var(--hairline);outline:none;cursor:pointer}.transport{display:flex;align-items:center;gap:6px;margin-top:8px}.t-row{display:flex;align-items:center;gap:6px;min-width:0}.t-primary{flex:1}.transport button{flex-shrink:0;min-width:38px;height:34px;padding:0 8px;border:1px solid var(--hairline);border-radius:6px;background:var(--surface);color:var(--grey);font:500 12.5px var(--font-sans);cursor:pointer}.transport button:hover{color:#fff;border-color:#555}.transport .play-btn{width:40px;height:40px;min-width:40px;border-radius:999px;color:var(--text);font-size:13px}.transport .scrubber{flex:1;min-width:40px}.transport .time-display{flex-shrink:0}.video-headline{margin:14px 0 4px}.video-headline h1{font-size:18px;line-height:1.35;margin:0 0 4px}.video-headline .view-meta{margin:0 0 8px}.icon-link{display:inline-flex;align-items:center;vertical-align:middle;color:var(--grey)}.icon-link:hover{color:#fff}.view-meta{color:var(--grey);font-size:13.5px;margin:10px 0 4px}.view-actions{margin:10px 0 24px;font-size:14px}.view-actions a:not(:last-child){margin-right:18px}.timeline{position:relative;height:34px;background:var(--surface);border:1px solid var(--hairline);border-radius:6px;margin:14px 0 8px;cursor:pointer}.timeline .marker{position:absolute;top:0;bottom:0;width:2px;opacity:.9}.timeline .playhead{position:absolute;top:-3px;bottom:-3px;width:2px;background:#fff;box-shadow:0 0 6px #fff9}.legend{display:flex;flex-wrap:wrap;gap:6px 16px;color:var(--grey);font-size:12.5px;margin-bottom:18px}.legend .chip:before{content:"";display:inline-block;width:8px;height:8px;border-radius:2px;margin-right:6px;background:var(--chip-color, var(--grey))}.segment-table{width:100%;border-collapse:collapse;font-size:14px}.segment-table th,.segment-table td{text-align:left;padding:7px 12px 7px 0;border-bottom:1px solid var(--hairline)}.segment-table th{color:var(--grey);font-weight:500;font-size:12.5px;text-transform:uppercase;letter-spacing:.04em}.segment-table .time-link{font-variant-numeric:tabular-nums}.segment-type{display:inline-flex;align-items:center;gap:6px}.segment-type:before{content:"";width:8px;height:8px;border-radius:2px;background:var(--chip-color, var(--grey))}.annotation-note{color:var(--grey);font-size:13px;margin:8px 0 24px}.scene-view h1{font-size:21px;margin:0 0 4px}.scene-view .view-meta{margin:0 0 12px}.scene-view .back-link{margin-bottom:10px}.scene-stage{position:relative;height:clamp(300px,calc(100vh - 400px),700px);border:1px solid var(--hairline);border-radius:8px;overflow:hidden;background:#050607}.scene-stage .canvas-holder{position:absolute;top:0;right:0;bottom:0;left:0}.scene-stage canvas{display:block;width:100%;height:100%}.scene-frame-panel{position:absolute;right:10px;bottom:10px;width:min(36%,340px);border:1px solid rgba(255,255,255,.25);border-radius:6px;overflow:hidden;background:#000;box-shadow:0 4px 18px #0000008c;z-index:3}.scene-frame-panel img,.scene-frame-panel canvas{display:block;width:100%;height:auto}.frame-tabs{display:flex;align-items:center;gap:2px;padding:4px;background:#000c}.frame-tabs button{border:0;border-radius:4px;padding:2px 7px;background:transparent;color:var(--grey);font:500 11px var(--font-sans);cursor:pointer}.frame-tabs button.active{background:#ffffff29;color:#fff}.frame-tabs .frame-counter{margin-left:auto;padding-right:4px;color:var(--grey);font-size:10.5px;font-variant-numeric:tabular-nums}.stage-btn{position:absolute;display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border:1px solid rgba(255,255,255,.25);border-radius:6px;background:#0009;color:var(--text);font-size:15px;cursor:pointer;z-index:4;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}.stage-btn:hover{color:#fff;border-color:#777}.fullscreen-btn{top:10px;right:10px}.scene-status{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;color:var(--grey);font-size:14px;z-index:2}.scene-controls{display:flex;align-items:center;gap:12px;margin:12px 0 4px}.play-btn{flex-shrink:0;width:40px;height:40px;border:1px solid var(--hairline);border-radius:999px;background:var(--surface);color:var(--text);font-size:14px;cursor:pointer;transition:border-color .15s ease,color .15s ease}.play-btn:hover{color:#fff;border-color:var(--brand)}.scrubber{flex:1;min-width:0;accent-color:var(--brand);height:4px;cursor:pointer}.time-display{flex-shrink:0;color:var(--grey);font-size:13px;font-variant-numeric:tabular-nums}.scene-toggles{flex-shrink:0;display:inline-flex;gap:12px;color:var(--grey);font-size:13px}.scene-toggles label{display:inline-flex;align-items:center;gap:5px;cursor:pointer;-webkit-user-select:none;user-select:none}.scene-toggles input{accent-color:var(--brand)}.measure-btn{min-height:26px;padding:0 10px;border:1px solid var(--hairline);border-radius:6px;background:var(--surface);color:var(--grey);font:500 12.5px var(--font-sans);cursor:pointer}.measure-btn:hover{color:#fff;border-color:#555}.measure-btn.active{border-color:var(--brand);color:var(--brand)}.measure-readout{color:var(--text);font-size:13.5px;margin:8px 0 0}.scene-charts{display:grid;gap:10px;margin-top:10px}.chart-card{border:1px solid var(--hairline);border-radius:8px;background:var(--surface);padding:10px 12px 8px}.chart-card header{display:flex;align-items:baseline;justify-content:space-between;gap:10px;font-size:14px;font-weight:600;color:#fff;margin-bottom:4px}.chart-readout{color:#ffb000;font-size:13px;font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap}.chart-canvas{display:block;width:100%;height:104px;cursor:crosshair;touch-action:none}@media screen and (max-width: 700px){.scene-stage{height:clamp(260px,44vh,480px)}.scene-frame-panel{width:46%;right:8px;bottom:8px}.scene-controls{flex-wrap:wrap;gap:10px}.play-btn{width:44px;height:44px}.scrubber{order:3;flex-basis:100%;height:6px}.scene-toggles{margin-left:auto;flex-wrap:wrap}.chart-canvas{height:96px}.transport{flex-direction:column;align-items:stretch;gap:8px}.transport .time-display{font-size:12px}.t-secondary button{flex:1 1 0;min-width:0;height:40px;padding:0 2px}}.back-link{display:inline-block;margin-bottom:16px;font-size:14px}.not-found{color:var(--grey);padding:60px 0;text-align:center} +:root{color-scheme:dark;--bg: #000000;--text: #ededed;--brand: #3291ff;--brand-hover: #ffffff;--grey: #a1a1a1;--hairline: #333333;--surface: #111111;--font-sans: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;--font-doto: "Doto", var(--font-sans);--content-width: 1160px;--spacing: 30px}*{box-sizing:border-box}html,body{margin:0;padding:0}body{font:400 17px/1.65 var(--font-sans);color:var(--text);background-color:var(--bg);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-kerning:normal}::selection{background:#3291ff4d}h1,h2,h3{font-weight:600;color:#fff;letter-spacing:-.01em;margin:0 0 15px}a{color:var(--brand);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.15em;transition:color .15s ease}a:visited{color:var(--brand)}a:hover{color:var(--brand-hover);text-decoration-thickness:2px}.wrapper{max-width:calc(var(--content-width) - var(--spacing) * 2);margin:0 auto;padding:0 var(--spacing)}@media screen and (max-width: 800px){.wrapper{max-width:calc(var(--content-width) - var(--spacing));padding:0 calc(var(--spacing) / 2)}}.site-header{border-bottom:1px solid var(--hairline);min-height:56px}.site-header .wrapper{display:flex;align-items:center;justify-content:space-between}.site-title{font-family:var(--font-doto);font-size:clamp(17px,4.6vw,26px);font-weight:700;line-height:56px;letter-spacing:.02em;text-decoration:none;white-space:nowrap}.site-title,.site-title:visited{color:#ededed}.site-title:hover{color:#fff;text-decoration:none}.site-nav{line-height:56px}.site-nav a{color:var(--text);text-decoration:none}.site-nav a:hover{color:#fff}.site-nav a:not(:last-child){margin-right:20px}.page-content{padding:var(--spacing) 0}.page-lede{color:var(--grey);font-size:15px;margin:-6px 0 24px}.gallery-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:24px}.gallery-toolbar input[type=search]{flex:1;min-width:0;max-width:380px;background:var(--surface);color:var(--text);border:1px solid var(--hairline);border-radius:6px;padding:8px 12px;font:400 14px var(--font-sans);outline:none}.gallery-toolbar input[type=search]:focus{border-color:var(--brand)}.gallery-count{margin-left:auto;color:var(--grey);font-size:13px}.video-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:18px 16px}.video-card{display:flex;flex-direction:column;gap:8px;min-width:0}.video-card .thumb{display:block;aspect-ratio:16 / 9;overflow:hidden;border-radius:8px;background:var(--surface) center/cover no-repeat;border:1px solid var(--hairline);position:relative}.video-card .thumb img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .25s ease}.video-card .thumb:hover img{transform:scale(1.03)}.badge-3d{position:absolute;right:8px;bottom:8px;background:#000000bf;color:#fff;font-size:11px;font-weight:500;padding:2px 6px;border-radius:4px}.video-card .title{font-size:14.5px;font-weight:500;color:var(--text);line-height:1.35;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;text-decoration:none}.video-card .title:hover{color:#fff}.video-card .meta{color:var(--grey);font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.card-actions{display:flex;gap:8px;margin-top:2px}.card-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;flex:1;min-height:30px;padding:0 10px;border:1px solid var(--hairline);border-radius:6px;background:var(--surface);color:var(--text);font-size:13px;font-weight:500;text-decoration:none;transition:border-color .15s ease,color .15s ease}.card-btn:hover{color:#fff;border-color:#555;text-decoration:none}.card-btn.primary{border-color:#3291ff8c;color:var(--brand)}.card-btn.primary:hover{border-color:var(--brand);color:#fff}.card-btn.disabled{color:#555;pointer-events:none}.toolbar-btn{display:inline-flex;align-items:center;gap:6px;min-height:36px;padding:0 12px;border:1px solid var(--hairline);border-radius:6px;background:var(--surface);color:var(--text);font:500 13px var(--font-sans);cursor:pointer;transition:border-color .15s ease,color .15s ease}.toolbar-btn:hover{border-color:#555;color:#fff}.toolbar-btn.active{border-color:var(--brand);color:var(--brand)}.video-view video{width:100%;max-height:62vh;background:#000;border-radius:8px;border:1px solid var(--hairline);outline:none;cursor:pointer}.video-stage{position:relative}.video-stage video{width:100%;max-height:62vh;background:#000;border-radius:8px;border:1px solid var(--hairline);outline:none;cursor:pointer;object-fit:contain}.video-play-overlay{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:64px;height:64px;border-radius:999px;border:1px solid rgba(255,255,255,.35);background:rgba(0,0,0,.45);color:#fff;font-size:22px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;padding-left:4px;transition:background .15s ease,border-color .15s ease,transform .15s ease}.video-play-overlay:hover{background:rgba(0,0,0,.65);border-color:var(--brand);transform:translate(-50%,-50%) scale(1.06)}.transport{display:flex;align-items:center;gap:6px;margin-top:8px}.t-row{display:flex;align-items:center;gap:6px;min-width:0}.t-primary{flex:1}.transport button{flex-shrink:0;min-width:38px;height:34px;padding:0 8px;border:1px solid var(--hairline);border-radius:6px;background:var(--surface);color:var(--grey);font:500 12.5px var(--font-sans);cursor:pointer}.transport button:hover{color:#fff;border-color:#555}.transport .play-btn{width:40px;height:40px;min-width:40px;border-radius:999px;color:var(--text);font-size:13px}.transport .scrubber{flex:1;min-width:40px}.transport .time-display{flex-shrink:0}.video-headline{margin:14px 0 4px}.video-headline h1{font-size:18px;line-height:1.35;margin:0 0 4px}.video-headline .view-meta{margin:0 0 8px}.icon-link{display:inline-flex;align-items:center;vertical-align:middle;color:var(--grey)}.icon-link:hover{color:#fff}.view-meta{color:var(--grey);font-size:13.5px;margin:10px 0 4px}.view-actions{margin:10px 0 24px;font-size:14px}.view-actions a:not(:last-child){margin-right:18px}.timeline{position:relative;height:34px;background:var(--surface);border:1px solid var(--hairline);border-radius:6px;margin:14px 0 8px;cursor:pointer}.timeline .marker{position:absolute;top:0;bottom:0;width:2px;opacity:.9}.timeline .playhead{position:absolute;top:-3px;bottom:-3px;width:2px;background:#fff;box-shadow:0 0 6px #fff9}.legend{display:flex;flex-wrap:wrap;gap:6px 16px;color:var(--grey);font-size:12.5px;margin-bottom:18px}.legend .chip:before{content:"";display:inline-block;width:8px;height:8px;border-radius:2px;margin-right:6px;background:var(--chip-color, var(--grey))}.segment-table{width:100%;border-collapse:collapse;font-size:14px}.segment-table th,.segment-table td{text-align:left;padding:7px 12px 7px 0;border-bottom:1px solid var(--hairline)}.segment-table th{color:var(--grey);font-weight:500;font-size:12.5px;text-transform:uppercase;letter-spacing:.04em}.segment-table .time-link{font-variant-numeric:tabular-nums}.segment-type{display:inline-flex;align-items:center;gap:6px}.segment-type:before{content:"";width:8px;height:8px;border-radius:2px;background:var(--chip-color, var(--grey))}.annotation-note{color:var(--grey);font-size:13px;margin:8px 0 24px}.scene-view h1{font-size:21px;margin:0 0 4px}.scene-view .view-meta{margin:0 0 12px}.scene-view .back-link{margin-bottom:10px}.scene-stage{position:relative;height:clamp(300px,calc(100vh - 400px),700px);border:1px solid var(--hairline);border-radius:8px;overflow:hidden;background:#050607}.scene-stage .canvas-holder{position:absolute;top:0;right:0;bottom:0;left:0}.scene-stage canvas{display:block;width:100%;height:100%}.scene-frame-panel{position:absolute;right:10px;bottom:10px;width:min(36%,340px);border:1px solid rgba(255,255,255,.25);border-radius:6px;overflow:hidden;background:#000;box-shadow:0 4px 18px #0000008c;z-index:3}.scene-frame-panel img,.scene-frame-panel canvas{display:block;width:100%;height:auto}.frame-tabs{display:flex;align-items:center;gap:2px;padding:4px;background:#000c}.frame-tabs button{border:0;border-radius:4px;padding:2px 7px;background:transparent;color:var(--grey);font:500 11px var(--font-sans);cursor:pointer}.frame-tabs button.active{background:#ffffff29;color:#fff}.frame-tabs .frame-counter{margin-left:auto;padding-right:4px;color:var(--grey);font-size:10.5px;font-variant-numeric:tabular-nums}.stage-btn{position:absolute;display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border:1px solid rgba(255,255,255,.25);border-radius:6px;background:#0009;color:var(--text);font-size:15px;cursor:pointer;z-index:4;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}.stage-btn:hover{color:#fff;border-color:#777}.fullscreen-btn{top:10px;right:10px}.scene-status{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;align-items:center;justify-content:center;color:var(--grey);font-size:14px;z-index:2}.scene-controls{display:flex;align-items:center;gap:12px;margin:12px 0 4px}.play-btn{flex-shrink:0;width:40px;height:40px;border:1px solid var(--hairline);border-radius:999px;background:var(--surface);color:var(--text);font-size:14px;cursor:pointer;transition:border-color .15s ease,color .15s ease}.play-btn:hover{color:#fff;border-color:var(--brand)}.scrubber{flex:1;min-width:0;accent-color:var(--brand);height:4px;cursor:pointer}.time-display{flex-shrink:0;color:var(--grey);font-size:13px;font-variant-numeric:tabular-nums}.scene-toggles{flex-shrink:0;display:inline-flex;gap:12px;color:var(--grey);font-size:13px}.scene-toggles label{display:inline-flex;align-items:center;gap:5px;cursor:pointer;-webkit-user-select:none;user-select:none}.scene-toggles input{accent-color:var(--brand)}.measure-btn{min-height:26px;padding:0 10px;border:1px solid var(--hairline);border-radius:6px;background:var(--surface);color:var(--grey);font:500 12.5px var(--font-sans);cursor:pointer}.measure-btn:hover{color:#fff;border-color:#555}.measure-btn.active{border-color:var(--brand);color:var(--brand)}.measure-readout{color:var(--text);font-size:13.5px;margin:8px 0 0}.scene-charts{display:grid;gap:10px;margin-top:10px}.chart-card{border:1px solid var(--hairline);border-radius:8px;background:var(--surface);padding:10px 12px 8px}.chart-card header{display:flex;align-items:baseline;justify-content:space-between;gap:10px;font-size:14px;font-weight:600;color:#fff;margin-bottom:4px}.chart-readout{color:#ffb000;font-size:13px;font-weight:600;font-variant-numeric:tabular-nums;white-space:nowrap}.chart-canvas{display:block;width:100%;height:104px;cursor:crosshair;touch-action:none}@media screen and (max-width: 700px){.scene-stage{height:clamp(260px,44vh,480px)}.scene-frame-panel{width:46%;right:8px;bottom:8px}.scene-controls{flex-wrap:wrap;gap:10px}.play-btn{width:44px;height:44px}.scrubber{order:3;flex-basis:100%;height:6px}.scene-toggles{margin-left:auto;flex-wrap:wrap}.chart-canvas{height:96px}.transport{flex-direction:column;align-items:stretch;gap:8px}.transport .time-display{font-size:12px}.t-secondary button{flex:1 1 0;min-width:0;height:40px;padding:0 2px}}.back-link{display:inline-block;margin-bottom:16px;font-size:14px}.not-found{color:var(--grey);padding:60px 0;text-align:center} diff --git a/public/fpv/assets/index-ObpdO5MX.js b/public/fpv/assets/index-ObpdO5MX.js index 1e06c81..76d09cf 100644 --- a/public/fpv/assets/index-ObpdO5MX.js +++ b/public/fpv/assets/index-ObpdO5MX.js @@ -37,4 +37,4 @@ `+l[o].replace(" at new "," at ");return e.displayName&&s.includes("")&&(s=s.replace("",e.displayName)),s}while(1<=o&&0<=i);break}}}finally{El=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?gn(e):""}function Ac(e){switch(e.tag){case 5:return gn(e.type);case 16:return gn("Lazy");case 13:return gn("Suspense");case 19:return gn("SuspenseList");case 0:case 2:case 15:return e=Cl(e.type,!1),e;case 11:return e=Cl(e.type.render,!1),e;case 1:return e=Cl(e.type,!0),e;default:return""}}function bl(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Ft:return"Fragment";case Mt:return"Portal";case Zl:return"Profiler";case Gu:return"StrictMode";case Jl:return"Suspense";case ql:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case ds:return(e.displayName||"Context")+".Consumer";case fs:return(e._context.displayName||"Context")+".Provider";case Zu:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Ju:return t=e.displayName||null,t!==null?t:bl(e.type)||"Memo";case Je:t=e._payload,e=e._init;try{return bl(e(t))}catch{}}return null}function Vc(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return bl(t);case 8:return t===Gu?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function ft(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function ms(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function Bc(e){var t=ms(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var l=n.get,u=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return l.call(this)},set:function(o){r=""+o,u.call(this,o)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(o){r=""+o},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function rr(e){e._valueTracker||(e._valueTracker=Bc(e))}function hs(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=ms(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Rr(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function eu(e,t){var n=t.checked;return B({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function Wo(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=ft(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function vs(e,t){t=t.checked,t!=null&&Xu(e,"checked",t,!1)}function tu(e,t){vs(e,t);var n=ft(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?nu(e,t.type,n):t.hasOwnProperty("defaultValue")&&nu(e,t.type,ft(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function Qo(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function nu(e,t,n){(t!=="number"||Rr(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var wn=Array.isArray;function Qt(e,t,n,r){if(e=e.options,t){t={};for(var l=0;l"+t.valueOf().toString()+"",t=lr.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Rn(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var xn={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Hc=["Webkit","ms","Moz","O"];Object.keys(xn).forEach(function(e){Hc.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),xn[t]=xn[e]})});function ks(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||xn.hasOwnProperty(e)&&xn[e]?(""+t).trim():t+"px"}function Ss(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,l=ks(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,l):e[n]=l}}var Wc=B({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function uu(e,t){if(t){if(Wc[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(g(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(g(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(g(61))}if(t.style!=null&&typeof t.style!="object")throw Error(g(62))}}function ou(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var iu=null;function qu(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var su=null,Kt=null,Yt=null;function Xo(e){if(e=Jn(e)){if(typeof su!="function")throw Error(g(280));var t=e.stateNode;t&&(t=il(t),su(e.stateNode,e.type,t))}}function xs(e){Kt?Yt?Yt.push(e):Yt=[e]:Kt=e}function Es(){if(Kt){var e=Kt,t=Yt;if(Yt=Kt=null,Xo(e),t)for(e=0;e>>=0,e===0?32:31-(tf(e)/nf|0)|0}var ur=64,or=4194304;function kn(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Or(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,l=e.suspendedLanes,u=e.pingedLanes,o=n&268435455;if(o!==0){var i=o&~l;i!==0?r=kn(i):(u&=o,u!==0&&(r=kn(u)))}else o=n&~l,o!==0?r=kn(o):u!==0&&(r=kn(u));if(r===0)return 0;if(t!==0&&t!==r&&!(t&l)&&(l=r&-r,u=t&-t,l>=u||l===16&&(u&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function Gn(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-Re(t),e[t]=n}function of(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=Cn),ri=" ",li=!1;function Hs(e,t){switch(e){case"keyup":return Df.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Ws(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Dt=!1;function If(e,t){switch(e){case"compositionend":return Ws(t);case"keypress":return t.which!==32?null:(li=!0,ri);case"textInput":return e=t.data,e===ri&&li?null:e;default:return null}}function $f(e,t){if(Dt)return e==="compositionend"||!oo&&Hs(e,t)?(e=Vs(),Er=ro=tt=null,Dt=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=si(n)}}function Xs(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Xs(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Gs(){for(var e=window,t=Rr();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Rr(e.document)}return t}function io(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function Yf(e){var t=Gs(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&Xs(n.ownerDocument.documentElement,n)){if(r!==null&&io(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var l=n.textContent.length,u=Math.min(r.start,l);r=r.end===void 0?u:Math.min(r.end,l),!e.extend&&u>r&&(l=r,r=u,u=l),l=ai(n,u);var o=ai(n,r);l&&o&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==o.node||e.focusOffset!==o.offset)&&(t=t.createRange(),t.setStart(l.node,l.offset),e.removeAllRanges(),u>r?(e.addRange(t),e.extend(o.node,o.offset)):(t.setEnd(o.node,o.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,Ot=null,mu=null,Nn=null,hu=!1;function ci(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;hu||Ot==null||Ot!==Rr(r)||(r=Ot,"selectionStart"in r&&io(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Nn&&$n(Nn,r)||(Nn=r,r=Ur(mu,"onSelect"),0Ut||(e.current=Su[Ut],Su[Ut]=null,Ut--)}function D(e,t){Ut++,Su[Ut]=e.current,e.current=t}var dt={},ue=mt(dt),de=mt(!1),_t=dt;function qt(e,t){var n=e.type.contextTypes;if(!n)return dt;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var l={},u;for(u in n)l[u]=t[u];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=l),l}function pe(e){return e=e.childContextTypes,e!=null}function Vr(){$(de),$(ue)}function yi(e,t,n){if(ue.current!==dt)throw Error(g(168));D(ue,t),D(de,n)}function la(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var l in r)if(!(l in t))throw Error(g(108,Vc(e)||"Unknown",l));return B({},n,r)}function Br(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||dt,_t=ue.current,D(ue,e),D(de,de.current),!0}function gi(e,t,n){var r=e.stateNode;if(!r)throw Error(g(169));n?(e=la(e,t,_t),r.__reactInternalMemoizedMergedChildContext=e,$(de),$(ue),D(ue,e)):$(de),D(de,n)}var Ve=null,sl=!1,$l=!1;function ua(e){Ve===null?Ve=[e]:Ve.push(e)}function ud(e){sl=!0,ua(e)}function ht(){if(!$l&&Ve!==null){$l=!0;var e=0,t=M;try{var n=Ve;for(M=1;e>=o,l-=o,Be=1<<32-Re(t)+l|n<P?(W=N,N=null):W=N.sibling;var L=p(d,N,c[P],v);if(L===null){N===null&&(N=W);break}e&&N&&L.alternate===null&&t(d,N),a=u(L,a,P),_===null?x=L:_.sibling=L,_=L,N=W}if(P===c.length)return n(d,N),U&>(d,P),x;if(N===null){for(;PP?(W=N,N=null):W=N.sibling;var Pe=p(d,N,L.value,v);if(Pe===null){N===null&&(N=W);break}e&&N&&Pe.alternate===null&&t(d,N),a=u(Pe,a,P),_===null?x=Pe:_.sibling=Pe,_=Pe,N=W}if(L.done)return n(d,N),U&>(d,P),x;if(N===null){for(;!L.done;P++,L=c.next())L=h(d,L.value,v),L!==null&&(a=u(L,a,P),_===null?x=L:_.sibling=L,_=L);return U&>(d,P),x}for(N=r(d,N);!L.done;P++,L=c.next())L=w(N,d,P,L.value,v),L!==null&&(e&&L.alternate!==null&&N.delete(L.key===null?P:L.key),a=u(L,a,P),_===null?x=L:_.sibling=L,_=L);return e&&N.forEach(function(sn){return t(d,sn)}),U&>(d,P),x}function F(d,a,c,v){if(typeof c=="object"&&c!==null&&c.type===Ft&&c.key===null&&(c=c.props.children),typeof c=="object"&&c!==null){switch(c.$$typeof){case nr:e:{for(var x=c.key,_=a;_!==null;){if(_.key===x){if(x=c.type,x===Ft){if(_.tag===7){n(d,_.sibling),a=l(_,c.props.children),a.return=d,d=a;break e}}else if(_.elementType===x||typeof x=="object"&&x!==null&&x.$$typeof===Je&&Si(x)===_.type){n(d,_.sibling),a=l(_,c.props),a.ref=hn(d,_,c),a.return=d,d=a;break e}n(d,_);break}else t(d,_);_=_.sibling}c.type===Ft?(a=Ct(c.props.children,d.mode,v,c.key),a.return=d,d=a):(v=Lr(c.type,c.key,c.props,null,d.mode,v),v.ref=hn(d,a,c),v.return=d,d=v)}return o(d);case Mt:e:{for(_=c.key;a!==null;){if(a.key===_)if(a.tag===4&&a.stateNode.containerInfo===c.containerInfo&&a.stateNode.implementation===c.implementation){n(d,a.sibling),a=l(a,c.children||[]),a.return=d,d=a;break e}else{n(d,a);break}else t(d,a);a=a.sibling}a=Kl(c,d.mode,v),a.return=d,d=a}return o(d);case Je:return _=c._init,F(d,a,_(c._payload),v)}if(wn(c))return k(d,a,c,v);if(cn(c))return S(d,a,c,v);pr(d,c)}return typeof c=="string"&&c!==""||typeof c=="number"?(c=""+c,a!==null&&a.tag===6?(n(d,a.sibling),a=l(a,c),a.return=d,d=a):(n(d,a),a=Ql(c,d.mode,v),a.return=d,d=a),o(d)):n(d,a)}return F}var en=aa(!0),ca=aa(!1),Qr=mt(null),Kr=null,Bt=null,fo=null;function po(){fo=Bt=Kr=null}function mo(e){var t=Qr.current;$(Qr),e._currentValue=t}function Cu(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function Gt(e,t){Kr=e,fo=Bt=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(fe=!0),e.firstContext=null)}function _e(e){var t=e._currentValue;if(fo!==e)if(e={context:e,memoizedValue:t,next:null},Bt===null){if(Kr===null)throw Error(g(308));Bt=e,Kr.dependencies={lanes:0,firstContext:e}}else Bt=Bt.next=e;return t}var St=null;function ho(e){St===null?St=[e]:St.push(e)}function fa(e,t,n,r){var l=t.interleaved;return l===null?(n.next=n,ho(t)):(n.next=l.next,l.next=n),t.interleaved=n,Ye(e,r)}function Ye(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var qe=!1;function vo(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function da(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function We(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function it(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,R&2){var l=r.pending;return l===null?t.next=t:(t.next=l.next,l.next=t),r.pending=t,Ye(e,n)}return l=r.interleaved,l===null?(t.next=t,ho(r)):(t.next=l.next,l.next=t),r.interleaved=t,Ye(e,n)}function _r(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,eo(e,n)}}function xi(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var l=null,u=null;if(n=n.firstBaseUpdate,n!==null){do{var o={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};u===null?l=u=o:u=u.next=o,n=n.next}while(n!==null);u===null?l=u=t:u=u.next=t}else l=u=t;n={baseState:r.baseState,firstBaseUpdate:l,lastBaseUpdate:u,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function Yr(e,t,n,r){var l=e.updateQueue;qe=!1;var u=l.firstBaseUpdate,o=l.lastBaseUpdate,i=l.shared.pending;if(i!==null){l.shared.pending=null;var s=i,f=s.next;s.next=null,o===null?u=f:o.next=f,o=s;var m=e.alternate;m!==null&&(m=m.updateQueue,i=m.lastBaseUpdate,i!==o&&(i===null?m.firstBaseUpdate=f:i.next=f,m.lastBaseUpdate=s))}if(u!==null){var h=l.baseState;o=0,m=f=s=null,i=u;do{var p=i.lane,w=i.eventTime;if((r&p)===p){m!==null&&(m=m.next={eventTime:w,lane:0,tag:i.tag,payload:i.payload,callback:i.callback,next:null});e:{var k=e,S=i;switch(p=t,w=n,S.tag){case 1:if(k=S.payload,typeof k=="function"){h=k.call(w,h,p);break e}h=k;break e;case 3:k.flags=k.flags&-65537|128;case 0:if(k=S.payload,p=typeof k=="function"?k.call(w,h,p):k,p==null)break e;h=B({},h,p);break e;case 2:qe=!0}}i.callback!==null&&i.lane!==0&&(e.flags|=64,p=l.effects,p===null?l.effects=[i]:p.push(i))}else w={eventTime:w,lane:p,tag:i.tag,payload:i.payload,callback:i.callback,next:null},m===null?(f=m=w,s=h):m=m.next=w,o|=p;if(i=i.next,i===null){if(i=l.shared.pending,i===null)break;p=i,i=p.next,p.next=null,l.lastBaseUpdate=p,l.shared.pending=null}}while(!0);if(m===null&&(s=h),l.baseState=s,l.firstBaseUpdate=f,l.lastBaseUpdate=m,t=l.shared.interleaved,t!==null){l=t;do o|=l.lane,l=l.next;while(l!==t)}else u===null&&(l.shared.lanes=0);jt|=o,e.lanes=o,e.memoizedState=h}}function Ei(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=Al.transition;Al.transition={};try{e(!1),t()}finally{M=n,Al.transition=r}}function za(){return Ne().memoizedState}function ad(e,t,n){var r=at(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Ta(e))La(t,n);else if(n=fa(e,t,n,r),n!==null){var l=ie();Me(n,e,r,l),Ra(n,t,r)}}function cd(e,t,n){var r=at(e),l={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Ta(e))La(t,l);else{var u=e.alternate;if(e.lanes===0&&(u===null||u.lanes===0)&&(u=t.lastRenderedReducer,u!==null))try{var o=t.lastRenderedState,i=u(o,n);if(l.hasEagerState=!0,l.eagerState=i,Fe(i,o)){var s=t.interleaved;s===null?(l.next=l,ho(t)):(l.next=s.next,s.next=l),t.interleaved=l;return}}catch{}finally{}n=fa(e,t,l,r),n!==null&&(l=ie(),Me(n,e,r,l),Ra(n,t,r))}}function Ta(e){var t=e.alternate;return e===V||t!==null&&t===V}function La(e,t){Pn=Gr=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Ra(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,eo(e,n)}}var Zr={readContext:_e,useCallback:ne,useContext:ne,useEffect:ne,useImperativeHandle:ne,useInsertionEffect:ne,useLayoutEffect:ne,useMemo:ne,useReducer:ne,useRef:ne,useState:ne,useDebugValue:ne,useDeferredValue:ne,useTransition:ne,useMutableSource:ne,useSyncExternalStore:ne,useId:ne,unstable_isNewReconciler:!1},fd={readContext:_e,useCallback:function(e,t){return Oe().memoizedState=[e,t===void 0?null:t],e},useContext:_e,useEffect:_i,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Pr(4194308,4,Ca.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Pr(4194308,4,e,t)},useInsertionEffect:function(e,t){return Pr(4,2,e,t)},useMemo:function(e,t){var n=Oe();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=Oe();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=ad.bind(null,V,e),[r.memoizedState,e]},useRef:function(e){var t=Oe();return e={current:e},t.memoizedState=e},useState:Ci,useDebugValue:Co,useDeferredValue:function(e){return Oe().memoizedState=e},useTransition:function(){var e=Ci(!1),t=e[0];return e=sd.bind(null,e[1]),Oe().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=V,l=Oe();if(U){if(n===void 0)throw Error(g(407));n=n()}else{if(n=t(),q===null)throw Error(g(349));Pt&30||va(r,t,n)}l.memoizedState=n;var u={value:n,getSnapshot:t};return l.queue=u,_i(ga.bind(null,r,u,e),[e]),r.flags|=2048,Kn(9,ya.bind(null,r,u,n,t),void 0,null),n},useId:function(){var e=Oe(),t=q.identifierPrefix;if(U){var n=He,r=Be;n=(r&~(1<<32-Re(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=Wn++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=o.createElement(n,{is:r.is}):(e=o.createElement(n),n==="select"&&(o=e,r.multiple?o.multiple=!0:r.size&&(o.size=r.size))):e=o.createElementNS(e,n),e[Ie]=t,e[Vn]=r,Ba(e,t,!1,!1),t.stateNode=e;e:{switch(o=ou(n,r),n){case"dialog":O("cancel",e),O("close",e),l=r;break;case"iframe":case"object":case"embed":O("load",e),l=r;break;case"video":case"audio":for(l=0;lrn&&(t.flags|=128,r=!0,vn(u,!1),t.lanes=4194304)}else{if(!r)if(e=Xr(o),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),vn(u,!0),u.tail===null&&u.tailMode==="hidden"&&!o.alternate&&!U)return re(t),null}else 2*K()-u.renderingStartTime>rn&&n!==1073741824&&(t.flags|=128,r=!0,vn(u,!1),t.lanes=4194304);u.isBackwards?(o.sibling=t.child,t.child=o):(n=u.last,n!==null?n.sibling=o:t.child=o,u.last=o)}return u.tail!==null?(t=u.tail,u.rendering=t,u.tail=t.sibling,u.renderingStartTime=K(),t.sibling=null,n=A.current,D(A,r?n&1|2:n&1),t):(re(t),null);case 22:case 23:return To(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?he&1073741824&&(re(t),t.subtreeFlags&6&&(t.flags|=8192)):re(t),null;case 24:return null;case 25:return null}throw Error(g(156,t.tag))}function wd(e,t){switch(ao(t),t.tag){case 1:return pe(t.type)&&Vr(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return tn(),$(de),$(ue),wo(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return go(t),null;case 13:if($(A),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(g(340));bt()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return $(A),null;case 4:return tn(),null;case 10:return mo(t.type._context),null;case 22:case 23:return To(),null;case 24:return null;default:return null}}var hr=!1,le=!1,kd=typeof WeakSet=="function"?WeakSet:Set,E=null;function Ht(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){H(e,t,r)}else n.current=null}function Mu(e,t,n){try{n()}catch(r){H(e,t,r)}}var Oi=!1;function Sd(e,t){if(vu=Ir,e=Gs(),io(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var l=r.anchorOffset,u=r.focusNode;r=r.focusOffset;try{n.nodeType,u.nodeType}catch{n=null;break e}var o=0,i=-1,s=-1,f=0,m=0,h=e,p=null;t:for(;;){for(var w;h!==n||l!==0&&h.nodeType!==3||(i=o+l),h!==u||r!==0&&h.nodeType!==3||(s=o+r),h.nodeType===3&&(o+=h.nodeValue.length),(w=h.firstChild)!==null;)p=h,h=w;for(;;){if(h===e)break t;if(p===n&&++f===l&&(i=o),p===u&&++m===r&&(s=o),(w=h.nextSibling)!==null)break;h=p,p=h.parentNode}h=w}n=i===-1||s===-1?null:{start:i,end:s}}else n=null}n=n||{start:0,end:0}}else n=null;for(yu={focusedElem:e,selectionRange:n},Ir=!1,E=t;E!==null;)if(t=E,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,E=e;else for(;E!==null;){t=E;try{var k=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(k!==null){var S=k.memoizedProps,F=k.memoizedState,d=t.stateNode,a=d.getSnapshotBeforeUpdate(t.elementType===t.type?S:ze(t.type,S),F);d.__reactInternalSnapshotBeforeUpdate=a}break;case 3:var c=t.stateNode.containerInfo;c.nodeType===1?c.textContent="":c.nodeType===9&&c.documentElement&&c.removeChild(c.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(g(163))}}catch(v){H(t,t.return,v)}if(e=t.sibling,e!==null){e.return=t.return,E=e;break}E=t.return}return k=Oi,Oi=!1,k}function jn(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var l=r=r.next;do{if((l.tag&e)===e){var u=l.destroy;l.destroy=void 0,u!==void 0&&Mu(t,n,u)}l=l.next}while(l!==r)}}function fl(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function Fu(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function Qa(e){var t=e.alternate;t!==null&&(e.alternate=null,Qa(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Ie],delete t[Vn],delete t[ku],delete t[rd],delete t[ld])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Ka(e){return e.tag===5||e.tag===3||e.tag===4}function Ii(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Ka(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Du(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Ar));else if(r!==4&&(e=e.child,e!==null))for(Du(e,t,n),e=e.sibling;e!==null;)Du(e,t,n),e=e.sibling}function Ou(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Ou(e,t,n),e=e.sibling;e!==null;)Ou(e,t,n),e=e.sibling}var b=null,Te=!1;function Ze(e,t,n){for(n=n.child;n!==null;)Ya(e,t,n),n=n.sibling}function Ya(e,t,n){if($e&&typeof $e.onCommitFiberUnmount=="function")try{$e.onCommitFiberUnmount(rl,n)}catch{}switch(n.tag){case 5:le||Ht(n,t);case 6:var r=b,l=Te;b=null,Ze(e,t,n),b=r,Te=l,b!==null&&(Te?(e=b,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):b.removeChild(n.stateNode));break;case 18:b!==null&&(Te?(e=b,n=n.stateNode,e.nodeType===8?Il(e.parentNode,n):e.nodeType===1&&Il(e,n),On(e)):Il(b,n.stateNode));break;case 4:r=b,l=Te,b=n.stateNode.containerInfo,Te=!0,Ze(e,t,n),b=r,Te=l;break;case 0:case 11:case 14:case 15:if(!le&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){l=r=r.next;do{var u=l,o=u.destroy;u=u.tag,o!==void 0&&(u&2||u&4)&&Mu(n,t,o),l=l.next}while(l!==r)}Ze(e,t,n);break;case 1:if(!le&&(Ht(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(i){H(n,t,i)}Ze(e,t,n);break;case 21:Ze(e,t,n);break;case 22:n.mode&1?(le=(r=le)||n.memoizedState!==null,Ze(e,t,n),le=r):Ze(e,t,n);break;default:Ze(e,t,n)}}function $i(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new kd),t.forEach(function(r){var l=Td.bind(null,e,r);n.has(r)||(n.add(r),r.then(l,l))})}}function je(e,t){var n=t.deletions;if(n!==null)for(var r=0;rl&&(l=o),r&=~u}if(r=l,r=K()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*Ed(r/1960))-r,10e?16:e,nt===null)var r=!1;else{if(e=nt,nt=null,br=0,R&6)throw Error(g(331));var l=R;for(R|=4,E=e.current;E!==null;){var u=E,o=u.child;if(E.flags&16){var i=u.deletions;if(i!==null){for(var s=0;sK()-jo?Et(e,0):Po|=n),me(e,t)}function tc(e,t){t===0&&(e.mode&1?(t=or,or<<=1,!(or&130023424)&&(or=4194304)):t=1);var n=ie();e=Ye(e,t),e!==null&&(Gn(e,t,n),me(e,n))}function zd(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),tc(e,n)}function Td(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,l=e.memoizedState;l!==null&&(n=l.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(g(314))}r!==null&&r.delete(t),tc(e,n)}var nc;nc=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||de.current)fe=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return fe=!1,yd(e,t,n);fe=!!(e.flags&131072)}else fe=!1,U&&t.flags&1048576&&oa(t,Wr,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;jr(e,t),e=t.pendingProps;var l=qt(t,ue.current);Gt(t,n),l=So(null,t,r,e,l,n);var u=xo();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,pe(r)?(u=!0,Br(t)):u=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,vo(t),l.updater=cl,t.stateNode=l,l._reactInternals=t,Nu(t,r,e,n),t=zu(null,t,r,!0,u,n)):(t.tag=0,U&&u&&so(t),oe(null,t,l,n),t=t.child),t;case 16:r=t.elementType;e:{switch(jr(e,t),e=t.pendingProps,l=r._init,r=l(r._payload),t.type=r,l=t.tag=Rd(r),e=ze(r,e),l){case 0:t=ju(null,t,r,e,n);break e;case 1:t=Mi(null,t,r,e,n);break e;case 11:t=Li(null,t,r,e,n);break e;case 14:t=Ri(null,t,r,ze(r.type,e),n);break e}throw Error(g(306,r,""))}return t;case 0:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),ju(e,t,r,l,n);case 1:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),Mi(e,t,r,l,n);case 3:e:{if(Ua(t),e===null)throw Error(g(387));r=t.pendingProps,u=t.memoizedState,l=u.element,da(e,t),Yr(t,r,null,n);var o=t.memoizedState;if(r=o.element,u.isDehydrated)if(u={element:r,isDehydrated:!1,cache:o.cache,pendingSuspenseBoundaries:o.pendingSuspenseBoundaries,transitions:o.transitions},t.updateQueue.baseState=u,t.memoizedState=u,t.flags&256){l=nn(Error(g(423)),t),t=Fi(e,t,r,n,l);break e}else if(r!==l){l=nn(Error(g(424)),t),t=Fi(e,t,r,n,l);break e}else for(ve=ot(t.stateNode.containerInfo.firstChild),ye=t,U=!0,Le=null,n=ca(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(bt(),r===l){t=Xe(e,t,n);break e}oe(e,t,r,n)}t=t.child}return t;case 5:return pa(t),e===null&&Eu(t),r=t.type,l=t.pendingProps,u=e!==null?e.memoizedProps:null,o=l.children,gu(r,l)?o=null:u!==null&&gu(r,u)&&(t.flags|=32),$a(e,t),oe(e,t,o,n),t.child;case 6:return e===null&&Eu(t),null;case 13:return Aa(e,t,n);case 4:return yo(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=en(t,null,r,n):oe(e,t,r,n),t.child;case 11:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),Li(e,t,r,l,n);case 7:return oe(e,t,t.pendingProps,n),t.child;case 8:return oe(e,t,t.pendingProps.children,n),t.child;case 12:return oe(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,l=t.pendingProps,u=t.memoizedProps,o=l.value,D(Qr,r._currentValue),r._currentValue=o,u!==null)if(Fe(u.value,o)){if(u.children===l.children&&!de.current){t=Xe(e,t,n);break e}}else for(u=t.child,u!==null&&(u.return=t);u!==null;){var i=u.dependencies;if(i!==null){o=u.child;for(var s=i.firstContext;s!==null;){if(s.context===r){if(u.tag===1){s=We(-1,n&-n),s.tag=2;var f=u.updateQueue;if(f!==null){f=f.shared;var m=f.pending;m===null?s.next=s:(s.next=m.next,m.next=s),f.pending=s}}u.lanes|=n,s=u.alternate,s!==null&&(s.lanes|=n),Cu(u.return,n,t),i.lanes|=n;break}s=s.next}}else if(u.tag===10)o=u.type===t.type?null:u.child;else if(u.tag===18){if(o=u.return,o===null)throw Error(g(341));o.lanes|=n,i=o.alternate,i!==null&&(i.lanes|=n),Cu(o,n,t),o=u.sibling}else o=u.child;if(o!==null)o.return=u;else for(o=u;o!==null;){if(o===t){o=null;break}if(u=o.sibling,u!==null){u.return=o.return,o=u;break}o=o.return}u=o}oe(e,t,l.children,n),t=t.child}return t;case 9:return l=t.type,r=t.pendingProps.children,Gt(t,n),l=_e(l),r=r(l),t.flags|=1,oe(e,t,r,n),t.child;case 14:return r=t.type,l=ze(r,t.pendingProps),l=ze(r.type,l),Ri(e,t,r,l,n);case 15:return Oa(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),jr(e,t),t.tag=1,pe(r)?(e=!0,Br(t)):e=!1,Gt(t,n),Ma(t,r,l),Nu(t,r,l,n),zu(null,t,r,!0,e,n);case 19:return Va(e,t,n);case 22:return Ia(e,t,n)}throw Error(g(156,t.tag))};function rc(e,t){return Ts(e,t)}function Ld(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Ee(e,t,n,r){return new Ld(e,t,n,r)}function Ro(e){return e=e.prototype,!(!e||!e.isReactComponent)}function Rd(e){if(typeof e=="function")return Ro(e)?1:0;if(e!=null){if(e=e.$$typeof,e===Zu)return 11;if(e===Ju)return 14}return 2}function ct(e,t){var n=e.alternate;return n===null?(n=Ee(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Lr(e,t,n,r,l,u){var o=2;if(r=e,typeof e=="function")Ro(e)&&(o=1);else if(typeof e=="string")o=5;else e:switch(e){case Ft:return Ct(n.children,l,u,t);case Gu:o=8,l|=8;break;case Zl:return e=Ee(12,n,t,l|2),e.elementType=Zl,e.lanes=u,e;case Jl:return e=Ee(13,n,t,l),e.elementType=Jl,e.lanes=u,e;case ql:return e=Ee(19,n,t,l),e.elementType=ql,e.lanes=u,e;case ps:return pl(n,l,u,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case fs:o=10;break e;case ds:o=9;break e;case Zu:o=11;break e;case Ju:o=14;break e;case Je:o=16,r=null;break e}throw Error(g(130,e==null?e:typeof e,""))}return t=Ee(o,n,t,l),t.elementType=e,t.type=r,t.lanes=u,t}function Ct(e,t,n,r){return e=Ee(7,e,r,t),e.lanes=n,e}function pl(e,t,n,r){return e=Ee(22,e,r,t),e.elementType=ps,e.lanes=n,e.stateNode={isHidden:!1},e}function Ql(e,t,n){return e=Ee(6,e,null,t),e.lanes=n,e}function Kl(e,t,n){return t=Ee(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Md(e,t,n,r,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Nl(0),this.expirationTimes=Nl(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Nl(0),this.identifierPrefix=r,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function Mo(e,t,n,r,l,u,o,i,s){return e=new Md(e,t,n,i,s),t===1?(t=1,u===!0&&(t|=8)):t=0,u=Ee(3,null,null,t),e.current=u,u.stateNode=e,u.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},vo(u),e}function Fd(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(ic)}catch(e){console.error(e)}}ic(),is.exports=we;var Ud=is.exports,sc,Ki=Ud;sc=Ki.createRoot,Ki.hydrateRoot;const Ad="modulepreload",Vd=function(e,t){return new URL(e,t).href},Yi={},Bd=function(t,n,r){let l=Promise.resolve();if(n&&n.length>0){const o=document.getElementsByTagName("link"),i=document.querySelector("meta[property=csp-nonce]"),s=(i==null?void 0:i.nonce)||(i==null?void 0:i.getAttribute("nonce"));l=Promise.allSettled(n.map(f=>{if(f=Vd(f,r),f in Yi)return;Yi[f]=!0;const m=f.endsWith(".css"),h=m?'[rel="stylesheet"]':"";if(!!r)for(let k=o.length-1;k>=0;k--){const S=o[k];if(S.href===f&&(!m||S.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${f}"]${h}`))return;const w=document.createElement("link");if(w.rel=m?"stylesheet":Ad,m||(w.as="script"),w.crossOrigin="",w.href=f,s&&w.setAttribute("nonce",s),document.head.appendChild(w),m)return new Promise((k,S)=>{w.addEventListener("load",k),w.addEventListener("error",()=>S(new Error(`Unable to preload CSS for ${f}`)))})}))}function u(o){const i=new Event("vite:preloadError",{cancelable:!0});if(i.payload=o,window.dispatchEvent(i),!i.defaultPrevented)throw o}return l.then(o=>{for(const i of o||[])i.status==="rejected"&&u(i.reason);return t().catch(u)})};function Hd(){return y.jsx("header",{className:"site-header",children:y.jsxs("div",{className:"wrapper",children:[y.jsx("a",{className:"site-title",href:"#/",children:"FPV Dataset"}),y.jsxs("nav",{className:"site-nav",children:[y.jsx("a",{href:"#/",children:"Videos"}),y.jsx("a",{href:"https://itamarweiss.com",rel:"noreferrer",children:"itamarweiss.com"})]})]})})}const Jd="https://d2fioemadmrru3.cloudfront.net/scenes".replace(/\/$/,""),Xi="https://d2fioemadmrru3.cloudfront.net/thumbnails".replace(/\/$/,""),gr={banner_start:{label:"Banner",color:"#4a9eff"},flight_start:{label:"Flight start",color:"#20c56b"},new_flight_start:{label:"New flight",color:"#00bcd4"},pause_start:{label:"Pause",color:"#f59e0b"},replay_start:{label:"Replay",color:"#9e77ed"},end:{label:"End",color:"#ef4444"},video_end:{label:"Video end",color:"#ef4444"},other:{label:"Other",color:"#8fa0ad"}},Wd=()=>y.jsx("svg",{viewBox:"0 0 24 24",width:"14",height:"14",fill:"currentColor","aria-hidden":!0,children:y.jsx("path",{d:"M8 5.14v13.72L19 12 8 5.14z"})}),Yl=()=>y.jsxs("svg",{viewBox:"0 0 24 24",width:"14",height:"14",fill:"none",stroke:"currentColor",strokeWidth:"1.8","aria-hidden":!0,children:[y.jsx("circle",{cx:"12",cy:"12",r:"9"}),y.jsx("ellipse",{cx:"12",cy:"12",rx:"4",ry:"9"}),y.jsx("path",{d:"M3.5 9h17M3.5 15h17"})]}),Qd=({dir:e})=>y.jsx("svg",{viewBox:"0 0 24 24",width:"13",height:"13",fill:"none",stroke:"currentColor",strokeWidth:"2","aria-hidden":!0,children:e==="desc"?y.jsx("path",{d:"M12 4v16m0 0l-6-6m6 6l6-6"}):y.jsx("path",{d:"M12 20V4m0 0l-6 6m6-6l6 6"})});function Kd({video:e}){var o;const[t,n]=I.useState(!1),r=!!((o=e.thumbWidths)!=null&&o.length)&&!t,l=r?`${Xi}/${e.slug}/${e.thumbWidths[e.thumbWidths.length-1]}.webp`:e.thumbnailUrl,u=r?e.thumbWidths.map(i=>`${Xi}/${e.slug}/${i}.webp ${i}w`).join(", "):void 0;return y.jsxs("a",{className:"thumb",href:Vu(e.videoFile),style:e.blur?{backgroundImage:`url(${e.blur})`}:void 0,children:[l?y.jsx("img",{src:l,srcSet:u,sizes:"(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 280px",alt:e.description,loading:"lazy",decoding:"async",onError:()=>n(!0)}):null,e.scenePath?y.jsx("span",{className:"badge-3d",children:"3D scene"}):null]})}function Yd({videos:e}){const[t,n]=I.useState(""),[r,l]=I.useState("desc"),[u,o]=I.useState("all"),i=I.useMemo(()=>{const s=t.trim().toLowerCase(),f=e.filter(m=>u==="with"&&!m.scenePath?!1:s?`${m.description} ${m.town} ${m.date} ${m.videoFile}`.toLowerCase().includes(s):!0);return f.sort((m,h)=>{const p=m.dateh.date?1:0;return r==="desc"?-p:p}),f},[e,t,r,u]);return y.jsxs("div",{children:[y.jsxs("div",{className:"gallery-toolbar",children:[y.jsx("input",{type:"search",value:t,onChange:s=>n(s.target.value),placeholder:"Search by description, town, date…","aria-label":"Search videos"}),y.jsxs("button",{type:"button",className:"toolbar-btn",onClick:()=>l(s=>s==="desc"?"asc":"desc"),"aria-label":`Sort by date, ${r==="desc"?"newest":"oldest"} first`,title:r==="desc"?"Newest first":"Oldest first",children:["Date ",y.jsx(Qd,{dir:r})]}),y.jsxs("button",{type:"button",className:`toolbar-btn${u==="with"?" active":""}`,onClick:()=>o(s=>s==="with"?"all":"with"),"aria-pressed":u==="with",title:"Only videos with a reconstructed 3D scene",children:[y.jsx(Yl,{})," 3D scenes"]}),y.jsx("span",{className:"gallery-count",children:i.length===e.length?`${e.length} videos`:`${i.length} of ${e.length}`})]}),y.jsx("div",{className:"video-grid",children:i.map(s=>y.jsxs("div",{className:"video-card",children:[y.jsx(Kd,{video:s}),y.jsx("a",{className:"title",href:Vu(s.videoFile),children:s.description||s.videoFile}),y.jsxs("span",{className:"meta",children:[s.date,s.town?` · ${s.town}`:""]}),y.jsxs("div",{className:"card-actions",children:[y.jsxs("a",{className:"card-btn",href:Vu(s.videoFile),children:[y.jsx(Wd,{})," Video"]}),s.scenePath?y.jsxs("a",{className:"card-btn primary",href:ac(s.videoFile),children:[y.jsx(Yl,{})," 3D scene"]}):y.jsxs("span",{className:"card-btn disabled",title:"No reconstructed scene yet",children:[y.jsx(Yl,{})," No scene"]})]})]},s.videoFile))}),i.length===0?y.jsx("p",{className:"not-found",children:"No videos match your filters."}):null]})}const wr=30;function Xl(e){const t=Math.floor(e/60),n=(e%60).toFixed(1).padStart(4,"0");return`${t}:${n}`}function Xd({video:e}){const t=I.useRef(null),[n,r]=I.useState(0),[l,u]=I.useState(0),[o,i]=I.useState(!1),[s,f]=I.useState(!1);I.useEffect(()=>{r(0),u(0),i(!1)},[e.videoFile]);const m=I.useMemo(()=>(e.segments??[]).slice().sort((a,c)=>a.time-c.time),[e.segments]),h=I.useMemo(()=>{const a=new Set(m.map(c=>c.type));return Object.entries(gr).filter(([c])=>a.has(c))},[m]),p=(a,c=!1)=>{const v=t.current;v&&(v.currentTime=Math.max(0,Math.min(a,v.duration||a)),c&&v.play().catch(()=>{}))},w=a=>{const c=t.current;c&&(c.pause(),p(c.currentTime+a))},k=()=>{const a=t.current;a&&(a.paused?a.play().catch(()=>{}):a.pause())},S=()=>{const a=t.current;a&&(a.muted=!a.muted,f(a.muted))},F=()=>{const a=t.current;a&&(document.fullscreenElement?document.exitFullscreen():a.requestFullscreen().catch(()=>{}))};I.useEffect(()=>{const a=c=>{var x,_,N;const v=((x=document.activeElement)==null?void 0:x.tagName)??"";if(!["INPUT","SELECT","TEXTAREA"].includes(v))switch(c.key){case" ":c.preventDefault(),k();break;case"ArrowLeft":c.preventDefault(),p((((_=t.current)==null?void 0:_.currentTime)??0)-5);break;case"ArrowRight":c.preventDefault(),p((((N=t.current)==null?void 0:N.currentTime)??0)+5);break;case",":w(-1/wr);break;case".":w(1/wr);break;case"m":S();break;case"f":F();break;case"Home":c.preventDefault(),p(0);break;case"End":c.preventDefault(),p(n);break}};return window.addEventListener("keydown",a),()=>window.removeEventListener("keydown",a)},[n]);const d=a=>{if(!n)return;const c=a.currentTarget.getBoundingClientRect();p((a.clientX-c.left)/c.width*n,!0)};return y.jsxs("div",{className:"video-view",children:[y.jsx("a",{className:"back-link",href:"#/",children:"← All videos"}),y.jsx("video",{ref:t,src:e.videoUrl,playsInline:!0,preload:"metadata",onClick:k,onLoadedMetadata:a=>r(a.currentTarget.duration||0),onTimeUpdate:a=>u(a.currentTarget.currentTime),onPlay:()=>i(!0),onPause:()=>i(!1)}),y.jsxs("div",{className:"transport",children:[y.jsxs("div",{className:"t-row t-primary",children:[y.jsx("button",{type:"button",className:"play-btn",onClick:k,"aria-label":o?"Pause":"Play",title:"Play/pause (space)",children:o?"❚❚":"▶"}),y.jsx("input",{type:"range",className:"scrubber",min:0,max:n||1,step:.01,value:Math.min(l,n||1),onChange:a=>p(Number(a.target.value)),"aria-label":"Seek"}),y.jsxs("span",{className:"time-display",children:[Xl(l)," / ",Xl(n)]})]}),y.jsxs("div",{className:"t-row t-secondary",children:[y.jsx("button",{type:"button",onClick:()=>w(-10),title:"Back 10s",children:"-10s"}),y.jsx("button",{type:"button",onClick:()=>w(-1/wr),title:"Previous frame (,)",children:"‹f"}),y.jsx("button",{type:"button",onClick:()=>w(1/wr),title:"Next frame (.)",children:"f›"}),y.jsx("button",{type:"button",onClick:()=>w(10),title:"Forward 10s",children:"+10s"}),y.jsx("button",{type:"button",onClick:S,title:"Mute (m)",children:s?"🔇":"🔊"}),y.jsx("button",{type:"button",onClick:F,title:"Fullscreen (f)",children:"⛶"})]})]}),y.jsxs("div",{className:"video-headline",children:[y.jsx("h1",{children:e.description||e.videoFile}),y.jsxs("p",{className:"view-meta",children:[e.date,e.town?` · ${e.town}`:""]}),y.jsxs("div",{className:"view-actions",children:[e.scenePath?y.jsx("a",{href:ac(e.videoFile),children:"View 3D scene →"}):null,y.jsx("a",{className:"icon-link",href:e.videoUrl,rel:"noreferrer",title:"Download video","aria-label":"Download video",children:y.jsxs("svg",{viewBox:"0 0 24 24",width:"16",height:"16",fill:"none",stroke:"currentColor",strokeWidth:"2","aria-hidden":!0,children:[y.jsx("path",{d:"M12 4v11m0 0l-5-5m5 5l5-5"}),y.jsx("path",{d:"M4 19h16"})]})})]})]}),m.length?y.jsxs("section",{children:[y.jsx("h2",{style:{fontSize:17},children:"Flight annotations"}),n>0?y.jsxs(y.Fragment,{children:[y.jsxs("div",{className:"timeline",onClick:d,title:"Click to seek",children:[m.map((a,c)=>{var v;return y.jsx("span",{className:"marker",style:{left:`${a.time/n*100}%`,background:((v=gr[a.type])==null?void 0:v.color)??"#8fa0ad"}},c)}),y.jsx("span",{className:"playhead",style:{left:`${l/n*100}%`}})]}),y.jsx("div",{className:"legend",children:h.map(([a,c])=>y.jsx("span",{className:"chip",style:{"--chip-color":c.color},children:c.label},a))})]}):null,y.jsxs("table",{className:"segment-table",children:[y.jsx("thead",{children:y.jsxs("tr",{children:[y.jsx("th",{children:"Time"}),y.jsx("th",{children:"Type"}),y.jsx("th",{children:"Note"})]})}),y.jsx("tbody",{children:m.map((a,c)=>{var v,x;return y.jsxs("tr",{children:[y.jsx("td",{children:y.jsx("a",{className:"time-link",href:"#",onClick:_=>{_.preventDefault(),p(a.time,!0)},children:Xl(a.time)})}),y.jsx("td",{children:y.jsx("span",{className:"segment-type",style:{"--chip-color":((v=gr[a.type])==null?void 0:v.color)??"#8fa0ad"},children:((x=gr[a.type])==null?void 0:x.label)??a.type})}),y.jsx("td",{style:{color:"var(--grey)"},children:a.comment??""})]},c)})})]}),e.annotationAuto?y.jsx("p",{className:"annotation-note",children:"Annotations were generated automatically."}):null]}):y.jsx("p",{className:"annotation-note",children:"No annotations for this video yet."})]})}const Gd=I.lazy(()=>Bd(()=>import("./SceneView-B3r-Nscl.js"),[],import.meta.url).then(e=>({default:e.SceneView})));function Gi(){const e=window.location.hash.replace(/^#\/?/,""),[t,...n]=e.split("/"),r=decodeURIComponent(n.join("/"));return t==="video"&&r?{view:"video",videoFile:r}:t==="scene"&&r?{view:"scene",videoFile:r}:{view:"gallery"}}function Vu(e){return`#/video/${encodeURIComponent(e)}`}function ac(e){return`#/scene/${encodeURIComponent(e)}`}function Zd(){const[e,t]=I.useState(Gi),[n,r]=I.useState(null),[l,u]=I.useState(null);I.useEffect(()=>{const s=()=>{t(Gi()),window.scrollTo(0,0)};return window.addEventListener("hashchange",s),()=>window.removeEventListener("hashchange",s)},[]),I.useEffect(()=>{fetch("./data/videos.json").then(s=>{if(!s.ok)throw new Error(`HTTP ${s.status}`);return s.json()}).then(r).catch(s=>u(String(s)))},[]);const o=I.useMemo(()=>{const s=new Map;for(const f of(n==null?void 0:n.videos)??[])s.set(f.videoFile,f);return s},[n]);let i;if(l)i=y.jsxs("p",{className:"not-found",children:["Failed to load the dataset (",l,")."]});else if(!n)i=y.jsx("p",{className:"not-found",children:"Loading…"});else if(e.view==="video"||e.view==="scene"){const s=o.get(e.videoFile);s?e.view==="video"?i=y.jsx(Xd,{video:s}):i=y.jsx(I.Suspense,{fallback:y.jsx("p",{className:"not-found",children:"Loading 3D viewer…"}),children:y.jsx(Gd,{video:s})}):i=y.jsx("p",{className:"not-found",children:"Video not found."})}else i=y.jsx(Yd,{videos:n.videos});return y.jsxs(y.Fragment,{children:[y.jsx(Hd,{}),y.jsx("div",{className:"page-content",children:y.jsx("div",{className:"wrapper",children:i})})]})}sc(document.getElementById("root")).render(y.jsx(Pc.StrictMode,{children:y.jsx(Zd,{})}));export{Jd as S,y as j,I as r,Vu as v}; +`+u.stack}return{value:e,source:t,stack:l,digest:null}}function Hl(e,t,n){return{value:e,source:null,stack:n??null,digest:t??null}}function Pu(e,t){try{console.error(t.value)}catch(n){setTimeout(function(){throw n})}}var md=typeof WeakMap=="function"?WeakMap:Map;function Fa(e,t,n){n=We(-1,n),n.tag=3,n.payload={element:null};var r=t.value;return n.callback=function(){qr||(qr=!0,Iu=r),Pu(e,t)},n}function Da(e,t,n){n=We(-1,n),n.tag=3;var r=e.type.getDerivedStateFromError;if(typeof r=="function"){var l=t.value;n.payload=function(){return r(l)},n.callback=function(){Pu(e,t)}}var u=e.stateNode;return u!==null&&typeof u.componentDidCatch=="function"&&(n.callback=function(){Pu(e,t),typeof r!="function"&&(st===null?st=new Set([this]):st.add(this));var o=t.stack;this.componentDidCatch(t.value,{componentStack:o!==null?o:""})}),n}function ji(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new md;var l=new Set;r.set(t,l)}else l=r.get(t),l===void 0&&(l=new Set,r.set(t,l));l.has(n)||(l.add(n),e=jd.bind(null,e,t,n),t.then(e,e))}function zi(e){do{var t;if((t=e.tag===13)&&(t=e.memoizedState,t=t!==null?t.dehydrated!==null:!0),t)return e;e=e.return}while(e!==null);return null}function Ti(e,t,n,r,l){return e.mode&1?(e.flags|=65536,e.lanes=l,e):(e===t?e.flags|=65536:(e.flags|=128,n.flags|=131072,n.flags&=-52805,n.tag===1&&(n.alternate===null?n.tag=17:(t=We(-1,1),t.tag=2,it(n,t,1))),n.lanes|=1),e)}var hd=Ge.ReactCurrentOwner,fe=!1;function oe(e,t,n,r){t.child=e===null?ca(t,null,n,r):en(t,e.child,n,r)}function Li(e,t,n,r,l){n=n.render;var u=t.ref;return Gt(t,l),r=So(e,t,n,r,u,l),n=xo(),e!==null&&!fe?(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~l,Xe(e,t,l)):(U&&n&&so(t),t.flags|=1,oe(e,t,r,l),t.child)}function Ri(e,t,n,r,l){if(e===null){var u=n.type;return typeof u=="function"&&!Ro(u)&&u.defaultProps===void 0&&n.compare===null&&n.defaultProps===void 0?(t.tag=15,t.type=u,Oa(e,t,u,r,l)):(e=Lr(n.type,null,r,t,t.mode,l),e.ref=t.ref,e.return=t,t.child=e)}if(u=e.child,!(e.lanes&l)){var o=u.memoizedProps;if(n=n.compare,n=n!==null?n:$n,n(o,r)&&e.ref===t.ref)return Xe(e,t,l)}return t.flags|=1,e=ct(u,r),e.ref=t.ref,e.return=t,t.child=e}function Oa(e,t,n,r,l){if(e!==null){var u=e.memoizedProps;if($n(u,r)&&e.ref===t.ref)if(fe=!1,t.pendingProps=r=u,(e.lanes&l)!==0)e.flags&131072&&(fe=!0);else return t.lanes=e.lanes,Xe(e,t,l)}return ju(e,t,n,r,l)}function Ia(e,t,n){var r=t.pendingProps,l=r.children,u=e!==null?e.memoizedState:null;if(r.mode==="hidden")if(!(t.mode&1))t.memoizedState={baseLanes:0,cachePool:null,transitions:null},D(Wt,he),he|=n;else{if(!(n&1073741824))return e=u!==null?u.baseLanes|n:n,t.lanes=t.childLanes=1073741824,t.memoizedState={baseLanes:e,cachePool:null,transitions:null},t.updateQueue=null,D(Wt,he),he|=e,null;t.memoizedState={baseLanes:0,cachePool:null,transitions:null},r=u!==null?u.baseLanes:n,D(Wt,he),he|=r}else u!==null?(r=u.baseLanes|n,t.memoizedState=null):r=n,D(Wt,he),he|=r;return oe(e,t,l,n),t.child}function $a(e,t){var n=t.ref;(e===null&&n!==null||e!==null&&e.ref!==n)&&(t.flags|=512,t.flags|=2097152)}function ju(e,t,n,r,l){var u=pe(n)?_t:ue.current;return u=qt(t,u),Gt(t,l),n=So(e,t,n,r,u,l),r=xo(),e!==null&&!fe?(t.updateQueue=e.updateQueue,t.flags&=-2053,e.lanes&=~l,Xe(e,t,l)):(U&&r&&so(t),t.flags|=1,oe(e,t,n,l),t.child)}function Mi(e,t,n,r,l){if(pe(n)){var u=!0;Br(t)}else u=!1;if(Gt(t,l),t.stateNode===null)jr(e,t),Ma(t,n,r),Nu(t,n,r,l),r=!0;else if(e===null){var o=t.stateNode,i=t.memoizedProps;o.props=i;var s=o.context,f=n.contextType;typeof f=="object"&&f!==null?f=_e(f):(f=pe(n)?_t:ue.current,f=qt(t,f));var m=n.getDerivedStateFromProps,h=typeof m=="function"||typeof o.getSnapshotBeforeUpdate=="function";h||typeof o.UNSAFE_componentWillReceiveProps!="function"&&typeof o.componentWillReceiveProps!="function"||(i!==r||s!==f)&&Pi(t,o,r,f),qe=!1;var p=t.memoizedState;o.state=p,Yr(t,r,o,l),s=t.memoizedState,i!==r||p!==s||de.current||qe?(typeof m=="function"&&(_u(t,n,m,r),s=t.memoizedState),(i=qe||Ni(t,n,i,r,p,s,f))?(h||typeof o.UNSAFE_componentWillMount!="function"&&typeof o.componentWillMount!="function"||(typeof o.componentWillMount=="function"&&o.componentWillMount(),typeof o.UNSAFE_componentWillMount=="function"&&o.UNSAFE_componentWillMount()),typeof o.componentDidMount=="function"&&(t.flags|=4194308)):(typeof o.componentDidMount=="function"&&(t.flags|=4194308),t.memoizedProps=r,t.memoizedState=s),o.props=r,o.state=s,o.context=f,r=i):(typeof o.componentDidMount=="function"&&(t.flags|=4194308),r=!1)}else{o=t.stateNode,da(e,t),i=t.memoizedProps,f=t.type===t.elementType?i:ze(t.type,i),o.props=f,h=t.pendingProps,p=o.context,s=n.contextType,typeof s=="object"&&s!==null?s=_e(s):(s=pe(n)?_t:ue.current,s=qt(t,s));var w=n.getDerivedStateFromProps;(m=typeof w=="function"||typeof o.getSnapshotBeforeUpdate=="function")||typeof o.UNSAFE_componentWillReceiveProps!="function"&&typeof o.componentWillReceiveProps!="function"||(i!==h||p!==s)&&Pi(t,o,r,s),qe=!1,p=t.memoizedState,o.state=p,Yr(t,r,o,l);var k=t.memoizedState;i!==h||p!==k||de.current||qe?(typeof w=="function"&&(_u(t,n,w,r),k=t.memoizedState),(f=qe||Ni(t,n,f,r,p,k,s)||!1)?(m||typeof o.UNSAFE_componentWillUpdate!="function"&&typeof o.componentWillUpdate!="function"||(typeof o.componentWillUpdate=="function"&&o.componentWillUpdate(r,k,s),typeof o.UNSAFE_componentWillUpdate=="function"&&o.UNSAFE_componentWillUpdate(r,k,s)),typeof o.componentDidUpdate=="function"&&(t.flags|=4),typeof o.getSnapshotBeforeUpdate=="function"&&(t.flags|=1024)):(typeof o.componentDidUpdate!="function"||i===e.memoizedProps&&p===e.memoizedState||(t.flags|=4),typeof o.getSnapshotBeforeUpdate!="function"||i===e.memoizedProps&&p===e.memoizedState||(t.flags|=1024),t.memoizedProps=r,t.memoizedState=k),o.props=r,o.state=k,o.context=s,r=f):(typeof o.componentDidUpdate!="function"||i===e.memoizedProps&&p===e.memoizedState||(t.flags|=4),typeof o.getSnapshotBeforeUpdate!="function"||i===e.memoizedProps&&p===e.memoizedState||(t.flags|=1024),r=!1)}return zu(e,t,n,r,u,l)}function zu(e,t,n,r,l,u){$a(e,t);var o=(t.flags&128)!==0;if(!r&&!o)return l&&gi(t,n,!1),Xe(e,t,u);r=t.stateNode,hd.current=t;var i=o&&typeof n.getDerivedStateFromError!="function"?null:r.render();return t.flags|=1,e!==null&&o?(t.child=en(t,e.child,null,u),t.child=en(t,null,i,u)):oe(e,t,i,u),t.memoizedState=r.state,l&&gi(t,n,!0),t.child}function Ua(e){var t=e.stateNode;t.pendingContext?yi(e,t.pendingContext,t.pendingContext!==t.context):t.context&&yi(e,t.context,!1),yo(e,t.containerInfo)}function Fi(e,t,n,r,l){return bt(),co(l),t.flags|=256,oe(e,t,n,r),t.child}var Tu={dehydrated:null,treeContext:null,retryLane:0};function Lu(e){return{baseLanes:e,cachePool:null,transitions:null}}function Aa(e,t,n){var r=t.pendingProps,l=A.current,u=!1,o=(t.flags&128)!==0,i;if((i=o)||(i=e!==null&&e.memoizedState===null?!1:(l&2)!==0),i?(u=!0,t.flags&=-129):(e===null||e.memoizedState!==null)&&(l|=1),D(A,l&1),e===null)return Eu(t),e=t.memoizedState,e!==null&&(e=e.dehydrated,e!==null)?(t.mode&1?e.data==="$!"?t.lanes=8:t.lanes=1073741824:t.lanes=1,null):(o=r.children,e=r.fallback,u?(r=t.mode,u=t.child,o={mode:"hidden",children:o},!(r&1)&&u!==null?(u.childLanes=0,u.pendingProps=o):u=pl(o,r,0,null),e=Ct(e,r,n,null),u.return=t,e.return=t,u.sibling=e,t.child=u,t.child.memoizedState=Lu(n),t.memoizedState=Tu,e):_o(t,o));if(l=e.memoizedState,l!==null&&(i=l.dehydrated,i!==null))return vd(e,t,o,r,i,l,n);if(u){u=r.fallback,o=t.mode,l=e.child,i=l.sibling;var s={mode:"hidden",children:r.children};return!(o&1)&&t.child!==l?(r=t.child,r.childLanes=0,r.pendingProps=s,t.deletions=null):(r=ct(l,s),r.subtreeFlags=l.subtreeFlags&14680064),i!==null?u=ct(i,u):(u=Ct(u,o,n,null),u.flags|=2),u.return=t,r.return=t,r.sibling=u,t.child=r,r=u,u=t.child,o=e.child.memoizedState,o=o===null?Lu(n):{baseLanes:o.baseLanes|n,cachePool:null,transitions:o.transitions},u.memoizedState=o,u.childLanes=e.childLanes&~n,t.memoizedState=Tu,r}return u=e.child,e=u.sibling,r=ct(u,{mode:"visible",children:r.children}),!(t.mode&1)&&(r.lanes=n),r.return=t,r.sibling=null,e!==null&&(n=t.deletions,n===null?(t.deletions=[e],t.flags|=16):n.push(e)),t.child=r,t.memoizedState=null,r}function _o(e,t){return t=pl({mode:"visible",children:t},e.mode,0,null),t.return=e,e.child=t}function mr(e,t,n,r){return r!==null&&co(r),en(t,e.child,null,n),e=_o(t,t.pendingProps.children),e.flags|=2,t.memoizedState=null,e}function vd(e,t,n,r,l,u,o){if(n)return t.flags&256?(t.flags&=-257,r=Hl(Error(g(422))),mr(e,t,o,r)):t.memoizedState!==null?(t.child=e.child,t.flags|=128,null):(u=r.fallback,l=t.mode,r=pl({mode:"visible",children:r.children},l,0,null),u=Ct(u,l,o,null),u.flags|=2,r.return=t,u.return=t,r.sibling=u,t.child=r,t.mode&1&&en(t,e.child,null,o),t.child.memoizedState=Lu(o),t.memoizedState=Tu,u);if(!(t.mode&1))return mr(e,t,o,null);if(l.data==="$!"){if(r=l.nextSibling&&l.nextSibling.dataset,r)var i=r.dgst;return r=i,u=Error(g(419)),r=Hl(u,r,void 0),mr(e,t,o,r)}if(i=(o&e.childLanes)!==0,fe||i){if(r=q,r!==null){switch(o&-o){case 4:l=2;break;case 16:l=8;break;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:l=32;break;case 536870912:l=268435456;break;default:l=0}l=l&(r.suspendedLanes|o)?0:l,l!==0&&l!==u.retryLane&&(u.retryLane=l,Ye(e,l),Me(r,e,l,-1))}return Lo(),r=Hl(Error(g(421))),mr(e,t,o,r)}return l.data==="$?"?(t.flags|=128,t.child=e.child,t=zd.bind(null,e),l._reactRetry=t,null):(e=u.treeContext,ve=ot(l.nextSibling),ye=t,U=!0,Le=null,e!==null&&(Se[xe++]=Be,Se[xe++]=He,Se[xe++]=Nt,Be=e.id,He=e.overflow,Nt=t),t=_o(t,r.children),t.flags|=4096,t)}function Di(e,t,n){e.lanes|=t;var r=e.alternate;r!==null&&(r.lanes|=t),Cu(e.return,t,n)}function Wl(e,t,n,r,l){var u=e.memoizedState;u===null?e.memoizedState={isBackwards:t,rendering:null,renderingStartTime:0,last:r,tail:n,tailMode:l}:(u.isBackwards=t,u.rendering=null,u.renderingStartTime=0,u.last=r,u.tail=n,u.tailMode=l)}function Va(e,t,n){var r=t.pendingProps,l=r.revealOrder,u=r.tail;if(oe(e,t,r.children,n),r=A.current,r&2)r=r&1|2,t.flags|=128;else{if(e!==null&&e.flags&128)e:for(e=t.child;e!==null;){if(e.tag===13)e.memoizedState!==null&&Di(e,n,t);else if(e.tag===19)Di(e,n,t);else if(e.child!==null){e.child.return=e,e=e.child;continue}if(e===t)break e;for(;e.sibling===null;){if(e.return===null||e.return===t)break e;e=e.return}e.sibling.return=e.return,e=e.sibling}r&=1}if(D(A,r),!(t.mode&1))t.memoizedState=null;else switch(l){case"forwards":for(n=t.child,l=null;n!==null;)e=n.alternate,e!==null&&Xr(e)===null&&(l=n),n=n.sibling;n=l,n===null?(l=t.child,t.child=null):(l=n.sibling,n.sibling=null),Wl(t,!1,l,n,u);break;case"backwards":for(n=null,l=t.child,t.child=null;l!==null;){if(e=l.alternate,e!==null&&Xr(e)===null){t.child=l;break}e=l.sibling,l.sibling=n,n=l,l=e}Wl(t,!0,n,null,u);break;case"together":Wl(t,!1,null,null,void 0);break;default:t.memoizedState=null}return t.child}function jr(e,t){!(t.mode&1)&&e!==null&&(e.alternate=null,t.alternate=null,t.flags|=2)}function Xe(e,t,n){if(e!==null&&(t.dependencies=e.dependencies),jt|=t.lanes,!(n&t.childLanes))return null;if(e!==null&&t.child!==e.child)throw Error(g(153));if(t.child!==null){for(e=t.child,n=ct(e,e.pendingProps),t.child=n,n.return=t;e.sibling!==null;)e=e.sibling,n=n.sibling=ct(e,e.pendingProps),n.return=t;n.sibling=null}return t.child}function yd(e,t,n){switch(t.tag){case 3:Ua(t),bt();break;case 5:pa(t);break;case 1:pe(t.type)&&Br(t);break;case 4:yo(t,t.stateNode.containerInfo);break;case 10:var r=t.type._context,l=t.memoizedProps.value;D(Qr,r._currentValue),r._currentValue=l;break;case 13:if(r=t.memoizedState,r!==null)return r.dehydrated!==null?(D(A,A.current&1),t.flags|=128,null):n&t.child.childLanes?Aa(e,t,n):(D(A,A.current&1),e=Xe(e,t,n),e!==null?e.sibling:null);D(A,A.current&1);break;case 19:if(r=(n&t.childLanes)!==0,e.flags&128){if(r)return Va(e,t,n);t.flags|=128}if(l=t.memoizedState,l!==null&&(l.rendering=null,l.tail=null,l.lastEffect=null),D(A,A.current),r)break;return null;case 22:case 23:return t.lanes=0,Ia(e,t,n)}return Xe(e,t,n)}var Ba,Ru,Ha,Wa;Ba=function(e,t){for(var n=t.child;n!==null;){if(n.tag===5||n.tag===6)e.appendChild(n.stateNode);else if(n.tag!==4&&n.child!==null){n.child.return=n,n=n.child;continue}if(n===t)break;for(;n.sibling===null;){if(n.return===null||n.return===t)return;n=n.return}n.sibling.return=n.return,n=n.sibling}};Ru=function(){};Ha=function(e,t,n,r){var l=e.memoizedProps;if(l!==r){e=t.stateNode,xt(Ue.current);var u=null;switch(n){case"input":l=eu(e,l),r=eu(e,r),u=[];break;case"select":l=B({},l,{value:void 0}),r=B({},r,{value:void 0}),u=[];break;case"textarea":l=ru(e,l),r=ru(e,r),u=[];break;default:typeof l.onClick!="function"&&typeof r.onClick=="function"&&(e.onclick=Ar)}uu(n,r);var o;n=null;for(f in l)if(!r.hasOwnProperty(f)&&l.hasOwnProperty(f)&&l[f]!=null)if(f==="style"){var i=l[f];for(o in i)i.hasOwnProperty(o)&&(n||(n={}),n[o]="")}else f!=="dangerouslySetInnerHTML"&&f!=="children"&&f!=="suppressContentEditableWarning"&&f!=="suppressHydrationWarning"&&f!=="autoFocus"&&(Ln.hasOwnProperty(f)?u||(u=[]):(u=u||[]).push(f,null));for(f in r){var s=r[f];if(i=l!=null?l[f]:void 0,r.hasOwnProperty(f)&&s!==i&&(s!=null||i!=null))if(f==="style")if(i){for(o in i)!i.hasOwnProperty(o)||s&&s.hasOwnProperty(o)||(n||(n={}),n[o]="");for(o in s)s.hasOwnProperty(o)&&i[o]!==s[o]&&(n||(n={}),n[o]=s[o])}else n||(u||(u=[]),u.push(f,n)),n=s;else f==="dangerouslySetInnerHTML"?(s=s?s.__html:void 0,i=i?i.__html:void 0,s!=null&&i!==s&&(u=u||[]).push(f,s)):f==="children"?typeof s!="string"&&typeof s!="number"||(u=u||[]).push(f,""+s):f!=="suppressContentEditableWarning"&&f!=="suppressHydrationWarning"&&(Ln.hasOwnProperty(f)?(s!=null&&f==="onScroll"&&O("scroll",e),u||i===s||(u=[])):(u=u||[]).push(f,s))}n&&(u=u||[]).push("style",n);var f=u;(t.updateQueue=f)&&(t.flags|=4)}};Wa=function(e,t,n,r){n!==r&&(t.flags|=4)};function vn(e,t){if(!U)switch(e.tailMode){case"hidden":t=e.tail;for(var n=null;t!==null;)t.alternate!==null&&(n=t),t=t.sibling;n===null?e.tail=null:n.sibling=null;break;case"collapsed":n=e.tail;for(var r=null;n!==null;)n.alternate!==null&&(r=n),n=n.sibling;r===null?t||e.tail===null?e.tail=null:e.tail.sibling=null:r.sibling=null}}function re(e){var t=e.alternate!==null&&e.alternate.child===e.child,n=0,r=0;if(t)for(var l=e.child;l!==null;)n|=l.lanes|l.childLanes,r|=l.subtreeFlags&14680064,r|=l.flags&14680064,l.return=e,l=l.sibling;else for(l=e.child;l!==null;)n|=l.lanes|l.childLanes,r|=l.subtreeFlags,r|=l.flags,l.return=e,l=l.sibling;return e.subtreeFlags|=r,e.childLanes=n,t}function gd(e,t,n){var r=t.pendingProps;switch(ao(t),t.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return re(t),null;case 1:return pe(t.type)&&Vr(),re(t),null;case 3:return r=t.stateNode,tn(),$(de),$(ue),wo(),r.pendingContext&&(r.context=r.pendingContext,r.pendingContext=null),(e===null||e.child===null)&&(dr(t)?t.flags|=4:e===null||e.memoizedState.isDehydrated&&!(t.flags&256)||(t.flags|=1024,Le!==null&&(Au(Le),Le=null))),Ru(e,t),re(t),null;case 5:go(t);var l=xt(Hn.current);if(n=t.type,e!==null&&t.stateNode!=null)Ha(e,t,n,r,l),e.ref!==t.ref&&(t.flags|=512,t.flags|=2097152);else{if(!r){if(t.stateNode===null)throw Error(g(166));return re(t),null}if(e=xt(Ue.current),dr(t)){r=t.stateNode,n=t.type;var u=t.memoizedProps;switch(r[Ie]=t,r[Vn]=u,e=(t.mode&1)!==0,n){case"dialog":O("cancel",r),O("close",r);break;case"iframe":case"object":case"embed":O("load",r);break;case"video":case"audio":for(l=0;l<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=o.createElement(n,{is:r.is}):(e=o.createElement(n),n==="select"&&(o=e,r.multiple?o.multiple=!0:r.size&&(o.size=r.size))):e=o.createElementNS(e,n),e[Ie]=t,e[Vn]=r,Ba(e,t,!1,!1),t.stateNode=e;e:{switch(o=ou(n,r),n){case"dialog":O("cancel",e),O("close",e),l=r;break;case"iframe":case"object":case"embed":O("load",e),l=r;break;case"video":case"audio":for(l=0;lrn&&(t.flags|=128,r=!0,vn(u,!1),t.lanes=4194304)}else{if(!r)if(e=Xr(o),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),vn(u,!0),u.tail===null&&u.tailMode==="hidden"&&!o.alternate&&!U)return re(t),null}else 2*K()-u.renderingStartTime>rn&&n!==1073741824&&(t.flags|=128,r=!0,vn(u,!1),t.lanes=4194304);u.isBackwards?(o.sibling=t.child,t.child=o):(n=u.last,n!==null?n.sibling=o:t.child=o,u.last=o)}return u.tail!==null?(t=u.tail,u.rendering=t,u.tail=t.sibling,u.renderingStartTime=K(),t.sibling=null,n=A.current,D(A,r?n&1|2:n&1),t):(re(t),null);case 22:case 23:return To(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?he&1073741824&&(re(t),t.subtreeFlags&6&&(t.flags|=8192)):re(t),null;case 24:return null;case 25:return null}throw Error(g(156,t.tag))}function wd(e,t){switch(ao(t),t.tag){case 1:return pe(t.type)&&Vr(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return tn(),$(de),$(ue),wo(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return go(t),null;case 13:if($(A),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(g(340));bt()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return $(A),null;case 4:return tn(),null;case 10:return mo(t.type._context),null;case 22:case 23:return To(),null;case 24:return null;default:return null}}var hr=!1,le=!1,kd=typeof WeakSet=="function"?WeakSet:Set,E=null;function Ht(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){H(e,t,r)}else n.current=null}function Mu(e,t,n){try{n()}catch(r){H(e,t,r)}}var Oi=!1;function Sd(e,t){if(vu=Ir,e=Gs(),io(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var l=r.anchorOffset,u=r.focusNode;r=r.focusOffset;try{n.nodeType,u.nodeType}catch{n=null;break e}var o=0,i=-1,s=-1,f=0,m=0,h=e,p=null;t:for(;;){for(var w;h!==n||l!==0&&h.nodeType!==3||(i=o+l),h!==u||r!==0&&h.nodeType!==3||(s=o+r),h.nodeType===3&&(o+=h.nodeValue.length),(w=h.firstChild)!==null;)p=h,h=w;for(;;){if(h===e)break t;if(p===n&&++f===l&&(i=o),p===u&&++m===r&&(s=o),(w=h.nextSibling)!==null)break;h=p,p=h.parentNode}h=w}n=i===-1||s===-1?null:{start:i,end:s}}else n=null}n=n||{start:0,end:0}}else n=null;for(yu={focusedElem:e,selectionRange:n},Ir=!1,E=t;E!==null;)if(t=E,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,E=e;else for(;E!==null;){t=E;try{var k=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(k!==null){var S=k.memoizedProps,F=k.memoizedState,d=t.stateNode,a=d.getSnapshotBeforeUpdate(t.elementType===t.type?S:ze(t.type,S),F);d.__reactInternalSnapshotBeforeUpdate=a}break;case 3:var c=t.stateNode.containerInfo;c.nodeType===1?c.textContent="":c.nodeType===9&&c.documentElement&&c.removeChild(c.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(g(163))}}catch(v){H(t,t.return,v)}if(e=t.sibling,e!==null){e.return=t.return,E=e;break}E=t.return}return k=Oi,Oi=!1,k}function jn(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var l=r=r.next;do{if((l.tag&e)===e){var u=l.destroy;l.destroy=void 0,u!==void 0&&Mu(t,n,u)}l=l.next}while(l!==r)}}function fl(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function Fu(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function Qa(e){var t=e.alternate;t!==null&&(e.alternate=null,Qa(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Ie],delete t[Vn],delete t[ku],delete t[rd],delete t[ld])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Ka(e){return e.tag===5||e.tag===3||e.tag===4}function Ii(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Ka(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Du(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Ar));else if(r!==4&&(e=e.child,e!==null))for(Du(e,t,n),e=e.sibling;e!==null;)Du(e,t,n),e=e.sibling}function Ou(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Ou(e,t,n),e=e.sibling;e!==null;)Ou(e,t,n),e=e.sibling}var b=null,Te=!1;function Ze(e,t,n){for(n=n.child;n!==null;)Ya(e,t,n),n=n.sibling}function Ya(e,t,n){if($e&&typeof $e.onCommitFiberUnmount=="function")try{$e.onCommitFiberUnmount(rl,n)}catch{}switch(n.tag){case 5:le||Ht(n,t);case 6:var r=b,l=Te;b=null,Ze(e,t,n),b=r,Te=l,b!==null&&(Te?(e=b,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):b.removeChild(n.stateNode));break;case 18:b!==null&&(Te?(e=b,n=n.stateNode,e.nodeType===8?Il(e.parentNode,n):e.nodeType===1&&Il(e,n),On(e)):Il(b,n.stateNode));break;case 4:r=b,l=Te,b=n.stateNode.containerInfo,Te=!0,Ze(e,t,n),b=r,Te=l;break;case 0:case 11:case 14:case 15:if(!le&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){l=r=r.next;do{var u=l,o=u.destroy;u=u.tag,o!==void 0&&(u&2||u&4)&&Mu(n,t,o),l=l.next}while(l!==r)}Ze(e,t,n);break;case 1:if(!le&&(Ht(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(i){H(n,t,i)}Ze(e,t,n);break;case 21:Ze(e,t,n);break;case 22:n.mode&1?(le=(r=le)||n.memoizedState!==null,Ze(e,t,n),le=r):Ze(e,t,n);break;default:Ze(e,t,n)}}function $i(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new kd),t.forEach(function(r){var l=Td.bind(null,e,r);n.has(r)||(n.add(r),r.then(l,l))})}}function je(e,t){var n=t.deletions;if(n!==null)for(var r=0;rl&&(l=o),r&=~u}if(r=l,r=K()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*Ed(r/1960))-r,10e?16:e,nt===null)var r=!1;else{if(e=nt,nt=null,br=0,R&6)throw Error(g(331));var l=R;for(R|=4,E=e.current;E!==null;){var u=E,o=u.child;if(E.flags&16){var i=u.deletions;if(i!==null){for(var s=0;sK()-jo?Et(e,0):Po|=n),me(e,t)}function tc(e,t){t===0&&(e.mode&1?(t=or,or<<=1,!(or&130023424)&&(or=4194304)):t=1);var n=ie();e=Ye(e,t),e!==null&&(Gn(e,t,n),me(e,n))}function zd(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),tc(e,n)}function Td(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,l=e.memoizedState;l!==null&&(n=l.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(g(314))}r!==null&&r.delete(t),tc(e,n)}var nc;nc=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||de.current)fe=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return fe=!1,yd(e,t,n);fe=!!(e.flags&131072)}else fe=!1,U&&t.flags&1048576&&oa(t,Wr,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;jr(e,t),e=t.pendingProps;var l=qt(t,ue.current);Gt(t,n),l=So(null,t,r,e,l,n);var u=xo();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,pe(r)?(u=!0,Br(t)):u=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,vo(t),l.updater=cl,t.stateNode=l,l._reactInternals=t,Nu(t,r,e,n),t=zu(null,t,r,!0,u,n)):(t.tag=0,U&&u&&so(t),oe(null,t,l,n),t=t.child),t;case 16:r=t.elementType;e:{switch(jr(e,t),e=t.pendingProps,l=r._init,r=l(r._payload),t.type=r,l=t.tag=Rd(r),e=ze(r,e),l){case 0:t=ju(null,t,r,e,n);break e;case 1:t=Mi(null,t,r,e,n);break e;case 11:t=Li(null,t,r,e,n);break e;case 14:t=Ri(null,t,r,ze(r.type,e),n);break e}throw Error(g(306,r,""))}return t;case 0:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),ju(e,t,r,l,n);case 1:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),Mi(e,t,r,l,n);case 3:e:{if(Ua(t),e===null)throw Error(g(387));r=t.pendingProps,u=t.memoizedState,l=u.element,da(e,t),Yr(t,r,null,n);var o=t.memoizedState;if(r=o.element,u.isDehydrated)if(u={element:r,isDehydrated:!1,cache:o.cache,pendingSuspenseBoundaries:o.pendingSuspenseBoundaries,transitions:o.transitions},t.updateQueue.baseState=u,t.memoizedState=u,t.flags&256){l=nn(Error(g(423)),t),t=Fi(e,t,r,n,l);break e}else if(r!==l){l=nn(Error(g(424)),t),t=Fi(e,t,r,n,l);break e}else for(ve=ot(t.stateNode.containerInfo.firstChild),ye=t,U=!0,Le=null,n=ca(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(bt(),r===l){t=Xe(e,t,n);break e}oe(e,t,r,n)}t=t.child}return t;case 5:return pa(t),e===null&&Eu(t),r=t.type,l=t.pendingProps,u=e!==null?e.memoizedProps:null,o=l.children,gu(r,l)?o=null:u!==null&&gu(r,u)&&(t.flags|=32),$a(e,t),oe(e,t,o,n),t.child;case 6:return e===null&&Eu(t),null;case 13:return Aa(e,t,n);case 4:return yo(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=en(t,null,r,n):oe(e,t,r,n),t.child;case 11:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),Li(e,t,r,l,n);case 7:return oe(e,t,t.pendingProps,n),t.child;case 8:return oe(e,t,t.pendingProps.children,n),t.child;case 12:return oe(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,l=t.pendingProps,u=t.memoizedProps,o=l.value,D(Qr,r._currentValue),r._currentValue=o,u!==null)if(Fe(u.value,o)){if(u.children===l.children&&!de.current){t=Xe(e,t,n);break e}}else for(u=t.child,u!==null&&(u.return=t);u!==null;){var i=u.dependencies;if(i!==null){o=u.child;for(var s=i.firstContext;s!==null;){if(s.context===r){if(u.tag===1){s=We(-1,n&-n),s.tag=2;var f=u.updateQueue;if(f!==null){f=f.shared;var m=f.pending;m===null?s.next=s:(s.next=m.next,m.next=s),f.pending=s}}u.lanes|=n,s=u.alternate,s!==null&&(s.lanes|=n),Cu(u.return,n,t),i.lanes|=n;break}s=s.next}}else if(u.tag===10)o=u.type===t.type?null:u.child;else if(u.tag===18){if(o=u.return,o===null)throw Error(g(341));o.lanes|=n,i=o.alternate,i!==null&&(i.lanes|=n),Cu(o,n,t),o=u.sibling}else o=u.child;if(o!==null)o.return=u;else for(o=u;o!==null;){if(o===t){o=null;break}if(u=o.sibling,u!==null){u.return=o.return,o=u;break}o=o.return}u=o}oe(e,t,l.children,n),t=t.child}return t;case 9:return l=t.type,r=t.pendingProps.children,Gt(t,n),l=_e(l),r=r(l),t.flags|=1,oe(e,t,r,n),t.child;case 14:return r=t.type,l=ze(r,t.pendingProps),l=ze(r.type,l),Ri(e,t,r,l,n);case 15:return Oa(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:ze(r,l),jr(e,t),t.tag=1,pe(r)?(e=!0,Br(t)):e=!1,Gt(t,n),Ma(t,r,l),Nu(t,r,l,n),zu(null,t,r,!0,e,n);case 19:return Va(e,t,n);case 22:return Ia(e,t,n)}throw Error(g(156,t.tag))};function rc(e,t){return Ts(e,t)}function Ld(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Ee(e,t,n,r){return new Ld(e,t,n,r)}function Ro(e){return e=e.prototype,!(!e||!e.isReactComponent)}function Rd(e){if(typeof e=="function")return Ro(e)?1:0;if(e!=null){if(e=e.$$typeof,e===Zu)return 11;if(e===Ju)return 14}return 2}function ct(e,t){var n=e.alternate;return n===null?(n=Ee(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Lr(e,t,n,r,l,u){var o=2;if(r=e,typeof e=="function")Ro(e)&&(o=1);else if(typeof e=="string")o=5;else e:switch(e){case Ft:return Ct(n.children,l,u,t);case Gu:o=8,l|=8;break;case Zl:return e=Ee(12,n,t,l|2),e.elementType=Zl,e.lanes=u,e;case Jl:return e=Ee(13,n,t,l),e.elementType=Jl,e.lanes=u,e;case ql:return e=Ee(19,n,t,l),e.elementType=ql,e.lanes=u,e;case ps:return pl(n,l,u,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case fs:o=10;break e;case ds:o=9;break e;case Zu:o=11;break e;case Ju:o=14;break e;case Je:o=16,r=null;break e}throw Error(g(130,e==null?e:typeof e,""))}return t=Ee(o,n,t,l),t.elementType=e,t.type=r,t.lanes=u,t}function Ct(e,t,n,r){return e=Ee(7,e,r,t),e.lanes=n,e}function pl(e,t,n,r){return e=Ee(22,e,r,t),e.elementType=ps,e.lanes=n,e.stateNode={isHidden:!1},e}function Ql(e,t,n){return e=Ee(6,e,null,t),e.lanes=n,e}function Kl(e,t,n){return t=Ee(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Md(e,t,n,r,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Nl(0),this.expirationTimes=Nl(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Nl(0),this.identifierPrefix=r,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function Mo(e,t,n,r,l,u,o,i,s){return e=new Md(e,t,n,i,s),t===1?(t=1,u===!0&&(t|=8)):t=0,u=Ee(3,null,null,t),e.current=u,u.stateNode=e,u.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},vo(u),e}function Fd(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(ic)}catch(e){console.error(e)}}ic(),is.exports=we;var Ud=is.exports,sc,Ki=Ud;sc=Ki.createRoot,Ki.hydrateRoot;const Ad="modulepreload",Vd=function(e,t){return new URL(e,t).href},Yi={},Bd=function(t,n,r){let l=Promise.resolve();if(n&&n.length>0){const o=document.getElementsByTagName("link"),i=document.querySelector("meta[property=csp-nonce]"),s=(i==null?void 0:i.nonce)||(i==null?void 0:i.getAttribute("nonce"));l=Promise.allSettled(n.map(f=>{if(f=Vd(f,r),f in Yi)return;Yi[f]=!0;const m=f.endsWith(".css"),h=m?'[rel="stylesheet"]':"";if(!!r)for(let k=o.length-1;k>=0;k--){const S=o[k];if(S.href===f&&(!m||S.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${f}"]${h}`))return;const w=document.createElement("link");if(w.rel=m?"stylesheet":Ad,m||(w.as="script"),w.crossOrigin="",w.href=f,s&&w.setAttribute("nonce",s),document.head.appendChild(w),m)return new Promise((k,S)=>{w.addEventListener("load",k),w.addEventListener("error",()=>S(new Error(`Unable to preload CSS for ${f}`)))})}))}function u(o){const i=new Event("vite:preloadError",{cancelable:!0});if(i.payload=o,window.dispatchEvent(i),!i.defaultPrevented)throw o}return l.then(o=>{for(const i of o||[])i.status==="rejected"&&u(i.reason);return t().catch(u)})};function Hd(){return y.jsx("header",{className:"site-header",children:y.jsxs("div",{className:"wrapper",children:[y.jsx("a",{className:"site-title",href:"#/",children:"FPV Dataset"}),y.jsxs("nav",{className:"site-nav",children:[y.jsx("a",{href:"#/",children:"Videos"}),y.jsx("a",{href:"https://itamarweiss.com",rel:"noreferrer",children:"itamarweiss.com"})]})]})})}const Jd="https://d2fioemadmrru3.cloudfront.net/scenes".replace(/\/$/,""),Xi="https://d2fioemadmrru3.cloudfront.net/thumbnails".replace(/\/$/,""),gr={banner_start:{label:"Banner",color:"#4a9eff"},flight_start:{label:"Flight start",color:"#20c56b"},new_flight_start:{label:"New flight",color:"#00bcd4"},pause_start:{label:"Pause",color:"#f59e0b"},replay_start:{label:"Replay",color:"#9e77ed"},end:{label:"End",color:"#ef4444"},video_end:{label:"Video end",color:"#ef4444"},other:{label:"Other",color:"#8fa0ad"}},Wd=()=>y.jsx("svg",{viewBox:"0 0 24 24",width:"14",height:"14",fill:"currentColor","aria-hidden":!0,children:y.jsx("path",{d:"M8 5.14v13.72L19 12 8 5.14z"})}),Yl=()=>y.jsxs("svg",{viewBox:"0 0 24 24",width:"14",height:"14",fill:"none",stroke:"currentColor",strokeWidth:"1.8","aria-hidden":!0,children:[y.jsx("circle",{cx:"12",cy:"12",r:"9"}),y.jsx("ellipse",{cx:"12",cy:"12",rx:"4",ry:"9"}),y.jsx("path",{d:"M3.5 9h17M3.5 15h17"})]}),Qd=({dir:e})=>y.jsx("svg",{viewBox:"0 0 24 24",width:"13",height:"13",fill:"none",stroke:"currentColor",strokeWidth:"2","aria-hidden":!0,children:e==="desc"?y.jsx("path",{d:"M12 4v16m0 0l-6-6m6 6l6-6"}):y.jsx("path",{d:"M12 20V4m0 0l-6 6m6-6l6 6"})});function Kd({video:e}){var o;const[t,n]=I.useState(!1),r=!!((o=e.thumbWidths)!=null&&o.length)&&!t,l=r?`${Xi}/${e.slug}/${e.thumbWidths[e.thumbWidths.length-1]}.webp`:e.thumbnailUrl,u=r?e.thumbWidths.map(i=>`${Xi}/${e.slug}/${i}.webp ${i}w`).join(", "):void 0;return y.jsxs("a",{className:"thumb",href:Vu(e.videoFile),style:e.blur?{backgroundImage:`url(${e.blur})`}:void 0,children:[l?y.jsx("img",{src:l,srcSet:u,sizes:"(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 280px",alt:e.description,loading:"lazy",decoding:"async",onError:()=>n(!0)}):null,e.scenePath?y.jsx("span",{className:"badge-3d",children:"3D scene"}):null]})}function Yd({videos:e}){const[t,n]=I.useState(""),[r,l]=I.useState("desc"),[u,o]=I.useState("all"),i=I.useMemo(()=>{const s=t.trim().toLowerCase(),f=e.filter(m=>u==="with"&&!m.scenePath?!1:s?`${m.description} ${m.town} ${m.date} ${m.videoFile}`.toLowerCase().includes(s):!0);return f.sort((m,h)=>{const p=m.dateh.date?1:0;return r==="desc"?-p:p}),f},[e,t,r,u]);return y.jsxs("div",{children:[y.jsxs("div",{className:"gallery-toolbar",children:[y.jsx("input",{type:"search",name:"site-search-query",value:t,onChange:s=>n(s.target.value),placeholder:"Search by description, town, date…","aria-label":"Search videos",autoComplete:"off",autoCorrect:"off",spellCheck:!1}),y.jsxs("button",{type:"button",className:"toolbar-btn",onClick:()=>l(s=>s==="desc"?"asc":"desc"),"aria-label":`Sort by date, ${r==="desc"?"newest":"oldest"} first`,title:r==="desc"?"Newest first":"Oldest first",children:["Date ",y.jsx(Qd,{dir:r})]}),y.jsxs("button",{type:"button",className:`toolbar-btn${u==="with"?" active":""}`,onClick:()=>o(s=>s==="with"?"all":"with"),"aria-pressed":u==="with",title:"Only videos with a reconstructed 3D scene",children:[y.jsx(Yl,{})," 3D scenes"]}),y.jsx("span",{className:"gallery-count",children:i.length===e.length?`${e.length} videos`:`${i.length} of ${e.length}`})]}),y.jsx("div",{className:"video-grid",children:i.map(s=>y.jsxs("div",{className:"video-card",children:[y.jsx(Kd,{video:s}),y.jsx("a",{className:"title",href:Vu(s.videoFile),children:s.description||s.videoFile}),y.jsxs("span",{className:"meta",children:[s.date,s.town?` · ${s.town}`:""]}),y.jsxs("div",{className:"card-actions",children:[y.jsxs("a",{className:"card-btn",href:Vu(s.videoFile),children:[y.jsx(Wd,{})," Video"]}),s.scenePath?y.jsxs("a",{className:"card-btn primary",href:ac(s.videoFile),children:[y.jsx(Yl,{})," 3D scene"]}):y.jsxs("span",{className:"card-btn disabled",title:"No reconstructed scene yet",children:[y.jsx(Yl,{})," No scene"]})]})]},s.videoFile))}),i.length===0?y.jsx("p",{className:"not-found",children:"No videos match your filters."}):null]})}const wr=30;function Xl(e){const t=Math.floor(e/60),n=(e%60).toFixed(1).padStart(4,"0");return`${t}:${n}`}function Xd({video:e}){const t=I.useRef(null),[n,r]=I.useState(0),[l,u]=I.useState(0),[o,i]=I.useState(!1),[s,f]=I.useState(!1);I.useEffect(()=>{r(0),u(0),i(!1)},[e.videoFile]);const m=I.useMemo(()=>(e.segments??[]).slice().sort((a,c)=>a.time-c.time),[e.segments]),h=I.useMemo(()=>{const a=new Set(m.map(c=>c.type));return Object.entries(gr).filter(([c])=>a.has(c))},[m]),p=(a,c=!1)=>{const v=t.current;v&&(v.currentTime=Math.max(0,Math.min(a,v.duration||a)),c&&v.play().catch(()=>{}))},w=a=>{const c=t.current;c&&(c.pause(),p(c.currentTime+a))},k=()=>{const a=t.current;a&&(a.paused?a.play().catch(()=>{}):a.pause())},S=()=>{const a=t.current;a&&(a.muted=!a.muted,f(a.muted))},F=()=>{const a=t.current;a&&(document.fullscreenElement?document.exitFullscreen():a.requestFullscreen().catch(()=>{}))};I.useEffect(()=>{const a=c=>{var x,_,N;const v=((x=document.activeElement)==null?void 0:x.tagName)??"";if(!["INPUT","SELECT","TEXTAREA"].includes(v))switch(c.key){case" ":c.preventDefault(),k();break;case"ArrowLeft":c.preventDefault(),p((((_=t.current)==null?void 0:_.currentTime)??0)-5);break;case"ArrowRight":c.preventDefault(),p((((N=t.current)==null?void 0:N.currentTime)??0)+5);break;case",":w(-1/wr);break;case".":w(1/wr);break;case"m":S();break;case"f":F();break;case"Home":c.preventDefault(),p(0);break;case"End":c.preventDefault(),p(n);break}};return window.addEventListener("keydown",a),()=>window.removeEventListener("keydown",a)},[n]);const d=a=>{if(!n)return;const c=a.currentTarget.getBoundingClientRect();p((a.clientX-c.left)/c.width*n,!0)};return y.jsxs("div",{className:"video-view",children:[y.jsx("a",{className:"back-link",href:"#/",children:"← All videos"}),y.jsxs("div",{className:"video-stage",children:[y.jsx("video",{ref:t,src:e.videoUrl,poster:e.thumbnailUrl,playsInline:!0,preload:"metadata",onClick:k,onLoadedMetadata:a=>r(a.currentTarget.duration||0),onTimeUpdate:a=>u(a.currentTarget.currentTime),onPlay:()=>i(!0),onPause:()=>i(!1)}),o?null:y.jsx("button",{type:"button",className:"video-play-overlay",onClick:k,"aria-label":"Play",children:"▶"})]}),y.jsxs("div",{className:"transport",children:[y.jsxs("div",{className:"t-row t-primary",children:[y.jsx("button",{type:"button",className:"play-btn",onClick:k,"aria-label":o?"Pause":"Play",title:"Play/pause (space)",children:o?"❚❚":"▶"}),y.jsx("input",{type:"range",className:"scrubber",min:0,max:n||1,step:.01,value:Math.min(l,n||1),onChange:a=>p(Number(a.target.value)),"aria-label":"Seek"}),y.jsxs("span",{className:"time-display",children:[Xl(l)," / ",Xl(n)]})]}),y.jsxs("div",{className:"t-row t-secondary",children:[y.jsx("button",{type:"button",onClick:()=>w(-10),title:"Back 10s",children:"-10s"}),y.jsx("button",{type:"button",onClick:()=>w(-1/wr),title:"Previous frame (,)",children:"‹f"}),y.jsx("button",{type:"button",onClick:()=>w(1/wr),title:"Next frame (.)",children:"f›"}),y.jsx("button",{type:"button",onClick:()=>w(10),title:"Forward 10s",children:"+10s"}),y.jsx("button",{type:"button",onClick:S,title:"Mute (m)",children:s?"🔇":"🔊"}),y.jsx("button",{type:"button",onClick:F,title:"Fullscreen (f)",children:"⛶"})]})]}),y.jsxs("div",{className:"video-headline",children:[y.jsx("h1",{children:e.description||e.videoFile}),y.jsxs("p",{className:"view-meta",children:[e.date,e.town?` · ${e.town}`:""]}),y.jsxs("div",{className:"view-actions",children:[e.scenePath?y.jsx("a",{href:ac(e.videoFile),children:"View 3D scene →"}):null,y.jsx("a",{className:"icon-link",href:e.videoUrl,rel:"noreferrer",title:"Download video","aria-label":"Download video",children:y.jsxs("svg",{viewBox:"0 0 24 24",width:"16",height:"16",fill:"none",stroke:"currentColor",strokeWidth:"2","aria-hidden":!0,children:[y.jsx("path",{d:"M12 4v11m0 0l-5-5m5 5l5-5"}),y.jsx("path",{d:"M4 19h16"})]})})]})]}),m.length?y.jsxs("section",{children:[y.jsx("h2",{style:{fontSize:17},children:"Flight annotations"}),n>0?y.jsxs(y.Fragment,{children:[y.jsxs("div",{className:"timeline",onClick:d,title:"Click to seek",children:[m.map((a,c)=>{var v;return y.jsx("span",{className:"marker",style:{left:`${a.time/n*100}%`,background:((v=gr[a.type])==null?void 0:v.color)??"#8fa0ad"}},c)}),y.jsx("span",{className:"playhead",style:{left:`${l/n*100}%`}})]}),y.jsx("div",{className:"legend",children:h.map(([a,c])=>y.jsx("span",{className:"chip",style:{"--chip-color":c.color},children:c.label},a))})]}):null,y.jsxs("table",{className:"segment-table",children:[y.jsx("thead",{children:y.jsxs("tr",{children:[y.jsx("th",{children:"Time"}),y.jsx("th",{children:"Type"}),y.jsx("th",{children:"Note"})]})}),y.jsx("tbody",{children:m.map((a,c)=>{var v,x;return y.jsxs("tr",{children:[y.jsx("td",{children:y.jsx("a",{className:"time-link",href:"#",onClick:_=>{_.preventDefault(),p(a.time,!0)},children:Xl(a.time)})}),y.jsx("td",{children:y.jsx("span",{className:"segment-type",style:{"--chip-color":((v=gr[a.type])==null?void 0:v.color)??"#8fa0ad"},children:((x=gr[a.type])==null?void 0:x.label)??a.type})}),y.jsx("td",{style:{color:"var(--grey)"},children:a.comment??""})]},c)})})]}),e.annotationAuto?y.jsx("p",{className:"annotation-note",children:"Annotations were generated automatically."}):null]}):y.jsx("p",{className:"annotation-note",children:"No annotations for this video yet."})]})}const Gd=I.lazy(()=>Bd(()=>import("./SceneView-B3r-Nscl.js"),[],import.meta.url).then(e=>({default:e.SceneView})));function Gi(){const e=window.location.hash.replace(/^#\/?/,""),[t,...n]=e.split("/"),r=decodeURIComponent(n.join("/"));return t==="video"&&r?{view:"video",videoFile:r}:t==="scene"&&r?{view:"scene",videoFile:r}:{view:"gallery"}}function Vu(e){return`#/video/${encodeURIComponent(e)}`}function ac(e){return`#/scene/${encodeURIComponent(e)}`}function Zd(){const[e,t]=I.useState(Gi),[n,r]=I.useState(null),[l,u]=I.useState(null);I.useEffect(()=>{const s=()=>{t(Gi()),window.scrollTo(0,0)};return window.addEventListener("hashchange",s),()=>window.removeEventListener("hashchange",s)},[]),I.useEffect(()=>{fetch("./data/videos.json").then(s=>{if(!s.ok)throw new Error(`HTTP ${s.status}`);return s.json()}).then(r).catch(s=>u(String(s)))},[]);const o=I.useMemo(()=>{const s=new Map;for(const f of(n==null?void 0:n.videos)??[])s.set(f.videoFile,f);return s},[n]);let i;if(l)i=y.jsxs("p",{className:"not-found",children:["Failed to load the dataset (",l,")."]});else if(!n)i=y.jsx("p",{className:"not-found",children:"Loading…"});else if(e.view==="video"||e.view==="scene"){const s=o.get(e.videoFile);s?e.view==="video"?i=y.jsx(Xd,{video:s}):i=y.jsx(I.Suspense,{fallback:y.jsx("p",{className:"not-found",children:"Loading 3D viewer…"}),children:y.jsx(Gd,{video:s})}):i=y.jsx("p",{className:"not-found",children:"Video not found."})}else i=y.jsx(Yd,{videos:n.videos});return y.jsxs(y.Fragment,{children:[y.jsx(Hd,{}),y.jsx("div",{className:"page-content",children:y.jsx("div",{className:"wrapper",children:i})})]})}sc(document.getElementById("root")).render(y.jsx(Pc.StrictMode,{children:y.jsx(Zd,{})}));export{Jd as S,y as j,I as r,Vu as v}; diff --git a/public/img/fpv-viewer/annotated_clip.png b/public/img/fpv-viewer/annotated_clip.png index 2de8ba6..cb9448a 100644 Binary files a/public/img/fpv-viewer/annotated_clip.png and b/public/img/fpv-viewer/annotated_clip.png differ diff --git a/public/img/fpv-viewer/footage_breakdown.png b/public/img/fpv-viewer/footage_breakdown.png index 563015e..ad2e2cf 100644 Binary files a/public/img/fpv-viewer/footage_breakdown.png and b/public/img/fpv-viewer/footage_breakdown.png differ diff --git a/public/img/fpv-viewer/scale_ambiguity.png b/public/img/fpv-viewer/scale_ambiguity.png new file mode 100644 index 0000000..b4044ba Binary files /dev/null and b/public/img/fpv-viewer/scale_ambiguity.png differ diff --git a/public/img/fpv-viewer/scene_pipeline.png b/public/img/fpv-viewer/scene_pipeline.png new file mode 100644 index 0000000..7a9585c Binary files /dev/null and b/public/img/fpv-viewer/scene_pipeline.png differ diff --git a/public/img/fpv-viewer/tool_flow.png b/public/img/fpv-viewer/tool_flow.png index dd526dd..8bec984 100644 Binary files a/public/img/fpv-viewer/tool_flow.png and b/public/img/fpv-viewer/tool_flow.png differ diff --git a/research/fpv-viewer/README.md b/research/fpv-viewer/README.md index 636f2ef..d7f4098 100644 --- a/research/fpv-viewer/README.md +++ b/research/fpv-viewer/README.md @@ -19,7 +19,8 @@ This directory only regenerates the post's **figures** (in sim/ figures.py tool_flow.png qualitative schematic of the three views (gallery -> annotated player -> 3-D scene); - no numeric axes. + no numeric axes. The 3-D panel is a REAL + capture (assets/biranit_scene_capture.png). annotated_clip.png REAL flight-annotation timeline of one clip (2026-06-06 Merkava tank, Blat), from its segment markers. @@ -29,6 +30,14 @@ sim/ boundaries; each clip's final open-ended segment is excluded (no clip-end time in the manifest). + scene_pipeline.png qualitative schematic of the reconstruction + pipeline (raw clip -> extract flight -> + enhance -> select the run -> 3-D scene); + no numeric axes. + scale_ambiguity.png qualitative schematic of monocular scale + ambiguity (small near house vs large far + house in the same view cone; a known-size + door anchors the scale); no numeric axes. social.png 1200x630 OpenGraph card, composited over a REAL capture of the viewer's 3-D scene (assets/biranit_scene_capture.png). @@ -47,10 +56,11 @@ capture/ (the guided tour embedded in the post). ``` -The little gallery cards and point clouds drawn *inside* the schematics are -illustrative stand-ins (not screenshots) — they say "this is what the view looks -like," they don't plot data. The social card and the demo video, by contrast, are -**real** captures of the running viewer (Biranit / Iron Dome scene). +The little gallery cards and the pipeline boxes drawn *inside* the schematics +are illustrative stand-ins (not screenshots) — they say "this is what the view +looks like," they don't plot data. The tool_flow 3-D panel, the social card and +the demo video, by contrast, are **real** captures of the running viewer +(Biranit / Iron Dome scene). ## Rebuild the demo video / social capture @@ -67,7 +77,7 @@ cp out/scene_still.png ../assets/biranit_scene_capture.png # refresh social bg ``` python3 -m venv .venv # gitignored (research/**/.venv/) -.venv/bin/pip install numpy matplotlib +.venv/bin/pip install numpy matplotlib pillow .venv/bin/python sim/figures.py ``` diff --git a/research/fpv-viewer/sim/figures.py b/research/fpv-viewer/sim/figures.py index 5580cb6..8a463d2 100644 --- a/research/fpv-viewer/sim/figures.py +++ b/research/fpv-viewer/sim/figures.py @@ -8,19 +8,28 @@ - annotated_clip.png : REAL flight-annotation timeline of one clip (2026-06-06 Merkava tank, Blat), straight from the dataset's segment markers. Shows how much of a - propaganda clip is banner / replay / pause vs. flight. + clip is banner / replay / pause vs. flight. - footage_breakdown.png: REAL — of all annotated footage across the dataset, how the seconds split by segment type. Durations are summed from consecutive segment boundaries (the final, open-ended segment of each clip is excluded because the clip end time isn't in the manifest). + - scene_pipeline.png : qualitative schematic of the reconstruction pipeline + (raw clip -> extract flight -> enhance -> select the + attack run -> recover path + point cloud). Concept + diagram, no numeric axes. + - scale_ambiguity.png : qualitative schematic of monocular scale ambiguity — + a small near house and a large far house fill the + same view cone; a known-size object (a door) anchors + the scale. Concept diagram, no numeric axes. - social.png : 1200x630 OpenGraph card for the post. All counts/durations are REAL, computed from ../2026-07-05_videos_snapshot.json (a frozen copy of public/fpv/data/videos.json; the live one keeps growing). -The little gallery cards and point clouds drawn inside the schematics are -illustrative stand-ins, not screenshots — they're there to say "this is what the -view looks like," not to plot data. +Inside the tool_flow schematic, the gallery cards and the small timeline are +illustrative stand-ins (the timeline uses real segment boundaries); the 3-D +scene panel is a REAL screenshot of the viewer +(../assets/biranit_scene_capture.png). """ import os, json from collections import Counter @@ -45,14 +54,16 @@ "font.family": "sans-serif", }) -# segment type -> (display label, colour). "flight" is the signal; the rest is -# editing added on top of the footage. +# segment type -> (display label, colour). "flight" is the signal (the one +# saturated colour); the rest is editing on top of the footage and stays in a +# muted family. All colours were checked against the black surface with the +# dataviz palette validator (>=3:1 contrast, CVD-separable with labels+gaps). SEG = { "flight_start": ("Flight", CYAN), "new_flight_start": ("Flight", CYAN), "banner_start": ("Banner", MUTED), "replay_start": ("Replay", PURPLE), - "pause_start": ("Pause/freeze", "#4a5260"), + "pause_start": ("Pause/freeze", "#5b6675"), "other": ("Other", "#6b7480"), } @@ -116,22 +127,25 @@ def draw_timeline(ax, x0, y0, w, h, segs): return T -def draw_scene(ax, cx, cy, s): - """A little point cloud with a cyan->gold flight path arcing onto a target.""" - rng = np.random.default_rng(3) - pts = rng.normal(0, 1, (260, 2)) * np.array([1.5, 0.7]) * s - ax.scatter(cx + pts[:, 0], cy + pts[:, 1] - 0.5 * s, s=2.2, - c="#3a444f", alpha=0.7, linewidths=0) - t = np.linspace(0, 1, 60) - px = cx + (-2.2 + 2.4 * t) * s - py = cy + (1.5 * s) * (1 - t) ** 1.6 - 0.15 * s - cols = plt.cm.ScalarMappable().to_rgba(t) # unused; explicit gradient below - for i in range(len(t) - 1): - f = i / (len(t) - 1) - col = (CYAN if f < 0.5 else GOLD) - ax.plot(px[i:i + 2], py[i:i + 2], color=col, lw=2.0, alpha=0.9) - ax.scatter([px[0]], [py[0]], s=26, color=GREEN, zorder=5) # launch - ax.scatter([px[-1]], [py[-1]], s=30, color=RED, marker="X", zorder=5) # target +def draw_scene_capture(ax, x0, y0, w, h): + """A REAL screenshot of the scene viewer (the Biranit / Iron Dome strike), + cropped and fitted inside the panel with rounded corners.""" + from PIL import Image + cap = Image.open(os.path.join(HERE, "..", "assets", + "biranit_scene_capture.png")).convert("RGB") + cap = cap.crop((240, 55, 1040, 400)) # drop dead space & the UI button + ar = cap.width / cap.height + dw, dh = (w, w / ar) if ar > w / h else (h * ar, h) + ex0, ey0 = x0 + (w - dw) / 2, y0 + (h - dh) / 2 + im = ax.imshow(np.asarray(cap) / 255.0, + extent=[ex0, ex0 + dw, ey0, ey0 + dh], + aspect="auto", zorder=2, interpolation="lanczos") + clip = FancyBboxPatch((ex0, ey0), dw, dh, + boxstyle="round,pad=0,rounding_size=0.05", + transform=ax.transData, + facecolor="none", edgecolor="none") + ax.add_patch(clip) + im.set_clip_path(clip) # -------------------------------------------------------------------------- @@ -143,7 +157,7 @@ def fig_tool_flow(videos): panels = [ ("Browse", "Gallery of every clip —\nsearch, sort, filter to the\nones with a 3-D scene", CYAN), ("Read the edit", "Auto-annotated timeline:\njump past banners &\nreplays to real flight", GOLD), - ("Fly the strike", "Orbit the reconstructed\n3-D scene & measure\nright in the browser", GREEN), + ("Explore the strike", "Replay the reconstructed\n3-D scene and learn\nhow it unfolded", GREEN), ] pw, ph, gap = 3.1, 2.4, 0.55 y0 = 1.35 @@ -158,7 +172,7 @@ def fig_tool_flow(videos): elif i == 1: draw_timeline(ax, x + 0.22, y0 + 0.35, pw - 0.44, 1.2, ex["segments"]) else: - draw_scene(ax, x + pw / 2, y0 + ph / 2 - 0.25, 0.46) + draw_scene_capture(ax, x + 0.18, y0 + 0.22, pw - 0.36, ph - 0.85) ax.text(x + pw / 2, y0 + ph - 0.06, title, ha="center", va="top", color=col, fontsize=12.5, fontweight="bold") ax.text(x + pw / 2, 0.98, body, ha="center", va="top", @@ -176,46 +190,124 @@ def fig_tool_flow(videos): print("tool_flow.png") +# ---- shared helpers for the two "breakdown" charts ------------------------ +# Both charts use an axes that maps 1 data unit = 1 inch in x AND y, so the +# rounded corners of FancyBboxPatch come out circular instead of squashed. + +def inch_axes(fig_w, fig_h): + fig = plt.figure(figsize=(fig_w, fig_h)) + ax = fig.add_axes([0, 0, 1, 1]) + ax.set_xlim(0, fig_w); ax.set_ylim(0, fig_h); ax.axis("off") + return fig, ax + + +def text_w(fig, ax, s, fontsize, fontweight="normal"): + """Measured width of a string, in inches (== data units here).""" + t = ax.text(0, -5, s, fontsize=fontsize, fontweight=fontweight) + fig.canvas.draw() + w = t.get_window_extent().width / fig.dpi + t.remove() + return w + + +def seg_patch(ax, x, y, w, h, color, gap=0.028, rs=0.045): + """One rounded timeline/bar segment with a small breathing gap around it.""" + x, w = x + gap / 2, max(w - gap, 0.02) + ax.add_patch(FancyBboxPatch( + (x, y), w, h, + boxstyle=f"round,pad=0,rounding_size={min(rs, 0.49 * w)}", + linewidth=0, facecolor=color)) + + +def legend_swatch(fig, ax, x, y, label, color, fontsize=9.5, color_txt="#c3cad3"): + """Rounded swatch + label; returns the x where the next item can start.""" + sw, sh = 0.17, 0.11 + ax.add_patch(FancyBboxPatch((x, y - sh / 2), sw, sh, + boxstyle="round,pad=0,rounding_size=0.03", + linewidth=0, facecolor=color)) + ax.text(x + sw + 0.07, y, label, va="center", color=color_txt, + fontsize=fontsize) + return x + sw + 0.07 + text_w(fig, ax, label, fontsize) + 0.32 + + def fig_annotated_clip(videos): ex = next(v for v in videos if v["slug"] == "2026-06-06_merkava_tank_blat_position") segs = ex["segments"] times = [s["time"] for s in segs] T = times[-1] + 3.0 - fig, ax = plt.subplots(figsize=(10, 3.1)) - ax.set_xlim(0, T); ax.set_ylim(0, 1); ax.axis("off") - - # title (top) ; legend (just under it) ; ribbon (middle) ; ticks (bottom) - ax.text(0, 0.95, - "One clip, annotated: Merkava tank, Blat (2026-06-06)", - color=TXT, fontsize=12.5, fontweight="bold") - y, h = 0.30, 0.30 - seen = {} + W, H = 10.0, 3.3 + M = 0.55 # side margin, inches + BW = W - 2 * M # ribbon width + fig, ax = inch_axes(W, H) + + def X(t): # seconds -> inches + return M + BW * t / T + + # title + ax.text(M, H - 0.42, "One clip, annotated", color=TXT, fontsize=13.5, + fontweight="bold") + ax.text(M + text_w(fig, ax, "One clip, annotated", 13.5, "bold") + 0.14, + H - 0.42, "— Merkava tank, Blat · 2026-06-06", color=MUTED, + fontsize=11) + + # ribbon — merge consecutive same-label markers (the data sometimes has + # e.g. two banner_start boundaries in a row) so each visual segment is one + # patch and the callouts measure the real span + seg_spans = [] # (t0, t1, label) for i, s in enumerate(segs): t0 = times[i] t1 = times[i + 1] if i + 1 < len(segs) else T - label, col = SEG.get(s["type"], ("Other", MUTED)) - ax.add_patch(Rectangle((t0, y), t1 - t0, h, facecolor=col, - edgecolor=BG, linewidth=1.2)) + label = SEG.get(s["type"], ("Other", MUTED))[0] + if seg_spans and seg_spans[-1][2] == label: + seg_spans[-1] = (seg_spans[-1][0], t1, label) + else: + seg_spans.append((t0, t1, label)) + ry, rh = 1.18, 0.62 + seen = {} + for t0, t1, label in seg_spans: + col = SEG_COLOR(label) + seg_patch(ax, X(t0), ry, BW * (t1 - t0) / T, rh, col) seen[label] = col - # time axis ticks every 15s + + # story callouts above the ribbon (thin leaders, staggered heights) + def callout(t0, t1, text, y_text, ha): + cx = X((t0 + t1) / 2) + ax.plot([cx, cx], [ry + rh + 0.05, y_text - 0.10], color="#39404b", + lw=0.9) + tx = {"left": max(cx - 0.05, M), "center": cx, + "right": min(cx + 0.05, M + BW)}[ha] + ax.text(tx, y_text, text, ha=ha, va="bottom", color=MUTED, + fontsize=9, style="italic") + banners = [s for s in seg_spans if s[2] == "Banner"] + pauses = [s for s in seg_spans if s[2] == "Pause/freeze"] + replays = [s for s in seg_spans if s[2] == "Replay"] + if banners: + b = banners[0] + callout(b[0], b[1], f"{b[1] - b[0]:.0f}-second banner", ry + rh + 0.22, + "left") + if pauses: + p = max(pauses, key=lambda s: s[1] - s[0]) + callout(p[0], p[1], "freeze at impact", ry + rh + 0.48, "center") + if replays: + r = replays[-1] + callout(r[0], r[1], "slow-mo replay", ry + rh + 0.22, "right") + + # time axis: hairline baseline + ticks every 15 s + ax.plot([M, M + BW], [ry - 0.09, ry - 0.09], color="#262c35", lw=1.0) for tt in range(0, int(T) + 1, 15): - ax.plot([tt, tt], [y - 0.05, y], color=MUTED, lw=1) - ax.text(tt, y - 0.11, f"{tt}s", ha="center", va="top", - color=MUTED, fontsize=9) - # legend row + ax.plot([X(tt), X(tt)], [ry - 0.09, ry - 0.16], color="#3a424e", lw=1.0) + ax.text(X(tt), ry - 0.24, f"{tt}s", ha="center", va="top", + color=MUTED, fontsize=8.5) + + # legend row (bottom, under the axis) order = ["Flight", "Pause/freeze", "Replay", "Banner", "Other"] - lx = 0 + lx = M for lab in order: - if lab not in seen: - continue - ax.add_patch(Rectangle((lx, 0.71), T * 0.022, 0.07, - facecolor=seen[lab], edgecolor="none")) - ax.text(lx + T * 0.03, 0.745, lab, va="center", color="#c3cad3", - fontsize=9.5) - lx += T * (0.03 + 0.0085 * len(lab) + 0.045) - fig.savefig(os.path.join(OUT, "annotated_clip.png"), dpi=150, facecolor=BG, - bbox_inches="tight") + if lab in seen: + lx = legend_swatch(fig, ax, lx, 0.36, lab, seen[lab]) + + fig.savefig(os.path.join(OUT, "annotated_clip.png"), dpi=150, facecolor=BG) plt.close(fig) print("annotated_clip.png span %.0fs" % T) @@ -234,32 +326,173 @@ def fig_footage_breakdown(videos): vals = [dur[k] for k in order] cols = [SEG_COLOR(k) for k in order] - fig, ax = plt.subplots(figsize=(10, 2.5)) - ax.set_xlim(0, total); ax.set_ylim(0, 1); ax.axis("off") - x = 0 + W, H = 10.0, 3.3 + M = 0.55 + BW = W - 2 * M + fig, ax = inch_axes(W, H) + + # title + total + ax.text(M, H - 0.42, "Where the seconds go", color=TXT, fontsize=13.5, + fontweight="bold") + ax.text(M + text_w(fig, ax, "Where the seconds go", 13.5, "bold") + 0.14, + H - 0.42, + f"— all annotated footage, {total/3600:.1f} hours", + color=MUTED, fontsize=11) + + # one proportional bar with rounded segments and gaps + by, bh = 1.22, 0.60 + x = M for k, v, c in zip(order, vals, cols): - ax.add_patch(Rectangle((x, 0.42), v, 0.34, facecolor=c, - edgecolor=BG, linewidth=1.4)) + w = BW * v / total + seg_patch(ax, x, by, w, bh, c) pct = 100 * v / total - if pct > 4: - ax.text(x + v / 2, 0.59, f"{k}\n{pct:.0f}%", ha="center", - va="center", color="#04070c" if c in (CYAN, GOLD) else TXT, - fontsize=10, fontweight="bold", linespacing=1.15) - x += v - ax.text(0, 0.90, - "Where the seconds go across all annotated footage", - color=TXT, fontsize=12.5, fontweight="bold") - ax.text(0, 0.14, - f"{total/3600:.1f} hours of annotated footage · barely half is actual flight — " - "the rest is banners, freezes and replays the editor added", - color=MUTED, fontsize=9.5) + if pct > 10: # big segments carry their share directly + ax.text(x + w / 2, by + bh / 2, f"{pct:.0f}%", ha="center", + va="center", fontsize=11.5, fontweight="bold", + color="#04141d" if c == CYAN else "#0b0e13") + x += w + + # the story, as two brackets over the bar: flight vs. everything else + fw = BW * dur["Flight"] / total + def bracket(x0, x1, label, col, y=by + bh + 0.17): + ax.plot([x0 + 0.02, x1 - 0.02], [y, y], color=col, lw=1.1) + for xe in (x0 + 0.02, x1 - 0.02): + ax.plot([xe, xe], [y, y - 0.07], color=col, lw=1.1) + ax.text((x0 + x1) / 2, y + 0.09, label, ha="center", va="bottom", + color=col, fontsize=9.8) + bracket(M, M + fw, f"actual flight — {100*dur['Flight']/total:.0f}%", CYAN) + bracket(M + fw, M + BW, + f"added in the edit — {100*(total-dur['Flight'])/total:.0f}%", + MUTED) + + # value row: every type, even the slivers too small to label in the bar + lx = M + for k, v, c in zip(order, vals, cols): + lab = f"{k} {100*v/total:.0f}% · {v/60:.0f} min" + lx = legend_swatch(fig, ax, lx, 0.62, lab, c) + fig.savefig(os.path.join(OUT, "footage_breakdown.png"), dpi=150, - facecolor=BG, bbox_inches="tight") + facecolor=BG) plt.close(fig) print("footage_breakdown.png flight=%.0f%% total=%.0fs" % (100 * dur["Flight"] / total, total)) +def fig_scene_pipeline(videos): + """How a raw clip becomes a 3-D scene — a five-step concept schematic.""" + steps = [ + ("Raw clip", "the edited footage —\nbanners, freezes, replays", MUTED), + ("Extract flight", "the annotations isolate\nthe real flying", CYAN), + ("Enhance", "equalize & clean up the\ncompressed frames", GOLD), + ("Select the run", "keep the relevant part\nof the attack flight", GREEN), + ("3-D scene", "recover the camera path\n+ the point cloud", PURPLE), + ] + W, H = 10.0, 2.55 + M, gap = 0.5, 0.42 + bw = (W - 2 * M - (len(steps) - 1) * gap) / len(steps) + bh, by = 0.62, 1.12 + fig, ax = inch_axes(W, H) + + ax.text(M, H - 0.38, "From raw clip to 3-D scene", color=TXT, + fontsize=13.5, fontweight="bold") + + x = M + for i, (title, body, col) in enumerate(steps): + ax.add_patch(FancyBboxPatch((x, by), bw, bh, + boxstyle="round,pad=0.02,rounding_size=0.07", + linewidth=1.4, edgecolor=col, facecolor=PANEL)) + ax.text(x + bw / 2, by + bh / 2, title, ha="center", va="center", + color=col, fontsize=10.5, fontweight="bold") + ax.text(x + bw / 2, by - 0.16, body, ha="center", va="top", + color=MUTED, fontsize=8.2, linespacing=1.4) + if i < len(steps) - 1: + ax.add_patch(FancyArrowPatch((x + bw + 0.07, by + bh / 2), + (x + bw + gap - 0.07, by + bh / 2), arrowstyle="-|>", + mutation_scale=13, color="#4a5260", linewidth=1.4)) + x += bw + gap + + fig.savefig(os.path.join(OUT, "scene_pipeline.png"), dpi=150, facecolor=BG) + plt.close(fig) + print("scene_pipeline.png") + + +def fig_scale_ambiguity(videos): + """Why the reconstruction doesn't know its scale — a small near house and a + large far house subtend the same view, so they project to the same pixels. + Concept schematic, no numeric axes.""" + W, H = 10.0, 3.4 + fig, ax = inch_axes(W, H) + + ax.text(0.5, H - 0.38, "One image, two possible worlds", color=TXT, + fontsize=13.5, fontweight="bold") + ax.text(0.5 + text_w(fig, ax, "One image, two possible worlds", 13.5, + "bold") + 0.14, + H - 0.38, "— the model recovers shape, not size", color=MUTED, + fontsize=11) + + apex = (0.85, 1.55) + m = 0.145 # half-angle slope of the view cone + x_end = 9.35 + + # view cone: faint fill + hairline rays + xs = np.linspace(apex[0], x_end, 2) + ax.fill_between(xs, apex[1] - m * (xs - apex[0]), + apex[1] + m * (xs - apex[0]), color=CYAN, alpha=0.045, + linewidth=0) + for sgn in (+1, -1): + ax.plot(xs, apex[1] + sgn * m * (xs - apex[0]), color="#3a424e", + lw=1.0) + # camera glyph + "same image" arc at the apex + ax.scatter([apex[0]], [apex[1]], s=34, color=GOLD, zorder=5) + ax.text(apex[0], apex[1] - 0.30, "camera", ha="center", va="top", + color=MUTED, fontsize=8.5) + th = np.linspace(-np.arctan(m), np.arctan(m), 40) + ax.plot(apex[0] + 0.55 * np.cos(th), apex[1] + 0.55 * np.sin(th), + color=GOLD, lw=1.0) + ax.text(apex[0] + 0.68, apex[1], "same\nview", va="center", color=MUTED, + fontsize=7.8, linespacing=1.3) + + def house(dx, col, label): + """A house that exactly fills the view cone at distance dx.""" + cx = apex[0] + dx + h = 2 * m * dx + base = apex[1] - m * dx + w = 0.72 * h + body = 0.62 * h + ax.add_patch(Rectangle((cx - w / 2, base), w, body, facecolor="none", + edgecolor=col, lw=1.6)) + ax.add_patch(plt.Polygon( + [[cx - 0.56 * w, base + body], [cx + 0.56 * w, base + body], + [cx, base + h]], closed=True, facecolor="none", edgecolor=col, + lw=1.6)) + dw, dh = 0.22 * w, 0.42 * body # the door + ax.add_patch(Rectangle((cx - dw / 2, base), dw, dh, facecolor="none", + edgecolor=col, lw=1.1)) + ax.text(cx, base - 0.13, label, ha="center", va="top", color=MUTED, + fontsize=8.5) + return cx, base, dw, dh + + house(2.3, CYAN, "small & near") + fcx, fbase, fdw, fdh = house(7.3, PURPLE, "large & far") + + # the resolution: measure an object of known size (the far house's door) + bx = fcx + fdw / 2 + 0.10 + ax.annotate("", (bx, fbase), (bx, fbase + fdh), + arrowprops=dict(arrowstyle="<->", color=GOLD, lw=1.2)) + tx, ty = 4.05, 0.38 + ax.text(tx, ty, + "a door is ~2 m — measure one known size\nand the whole scene snaps to real units", + va="center", color=GOLD, fontsize=8.6, linespacing=1.5) + ax.plot([tx + text_w(fig, ax, "and the whole scene snaps to real units", + 8.6) + 0.30, bx - 0.04], + [ty, fbase + fdh * 0.35], color="#6b5a2a", lw=0.9) + + fig.savefig(os.path.join(OUT, "scale_ambiguity.png"), dpi=150, + facecolor=BG) + plt.close(fig) + print("scale_ambiguity.png") + + def SEG_COLOR(label): for _, (lab, col) in SEG.items(): if lab == label: @@ -321,4 +554,6 @@ def fig_social(videos): fig_tool_flow(videos) fig_annotated_clip(videos) fig_footage_breakdown(videos) + fig_scene_pipeline(videos) + fig_scale_ambiguity(videos) fig_social(videos)