@displayxr/inline3d 1.43.1 → 1.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -59,10 +59,15 @@ import {
59
59
  cursorArrowFootprint,
60
60
  cursorDefaultHeight,
61
61
  cursorModelMatrix,
62
+ cursorPlacementSoften,
63
+ cursorSoftArrowBox,
64
+ cursorSoftArrowGLSL,
62
65
  cursorViewRay,
66
+ resolveCursorSoften,
63
67
  CURSOR_DEFAULT_TUNING,
64
68
  CURSOR_OUTLINE_COLOR,
65
69
  } from './inline3d-cursor-depth.js';
70
+ import { CursorAmortisedPick, CursorDebugStats, cursorDebugMode } from './inline3d-cursor-perf.js';
66
71
 
67
72
  /**
68
73
  * A reusable three.js camera driven directly by an XRView's matrices. Construct once with
@@ -496,33 +501,63 @@ export class DepthCursor {
496
501
  * content) while it is still; 'screen' never parallaxes; 'world' always does.
497
502
  * @param {'canvas'|'window'} [opts.pointerScope='canvas'] 'window' keeps the cursor over DOM
498
503
  * layered on the canvas (overlay buttons) and hides the CSS cursor page-wide meanwhile.
504
+ * @param {'both'|'off'|'alpha'|'blur'|object} [opts.soften='both'] crosstalk softening of the
505
+ * LIFTED arrow (runtime ADR-046 Amendment 2 §B.7): an edge blur of 0.1 × its ghost offset
506
+ * (capped at 6% of its height, 8 px) and an opacity easing to 0.5 over 0.03 baselines of
507
+ * lift, both zero on the glass. A preset, or `{ mode, blurK, blurMaxPx, blurMaxFrac,
508
+ * alphaMin, fullD }` over the defaults. Drawn in the arrow's own shader.
499
509
  * @param {object} [opts.viewSpace] Object3D whose world matrix maps view transforms to world.
500
- * @param {number} [opts.raysPerFrame=0] 0 = the whole footprint every frame (two eyes × 9
501
- * points). N > 0 = an EXPENSIVE hit test (e.g. a gaussian-splat raycast, ~8 ms a ray):
502
- * cast N rays a frame from the first eye, cycling through the footprint, and take the
503
- * nearest of the most recent full cycle.
510
+ * @param {number} [opts.raysPerFrame=0] 0 = the whole footprint every frame (two eyes × 10
511
+ * points), synchronously. N > 0 = amortised: N rays a frame, cycling the footprint
512
+ * (alternating eyes), each point's last hit kept until the pointer moves away from where it
513
+ * was cast. The sprite still follows the NEWEST pointer position every frame, at the depth
514
+ * the pick has so far; the depth filter absorbs the cadence. ./model passes 3, ./splat 1
515
+ * (a gaussian-splat raycast costs ~8 ms a ray).
516
+ * @param {boolean|'both'} [opts.debug=false] true: log update() cost, rays a frame and the frame
517
+ * interval (rolling stats, at most once a second; `cursor.debugStats.last` holds the newest).
518
+ * 'both': that, and the OS cursor stays visible beside the sprite (the latency check).
504
519
  */
505
520
  constructor(
506
521
  THREE,
507
- { canvas, hitTest, height = null, color = 0xffffff, viewSpace = null, raysPerFrame = 0, margin, anchor = 'hybrid', pointerScope = 'canvas' },
522
+ { canvas, hitTest, height = null, color = 0xffffff, viewSpace = null, raysPerFrame = 0, margin, anchor = 'hybrid', pointerScope = 'canvas', debug = false, soften },
508
523
  ) {
509
524
  this._THREE = THREE;
510
525
  this.canvas = canvas;
511
526
  this.hitTest = hitTest;
527
+ const debugMode = cursorDebugMode(debug);
528
+ /** `cursor: { debug }` only: the rolling stats (null otherwise — nothing is measured). */
529
+ this.debugStats = null;
530
+ if (debugMode) {
531
+ this.debugStats = new CursorDebugStats({ info: typeof hitTest.info === 'function' ? hitTest.info : null });
532
+ this._rays = 0;
533
+ this._seenSamples = 0;
534
+ this._seenTime = 0;
535
+ const inner = hitTest;
536
+ this.hitTest = (o, d) => {
537
+ this._rays++;
538
+ return inner(o, d);
539
+ };
540
+ }
512
541
  /** Sprite height (canvas heights) when set; null = the OS arrow's size, from the canvas's on-page height. */
513
542
  this.height = height > 0 && Number.isFinite(height) ? height : null;
514
543
  this.viewSpace = viewSpace;
515
544
  this.raysPerFrame = raysPerFrame;
516
- this._ring = []; // amortised mode: the last hit per footprint point (null = a miss)
517
- this._next = 0;
545
+ this._pick = null; // amortised mode (raysPerFrame > 0): a CursorAmortisedPick, built on first use
518
546
  const tuning = margin > 0 && Number.isFinite(margin) ? { ...CURSOR_DEFAULT_TUNING, margin } : CURSOR_DEFAULT_TUNING;
519
547
  this.placer = new CursorDepthPlacer(tuning, { anchor });
520
- this.pointer = new CursorPointer(canvas, { scope: pointerScope });
548
+ this.pointer = new CursorPointer(canvas, { scope: pointerScope, keepCss: debugMode === 'both' });
549
+ if (this.debugStats) this.debugStats.source = this.pointer.source;
521
550
  /** The last placement (diagnostics): `{active, position, height, disparity, targetDisparity, anchored}`. */
522
551
  this.placement = { active: false };
552
+ /** Crosstalk softening parameters (resolveCursorSoften). */
553
+ this.soften = resolveCursorSoften(soften, '@displayxr/inline3d/three DepthCursor');
554
+ /** The last frame's softening (diagnostics): `{blurPx, alpha, ghostPx, spritePx, radius, aa, soft}`. */
555
+ this.softening = null;
556
+ this._soft = null; // { geometry, material } — built on the first softened frame
523
557
 
524
558
  // The arrow: a dark outline polygon, the fill inset over it; tip at the origin (the hotspot).
525
559
  const fill = [((color >> 16) & 255) / 255, ((color >> 8) & 255) / 255, (color & 255) / 255, 1];
560
+ this._fill = fill;
526
561
  const m = cursorArrowMesh(fill, CURSOR_OUTLINE_COLOR);
527
562
  const geom = new THREE.BufferGeometry();
528
563
  geom.setAttribute('position', new THREE.Float32BufferAttribute(m.positions, 3));
@@ -541,6 +576,7 @@ export class DepthCursor {
541
576
  this.object.frustumCulled = false;
542
577
  this.object.renderOrder = 1e9; // last: never occluded, it is in front by construction
543
578
  this.object.visible = false;
579
+ this._crisp = { geometry: geom, material: mat };
544
580
  }
545
581
 
546
582
  /** Set the pointer position directly (canvas-normalised, v down), or null — for scripted input. */
@@ -554,12 +590,34 @@ export class DepthCursor {
554
590
  * @param {number} [nowMs=performance.now()]
555
591
  */
556
592
  update(views, nowMs = globalThis.performance ? globalThis.performance.now() : Date.now()) {
593
+ if (this.debugStats) return this._updateMeasured(views, nowMs);
594
+ return this._update(views, nowMs);
595
+ }
596
+
597
+ // `cursor: { debug }`: the same update, timed. Off, update() never reaches this.
598
+ _updateMeasured(views, nowMs) {
599
+ const clock = () => (globalThis.performance ? globalThis.performance.now() : Date.now());
600
+ this._rays = 0;
601
+ const t0 = clock();
602
+ const p = this._update(views, nowMs);
603
+ const t1 = clock();
604
+ const ptr = this.pointer;
605
+ const fresh = ptr.samples !== this._seenSamples && ptr.sampleTime > 0 && ptr.sampleTime !== this._seenTime;
606
+ const samples = ptr.samples - this._seenSamples;
607
+ this._seenSamples = ptr.samples;
608
+ this._seenTime = ptr.sampleTime;
609
+ this.debugStats.frame(t1 - t0, this._rays, t0, fresh ? t0 - ptr.sampleTime : null, samples);
610
+ return p;
611
+ }
612
+
613
+ _update(views, nowMs) {
557
614
  const vs = this._worldViews(views);
558
615
  const uv = this.pointer.uv;
559
616
  let p = { active: false };
617
+ let h = 0;
560
618
  if (uv && vs.length >= 2) {
561
619
  const [u, v] = uv;
562
- const h = this.height ?? cursorDefaultHeight(this.pointer.cssHeight());
620
+ h = this.height ?? cursorDefaultHeight(this.pointer.cssHeight());
563
621
  const nearestPoint = this._footprintHit(vs, u, v, h);
564
622
  p = this.placer.update(vs, { u, v, nearestPoint, cursorHeight: h, canvasPx: this.pointer.panelPx() }, nowMs / 1000);
565
623
  }
@@ -568,17 +626,83 @@ export class DepthCursor {
568
626
  if (p.active) {
569
627
  this.object.matrix.fromArray(cursorModelMatrix(p));
570
628
  this.object.matrixWorldNeedsUpdate = true;
629
+ const [pw, ph] = this.pointer.panelSize();
630
+ const s = (this.softening = cursorPlacementSoften(p, vs, pw, ph, h, this.soften));
631
+ this._useSoft(s);
632
+ } else {
633
+ this.softening = null;
571
634
  }
572
635
  this.pointer.hideCss(!!p.active);
573
636
  return p;
574
637
  }
575
638
 
639
+ // Crisp frames draw the arrow mesh exactly as without softening; softened ones swap in a quad
640
+ // whose shader evaluates the arrow at the runtime's 13 blur taps, times the opacity.
641
+ _useSoft(s) {
642
+ if (!s.soft) {
643
+ this.object.geometry = this._crisp.geometry;
644
+ this.object.material = this._crisp.material;
645
+ return;
646
+ }
647
+ const soft = this._soft || (this._soft = this._makeSoft());
648
+ const u = soft.material.uniforms;
649
+ const [x0, y0, x1, y1] = cursorSoftArrowBox(s.radius, s.aa);
650
+ u.inline3dCursorBox.value.set(x0, y0, x1, y1);
651
+ u.inline3dCursorSoft.value.set(s.radius, s.alpha, s.aa, 0);
652
+ this.object.geometry = soft.geometry;
653
+ this.object.material = soft.material;
654
+ }
655
+
656
+ _makeSoft() {
657
+ const THREE = this._THREE;
658
+ const geometry = new THREE.BufferGeometry();
659
+ // A unit quad; the vertex shader spreads it over the padded arrow box (arrow units, y down).
660
+ geometry.setAttribute('position', new THREE.Float32BufferAttribute([0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0], 3));
661
+ // three >= 0.154 names the output-transform chunk colorspace_fragment; 0.150-0.153 encodings_fragment.
662
+ const chunk = THREE.ShaderChunk && THREE.ShaderChunk.colorspace_fragment !== undefined ? 'colorspace_fragment' : 'encodings_fragment';
663
+ const material = new THREE.ShaderMaterial({
664
+ uniforms: {
665
+ inline3dCursorBox: { value: new THREE.Vector4() },
666
+ inline3dCursorSoft: { value: new THREE.Vector4(0, 1, 0, 0) },
667
+ inline3dCursorFill: { value: new THREE.Vector3(this._fill[0], this._fill[1], this._fill[2]) },
668
+ inline3dCursorOutline: { value: new THREE.Vector3(CURSOR_OUTLINE_COLOR[0], CURSOR_OUTLINE_COLOR[1], CURSOR_OUTLINE_COLOR[2]) },
669
+ },
670
+ vertexShader: `
671
+ uniform vec4 inline3dCursorBox;
672
+ varying vec2 vArrow;
673
+ void main() {
674
+ vArrow = vec2(mix(inline3dCursorBox.x, inline3dCursorBox.z, position.x), mix(inline3dCursorBox.y, inline3dCursorBox.w, position.y));
675
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(vArrow.x, -vArrow.y, 0.0, 1.0);
676
+ }`,
677
+ fragmentShader: `
678
+ uniform vec4 inline3dCursorSoft; // radius, opacity, aa (arrow units)
679
+ uniform vec3 inline3dCursorFill;
680
+ uniform vec3 inline3dCursorOutline;
681
+ varying vec2 vArrow;
682
+ ${cursorSoftArrowGLSL()}
683
+ void main() {
684
+ vec4 c = inline3dSoftArrow(vArrow, inline3dCursorSoft.x, inline3dCursorSoft.z, inline3dCursorFill, inline3dCursorOutline);
685
+ gl_FragColor = vec4(c.rgb, c.a * inline3dCursorSoft.y);
686
+ #include <${chunk}>
687
+ }`,
688
+ transparent: true,
689
+ depthTest: false,
690
+ depthWrite: false,
691
+ side: THREE.DoubleSide,
692
+ toneMapped: false,
693
+ });
694
+ return { geometry, material };
695
+ }
696
+
576
697
  /** Remove listeners, give the CSS cursor back, free the sprite's GPU resources. */
577
698
  dispose() {
578
699
  this.pointer.dispose();
579
700
  this.object.visible = false;
580
- this.object.geometry.dispose();
581
- this.object.material.dispose();
701
+ for (const r of [this._crisp, this._soft]) {
702
+ if (!r) continue;
703
+ r.geometry.dispose();
704
+ r.material.dispose();
705
+ }
582
706
  }
583
707
 
584
708
  // Nearest content point under the footprint, from the two outer views (or, amortised, from
@@ -589,23 +713,21 @@ export class DepthCursor {
589
713
  const fl = Math.hypot(m[8], m[9], m[10]) || 1;
590
714
  const f = [-m[8] / fl, -m[9] / fl, -m[10] / fl];
591
715
  const fp = cursorArrowFootprint(u, v, height, this.pointer.aspect());
592
- let candidates;
593
716
  if (this.raysPerFrame > 0) {
594
- const ring = this._ring;
595
- ring.length = fp.length;
596
- for (let i = 0; i < this.raysPerFrame; i++) {
597
- const k = this._next++ % fp.length;
598
- const ray = cursorViewRay(a, fp[k][0], fp[k][1]);
599
- ring[k] = this.hitTest(ray.origin, ray.direction);
600
- }
601
- candidates = ring;
602
- } else {
603
- candidates = [];
604
- for (const [su, sv] of fp) {
605
- for (const view of [a, b]) {
606
- const ray = cursorViewRay(view, su, sv);
607
- candidates.push(this.hitTest(ray.origin, ray.direction));
608
- }
717
+ // Amortised: N rays a frame over the (point, eye) slots; the newest pointer position is
718
+ // placed this frame regardless, with the depth the pick has so far (CursorAmortisedPick).
719
+ const pick = (this._pick ||= new CursorAmortisedPick(this.raysPerFrame));
720
+ const eyes = [a, b];
721
+ return pick.step(fp, 2, (e, su, sv) => {
722
+ const ray = cursorViewRay(eyes[e], su, sv);
723
+ return this.hitTest(ray.origin, ray.direction);
724
+ }, f, this.pointer.aspect(), height);
725
+ }
726
+ const candidates = [];
727
+ for (const [su, sv] of fp) {
728
+ for (const view of [a, b]) {
729
+ const ray = cursorViewRay(view, su, sv);
730
+ candidates.push(this.hitTest(ray.origin, ray.direction));
609
731
  }
610
732
  }
611
733
  let best = Infinity, nearest = null;
@@ -0,0 +1,3 @@
1
+ /* three-mesh-bvh 0.9.15 (MeshBVH only) — MIT License, Copyright (c) 2018 Garrett Johnson — https://github.com/gkjohnson/three-mesh-bvh
2
+ * Vendored by @displayxr/inline3d for the depth cursor's pick; rebuilt by tools/vendor/three-mesh-bvh.mjs. Do not edit. */
3
+ import{Box3 as je}from"three";var ut=Math.pow(2,-24),Et=Symbol("SKIP_GENERATION"),Ht={strategy:0,maxDepth:40,targetLeafSize:10,useSharedArrayBuffer:!1,setBoundingBox:!0,onProgress:null,indirect:!1,verbose:!0,range:null,[Et]:!1};function C(i,t,n){return n.min.x=t[i],n.min.y=t[i+1],n.min.z=t[i+2],n.max.x=t[i+3],n.max.y=t[i+4],n.max.z=t[i+5],n}function bt(i){let t=-1,n=-1/0;for(let e=0;e<3;e++){let s=i[e+3]-i[e];s>n&&(n=s,t=e)}return t}function xn(i,t){t.set(i)}function hn(i,t,n){let e,s;for(let o=0;o<3;o++){let r=o+3;e=i[o],s=t[o],n[o]=e<s?e:s,e=i[r],s=t[r],n[r]=e>s?e:s}}function It(i,t,n){for(let e=0;e<3;e++){let s=t[i+2*e],o=t[i+2*e+1],r=s-o,l=s+o;r<n[e]&&(n[e]=r),l>n[e+3]&&(n[e+3]=l)}}function pt(i){let t=i[3]-i[0],n=i[4]-i[1],e=i[5]-i[2];return 2*(t*n+n*e+e*t)}function L(i,t){return t[i+15]===65535}function U(i,t){return t[i+6]}function O(i,t){return t[i+14]}function v(i){return i+8}function R(i,t){let n=t[i+6];return i+n*8}function mt(i,t){return t[i+7]}function qt(i,t,n,e,s){let o=1/0,r=1/0,l=1/0,c=-1/0,p=-1/0,u=-1/0,a=1/0,f=1/0,m=1/0,T=-1/0,w=-1/0,A=-1/0,g=i.offset||0;for(let y=(t-g)*6,x=(t+n-g)*6;y<x;y+=6){let d=i[y+0],h=i[y+1],_=d-h,B=d+h;_<o&&(o=_),B>c&&(c=B),d<a&&(a=d),d>T&&(T=d);let E=i[y+2],b=i[y+3],P=E-b,I=E+b;P<r&&(r=P),I>p&&(p=I),E<f&&(f=E),E>w&&(w=E);let S=i[y+4],N=i[y+5],F=S-N,D=S+N;F<l&&(l=F),D>u&&(u=D),S<m&&(m=S),S>A&&(A=S)}e[0]=o,e[1]=r,e[2]=l,e[3]=c,e[4]=p,e[5]=u,s[0]=a,s[1]=f,s[2]=m,s[3]=T,s[4]=w,s[5]=A}var J=32,Ge=(i,t)=>i.candidate-t.candidate,tt=new Array(J).fill().map(()=>({count:0,bounds:new Float32Array(6),rightCacheBounds:new Float32Array(6),leftCacheBounds:new Float32Array(6),candidate:0})),kt=new Float32Array(6);function Yn(i,t,n,e,s,o){let r=-1,l=0;if(o===0)r=bt(t),r!==-1&&(l=(t[r]+t[r+3])/2);else if(o===1)r=bt(i),r!==-1&&(l=Ze(n,e,s,r));else if(o===2){let c=pt(i),p=1.25*s,u=n.offset||0,a=(e-u)*6,f=(e+s-u)*6;for(let m=0;m<3;m++){let T=t[m],g=(t[m+3]-T)/J;if(s<J/4){let y=[...tt];y.length=s;let x=0;for(let h=a;h<f;h+=6,x++){let _=y[x];_.candidate=n[h+2*m],_.count=0;let{bounds:B,leftCacheBounds:E,rightCacheBounds:b}=_;for(let P=0;P<3;P++)b[P]=1/0,b[P+3]=-1/0,E[P]=1/0,E[P+3]=-1/0,B[P]=1/0,B[P+3]=-1/0;It(h,n,B)}y.sort(Ge);let d=s;for(let h=0;h<d;h++){let _=y[h];for(;h+1<d&&y[h+1].candidate===_.candidate;)y.splice(h+1,1),d--}for(let h=a;h<f;h+=6){let _=n[h+2*m];for(let B=0;B<d;B++){let E=y[B];_>=E.candidate?It(h,n,E.rightCacheBounds):(It(h,n,E.leftCacheBounds),E.count++)}}for(let h=0;h<d;h++){let _=y[h],B=_.count,E=s-_.count,b=_.leftCacheBounds,P=_.rightCacheBounds,I=0;B!==0&&(I=pt(b)/c);let S=0;E!==0&&(S=pt(P)/c);let N=1+1.25*(I*B+S*E);N<p&&(r=m,p=N,l=_.candidate)}}else{for(let d=0;d<J;d++){let h=tt[d];h.count=0,h.candidate=T+g+d*g;let _=h.bounds;for(let B=0;B<3;B++)_[B]=1/0,_[B+3]=-1/0}for(let d=a;d<f;d+=6){let B=~~((n[d+2*m]-T)/g);B>=J&&(B=J-1);let E=tt[B];E.count++,It(d,n,E.bounds)}let y=tt[J-1];xn(y.bounds,y.rightCacheBounds);for(let d=J-2;d>=0;d--){let h=tt[d],_=tt[d+1];hn(h.bounds,_.rightCacheBounds,h.rightCacheBounds)}let x=0;for(let d=0;d<J-1;d++){let h=tt[d],_=h.count,B=h.bounds,b=tt[d+1].rightCacheBounds;_!==0&&(x===0?xn(B,kt):hn(B,kt,kt)),x+=_;let P=0,I=0;x!==0&&(P=pt(kt)/c);let S=s-x;S!==0&&(I=pt(b)/c);let N=1+1.25*(P*x+I*S);N<p&&(r=m,p=N,l=h.candidate)}}}}else console.warn(`BVH: Invalid build strategy value ${o} used.`);return{axis:r,pos:l}}function Ze(i,t,n,e){let s=0,o=i.offset;for(let r=t,l=t+n;r<l;r++)s+=i[(r-o)*6+e*2];return s/n}var yt=class{constructor(){this.boundingData=new Float32Array(6)}};function Gn(i,t,n,e,s,o){let r=e,l=e+s-1,c=o.pos,p=o.axis*2,u=n.offset||0;for(;;){for(;r<=l&&n[(r-u)*6+p]<c;)r++;for(;r<=l&&n[(l-u)*6+p]>=c;)l--;if(r<l){for(let a=0;a<t;a++){let f=i[r*t+a];i[r*t+a]=i[l*t+a],i[l*t+a]=f}for(let a=0;a<6;a++){let f=r-u,m=l-u,T=n[f*6+a];n[f*6+a]=n[m*6+a],n[m*6+a]=T}r++,l--}else return r}}var Zn,Xt,Tn,Kn,Ke=Math.pow(2,32);function Yt(i){return"count"in i?1:1+Yt(i.left)+Yt(i.right)}function Wn(i,t,n){return Zn=new Float32Array(n),Xt=new Uint32Array(n),Tn=new Uint16Array(n),Kn=new Uint8Array(n),An(i,t)}function An(i,t){let n=i/4,e=i/2,s="count"in t,o=t.boundingData;for(let r=0;r<6;r++)Zn[n+r]=o[r];if(s)return t.buffer?(Kn.set(new Uint8Array(t.buffer),i),i+t.buffer.byteLength):(Xt[n+6]=t.offset,Tn[e+14]=t.count,Tn[e+15]=65535,i+32);{let{left:r,right:l,splitAxis:c}=t,p=i+32,u=An(p,r),a=i/32,m=u/32-a;if(m>Ke)throw new Error("MeshBVH: Cannot store relative child node offset greater than 32 bits.");return Xt[n+6]=m,Xt[n+7]=c,An(u,l)}}function We(i,t,n,e,s,o){let{maxDepth:r,verbose:l,targetLeafSize:c,_strictLeafSize:p=1/0,strategy:u,onProgress:a}=s,f=i.primitiveBuffer,m=i.primitiveBufferStride,T=new Float32Array(6),w=!1,A=new yt;return qt(t,n,e,A.boundingData,T),y(A,n,e,T),A;function g(x){a&&a((x-o.offset)/o.count)}function y(x,d,h,_=null,B=0){!w&&B>=r&&(w=!0,l&&console.warn(`BVH: Max depth of ${r} reached when generating BVH. Consider increasing maxDepth.`));let E=h>p;if(h<=c&&!E||B>=r)return g(d+h),x.offset=d,x.count=h,x;let b=Yn(x.boundingData,_,t,d,h,u),P=b.axis===-1?-1:Gn(f,m,t,d,h,b);if(b.axis===-1||P===d||P===d+h){if(!E)return g(d+h),x.offset=d,x.count=h,x;b.axis=Math.max(0,bt(x.boundingData)),P=d+Math.max(1,Math.floor(h/2))}x.splitAxis=b.axis;let I=new yt,S=d,N=P-d;x.left=I,qt(t,S,N,I.boundingData,T),y(I,S,N,T,B+1);let F=new yt,D=P,z=h-N;return x.right=F,qt(t,D,z,F.boundingData,T),y(F,D,z,T,B+1),x}}function $n(i,t){let n=t.useSharedArrayBuffer?SharedArrayBuffer:ArrayBuffer,e=i.getRootRanges(t.range),s=e[0],o=e[e.length-1],r={offset:s.offset,count:o.offset+o.count-s.offset},l=new Float32Array(6*r.count);l.offset=r.offset,i.computePrimitiveBounds(r.offset,r.count,l),i._roots=e.map(c=>{let p=We(i,l,c.offset,c.count,t,r),u=Yt(p),a=new n(32*u);return Wn(0,p,a),a})}import{Box3 as Qe}from"three";var nt=class{constructor(t){this._getNewPrimitive=t,this._primitives=[]}getPrimitive(){let t=this._primitives;return t.length===0?this._getNewPrimitive():t.pop()}releasePrimitive(t){this._primitives.push(t)}};var wn=class{constructor(){this.float32Array=null,this.uint16Array=null,this.uint32Array=null;let t=[],n=null;this.setBuffer=e=>{n&&t.push(n),n=e,this.float32Array=new Float32Array(e),this.uint16Array=new Uint16Array(e),this.uint32Array=new Uint32Array(e)},this.clearBuffer=()=>{n=null,this.float32Array=null,this.uint16Array=null,this.uint32Array=null,t.length!==0&&this.setBuffer(t.pop())}}},M=new wn;var et,xt,dt=[],Gt=new nt(()=>new Qe);function Qn(i,t,n,e,s,o){et=Gt.getPrimitive(),xt=Gt.getPrimitive(),dt.push(et,xt),M.setBuffer(i._roots[t]);let r=gn(0,i.geometry,n,e,s,o);M.clearBuffer(),Gt.releasePrimitive(et),Gt.releasePrimitive(xt),dt.pop(),dt.pop();let l=dt.length;return l>0&&(xt=dt[l-1],et=dt[l-2]),r}function gn(i,t,n,e,s=null,o=0,r=0){let{float32Array:l,uint16Array:c,uint32Array:p}=M,u=i*2;if(L(u,c)){let f=U(i,p),m=O(u,c);return C(i,l,et),e(f,m,!1,r,o+i/8,et)}else{let P=function(S){let{uint16Array:N,uint32Array:F}=M,D=S*2;for(;!L(D,N);)S=v(S),D=S*2;return U(S,F)},I=function(S){let{uint16Array:N,uint32Array:F}=M,D=S*2;for(;!L(D,N);)S=R(S,F),D=S*2;return U(S,F)+O(D,N)},f=v(i),m=R(i,p),T=f,w=m,A,g,y,x;if(s&&(y=et,x=xt,C(T,l,y),C(w,l,x),A=s(y),g=s(x),g<A)){T=m,w=f;let S=A;A=g,g=S,y=x}y||(y=et,C(T,l,y));let d=L(T*2,c),h=n(y,d,A,r+1,o+T/8),_;if(h===2){let S=P(T),F=I(T)-S;_=e(S,F,!0,r+1,o+T/8,y)}else _=h&&gn(T,t,n,e,s,o,r+1);if(_)return!0;x=xt,C(w,l,x);let B=L(w*2,c),E=n(x,B,g,r+1,o+w/8),b;if(E===2){let S=P(w),F=I(w)-S;b=e(S,F,!0,r+1,o+w/8,x)}else b=E&&gn(w,t,n,e,s,o,r+1);return!!b}}import{Box3 as Ft,Matrix4 as Je}from"three";var Nt=new M.constructor,Zt=new M.constructor,it=new nt(()=>new Ft),ht=new Ft,Tt=new Ft,Pn=new Ft,Sn=new Ft,_n=!1;function Jn(i,t,n,e){if(_n)throw new Error("MeshBVH: Recursive calls to bvhcast not supported.");_n=!0;let s=i._roots,o=t._roots,r,l=0,c=0,p=new Je().copy(n).invert();for(let u=0,a=s.length;u<a;u++){Nt.setBuffer(s[u]),c=0;let f=it.getPrimitive();C(0,Nt.float32Array,f),f.applyMatrix4(p);for(let m=0,T=o.length;m<T&&(Zt.setBuffer(o[m]),r=W(0,0,n,p,e,l,c,0,0,f),Zt.clearBuffer(),c+=o[m].byteLength/32,!r);m++);if(it.releasePrimitive(f),Nt.clearBuffer(),l+=s[u].byteLength/32,r)break}return _n=!1,r}function W(i,t,n,e,s,o=0,r=0,l=0,c=0,p=null,u=!1){let a,f;u?(a=Zt,f=Nt):(a=Nt,f=Zt);let m=a.float32Array,T=a.uint32Array,w=a.uint16Array,A=f.float32Array,g=f.uint32Array,y=f.uint16Array,x=i*2,d=t*2,h=L(x,w),_=L(d,y),B=!1;if(_&&h)u?B=s(U(t,g),O(t*2,y),U(i,T),O(i*2,w),c,r+t/8,l,o+i/8):B=s(U(i,T),O(i*2,w),U(t,g),O(t*2,y),l,o+i/8,c,r+t/8);else if(_){let E=it.getPrimitive();C(t,A,E),E.applyMatrix4(n);let b=v(i),P=R(i,T);C(b,m,ht),C(P,m,Tt);let I=E.intersectsBox(ht),S=E.intersectsBox(Tt);B=I&&W(t,b,e,n,s,r,o,c,l+1,E,!u)||S&&W(t,P,e,n,s,r,o,c,l+1,E,!u),it.releasePrimitive(E)}else{let E=v(t),b=R(t,g);C(E,A,Pn),C(b,A,Sn);let P=p.intersectsBox(Pn),I=p.intersectsBox(Sn);if(P&&I)B=W(i,E,n,e,s,o,r,l,c+1,p,u)||W(i,b,n,e,s,o,r,l,c+1,p,u);else if(P)if(h)B=W(i,E,n,e,s,o,r,l,c+1,p,u);else{let S=it.getPrimitive();S.copy(Pn).applyMatrix4(n);let N=v(i),F=R(i,T);C(N,m,ht),C(F,m,Tt);let D=S.intersectsBox(ht),z=S.intersectsBox(Tt);B=D&&W(E,N,e,n,s,r,o,c,l+1,S,!u)||z&&W(E,F,e,n,s,r,o,c,l+1,S,!u),it.releasePrimitive(S)}else if(I)if(h)B=W(i,b,n,e,s,o,r,l,c+1,p,u);else{let S=it.getPrimitive();S.copy(Sn).applyMatrix4(n);let N=v(i),F=R(i,T);C(N,m,ht),C(F,m,Tt);let D=S.intersectsBox(ht),z=S.intersectsBox(Tt);B=D&&W(b,N,e,n,s,r,o,c,l+1,S,!u)||z&&W(b,F,e,n,s,r,o,c,l+1,S,!u),it.releasePrimitive(S)}}return B}var Kt=new class{constructor(){let i=null,t=null,n=null,e=!1;this.root=null,this.buffer=null,this.uint32Array=null,this.uint16Array=null,this.setBVH=(o,r)=>{if(e)throw new Error("BVHTraversalHelper: cannot call setBVH during an active traversal.");this.root=r,this.buffer=i=o._roots[r],this.uint16Array=n=new Uint16Array(i),this.uint32Array=t=new Uint32Array(i)},this.reset=()=>{this.root=null,this.buffer=i=null,this.uint16Array=n=null,this.uint32Array=t=null},this.getRangeStart=o=>{let r=o*2;for(;!L(r,n);)o=v(o),r=o*2;return U(o,t)},this.getRangeEnd=o=>{let r=o*2;for(;!L(r,n);)o=R(o,t),r=o*2;return U(o,t)+O(r,n)};let s=(o,r,l)=>{let c=r*2,p=L(c,n);if(!o(l,p,r)&&!p){let a=v(r),f=R(r,t);s(o,a,l+1),s(o,f,l+1)}};this.traverseBuffer=o=>{if(e)throw new Error("BVHTraversalHelper: cannot start a traversal during an active traversal.");e=!0;try{s(o,0,0)}finally{e=!1}},this.traverse=o=>{this.traverseBuffer((r,l,c)=>{if(l){let p=c*2,u=t[c+6],a=n[p+14];return o(r,l,new Float32Array(i,c*4,6),u,a)}else{let p=mt(c,t);return o(r,l,new Float32Array(i,c*4,6),p)}})}}};var jn=new je,At=new Float32Array(6),Wt=class{constructor(){this._roots=null,this.primitiveBuffer=null,this.primitiveBufferStride=null}init(t){t={...Ht,...t},"maxLeafSize"in t&&(console.warn('BVH: "maxLeafSize" option has been deprecated. Use "targetLeafSize", instead.'),t={...t,targetLeafSize:t.maxLeafSize}),$n(this,t)}getRootRanges(){throw new Error("BVH: getRootRanges() not implemented")}writePrimitiveBounds(){throw new Error("BVH: writePrimitiveBounds() not implemented")}writePrimitiveRangeBounds(t,n,e,s){let o=1/0,r=1/0,l=1/0,c=-1/0,p=-1/0,u=-1/0;for(let a=t,f=t+n;a<f;a++){this.writePrimitiveBounds(a,At,0);let[m,T,w,A,g,y]=At;m<o&&(o=m),A>c&&(c=A),T<r&&(r=T),g>p&&(p=g),w<l&&(l=w),y>u&&(u=y)}return e[s+0]=o,e[s+1]=r,e[s+2]=l,e[s+3]=c,e[s+4]=p,e[s+5]=u,e}computePrimitiveBounds(t,n,e){let s=e.offset||0;for(let o=t,r=t+n;o<r;o++){this.writePrimitiveBounds(o,At,0);let[l,c,p,u,a,f]=At,m=(l+u)/2,T=(c+a)/2,w=(p+f)/2,A=(u-l)/2,g=(a-c)/2,y=(f-p)/2,x=(o-s)*6;e[x+0]=m,e[x+1]=A+(Math.abs(m)+A)*ut,e[x+2]=T,e[x+3]=g+(Math.abs(T)+g)*ut,e[x+4]=w,e[x+5]=y+(Math.abs(w)+y)*ut}return e}shiftPrimitiveOffsets(t){let n=this._indirectBuffer;if(n)for(let e=0,s=n.length;e<s;e++)n[e]+=t;else{let e=this._roots;for(let s=0;s<e.length;s++){let o=e[s],r=new Uint32Array(o),l=new Uint16Array(o),c=o.byteLength/32;for(let p=0;p<c;p++){let u=8*p,a=2*u;L(a,l)&&(r[u+6]+=t)}}}}traverse(t,n=0){Kt.setBVH(this,n),Kt.traverse(t),Kt.reset()}refit(){let t=this._roots;for(let n=0,e=t.length;n<e;n++){let s=t[n],o=new Uint32Array(s),r=new Uint16Array(s),l=new Float32Array(s),c=s.byteLength/32;for(let p=c-1;p>=0;p--){let u=p*8,a=u*2;if(L(a,r)){let m=U(u,o),T=O(a,r);this.writePrimitiveRangeBounds(m,T,At,0),l.set(At,u)}else{let m=v(u),T=R(u,o);for(let w=0;w<3;w++){let A=l[m+w],g=l[m+w+3],y=l[T+w],x=l[T+w+3];l[u+w]=A<y?A:y,l[u+w+3]=g>x?g:x}}}}}getBoundingBox(t){return t.makeEmpty(),this._roots.forEach(e=>{C(0,new Float32Array(e),jn),t.union(jn)}),t}shapecast(t){let{boundsTraverseOrder:n,intersectsBounds:e,intersectsRange:s,intersectsPrimitive:o,scratchPrimitive:r,iterate:l}=t;if(s&&o){let a=s;s=(f,m,T,w,A)=>a(f,m,T,w,A)?!0:l(f,m,this,o,T,w,r)}else s||(o?s=(a,f,m,T)=>l(a,f,this,o,m,T,r):s=(a,f,m)=>m);let c=!1,p=0,u=this._roots;for(let a=0,f=u.length;a<f;a++){let m=u[a];if(c=Qn(this,a,e,s,n,p),c)break;p+=m.byteLength/32}return c}bvhcast(t,n,e){let{intersectsRanges:s}=e;return Jn(this,t,n,s)}};import{Box3 as si}from"three";function te(){return typeof SharedArrayBuffer<"u"}import{BufferAttribute as ti}from"three";function En(i){return i.index?i.index.count:i.attributes.position.count}function st(i){return En(i)/3}function ni(i,t=ArrayBuffer){return i>65535?new Uint32Array(new t(4*i)):new Uint16Array(new t(2*i))}function ne(i,t){if(!i.index){let n=i.attributes.position.count,e=t.useSharedArrayBuffer?SharedArrayBuffer:ArrayBuffer,s=ni(n,e);i.setIndex(new ti(s,1));for(let o=0;o<n;o++)s[o]=o}}function ei(i,t,n){let e=En(i)/n,s=t||i.drawRange,o=s.start/n,r=(s.start+s.count)/n,l=Math.max(0,o),c=Math.min(e,r)-l;return{offset:Math.floor(l),count:Math.floor(c)}}function ii(i,t){return i.groups.map(n=>({offset:n.start/t,count:n.count/t}))}function bn(i,t,n){let e=ei(i,t,n),s=ii(i,n);if(!s.length)return[e];let o=[],r=e.offset,l=e.offset+e.count,c=En(i)/n,p=[];for(let f of s){let{offset:m,count:T}=f,w=m,A=isFinite(T)?T:c-m,g=m+A;w<l&&g>r&&(p.push({pos:Math.max(r,w),isStart:!0}),p.push({pos:Math.min(l,g),isStart:!1}))}p.sort((f,m)=>f.pos!==m.pos?f.pos-m.pos:f.type==="end"?-1:1);let u=0,a=null;for(let f of p){let m=f.pos;u!==0&&m!==a&&o.push({offset:a,count:m-a}),u+=f.isStart?1:-1,a=m}return o}function ri(i,t){let n=i[i.length-1],e=n.offset+n.count>2**16,s=i.reduce((p,u)=>p+u.count,0),o=e?4:2,r=t?new SharedArrayBuffer(s*o):new ArrayBuffer(s*o),l=e?new Uint32Array(r):new Uint16Array(r),c=0;for(let p=0;p<i.length;p++){let{offset:u,count:a}=i[p];for(let f=0;f<a;f++)l[c+f]=u+f;c+=a}return l}var $t=class extends Wt{get indirect(){return!!this._indirectBuffer}get primitiveStride(){return null}get primitiveBufferStride(){return this.indirect?1:this.primitiveStride}set primitiveBufferStride(t){}get primitiveBuffer(){return this.indirect?this._indirectBuffer:this.geometry.index.array}set primitiveBuffer(t){}constructor(t,n={}){if(t.isBufferGeometry){if(t.index&&t.index.isInterleavedBufferAttribute)throw new Error("BVH: InterleavedBufferAttribute is not supported for the index attribute.")}else throw new Error("BVH: Only BufferGeometries are supported.");if(n.useSharedArrayBuffer&&!te())throw new Error("BVH: SharedArrayBuffer is not available.");super(),this.geometry=t,this.resolvePrimitiveIndex=n.indirect?e=>this._indirectBuffer[e]:e=>e,this.primitiveBuffer=null,this.primitiveBufferStride=null,this._indirectBuffer=null,n={...Ht,...n},n[Et]||this.init(n)}init(t){let{geometry:n,primitiveStride:e}=this;if(t.indirect){let s=bn(n,t.range,e),o=ri(s,t.useSharedArrayBuffer);this._indirectBuffer=o}else ne(n,t);super.init(t),!n.boundingBox&&t.setBoundingBox&&(n.boundingBox=this.getBoundingBox(new si))}getRootRanges(t){return this.indirect?[{offset:0,count:this._indirectBuffer.length}]:bn(this.geometry,t,this.primitiveStride)}raycastObject3D(){throw new Error("BVH: raycastObject3D() not implemented")}};import{BufferAttribute as vi,FrontSide as Me,Ray as Ri,Vector3 as Oe,Matrix4 as Ui}from"three";import{Vector3 as rt,Matrix4 as re,Line3 as oe}from"three";import{Vector3 as oi}from"three";var G=class{constructor(){this.min=1/0,this.max=-1/0}setFromPointsField(t,n){let e=1/0,s=-1/0;for(let o=0,r=t.length;o<r;o++){let c=t[o][n];e=c<e?c:e,s=c>s?c:s}this.min=e,this.max=s}setFromPoints(t,n){let e=1/0,s=-1/0;for(let o=0,r=n.length;o<r;o++){let l=n[o],c=t.dot(l);e=c<e?c:e,s=c>s?c:s}this.min=e,this.max=s}isSeparated(t){return this.min>t.max||t.min>this.max}};G.prototype.setFromBox=(function(){let i=new oi;return function(n,e){let s=e.min,o=e.max,r=1/0,l=-1/0;for(let c=0;c<=1;c++)for(let p=0;p<=1;p++)for(let u=0;u<=1;u++){i.x=s.x*c+o.x*(1-c),i.y=s.y*p+o.y*(1-p),i.z=s.z*u+o.z*(1-u);let a=n.dot(i);r=Math.min(a,r),l=Math.max(a,l)}this.min=r,this.max=l}})();import{Triangle as ui,Vector3 as $,Vector2 as ie,Line3 as wt,Plane as pi}from"three";import{Vector3 as ot,Vector2 as ci,Plane as li,Line3 as fi}from"three";var ai=(function(){let i=new ot,t=new ot,n=new ot;return function(s,o,r){let l=s.start,c=i,p=o.start,u=t;n.subVectors(l,p),i.subVectors(s.end,s.start),t.subVectors(o.end,o.start);let a=n.dot(u),f=u.dot(c),m=u.dot(u),T=n.dot(c),A=c.dot(c)*m-f*f,g,y;A!==0?g=(a*f-T*m)/A:g=0,y=(a+g*f)/m,r.x=g,r.y=y}})(),Dt=(function(){let i=new ci,t=new ot,n=new ot;return function(s,o,r,l){ai(s,o,i);let c=i.x,p=i.y;if(c>=0&&c<=1&&p>=0&&p<=1){s.at(c,r),o.at(p,l);return}else if(c>=0&&c<=1){p<0?o.at(0,l):o.at(1,l),s.closestPointToPoint(l,!0,r);return}else if(p>=0&&p<=1){c<0?s.at(0,r):s.at(1,r),o.closestPointToPoint(r,!0,l);return}else{let u;c<0?u=s.start:u=s.end;let a;p<0?a=o.start:a=o.end;let f=t,m=n;if(s.closestPointToPoint(a,!0,t),o.closestPointToPoint(u,!0,n),f.distanceToSquared(a)<=m.distanceToSquared(u)){r.copy(f),l.copy(a);return}else{r.copy(u),l.copy(m);return}}}})(),ee=(function(){let i=new ot,t=new ot,n=new li,e=new fi;return function(o,r){let{radius:l,center:c}=o,{a:p,b:u,c:a}=r;if(e.start=p,e.end=u,e.closestPointToPoint(c,!0,i).distanceTo(c)<=l||(e.start=p,e.end=a,e.closestPointToPoint(c,!0,i).distanceTo(c)<=l)||(e.start=u,e.end=a,e.closestPointToPoint(c,!0,i).distanceTo(c)<=l))return!0;let w=r.getPlane(n);if(Math.abs(w.distanceToPoint(c))<=l){let g=w.projectPoint(c,t);if(r.containsPoint(g))return!0}return!1}})();var mi=["x","y","z"],j=1e-15,se=j*j;function Z(i){return Math.abs(i)<j}var k=class extends ui{constructor(...t){super(...t),this.isExtendedTriangle=!0,this.satAxes=new Array(4).fill().map(()=>new $),this.satBounds=new Array(4).fill().map(()=>new G),this.points=[this.a,this.b,this.c],this.plane=new pi,this.isDegenerateIntoSegment=!1,this.isDegenerateIntoPoint=!1,this.degenerateSegment=new wt,this.needsUpdate=!0}intersectsSphere(t){return ee(t,this)}update(){let t=this.a,n=this.b,e=this.c,s=this.points,o=this.satAxes,r=this.satBounds,l=o[0],c=r[0];this.getNormal(l),c.setFromPoints(l,s);let p=o[1],u=r[1];p.subVectors(t,n),u.setFromPoints(p,s);let a=o[2],f=r[2];a.subVectors(n,e),f.setFromPoints(a,s);let m=o[3],T=r[3];m.subVectors(e,t),T.setFromPoints(m,s);let w=p.length(),A=a.length(),g=m.length();this.isDegenerateIntoPoint=!1,this.isDegenerateIntoSegment=!1,w<j?A<j||g<j?this.isDegenerateIntoPoint=!0:(this.isDegenerateIntoSegment=!0,this.degenerateSegment.start.copy(t),this.degenerateSegment.end.copy(e)):A<j?g<j?this.isDegenerateIntoPoint=!0:(this.isDegenerateIntoSegment=!0,this.degenerateSegment.start.copy(n),this.degenerateSegment.end.copy(t)):g<j&&(this.isDegenerateIntoSegment=!0,this.degenerateSegment.start.copy(e),this.degenerateSegment.end.copy(n)),this.plane.setFromNormalAndCoplanarPoint(l,t),this.needsUpdate=!1}};k.prototype.closestPointToSegment=(function(){let i=new $,t=new $,n=new wt;return function(s,o=null,r=null){let{start:l,end:c}=s,p=this.points,u,a=1/0;for(let f=0;f<3;f++){let m=(f+1)%3;n.start.copy(p[f]),n.end.copy(p[m]),Dt(n,s,i,t),u=i.distanceToSquared(t),u<a&&(a=u,o&&o.copy(i),r&&r.copy(t))}return this.closestPointToPoint(l,i),u=l.distanceToSquared(i),u<a&&(a=u,o&&o.copy(i),r&&r.copy(l)),this.closestPointToPoint(c,i),u=c.distanceToSquared(i),u<a&&(a=u,o&&o.copy(i),r&&r.copy(c)),Math.sqrt(a)}})();k.prototype.intersectsTriangle=(function(){let i=new k,t=new G,n=new G,e=new $,s=new $,o=new $,r=new $,l=new wt,c=new wt,p=new $,u=new ie,a=new ie;function f(x,d,h,_){let B=e;!x.isDegenerateIntoPoint&&!x.isDegenerateIntoSegment?B.copy(x.plane.normal):B.copy(d.plane.normal);let E=x.satBounds,b=x.satAxes;for(let S=1;S<4;S++){let N=E[S],F=b[S];if(t.setFromPoints(F,d.points),N.isSeparated(t)||(r.copy(B).cross(F),t.setFromPoints(r,x.points),n.setFromPoints(r,d.points),t.isSeparated(n)))return!1}let P=d.satBounds,I=d.satAxes;for(let S=1;S<4;S++){let N=P[S],F=I[S];if(t.setFromPoints(F,x.points),N.isSeparated(t)||(r.crossVectors(B,F),t.setFromPoints(r,x.points),n.setFromPoints(r,d.points),t.isSeparated(n)))return!1}return h&&(_||console.warn("ExtendedTriangle.intersectsTriangle: Triangles are coplanar which does not support an output edge. Setting edge to 0, 0, 0."),h.start.set(0,0,0),h.end.set(0,0,0)),!0}function m(x,d,h,_,B,E,b,P,I,S,N){let F=b/(b-P);S.x=_+(B-_)*F,N.start.subVectors(d,x).multiplyScalar(F).add(x),F=b/(b-I),S.y=_+(E-_)*F,N.end.subVectors(h,x).multiplyScalar(F).add(x)}function T(x,d,h,_,B,E,b,P,I,S,N){if(B>0)m(x.c,x.a,x.b,_,d,h,I,b,P,S,N);else if(E>0)m(x.b,x.a,x.c,h,d,_,P,b,I,S,N);else if(P*I>0||b!=0)m(x.a,x.b,x.c,d,h,_,b,P,I,S,N);else if(P!=0)m(x.b,x.a,x.c,h,d,_,P,b,I,S,N);else if(I!=0)m(x.c,x.a,x.b,_,d,h,I,b,P,S,N);else return!0;return!1}function w(x,d,h,_){let B=d.degenerateSegment,E=x.plane.distanceToPoint(B.start),b=x.plane.distanceToPoint(B.end);return Z(E)?Z(b)?f(x,d,h,_):(h&&(h.start.copy(B.start),h.end.copy(B.start)),x.containsPoint(B.start)):Z(b)?(h&&(h.start.copy(B.end),h.end.copy(B.end)),x.containsPoint(B.end)):x.plane.intersectLine(B,e)!=null?(h&&(h.start.copy(e),h.end.copy(e)),x.containsPoint(e)):!1}function A(x,d,h){let _=d.a;return Z(x.plane.distanceToPoint(_))&&x.containsPoint(_)?(h&&(h.start.copy(_),h.end.copy(_)),!0):!1}function g(x,d,h){let _=x.degenerateSegment,B=d.a;return _.closestPointToPoint(B,!0,e),B.distanceToSquared(e)<se?(h&&(h.start.copy(B),h.end.copy(B)),!0):!1}function y(x,d,h,_){if(x.isDegenerateIntoSegment)if(d.isDegenerateIntoSegment){let B=x.degenerateSegment,E=d.degenerateSegment,b=s,P=o;B.delta(b),E.delta(P);let I=e.subVectors(E.start,B.start),S=b.x*P.y-b.y*P.x;if(Z(S))return!1;let N=(I.x*P.y-I.y*P.x)/S,F=-(b.x*I.y-b.y*I.x)/S;if(N<0||N>1||F<0||F>1)return!1;let D=B.start.z+b.z*N,z=E.start.z+P.z*F;return Z(D-z)?(h&&(h.start.copy(B.start).addScaledVector(b,N),h.end.copy(B.start).addScaledVector(b,N)),!0):!1}else return d.isDegenerateIntoPoint?g(x,d,h):w(d,x,h,_);else{if(x.isDegenerateIntoPoint)return d.isDegenerateIntoPoint?d.a.distanceToSquared(x.a)<se?(h&&(h.start.copy(x.a),h.end.copy(x.a)),!0):!1:d.isDegenerateIntoSegment?g(d,x,h):A(d,x,h);if(d.isDegenerateIntoPoint)return A(x,d,h);if(d.isDegenerateIntoSegment)return w(x,d,h,_)}}return function(d,h=null,_=!1){this.needsUpdate&&this.update(),d.isExtendedTriangle?d.needsUpdate&&d.update():(i.copy(d),i.update(),d=i);let B=y(this,d,h,_);if(B!==void 0)return B;let E=this.plane,b=d.plane,P=b.distanceToPoint(this.a),I=b.distanceToPoint(this.b),S=b.distanceToPoint(this.c);Z(P)&&(P=0),Z(I)&&(I=0),Z(S)&&(S=0);let N=P*I,F=P*S;if(N>0&&F>0)return!1;let D=E.distanceToPoint(d.a),z=E.distanceToPoint(d.b),zt=E.distanceToPoint(d.c);Z(D)&&(D=0),Z(z)&&(z=0),Z(zt)&&(zt=0);let Hn=D*z,qn=D*zt;if(Hn>0&&qn>0)return!1;s.copy(E.normal),o.copy(b.normal);let pn=s.cross(o),mn=0,yn=Math.abs(pn.x),kn=Math.abs(pn.y);kn>yn&&(yn=kn,mn=1),Math.abs(pn.z)>yn&&(mn=2);let at=mi[mn],Ce=this.a[at],Ve=this.b[at],ze=this.c[at],He=d.a[at],qe=d.b[at],ke=d.c[at];if(T(this,Ce,Ve,ze,N,F,P,I,S,u,l))return f(this,d,h,_);if(T(d,He,qe,ke,Hn,qn,D,z,zt,a,c))return f(this,d,h,_);if(u.y<u.x){let dn=u.y;u.y=u.x,u.x=dn,p.copy(l.start),l.start.copy(l.end),l.end.copy(p)}if(a.y<a.x){let dn=a.y;a.y=a.x,a.x=dn,p.copy(c.start),c.start.copy(c.end),c.end.copy(p)}return u.y<a.x||a.y<u.x?!1:(h&&(a.x>u.x?h.start.copy(c.start):h.start.copy(l.start),a.y<u.y?h.end.copy(c.end):h.end.copy(l.end)),!0)}})();k.prototype.distanceToPoint=(function(){let i=new $;return function(n){return this.closestPointToPoint(n,i),n.distanceTo(i)}})();k.prototype.distanceToTriangle=(function(){let i=new $,t=new $,n=["a","b","c"],e=new wt,s=new wt;return function(r,l=null,c=null){let p=l||c?e:null;if(this.intersectsTriangle(r,p,!0))return(l||c)&&(l&&p.getCenter(l),c&&p.getCenter(c)),0;let u=1/0;for(let a=0;a<3;a++){let f,m=n[a],T=r[m];this.closestPointToPoint(T,i),f=T.distanceToSquared(i),f<u&&(u=f,l&&l.copy(i),c&&c.copy(T));let w=this[m];r.closestPointToPoint(w,i),f=w.distanceToSquared(i),f<u&&(u=f,l&&l.copy(w),c&&c.copy(i))}for(let a=0;a<3;a++){let f=n[a],m=n[(a+1)%3];e.set(this[f],this[m]);for(let T=0;T<3;T++){let w=n[T],A=n[(T+1)%3];s.set(r[w],r[A]),Dt(e,s,i,t);let g=i.distanceToSquared(t);g<u&&(u=g,l&&l.copy(i),c&&c.copy(t))}}return Math.sqrt(u)}})();var H=class{constructor(t,n,e){this.isOrientedBox=!0,this.min=new rt,this.max=new rt,this.matrix=new re,this.invMatrix=new re,this.points=new Array(8).fill().map(()=>new rt),this.satAxes=new Array(3).fill().map(()=>new rt),this.satBounds=new Array(3).fill().map(()=>new G),this.alignedSatBounds=new Array(3).fill().map(()=>new G),this.needsUpdate=!1,t&&this.min.copy(t),n&&this.max.copy(n),e&&this.matrix.copy(e)}set(t,n,e){this.min.copy(t),this.max.copy(n),this.matrix.copy(e),this.needsUpdate=!0}copy(t){this.min.copy(t.min),this.max.copy(t.max),this.matrix.copy(t.matrix),this.needsUpdate=!0}};H.prototype.update=(function(){return function(){let t=this.matrix,n=this.min,e=this.max,s=this.points;for(let p=0;p<=1;p++)for(let u=0;u<=1;u++)for(let a=0;a<=1;a++){let f=1*p|2*u|4*a,m=s[f];m.x=p?e.x:n.x,m.y=u?e.y:n.y,m.z=a?e.z:n.z,m.applyMatrix4(t)}let o=this.satBounds,r=this.satAxes,l=s[0];for(let p=0;p<3;p++){let u=r[p],a=o[p],f=1<<p,m=s[f];u.subVectors(l,m),a.setFromPoints(u,s)}let c=this.alignedSatBounds;c[0].setFromPointsField(s,"x"),c[1].setFromPointsField(s,"y"),c[2].setFromPointsField(s,"z"),this.invMatrix.copy(this.matrix).invert(),this.needsUpdate=!1}})();H.prototype.intersectsBox=(function(){let i=new G;return function(n){this.needsUpdate&&this.update();let e=n.min,s=n.max,o=this.satBounds,r=this.satAxes,l=this.alignedSatBounds;if(i.min=e.x,i.max=s.x,l[0].isSeparated(i)||(i.min=e.y,i.max=s.y,l[1].isSeparated(i))||(i.min=e.z,i.max=s.z,l[2].isSeparated(i)))return!1;for(let c=0;c<3;c++){let p=r[c],u=o[c];if(i.setFromBox(p,n),u.isSeparated(i))return!1}return!0}})();H.prototype.intersectsTriangle=(function(){let i=new k,t=new Array(3),n=new G,e=new G,s=new rt;return function(r){this.needsUpdate&&this.update(),r.isExtendedTriangle?r.needsUpdate&&r.update():(i.copy(r),i.update(),r=i);let l=this.satBounds,c=this.satAxes;t[0]=r.a,t[1]=r.b,t[2]=r.c;for(let f=0;f<3;f++){let m=l[f],T=c[f];if(n.setFromPoints(T,t),m.isSeparated(n))return!1}let p=r.satBounds,u=r.satAxes,a=this.points;for(let f=0;f<3;f++){let m=p[f],T=u[f];if(n.setFromPoints(T,a),m.isSeparated(n))return!1}for(let f=0;f<3;f++){let m=c[f];for(let T=0;T<4;T++){let w=u[T];if(s.crossVectors(m,w),n.setFromPoints(s,t),e.setFromPoints(s,a),n.isSeparated(e))return!1}}return!0}})();H.prototype.closestPointToPoint=(function(){return function(t,n){return this.needsUpdate&&this.update(),n.copy(t).applyMatrix4(this.invMatrix).clamp(this.min,this.max).applyMatrix4(this.matrix),n}})();H.prototype.distanceToPoint=(function(){let i=new rt;return function(n){return this.closestPointToPoint(n,i),n.distanceTo(i)}})();H.prototype.distanceToBox=(function(){let i=["x","y","z"],t=new Array(12).fill().map(()=>new oe),n=new Array(12).fill().map(()=>new oe),e=new rt,s=new rt;return function(r,l=0,c=null,p=null){if(this.needsUpdate&&this.update(),this.intersectsBox(r))return(c||p)&&(r.getCenter(s),this.closestPointToPoint(s,e),r.closestPointToPoint(e,s),c&&c.copy(e),p&&p.copy(s)),0;let u=l*l,a=r.min,f=r.max,m=this.points,T=1/0;for(let A=0;A<8;A++){let g=m[A];s.copy(g).clamp(a,f);let y=g.distanceToSquared(s);if(y<T&&(T=y,c&&c.copy(g),p&&p.copy(s),y<u))return Math.sqrt(y)}let w=0;for(let A=0;A<3;A++)for(let g=0;g<=1;g++)for(let y=0;y<=1;y++){let x=(A+1)%3,d=(A+2)%3,h=g<<x|y<<d,_=1<<A|g<<x|y<<d,B=m[h],E=m[_];t[w].set(B,E);let P=i[A],I=i[x],S=i[d],N=n[w],F=N.start,D=N.end;F[P]=a[P],F[I]=g?a[I]:f[I],F[S]=y?a[S]:f[I],D[P]=f[P],D[I]=g?a[I]:f[I],D[S]=y?a[S]:f[I],w++}for(let A=0;A<=1;A++)for(let g=0;g<=1;g++)for(let y=0;y<=1;y++){s.x=A?f.x:a.x,s.y=g?f.y:a.y,s.z=y?f.z:a.z,this.closestPointToPoint(s,e);let x=s.distanceToSquared(e);if(x<T&&(T=x,c&&c.copy(e),p&&p.copy(s),x<u))return Math.sqrt(x)}for(let A=0;A<12;A++){let g=t[A];for(let y=0;y<12;y++){let x=n[y];Dt(g,x,e,s);let d=e.distanceToSquared(s);if(d<T&&(T=d,c&&c.copy(e),p&&p.copy(s),d<u))return Math.sqrt(d)}}return Math.sqrt(T)}})();var In=class extends nt{constructor(){super(()=>new k)}},Y=new In;import{Vector3 as ce}from"three";var Lt=new ce,Nn=new ce;function le(i,t,n={},e=0,s=1/0){let o=e*e,r=s*s,l=1/0,c=null;if(i.shapecast({boundsTraverseOrder:u=>(Lt.copy(t).clamp(u.min,u.max),Lt.distanceToSquared(t)),intersectsBounds:(u,a,f)=>f<l&&f<r,intersectsTriangle:(u,a)=>{u.closestPointToPoint(t,Lt);let f=t.distanceToSquared(Lt);return f<l&&(Nn.copy(Lt),l=f,c=a),f<o}}),l===1/0)return null;let p=Math.sqrt(l);return n.point?n.point.copy(Nn):n.point=Nn.clone(),n.distance=p,n.faceIndex=c,n}import{Vector3 as Q,Vector2 as Rt,Triangle as Mt,DoubleSide as yi,BackSide as di,REVISION as ye}from"three";var Qt=parseInt(ye)>=169,xi=parseInt(ye)<=161,ct=new Q,lt=new Q,ft=new Q,Jt=new Rt,jt=new Rt,tn=new Rt,fe=new Q,ae=new Q,ue=new Q,vt=new Q;function hi(i,t,n,e,s,o,r,l){let c;if(o===di?c=i.intersectTriangle(e,n,t,!0,s):c=i.intersectTriangle(t,n,e,o!==yi,s),c===null)return null;let p=i.origin.distanceTo(s);return p<r||p>l?null:{distance:p,point:s.clone()}}function pe(i,t,n,e,s,o,r,l,c,p,u){ct.fromBufferAttribute(t,o),lt.fromBufferAttribute(t,r),ft.fromBufferAttribute(t,l);let a=hi(i,ct,lt,ft,vt,c,p,u);if(a){if(e){Jt.fromBufferAttribute(e,o),jt.fromBufferAttribute(e,r),tn.fromBufferAttribute(e,l),a.uv=new Rt;let m=Mt.getInterpolation(vt,ct,lt,ft,Jt,jt,tn,a.uv);Qt||(a.uv=m)}if(s){Jt.fromBufferAttribute(s,o),jt.fromBufferAttribute(s,r),tn.fromBufferAttribute(s,l),a.uv1=new Rt;let m=Mt.getInterpolation(vt,ct,lt,ft,Jt,jt,tn,a.uv1);Qt||(a.uv1=m),xi&&(a.uv2=a.uv1)}if(n){fe.fromBufferAttribute(n,o),ae.fromBufferAttribute(n,r),ue.fromBufferAttribute(n,l),a.normal=new Q;let m=Mt.getInterpolation(vt,ct,lt,ft,fe,ae,ue,a.normal);a.normal.dot(i.direction)>0&&a.normal.multiplyScalar(-1),Qt||(a.normal=m)}let f={a:o,b:r,c:l,normal:new Q,materialIndex:0};if(Mt.getNormal(ct,lt,ft,f.normal),a.face=f,a.faceIndex=o,Qt){let m=new Q;Mt.getBarycoord(vt,ct,lt,ft,m),a.barycoord=m}}return a}function me(i){return i&&i.isMaterial?i.side:i}function gt(i,t,n,e,s,o,r){let l=e*3,c=l+0,p=l+1,u=l+2,{index:a,groups:f}=i;i.index&&(c=a.getX(c),p=a.getX(p),u=a.getX(u));let{position:m,normal:T,uv:w,uv1:A}=i.attributes;if(Array.isArray(t)){let g=e*3;for(let y=0,x=f.length;y<x;y++){let{start:d,count:h,materialIndex:_}=f[y];if(g>=d&&g<d+h){let B=me(t[_]),E=pe(n,m,T,w,A,c,p,u,B,o,r);if(E)if(E.faceIndex=e,E.face.materialIndex=_,s)s.push(E);else return E}}}else{let g=me(t),y=pe(n,m,T,w,A,c,p,u,g,o,r);if(y)if(y.faceIndex=e,y.face.materialIndex=0,s)s.push(y);else return y}return null}import{Vector2 as rr,Vector3 as or,Triangle as cr}from"three";function V(i,t,n,e){let s=i.a,o=i.b,r=i.c,l=t,c=t+1,p=t+2;n&&(l=n.getX(l),c=n.getX(c),p=n.getX(p)),s.x=e.getX(l),s.y=e.getY(l),s.z=e.getZ(l),o.x=e.getX(c),o.y=e.getY(c),o.z=e.getZ(c),r.x=e.getX(p),r.y=e.getY(p),r.z=e.getZ(p)}function de(i,t,n,e,s,o,r,l){let{geometry:c,_indirectBuffer:p}=i;for(let u=e,a=e+s;u<a;u++)gt(c,t,n,u,o,r,l)}function xe(i,t,n,e,s,o,r){let{geometry:l,_indirectBuffer:c}=i,p=1/0,u=null;for(let a=e,f=e+s;a<f;a++){let m;m=gt(l,t,n,a,null,o,r),m&&m.distance<p&&(u=m,p=m.distance)}return u}function he(i,t,n,e,s,o,r){let{geometry:l}=n,{index:c}=l,p=l.attributes.position;for(let u=i,a=t+i;u<a;u++){let f;if(f=u,V(r,f*3,c,p),r.needsUpdate=!0,e(r,f,s,o))return!0}return!1}function Te(i,t=null){t&&Array.isArray(t)&&(t=new Set(t));let n=i.geometry,e=n.index?n.index.array:null,s=n.attributes.position,o,r,l,c,p=0,u=i._roots;for(let f=0,m=u.length;f<m;f++)o=u[f],r=new Uint32Array(o),l=new Uint16Array(o),c=new Float32Array(o),a(0,p),p+=o.byteLength;function a(f,m,T=!1){let w=f*2;if(L(w,l)){let A=U(f,r),g=O(w,l),y=1/0,x=1/0,d=1/0,h=-1/0,_=-1/0,B=-1/0;for(let E=3*A,b=3*(A+g);E<b;E++){let P=e[E],I=s.getX(P),S=s.getY(P),N=s.getZ(P);I<y&&(y=I),I>h&&(h=I),S<x&&(x=S),S>_&&(_=S),N<d&&(d=N),N>B&&(B=N)}return c[f+0]!==y||c[f+1]!==x||c[f+2]!==d||c[f+3]!==h||c[f+4]!==_||c[f+5]!==B?(c[f+0]=y,c[f+1]=x,c[f+2]=d,c[f+3]=h,c[f+4]=_,c[f+5]=B,!0):!1}else{let A=v(f),g=R(f,r),y=T,x=!1,d=!1;if(t){if(!y){let P=A/8+m/32,I=g/8+m/32;x=t.has(P),d=t.has(I),y=!x&&!d}}else x=!0,d=!0;let h=y||x,_=y||d,B=!1;h&&(B=a(A,m,y));let E=!1;_&&(E=a(g,m,y));let b=B||E;if(b)for(let P=0;P<3;P++){let I=A+P,S=g+P,N=c[I],F=c[I+3],D=c[S],z=c[S+3];c[f+P]=N<D?N:D,c[f+P+3]=F>z?F:z}return b}}}function K(i,t,n,e,s){let o,r,l,c,p,u,a=1/n.direction.x,f=1/n.direction.y,m=1/n.direction.z,T=n.origin.x,w=n.origin.y,A=n.origin.z,g=t[i],y=t[i+3],x=t[i+1],d=t[i+3+1],h=t[i+2],_=t[i+3+2];return a>=0?(o=(g-T)*a,r=(y-T)*a):(o=(y-T)*a,r=(g-T)*a),f>=0?(l=(x-w)*f,c=(d-w)*f):(l=(d-w)*f,c=(x-w)*f),o>c||l>r||((l>o||isNaN(o))&&(o=l),(c<r||isNaN(r))&&(r=c),m>=0?(p=(h-A)*m,u=(_-A)*m):(p=(_-A)*m,u=(h-A)*m),o>u||p>r)?!1:((p>o||o!==o)&&(o=p),(u<r||r!==r)&&(r=u),o<=s&&r>=e)}function Ae(i,t,n,e,s,o,r,l){let{geometry:c,_indirectBuffer:p}=i;for(let u=e,a=e+s;u<a;u++){let f=p?p[u]:u;gt(c,t,n,f,o,r,l)}}function we(i,t,n,e,s,o,r){let{geometry:l,_indirectBuffer:c}=i,p=1/0,u=null;for(let a=e,f=e+s;a<f;a++){let m;m=gt(l,t,n,c?c[a]:a,null,o,r),m&&m.distance<p&&(u=m,p=m.distance)}return u}function ge(i,t,n,e,s,o,r){let{geometry:l}=n,{index:c}=l,p=l.attributes.position;for(let u=i,a=t+i;u<a;u++){let f;if(f=n.resolveTriangleIndex(u),V(r,f*3,c,p),r.needsUpdate=!0,e(r,f,s,o))return!0}return!1}function Be(i,t,n,e,s,o,r){M.setBuffer(i._roots[t]),Fn(0,i,n,e,s,o,r),M.clearBuffer()}function Fn(i,t,n,e,s,o,r){let{float32Array:l,uint16Array:c,uint32Array:p}=M,u=i*2;if(L(u,c)){let f=U(i,p),m=O(u,c);de(t,n,e,f,m,s,o,r)}else{let f=v(i);K(f,l,e,o,r)&&Fn(f,t,n,e,s,o,r);let m=R(i,p);K(m,l,e,o,r)&&Fn(m,t,n,e,s,o,r)}}var Ti=["x","y","z"];function Pe(i,t,n,e,s,o){M.setBuffer(i._roots[t]);let r=Dn(0,i,n,e,s,o);return M.clearBuffer(),r}function Dn(i,t,n,e,s,o){let{float32Array:r,uint16Array:l,uint32Array:c}=M,p=i*2;if(L(p,l)){let a=U(i,c),f=O(p,l);return xe(t,n,e,a,f,s,o)}else{let a=mt(i,c),f=Ti[a],T=e.direction[f]>=0,w,A;T?(w=v(i),A=R(i,c)):(w=R(i,c),A=v(i));let y=K(w,r,e,s,o)?Dn(w,t,n,e,s,o):null;if(y){let h=y.point[f];if(T?h<=r[A+a]:h>=r[A+a+3])return y}let d=K(A,r,e,s,o)?Dn(A,t,n,e,s,o):null;return y&&d?y.distance<=d.distance?y:d:y||d||null}}import{Box3 as Ai,Matrix4 as wi}from"three";var nn=new Ai,Bt=new k,Pt=new k,Ut=new wi,Se=new H,en=new H;function _e(i,t,n,e){M.setBuffer(i._roots[t]);let s=Ln(0,i,n,e);return M.clearBuffer(),s}function Ln(i,t,n,e,s=null){let{float32Array:o,uint16Array:r,uint32Array:l}=M,c=i*2;if(s===null&&(n.boundingBox||n.computeBoundingBox(),Se.set(n.boundingBox.min,n.boundingBox.max,e),s=Se),L(c,r)){let u=t.geometry,a=u.index,f=u.attributes.position,m=n.index,T=n.attributes.position,w=U(i,l),A=O(c,r);if(Ut.copy(e).invert(),n.boundsTree)return C(i,o,en),en.matrix.copy(Ut),en.needsUpdate=!0,n.boundsTree.shapecast({intersectsBounds:y=>en.intersectsBox(y),intersectsTriangle:y=>{y.a.applyMatrix4(e),y.b.applyMatrix4(e),y.c.applyMatrix4(e),y.needsUpdate=!0;for(let x=w*3,d=(A+w)*3;x<d;x+=3)if(V(Pt,x,a,f),Pt.needsUpdate=!0,y.intersectsTriangle(Pt))return!0;return!1}});{let g=st(n);for(let y=w*3,x=(A+w)*3;y<x;y+=3){V(Bt,y,a,f),Bt.a.applyMatrix4(Ut),Bt.b.applyMatrix4(Ut),Bt.c.applyMatrix4(Ut),Bt.needsUpdate=!0;for(let d=0,h=g*3;d<h;d+=3)if(V(Pt,d,m,T),Pt.needsUpdate=!0,Bt.intersectsTriangle(Pt))return!0}}}else{let u=v(i),a=R(i,l);return C(u,o,nn),!!(s.intersectsBox(nn)&&Ln(u,t,n,e,s)||(C(a,o,nn),s.intersectsBox(nn)&&Ln(a,t,n,e,s)))}}import{Matrix4 as gi,Vector3 as rn}from"three";var sn=new gi,Mn=new H,Ot=new H,Bi=new rn,Pi=new rn,Si=new rn,_i=new rn;function Ee(i,t,n,e={},s={},o=0,r=1/0){t.boundingBox||t.computeBoundingBox(),Mn.set(t.boundingBox.min,t.boundingBox.max,n),Mn.needsUpdate=!0;let l=i.geometry,c=l.attributes.position,p=l.index,u=t.attributes.position,a=t.index,f=Y.getPrimitive(),m=Y.getPrimitive(),T=Bi,w=Pi,A=null,g=null;s&&(A=Si,g=_i);let y=1/0,x=null,d=null;return sn.copy(n).invert(),Ot.matrix.copy(sn),i.shapecast({boundsTraverseOrder:h=>Mn.distanceToBox(h),intersectsBounds:(h,_,B)=>B<y&&B<r?(_&&(Ot.min.copy(h.min),Ot.max.copy(h.max),Ot.needsUpdate=!0),!0):!1,intersectsRange:(h,_)=>{if(t.boundsTree)return t.boundsTree.shapecast({boundsTraverseOrder:E=>Ot.distanceToBox(E),intersectsBounds:(E,b,P)=>P<y&&P<r,intersectsRange:(E,b)=>{for(let P=E,I=E+b;P<I;P++){V(m,3*P,a,u),m.a.applyMatrix4(n),m.b.applyMatrix4(n),m.c.applyMatrix4(n),m.needsUpdate=!0;for(let S=h,N=h+_;S<N;S++){V(f,3*S,p,c),f.needsUpdate=!0;let F=f.distanceToTriangle(m,T,A);if(F<y&&(w.copy(T),g&&g.copy(A),y=F,x=S,d=P),F<o)return!0}}}});{let B=st(t);for(let E=0,b=B;E<b;E++){V(m,3*E,a,u),m.a.applyMatrix4(n),m.b.applyMatrix4(n),m.c.applyMatrix4(n),m.needsUpdate=!0;for(let P=h,I=h+_;P<I;P++){V(f,3*P,p,c),f.needsUpdate=!0;let S=f.distanceToTriangle(m,T,A);if(S<y&&(w.copy(T),g&&g.copy(A),y=S,x=P,d=E),S<o)return!0}}}}}),Y.releasePrimitive(f),Y.releasePrimitive(m),y===1/0?null:(e.point?e.point.copy(w):e.point=w.clone(),e.distance=y,e.faceIndex=x,s&&(s.point?s.point.copy(g):s.point=g.clone(),s.point.applyMatrix4(sn),w.applyMatrix4(sn),s.distance=w.sub(s.point).length(),s.faceIndex=d),e)}function be(i,t=null){t&&Array.isArray(t)&&(t=new Set(t));let n=i.geometry,e=n.index?n.index.array:null,s=n.attributes.position,o,r,l,c,p=0,u=i._roots;for(let f=0,m=u.length;f<m;f++)o=u[f],r=new Uint32Array(o),l=new Uint16Array(o),c=new Float32Array(o),a(0,p),p+=o.byteLength;function a(f,m,T=!1){let w=f*2;if(L(w,l)){let A=U(f,r),g=O(w,l),y=1/0,x=1/0,d=1/0,h=-1/0,_=-1/0,B=-1/0;for(let E=A,b=A+g;E<b;E++){let P=3*i.resolveTriangleIndex(E);for(let I=0;I<3;I++){let S=P+I;S=e?e[S]:S;let N=s.getX(S),F=s.getY(S),D=s.getZ(S);N<y&&(y=N),N>h&&(h=N),F<x&&(x=F),F>_&&(_=F),D<d&&(d=D),D>B&&(B=D)}}return c[f+0]!==y||c[f+1]!==x||c[f+2]!==d||c[f+3]!==h||c[f+4]!==_||c[f+5]!==B?(c[f+0]=y,c[f+1]=x,c[f+2]=d,c[f+3]=h,c[f+4]=_,c[f+5]=B,!0):!1}else{let A=v(f),g=R(f,r),y=T,x=!1,d=!1;if(t){if(!y){let P=A/8+m/32,I=g/8+m/32;x=t.has(P),d=t.has(I),y=!x&&!d}}else x=!0,d=!0;let h=y||x,_=y||d,B=!1;h&&(B=a(A,m,y));let E=!1;_&&(E=a(g,m,y));let b=B||E;if(b)for(let P=0;P<3;P++){let I=A+P,S=g+P,N=c[I],F=c[I+3],D=c[S],z=c[S+3];c[f+P]=N<D?N:D,c[f+P+3]=F>z?F:z}return b}}}function Ie(i,t,n,e,s,o,r){M.setBuffer(i._roots[t]),vn(0,i,n,e,s,o,r),M.clearBuffer()}function vn(i,t,n,e,s,o,r){let{float32Array:l,uint16Array:c,uint32Array:p}=M,u=i*2;if(L(u,c)){let f=U(i,p),m=O(u,c);Ae(t,n,e,f,m,s,o,r)}else{let f=v(i);K(f,l,e,o,r)&&vn(f,t,n,e,s,o,r);let m=R(i,p);K(m,l,e,o,r)&&vn(m,t,n,e,s,o,r)}}var Ei=["x","y","z"];function Ne(i,t,n,e,s,o){M.setBuffer(i._roots[t]);let r=Rn(0,i,n,e,s,o);return M.clearBuffer(),r}function Rn(i,t,n,e,s,o){let{float32Array:r,uint16Array:l,uint32Array:c}=M,p=i*2;if(L(p,l)){let a=U(i,c),f=O(p,l);return we(t,n,e,a,f,s,o)}else{let a=mt(i,c),f=Ei[a],T=e.direction[f]>=0,w,A;T?(w=v(i),A=R(i,c)):(w=R(i,c),A=v(i));let y=K(w,r,e,s,o)?Rn(w,t,n,e,s,o):null;if(y){let h=y.point[f];if(T?h<=r[A+a]:h>=r[A+a+3])return y}let d=K(A,r,e,s,o)?Rn(A,t,n,e,s,o):null;return y&&d?y.distance<=d.distance?y:d:y||d||null}}import{Box3 as bi,Matrix4 as Ii}from"three";var on=new bi,St=new k,_t=new k,Ct=new Ii,Fe=new H,cn=new H;function De(i,t,n,e){M.setBuffer(i._roots[t]);let s=Un(0,i,n,e);return M.clearBuffer(),s}function Un(i,t,n,e,s=null){let{float32Array:o,uint16Array:r,uint32Array:l}=M,c=i*2;if(s===null&&(n.boundingBox||n.computeBoundingBox(),Fe.set(n.boundingBox.min,n.boundingBox.max,e),s=Fe),L(c,r)){let u=t.geometry,a=u.index,f=u.attributes.position,m=n.index,T=n.attributes.position,w=U(i,l),A=O(c,r);if(Ct.copy(e).invert(),n.boundsTree)return C(i,o,cn),cn.matrix.copy(Ct),cn.needsUpdate=!0,n.boundsTree.shapecast({intersectsBounds:y=>cn.intersectsBox(y),intersectsTriangle:y=>{y.a.applyMatrix4(e),y.b.applyMatrix4(e),y.c.applyMatrix4(e),y.needsUpdate=!0;for(let x=w,d=A+w;x<d;x++)if(V(_t,3*t.resolveTriangleIndex(x),a,f),_t.needsUpdate=!0,y.intersectsTriangle(_t))return!0;return!1}});{let g=st(n);for(let y=w,x=A+w;y<x;y++){let d=t.resolveTriangleIndex(y);V(St,3*d,a,f),St.a.applyMatrix4(Ct),St.b.applyMatrix4(Ct),St.c.applyMatrix4(Ct),St.needsUpdate=!0;for(let h=0,_=g*3;h<_;h+=3)if(V(_t,h,m,T),_t.needsUpdate=!0,St.intersectsTriangle(_t))return!0}}}else{let u=v(i),a=R(i,l);return C(u,o,on),!!(s.intersectsBox(on)&&Un(u,t,n,e,s)||(C(a,o,on),s.intersectsBox(on)&&Un(a,t,n,e,s)))}}import{Matrix4 as Ni,Vector3 as fn}from"three";var ln=new Ni,On=new H,Vt=new H,Fi=new fn,Di=new fn,Li=new fn,Mi=new fn;function Le(i,t,n,e={},s={},o=0,r=1/0){t.boundingBox||t.computeBoundingBox(),On.set(t.boundingBox.min,t.boundingBox.max,n),On.needsUpdate=!0;let l=i.geometry,c=l.attributes.position,p=l.index,u=t.attributes.position,a=t.index,f=Y.getPrimitive(),m=Y.getPrimitive(),T=Fi,w=Di,A=null,g=null;s&&(A=Li,g=Mi);let y=1/0,x=null,d=null;return ln.copy(n).invert(),Vt.matrix.copy(ln),i.shapecast({boundsTraverseOrder:h=>On.distanceToBox(h),intersectsBounds:(h,_,B)=>B<y&&B<r?(_&&(Vt.min.copy(h.min),Vt.max.copy(h.max),Vt.needsUpdate=!0),!0):!1,intersectsRange:(h,_)=>{if(t.boundsTree){let B=t.boundsTree;return B.shapecast({boundsTraverseOrder:E=>Vt.distanceToBox(E),intersectsBounds:(E,b,P)=>P<y&&P<r,intersectsRange:(E,b)=>{for(let P=E,I=E+b;P<I;P++){let S=B.resolveTriangleIndex(P);V(m,3*S,a,u),m.a.applyMatrix4(n),m.b.applyMatrix4(n),m.c.applyMatrix4(n),m.needsUpdate=!0;for(let N=h,F=h+_;N<F;N++){let D=i.resolveTriangleIndex(N);V(f,3*D,p,c),f.needsUpdate=!0;let z=f.distanceToTriangle(m,T,A);if(z<y&&(w.copy(T),g&&g.copy(A),y=z,x=N,d=P),z<o)return!0}}}})}else{let B=st(t);for(let E=0,b=B;E<b;E++){V(m,3*E,a,u),m.a.applyMatrix4(n),m.b.applyMatrix4(n),m.c.applyMatrix4(n),m.needsUpdate=!0;for(let P=h,I=h+_;P<I;P++){let S=i.resolveTriangleIndex(P);V(f,3*S,p,c),f.needsUpdate=!0;let N=f.distanceToTriangle(m,T,A);if(N<y&&(w.copy(T),g&&g.copy(A),y=N,x=P,d=E),N<o)return!0}}}}}),Y.releasePrimitive(f),Y.releasePrimitive(m),y===1/0?null:(e.point?e.point.copy(w):e.point=w.clone(),e.distance=y,e.faceIndex=x,s&&(s.point?s.point.copy(g):s.point=g.clone(),s.point.applyMatrix4(ln),w.applyMatrix4(ln),s.distance=w.sub(s.point).length(),s.faceIndex=d),e)}function Cn(i,t,n){return i===null?null:(i.point.applyMatrix4(t.matrixWorld),i.distance=i.point.distanceTo(n.ray.origin),i.object=t,i)}var an=new H,un=new Ri,ve=new Oe,Re=new Ui,Ue=new Oe,Vn=["getX","getY","getZ"],zn=class i extends $t{static serialize(t,n={}){n={cloneBuffers:!0,...n};let e=t.geometry,s=t._roots,o=t._indirectBuffer,r=e.getIndex(),l={version:1,roots:null,index:null,indirectBuffer:null};return n.cloneBuffers?(l.roots=s.map(c=>c.slice()),l.index=r?r.array.slice():null,l.indirectBuffer=o?o.slice():null):(l.roots=s,l.index=r?r.array:null,l.indirectBuffer=o),l}static deserialize(t,n,e={}){e={setIndex:!0,indirect:!!t.indirectBuffer,...e};let{index:s,roots:o,indirectBuffer:r}=t;t.version||(console.warn("MeshBVH.deserialize: Serialization format has been changed and will be fixed up. It is recommended to regenerate any stored serialized data."),c(o));let l=new i(n,{...e,[Et]:!0});if(l._roots=o,l._indirectBuffer=r||null,e.setIndex){let p=n.getIndex();if(p===null){let u=new vi(t.index,1,!1);n.setIndex(u)}else p.array!==s&&(p.array.set(s),p.needsUpdate=!0)}return l;function c(p){for(let u=0;u<p.length;u++){let a=p[u],f=new Uint32Array(a),m=new Uint16Array(a);for(let T=0,w=a.byteLength/32;T<w;T++){let A=8*T,g=2*A;L(g,m)||(f[A+6]=f[A+6]/8-T)}}}}get primitiveStride(){return 3}get resolveTriangleIndex(){return this.resolvePrimitiveIndex}constructor(t,n={}){n.maxLeafTris&&(console.warn('MeshBVH: "maxLeafTris" option has been deprecated. Use "targetLeafSize", instead.'),n={...n,targetLeafSize:n.maxLeafTris}),super(t,n)}shiftTriangleOffsets(t){return super.shiftPrimitiveOffsets(t)}writePrimitiveBounds(t,n,e){let s=this.geometry,o=this._indirectBuffer,r=s.attributes.position,l=s.index?s.index.array:null,p=(o?o[t]:t)*3,u=p+0,a=p+1,f=p+2;l&&(u=l[u],a=l[a],f=l[f]);for(let m=0;m<3;m++){let T=r[Vn[m]](u),w=r[Vn[m]](a),A=r[Vn[m]](f),g=T;w<g&&(g=w),A<g&&(g=A);let y=T;w>y&&(y=w),A>y&&(y=A),n[e+m]=g,n[e+m+3]=y}return n}computePrimitiveBounds(t,n,e){let s=this.geometry,o=this._indirectBuffer,r=s.attributes.position,l=s.index?s.index.array:null,c=r.normalized;if(t<0||n+t-e.offset>e.length/6)throw new Error("MeshBVH: compute triangle bounds range is invalid.");let p=r.array,u=r.offset||0,a=3;r.isInterleavedBufferAttribute&&(a=r.data.stride);let f=["getX","getY","getZ"],m=e.offset;for(let T=t,w=t+n;T<w;T++){let g=(o?o[T]:T)*3,y=(T-m)*6,x=g+0,d=g+1,h=g+2;l&&(x=l[x],d=l[d],h=l[h]),c||(x=x*a+u,d=d*a+u,h=h*a+u);for(let _=0;_<3;_++){let B,E,b;c?(B=r[f[_]](x),E=r[f[_]](d),b=r[f[_]](h)):(B=p[x+_],E=p[d+_],b=p[h+_]);let P=B;E<P&&(P=E),b<P&&(P=b);let I=B;E>I&&(I=E),b>I&&(I=b);let S=(I-P)/2,N=_*2;e[y+N+0]=P+S,e[y+N+1]=S+(Math.abs(P)+S)*ut}}return e}raycastObject3D(t,n,e=[]){let{material:s}=t;if(s===void 0)return;Re.copy(t.matrixWorld).invert(),un.copy(n.ray).applyMatrix4(Re),Ue.setFromMatrixScale(t.matrixWorld),ve.copy(un.direction).multiply(Ue);let o=ve.length(),r=n.near/o,l=n.far/o;if(n.firstHitOnly===!0){let c=this.raycastFirst(un,s,r,l);c=Cn(c,t,n),c&&e.push(c)}else{let c=this.raycast(un,s,r,l);for(let p=0,u=c.length;p<u;p++){let a=Cn(c[p],t,n);a&&e.push(a)}}return e}refit(t=null){return(this.indirect?be:Te)(this,t)}raycast(t,n=Me,e=0,s=1/0){let o=this._roots,r=[],l=this.indirect?Ie:Be;for(let c=0,p=o.length;c<p;c++)l(this,c,n,t,r,e,s);return r}raycastFirst(t,n=Me,e=0,s=1/0){let o=this._roots,r=null,l=this.indirect?Ne:Pe;for(let c=0,p=o.length;c<p;c++){let u=l(this,c,n,t,e,s);u!=null&&(r==null||u.distance<r.distance)&&(r=u)}return r}intersectsGeometry(t,n){let e=!1,s=this._roots,o=this.indirect?De:_e;for(let r=0,l=s.length;r<l&&(e=o(this,r,t,n),!e);r++);return e}shapecast(t){let n=Y.getPrimitive(),e=super.shapecast({...t,intersectsPrimitive:t.intersectsTriangle,scratchPrimitive:n,iterate:this.indirect?ge:he});return Y.releasePrimitive(n),e}bvhcast(t,n,e){let{intersectsRanges:s,intersectsTriangles:o}=e,r=Y.getPrimitive(),l=this.geometry.index,c=this.geometry.attributes.position,p=this.indirect?T=>{let w=this.resolveTriangleIndex(T);V(r,w*3,l,c)}:T=>{V(r,T*3,l,c)},u=Y.getPrimitive(),a=t.geometry.index,f=t.geometry.attributes.position,m=t.indirect?T=>{let w=t.resolveTriangleIndex(T);V(u,w*3,a,f)}:T=>{V(u,T*3,a,f)};if(o){if(!(t instanceof i))throw new Error('MeshBVH: "intersectsTriangles" callback can only be used with another MeshBVH.');let T=(w,A,g,y,x,d,h,_)=>{for(let B=g,E=g+y;B<E;B++){m(B),u.a.applyMatrix4(n),u.b.applyMatrix4(n),u.c.applyMatrix4(n),u.needsUpdate=!0;for(let b=w,P=w+A;b<P;b++)if(p(b),r.needsUpdate=!0,o(r,u,b,B,x,d,h,_))return!0}return!1};if(s){let w=s;s=function(A,g,y,x,d,h,_,B){return w(A,g,y,x,d,h,_,B)?!0:T(A,g,y,x,d,h,_,B)}}else s=T}return super.bvhcast(t,n,{intersectsRanges:s})}intersectsBox(t,n){return an.set(t.min,t.max,n),an.needsUpdate=!0,this.shapecast({intersectsBounds:e=>an.intersectsBox(e),intersectsTriangle:e=>an.intersectsTriangle(e)})}intersectsSphere(t){return this.shapecast({intersectsBounds:n=>t.intersectsBox(n),intersectsTriangle:n=>n.intersectsSphere(t)})}closestPointToGeometry(t,n,e={},s={},o=0,r=1/0){return(this.indirect?Le:Ee)(this,t,n,e,s,o,r)}closestPointToPoint(t,n={},e=0,s=1/0){return le(this,t,n,e,s)}};export{zn as MeshBVH};
package/model.d.ts CHANGED
@@ -58,7 +58,7 @@ export interface ModelOptions {
58
58
  * cursor, untouched. Never behind the glass. OPT-IN: without it nothing
59
59
  * is loaded or run. PlayCanvas: hit-tested with the engine's depth picker (meshes and splats,
60
60
  * one low-res pass every other frame while the pointer is over the tile). three: a raycast
61
- * against the subject. Pass an object to tune it: `{ margin, anchor, height, pointerScope }`
61
+ * against the subject. Pass an object to tune it: `{ margin, anchor, height, pointerScope, soften }`
62
62
  * (any object also means depth).
63
63
  */
64
64
  cursor?: 'depth' | CursorOptions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@displayxr/inline3d",
3
- "version": "1.43.1",
3
+ "version": "1.44.0",
4
4
  "description": "Turn any HTML <canvas> into a 3D window on a spatial display, inside an ordinary web page, for the DisplayXR Browser. Dependency-free; progressive enhancement (falls back to plain 2D everywhere else).",
5
5
  "type": "module",
6
6
  "types": "./index.d.ts",
@@ -77,6 +77,9 @@
77
77
  "js/inline3d-cursor-option.js",
78
78
  "js/inline3d-cursor-depth.js",
79
79
  "js/inline3d-cursor-depth-playcanvas.js",
80
+ "js/inline3d-cursor-perf.js",
81
+ "js/inline3d-cursor-bvh.js",
82
+ "js/vendor/",
80
83
  "js/inline3d-viewer.js",
81
84
  "js/inline3d-splat.js",
82
85
  "js/inline3d-splat-pc-entry.js",
@@ -172,10 +175,12 @@
172
175
  "typecheck": "tsc --noEmit -p tsconfig.json",
173
176
  "test": "tsc --noEmit -p tsconfig.json && node --test \"test/*.test.mjs\"",
174
177
  "build:dist": "node tools/dist/build.mjs",
178
+ "vendor:bvh": "node tools/vendor/three-mesh-bvh.mjs",
175
179
  "prepack": "node tools/dist/build.mjs",
176
180
  "test:e2e": "node test/e2e/call-element.e2e.mjs",
177
181
  "test:e2e:camera": "node test/e2e/camera.e2e.mjs",
178
182
  "test:e2e:cursor": "node test/e2e/cursor-depth.e2e.mjs",
183
+ "test:e2e:cursor-perf": "node test/e2e/cursor-perf.e2e.mjs",
179
184
  "test:e2e:samples-panel": "node test/e2e/samples-panel.e2e.mjs",
180
185
  "api:check": "node tools/api-surface.mjs --check",
181
186
  "api:update": "node tools/api-surface.mjs --update",
package/splat.d.ts CHANGED
@@ -482,7 +482,7 @@ export interface SplatOptions {
482
482
  * cursor, untouched. Never behind the glass. OPT-IN: without it nothing
483
483
  * is loaded or run. PlayCanvas: hit-tested with the engine's depth picker (meshes and splats,
484
484
  * one low-res pass every other frame while the pointer is over the tile). three: a raycast
485
- * against the subject. Pass an object to tune it: `{ margin, anchor, height, pointerScope }`
485
+ * against the subject. Pass an object to tune it: `{ margin, anchor, height, pointerScope, soften }`
486
486
  * (any object also means depth).
487
487
  */
488
488
  cursor?: 'depth' | CursorOptions;
package/three.d.ts CHANGED
@@ -143,7 +143,19 @@ export class EdgeFeather {
143
143
  ): void;
144
144
  }
145
145
 
146
- import type { CursorAnchorMode, CursorPlacement, CursorView } from './cursor-depth.js';
146
+ import type { CursorAnchorMode, CursorPlacement, CursorSoftenOption, CursorSoftenParams, CursorSoftening, CursorView } from './cursor-depth.js';
147
+
148
+ /** One second of `debug` stats: each figure as `{ mean, p95, max, n }`. */
149
+ export interface CursorDebugSummary {
150
+ frames: number;
151
+ seconds: number;
152
+ updateMs: { mean: number; p95: number; max: number; n: number };
153
+ rays: { mean: number; p95: number; max: number; n: number };
154
+ frameMs: { mean: number; p95: number; max: number; n: number };
155
+ /** Age of the pointer sample a frame used, on frames where it was new. */
156
+ pointerAgeMs: { mean: number; p95: number; max: number; n: number };
157
+ samplesPerFrame: number;
158
+ }
147
159
 
148
160
  /**
149
161
  * A hit test for {@link DepthCursor} that raycasts three.js objects (recursively): the first hit
@@ -179,22 +191,39 @@ export class DepthCursor {
179
191
  height?: number;
180
192
  /** Fill colour of the arrow (default 0xffffff; the outline is always dark). */
181
193
  color?: number;
182
- /** How far in front of out-of-screen content it floats, in eye-baseline units (default 0.03 ≈ 2 mm at a 65 mm IPD). */
194
+ /** How far in front of out-of-screen content it floats, in eye-baseline units (default 0.015 ≈ 1 mm at a 63-65 mm IPD). */
183
195
  margin?: number;
184
196
  /** Default `'hybrid'`: exact while the pointer moves, world-fixed (parallaxing) while it is still. */
185
197
  anchor?: CursorAnchorMode;
186
198
  /** `'window'`: keep the cursor over DOM layered on the canvas; hides the CSS cursor page-wide meanwhile. */
187
199
  pointerScope?: 'canvas' | 'window';
188
- /** An EXPENSIVE hit test: N rays a frame from the first eye, cycling the footprint (0 = all). */
200
+ /** 0 (default): the whole footprint every frame. N: amortised — N rays a frame cycling the footprint (both eyes); the arrow still follows the newest pointer each frame. */
189
201
  raysPerFrame?: number;
202
+ /**
203
+ * Crosstalk softening of the LIFTED arrow (runtime ADR-046 Amendment 2 §B.7), in the arrow's own
204
+ * shader: blur = 0.1 × its ghost offset (capped at 6% of its height, 8 px), opacity easing to
205
+ * 0.5 over 0.03 baselines of lift; both zero on the glass. Default `'both'`; `'off'` = the crisp arrow.
206
+ */
207
+ soften?: CursorSoftenOption;
190
208
  /** Attach pattern: the Object3D the eye cameras hang off; its world matrix carries the views to world. */
191
209
  viewSpace?: unknown;
210
+ /** `true`: log update() cost, rays a frame and the frame interval once a second; `'both'`: also keep the OS cursor visible. */
211
+ debug?: boolean | 'both';
192
212
  },
193
213
  );
194
- /** The arrow (a `THREE.Mesh`: dark outline, white fill, tip at its origin; depth test off, drawn last). Add it to the scene root. */
214
+ /** With `debug` only (else null): the rolling stats; `last` is the newest one-second summary, `history` the last 120. */
215
+ readonly debugStats: { last: CursorDebugSummary | null; history: CursorDebugSummary[] } | null;
216
+ /**
217
+ * The arrow (a `THREE.Mesh`: dark outline, white fill, tip at its origin; depth test off, drawn last). Add it to the scene root.
218
+ * While it is softened its geometry and material are a padded quad and the soft-arrow shader; otherwise the crisp mesh.
219
+ */
195
220
  readonly object: unknown;
196
221
  /** The last placement, for diagnostics. */
197
222
  readonly placement: CursorPlacement | { active: false };
223
+ /** The resolved softening parameters. */
224
+ readonly soften: CursorSoftenParams;
225
+ /** The last drawn frame's softening (diagnostics); null while nothing is drawn. */
226
+ readonly softening: CursorSoftening | null;
198
227
  /** Place the sprite for this frame — call with the views you are about to render, before rendering. */
199
228
  update(views: ArrayLike<XRView | CursorView>, nowMs?: number): CursorPlacement | { active: false };
200
229
  /** Set the pointer directly (canvas-normalised, v down), or null — for scripted input. */