avbd-babylon 0.3.0 → 0.4.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.
package/dist/avbd.js CHANGED
@@ -1,4 +1,4 @@
1
- var C=(s=0,e=0,t=0)=>Float64Array.of(s,e,t),jt=(s=0,e=0,t=0,i=1)=>Float64Array.of(s,e,t,i),oe=()=>new Float64Array(9);var us=s=>s<0?-1:s>0?1:0,xt=(s,e)=>s<e?s:e,Lc=(s,e)=>s>e?s:e,ce=(s,e,t)=>Lc(e,xt(t,s)),V=(s,e)=>s[0]*e[0]+s[1]*e[1]+s[2]*e[2],Ge=s=>V(s,s),ir=s=>Math.sqrt(Ge(s));function at(s,e,t,i){return s[0]=e,s[1]=t,s[2]=i,s}var ki=(s,e,t)=>at(s,e[0]+t[0],e[1]+t[1],e[2]+t[2]),$=(s,e,t)=>at(s,e[0]-t[0],e[1]-t[1],e[2]-t[2]),ne=(s,e,t)=>at(s,e[0]*t,e[1]*t,e[2]*t),_t=(s,e,t)=>at(s,e[0]/t,e[1]/t,e[2]/t),ee=(s,e)=>at(s,-e[0],-e[1],-e[2]),Xo=(s,e)=>at(s,Math.abs(e[0]),Math.abs(e[1]),Math.abs(e[2])),D=(s,e,t,i)=>at(s,e[0]+t[0]*i,e[1]+t[1]*i,e[2]+t[2]*i),_c=(s,e)=>_t(s,e,ir(e)),Dt=(s,e,t)=>at(s,e[1]*t[2]-e[2]*t[1],e[2]*t[0]-e[0]*t[2],e[0]*t[1]-e[1]*t[0]);function tr(s,e,t,i,r){return s[0]=e,s[1]=t,s[2]=i,s[3]=r,s}function Or(s,e,t){let i=e[0],r=e[1],o=e[2],n=e[3],a=t[0],l=t[1],c=t[2],u=t[3];return tr(s,n*a+i*u+r*c-o*l,n*l-i*c+r*u+o*a,n*c+i*l-r*a+o*u,n*u-i*a-r*l-o*c)}var Ec=(s,e)=>tr(s,-e[0],-e[1],-e[2],e[3]),ga=s=>Ge(s)+s[3]*s[3];function Yo(s,e){let t=ga(e);return tr(s,-e[0]/t,-e[1]/t,-e[2]/t,e[3]/t)}function Mc(s,e){let t=Math.sqrt(ga(e));return tr(s,e[0]/t,e[1]/t,e[2]/t,e[3]/t)}var er=new Float64Array(4),Si=new Float64Array(4);function lt(s,e,t){return Or(er,e,Yo(er,t)),at(s,er[0]*2,er[1]*2,er[2]*2)}function ri(s,e,t){return tr(Si,t[0],t[1],t[2],0),Or(Si,Si,e),Mc(s,tr(s,e[0]+Si[0]*.5,e[1]+Si[1]*.5,e[2]+Si[2]*.5,e[3]+Si[3]*.5))}function ae(s,e,t){let i=e[0],r=e[1],o=e[2],n=e[3],a=(r*t[2]-o*t[1])*2,l=(o*t[0]-i*t[2])*2,c=(i*t[1]-r*t[0])*2;return at(s,t[0]+a*n+(r*c-o*l),t[1]+l*n+(o*a-i*c),t[2]+c*n+(i*l-r*a))}var ma=new Float64Array(3);function Ft(s,e,t,i){return ae(ma,t,i),ki(s,ma,e)}function Te(s,e,t){return ae(s,Ec(er,e),t)}function Ce(s,e,t,i){return s.fill(0),s[0]=e,s[4]=t,s[8]=i,s}function Qo(s,e){return s[0]=0,s[1]=-e[2],s[2]=e[1],s[3]=e[2],s[4]=0,s[5]=-e[0],s[6]=-e[1],s[7]=e[0],s[8]=0,s}function Pi(s,e){let t=e[1],i=e[2],r=e[5];return s[0]=e[0],s[1]=e[3],s[2]=e[6],s[3]=t,s[4]=e[4],s[5]=e[7],s[6]=i,s[7]=r,s[8]=e[8],s}function Ke(s,e,t){let i=e[0],r=e[1],o=e[2],n=e[3],a=e[4],l=e[5],c=e[6],u=e[7],f=e[8],d=t[0],p=t[1],g=t[2],h=t[3],m=t[4],b=t[5],v=t[6],w=t[7],y=t[8];return s[0]=i*d+r*h+o*v,s[1]=i*p+r*m+o*w,s[2]=i*g+r*b+o*y,s[3]=n*d+a*h+l*v,s[4]=n*p+a*m+l*w,s[5]=n*g+a*b+l*y,s[6]=c*d+u*h+f*v,s[7]=c*p+u*m+f*w,s[8]=c*g+u*b+f*y,s}function ue(s,e,t){let i=t[0],r=t[1],o=t[2];return at(s,e[0]*i+e[1]*r+e[2]*o,e[3]*i+e[4]*r+e[5]*o,e[6]*i+e[7]*r+e[8]*o)}function Ne(s,e){for(let t=0;t<9;t++)s[t]+=e[t];return s}function Li(s,e,t){for(let i=0;i<9;i++)s[i]=e[i]*t;return s}function ba(s,e){for(let t=0;t<9;t++)s[t]=-e[t];return s}function fs(s,e,t){for(let i=0;i<3;i++)for(let r=0;r<3;r++)s[i*3+r]=t[r]*e[i];return s}function ya(s,e){let t=Math.sqrt(e[0]*e[0]+e[3]*e[3]+e[6]*e[6]),i=Math.sqrt(e[1]*e[1]+e[4]*e[4]+e[7]*e[7]),r=Math.sqrt(e[2]*e[2]+e[5]*e[5]+e[8]*e[8]);return Ce(s,t,i,r)}function ds(s,e){let t=Math.abs(e[0])>Math.abs(e[2])?C(-e[1],e[0],0):C(0,-e[2],e[1]);_c(t,t);let i=Dt(C(),e,t);return s[0]=e[0],s[1]=e[1],s[2]=e[2],s.set(t,3),s.set(i,6),s}function hs(s,e,t,i,r,o,n){let a=s[0],l=s[3],c=s[4],u=s[6],f=s[7],d=s[8],p=t[0],g=t[1],h=t[2],m=e[0],b=t[3],v=t[4],w=t[5],y=e[3],A=e[4],x=t[6],B=t[7],E=t[8],L=e[6],M=e[7],z=e[8],_=l/a,k=u/a,S=p/a,P=b/a,I=x/a,R=a,F=c-_*_*R,X=(f-_*k*R)/F,W=(g-_*S*R)/F,N=(v-_*P*R)/F,H=(B-_*I*R)/F,Z=d-(k*k*R+X*X*F),he=(h-k*S*R-X*W*F)/Z,we=(w-k*P*R-X*N*F)/Z,Oe=(E-k*I*R-X*H*F)/Z,J=m-(S*S*R+W*W*F+he*he*Z),$e=(y-S*P*R-W*N*F-he*we*Z)/J,Xe=(L-S*I*R-W*H*F-he*Oe*Z)/J,Be=A-(P*P*R+N*N*F+we*we*Z+$e*$e*J),st=(M-P*I*R-N*H*F-we*Oe*Z-$e*Xe*J)/Be,ii=z-(I*I*R+H*H*F+Oe*Oe*Z+Xe*Xe*J+st*st*Be),Ye=i[0],ot=i[1]-_*Ye,Qe=i[2]-k*Ye-X*ot,nt=r[0]-S*Ye-W*ot-he*Qe,At=r[1]-P*Ye-N*ot-we*Qe-$e*nt,Yi=r[2]-I*Ye-H*ot-Oe*Qe-Xe*nt-st*At,Qi=Ye/R,Ki=ot/F,Zi=Qe/Z,Wt=nt/J,kc=At/Be,Pc=Yi/ii;n[2]=Pc,n[1]=kc-st*n[2],n[0]=Wt-$e*n[1]-Xe*n[2],o[2]=Zi-he*n[0]-we*n[1]-Oe*n[2],o[1]=Ki-X*o[2]-W*n[0]-N*n[1]-H*n[2],o[0]=Qi-_*o[1]-k*o[2]-S*n[0]-P*n[1]-I*n[2]}var Et=1,Ue=1e10,ps=.01,va=1e-5,Ze=class{solver;forces=[];positionLin;positionAng=jt();initialLin=C();initialAng=jt();inertialLin=C();inertialAng=jt();velocityLin;velocityAng=C();prevVelocityLin;size;mass;moment;friction;radius;constructor(e,t,i,r,o,n=[0,0,0]){this.solver=e,this.size=C(t[0],t[1],t[2]),this.friction=r,this.positionLin=C(o[0],o[1],o[2]),this.velocityLin=C(n[0],n[1],n[2]),this.prevVelocityLin=C(n[0],n[1],n[2]);let[a,l,c]=this.size;this.mass=a*l*c*i,this.moment=C((l*l+c*c)/12*this.mass,(a*a+c*c)/12*this.mass,(a*a+l*l)/12*this.mass),this.radius=ir([a*.5,l*.5,c*.5]),e.bodies.push(this)}constrainedTo(e){for(let t of this.forces)if(t.bodyA===this&&t.bodyB===e||t.bodyA===e&&t.bodyB===this)return!0;return!1}},ms=()=>({lhsLin:oe(),lhsAng:oe(),lhsCross:oe(),rhsLin:C(),rhsAng:C()}),Gt=class{solver;bodyA;bodyB;constructor(e,t,i){this.solver=e,this.bodyA=t,this.bodyB=i,e.forces.push(this),t?.forces.push(this),i.forces.push(this)}destroy(){let e=this.solver.forces,t=e.indexOf(this);t>=0&&e.splice(t,1),this.unlinkFromBodies()}unlinkFromBodies(){for(let e of[this.bodyA,this.bodyB]){if(!e)continue;let t=e.forces.indexOf(this);t>=0&&e.forces.splice(t,1)}}};var Ca=8,Aa=16,Ei=1e-6,Zo=1e-5,zc=1e-6,en=34028234663852886e22,gs=0,Sa=1,bs=2;function xa(s){let e=s.positionAng;return{center:s.positionLin,half:ne(C(),s.size,.5),axis:[ae(C(),e,[1,0,0]),ae(C(),e,[0,1,0]),ae(C(),e,[0,0,1])]}}var _i=(s,e)=>Math.abs(V(s,e));function ys(s,e){let t=V(e,s.axis[0])>=0?1:-1,i=V(e,s.axis[1])>=0?1:-1,r=V(e,s.axis[2])>=0?1:-1,o=D(C(),s.center,s.axis[0],s.half[0]*t);return D(o,o,s.axis[1],s.half[1]*i),D(o,o,s.axis[2],s.half[2]*r)}function ka(s,e){return e===0?{u:s.axis[1],v:s.axis[2],extentU:s.half[1],extentV:s.half[2]}:e===1?{u:s.axis[0],v:s.axis[2],extentU:s.half[0],extentV:s.half[2]}:{u:s.axis[0],v:s.axis[1],extentU:s.half[0],extentV:s.half[1]}}function Ic(s,e,t){let i=V(t,s.axis[e])>=0?1:-1,r=ne(C(),s.axis[e],i),o=D(C(),s.center,r,s.half[e]);return{normal:r,center:o,...ka(s,e)}}function Rc(s,e){let t=0,i=-en;for(let r=0;r<3;r++){let o=_i(s.axis[r],e);o>i&&(i=o,t=r)}return t}function Oc(s,e,t){let i=V(s.axis[e],t)>0?-1:1,r=ne(C(),s.axis[e],i),o=D(C(),s.center,r,s.half[e]),{u:n,v:a,extentU:l,extentV:c}=ka(s,e),u=(f,d)=>{let p=D(C(),o,n,f*l);return D(p,p,a,d*c)};return[u(1,1),u(-1,1),u(-1,-1),u(1,-1)]}function Tc(s,e,t){let i=[];if(s.length===0)return i;let r=s[s.length-1],o=V(e,r)-t;for(let n of s){let a=V(e,n)-t,l=o<=Zo,c=a<=Zo;if(l!==c){let u=0,f=o-a;Math.abs(f)>Ei&&(u=ce(o/f,0,1)),i.length<Aa&&i.push(D(C(),r,$(C(),n,r),u))}c&&i.length<Aa&&i.push(n),r=n,o=a}return i}var vs=class{contacts=[];midpoints=[];bodyA;bodyB;constructor(e,t){this.bodyA=e,this.bodyB=t}add(e,t,i){let r=ne(C(),ki(C(),e,t),.5);for(let a of this.midpoints)if(Ge($(C(),r,a))<zc)return;if(this.contacts.length>=Ca)return;let{bodyA:o,bodyB:n}=this;this.contacts.push({feature:i,rA:Te(C(),o.positionAng,$(C(),e,o.positionLin)),rB:Te(C(),n.positionAng,$(C(),t,n.positionLin))}),this.midpoints.push(r)}};function Ko(s,e,t,i,r,o,n,a){let l=Ge(i);if(l<Ei)return!0;let c=1/Math.sqrt(l),u=ne(C(),i,c);V(u,t)<0&&ee(u,u);let f=Math.abs(V(t,u)),d=s.half[0]*_i(u,s.axis[0])+s.half[1]*_i(u,s.axis[1])+s.half[2]*_i(u,s.axis[2]),p=e.half[0]*_i(u,e.axis[0])+e.half[1]*_i(u,e.axis[1])+e.half[2]*_i(u,e.axis[2]),g=f-(d+p);return g>0?!1:((!a.valid||g>a.separation)&&(a.valid=!0,a.type=r,a.indexA=o,a.indexB=n,a.separation=g,a.normalAB=u),!0)}function wa(s,e,t){let i=(e+1)%3,r=(e+2)%3,o=V(t,s.axis[i])>=0?1:-1,n=V(t,s.axis[r])>=0?1:-1,a=D(C(),s.center,s.axis[i],s.half[i]*o);D(a,a,s.axis[r],s.half[r]*n);let l=ne(C(),s.axis[e],s.half[e]);return[$(C(),a,l),ki(C(),a,l)]}function jc(s,e,t,i){let r=$(C(),e,s),o=$(C(),i,t),n=$(C(),s,t),a=V(r,r),l=V(o,o),c=V(o,n),u=0,f=0;if(a<=Ei&&l<=Ei)return[s,t];if(a<=Ei)f=ce(c/l,0,1);else{let d=V(r,n);if(l<=Ei)u=ce(-d/a,0,1);else{let p=V(r,o),g=a*l-p*p;Math.abs(g)>Ei&&(u=ce((p*c-d*l)/g,0,1)),f=(p*u+c)/l,f<0?(f=0,u=ce(-d/a,0,1)):f>1&&(f=1,u=ce((p-d)/a,0,1))}}return[D(C(),s,r,u),D(C(),t,o,f)]}function Ba(s,e,t,i,r,o,n){let a=r?t:i,l=r?i:t,c=r?n:ee(C(),n),u=Ic(a,o,c),f=Rc(l,u.normal),d=Oc(l,f,u.normal),p=[[u.u,u.extentU],[ee(C(),u.u),u.extentU],[u.v,u.extentV],[ee(C(),u.v),u.extentV]];for(let[m,b]of p)if(d=Tc(d,m,V(m,u.center)+b),!d.length)return[];let g=new vs(s,e),h=(r?gs:Sa)<<24|(o&255)<<16|(f&255)<<8;for(let m=0;m<d.length&&g.contacts.length<Ca;m++){let b=d[m],v=V($(C(),b,u.center),u.normal);if(v>Zo)continue;let w=D(C(),b,u.normal,-v),y=r?w:b,A=r?b:w;g.add(y,A,h|m&255)}return g.contacts.length||g.add(ys(t,n),ys(i,ee(C(),n)),h),g.contacts}function Dc(s,e,t,i,r,o,n){let[a,l]=wa(t,r,n),[c,u]=wa(i,o,ee(C(),n)),[f,d]=jc(a,l,c,u),p=new vs(s,e),g=bs<<24|(r&255)<<8|o&255;return p.add(f,d,g),p.contacts.length||p.add(ys(t,n),ys(i,ee(C(),n)),g),p.contacts}function Pa(s,e,t){let i=xa(s),r=xa(e),o=$(C(),r.center,i.center),n={type:gs,indexA:0,indexB:0,separation:-en,normalAB:C(),valid:!1},a={type:bs,indexA:0,indexB:0,separation:-en,normalAB:C(),valid:!1};for(let u=0;u<3;u++)if(!Ko(i,r,o,i.axis[u],gs,u,-1,n))return[];for(let u=0;u<3;u++)if(!Ko(i,r,o,r.axis[u],Sa,-1,u,n))return[];let l=C();for(let u=0;u<3;u++)for(let f=0;f<3;f++)if(Dt(l,i.axis[u],r.axis[f]),!Ko(i,r,o,l,bs,u,f,a))return[];if(!n.valid)return[];let c=n;return a.valid&&.95*a.separation>n.separation+.01&&(c=a),ds(t,ee(C(),c.normalAB)),c.type===bs?Dc(s,e,i,r,c.indexA,c.indexB,c.normalAB):c.type===gs?Ba(s,e,i,r,!0,c.indexA,c.normalAB):Ba(s,e,i,r,!1,c.indexB,c.normalAB)}var La=C(),_a=C(),Ea=C(),Ma=C(),za=C(),Ia=C(),As=oe(),tn=oe(),rn=oe(),xs=oe(),sn=oe(),on=oe(),nn=oe(),ws=oe(),Ee=C(),je=C(),Mi=C(),si=C(),Ra=C(),Oa=C(),rr=0,Tr=0;function Ta(s,e,t){for(let i=0;i<3;i++)si[0]=t[i*3],si[1]=t[i*3+1],si[2]=t[i*3+2],Dt(si,e,si),s[i*3]=si[0],s[i*3+1]=si[1],s[i*3+2]=si[2];return s}var oi=class extends Gt{contacts=[];basis=oe();friction=0;constructor(e,t,i){super(e,t,i)}get numContacts(){return this.contacts.length}initialize(){let e=this.bodyA,t=this.bodyB,{solver:i}=this;this.friction=Math.sqrt(e.friction*t.friction);let r=this.contacts;this.contacts=Pa(e,t,this.basis).map(o=>{let n=r.find(a=>a.feature===o.feature);return n?{feature:o.feature,rA:n.stick?n.rA:o.rA,rB:n.stick?n.rB:o.rB,C0:C(),penalty:n.penalty.slice(),lambda:n.lambda.slice(),stick:n.stick}:{feature:o.feature,rA:o.rA,rB:o.rB,C0:C(),penalty:C(),lambda:C(),stick:!1}});for(let o of this.contacts){Ft(Ra,e.positionLin,e.positionAng,o.rA),Ft(Oa,t.positionLin,t.positionAng,o.rB),ue(o.C0,this.basis,$(Mi,Ra,Oa)),o.C0[0]+=ps;for(let n=0;n<3;n++)o.lambda[n]=o.lambda[n]*i.alpha*i.gamma,o.penalty[n]=ce(o.penalty[n]*i.gamma,Et,Ue)}return this.contacts.length>0}evaluate(e,t){let i=this.bodyA,r=this.bodyB,o=this.basis;ae(za,i.positionAng,e.rA),ae(Ia,r.positionAng,e.rB),ba(As,o),Ta(tn,za,o),Ta(rn,Ia,As),Ce(xs,e.penalty[0],e.penalty[1],e.penalty[2]),ne(Ee,e.C0,1-t),D(Ee,Ee,ue(Mi,o,La),1),D(Ee,Ee,ue(Mi,As,Ea),1),D(Ee,Ee,ue(Mi,tn,_a),1),D(Ee,Ee,ue(Mi,rn,Ma),1),ue(je,xs,Ee),D(je,je,e.lambda,1),je[0]=xt(je[0],0),Tr=Math.abs(je[0])*this.friction,rr=Math.sqrt(je[1]*je[1]+je[2]*je[2]),rr>Tr&&rr>0&&(je[1]*=Tr/rr,je[2]*=Tr/rr)}computeDisplacements(){let e=this.bodyA,t=this.bodyB;$(La,e.positionLin,e.initialLin),lt(_a,e.positionAng,e.initialAng),$(Ea,t.positionLin,t.initialLin),lt(Ma,t.positionAng,t.initialAng)}updatePrimal(e,t,i){this.computeDisplacements();let r=e===this.bodyA;for(let o of this.contacts){this.evaluate(o,t);let n=r?this.basis:As,a=r?tn:rn;Pi(sn,n),Pi(on,a),Ke(nn,on,xs),Ne(i.lhsLin,Ke(ws,Ke(ws,sn,xs),n)),Ne(i.lhsAng,Ke(ws,nn,a)),Ne(i.lhsCross,Ke(ws,nn,n)),D(i.rhsLin,i.rhsLin,ue(Mi,sn,je),1),D(i.rhsAng,i.rhsAng,ue(Mi,on,je),1)}}updateDual(e){let{solver:t}=this;this.computeDisplacements();for(let i of this.contacts)this.evaluate(i,e),i.lambda.set(je),je[0]<0&&(i.penalty[0]=xt(i.penalty[0]+t.betaLin*Math.abs(Ee[0]),Ue)),rr<=Tr&&(i.penalty[1]=xt(i.penalty[1]+t.betaLin*Math.abs(Ee[1]),Ue),i.penalty[2]=xt(i.penalty[2]+t.betaLin*Math.abs(Ee[2]),Ue),i.stick=Math.sqrt(Ee[1]*Ee[1]+Ee[2]*Ee[2])<va)}};var an=()=>({dt:1/60,gravity:-10,iterations:10,betaLin:1e4,betaAng:100,alpha:.99,gamma:.999}),ni=class{dt=1/60;gravity=-10;iterations=10;alpha=.99;betaLin=1e4;betaAng=100;gamma=.999;bodies=[];forces=[];constructor(){this.defaultParams()}defaultParams(){Object.assign(this,an())}clear(){this.forces=[],this.bodies=[]}pick(e,t){let r=null,o=C(),n=C();for(let a=this.bodies.length-1;a>=0;a--){let l=this.bodies[a];if(l.mass<=0)continue;Te(o,l.positionAng,$(o,e,l.positionLin)),Te(n,l.positionAng,t);let c=0,u=1/0,f=!0;for(let p=0;p<3&&f;p++){let g=l.size[p]*.5;if(Math.abs(n[p])<1e-6){(o[p]<-g||o[p]>g)&&(f=!1);continue}let h=1/n[p],m=(-g-o[p])*h,b=(g-o[p])*h;m>b&&([m,b]=[b,m]),c=Math.max(c,m),u=Math.min(u,b),c>u&&(f=!1)}if(!f)continue;let d=c>=0?c:u;d<0||(!r||d<r.t)&&(r={body:l,local:D(C(),o,n,d),t:d})}return r}sys=ms();dxLin=C();dxAng=C();dp=C();accel=C();step(){let{dt:e,gravity:t,bodies:i,sys:r,dp:o}=this;for(let a=i.length-1;a>=0;a--){let l=i[a];for(let c=a-1;c>=0;c--){let u=i[c];$(o,l.positionLin,u.positionLin);let f=l.radius+u.radius;V(o,o)<=f*f&&!l.constrainedTo(u)&&new oi(this,l,u)}}let n=[];for(let a of this.forces)a.initialize()?n.push(a):a.unlinkFromBodies();this.forces=n;for(let a=i.length-1;a>=0;a--){let l=i[a];D(l.inertialLin,l.positionLin,l.velocityLin,e),l.mass>0&&(l.inertialLin[2]+=t*(e*e)),ri(l.inertialAng,l.positionAng,ja(l.velocityAng,e)),_t(this.accel,$(this.accel,l.velocityLin,l.prevVelocityLin),e);let c=this.accel[2]*us(t),u=ce(c/Math.abs(t),0,1);Number.isFinite(u)||(u=0),l.initialLin.set(l.positionLin),l.initialAng.set(l.positionAng),l.mass>0&&(D(l.positionLin,l.positionLin,l.velocityLin,e),l.positionLin[2]+=t*(u*e*e),ri(l.positionAng,l.positionAng,ja(l.velocityAng,e)))}for(let a=0;a<this.iterations;a++){for(let l=i.length-1;l>=0;l--){let c=i[l];if(c.mass<=0)continue;let u=c.mass,f=c.moment;Ce(r.lhsLin,u/(e*e),u/(e*e),u/(e*e)),Ce(r.lhsAng,f[0]/(e*e),f[1]/(e*e),f[2]/(e*e)),r.lhsCross.fill(0),ue(r.rhsLin,r.lhsLin,$(o,c.positionLin,c.inertialLin)),ue(r.rhsAng,r.lhsAng,lt(o,c.positionAng,c.inertialAng));let d=c.forces;for(let p=d.length-1;p>=0;p--)d[p].updatePrimal(c,this.alpha,r);hs(r.lhsLin,r.lhsAng,r.lhsCross,ee(r.rhsLin,r.rhsLin),ee(r.rhsAng,r.rhsAng),this.dxLin,this.dxAng),D(c.positionLin,c.positionLin,this.dxLin,1),ri(c.positionAng,c.positionAng,this.dxAng)}for(let l of this.forces)l.updateDual(this.alpha)}for(let a of i)a.prevVelocityLin.set(a.velocityLin),a.mass>0&&(_t(a.velocityLin,$(a.velocityLin,a.positionLin,a.initialLin),e),_t(a.velocityAng,lt(a.velocityAng,a.positionAng,a.initialAng),e))}},Fc=C(),ja=(s,e)=>ne(Fc,s,e);var ve=(s,e)=>[s[0]-e[0],s[1]-e[1],s[2]-e[2]],Mt=(s,e)=>s[0]*e[0]+s[1]*e[1]+s[2]*e[2],zi=(s,e)=>[s[1]*e[2]-s[2]*e[1],s[2]*e[0]-s[0]*e[2],s[0]*e[1]-s[1]*e[0]],et=s=>Math.sqrt(Mt(s,s));function jr(s){let e=Da(s);return!e||e.vertices.length/3<=32?e:Da(Gc(e,32))}function Gc(s,e){let[t,i,r,o]=s.rotation,n=f=>{let d=[2*(i*f[2]-r*f[1]),2*(r*f[0]-t*f[2]),2*(t*f[1]-i*f[0])];return[f[0]+o*d[0]+(i*d[2]-r*d[1])+s.center[0],f[1]+o*d[1]+(r*d[0]-t*d[2])+s.center[1],f[2]+o*d[2]+(t*d[1]-i*d[0])+s.center[2]]},a=[];for(let f=0;f<s.vertices.length;f+=3)a.push(n([s.vertices[f],s.vertices[f+1],s.vertices[f+2]]));let l=0;a.forEach((f,d)=>{et(ve(f,s.center))>et(ve(a[l],s.center))&&(l=d)});let c=[l],u=a.map(f=>et(ve(f,a[l])));for(;c.length<e;){let f=0;u.forEach((d,p)=>{d>u[f]&&(f=p)}),c.push(f),a.forEach((d,p)=>{u[p]=Math.min(u[p],et(ve(d,a[f])))})}return c.flatMap(f=>a[f])}function Da(s){let e=0;for(let y=0;y<s.length;y++)e=Math.max(e,Math.abs(s[y]));let t=Math.max(e,1e-9)*1e-6,i=new Set,r=[];for(let y=0;y+2<s.length;y+=3){let A=[s[y],s[y+1],s[y+2]],x=A.map(B=>Math.round(B/t)).join(",");i.has(x)||(i.add(x),r.push(A))}if(r.length<4)return null;let o=Math.max(e,1e-9)*1e-10,n=0;for(let y=1;y<r.length;y++)r[y][0]<r[n][0]&&(n=y);let a=-1,l=0;for(let y=0;y<r.length;y++){let A=et(ve(r[y],r[n]));A>l&&(l=A,a=y)}if(a<0||l<o)return null;let c=-1;l=0;let u=ve(r[a],r[n]);for(let y=0;y<r.length;y++){let A=et(zi(u,ve(r[y],r[n])));A>l&&(l=A,c=y)}if(c<0||l<o*et(u))return null;let f=zi(u,ve(r[c],r[n])),d=-1;l=0;for(let y=0;y<r.length;y++){let A=Math.abs(Mt(f,ve(r[y],r[n])));A>l&&(l=A,d=y)}if(d<0||l<o*et(f))return null;let p=[],g=(y,A,x)=>{let B=zi(ve(r[A],r[y]),ve(r[x],r[y])),E=et(B)||1,L=[B[0]/E,B[1]/E,B[2]/E];return{v:[y,A,x],n:L,d:Mt(L,r[y])}},m=Mt(f,ve(r[d],r[n]))>0?[n,c,a]:[n,a,c];p.push(g(m[0],m[1],m[2])),p.push(g(m[0],d,m[1])),p.push(g(m[1],d,m[2])),p.push(g(m[2],d,m[0]));let b=new Set([n,a,c,d]),v=r.map((y,A)=>A).filter(y=>!b.has(y)),w=[n,a,c,d].reduce((y,A)=>[y[0]+r[A][0]/4,y[1]+r[A][1]/4,y[2]+r[A][2]/4],[0,0,0]);v.sort((y,A)=>et(ve(r[A],w))-et(ve(r[y],w)));for(let y of v){let A=p.filter(_=>Mt(_.n,r[y])-_.d>o);if(!A.length)continue;let x=new Map;for(let _ of p)for(let k=0;k<3;k++)x.set(`${_.v[k]},${_.v[(k+1)%3]}`,_);let B=new Set(A),E=[...A];for(;E.length;){let _=E.pop();for(let k=0;k<3;k++){let S=x.get(`${_.v[(k+1)%3]},${_.v[k]}`);S&&!B.has(S)&&Mt(S.n,r[y])-S.d>-o&&(B.add(S),E.push(S))}}let L=[...B],M=new Set;for(let _ of L)for(let k=0;k<3;k++)M.add(`${_.v[k]},${_.v[(k+1)%3]}`);let z=[];for(let _ of L)for(let k=0;k<3;k++){let S=_.v[k],P=_.v[(k+1)%3];M.has(`${P},${S}`)||z.push([S,P])}for(let _ of L)p.splice(p.indexOf(_),1);for(let[_,k]of z)p.push(g(_,k,y))}return Nc(r.flat(),p.flatMap(y=>y.v))}function Nc(s,e){let t=[];for(let S=0;S+2<s.length;S+=3)t.push([s[S],s[S+1],s[S+2]]);let i=0;for(let S of t)i=Math.max(i,Math.abs(S[0]),Math.abs(S[1]),Math.abs(S[2]));let r=Math.max(i,1e-9)*1e-5,o=[];for(let S=0;S+2<e.length;S+=3){let P=[e[S],e[S+1],e[S+2]],I=zi(ve(t[P[1]],t[P[0]]),ve(t[P[2]],t[P[0]])),R=et(I);if(!(R>0))continue;let F=[I[0]/R,I[1]/R,I[2]/R];o.push({v:P,n:F,d:Mt(F,t[P[0]])})}let n=new Map;o.forEach((S,P)=>{for(let I=0;I<3;I++)n.set(`${S.v[I]},${S.v[(I+1)%3]}`,P)});let a=new Array(o.length).fill(-1),l=[];o.forEach((S,P)=>{if(a[P]>=0)return;let I=[P];a[P]=l.length;for(let R=0;R<I.length;R++){let F=o[I[R]];for(let X=0;X<3;X++){let W=n.get(`${F.v[(X+1)%3]},${F.v[X]}`);if(W===void 0||a[W]>=0)continue;let N=o[W];Mt(S.n,N.n)>1-1e-5&&N.v.every(H=>Math.abs(Mt(S.n,t[H])-S.d)<=r)&&(a[W]=l.length,I.push(W))}}l.push(I)});let c=[];for(let S of l){let P=new Set;for(let N of S)for(let H=0;H<3;H++)P.add(`${o[N].v[H]},${o[N].v[(H+1)%3]}`);let I=new Map;for(let N of S)for(let H=0;H<3;H++){let Z=o[N].v[H],he=o[N].v[(H+1)%3];if(!P.has(`${he},${Z}`)){if(I.has(Z))return null;I.set(Z,he)}}let R=[0,0,0];for(let N of S){let H=o[N],Z=zi(ve(t[H.v[1]],t[H.v[0]]),ve(t[H.v[2]],t[H.v[0]]));R[0]+=Z[0],R[1]+=Z[1],R[2]+=Z[2]}let F=et(R)||1,X=I.keys().next().value,W=[X];for(let N=I.get(X);N!==X&&W.length<=I.size;N=I.get(N))W.push(N);if(W.length!==I.size)return null;c.push({n:[R[0]/F,R[1]/F,R[2]/F],verts:W})}let u=new Map,f=[];for(let S of c)for(let P of S.verts)u.has(P)||(u.set(P,f.length),f.push(t[P]));for(let S of c)S.verts=S.verts.map(P=>u.get(P));let d=new Set,p=0;for(let S of c)S.verts.forEach((P,I)=>{d.add(`${P},${S.verts[(I+1)%S.verts.length]}`),p++});if(d.size!==p||![...d].every(S=>{let[P,I]=S.split(",");return d.has(`${I},${P}`)})||f.length-d.size/2+c.length!==2)return null;let g=0,h=[0,0,0],m=[0,0,0,0,0,0];for(let S of c){let P=f[S.verts[0]];for(let I=1;I+1<S.verts.length;I++){let R=f[S.verts[I]],F=f[S.verts[I+1]],X=Mt(P,zi(R,F));g+=X/6;for(let N=0;N<3;N++)h[N]+=X/24*(P[N]+R[N]+F[N]);let W=(N,H)=>X/120*(P[N]*P[H]+R[N]*R[H]+F[N]*F[H]+(P[N]+R[N]+F[N])*(P[H]+R[H]+F[H]));m[0]+=W(0,0),m[1]+=W(1,1),m[2]+=W(2,2),m[3]+=W(0,1),m[4]+=W(0,2),m[5]+=W(1,2)}}if(!(g>0))return null;for(let S=0;S<3;S++)h[S]/=g;m[0]-=g*h[0]*h[0],m[1]-=g*h[1]*h[1],m[2]-=g*h[2]*h[2],m[3]-=g*h[0]*h[1],m[4]-=g*h[0]*h[2],m[5]-=g*h[1]*h[2];let b=m[0]+m[1]+m[2],v=[[b-m[0],-m[3],-m[4]],[-m[3],b-m[1],-m[5]],[-m[4],-m[5],b-m[2]]],{values:w,vectors:y}=Uc(v),A=y,x=S=>{let P=ve(S,h);return[A[0][0]*P[0]+A[1][0]*P[1]+A[2][0]*P[2],A[0][1]*P[0]+A[1][1]*P[1]+A[2][1]*P[2],A[0][2]*P[0]+A[1][2]*P[1]+A[2][2]*P[2]]},B=f.map(x),E=new Float32Array(B.flat()),L=c.map(S=>{let P=S.n,I=[A[0][0]*P[0]+A[1][0]*P[1]+A[2][0]*P[2],A[0][1]*P[0]+A[1][1]*P[1]+A[2][1]*P[2],A[0][2]*P[0]+A[1][2]*P[1]+A[2][2]*P[2]],R=-1/0;for(let F of S.verts)R=Math.max(R,Mt(I,B[F]));return{normal:I,d:R,verts:S.verts}}),M=new Map;L.forEach((S,P)=>S.verts.forEach((I,R)=>M.set(`${I},${S.verts[(R+1)%S.verts.length]}`,P)));let z=[];L.forEach((S,P)=>S.verts.forEach((I,R)=>{let F=S.verts[(R+1)%S.verts.length],X=M.get(`${F},${I}`);I<F&&X!==void 0&&z.push([I,F,P,X])}));let _=[0,0,0],k=0;for(let S of B){for(let P=0;P<3;P++)_[P]=Math.max(_[P],2*Math.abs(S[P]));k=Math.max(k,et(S))}return{vertices:E,faces:L,edges:z,volume:g,moments:[w[0],w[1],w[2]],size:_,radius:k,center:h,rotation:qc(A)}}function Uc(s){let e=s.map(a=>[...a]),t=[[1,0,0],[0,1,0],[0,0,1]];for(let a=0;a<50&&!(e[0][1]**2+e[0][2]**2+e[1][2]**2<1e-30*(e[0][0]**2+e[1][1]**2+e[2][2]**2+1e-300));a++)for(let c=0;c<3;c++)for(let u=c+1;u<3;u++){if(Math.abs(e[c][u])<1e-300)continue;let f=(e[u][u]-e[c][c])/(2*e[c][u]),d=Math.sign(f||1)/(Math.abs(f)+Math.sqrt(f*f+1)),p=1/Math.sqrt(d*d+1),g=d*p;for(let h=0;h<3;h++){let m=e[h][c],b=e[h][u];e[h][c]=p*m-g*b,e[h][u]=g*m+p*b}for(let h=0;h<3;h++){let m=e[c][h],b=e[u][h];e[c][h]=p*m-g*b,e[u][h]=g*m+p*b}for(let h=0;h<3;h++){let m=t[h][c],b=t[h][u];t[h][c]=p*m-g*b,t[h][u]=g*m+p*b}}let i=[t[0][0],t[1][0],t[2][0]],r=[t[0][1],t[1][1],t[2][1]],o=zi(i,r),n=[[i[0],r[0],o[0]],[i[1],r[1],o[1]],[i[2],r[2],o[2]]];return{values:[e[0][0],e[1][1],e[2][2]],vectors:n}}function qc(s){let e=s[0][0]+s[1][1]+s[2][2],t,i,r,o;if(e>0){let a=.5/Math.sqrt(e+1);o=.25/a,t=(s[2][1]-s[1][2])*a,i=(s[0][2]-s[2][0])*a,r=(s[1][0]-s[0][1])*a}else if(s[0][0]>s[1][1]&&s[0][0]>s[2][2]){let a=2*Math.sqrt(1+s[0][0]-s[1][1]-s[2][2]);o=(s[2][1]-s[1][2])/a,t=.25*a,i=(s[0][1]+s[1][0])/a,r=(s[0][2]+s[2][0])/a}else if(s[1][1]>s[2][2]){let a=2*Math.sqrt(1+s[1][1]-s[0][0]-s[2][2]);o=(s[0][2]-s[2][0])/a,t=(s[0][1]+s[1][0])/a,i=.25*a,r=(s[1][2]+s[2][1])/a}else{let a=2*Math.sqrt(1+s[2][2]-s[0][0]-s[1][1]);o=(s[1][0]-s[0][1])/a,t=(s[0][2]+s[2][0])/a,i=(s[1][2]+s[2][1])/a,r=.25*a}let n=Math.hypot(t,i,r,o);return[t/n,i/n,r/n,o/n]}var Ga=new WeakSet,De=s=>Ga.has(s),Vc=new WeakSet;var sr=s=>Vc.has(s);function or(s,e,t,i,r,o=[0,0,0]){let n=new Ze(s,[2*e,2*e,2*e],t,i,r,o);n.mass=t>0?4/3*Math.PI*e*e*e*t:0;let a=.4*n.mass*e*e;return n.moment.set([a,a,a]),n.radius=e,Ga.add(n),n}var Na=new WeakMap,wt=s=>Na.get(s);function Bs(s,e,t,i,r,o=[0,0,0,1],n=[0,0,0]){if(e.vertices.length/3>32||e.faces.length>255||e.edges.length>255)throw new Error(`hull: ${e.vertices.length/3} vertices, ${e.faces.length} faces, ${e.edges.length} edges (at most ${32} vertices, 255 faces and edges)`);let a=new Ze(s,e.size,t,i,r,n);return a.positionAng.set([o[0],o[1],o[2],o[3]]),a.mass=t>0?e.volume*t:0,a.moment.set(e.moments.map(l=>l*Math.max(t,0))),a.radius=e.radius,Na.set(a,e),a}var ln=`
1
+ var S=(s=0,e=0,t=0)=>Float64Array.of(s,e,t),jt=(s=0,e=0,t=0,i=1)=>Float64Array.of(s,e,t,i),oe=()=>new Float64Array(9);var Ps=s=>s<0?-1:s>0?1:0,Bt=(s,e)=>s<e?s:e,Cu=(s,e)=>s>e?s:e,ce=(s,e,t)=>Cu(e,Bt(t,s)),V=(s,e)=>s[0]*e[0]+s[1]*e[1]+s[2]*e[2],Ne=s=>V(s,s),rr=s=>Math.sqrt(Ne(s));function lt(s,e,t,i){return s[0]=e,s[1]=t,s[2]=i,s}var Li=(s,e,t)=>lt(s,e[0]+t[0],e[1]+t[1],e[2]+t[2]),J=(s,e,t)=>lt(s,e[0]-t[0],e[1]-t[1],e[2]-t[2]),ne=(s,e,t)=>lt(s,e[0]*t,e[1]*t,e[2]*t),_t=(s,e,t)=>lt(s,e[0]/t,e[1]/t,e[2]/t),ee=(s,e)=>lt(s,-e[0],-e[1],-e[2]),vn=(s,e)=>lt(s,Math.abs(e[0]),Math.abs(e[1]),Math.abs(e[2])),D=(s,e,t,i)=>lt(s,e[0]+t[0]*i,e[1]+t[1]*i,e[2]+t[2]*i),Su=(s,e)=>_t(s,e,rr(e)),Dt=(s,e,t)=>lt(s,e[1]*t[2]-e[2]*t[1],e[2]*t[0]-e[0]*t[2],e[0]*t[1]-e[1]*t[0]);function ir(s,e,t,i,r){return s[0]=e,s[1]=t,s[2]=i,s[3]=r,s}function Gr(s,e,t){let i=e[0],r=e[1],o=e[2],n=e[3],a=t[0],l=t[1],c=t[2],u=t[3];return ir(s,n*a+i*u+r*c-o*l,n*l-i*c+r*u+o*a,n*c+i*l-r*a+o*u,n*u-i*a-r*l-o*c)}var ku=(s,e)=>ir(s,-e[0],-e[1],-e[2],e[3]),Xa=s=>Ne(s)+s[3]*s[3];function xn(s,e){let t=Xa(e);return ir(s,-e[0]/t,-e[1]/t,-e[2]/t,e[3]/t)}function Pu(s,e){let t=Math.sqrt(Xa(e));return ir(s,e[0]/t,e[1]/t,e[2]/t,e[3]/t)}var tr=new Float64Array(4),Pi=new Float64Array(4);function ct(s,e,t){return Gr(tr,e,xn(tr,t)),lt(s,tr[0]*2,tr[1]*2,tr[2]*2)}function si(s,e,t){return ir(Pi,t[0],t[1],t[2],0),Gr(Pi,Pi,e),Pu(s,ir(s,e[0]+Pi[0]*.5,e[1]+Pi[1]*.5,e[2]+Pi[2]*.5,e[3]+Pi[3]*.5))}function ae(s,e,t){let i=e[0],r=e[1],o=e[2],n=e[3],a=(r*t[2]-o*t[1])*2,l=(o*t[0]-i*t[2])*2,c=(i*t[1]-r*t[0])*2;return lt(s,t[0]+a*n+(r*c-o*l),t[1]+l*n+(o*a-i*c),t[2]+c*n+(i*l-r*a))}var Ja=new Float64Array(3);function Gt(s,e,t,i){return ae(Ja,t,i),Li(s,Ja,e)}function Te(s,e,t){return ae(s,ku(tr,e),t)}function Ce(s,e,t,i){return s.fill(0),s[0]=e,s[4]=t,s[8]=i,s}function An(s,e){return s[0]=0,s[1]=-e[2],s[2]=e[1],s[3]=e[2],s[4]=0,s[5]=-e[0],s[6]=-e[1],s[7]=e[0],s[8]=0,s}function _i(s,e){let t=e[1],i=e[2],r=e[5];return s[0]=e[0],s[1]=e[3],s[2]=e[6],s[3]=t,s[4]=e[4],s[5]=e[7],s[6]=i,s[7]=r,s[8]=e[8],s}function Ke(s,e,t){let i=e[0],r=e[1],o=e[2],n=e[3],a=e[4],l=e[5],c=e[6],u=e[7],f=e[8],d=t[0],p=t[1],m=t[2],h=t[3],g=t[4],b=t[5],y=t[6],A=t[7],v=t[8];return s[0]=i*d+r*h+o*y,s[1]=i*p+r*g+o*A,s[2]=i*m+r*b+o*v,s[3]=n*d+a*h+l*y,s[4]=n*p+a*g+l*A,s[5]=n*m+a*b+l*v,s[6]=c*d+u*h+f*y,s[7]=c*p+u*g+f*A,s[8]=c*m+u*b+f*v,s}function ue(s,e,t){let i=t[0],r=t[1],o=t[2];return lt(s,e[0]*i+e[1]*r+e[2]*o,e[3]*i+e[4]*r+e[5]*o,e[6]*i+e[7]*r+e[8]*o)}function qe(s,e){for(let t=0;t<9;t++)s[t]+=e[t];return s}function Ei(s,e,t){for(let i=0;i<9;i++)s[i]=e[i]*t;return s}function Ya(s,e){for(let t=0;t<9;t++)s[t]=-e[t];return s}function Ls(s,e,t){for(let i=0;i<3;i++)for(let r=0;r<3;r++)s[i*3+r]=t[r]*e[i];return s}function Qa(s,e){let t=Math.sqrt(e[0]*e[0]+e[3]*e[3]+e[6]*e[6]),i=Math.sqrt(e[1]*e[1]+e[4]*e[4]+e[7]*e[7]),r=Math.sqrt(e[2]*e[2]+e[5]*e[5]+e[8]*e[8]);return Ce(s,t,i,r)}function _s(s,e){let t=Math.abs(e[0])>Math.abs(e[2])?S(-e[1],e[0],0):S(0,-e[2],e[1]);Su(t,t);let i=Dt(S(),e,t);return s[0]=e[0],s[1]=e[1],s[2]=e[2],s.set(t,3),s.set(i,6),s}function Es(s,e,t,i,r,o,n){let a=s[0],l=s[3],c=s[4],u=s[6],f=s[7],d=s[8],p=t[0],m=t[1],h=t[2],g=e[0],b=t[3],y=t[4],A=t[5],v=e[3],x=e[4],w=t[6],B=t[7],L=t[8],M=e[6],I=e[7],E=e[8],k=l/a,P=u/a,C=p/a,_=b/a,z=w/a,R=a,G=c-k*k*R,X=(f-k*P*R)/G,W=(m-k*C*R)/G,U=(y-k*_*R)/G,H=(B-k*z*R)/G,Z=d-(P*P*R+X*X*G),he=(h-P*C*R-X*W*G)/Z,we=(A-P*_*R-X*U*G)/Z,Oe=(L-P*z*R-X*H*G)/Z,$=g-(C*C*R+W*W*G+he*he*Z),Je=(v-C*_*R-W*U*G-he*we*Z)/$,Xe=(M-C*z*R-W*H*G-he*Oe*Z)/$,Be=x-(_*_*R+U*U*G+we*we*Z+Je*Je*$),ot=(I-_*z*R-U*H*G-we*Oe*Z-Je*Xe*$)/Be,ri=E-(z*z*R+H*H*G+Oe*Oe*Z+Xe*Xe*$+ot*ot*Be),Ye=i[0],nt=i[1]-k*Ye,Qe=i[2]-P*Ye-X*nt,at=r[0]-C*Ye-W*nt-he*Qe,wt=r[1]-_*Ye-U*nt-we*Qe-Je*at,Qi=r[2]-z*Ye-H*nt-Oe*Qe-Xe*at-ot*wt,Ki=Ye/R,Zi=nt/G,er=Qe/Z,Wt=at/$,wu=wt/Be,Bu=Qi/ri;n[2]=Bu,n[1]=wu-ot*n[2],n[0]=Wt-Je*n[1]-Xe*n[2],o[2]=er-he*n[0]-we*n[1]-Oe*n[2],o[1]=Zi-X*o[2]-W*n[0]-U*n[1]-H*n[2],o[0]=Ki-k*o[1]-P*o[2]-C*n[0]-_*n[1]-z*n[2]}var Et=1,Ve=1e10,Ms=.01,Ka=1e-5,Ze=class{solver;forces=[];positionLin;positionAng=jt();initialLin=S();initialAng=jt();inertialLin=S();inertialAng=jt();velocityLin;velocityAng=S();prevVelocityLin;size;mass;moment;friction;radius;constructor(e,t,i,r,o,n=[0,0,0]){this.solver=e,this.size=S(t[0],t[1],t[2]),this.friction=r,this.positionLin=S(o[0],o[1],o[2]),this.velocityLin=S(n[0],n[1],n[2]),this.prevVelocityLin=S(n[0],n[1],n[2]);let[a,l,c]=this.size;this.mass=a*l*c*i,this.moment=S((l*l+c*c)/12*this.mass,(a*a+c*c)/12*this.mass,(a*a+l*l)/12*this.mass),this.radius=rr([a*.5,l*.5,c*.5]),e.bodies.push(this)}constrainedTo(e){for(let t of this.forces)if(t.bodyA===this&&t.bodyB===e||t.bodyA===e&&t.bodyB===this)return!0;return!1}},zs=()=>({lhsLin:oe(),lhsAng:oe(),lhsCross:oe(),rhsLin:S(),rhsAng:S()}),Ft=class{solver;bodyA;bodyB;constructor(e,t,i){this.solver=e,this.bodyA=t,this.bodyB=i,e.forces.push(this),t?.forces.push(this),i.forces.push(this)}destroy(){let e=this.solver.forces,t=e.indexOf(this);t>=0&&e.splice(t,1),this.unlinkFromBodies()}unlinkFromBodies(){for(let e of[this.bodyA,this.bodyB]){if(!e)continue;let t=e.forces.indexOf(this);t>=0&&e.forces.splice(t,1)}}};var rl=8,Za=16,zi=1e-6,Bn=1e-5,Lu=1e-6,Cn=34028234663852886e22,Is=0,sl=1,Rs=2;function el(s){let e=s.positionAng;return{center:s.positionLin,half:ne(S(),s.size,.5),axis:[ae(S(),e,[1,0,0]),ae(S(),e,[0,1,0]),ae(S(),e,[0,0,1])]}}var Mi=(s,e)=>Math.abs(V(s,e));function Os(s,e){let t=V(e,s.axis[0])>=0?1:-1,i=V(e,s.axis[1])>=0?1:-1,r=V(e,s.axis[2])>=0?1:-1,o=D(S(),s.center,s.axis[0],s.half[0]*t);return D(o,o,s.axis[1],s.half[1]*i),D(o,o,s.axis[2],s.half[2]*r)}function ol(s,e){return e===0?{u:s.axis[1],v:s.axis[2],extentU:s.half[1],extentV:s.half[2]}:e===1?{u:s.axis[0],v:s.axis[2],extentU:s.half[0],extentV:s.half[2]}:{u:s.axis[0],v:s.axis[1],extentU:s.half[0],extentV:s.half[1]}}function _u(s,e,t){let i=V(t,s.axis[e])>=0?1:-1,r=ne(S(),s.axis[e],i),o=D(S(),s.center,r,s.half[e]);return{normal:r,center:o,...ol(s,e)}}function Eu(s,e){let t=0,i=-Cn;for(let r=0;r<3;r++){let o=Mi(s.axis[r],e);o>i&&(i=o,t=r)}return t}function Mu(s,e,t){let i=V(s.axis[e],t)>0?-1:1,r=ne(S(),s.axis[e],i),o=D(S(),s.center,r,s.half[e]),{u:n,v:a,extentU:l,extentV:c}=ol(s,e),u=(f,d)=>{let p=D(S(),o,n,f*l);return D(p,p,a,d*c)};return[u(1,1),u(-1,1),u(-1,-1),u(1,-1)]}function zu(s,e,t){let i=[];if(s.length===0)return i;let r=s[s.length-1],o=V(e,r)-t;for(let n of s){let a=V(e,n)-t,l=o<=Bn,c=a<=Bn;if(l!==c){let u=0,f=o-a;Math.abs(f)>zi&&(u=ce(o/f,0,1)),i.length<Za&&i.push(D(S(),r,J(S(),n,r),u))}c&&i.length<Za&&i.push(n),r=n,o=a}return i}var Ts=class{contacts=[];midpoints=[];bodyA;bodyB;constructor(e,t){this.bodyA=e,this.bodyB=t}add(e,t,i){let r=ne(S(),Li(S(),e,t),.5);for(let a of this.midpoints)if(Ne(J(S(),r,a))<Lu)return;if(this.contacts.length>=rl)return;let{bodyA:o,bodyB:n}=this;this.contacts.push({feature:i,rA:Te(S(),o.positionAng,J(S(),e,o.positionLin)),rB:Te(S(),n.positionAng,J(S(),t,n.positionLin))}),this.midpoints.push(r)}};function wn(s,e,t,i,r,o,n,a){let l=Ne(i);if(l<zi)return!0;let c=1/Math.sqrt(l),u=ne(S(),i,c);V(u,t)<0&&ee(u,u);let f=Math.abs(V(t,u)),d=s.half[0]*Mi(u,s.axis[0])+s.half[1]*Mi(u,s.axis[1])+s.half[2]*Mi(u,s.axis[2]),p=e.half[0]*Mi(u,e.axis[0])+e.half[1]*Mi(u,e.axis[1])+e.half[2]*Mi(u,e.axis[2]),m=f-(d+p);return m>0?!1:((!a.valid||m>a.separation)&&(a.valid=!0,a.type=r,a.indexA=o,a.indexB=n,a.separation=m,a.normalAB=u),!0)}function tl(s,e,t){let i=(e+1)%3,r=(e+2)%3,o=V(t,s.axis[i])>=0?1:-1,n=V(t,s.axis[r])>=0?1:-1,a=D(S(),s.center,s.axis[i],s.half[i]*o);D(a,a,s.axis[r],s.half[r]*n);let l=ne(S(),s.axis[e],s.half[e]);return[J(S(),a,l),Li(S(),a,l)]}function Iu(s,e,t,i){let r=J(S(),e,s),o=J(S(),i,t),n=J(S(),s,t),a=V(r,r),l=V(o,o),c=V(o,n),u=0,f=0;if(a<=zi&&l<=zi)return[s,t];if(a<=zi)f=ce(c/l,0,1);else{let d=V(r,n);if(l<=zi)u=ce(-d/a,0,1);else{let p=V(r,o),m=a*l-p*p;Math.abs(m)>zi&&(u=ce((p*c-d*l)/m,0,1)),f=(p*u+c)/l,f<0?(f=0,u=ce(-d/a,0,1)):f>1&&(f=1,u=ce((p-d)/a,0,1))}}return[D(S(),s,r,u),D(S(),t,o,f)]}function il(s,e,t,i,r,o,n){let a=r?t:i,l=r?i:t,c=r?n:ee(S(),n),u=_u(a,o,c),f=Eu(l,u.normal),d=Mu(l,f,u.normal),p=[[u.u,u.extentU],[ee(S(),u.u),u.extentU],[u.v,u.extentV],[ee(S(),u.v),u.extentV]];for(let[g,b]of p)if(d=zu(d,g,V(g,u.center)+b),!d.length)return[];let m=new Ts(s,e),h=(r?Is:sl)<<24|(o&255)<<16|(f&255)<<8;for(let g=0;g<d.length&&m.contacts.length<rl;g++){let b=d[g],y=V(J(S(),b,u.center),u.normal);if(y>Bn)continue;let A=D(S(),b,u.normal,-y),v=r?A:b,x=r?b:A;m.add(v,x,h|g&255)}return m.contacts.length||m.add(Os(t,n),Os(i,ee(S(),n)),h),m.contacts}function Ru(s,e,t,i,r,o,n){let[a,l]=tl(t,r,n),[c,u]=tl(i,o,ee(S(),n)),[f,d]=Iu(a,l,c,u),p=new Ts(s,e),m=Rs<<24|(r&255)<<8|o&255;return p.add(f,d,m),p.contacts.length||p.add(Os(t,n),Os(i,ee(S(),n)),m),p.contacts}function nl(s,e,t){let i=el(s),r=el(e),o=J(S(),r.center,i.center),n={type:Is,indexA:0,indexB:0,separation:-Cn,normalAB:S(),valid:!1},a={type:Rs,indexA:0,indexB:0,separation:-Cn,normalAB:S(),valid:!1};for(let u=0;u<3;u++)if(!wn(i,r,o,i.axis[u],Is,u,-1,n))return[];for(let u=0;u<3;u++)if(!wn(i,r,o,r.axis[u],sl,-1,u,n))return[];let l=S();for(let u=0;u<3;u++)for(let f=0;f<3;f++)if(Dt(l,i.axis[u],r.axis[f]),!wn(i,r,o,l,Rs,u,f,a))return[];if(!n.valid)return[];let c=n;return a.valid&&.95*a.separation>n.separation+.01&&(c=a),_s(t,ee(S(),c.normalAB)),c.type===Rs?Ru(s,e,i,r,c.indexA,c.indexB,c.normalAB):c.type===Is?il(s,e,i,r,!0,c.indexA,c.normalAB):il(s,e,i,r,!1,c.indexB,c.normalAB)}var al=S(),ll=S(),cl=S(),ul=S(),fl=S(),dl=S(),js=oe(),Sn=oe(),kn=oe(),Ds=oe(),Pn=oe(),Ln=oe(),_n=oe(),Gs=oe(),Me=S(),je=S(),Ii=S(),oi=S(),hl=S(),pl=S(),sr=0,Fr=0;function ml(s,e,t){for(let i=0;i<3;i++)oi[0]=t[i*3],oi[1]=t[i*3+1],oi[2]=t[i*3+2],Dt(oi,e,oi),s[i*3]=oi[0],s[i*3+1]=oi[1],s[i*3+2]=oi[2];return s}var ni=class extends Ft{contacts=[];basis=oe();friction=0;constructor(e,t,i){super(e,t,i)}get numContacts(){return this.contacts.length}initialize(){let e=this.bodyA,t=this.bodyB,{solver:i}=this;this.friction=Math.sqrt(e.friction*t.friction);let r=this.contacts;this.contacts=nl(e,t,this.basis).map(o=>{let n=r.find(a=>a.feature===o.feature);return n?{feature:o.feature,rA:n.stick?n.rA:o.rA,rB:n.stick?n.rB:o.rB,C0:S(),penalty:n.penalty.slice(),lambda:n.lambda.slice(),stick:n.stick}:{feature:o.feature,rA:o.rA,rB:o.rB,C0:S(),penalty:S(),lambda:S(),stick:!1}});for(let o of this.contacts){Gt(hl,e.positionLin,e.positionAng,o.rA),Gt(pl,t.positionLin,t.positionAng,o.rB),ue(o.C0,this.basis,J(Ii,hl,pl)),o.C0[0]+=Ms;for(let n=0;n<3;n++)o.lambda[n]=o.lambda[n]*i.alpha*i.gamma,o.penalty[n]=ce(o.penalty[n]*i.gamma,Et,Ve)}return this.contacts.length>0}evaluate(e,t){let i=this.bodyA,r=this.bodyB,o=this.basis;ae(fl,i.positionAng,e.rA),ae(dl,r.positionAng,e.rB),Ya(js,o),ml(Sn,fl,o),ml(kn,dl,js),Ce(Ds,e.penalty[0],e.penalty[1],e.penalty[2]),ne(Me,e.C0,1-t),D(Me,Me,ue(Ii,o,al),1),D(Me,Me,ue(Ii,js,cl),1),D(Me,Me,ue(Ii,Sn,ll),1),D(Me,Me,ue(Ii,kn,ul),1),ue(je,Ds,Me),D(je,je,e.lambda,1),je[0]=Bt(je[0],0),Fr=Math.abs(je[0])*this.friction,sr=Math.sqrt(je[1]*je[1]+je[2]*je[2]),sr>Fr&&sr>0&&(je[1]*=Fr/sr,je[2]*=Fr/sr)}computeDisplacements(){let e=this.bodyA,t=this.bodyB;J(al,e.positionLin,e.initialLin),ct(ll,e.positionAng,e.initialAng),J(cl,t.positionLin,t.initialLin),ct(ul,t.positionAng,t.initialAng)}updatePrimal(e,t,i){this.computeDisplacements();let r=e===this.bodyA;for(let o of this.contacts){this.evaluate(o,t);let n=r?this.basis:js,a=r?Sn:kn;_i(Pn,n),_i(Ln,a),Ke(_n,Ln,Ds),qe(i.lhsLin,Ke(Gs,Ke(Gs,Pn,Ds),n)),qe(i.lhsAng,Ke(Gs,_n,a)),qe(i.lhsCross,Ke(Gs,_n,n)),D(i.rhsLin,i.rhsLin,ue(Ii,Pn,je),1),D(i.rhsAng,i.rhsAng,ue(Ii,Ln,je),1)}}updateDual(e){let{solver:t}=this;this.computeDisplacements();for(let i of this.contacts)this.evaluate(i,e),i.lambda.set(je),je[0]<0&&(i.penalty[0]=Bt(i.penalty[0]+t.betaLin*Math.abs(Me[0]),Ve)),sr<=Fr&&(i.penalty[1]=Bt(i.penalty[1]+t.betaLin*Math.abs(Me[1]),Ve),i.penalty[2]=Bt(i.penalty[2]+t.betaLin*Math.abs(Me[2]),Ve),i.stick=Math.sqrt(Me[1]*Me[1]+Me[2]*Me[2])<Ka)}};var En=()=>({dt:1/60,gravity:-10,iterations:10,betaLin:1e4,betaAng:100,alpha:.99,gamma:.999}),ai=class{dt=1/60;gravity=-10;iterations=10;alpha=.99;betaLin=1e4;betaAng=100;gamma=.999;bodies=[];forces=[];constructor(){this.defaultParams()}defaultParams(){Object.assign(this,En())}clear(){this.forces=[],this.bodies=[]}pick(e,t){let r=null,o=S(),n=S();for(let a=this.bodies.length-1;a>=0;a--){let l=this.bodies[a];if(l.mass<=0)continue;Te(o,l.positionAng,J(o,e,l.positionLin)),Te(n,l.positionAng,t);let c=0,u=1/0,f=!0;for(let p=0;p<3&&f;p++){let m=l.size[p]*.5;if(Math.abs(n[p])<1e-6){(o[p]<-m||o[p]>m)&&(f=!1);continue}let h=1/n[p],g=(-m-o[p])*h,b=(m-o[p])*h;g>b&&([g,b]=[b,g]),c=Math.max(c,g),u=Math.min(u,b),c>u&&(f=!1)}if(!f)continue;let d=c>=0?c:u;d<0||(!r||d<r.t)&&(r={body:l,local:D(S(),o,n,d),t:d})}return r}sys=zs();dxLin=S();dxAng=S();dp=S();accel=S();step(){let{dt:e,gravity:t,bodies:i,sys:r,dp:o}=this;for(let a=i.length-1;a>=0;a--){let l=i[a];for(let c=a-1;c>=0;c--){let u=i[c];J(o,l.positionLin,u.positionLin);let f=l.radius+u.radius;V(o,o)<=f*f&&!l.constrainedTo(u)&&new ni(this,l,u)}}let n=[];for(let a of this.forces)a.initialize()?n.push(a):a.unlinkFromBodies();this.forces=n;for(let a=i.length-1;a>=0;a--){let l=i[a];D(l.inertialLin,l.positionLin,l.velocityLin,e),l.mass>0&&(l.inertialLin[2]+=t*(e*e)),si(l.inertialAng,l.positionAng,gl(l.velocityAng,e)),_t(this.accel,J(this.accel,l.velocityLin,l.prevVelocityLin),e);let c=this.accel[2]*Ps(t),u=ce(c/Math.abs(t),0,1);Number.isFinite(u)||(u=0),l.initialLin.set(l.positionLin),l.initialAng.set(l.positionAng),l.mass>0&&(D(l.positionLin,l.positionLin,l.velocityLin,e),l.positionLin[2]+=t*(u*e*e),si(l.positionAng,l.positionAng,gl(l.velocityAng,e)))}for(let a=0;a<this.iterations;a++){for(let l=i.length-1;l>=0;l--){let c=i[l];if(c.mass<=0)continue;let u=c.mass,f=c.moment;Ce(r.lhsLin,u/(e*e),u/(e*e),u/(e*e)),Ce(r.lhsAng,f[0]/(e*e),f[1]/(e*e),f[2]/(e*e)),r.lhsCross.fill(0),ue(r.rhsLin,r.lhsLin,J(o,c.positionLin,c.inertialLin)),ue(r.rhsAng,r.lhsAng,ct(o,c.positionAng,c.inertialAng));let d=c.forces;for(let p=d.length-1;p>=0;p--)d[p].updatePrimal(c,this.alpha,r);Es(r.lhsLin,r.lhsAng,r.lhsCross,ee(r.rhsLin,r.rhsLin),ee(r.rhsAng,r.rhsAng),this.dxLin,this.dxAng),D(c.positionLin,c.positionLin,this.dxLin,1),si(c.positionAng,c.positionAng,this.dxAng)}for(let l of this.forces)l.updateDual(this.alpha)}for(let a of i)a.prevVelocityLin.set(a.velocityLin),a.mass>0&&(_t(a.velocityLin,J(a.velocityLin,a.positionLin,a.initialLin),e),_t(a.velocityAng,ct(a.velocityAng,a.positionAng,a.initialAng),e))}},Ou=S(),gl=(s,e)=>ne(Ou,s,e);var xe=(s,e)=>[s[0]-e[0],s[1]-e[1],s[2]-e[2]],Mt=(s,e)=>s[0]*e[0]+s[1]*e[1]+s[2]*e[2],Ri=(s,e)=>[s[1]*e[2]-s[2]*e[1],s[2]*e[0]-s[0]*e[2],s[0]*e[1]-s[1]*e[0]],et=s=>Math.sqrt(Mt(s,s));function Ur(s){let e=Mn(s);return!e||e.vertices.length/3<=32?e:Mn(bl(e,32))}function bl(s,e){let[t,i,r,o]=s.rotation,n=f=>{let d=[2*(i*f[2]-r*f[1]),2*(r*f[0]-t*f[2]),2*(t*f[1]-i*f[0])];return[f[0]+o*d[0]+(i*d[2]-r*d[1])+s.center[0],f[1]+o*d[1]+(r*d[0]-t*d[2])+s.center[1],f[2]+o*d[2]+(t*d[1]-i*d[0])+s.center[2]]},a=[];for(let f=0;f<s.vertices.length;f+=3)a.push(n([s.vertices[f],s.vertices[f+1],s.vertices[f+2]]));let l=0;a.forEach((f,d)=>{et(xe(f,s.center))>et(xe(a[l],s.center))&&(l=d)});let c=[l],u=a.map(f=>et(xe(f,a[l])));for(;c.length<e;){let f=0;u.forEach((d,p)=>{d>u[f]&&(f=p)}),c.push(f),a.forEach((d,p)=>{u[p]=Math.min(u[p],et(xe(d,a[f])))})}return c.flatMap(f=>a[f])}function Mn(s){let e=0;for(let v=0;v<s.length;v++)e=Math.max(e,Math.abs(s[v]));let t=Math.max(e,1e-9)*1e-6,i=new Set,r=[];for(let v=0;v+2<s.length;v+=3){let x=[s[v],s[v+1],s[v+2]],w=x.map(B=>Math.round(B/t)).join(",");i.has(w)||(i.add(w),r.push(x))}if(r.length<4)return null;let o=Math.max(e,1e-9)*1e-10,n=0;for(let v=1;v<r.length;v++)r[v][0]<r[n][0]&&(n=v);let a=-1,l=0;for(let v=0;v<r.length;v++){let x=et(xe(r[v],r[n]));x>l&&(l=x,a=v)}if(a<0||l<o)return null;let c=-1;l=0;let u=xe(r[a],r[n]);for(let v=0;v<r.length;v++){let x=et(Ri(u,xe(r[v],r[n])));x>l&&(l=x,c=v)}if(c<0||l<o*et(u))return null;let f=Ri(u,xe(r[c],r[n])),d=-1;l=0;for(let v=0;v<r.length;v++){let x=Math.abs(Mt(f,xe(r[v],r[n])));x>l&&(l=x,d=v)}if(d<0||l<o*et(f))return null;let p=[],m=(v,x,w)=>{let B=Ri(xe(r[x],r[v]),xe(r[w],r[v])),L=et(B)||1,M=[B[0]/L,B[1]/L,B[2]/L];return{v:[v,x,w],n:M,d:Mt(M,r[v])}},g=Mt(f,xe(r[d],r[n]))>0?[n,c,a]:[n,a,c];p.push(m(g[0],g[1],g[2])),p.push(m(g[0],d,g[1])),p.push(m(g[1],d,g[2])),p.push(m(g[2],d,g[0]));let b=new Set([n,a,c,d]),y=r.map((v,x)=>x).filter(v=>!b.has(v)),A=[n,a,c,d].reduce((v,x)=>[v[0]+r[x][0]/4,v[1]+r[x][1]/4,v[2]+r[x][2]/4],[0,0,0]);y.sort((v,x)=>et(xe(r[x],A))-et(xe(r[v],A)));for(let v of y){let x=p.filter(k=>Mt(k.n,r[v])-k.d>o);if(!x.length)continue;let w=new Map;for(let k of p)for(let P=0;P<3;P++)w.set(`${k.v[P]},${k.v[(P+1)%3]}`,k);let B=new Set(x),L=[...x];for(;L.length;){let k=L.pop();for(let P=0;P<3;P++){let C=w.get(`${k.v[(P+1)%3]},${k.v[P]}`);C&&!B.has(C)&&Mt(C.n,r[v])-C.d>-o&&(B.add(C),L.push(C))}}let M=[...B],I=new Set;for(let k of M)for(let P=0;P<3;P++)I.add(`${k.v[P]},${k.v[(P+1)%3]}`);let E=[];for(let k of M)for(let P=0;P<3;P++){let C=k.v[P],_=k.v[(P+1)%3];I.has(`${_},${C}`)||E.push([C,_])}for(let k of M)p.splice(p.indexOf(k),1);for(let[k,P]of E)p.push(m(k,P,v))}return yl(r.flat(),p.flatMap(v=>v.v))}function zn(s,e){let t=yl(s,e);return t&&t.vertices.length/3>32?Mn(bl(t,32)):t}function yl(s,e){let t=[];for(let C=0;C+2<s.length;C+=3)t.push([s[C],s[C+1],s[C+2]]);let i=0;for(let C of t)i=Math.max(i,Math.abs(C[0]),Math.abs(C[1]),Math.abs(C[2]));let r=Math.max(i,1e-9)*1e-5,o=[];for(let C=0;C+2<e.length;C+=3){let _=[e[C],e[C+1],e[C+2]],z=Ri(xe(t[_[1]],t[_[0]]),xe(t[_[2]],t[_[0]])),R=et(z);if(!(R>0))continue;let G=[z[0]/R,z[1]/R,z[2]/R];o.push({v:_,n:G,d:Mt(G,t[_[0]])})}let n=new Map;o.forEach((C,_)=>{for(let z=0;z<3;z++)n.set(`${C.v[z]},${C.v[(z+1)%3]}`,_)});let a=new Array(o.length).fill(-1),l=[];o.forEach((C,_)=>{if(a[_]>=0)return;let z=[_];a[_]=l.length;for(let R=0;R<z.length;R++){let G=o[z[R]];for(let X=0;X<3;X++){let W=n.get(`${G.v[(X+1)%3]},${G.v[X]}`);if(W===void 0||a[W]>=0)continue;let U=o[W];Mt(C.n,U.n)>1-1e-5&&U.v.every(H=>Math.abs(Mt(C.n,t[H])-C.d)<=r)&&(a[W]=l.length,z.push(W))}}l.push(z)});let c=[];for(let C of l){let _=new Set;for(let U of C)for(let H=0;H<3;H++)_.add(`${o[U].v[H]},${o[U].v[(H+1)%3]}`);let z=new Map;for(let U of C)for(let H=0;H<3;H++){let Z=o[U].v[H],he=o[U].v[(H+1)%3];if(!_.has(`${he},${Z}`)){if(z.has(Z))return null;z.set(Z,he)}}let R=[0,0,0];for(let U of C){let H=o[U],Z=Ri(xe(t[H.v[1]],t[H.v[0]]),xe(t[H.v[2]],t[H.v[0]]));R[0]+=Z[0],R[1]+=Z[1],R[2]+=Z[2]}let G=et(R)||1,X=z.keys().next().value,W=[X];for(let U=z.get(X);U!==X&&W.length<=z.size;U=z.get(U))W.push(U);if(W.length!==z.size)return null;c.push({n:[R[0]/G,R[1]/G,R[2]/G],verts:W})}let u=new Map,f=[];for(let C of c)for(let _ of C.verts)u.has(_)||(u.set(_,f.length),f.push(t[_]));for(let C of c)C.verts=C.verts.map(_=>u.get(_));let d=new Set,p=0;for(let C of c)C.verts.forEach((_,z)=>{d.add(`${_},${C.verts[(z+1)%C.verts.length]}`),p++});if(d.size!==p||![...d].every(C=>{let[_,z]=C.split(",");return d.has(`${z},${_}`)})||f.length-d.size/2+c.length!==2)return null;let m=0,h=[0,0,0],g=[0,0,0,0,0,0];for(let C of c){let _=f[C.verts[0]];for(let z=1;z+1<C.verts.length;z++){let R=f[C.verts[z]],G=f[C.verts[z+1]],X=Mt(_,Ri(R,G));m+=X/6;for(let U=0;U<3;U++)h[U]+=X/24*(_[U]+R[U]+G[U]);let W=(U,H)=>X/120*(_[U]*_[H]+R[U]*R[H]+G[U]*G[H]+(_[U]+R[U]+G[U])*(_[H]+R[H]+G[H]));g[0]+=W(0,0),g[1]+=W(1,1),g[2]+=W(2,2),g[3]+=W(0,1),g[4]+=W(0,2),g[5]+=W(1,2)}}if(!(m>0))return null;for(let C=0;C<3;C++)h[C]/=m;g[0]-=m*h[0]*h[0],g[1]-=m*h[1]*h[1],g[2]-=m*h[2]*h[2],g[3]-=m*h[0]*h[1],g[4]-=m*h[0]*h[2],g[5]-=m*h[1]*h[2];let b=g[0]+g[1]+g[2],y=[[b-g[0],-g[3],-g[4]],[-g[3],b-g[1],-g[5]],[-g[4],-g[5],b-g[2]]],{values:A,vectors:v}=Tu(y),x=v,w=C=>{let _=xe(C,h);return[x[0][0]*_[0]+x[1][0]*_[1]+x[2][0]*_[2],x[0][1]*_[0]+x[1][1]*_[1]+x[2][1]*_[2],x[0][2]*_[0]+x[1][2]*_[1]+x[2][2]*_[2]]},B=f.map(w),L=new Float32Array(B.flat()),M=c.map(C=>{let _=C.n,z=[x[0][0]*_[0]+x[1][0]*_[1]+x[2][0]*_[2],x[0][1]*_[0]+x[1][1]*_[1]+x[2][1]*_[2],x[0][2]*_[0]+x[1][2]*_[1]+x[2][2]*_[2]],R=-1/0;for(let G of C.verts)R=Math.max(R,Mt(z,B[G]));return{normal:z,d:R,verts:C.verts}}),I=new Map;M.forEach((C,_)=>C.verts.forEach((z,R)=>I.set(`${z},${C.verts[(R+1)%C.verts.length]}`,_)));let E=[];M.forEach((C,_)=>C.verts.forEach((z,R)=>{let G=C.verts[(R+1)%C.verts.length],X=I.get(`${G},${z}`);z<G&&X!==void 0&&E.push([z,G,_,X])}));let k=[0,0,0],P=0;for(let C of B){for(let _=0;_<3;_++)k[_]=Math.max(k[_],2*Math.abs(C[_]));P=Math.max(P,et(C))}return{vertices:L,faces:M,edges:E,volume:m,moments:[A[0],A[1],A[2]],size:k,radius:P,center:h,rotation:ju(x)}}function Tu(s){let e=s.map(a=>[...a]),t=[[1,0,0],[0,1,0],[0,0,1]];for(let a=0;a<50&&!(e[0][1]**2+e[0][2]**2+e[1][2]**2<1e-30*(e[0][0]**2+e[1][1]**2+e[2][2]**2+1e-300));a++)for(let c=0;c<3;c++)for(let u=c+1;u<3;u++){if(Math.abs(e[c][u])<1e-300)continue;let f=(e[u][u]-e[c][c])/(2*e[c][u]),d=Math.sign(f||1)/(Math.abs(f)+Math.sqrt(f*f+1)),p=1/Math.sqrt(d*d+1),m=d*p;for(let h=0;h<3;h++){let g=e[h][c],b=e[h][u];e[h][c]=p*g-m*b,e[h][u]=m*g+p*b}for(let h=0;h<3;h++){let g=e[c][h],b=e[u][h];e[c][h]=p*g-m*b,e[u][h]=m*g+p*b}for(let h=0;h<3;h++){let g=t[h][c],b=t[h][u];t[h][c]=p*g-m*b,t[h][u]=m*g+p*b}}let i=[t[0][0],t[1][0],t[2][0]],r=[t[0][1],t[1][1],t[2][1]],o=Ri(i,r),n=[[i[0],r[0],o[0]],[i[1],r[1],o[1]],[i[2],r[2],o[2]]];return{values:[e[0][0],e[1][1],e[2][2]],vectors:n}}function ju(s){let e=s[0][0]+s[1][1]+s[2][2],t,i,r,o;if(e>0){let a=.5/Math.sqrt(e+1);o=.25/a,t=(s[2][1]-s[1][2])*a,i=(s[0][2]-s[2][0])*a,r=(s[1][0]-s[0][1])*a}else if(s[0][0]>s[1][1]&&s[0][0]>s[2][2]){let a=2*Math.sqrt(1+s[0][0]-s[1][1]-s[2][2]);o=(s[2][1]-s[1][2])/a,t=.25*a,i=(s[0][1]+s[1][0])/a,r=(s[0][2]+s[2][0])/a}else if(s[1][1]>s[2][2]){let a=2*Math.sqrt(1+s[1][1]-s[0][0]-s[2][2]);o=(s[0][2]-s[2][0])/a,t=(s[0][1]+s[1][0])/a,i=.25*a,r=(s[1][2]+s[2][1])/a}else{let a=2*Math.sqrt(1+s[2][2]-s[0][0]-s[1][1]);o=(s[1][0]-s[0][1])/a,t=(s[0][2]+s[2][0])/a,i=(s[1][2]+s[2][1])/a,r=.25*a}let n=Math.hypot(t,i,r,o);return[t/n,i/n,r/n,o/n]}var xl=new WeakSet,De=s=>xl.has(s),Du=new WeakSet;var or=s=>Du.has(s);function nr(s,e,t,i,r,o=[0,0,0]){let n=new Ze(s,[2*e,2*e,2*e],t,i,r,o);n.mass=t>0?4/3*Math.PI*e*e*e*t:0;let a=.4*n.mass*e*e;return n.moment.set([a,a,a]),n.radius=e,xl.add(n),n}var Al=new WeakMap,Ct=s=>Al.get(s);function ar(s,e,t,i,r,o=[0,0,0,1],n=[0,0,0]){if(e.vertices.length/3>32||e.faces.length>255||e.edges.length>255)throw new Error(`hull: ${e.vertices.length/3} vertices, ${e.faces.length} faces, ${e.edges.length} edges (at most ${32} vertices, 255 faces and edges)`);let a=new Ze(s,e.size,t,i,r,n);return a.positionAng.set([o[0],o[1],o[2],o[3]]),a.mass=t>0?e.volume*t:0,a.moment.set(e.moments.map(l=>l*Math.max(t,0))),a.radius=e.radius,Al.set(a,e),a}var In=`
2
2
  const T_NONE = 0;
3
3
 
4
4
  const MAX_COLORS = 64u;
@@ -38,9 +38,9 @@ fn hash32(v: u32) -> u32 {
38
38
  x ^= x >> 16u;
39
39
  return x;
40
40
  }
41
- `,Nt=`
41
+ `,Ut=`
42
42
  // Shared by every 2D module (layout.ts)
43
- ${ln}
43
+ ${In}
44
44
  const T_JOINT = 1;
45
45
  const T_SPRING = 2;
46
46
  const T_MOTOR = 3;
@@ -148,7 +148,7 @@ fn rot(angle: f32, v: vec2f) -> vec2f {
148
148
  return vec2f(cs.x * v.x - cs.y * v.y, cs.y * v.x + cs.x * v.y);
149
149
  }
150
150
 
151
- `,cn=(s,e={counter:"C_CONTACTS",prevCounter:"C_PREV_CONTACTS",capacity:"params.contactCapacity"})=>`
151
+ `,Nr=(s,e={counter:"C_CONTACTS",prevCounter:"C_PREV_CONTACTS",capacity:"params.contactCapacity"})=>`
152
152
  ${s}
153
153
  ${e.colorThreads??"fn colorThreads(bodies: u32) -> u32 { return bodies; }"}
154
154
 
@@ -185,7 +185,7 @@ fn argsColors(@builtin(local_invocation_id) lid: vec3u) {
185
185
  let c = lid.x;
186
186
  setArgs(IA_COLOR + 3u * c, colorThreads(color[params.colorStartOffset + c + 1u] - color[params.colorStartOffset + c]));
187
187
  }
188
- `,Cs=cn(Nt),Se=["collision","adjacency","coloring","solve"];var Wc=`
188
+ `,Fs=Nr(Ut),Se=["collision","adjacency","coloring","solve"];var Gu=`
189
189
  struct ScanParams {
190
190
  offset: u32, // first element of the range in data
191
191
  n: u32, // elements in the range
@@ -233,7 +233,7 @@ fn addBlocks(@builtin(workgroup_id) wid: vec3u, @builtin(local_invocation_id) li
233
233
  if (base < sp.n) { data[sp.offset + base] += add; }
234
234
  if (base + 1u < sp.n) { data[sp.offset + base + 1u] += add; }
235
235
  }
236
- `,tt=class{levels=[];buffers=[];scanPipeline;addPipeline;constructor(e,t,i,r){let o=e.createShaderModule({label:"prefix scan",code:Wc}),n=e.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}},{binding:2,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}}]}),a=e.createPipelineLayout({bindGroupLayouts:[n]});this.scanPipeline=e.createComputePipeline({label:"scanBlocks",layout:a,compute:{module:o,entryPoint:"scanBlocks"}}),this.addPipeline=e.createComputePipeline({label:"addBlocks",layout:a,compute:{module:o,entryPoint:"addBlocks"}});let l=t,c=i,u=r;for(;;){let f=Math.max(1,Math.ceil(u/512)),d=e.createBuffer({label:`scan sums ${this.levels.length}`,size:Math.max(f,4)*4,usage:GPUBufferUsage.STORAGE}),p=e.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});new Uint32Array(p.getMappedRange()).set([c,u,0,0]),p.unmap(),this.buffers.push(d,p);let g=e.createBindGroup({layout:n,entries:[{binding:0,resource:{buffer:p}},{binding:1,resource:{buffer:l}},{binding:2,resource:{buffer:d}}]});if(this.levels.push({n:u,blocks:f,group:g}),f===1)break;l=d,c=0,u=f}}encode(e){e.setPipeline(this.scanPipeline);for(let t of this.levels)e.setBindGroup(0,t.group),e.dispatchWorkgroups(t.blocks);e.setPipeline(this.addPipeline);for(let t=this.levels.length-2;t>=0;t--)e.setBindGroup(0,this.levels[t].group),e.dispatchWorkgroups(this.levels[t].blocks)}destroy(){for(let e of this.buffers)e.destroy()}};var Hc=`
236
+ `,tt=class{levels=[];buffers=[];scanPipeline;addPipeline;constructor(e,t,i,r){let o=e.createShaderModule({label:"prefix scan",code:Gu}),n=e.createBindGroupLayout({entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform"}},{binding:1,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}},{binding:2,visibility:GPUShaderStage.COMPUTE,buffer:{type:"storage"}}]}),a=e.createPipelineLayout({bindGroupLayouts:[n]});this.scanPipeline=e.createComputePipeline({label:"scanBlocks",layout:a,compute:{module:o,entryPoint:"scanBlocks"}}),this.addPipeline=e.createComputePipeline({label:"addBlocks",layout:a,compute:{module:o,entryPoint:"addBlocks"}});let l=t,c=i,u=r;for(;;){let f=Math.max(1,Math.ceil(u/512)),d=e.createBuffer({label:`scan sums ${this.levels.length}`,size:Math.max(f,4)*4,usage:GPUBufferUsage.STORAGE}),p=e.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});new Uint32Array(p.getMappedRange()).set([c,u,0,0]),p.unmap(),this.buffers.push(d,p);let m=e.createBindGroup({layout:n,entries:[{binding:0,resource:{buffer:p}},{binding:1,resource:{buffer:l}},{binding:2,resource:{buffer:d}}]});if(this.levels.push({n:u,blocks:f,group:m}),f===1)break;l=d,c=0,u=f}}encode(e){e.setPipeline(this.scanPipeline);for(let t of this.levels)e.setBindGroup(0,t.group),e.dispatchWorkgroups(t.blocks);e.setPipeline(this.addPipeline);for(let t=this.levels.length-2;t>=0;t--)e.setBindGroup(0,this.levels[t].group),e.dispatchWorkgroups(this.levels[t].blocks)}destroy(){for(let e of this.buffers)e.destroy()}};var Fu=`
237
237
  alias TopoItem = Contact;
238
238
 
239
239
  fn topoCount() -> u32 {
@@ -254,7 +254,7 @@ fn jointActive(j: u32) -> bool {
254
254
  let s = joints[j].stiff;
255
255
  return info[j].x != T_NONE && (s.x != 0.0 || s.y != 0.0 || s.z != 0.0);
256
256
  }
257
- `,Ri=(s,e)=>`
257
+ `,Ti=(s,e)=>`
258
258
  ${s}
259
259
  ${e}
260
260
 
@@ -532,11 +532,11 @@ fn colorScatter(@builtin(global_invocation_id) gid: vec3u, @builtin(workgroup_id
532
532
  let slot = atomicLoad(&color[params.colorHistOffset + col * params.colorGroups + wid.x]) + state(params.stateBOffset, b);
533
533
  atomicStore(&color[params.colorBodiesOffset + slot], b);
534
534
  }
535
- `,Dr=Ri(Nt,Hc);var Jc=jt(),zt=oe(),Ss=oe(),Oi=oe(),un=oe(),nr=oe(),fn=oe(),ct=oe(),ks=oe(),Fr=oe(),be=C(),Me=C(),ye=C(),ai=C(),ar=C();function dn(s,e,t){return Ce(s,-t[e],-t[e],-t[e]),s[e]+=t[0],s[3+e]+=t[1],s[6+e]+=t[2],s}var Ps=(s,e,t)=>at(s,xt(e[0],t),xt(e[1],t),xt(e[2],t)),ke=class extends Gt{rA;rB;C0Lin=C();C0Ang=C();penaltyLin=C();penaltyAng=C();lambdaLin=C();lambdaAng=C();stiffnessLin;stiffnessAng;fracture;torqueArm;broken=!1;constructor(e,t,i,r,o,n=1/0,a=0,l=1/0){super(e,t,i),this.rA=C(r[0],r[1],r[2]),this.rB=C(o[0],o[1],o[2]),this.stiffnessLin=n,this.stiffnessAng=a,this.fracture=l;let c=t?t.size:[0,0,0];this.torqueArm=Ge([c[0]+i.size[0],c[1]+i.size[1],c[2]+i.size[2]])}evaluateLin(e){let{bodyA:t,bodyB:i}=this;return t?Ft(ai,t.positionLin,t.positionAng,this.rA):ai.set(this.rA),$(e,ai,Ft(ar,i.positionLin,i.positionAng,this.rB))}evaluateAng(e){return lt(e,this.bodyA?this.bodyA.positionAng:Jc,this.bodyB.positionAng),ne(e,e,this.torqueArm)}initialize(){let{solver:e}=this;this.evaluateLin(this.C0Lin),this.evaluateAng(this.C0Ang);for(let t=0;t<3;t++)this.lambdaLin[t]=this.lambdaLin[t]*e.alpha*e.gamma,this.lambdaAng[t]=this.lambdaAng[t]*e.alpha*e.gamma,this.penaltyLin[t]=ce(this.penaltyLin[t]*e.gamma,Et,Ue),this.penaltyAng[t]=ce(this.penaltyAng[t]*e.gamma,Et,Ue);return Ps(this.penaltyLin,this.penaltyLin,this.stiffnessLin),Ps(this.penaltyAng,this.penaltyAng,this.stiffnessAng),!this.broken}updatePrimal(e,t,i){let r=e===this.bodyA;if(Ge(this.penaltyLin)>0){Ce(zt,this.penaltyLin[0],this.penaltyLin[1],this.penaltyLin[2]),this.evaluateLin(be),this.stiffnessLin===1/0&&D(be,be,this.C0Lin,-t),ue(Me,zt,be),D(Me,Me,this.lambdaLin,1);let o=r?1:-1;Ce(Ss,o,o,o),r?Qo(Oi,ee(ye,ae(ye,this.bodyA.positionAng,this.rA))):Qo(Oi,ae(ye,this.bodyB.positionAng,this.rB)),Pi(un,Ss),Pi(nr,Oi),Ke(fn,nr,zt),Ne(i.lhsLin,Ke(ct,Ke(ct,un,zt),Ss)),Ne(i.lhsAng,Ke(ct,fn,Oi)),Ne(i.lhsCross,Ke(ct,fn,Ss)),r?ae(ye,this.bodyA.positionAng,this.rA):ee(ye,ae(ye,this.bodyB.positionAng,this.rB)),Li(ks,dn(Fr,0,ye),Me[0]),Ne(ks,Li(Fr,dn(Fr,1,ye),Me[1])),Ne(ks,Li(Fr,dn(Fr,2,ye),Me[2])),Ne(i.lhsAng,ya(ct,ks)),D(i.rhsLin,i.rhsLin,ue(ye,un,Me),1),D(i.rhsAng,i.rhsAng,ue(ye,nr,Me),1)}if(Ge(this.penaltyAng)>0){Ce(zt,this.penaltyAng[0],this.penaltyAng[1],this.penaltyAng[2]),this.evaluateAng(be),this.stiffnessAng===1/0&&D(be,be,this.C0Ang,-t),ue(Me,zt,be),D(Me,Me,this.lambdaAng,1);let o=(r?1:-1)*this.torqueArm;Ce(Oi,o,o,o),Pi(nr,Oi),Ne(i.lhsAng,Ke(ct,Ke(ct,nr,zt),Oi)),D(i.rhsAng,i.rhsAng,ue(ye,nr,Me),1)}}updateDual(e){let{solver:t}=this;Ge(this.penaltyLin)>0&&(Ce(zt,this.penaltyLin[0],this.penaltyLin[1],this.penaltyLin[2]),this.evaluateLin(be),this.stiffnessLin===1/0&&(D(be,be,this.C0Lin,-e),ue(Me,zt,be),D(this.lambdaLin,Me,this.lambdaLin,1)),D(this.penaltyLin,this.penaltyLin,Xo(ye,be),t.betaLin),Ps(this.penaltyLin,this.penaltyLin,xt(this.stiffnessLin,Ue))),Ge(this.penaltyAng)>0&&(Ce(zt,this.penaltyAng[0],this.penaltyAng[1],this.penaltyAng[2]),this.evaluateAng(be),this.stiffnessAng===1/0&&(D(be,be,this.C0Ang,-e),ue(Me,zt,be),D(this.lambdaAng,Me,this.lambdaAng,1)),D(this.penaltyAng,this.penaltyAng,Xo(ye,be),t.betaAng),Ps(this.penaltyAng,this.penaltyAng,xt(this.stiffnessAng,Ue))),Ge(this.lambdaAng)>this.fracture*this.fracture&&(this.penaltyLin.fill(0),this.penaltyAng.fill(0),this.lambdaLin.fill(0),this.lambdaAng.fill(0),this.broken=!0)}},ut=class extends Gt{rA;rB;rest;stiffness;constructor(e,t,i,r,o,n,a=-1){super(e,t,i),this.rA=C(r[0],r[1],r[2]),this.rB=C(o[0],o[1],o[2]),this.stiffness=n,this.rest=a,this.rest<0&&(Ft(ai,t.positionLin,t.positionAng,this.rA),Ft(ar,i.positionLin,i.positionAng,this.rB),this.rest=ir($(be,ai,ar)))}initialize(){return!0}updatePrimal(e,t,i){let r=this.bodyA,o=this.bodyB;Ft(ai,r.positionLin,r.positionAng,this.rA),Ft(ar,o.positionLin,o.positionAng,this.rB);let n=$(be,ai,ar),a=ir(n);if(a<=1e-6)return;let l=_t(Me,n,a),c=a-this.rest,u=this.stiffness*c,f=ai,d=ar;e===r?(ae(ye,r.positionAng,this.rA),f.set(l),Dt(d,ye,l)):(ae(ye,o.positionAng,this.rB),ee(f,l),ee(d,Dt(d,ye,l))),Ne(i.lhsLin,Li(ct,fs(ct,f,f),this.stiffness)),Ne(i.lhsAng,Li(ct,fs(ct,d,d),this.stiffness)),Ne(i.lhsCross,Li(ct,fs(ct,d,f),this.stiffness)),D(i.rhsLin,i.rhsLin,ne(ye,f,u),1),D(i.rhsAng,i.rhsAng,ne(ye,d,u),1)}updateDual(){}},Ls=class extends Gt{initialize(){return!0}updatePrimal(){}updateDual(){}};var qe=40,lr=0,Gr=4,Ua=8,qa=12,hn=16,pn=20,Va=24,Wa=28,mn=32,gn=36,pe=32,li=0,Nr=4,cr=8,ur=12,Ha=16,Ja=20,ci=24,fr=28,Ut=8;var _s=4,Ht=16,dr=0,Es=4,Ms=8,zs=12,Ur=2147483648,hr=6,$c=7,$a=0,bn=1,yn=2,Is=3,qr=1,pr=2,vn=1,An=2,xn=4,wn=8,Bn=16,Xc=.1,Xa=.002,Ya=.002,Yc=.05,Cn=44,Ae=`
535
+ `,qr=Ti(Ut,Fu);var Uu=jt(),zt=oe(),Us=oe(),ji=oe(),Rn=oe(),lr=oe(),On=oe(),ut=oe(),Ns=oe(),Vr=oe(),ye=S(),ze=S(),ve=S(),li=S(),cr=S();function Tn(s,e,t){return Ce(s,-t[e],-t[e],-t[e]),s[e]+=t[0],s[3+e]+=t[1],s[6+e]+=t[2],s}var qs=(s,e,t)=>lt(s,Bt(e[0],t),Bt(e[1],t),Bt(e[2],t)),ke=class extends Ft{rA;rB;C0Lin=S();C0Ang=S();penaltyLin=S();penaltyAng=S();lambdaLin=S();lambdaAng=S();stiffnessLin;stiffnessAng;fracture;torqueArm;broken=!1;constructor(e,t,i,r,o,n=1/0,a=0,l=1/0){super(e,t,i),this.rA=S(r[0],r[1],r[2]),this.rB=S(o[0],o[1],o[2]),this.stiffnessLin=n,this.stiffnessAng=a,this.fracture=l;let c=t?t.size:[0,0,0];this.torqueArm=Ne([c[0]+i.size[0],c[1]+i.size[1],c[2]+i.size[2]])}evaluateLin(e){let{bodyA:t,bodyB:i}=this;return t?Gt(li,t.positionLin,t.positionAng,this.rA):li.set(this.rA),J(e,li,Gt(cr,i.positionLin,i.positionAng,this.rB))}evaluateAng(e){return ct(e,this.bodyA?this.bodyA.positionAng:Uu,this.bodyB.positionAng),ne(e,e,this.torqueArm)}initialize(){let{solver:e}=this;this.evaluateLin(this.C0Lin),this.evaluateAng(this.C0Ang);for(let t=0;t<3;t++)this.lambdaLin[t]=this.lambdaLin[t]*e.alpha*e.gamma,this.lambdaAng[t]=this.lambdaAng[t]*e.alpha*e.gamma,this.penaltyLin[t]=ce(this.penaltyLin[t]*e.gamma,Et,Ve),this.penaltyAng[t]=ce(this.penaltyAng[t]*e.gamma,Et,Ve);return qs(this.penaltyLin,this.penaltyLin,this.stiffnessLin),qs(this.penaltyAng,this.penaltyAng,this.stiffnessAng),!this.broken}updatePrimal(e,t,i){let r=e===this.bodyA;if(Ne(this.penaltyLin)>0){Ce(zt,this.penaltyLin[0],this.penaltyLin[1],this.penaltyLin[2]),this.evaluateLin(ye),this.stiffnessLin===1/0&&D(ye,ye,this.C0Lin,-t),ue(ze,zt,ye),D(ze,ze,this.lambdaLin,1);let o=r?1:-1;Ce(Us,o,o,o),r?An(ji,ee(ve,ae(ve,this.bodyA.positionAng,this.rA))):An(ji,ae(ve,this.bodyB.positionAng,this.rB)),_i(Rn,Us),_i(lr,ji),Ke(On,lr,zt),qe(i.lhsLin,Ke(ut,Ke(ut,Rn,zt),Us)),qe(i.lhsAng,Ke(ut,On,ji)),qe(i.lhsCross,Ke(ut,On,Us)),r?ae(ve,this.bodyA.positionAng,this.rA):ee(ve,ae(ve,this.bodyB.positionAng,this.rB)),Ei(Ns,Tn(Vr,0,ve),ze[0]),qe(Ns,Ei(Vr,Tn(Vr,1,ve),ze[1])),qe(Ns,Ei(Vr,Tn(Vr,2,ve),ze[2])),qe(i.lhsAng,Qa(ut,Ns)),D(i.rhsLin,i.rhsLin,ue(ve,Rn,ze),1),D(i.rhsAng,i.rhsAng,ue(ve,lr,ze),1)}if(Ne(this.penaltyAng)>0){Ce(zt,this.penaltyAng[0],this.penaltyAng[1],this.penaltyAng[2]),this.evaluateAng(ye),this.stiffnessAng===1/0&&D(ye,ye,this.C0Ang,-t),ue(ze,zt,ye),D(ze,ze,this.lambdaAng,1);let o=(r?1:-1)*this.torqueArm;Ce(ji,o,o,o),_i(lr,ji),qe(i.lhsAng,Ke(ut,Ke(ut,lr,zt),ji)),D(i.rhsAng,i.rhsAng,ue(ve,lr,ze),1)}}updateDual(e){let{solver:t}=this;Ne(this.penaltyLin)>0&&(Ce(zt,this.penaltyLin[0],this.penaltyLin[1],this.penaltyLin[2]),this.evaluateLin(ye),this.stiffnessLin===1/0&&(D(ye,ye,this.C0Lin,-e),ue(ze,zt,ye),D(this.lambdaLin,ze,this.lambdaLin,1)),D(this.penaltyLin,this.penaltyLin,vn(ve,ye),t.betaLin),qs(this.penaltyLin,this.penaltyLin,Bt(this.stiffnessLin,Ve))),Ne(this.penaltyAng)>0&&(Ce(zt,this.penaltyAng[0],this.penaltyAng[1],this.penaltyAng[2]),this.evaluateAng(ye),this.stiffnessAng===1/0&&(D(ye,ye,this.C0Ang,-e),ue(ze,zt,ye),D(this.lambdaAng,ze,this.lambdaAng,1)),D(this.penaltyAng,this.penaltyAng,vn(ve,ye),t.betaAng),qs(this.penaltyAng,this.penaltyAng,Bt(this.stiffnessAng,Ve))),Ne(this.lambdaAng)>this.fracture*this.fracture&&(this.penaltyLin.fill(0),this.penaltyAng.fill(0),this.lambdaLin.fill(0),this.lambdaAng.fill(0),this.broken=!0)}},ft=class extends Ft{rA;rB;rest;stiffness;constructor(e,t,i,r,o,n,a=-1){super(e,t,i),this.rA=S(r[0],r[1],r[2]),this.rB=S(o[0],o[1],o[2]),this.stiffness=n,this.rest=a,this.rest<0&&(Gt(li,t.positionLin,t.positionAng,this.rA),Gt(cr,i.positionLin,i.positionAng,this.rB),this.rest=rr(J(ye,li,cr)))}initialize(){return!0}updatePrimal(e,t,i){let r=this.bodyA,o=this.bodyB;Gt(li,r.positionLin,r.positionAng,this.rA),Gt(cr,o.positionLin,o.positionAng,this.rB);let n=J(ye,li,cr),a=rr(n);if(a<=1e-6)return;let l=_t(ze,n,a),c=a-this.rest,u=this.stiffness*c,f=li,d=cr;e===r?(ae(ve,r.positionAng,this.rA),f.set(l),Dt(d,ve,l)):(ae(ve,o.positionAng,this.rB),ee(f,l),ee(d,Dt(d,ve,l))),qe(i.lhsLin,Ei(ut,Ls(ut,f,f),this.stiffness)),qe(i.lhsAng,Ei(ut,Ls(ut,d,d),this.stiffness)),qe(i.lhsCross,Ei(ut,Ls(ut,d,f),this.stiffness)),D(i.rhsLin,i.rhsLin,ne(ve,f,u),1),D(i.rhsAng,i.rhsAng,ne(ve,d,u),1)}updateDual(){}},Vs=class extends Ft{initialize(){return!0}updatePrimal(){}updateDual(){}};var We=40,ur=0,Wr=4,wl=8,Bl=12,jn=16,Dn=20,Cl=24,Sl=28,Gn=32,Fn=36,pe=32,ci=0,Hr=4,fr=8,dr=12,kl=16,Pl=20,ui=24,hr=28,Nt=8;var Ws=4,Ht=16,pr=0,Hs=4,$s=8,Js=12,$r=2147483648,mr=6,Nu=7,Ll=0,Un=1,Nn=2,Xs=3,Jr=1,gr=2,Xr=1,Yr=2,Qr=4,Kr=8,Zr=16,qu=.1,_l=.002,El=.002,Vu=.05,es=44,ge=`
536
536
  // Shared by every 3D module (avbd3d/gpu/layout.ts)
537
- ${ln}
538
- const T_JOINT = ${qr};
539
- const T_SPRING = ${pr};
537
+ ${In}
538
+ const T_JOINT = ${Jr};
539
+ const T_SPRING = ${gr};
540
540
 
541
541
  const PENALTY_MIN = 1.0;
542
542
  const PENALTY_MAX = 1e10;
@@ -545,22 +545,22 @@ const PIVOT_FLOOR = 1e-5;
545
545
  const COLLISION_MARGIN = 0.01;
546
546
  const STICK_THRESH = 0.00001;
547
547
 
548
- const SHAPE_SPHERE = ${bn}.0;
549
- const SHAPE_SAIL = ${yn}.0;
550
- const SHAPE_HULL = ${Is}.0;
551
- const STICK_BIT = ${Ur}u;
552
- const C_MANIFOLDS = ${hr}u;
553
- const C_PREV_MANIFOLDS = ${$c}u;
548
+ const SHAPE_SPHERE = ${Un}.0;
549
+ const SHAPE_SAIL = ${Nn}.0;
550
+ const SHAPE_HULL = ${Xs}.0;
551
+ const STICK_BIT = ${$r}u;
552
+ const C_MANIFOLDS = ${mr}u;
553
+ const C_PREV_MANIFOLDS = ${Nu}u;
554
554
  /** Feature key of every contact involving a sphere (one contact per pair). */
555
555
  const SPHERE_FEATURE = 3u << 24u;
556
556
 
557
- const FLAG_MATCH_NEAREST = ${vn}u;
558
- const FLAG_FACE_BIAS = ${An}u;
559
- const FLAG_REUSE_CONTACTS = ${xn}u;
560
- const FLAG_START_AT_REST = ${wn}u;
561
- const FLAG_MASS_PENALTY = ${Bn}u;
562
- const REST_SPEED = ${Xc};
563
- const NEAREST_FRACTION = ${Yc};
557
+ const FLAG_MATCH_NEAREST = ${Xr}u;
558
+ const FLAG_FACE_BIAS = ${Yr}u;
559
+ const FLAG_REUSE_CONTACTS = ${Qr}u;
560
+ const FLAG_START_AT_REST = ${Kr}u;
561
+ const FLAG_MASS_PENALTY = ${Zr}u;
562
+ const REST_SPEED = ${qu};
563
+ const NEAREST_FRACTION = ${Vu};
564
564
 
565
565
  struct Body {
566
566
  pos: vec4f, // xyz, w: friction
@@ -678,7 +678,7 @@ fn orthonormal(n: vec3f) -> mat3x3f {
678
678
  // Columns of the WGSL matrix are the basis rows
679
679
  return mat3x3f(n, t1, cross(n, t1));
680
680
  }
681
- `,mr=`
681
+ `,br=`
682
682
  alias TopoItem = Manifold;
683
683
 
684
684
  /** A body pair has one manifold, so the other body alone orders a body's contacts. */
@@ -699,7 +699,7 @@ fn jointActive(j: u32) -> bool {
699
699
  let k = joints[j];
700
700
  return info[j].x != T_NONE && (k.penLin.w != 0.0 || k.penAng.w != 0.0);
701
701
  }
702
- `,Sn=`
702
+ `,qn=`
703
703
  fn lanesFor(bodies: u32) -> u32 {
704
704
  let rule = params.primalLanes;
705
705
  if (bodies >= (1u << (rule & 255u))) { return 1u; }
@@ -711,7 +711,7 @@ fn lanesFor(bodies: u32) -> u32 {
711
711
  fn colorThreads(bodies: u32) -> u32 {
712
712
  return bodies * lanesFor(bodies);
713
713
  }
714
- `,Qa={counter:"C_MANIFOLDS",prevCounter:"C_PREV_MANIFOLDS",capacity:"params.manifoldCapacity",colorThreads:Sn};var Ka=`
714
+ `,Ys={counter:"C_MANIFOLDS",prevCounter:"C_PREV_MANIFOLDS",capacity:"params.manifoldCapacity",colorThreads:qn};var Ml=`
715
715
  const MAX_CLIP = 64u;
716
716
  const NO_HULL = 0xffffffffu;
717
717
 
@@ -1095,8 +1095,8 @@ fn sphereHull(c: vec3f, r: f32, X: Poly) -> SphereBoxHit {
1095
1095
  out.onSphere = c - n * r;
1096
1096
  return out;
1097
1097
  }
1098
- `;var Rs=`
1099
- ${Ae}
1098
+ `;var Qs=`
1099
+ ${ge}
1100
1100
 
1101
1101
  struct RefPose {
1102
1102
  pos: vec4f,
@@ -1116,15 +1116,15 @@ fn updateRefs(@builtin(global_invocation_id) gid: vec3u) {
1116
1116
  let last = refs[i];
1117
1117
  // A zero quaternion marks a body without a reference yet
1118
1118
  let moved = dot(last.rot, last.rot) == 0.0
1119
- || length(pos - last.pos.xyz) > ${Xa}
1120
- || length(qsub(rot, last.rot)) > ${Ya};
1119
+ || length(pos - last.pos.xyz) > ${_l}
1120
+ || length(qsub(rot, last.rot)) > ${El};
1121
1121
  if (moved) {
1122
1122
  refs[i] = RefPose(vec4f(pos, 0.0), rot);
1123
1123
  bodies[i].inertialPos.w = bitcast<f32>(params.step);
1124
1124
  }
1125
1125
  }
1126
- `,ui=`
1127
- ${Ae}
1126
+ `,fi=`
1127
+ ${ge}
1128
1128
 
1129
1129
  @group(0) @binding(0) var<uniform> params: Params;
1130
1130
  @group(0) @binding(1) var<storage, read> bodies: array<Body>;
@@ -1331,8 +1331,8 @@ fn findPairs(@builtin(global_invocation_id) gid: vec3u) {
1331
1331
  testPair(P, l);
1332
1332
  }
1333
1333
  }
1334
- `,Ti=s=>`
1335
- ${Ae}
1334
+ `,yr=s=>`
1335
+ ${ge}
1336
1336
 
1337
1337
  @group(0) @binding(0) var<uniform> params: Params;
1338
1338
  @group(0) @binding(1) var<storage, read> bodies: array<Body>;
@@ -1747,7 +1747,7 @@ fn reuseContacts(a: u32, b: u32) -> bool {
1747
1747
  return true;
1748
1748
  }
1749
1749
 
1750
- ${s?Ka:"fn isHull(i: u32) -> bool { return false; }"}
1750
+ ${s?Ml:"fn isHull(i: u32) -> bool { return false; }"}
1751
1751
 
1752
1752
  @compute @workgroup_size(64)
1753
1753
  fn narrowphase(@builtin(global_invocation_id) gid: vec3u) {
@@ -1876,9 +1876,9 @@ fn narrowphase(@builtin(global_invocation_id) gid: vec3u) {
1876
1876
  contacts[base + i] = Contact(rA, found.feature[i] | stick, rB, c0.x, pen, c0.y, lam, c0.z);
1877
1877
  }
1878
1878
  }
1879
- `,Za=Ti(!1),el=Ti(!0);var ze=`
1880
- ${Ae}
1881
- ${Sn}
1879
+ `,zl=yr(!1),Il=yr(!0);var Ge=`
1880
+ ${ge}
1881
+ ${qn}
1882
1882
 
1883
1883
  // Per-dispatch constants, selected with a dynamic uniform offset
1884
1884
  struct PassConstants {
@@ -2418,11 +2418,11 @@ fn updateVelocities(@builtin(global_invocation_id) gid: vec3u) {
2418
2418
  bodies[i].vel.w = prevUp;
2419
2419
  }
2420
2420
  }
2421
- `;function Os(s,e){let t=0,i=s.length-1;for(;t<i;){let r=s[e],o=t,n=i;do{for(;s[o]<r;)o++;for(;r<s[n];)n--;if(o<=n){let a=s[o];s[o]=s[n],s[n]=a,o++,n--}}while(o<=n);n<e&&(t=o),e<o&&(i=n)}return s[e]}function kn(s){let e=s.length,t=e>0?Os(s,e>>1):1,i=0;for(let r=0;r<e;r++)s[r]<=2*t&&(i=Math.max(i,s[r]));return e>64&&(i=Math.max(i,Os(s,e-64-1))),i}var Jt=s=>s===1/0?3e38:s===-1/0?-3e38:s,ft=s=>Math.ceil(s/64),il=s=>2**Math.ceil(Math.log2(Math.max(s,2))),Qc=s=>Math.max(s,1)*qe*4,Kc=8,Ts=3,Zc=8,eu=1.6,tu=.8,iu=2,ru=[0,0,1],su=()=>({...an(),matchNearest:!0,faceBias:!0,reuseContacts:!0,startAtRest:!0,massPenalty:!0,windSpeed:0,windAngle:0,windGust:.4,windPressure:.72,up:[0,1,0]});function ou(s,e){let t=s.vertices.length/3,i=s.faces.length,r=s.faces.reduce((g,h)=>g+h.verts.length,0),o=Math.ceil(r/4),n=s.edges.length,a=new Float32Array((2+t+2*i+o+n)*4),l=new Uint32Array(a.buffer),c=e+2,u=c+t,f=u+2*i,d=f+o;l.set([c,t,u,i,d,n,f,0],0);for(let g=0;g<t;g++)a.set(s.vertices.subarray(g*3,g*3+3),(2+g)*4);let p=0;return s.faces.forEach((g,h)=>{let m=(2+t+2*h)*4;a.set(g.normal,m),a[m+3]=g.d,l[m+4]=p,l[m+5]=g.verts.length;for(let b of g.verts)l[(2+t+2*i)*4+p++]=b}),s.edges.forEach((g,h)=>l.set(g,(2+t+2*i+o+h)*4)),a}var Pn=.001;function nu(s,e){let t=s.length,i=s.map(m=>[0,1,2].map(b=>{let v=[0,0,0];return v[b]=1,ae(C(),m.positionAng,v)})),r=s.map((m,b)=>{if(De(m))return[m.radius,m.radius,m.radius];let v=[0,0,0];for(let w=0;w<3;w++)for(let y=0;y<3;y++)v[y]+=m.size[w]*.5*Math.abs(i[b][w][y]);return v}),o=kn(Float64Array.from(s,m=>m.radius)),n=Math.max(2*o,.001),a=(m,b)=>{let v=s[m],w=s[b];if(v.mass<=0&&w.mass<=0)return!1;let y=[0,1,2].map(x=>v.positionLin[x]-w.positionLin[x]),A=v.radius+w.radius;return y[0]*y[0]+y[1]*y[1]+y[2]*y[2]>A*A?!1:y.every((x,B)=>Math.abs(x)<=r[m][B]+r[b][B])},l=(m,b)=>m[0]*b[0]+m[1]*b[1]+m[2]*b[2],c=(m,b)=>{let v=s[m],w=s[b],y=[0,1,2].map(L=>w.positionLin[L]-v.positionLin[L]),[A,x]=[De(v),De(w)];if(A&&x)return Math.hypot(y[0],y[1],y[2])<=v.radius+w.radius+Pn;if(A||x){let[L,M,z]=A?[b,v.radius,-1]:[m,w.radius,1],_=0;for(let k=0;k<3;k++){let S=Math.abs(z*l(y,i[L][k]))-s[L].size[k]*.5;S>0&&(_+=S*S)}return _<=(M+Pn)**2}let B=(L,M)=>s[L].size[0]*.5*Math.abs(l(i[L][0],M))+s[L].size[1]*.5*Math.abs(l(i[L][1],M))+s[L].size[2]*.5*Math.abs(l(i[L][2],M)),E=L=>{let M=Math.hypot(L[0],L[1],L[2]);return M<1e-6?!1:Math.abs(l(y,L))-B(m,L)-B(b,L)>Pn*M};for(let L=0;L<3;L++)if(E(i[m][L])||E(i[b][L]))return!1;for(let L of i[m])for(let M of i[b])if(E([L[1]*M[2]-L[2]*M[1],L[2]*M[0]-L[0]*M[2],L[0]*M[1]-L[1]*M[0]]))return!1;return!0},u=new Set,f=new Map,d=(m,b,v)=>(m*73856093^b*19349663^v*83492791)>>>0,p=m=>[0,1,2].map(b=>Math.floor(s[m].positionLin[b]/n));for(let m=0;m<t;m++){if(s[m].radius>o){u.add(m);continue}let[b,v,w]=p(m),y=d(b,v,w),A=f.get(y);A?A.push(m):f.set(y,[m])}let g=0,h=0;for(let m=0;m<t;m++){if(u.has(m))continue;let[b,v,w]=p(m);for(let y=-1;y<=1;y++)for(let A=-1;A<=1;A++)for(let x=-1;x<=1;x++)for(let B of f.get(d(b+x,v+A,w+y))??[])B<m&&a(m,B)&&(g++,c(m,B)&&(h++,e[m]++,e[B]++))}for(let m of u)for(let b=0;b<t;b++)b!==m&&(!u.has(b)||b<m)&&a(m,b)&&(g++,c(m,b)&&(h++,e[m]++,e[b]++));return{pairs:g,touching:h}}function au(s){let e=[1/0,1/0,1/0],t=[-1/0,-1/0,-1/0];for(let o of s)for(let n=0;n<3;n++)e[n]=Math.min(e[n],o.positionLin[n]),t[n]=Math.max(t[n],o.positionLin[n]);let i=o=>{let n=o&1023;return n=(n|n<<16)&50331903,n=(n|n<<8)&50393103,n=(n|n<<4)&51130563,n=(n|n<<2)&153391689,n},r=s.map(o=>{let n=[0,1,2].map(a=>Math.min(1023,Math.floor((o.positionLin[a]-e[a])/Math.max(t[a]-e[a],1e-9)*1024)));return(i(n[0])|i(n[1])<<1|i(n[2])<<2)>>>0});return s.map((o,n)=>n).sort((o,n)=>r[o]-r[n]||o-n)}var Pe=()=>GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST,js=class{device;params=su();bodyCount=0;bodyCapacity;bodies=[];hulls;hullBuffer;get hullStorage(){return this.hullBuffer}hullCapacity=4096;hullTop=0;hullSlots=new Map;contactShaders;hullShaders=!1;hullFree=[];refToGpu;jointCount=0;jointCapacity=0;info=new Int32Array(0);pairCapacity=0;manifoldCapacity=0;contactCapacity=0;colorCap=12;fixedColors=null;primalLanes=[2**31,2**15,2**12];splitPasses=!1;shrinkVotes=0;colorRounds;get colorHistOffset(){return 3*this.bodyCapacity+65}bodyBuffer;ownsBodyBuffer;jointBuffer;infoBuffer;contactBuffers;manifoldBuffers;pairBuffer;tableBuffer;gridBuffer;staticBuffer=null;filterBuffer;get filterStorage(){return this.filterBuffer}counterBuffer;get contactStorage(){let e=1-this.parity;return{manifolds:this.manifoldBuffers[e],contacts:this.contactBuffers[e],counters:this.counterBuffer}}argsBuffer;adjBuffer=null;colorBuffer;paramsBuffer;refBuffer;stepCount=0;passBuffer=null;passEntries=0;parity=0;tableSize;hashSize=0;cellSize=1;maxSmallRadius=0;largeCount=0;noCollideCount=0;radiiDirty=!0;noCollideDirty=!0;large=[];entries=[];pendingEntries=[];releasedSlots=new Set;freeSlots=[];layouts;pipes={};groups;passGroup=null;gridScan;colorHistScan;colorGroups;adjScan=null;timing;timingCallback=null;timingBusy=!1;destroyed=!1;constructor(e,t,i={}){this.device=e;let{dt:r,gravity:o,iterations:n,alpha:a,betaLin:l,betaAng:c,gamma:u}=t;if(Object.assign(this.params,{dt:r,gravity:o,iterations:n,alpha:a,betaLin:l,betaAng:c,gamma:u,up:ru}),this.bodyCount=t.bodies.length,this.colorRounds=i.colorRounds??16,this.ownsBodyBuffer=!i.bodyBuffer,this.bodyCapacity=i.bodyBuffer?Math.floor(i.bodyBuffer.size/(qe*4)):Math.max(i.bodyCapacity??this.bodyCount+1024,this.bodyCount,1),this.bodyCapacity<this.bodyCount)throw new Error("body buffer too small");this.bodyBuffer=i.bodyBuffer??e.createBuffer({label:"bodies 3d",size:Qc(this.bodyCapacity),usage:Pe()}),this.filterBuffer=e.createBuffer({label:"collision filters",size:Math.max(this.bodyCapacity,1)*8,usage:Pe()}),e.queue.writeBuffer(this.filterBuffer,0,new Uint32Array(Math.max(this.bodyCapacity,1)*2).fill(4294967295));let f=this.bodyCapacity;this.tableSize=il(2*f),this.gridBuffer=e.createBuffer({label:"grid 3d",size:(2*this.tableSize+1+4*f)*4,usage:Pe()}),this.counterBuffer=e.createBuffer({label:"counters",size:64,usage:Pe()}),this.argsBuffer=e.createBuffer({label:"indirect args",size:816,usage:Pe()|GPUBufferUsage.INDIRECT}),this.colorGroups=Math.ceil(f/256),this.colorBuffer=e.createBuffer({label:"colours",size:(3*f+65+64*this.colorGroups+1)*4,usage:Pe()}),this.paramsBuffer=e.createBuffer({label:"params 3d",size:Cn*4,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.refBuffer=e.createBuffer({label:"reference poses",size:f*32,usage:Pe()}),this.hulls=(i.hulls??!0)&&e.limits.maxStorageBuffersPerShaderStage>=9,this.hullBuffer=e.createBuffer({label:"hulls",size:this.hullCapacity*16,usage:Pe()}),e.queue.writeBuffer(this.colorBuffer,0,new Uint32Array(f).fill(255));let d=2*Se.length;this.timing=e.features.has("timestamp-query")?{querySet:e.createQuerySet({type:"timestamp",count:d}),resolve:e.createBuffer({size:d*8,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),read:e.createBuffer({size:d*8,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST})}:null,this.layouts=this.createLayouts(),this.createPipelines(i.shaders??{}),this.gridScan=new tt(e,this.gridBuffer,0,this.tableSize+1),this.colorHistScan=new tt(e,this.colorBuffer,this.colorHistOffset,64*this.colorGroups+1);let p=i.spatialSort===!1?t.bodies.map((x,B)=>B):au(t.bodies);this.refToGpu=new Int32Array(p.length),p.forEach((x,B)=>this.refToGpu[x]=B);let g=new Map(t.bodies.map((x,B)=>[x,this.refToGpu[B]])),h=t.forces.filter(x=>x instanceof ke||x instanceof ut);for(let x of t.forces){if(!(x instanceof Ls))continue;let B=g.get(x.bodyA),E=g.get(x.bodyB);this.pendingEntries.push([Math.max(B,E),Math.min(B,E),4294967295])}this.allocateJoints(Math.max(h.length+256,i.capacity?.joints??0));for(let x of h)this.writeJoint(this.jointCount++,x,g);let m=new Int32Array(t.bodies.length),{pairs:b,touching:v}=nu(t.bodies,m),w=new Map(t.bodies.map((x,B)=>[x,B]));for(let x of h)x.bodyA&&m[w.get(x.bodyA)]++,m[w.get(x.bodyB)]++;let y=0;t.bodies.forEach((x,B)=>{x.mass>0&&(y=Math.max(y,m[B]))}),this.colorCap=Math.min(64,Math.max(Zc,y+1+Ts,i.capacity?.colors??0));let A=i.capacity??{};this.allocateContacts(Math.max(8192,4*f,Kc*v,A.contacts??0),Math.max(4096,4*f,2*b,A.pairs??0),Math.max(4096,f,eu*v,A.manifolds??0)),this.writeBodies(0,p.map(x=>t.bodies[x]))}gpuIndex(e){return e<this.refToGpu.length?this.refToGpu[e]:e}createLayouts(){let e=this.device,t=(n,a)=>e.createBindGroupLayout({label:n,entries:a.map((l,c)=>({binding:c,visibility:GPUShaderStage.COMPUTE,buffer:{type:l}}))}),i="read-only-storage",r="storage",o="uniform";return{broad:t("broadphase 3d",[o,i,r,r,r,i,i,i]),contacts:t("contacts 3d",[o,i,i,r,i,r,i,r,r,...this.hulls?[i]:[]]),topo:t("topology 3d",[o,i,i,i,i,r,r,r]),solve:t("solve 3d",[o,r,r,i,r,i,i,i,i]),pass:e.createBindGroupLayout({label:"pass",entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform",hasDynamicOffset:!0,minBindingSize:16}}]}),args:t("args 3d",[o,i,i,r]),refs:t("refs 3d",[o,r,r])}}createPipelines(e){let t=this.device,i=(o,n,a)=>{let l=t.createShaderModule({code:o}),c=t.createPipelineLayout({bindGroupLayouts:n});for(let u of a)this.pipes[u]=t.createComputePipeline({label:u,layout:c,compute:{module:l,entryPoint:u}})},r=this.layouts;i(ui,[r.broad],["beginFrame","gridCount","gridScatter","findPairs"]),i(Rs,[r.refs],["updateRefs"]),i(e.contacts??Za,[r.contacts],["hashInsert","narrowphase"]),this.contactShaders={make:o=>i(o,[r.contacts],["hashInsert","narrowphase"]),custom:!!e.contacts},i(Ri(Ae,mr),[r.topo],["degreeJoints","degreeContacts","fillJoints","fillContacts","sortAdjacency","colorCompact","colorMark","colorRoundAB","colorRoundBA","colorCount","colorStarts","colorScatter"]),i(e.solve??ze,[r.solve,r.pass],["warmStartJoints","warmStartBodies","primal","dual","updateVelocities"]),i(cn(Ae,Qa),[r.args],["argsPrev","argsPairs","argsContacts","argsColors"])}allocateJoints(e){let t=this.device,i=t.createBuffer({label:"joints 3d",size:Math.max(e,1)*pe*4,usage:Pe()}),r=t.createBuffer({label:"joint info",size:Math.max(e,1)*16,usage:Pe()});if(this.jointBuffer){let n=t.createCommandEncoder();n.copyBufferToBuffer(this.jointBuffer,0,i,0,this.jointCapacity*pe*4),n.copyBufferToBuffer(this.infoBuffer,0,r,0,this.jointCapacity*16),t.queue.submit([n.finish()]),this.jointBuffer.destroy(),this.infoBuffer.destroy()}let o=new Int32Array(e*4);o.set(this.info.subarray(0,Math.min(this.info.length,o.length))),this.info=o,this.jointBuffer=i,this.infoBuffer=r,this.jointCapacity=e,this.contactBuffers&&this.rebuildBindings()}allocateContacts(e,t,i){let r=this.device,o=r.limits.maxStorageBufferBindingSize,n=Math.min(Math.ceil(e),Math.floor(o/(Ht*4))),a=Math.min(Math.ceil(t),Math.floor(o/8)),l=Math.min(Math.ceil(i),a,Math.floor(o/(Ut*4))),c={contacts:this.contactBuffers,manifolds:this.manifoldBuffers,contactCapacity:this.contactCapacity,manifoldCapacity:this.manifoldCapacity};for(let u of[this.pairBuffer,this.tableBuffer])u?.destroy();if(this.contactCapacity=n,this.pairCapacity=a,this.manifoldCapacity=l,this.hashSize=il(2*l),this.pairBuffer=r.createBuffer({label:"pairs",size:a*8,usage:Pe()}),this.tableBuffer=r.createBuffer({label:"manifold hash",size:this.hashSize*4,usage:Pe()}),this.contactBuffers=[0,1].map(u=>r.createBuffer({label:`contacts 3d ${u}`,size:n*Ht*4,usage:Pe()})),this.manifoldBuffers=[0,1].map(u=>r.createBuffer({label:`manifolds 3d ${u}`,size:l*Ut*4,usage:Pe()})),c.contacts){let u=r.createCommandEncoder(),f=Math.min(c.contactCapacity,n)*Ht*4,d=Math.min(c.manifoldCapacity,l)*Ut*4;c.contacts.forEach((p,g)=>u.copyBufferToBuffer(p,0,this.contactBuffers[g],0,f)),c.manifolds.forEach((p,g)=>u.copyBufferToBuffer(p,0,this.manifoldBuffers[g],0,d)),r.queue.submit([u.finish()]),[...c.contacts,...c.manifolds].forEach(p=>p.destroy())}this.rebuildBindings()}rebuildBindings(){let e=this.device,t=this.bodyCapacity;this.adjBuffer?.destroy(),this.adjBuffer=e.createBuffer({label:"adjacency",size:(2*t+1+2*(this.jointCapacity+this.manifoldCapacity))*4,usage:Pe()}),this.adjScan?.destroy(),this.adjScan=new tt(e,this.adjBuffer,0,this.bodyCount+1),this.staticBuffer??=e.createBuffer({label:"statics",size:16,usage:Pe()});let i=(d,p)=>e.createBindGroup({layout:d,entries:p.map((g,h)=>({binding:h,resource:{buffer:g}}))}),r=this.paramsBuffer,[o,n]=this.contactBuffers,[a,l]=this.manifoldBuffers,c=this.adjBuffer,u=this.tableBuffer,f=this.counterBuffer;this.groups={broad:i(this.layouts.broad,[r,this.bodyBuffer,this.gridBuffer,this.pairBuffer,f,this.staticBuffer,this.jointBuffer,this.filterBuffer]),contacts:[i(this.layouts.contacts,[r,this.bodyBuffer,this.pairBuffer,o,n,a,l,u,f,...this.hulls?[this.hullBuffer]:[]]),i(this.layouts.contacts,[r,this.bodyBuffer,this.pairBuffer,n,o,l,a,u,f,...this.hulls?[this.hullBuffer]:[]])],topo:[a,l].map(d=>i(this.layouts.topo,[r,this.bodyBuffer,this.jointBuffer,this.infoBuffer,d,f,c,this.colorBuffer])),solve:[0,1].map(d=>i(this.layouts.solve,[r,this.bodyBuffer,this.jointBuffer,this.infoBuffer,[o,n][d],c,this.colorBuffer,f,[a,l][d]])),args:i(this.layouts.args,[r,this.counterBuffer,this.colorBuffer,this.argsBuffer]),refs:i(this.layouts.refs,[r,this.bodyBuffer,this.refBuffer])}}writeBodies(e,t){let i=new Float32Array(Math.max(t.length,1)*qe);t.forEach((r,o)=>{let n=this.pack(r,i,o*qe,this.bodies[e+o]?.hull);this.bodies[e+o]?.radius!==n.radius&&(this.radiiDirty=!0),this.bodies[e+o]=n}),this.device.queue.writeBuffer(this.bodyBuffer,e*qe*4,i,0,t.length*qe)}rewriteFixed(e,t,i,r,o){if(!e.length)return;let n=new Float32Array(qe),a={positionLin:[0,0,0],positionAng:[0,0,0,1],initialLin:[0,0,0],initialAng:[0,0,0,1],inertialLin:[0,0,0],inertialAng:[0,0,0,1],velocityLin:[0,0,0],prevVelocityLin:[0,0,0],velocityAng:[0,0,0],size:[i[0],i[1],i[2]],mass:0,moment:[0,0,0],friction:r,radius:Math.hypot(i[0]/2,i[1]/2,i[2]/2)},l=this.pack(a,n,0);for(let c=0;c<e.length;){let u=c+1;for(;u<e.length&&e[u]===e[u-1]+1;)u++;let f=new Float32Array((u-c)*qe);for(let d=c;d<u;d++){let p=(d-c)*qe;f.set(n,p);for(let h=0;h<3;h++)f[p+lr+h]=t[3*d+h];if(o)for(let h=0;h<4;h++)f[p+Gr+h]=o[4*d+h];let g=this.bodies[e[d]];g?.radius!==l.radius&&(this.radiiDirty=!0),g?.hull&&this.releaseHull(g.hull),this.bodies[e[d]]={...l,size:[...l.size]}}this.device.queue.writeBuffer(this.bodyBuffer,e[c]*qe*4,f),this.device.queue.writeBuffer(this.colorBuffer,e[c]*4,new Uint32Array(u-c).fill(255)),c=u}}pack(e,t,i,r){{t.set(e.positionLin,i+lr),t[i+lr+3]=e.friction,t.set(e.positionAng,i+Gr),t.set(e.size,i+hn),t[i+hn+3]=e.mass,t.set(e.moment,i+pn),t[i+pn+3]=e.radius,t.set(e.initialLin,i+Ua),t.set(e.initialAng,i+qa),t.set(e.inertialLin,i+Va),t.set(e.inertialAng,i+Wa),t.set(e.velocityLin,i+mn);let o=this.params.up;t[i+mn+3]=e.prevVelocityLin[0]*o[0]+e.prevVelocityLin[1]*o[1]+e.prevVelocityLin[2]*o[2],t.set(e.velocityAng,i+gn);let n=De(e),a=this.hulls?wt(e):void 0;r&&r!==a&&this.releaseHull(r);let l=a?r===a?this.hullSlots.get(a).offset:this.acquireHull(a):-1;return t[i+gn+3]=n?bn:l>=0?Is+l:sr(e)?yn:$a,{radius:e.radius,dynamic:e.mass>0,sphere:n,size:[e.size[0],e.size[1],e.size[2]],hull:a}}}writeJoint(e,t,i){let r=new Float32Array(pe),o=t.bodyA?i.get(t.bodyA):-1,n=i.get(t.bodyB);t instanceof ke?(r.set(t.penaltyLin,li),r[li+3]=Jt(t.broken?0:t.stiffnessLin),r.set(t.penaltyAng,Nr),r[Nr+3]=Jt(t.broken?0:t.stiffnessAng),r.set(t.lambdaLin,cr),r[cr+3]=Jt(t.fracture),r.set(t.lambdaAng,ur),r[ur+3]=t.torqueArm,r.set(t.C0Lin,Ha),r.set(t.C0Ang,Ja),r.set(t.rA,ci),r.set(t.rB,fr)):(r[li+3]=t.stiffness,r.set(t.rA,ci),r[ci+3]=t.rest,r.set(t.rB,fr)),this.info.set([t instanceof ke?qr:pr,o,n,0],e*4),this.device.queue.writeBuffer(this.jointBuffer,e*pe*4,r),this.device.queue.writeBuffer(this.infoBuffer,e*16,this.info,e*4,4),this.noCollide(o,n,e)}noCollide(e,t,i){e<0||(this.pendingEntries.push([Math.max(e,t),Math.min(e,t),i]),this.noCollideDirty=!0)}uploadStatics(){if(this.radiiDirty){let r=this.bodyCount,o=new Float64Array(r);for(let c=0;c<r;c++)o[c]=this.bodies[c].radius;let n=kn(o),a=1/0;for(let c=0;c<r;c++)o[c]>n&&(a=Math.min(a,o[c]));let l=a===1/0?n*1.5:(n+a)/2;this.maxSmallRadius=l,this.cellSize=Math.max(2*n*(1+1e-4),.001),this.large=[];for(let c=0;c<r;c++)this.bodies[c].radius>l&&this.large.push(c);this.radiiDirty=!1}if(this.noCollideDirty){let r=(l,c)=>l[0]-c[0]||l[1]-c[1],o=this.releasedSlots.size?this.entries.filter(l=>!this.releasedSlots.has(l[2])):this.entries;this.releasedSlots.clear();let n=this.pendingEntries.sort(r);this.pendingEntries=[];let a=[];for(let l=0,c=0;l<o.length||c<n.length;)c>=n.length||l<o.length&&r(o[l],n[c])<=0?a.push(o[l++]):a.push(n[c++]);this.entries=a,this.noCollideDirty=!1}let{large:e,entries:t}=this;this.largeCount=e.length,this.noCollideCount=t.length;let i=new Uint32Array(Math.max(e.length+3*t.length,4));i.set(e,0),t.forEach((r,o)=>i.set(r,e.length+3*o)),this.staticBuffer.size<i.byteLength&&(this.staticBuffer.destroy(),this.staticBuffer=this.device.createBuffer({label:"statics",size:i.byteLength,usage:Pe()}),this.rebuildBindings()),this.device.queue.writeBuffer(this.staticBuffer,0,i)}seedFrom(e){if(this.refToGpu.some((g,h)=>g!==h))throw new Error("seedFrom needs spatialSort: false");let t=new Map(e.bodies.map((g,h)=>[g,h]));this.writeBodies(0,e.bodies);let i=0;for(let g of e.forces)(g instanceof ke||g instanceof ut)&&this.writeJoint(i++,g,t);if(i!==this.jointCount)throw new Error("seedFrom: joints differ from the reference");let r=e.forces.filter(g=>g instanceof oi),o=r.reduce((g,h)=>g+h.contacts.length,0);if(o>this.contactCapacity||r.length>this.manifoldCapacity)throw new Error("seedFrom: too many contacts");let n=new ArrayBuffer(Math.max(o,1)*Ht*4),a=new Uint32Array(n),l=new Float32Array(n),c=new ArrayBuffer(Math.max(r.length,1)*Ut*4),u=new Uint32Array(c),f=new Float32Array(c),d=0;r.forEach((g,h)=>{u.set([t.get(g.bodyA),t.get(g.bodyB),d,g.contacts.length],h*Ut),f.set([g.basis[0],g.basis[1],g.basis[2],g.friction],h*Ut+_s);for(let m of g.contacts){let b=d++*Ht;l.set(m.rA,b+dr),a[b+dr+3]=m.feature>>>0|(m.stick?Ur:0),l.set([...m.rB,m.C0[0]],b+Es),l.set([...m.penalty,m.C0[1]],b+Ms),l.set([...m.lambda,m.C0[2]],b+zs)}}),this.device.queue.writeBuffer(this.contactBuffers[1-this.parity],0,n),this.device.queue.writeBuffer(this.manifoldBuffers[1-this.parity],0,c);let p=new Uint32Array(16);p[1]=o,p[hr]=r.length,this.device.queue.writeBuffer(this.counterBuffer,0,p)}sequentialColors(){let e=new Uint32Array(this.bodyCount).fill(255),t=0;for(let i=this.bodyCount-1;i>=0;i--)this.bodies[i].dynamic&&(e[i]=t++);if(t>64)throw new Error(`sequentialColors: ${t} dynamic bodies, at most ${64}`);return e}acquireHull(e){!this.hullShaders&&!this.contactShaders.custom&&(this.contactShaders.make(el),this.hullShaders=!0);let t=this.hullSlots.get(e);if(t)return t.refs++,t.offset;let i=2+e.vertices.length/3+2*e.faces.length+Math.ceil(e.faces.reduce((n,a)=>n+a.verts.length,0)/4)+e.edges.length,r=-1,o=this.hullFree.findIndex(n=>n.size>=i);if(o>=0){let n=this.hullFree[o];r=n.offset,n.size===i?this.hullFree.splice(o,1):Object.assign(n,{offset:n.offset+i,size:n.size-i})}else r=this.hullTop,this.hullTop+=i,this.hullTop>this.hullCapacity&&this.growHulls(this.hullTop);if(r+Is>=2**24)throw new Error("hull buffer beyond 2^24 vec4s");return this.device.queue.writeBuffer(this.hullBuffer,r*16,ou(e,r)),this.hullSlots.set(e,{offset:r,size:i,refs:1}),r}releaseHull(e){let t=this.hullSlots.get(e);if(!t||--t.refs>0)return;this.hullSlots.delete(e),this.hullFree.push({offset:t.offset,size:t.size}),this.hullFree.sort((r,o)=>r.offset-o.offset);let i=[];for(let r of this.hullFree){let o=i[i.length-1];o&&o.offset+o.size===r.offset?o.size+=r.size:i.push({...r})}this.hullFree=i}growHulls(e){let t=this.hullCapacity;for(;t<e;)t*=2;let i=this.device.createBuffer({label:"hulls",size:t*16,usage:Pe()}),r=this.device.createCommandEncoder();r.copyBufferToBuffer(this.hullBuffer,0,i,0,this.hullCapacity*16),this.device.queue.submit([r.finish()]),this.hullBuffer.destroy(),this.hullBuffer=i,this.hullCapacity=t,this.contactBuffers&&this.rebuildBindings()}addBody(e){return this.addBodies([e])}addBodies(e){let t=Math.min(e.length,this.bodyCapacity-this.bodyCount);if(t<=0)return-1;let i=this.bodyCount;return this.bodyCount+=t,this.writeBodies(i,e.slice(0,t)),this.device.queue.writeBuffer(this.colorBuffer,i*4,new Uint32Array(t).fill(255)),this.adjScan.destroy(),this.adjScan=new tt(this.device,this.adjBuffer,0,this.bodyCount+1),i}appendJoint(e,t,i,r,o,n){let a=this.jointCount;a>=this.jointCapacity&&this.allocateJoints(this.jointCapacity*2),this.jointCount++;let l=new Float32Array(pe);l[li+3]=Jt(o),l[Nr+3]=Jt(n),l[cr+3]=3e38,l.set([i[0],i[1],i[2]],ci),l.set([r[0],r[1],r[2]],fr);let c=e>=0?this.bodies[e].size:[0,0,0],u=this.bodies[t].size;return l[ur+3]=(c[0]+u[0])**2+(c[1]+u[1])**2+(c[2]+u[2])**2,this.info.set([qr,e,t,0],a*4),this.device.queue.writeBuffer(this.jointBuffer,a*pe*4,l),this.device.queue.writeBuffer(this.infoBuffer,a*16,this.info,a*4,4),this.noCollide(e,t,a),a}appendJoints(e,t,i=!1){return this.appendConstraints(e.length,(r,o)=>{let{a:n,b:a,rA:l,rB:c,angular:u}=e[r];o[li+3]=3e38,o[Nr+3]=u===void 0?3e38:Jt(u),o[cr+3]=i?-Jt(t):Jt(t),o.set([l[0],l[1],l[2]],ci),o.set([c[0],c[1],c[2]],fr);let[f,d]=[this.bodies[n].size,this.bodies[a].size];return o[ur+3]=(f[0]+d[0])**2+(f[1]+d[1])**2+(f[2]+d[2])**2,[qr,n,a]})}appendSprings(e){return this.appendConstraints(e.length,(t,i)=>{let{a:r,b:o,rA:n,rB:a,stiffness:l,rest:c}=e[t];return i[li+3]=Jt(l),i.set([n[0],n[1],n[2],c],ci),i.set([a[0],a[1],a[2]],fr),[pr,r,o]})}appendConstraints(e,t){let i=[];if(this.freeSlots.length)for(this.freeSlots.sort((a,l)=>l-a);i.length<e&&this.freeSlots.length;)i.push(this.freeSlots.pop());let r=e-i.length,o=this.jointCapacity;for(;this.jointCount+r>o;)o*=2;o>this.jointCapacity&&this.allocateJoints(o);for(let a=0;a<r;a++)i.push(this.jointCount++);let n=new Float32Array(e*pe);for(let a=0;a<e;a++){let[l,c,u]=t(a,n.subarray(a*pe,(a+1)*pe));this.info.set([l,c,u,0],i[a]*4),this.releasedSlots.delete(i[a]),this.noCollide(c,u,i[a])}for(let a=0;a<e;){let l=a+1;for(;l<e&&i[l]===i[l-1]+1;)l++;this.device.queue.writeBuffer(this.jointBuffer,i[a]*pe*4,n,a*pe,(l-a)*pe),this.device.queue.writeBuffer(this.infoBuffer,i[a]*16,this.info,i[a]*4,(l-a)*4),a=l}return i}releaseJoints(e){let t=[...new Set(Array.from(e))].filter(r=>r<this.jointCount&&this.info[r*4]!==0).sort((r,o)=>r-o);if(!t.length)return;for(let r of t)this.info.set([0,-1,-1,0],r*4),this.releasedSlots.add(r),this.freeSlots.push(r);let i=new Float32Array(0);for(let r=0;r<t.length;){let o=r+1;for(;o<t.length&&t[o]===t[o-1]+1;)o++;i.length<(o-r)*pe&&(i=new Float32Array((o-r)*pe)),this.device.queue.writeBuffer(this.jointBuffer,t[r]*pe*4,i,0,(o-r)*pe),this.device.queue.writeBuffer(this.infoBuffer,t[r]*16,this.info,t[r]*4,(o-r)*4),r=o}this.noCollideDirty=!0}rewriteBodies(e,t){for(let i=0;i<e.length;){let r=i+1;for(;r<e.length&&e[r]===e[r-1]+1;)r++;this.writeBodies(e[i],t.slice(i,r)),this.device.queue.writeBuffer(this.colorBuffer,e[i]*4,new Uint32Array(r-i).fill(255)),i=r}}setFilters(e,t,i){for(let r=0;r<e.length;){let o=r+1;for(;o<e.length&&e[o]===e[o-1]+1;)o++;let n=new Uint32Array(2*(o-r));for(let a=r;a<o;a++)n.set([t[a]>>>0,i[a]>>>0],2*(a-r));this.device.queue.writeBuffer(this.filterBuffer,e[r]*8,n),r=o}}setWorldAnchor(e,t){this.device.queue.writeBuffer(this.jointBuffer,(e*pe+ci)*4,new Float32Array([t[0],t[1],t[2]]))}disableConstraint(e){this.device.queue.writeBuffer(this.jointBuffer,(e*pe+li)*4,new Float32Array(8)),this.device.queue.writeBuffer(this.jointBuffer,(e*pe+cr)*4,new Float32Array(3)),this.device.queue.writeBuffer(this.jointBuffer,(e*pe+ur)*4,new Float32Array(3))}profileNextStep(e){this.timing&&!this.timingBusy&&(this.timingCallback=e)}writeParams(){let e=this.params,t=this.bodyCapacity,i=new ArrayBuffer(Cn*4),r=new Float32Array(i),o=new Uint32Array(i);r[0]=e.dt,r[1]=e.gravity,r[2]=e.betaLin,r[3]=e.betaAng,r[4]=e.gamma,r[5]=e.alpha,o[6]=(e.matchNearest?vn:0)|(e.faceBias?An:0)|(e.reuseContacts?xn:0)|(e.startAtRest?wn:0)|(e.massPenalty?Bn:0),o[7]=this.bodyCount,o[8]=this.jointCount,o[9]=this.colorCap,r[10]=this.cellSize,o[11]=this.tableSize-1,r[12]=this.maxSmallRadius,o[13]=this.largeCount,o[14]=this.noCollideCount,o[15]=this.pairCapacity,o[16]=this.contactCapacity,o[17]=this.hashSize-1,o[18]=t+1,o[19]=2*t+1,o[20]=this.tableSize+1,o[21]=2*this.tableSize+1,o[22]=2*this.tableSize+1+t,o[23]=t,o[24]=this.colorHistOffset,o[25]=2*t,o[26]=this.colorGroups,o[27]=2*t+65,o[28]=this.colorRounds,o[29]=this.manifoldCapacity,o[30]=this.stepCount;let n=a=>Math.min(31,Math.max(0,Math.round(Math.log2(a))));o[31]=n(this.primalLanes[0])|n(this.primalLanes[1])<<8|n(this.primalLanes[2])<<16,r.set([e.windSpeed*Math.cos(e.windAngle),e.windSpeed*Math.sin(e.windAngle),0,e.windPressure,e.windGust],32),r.set([e.up[0],e.up[1],e.up[2],0],40),this.device.queue.writeBuffer(this.paramsBuffer,0,i)}writePassConstants(e,t){let i=this.colorCap+1,r=Math.max(e*i,1);(r>this.passEntries||!this.passGroup)&&(this.passBuffer?.destroy(),this.passBuffer=this.device.createBuffer({label:"pass constants",size:r*256,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.passEntries=r,this.passGroup=this.device.createBindGroup({layout:this.layouts.pass,entries:[{binding:0,resource:{buffer:this.passBuffer,size:16}}]}));let o=new ArrayBuffer(r*256),n=new Uint32Array(o),a=new Float32Array(o);for(let l=0;l<e;l++)for(let c=0;c<=this.colorCap;c++){let u=(l*i+c)*256/4;n[u]=c,a[u+1]=t}this.device.queue.writeBuffer(this.passBuffer,0,o)}step(){(this.radiiDirty||this.noCollideDirty)&&this.uploadStatics();let e=this.params;this.fixedColors&&(this.device.queue.writeBuffer(this.colorBuffer,0,this.fixedColors),this.colorCap=Math.max(1,...this.fixedColors.map(v=>v===255?0:v+1))),this.stepCount++,this.writeParams(),this.writePassConstants(e.iterations,e.alpha);let t=this.parity,i=this.bodyCapacity,r=this.bodyCount,o=this.jointCount,n=this.device.createCommandEncoder({label:"avbd3d step"});n.clearBuffer(this.gridBuffer,0,(2*this.tableSize+1)*4),n.clearBuffer(this.tableBuffer),n.clearBuffer(this.adjBuffer,0,(2*i+1)*4);let a=this.timingCallback!==null&&this.timing!==null,l,c=0,u=a||this.splitPasses,f=()=>{l&&!u||(l?.end(),l=n.beginComputePass({label:u?Se[c]:"avbd3d step",timestampWrites:a?{querySet:this.timing.querySet,beginningOfPassWriteIndex:2*c,endOfPassWriteIndex:2*c+1}:void 0}),c++)},d=this.groups,p=(v,w,y)=>{y<=0||(l.setPipeline(this.pipes[v]),l.setBindGroup(0,w),l.dispatchWorkgroups(y))},g=(v,w,y)=>{l.setPipeline(this.pipes[v]),l.setBindGroup(0,w),l.dispatchWorkgroupsIndirect(this.argsBuffer,y*4)};if(f(),p("beginFrame",d.broad,1),e.reuseContacts&&p("updateRefs",d.refs,ft(r)),p("argsPrev",d.args,1),g("hashInsert",d.contacts[t],6),p("gridCount",d.broad,ft(r)),this.gridScan.encode(l),p("gridScatter",d.broad,ft(r)),p("findPairs",d.broad,ft(r)),p("argsPairs",d.args,1),g("narrowphase",d.contacts[t],0),p("argsContacts",d.args,1),f(),p("degreeJoints",d.topo[t],ft(o)),g("degreeContacts",d.topo[t],3),this.adjScan.encode(l),p("fillJoints",d.topo[t],ft(o)),g("fillContacts",d.topo[t],3),p("sortAdjacency",d.topo[t],ft(r)),f(),!this.fixedColors){p("colorCompact",d.topo[t],ft(r)),p("colorMark",d.topo[t],ft(r));for(let v=0;v<this.colorRounds;v++)p(v%2===0?"colorRoundAB":"colorRoundBA",d.topo[t],ft(r))}p("colorCount",d.topo[t],this.colorGroups),this.colorHistScan.encode(l),p("colorStarts",d.topo[t],1),p("argsColors",d.args,1),p("colorScatter",d.topo[t],this.colorGroups),f();let h=this.colorCap+1,m=v=>l.setBindGroup(1,this.passGroup,[v*256]);l.setBindGroup(0,d.solve[t]),m(0),o>0&&(l.setPipeline(this.pipes.warmStartJoints),l.dispatchWorkgroups(ft(o))),l.setPipeline(this.pipes.warmStartBodies),l.dispatchWorkgroups(ft(r));for(let v=0;v<e.iterations;v++){l.setPipeline(this.pipes.primal);for(let w=0;w<this.colorCap;w++)m(v*h+w),l.dispatchWorkgroupsIndirect(this.argsBuffer,(12+3*w)*4);m(v*h+this.colorCap),l.setPipeline(this.pipes.dual),l.dispatchWorkgroupsIndirect(this.argsBuffer,36)}l.setPipeline(this.pipes.updateVelocities),l.dispatchWorkgroups(ft(r)),l.end();let b=2*Se.length;if(a){let{querySet:v,resolve:w,read:y}=this.timing;n.resolveQuerySet(v,0,b,w,0),n.copyBufferToBuffer(w,0,y,0,b*8)}if(this.device.queue.submit([n.finish()]),this.parity=1-t,a){let v=this.timingCallback;this.timingCallback=null,this.timingBusy=!0;let w=this.timing.read;w.mapAsync(GPUMapMode.READ).then(()=>{let y=new BigUint64Array(w.getMappedRange()).slice();if(w.unmap(),this.timingBusy=!1,this.destroyed)return this.releaseTiming();let A=(B,E)=>Number(y[E]-y[B])/1e6,x={total:A(0,b-1)};Se.forEach((B,E)=>x[B]=A(2*E,2*E+1)),v(x)},()=>{this.timingBusy=!1,this.destroyed&&this.releaseTiming()})}}async readBodies(){return new Float32Array(await this.read(this.bodyBuffer,this.bodyCount*qe*4))}async readJoints(){return new Float32Array(await this.read(this.jointBuffer,this.jointCount*pe*4))}async readCounters(){let e=new Uint32Array(await this.read(this.counterBuffer,64));return{pairs:e[0],contacts:e[1],manifolds:e[hr],overflow:e[3],clashes:e[4],colors:e[5]}}async readContactList(){let e=await this.readCounters(),t=Math.min(e.manifolds,this.manifoldCapacity),i=Math.min(e.contacts,this.contactCapacity),r=1-this.parity,[o,n]=await Promise.all([this.read(this.manifoldBuffers[r],t*Ut*4),this.read(this.contactBuffers[r],i*Ht*4)]),a=new Uint32Array(o),l=new Float32Array(o),c=new Uint32Array(n),u=new Float32Array(n),f=[];for(let d=0;d<t;d++){let p=d*Ut,g=[...l.subarray(p+_s,p+_s+3)];for(let h=a[p+2];h<a[p+2]+(a[p+3]&15);h++){let m=h*Ht,b=c[m+dr+3];f.push({a:a[p],b:a[p+1],feature:(b&~Ur)>>>0,stick:(b&Ur)!==0,rA:[...u.subarray(m+dr,m+dr+3)],rB:[...u.subarray(m+Es,m+Es+3)],pen:[...u.subarray(m+Ms,m+Ms+3)],lam:[...u.subarray(m+zs,m+zs+3)],normal:g})}}return f}async readPairs(){let{pairs:e}=await this.readCounters();return new Uint32Array(await this.read(this.pairBuffer,Math.min(e,this.pairCapacity)*8))}jointInfo(){return this.info.subarray(0,this.jointCount*4)}adapt(e){if(this.fixedColors)return;let t=e.colors;e.clashes>0&&(this.colorRounds=Math.min(32,this.colorRounds*2)),e.clashes>0||this.colorCap-t<2?(this.colorCap=Math.min(64,Math.max(t+Ts+2,this.colorCap+4)),this.shrinkVotes=0):t+Ts+2<this.colorCap||this.colorRounds>4?++this.shrinkVotes>=3&&(this.colorCap=Math.min(64,t+Ts),this.colorRounds=Math.max(4,this.colorRounds-4),this.shrinkVotes=0):this.shrinkVotes=0;let i=(a,l,c)=>(e.overflow&c)!==0||a>tu*l?Math.max(iu*a,1.25*l):l,r=i(e.contacts,this.contactCapacity,2),o=i(e.pairs,this.pairCapacity,1),n=i(e.manifolds,this.manifoldCapacity,4);this.capacityCanGrow(r,o,n)&&this.allocateContacts(r,o,n)}capacityCanGrow(e,t,i){let r=this.device.limits.maxStorageBufferBindingSize;return Math.min(e,r/(Ht*4))>this.contactCapacity||Math.min(t,r/8)>this.pairCapacity||Math.min(i,t,r/(Ut*4))>this.manifoldCapacity}async read(e,t){if(t===0)return new ArrayBuffer(0);let i=this.device.createBuffer({size:t,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),r=this.device.createCommandEncoder();r.copyBufferToBuffer(e,0,i,0,t),this.device.queue.submit([r.finish()]),await i.mapAsync(GPUMapMode.READ);let o=i.getMappedRange().slice(0);return i.unmap(),i.destroy(),o}releaseTiming(){this.timing?.resolve.destroy(),this.timing?.read.destroy(),this.timing?.querySet.destroy()}destroy(){this.ownsBodyBuffer&&this.bodyBuffer.destroy();let e=[this.jointBuffer,this.infoBuffer,...this.contactBuffers,...this.manifoldBuffers,this.pairBuffer,this.tableBuffer,this.gridBuffer,this.staticBuffer,this.counterBuffer,this.argsBuffer,this.adjBuffer,this.colorBuffer,this.paramsBuffer,this.refBuffer,this.hullBuffer,this.passBuffer,this.filterBuffer];for(let t of e)t?.destroy();this.destroyed=!0,this.timingBusy||this.releaseTiming(),this.gridScan.destroy(),this.colorHistScan.destroy(),this.adjScan?.destroy()}};var rl=` e.C = vec3f(
2421
+ `;function Ks(s,e){let t=0,i=s.length-1;for(;t<i;){let r=s[e],o=t,n=i;do{for(;s[o]<r;)o++;for(;r<s[n];)n--;if(o<=n){let a=s[o];s[o]=s[n],s[n]=a,o++,n--}}while(o<=n);n<e&&(t=o),e<o&&(i=n)}return s[e]}function Vn(s){let e=s.length,t=e>0?Ks(s,e>>1):1,i=0;for(let r=0;r<e;r++)s[r]<=2*t&&(i=Math.max(i,s[r]));return e>64&&(i=Math.max(i,Ks(s,e-64-1))),i}var $t=s=>s===1/0?3e38:s===-1/0?-3e38:s,dt=s=>Math.ceil(s/64),Ol=s=>2**Math.ceil(Math.log2(Math.max(s,2))),Wu=s=>Math.max(s,1)*We*4,Hu=8,Zs=3,$u=8,Ju=1.6,Xu=.8,Yu=2,Qu=[0,0,1],Ku=()=>({...En(),matchNearest:!0,faceBias:!0,reuseContacts:!0,startAtRest:!0,massPenalty:!0,windSpeed:0,windAngle:0,windGust:.4,windPressure:.72,up:[0,1,0]});function Zu(s,e){let t=s.vertices.length/3,i=s.faces.length,r=s.faces.reduce((m,h)=>m+h.verts.length,0),o=Math.ceil(r/4),n=s.edges.length,a=new Float32Array((2+t+2*i+o+n)*4),l=new Uint32Array(a.buffer),c=e+2,u=c+t,f=u+2*i,d=f+o;l.set([c,t,u,i,d,n,f,0],0);for(let m=0;m<t;m++)a.set(s.vertices.subarray(m*3,m*3+3),(2+m)*4);let p=0;return s.faces.forEach((m,h)=>{let g=(2+t+2*h)*4;a.set(m.normal,g),a[g+3]=m.d,l[g+4]=p,l[g+5]=m.verts.length;for(let b of m.verts)l[(2+t+2*i)*4+p++]=b}),s.edges.forEach((m,h)=>l.set(m,(2+t+2*i+o+h)*4)),a}var Wn=.001;function ef(s,e){let t=s.length,i=s.map(y=>{let A=y;return[A.group??4294967295,A.collidesWith??4294967295]}),r=i.map(([y,A])=>y!==0&&A!==0),o=s.map(y=>[0,1,2].map(A=>{let v=[0,0,0];return v[A]=1,ae(S(),y.positionAng,v)})),n=s.map((y,A)=>{if(De(y))return[y.radius,y.radius,y.radius];let v=[0,0,0];for(let x=0;x<3;x++)for(let w=0;w<3;w++)v[w]+=y.size[x]*.5*Math.abs(o[A][x][w]);return v}),a=Vn(Float64Array.from(s,y=>y.radius)),l=Math.max(2*a,.001),c=(y,A)=>{let v=s[y],x=s[A];if(v.mass<=0&&x.mass<=0||!(i[y][0]&i[A][1])||!(i[A][0]&i[y][1]))return!1;let w=v.positionLin[0]-x.positionLin[0],B=v.positionLin[1]-x.positionLin[1],L=v.positionLin[2]-x.positionLin[2];if(!(Math.abs(w)<=n[y][0]+n[A][0]&&Math.abs(B)<=n[y][1]+n[A][1]&&Math.abs(L)<=n[y][2]+n[A][2]))return!1;let M=v.radius+x.radius;return w*w+B*B+L*L<=M*M},u=(y,A)=>y[0]*A[0]+y[1]*A[1]+y[2]*A[2],f=(y,A)=>{let v=s[y],x=s[A],w=[0,1,2].map(E=>x.positionLin[E]-v.positionLin[E]),[B,L]=[De(v),De(x)];if(B&&L)return Math.hypot(w[0],w[1],w[2])<=v.radius+x.radius+Wn;if(B||L){let[E,k,P]=B?[A,v.radius,-1]:[y,x.radius,1],C=0;for(let _=0;_<3;_++){let z=Math.abs(P*u(w,o[E][_]))-s[E].size[_]*.5;z>0&&(C+=z*z)}return C<=(k+Wn)**2}let M=(E,k)=>s[E].size[0]*.5*Math.abs(u(o[E][0],k))+s[E].size[1]*.5*Math.abs(u(o[E][1],k))+s[E].size[2]*.5*Math.abs(u(o[E][2],k)),I=E=>{let k=Math.hypot(E[0],E[1],E[2]);return k<1e-6?!1:Math.abs(u(w,E))-M(y,E)-M(A,E)>Wn*k};for(let E=0;E<3;E++)if(I(o[y][E])||I(o[A][E]))return!1;for(let E of o[y])for(let k of o[A])if(I([E[1]*k[2]-E[2]*k[1],E[2]*k[0]-E[0]*k[2],E[0]*k[1]-E[1]*k[0]]))return!1;return!0},d=new Set,p=new Map,m=(y,A,v)=>(y*73856093^A*19349663^v*83492791)>>>0,h=y=>[0,1,2].map(A=>Math.floor(s[y].positionLin[A]/l));for(let y=0;y<t;y++){if(!r[y])continue;if(s[y].radius>a){d.add(y);continue}let[A,v,x]=h(y),w=m(A,v,x),B=p.get(w);B?B.push(y):p.set(w,[y])}let g=0,b=0;for(let y=0;y<t;y++){if(!r[y]||d.has(y))continue;let[A,v,x]=h(y);for(let w=-1;w<=1;w++)for(let B=-1;B<=1;B++)for(let L=-1;L<=1;L++)for(let M of p.get(m(A+L,v+B,x+w))??[])M<y&&c(y,M)&&(g++,f(y,M)&&(b++,e[y]++,e[M]++))}for(let y of d)for(let A=0;A<t;A++)r[A]&&A!==y&&(!d.has(A)||A<y)&&c(y,A)&&(g++,f(y,A)&&(b++,e[y]++,e[A]++));return{pairs:g,touching:b}}function tf(s){let e=[1/0,1/0,1/0],t=[-1/0,-1/0,-1/0];for(let o of s)for(let n=0;n<3;n++)e[n]=Math.min(e[n],o.positionLin[n]),t[n]=Math.max(t[n],o.positionLin[n]);let i=o=>{let n=o&1023;return n=(n|n<<16)&50331903,n=(n|n<<8)&50393103,n=(n|n<<4)&51130563,n=(n|n<<2)&153391689,n},r=s.map(o=>{let n=[0,1,2].map(a=>Math.min(1023,Math.floor((o.positionLin[a]-e[a])/Math.max(t[a]-e[a],1e-9)*1024)));return(i(n[0])|i(n[1])<<1|i(n[2])<<2)>>>0});return s.map((o,n)=>n).sort((o,n)=>r[o]-r[n]||o-n)}var Pe=()=>GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST,eo=class{device;params=Ku();bodyCount=0;bodyCapacity;bodies=[];hulls;hullBuffer;get hullStorage(){return this.hullBuffer}hullCapacity=4096;hullTop=0;hullSlots=new Map;contactShaders;hullShaders=!1;hullFree=[];refToGpu;jointCount=0;jointCapacity=0;info=new Int32Array(0);pairCapacity=0;manifoldCapacity=0;contactCapacity=0;colorCap=12;fixedColors=null;primalLanes=[2**31,2**15,2**12];splitPasses=!1;shrinkVotes=0;colorRounds;get colorHistOffset(){return 3*this.bodyCapacity+65}bodyBuffer;ownsBodyBuffer;jointBuffer;infoBuffer;contactBuffers;manifoldBuffers;pairBuffer;tableBuffer;gridBuffer;staticBuffer=null;filterBuffer;get filterStorage(){return this.filterBuffer}counterBuffer;get contactStorage(){let e=1-this.parity;return{manifolds:this.manifoldBuffers[e],contacts:this.contactBuffers[e],counters:this.counterBuffer}}argsBuffer;adjBuffer=null;colorBuffer;paramsBuffer;refBuffer;stepCount=0;passBuffer=null;passEntries=0;parity=0;tableSize;hashSize=0;cellSize=1;maxSmallRadius=0;largeCount=0;noCollideCount=0;radiiDirty=!0;noCollideDirty=!0;large=[];entries=[];pendingEntries=[];releasedSlots=new Set;freeSlots=[];layouts;pipes={};groups;passGroup=null;gridScan;colorHistScan;colorGroups;adjScan=null;timing;timingCallback=null;timingBusy=!1;destroyed=!1;constructor(e,t,i={}){this.device=e;let{dt:r,gravity:o,iterations:n,alpha:a,betaLin:l,betaAng:c,gamma:u}=t;if(Object.assign(this.params,{dt:r,gravity:o,iterations:n,alpha:a,betaLin:l,betaAng:c,gamma:u,up:Qu}),this.bodyCount=t.bodies.length,this.colorRounds=i.colorRounds??16,this.ownsBodyBuffer=!i.bodyBuffer,this.bodyCapacity=i.bodyBuffer?Math.floor(i.bodyBuffer.size/(We*4)):Math.max(i.bodyCapacity??this.bodyCount+1024,this.bodyCount,1),this.bodyCapacity<this.bodyCount)throw new Error("body buffer too small");this.bodyBuffer=i.bodyBuffer??e.createBuffer({label:"bodies 3d",size:Wu(this.bodyCapacity),usage:Pe()}),this.filterBuffer=e.createBuffer({label:"collision filters",size:Math.max(this.bodyCapacity,1)*8,usage:Pe()}),e.queue.writeBuffer(this.filterBuffer,0,new Uint32Array(Math.max(this.bodyCapacity,1)*2).fill(4294967295));let f=this.bodyCapacity;this.tableSize=Ol(2*f),this.gridBuffer=e.createBuffer({label:"grid 3d",size:(2*this.tableSize+1+4*f)*4,usage:Pe()}),this.counterBuffer=e.createBuffer({label:"counters",size:64,usage:Pe()}),this.argsBuffer=e.createBuffer({label:"indirect args",size:816,usage:Pe()|GPUBufferUsage.INDIRECT}),this.colorGroups=Math.ceil(f/256),this.colorBuffer=e.createBuffer({label:"colours",size:(3*f+65+64*this.colorGroups+1)*4,usage:Pe()}),this.paramsBuffer=e.createBuffer({label:"params 3d",size:es*4,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.refBuffer=e.createBuffer({label:"reference poses",size:f*32,usage:Pe()}),this.hulls=(i.hulls??!0)&&e.limits.maxStorageBuffersPerShaderStage>=9,this.hullBuffer=e.createBuffer({label:"hulls",size:this.hullCapacity*16,usage:Pe()}),e.queue.writeBuffer(this.colorBuffer,0,new Uint32Array(f).fill(255));let d=2*Se.length;this.timing=e.features.has("timestamp-query")?{querySet:e.createQuerySet({type:"timestamp",count:d}),resolve:e.createBuffer({size:d*8,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),read:e.createBuffer({size:d*8,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST})}:null,this.layouts=this.createLayouts(),this.createPipelines(i.shaders??{}),this.gridScan=new tt(e,this.gridBuffer,0,this.tableSize+1),this.colorHistScan=new tt(e,this.colorBuffer,this.colorHistOffset,64*this.colorGroups+1);let p=i.spatialSort===!1?t.bodies.map((w,B)=>B):tf(t.bodies);this.refToGpu=new Int32Array(p.length),p.forEach((w,B)=>this.refToGpu[w]=B);let m=new Map(t.bodies.map((w,B)=>[w,this.refToGpu[B]])),h=t.forces.filter(w=>w instanceof ke||w instanceof ft);for(let w of t.forces){if(!(w instanceof Vs))continue;let B=m.get(w.bodyA),L=m.get(w.bodyB);this.pendingEntries.push([Math.max(B,L),Math.min(B,L),4294967295])}this.allocateJoints(Math.max(h.length+256,i.capacity?.joints??0));for(let w of h)this.writeJoint(this.jointCount++,w,m);let g=new Int32Array(t.bodies.length),{pairs:b,touching:y}=ef(t.bodies,g),A=new Map(t.bodies.map((w,B)=>[w,B]));for(let w of h)w.bodyA&&g[A.get(w.bodyA)]++,g[A.get(w.bodyB)]++;let v=0;t.bodies.forEach((w,B)=>{w.mass>0&&(v=Math.max(v,g[B]))}),this.colorCap=Math.min(64,Math.max($u,v+1+Zs,i.capacity?.colors??0));let x=i.capacity??{};this.allocateContacts(Math.max(8192,4*f,Hu*y,x.contacts??0),Math.max(4096,4*f,2*b,x.pairs??0),Math.max(4096,f,Ju*y,x.manifolds??0)),this.writeBodies(0,p.map(w=>t.bodies[w]))}gpuIndex(e){return e<this.refToGpu.length?this.refToGpu[e]:e}createLayouts(){let e=this.device,t=(n,a)=>e.createBindGroupLayout({label:n,entries:a.map((l,c)=>({binding:c,visibility:GPUShaderStage.COMPUTE,buffer:{type:l}}))}),i="read-only-storage",r="storage",o="uniform";return{broad:t("broadphase 3d",[o,i,r,r,r,i,i,i]),contacts:t("contacts 3d",[o,i,i,r,i,r,i,r,r,...this.hulls?[i]:[]]),topo:t("topology 3d",[o,i,i,i,i,r,r,r]),solve:t("solve 3d",[o,r,r,i,r,i,i,i,i]),pass:e.createBindGroupLayout({label:"pass",entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform",hasDynamicOffset:!0,minBindingSize:16}}]}),args:t("args 3d",[o,i,i,r]),refs:t("refs 3d",[o,r,r])}}createPipelines(e){let t=this.device,i=(o,n,a)=>{let l=t.createShaderModule({code:o}),c=t.createPipelineLayout({bindGroupLayouts:n});for(let u of a)this.pipes[u]=t.createComputePipeline({label:u,layout:c,compute:{module:l,entryPoint:u}})},r=this.layouts;i(fi,[r.broad],["beginFrame","gridCount","gridScatter","findPairs"]),i(e.refs??Qs,[r.refs],["updateRefs"]),i(e.contacts??zl,[r.contacts],["hashInsert","narrowphase"]),this.contactShaders={make:o=>i(o,[r.contacts],["hashInsert","narrowphase"]),custom:!!e.contacts},i(e.topology??Ti(ge,br),[r.topo],["degreeJoints","degreeContacts","fillJoints","fillContacts","sortAdjacency","colorCompact","colorMark","colorRoundAB","colorRoundBA","colorCount","colorStarts","colorScatter"]),i(e.solve??Ge,[r.solve,r.pass],["warmStartJoints","warmStartBodies","primal","dual","updateVelocities"]),i(Nr(ge,Ys),[r.args],["argsPrev","argsPairs","argsContacts","argsColors"])}allocateJoints(e){let t=this.device,i=t.createBuffer({label:"joints 3d",size:Math.max(e,1)*pe*4,usage:Pe()}),r=t.createBuffer({label:"joint info",size:Math.max(e,1)*16,usage:Pe()});if(this.jointBuffer){let n=t.createCommandEncoder();n.copyBufferToBuffer(this.jointBuffer,0,i,0,this.jointCapacity*pe*4),n.copyBufferToBuffer(this.infoBuffer,0,r,0,this.jointCapacity*16),t.queue.submit([n.finish()]),this.jointBuffer.destroy(),this.infoBuffer.destroy()}let o=new Int32Array(e*4);o.set(this.info.subarray(0,Math.min(this.info.length,o.length))),this.info=o,this.jointBuffer=i,this.infoBuffer=r,this.jointCapacity=e,this.contactBuffers&&this.rebuildBindings()}allocateContacts(e,t,i){let r=this.device,o=r.limits.maxStorageBufferBindingSize,n=Math.min(Math.ceil(e),Math.floor(o/(Ht*4))),a=Math.min(Math.ceil(t),Math.floor(o/8)),l=Math.min(Math.ceil(i),a,Math.floor(o/(Nt*4))),c={contacts:this.contactBuffers,manifolds:this.manifoldBuffers,contactCapacity:this.contactCapacity,manifoldCapacity:this.manifoldCapacity};for(let u of[this.pairBuffer,this.tableBuffer])u?.destroy();if(this.contactCapacity=n,this.pairCapacity=a,this.manifoldCapacity=l,this.hashSize=Ol(2*l),this.pairBuffer=r.createBuffer({label:"pairs",size:a*8,usage:Pe()}),this.tableBuffer=r.createBuffer({label:"manifold hash",size:this.hashSize*4,usage:Pe()}),this.contactBuffers=[0,1].map(u=>r.createBuffer({label:`contacts 3d ${u}`,size:n*Ht*4,usage:Pe()})),this.manifoldBuffers=[0,1].map(u=>r.createBuffer({label:`manifolds 3d ${u}`,size:l*Nt*4,usage:Pe()})),c.contacts){let u=r.createCommandEncoder(),f=Math.min(c.contactCapacity,n)*Ht*4,d=Math.min(c.manifoldCapacity,l)*Nt*4;c.contacts.forEach((p,m)=>u.copyBufferToBuffer(p,0,this.contactBuffers[m],0,f)),c.manifolds.forEach((p,m)=>u.copyBufferToBuffer(p,0,this.manifoldBuffers[m],0,d)),r.queue.submit([u.finish()]),[...c.contacts,...c.manifolds].forEach(p=>p.destroy())}this.rebuildBindings()}rebuildBindings(){let e=this.device,t=this.bodyCapacity;this.adjBuffer?.destroy(),this.adjBuffer=e.createBuffer({label:"adjacency",size:(2*t+1+2*(this.jointCapacity+this.manifoldCapacity))*4,usage:Pe()}),this.adjScan?.destroy(),this.adjScan=new tt(e,this.adjBuffer,0,this.bodyCount+1),this.staticBuffer??=e.createBuffer({label:"statics",size:16,usage:Pe()});let i=(d,p)=>e.createBindGroup({layout:d,entries:p.map((m,h)=>({binding:h,resource:{buffer:m}}))}),r=this.paramsBuffer,[o,n]=this.contactBuffers,[a,l]=this.manifoldBuffers,c=this.adjBuffer,u=this.tableBuffer,f=this.counterBuffer;this.groups={broad:i(this.layouts.broad,[r,this.bodyBuffer,this.gridBuffer,this.pairBuffer,f,this.staticBuffer,this.jointBuffer,this.filterBuffer]),contacts:[i(this.layouts.contacts,[r,this.bodyBuffer,this.pairBuffer,o,n,a,l,u,f,...this.hulls?[this.hullBuffer]:[]]),i(this.layouts.contacts,[r,this.bodyBuffer,this.pairBuffer,n,o,l,a,u,f,...this.hulls?[this.hullBuffer]:[]])],topo:[a,l].map(d=>i(this.layouts.topo,[r,this.bodyBuffer,this.jointBuffer,this.infoBuffer,d,f,c,this.colorBuffer])),solve:[0,1].map(d=>i(this.layouts.solve,[r,this.bodyBuffer,this.jointBuffer,this.infoBuffer,[o,n][d],c,this.colorBuffer,f,[a,l][d]])),args:i(this.layouts.args,[r,this.counterBuffer,this.colorBuffer,this.argsBuffer]),refs:i(this.layouts.refs,[r,this.bodyBuffer,this.refBuffer])}}writeBodies(e,t){let i=new Float32Array(Math.max(t.length,1)*We);t.forEach((r,o)=>{let n=this.pack(r,i,o*We,this.bodies[e+o]?.hull);this.bodies[e+o]?.radius!==n.radius&&(this.radiiDirty=!0),this.bodies[e+o]=n}),this.device.queue.writeBuffer(this.bodyBuffer,e*We*4,i,0,t.length*We)}rewriteFixed(e,t,i,r,o){if(!e.length)return;let n=new Float32Array(We),a={positionLin:[0,0,0],positionAng:[0,0,0,1],initialLin:[0,0,0],initialAng:[0,0,0,1],inertialLin:[0,0,0],inertialAng:[0,0,0,1],velocityLin:[0,0,0],prevVelocityLin:[0,0,0],velocityAng:[0,0,0],size:[i[0],i[1],i[2]],mass:0,moment:[0,0,0],friction:r,radius:Math.hypot(i[0]/2,i[1]/2,i[2]/2)},l=this.pack(a,n,0);for(let c=0;c<e.length;){let u=c+1;for(;u<e.length&&e[u]===e[u-1]+1;)u++;let f=new Float32Array((u-c)*We);for(let d=c;d<u;d++){let p=(d-c)*We;f.set(n,p);for(let h=0;h<3;h++)f[p+ur+h]=t[3*d+h];if(o)for(let h=0;h<4;h++)f[p+Wr+h]=o[4*d+h];let m=this.bodies[e[d]];m?.radius!==l.radius&&(this.radiiDirty=!0),m?.hull&&this.releaseHull(m.hull),this.bodies[e[d]]={...l,size:[...l.size]}}this.device.queue.writeBuffer(this.bodyBuffer,e[c]*We*4,f),this.device.queue.writeBuffer(this.colorBuffer,e[c]*4,new Uint32Array(u-c).fill(255)),c=u}}pack(e,t,i,r){{t.set(e.positionLin,i+ur),t[i+ur+3]=e.friction,t.set(e.positionAng,i+Wr),t.set(e.size,i+jn),t[i+jn+3]=e.mass,t.set(e.moment,i+Dn),t[i+Dn+3]=e.radius,t.set(e.initialLin,i+wl),t.set(e.initialAng,i+Bl),t.set(e.inertialLin,i+Cl),t.set(e.inertialAng,i+Sl),t.set(e.velocityLin,i+Gn);let o=this.params.up;t[i+Gn+3]=e.prevVelocityLin[0]*o[0]+e.prevVelocityLin[1]*o[1]+e.prevVelocityLin[2]*o[2],t.set(e.velocityAng,i+Fn);let n=De(e),a=this.hulls?Ct(e):void 0;r&&r!==a&&this.releaseHull(r);let l=a?r===a?this.hullSlots.get(a).offset:this.acquireHull(a):-1;return t[i+Fn+3]=n?Un:l>=0?Xs+l:or(e)?Nn:Ll,{radius:e.radius,dynamic:e.mass>0,sphere:n,size:[e.size[0],e.size[1],e.size[2]],hull:a}}}writeJoint(e,t,i){let r=new Float32Array(pe),o=t.bodyA?i.get(t.bodyA):-1,n=i.get(t.bodyB);t instanceof ke?(r.set(t.penaltyLin,ci),r[ci+3]=$t(t.broken?0:t.stiffnessLin),r.set(t.penaltyAng,Hr),r[Hr+3]=$t(t.broken?0:t.stiffnessAng),r.set(t.lambdaLin,fr),r[fr+3]=$t(t.fracture),r.set(t.lambdaAng,dr),r[dr+3]=t.torqueArm,r.set(t.C0Lin,kl),r.set(t.C0Ang,Pl),r.set(t.rA,ui),r.set(t.rB,hr)):(r[ci+3]=t.stiffness,r.set(t.rA,ui),r[ui+3]=t.rest,r.set(t.rB,hr)),this.info.set([t instanceof ke?Jr:gr,o,n,0],e*4),this.device.queue.writeBuffer(this.jointBuffer,e*pe*4,r),this.device.queue.writeBuffer(this.infoBuffer,e*16,this.info,e*4,4),this.noCollide(o,n,e)}noCollide(e,t,i){e<0||(this.pendingEntries.push([Math.max(e,t),Math.min(e,t),i]),this.noCollideDirty=!0)}uploadStatics(){if(this.radiiDirty){let r=this.bodyCount,o=new Float64Array(r);for(let c=0;c<r;c++)o[c]=this.bodies[c].radius;let n=Vn(o),a=1/0;for(let c=0;c<r;c++)o[c]>n&&(a=Math.min(a,o[c]));let l=a===1/0?n*1.5:(n+a)/2;this.maxSmallRadius=l,this.cellSize=Math.max(2*n*(1+1e-4),.001),this.large=[];for(let c=0;c<r;c++)this.bodies[c].radius>l&&this.large.push(c);this.radiiDirty=!1}if(this.noCollideDirty){let r=(l,c)=>l[0]-c[0]||l[1]-c[1],o=this.releasedSlots.size?this.entries.filter(l=>!this.releasedSlots.has(l[2])):this.entries;this.releasedSlots.clear();let n=this.pendingEntries.sort(r);this.pendingEntries=[];let a=[];for(let l=0,c=0;l<o.length||c<n.length;)c>=n.length||l<o.length&&r(o[l],n[c])<=0?a.push(o[l++]):a.push(n[c++]);this.entries=a,this.noCollideDirty=!1}let{large:e,entries:t}=this;this.largeCount=e.length,this.noCollideCount=t.length;let i=new Uint32Array(Math.max(e.length+3*t.length,4));i.set(e,0),t.forEach((r,o)=>i.set(r,e.length+3*o)),this.staticBuffer.size<i.byteLength&&(this.staticBuffer.destroy(),this.staticBuffer=this.device.createBuffer({label:"statics",size:i.byteLength,usage:Pe()}),this.rebuildBindings()),this.device.queue.writeBuffer(this.staticBuffer,0,i)}seedFrom(e){if(this.refToGpu.some((m,h)=>m!==h))throw new Error("seedFrom needs spatialSort: false");let t=new Map(e.bodies.map((m,h)=>[m,h]));this.writeBodies(0,e.bodies);let i=0;for(let m of e.forces)(m instanceof ke||m instanceof ft)&&this.writeJoint(i++,m,t);if(i!==this.jointCount)throw new Error("seedFrom: joints differ from the reference");let r=e.forces.filter(m=>m instanceof ni),o=r.reduce((m,h)=>m+h.contacts.length,0);if(o>this.contactCapacity||r.length>this.manifoldCapacity)throw new Error("seedFrom: too many contacts");let n=new ArrayBuffer(Math.max(o,1)*Ht*4),a=new Uint32Array(n),l=new Float32Array(n),c=new ArrayBuffer(Math.max(r.length,1)*Nt*4),u=new Uint32Array(c),f=new Float32Array(c),d=0;r.forEach((m,h)=>{u.set([t.get(m.bodyA),t.get(m.bodyB),d,m.contacts.length],h*Nt),f.set([m.basis[0],m.basis[1],m.basis[2],m.friction],h*Nt+Ws);for(let g of m.contacts){let b=d++*Ht;l.set(g.rA,b+pr),a[b+pr+3]=g.feature>>>0|(g.stick?$r:0),l.set([...g.rB,g.C0[0]],b+Hs),l.set([...g.penalty,g.C0[1]],b+$s),l.set([...g.lambda,g.C0[2]],b+Js)}}),this.device.queue.writeBuffer(this.contactBuffers[1-this.parity],0,n),this.device.queue.writeBuffer(this.manifoldBuffers[1-this.parity],0,c);let p=new Uint32Array(16);p[1]=o,p[mr]=r.length,this.device.queue.writeBuffer(this.counterBuffer,0,p)}sequentialColors(){let e=new Uint32Array(this.bodyCount).fill(255),t=0;for(let i=this.bodyCount-1;i>=0;i--)this.bodies[i].dynamic&&(e[i]=t++);if(t>64)throw new Error(`sequentialColors: ${t} dynamic bodies, at most ${64}`);return e}acquireHull(e){!this.hullShaders&&!this.contactShaders.custom&&(this.contactShaders.make(Il),this.hullShaders=!0);let t=this.hullSlots.get(e);if(t)return t.refs++,t.offset;let i=2+e.vertices.length/3+2*e.faces.length+Math.ceil(e.faces.reduce((n,a)=>n+a.verts.length,0)/4)+e.edges.length,r=-1,o=this.hullFree.findIndex(n=>n.size>=i);if(o>=0){let n=this.hullFree[o];r=n.offset,n.size===i?this.hullFree.splice(o,1):Object.assign(n,{offset:n.offset+i,size:n.size-i})}else r=this.hullTop,this.hullTop+=i,this.hullTop>this.hullCapacity&&this.growHulls(this.hullTop);if(r+Xs>=2**24)throw new Error("hull buffer beyond 2^24 vec4s");return this.device.queue.writeBuffer(this.hullBuffer,r*16,Zu(e,r)),this.hullSlots.set(e,{offset:r,size:i,refs:1}),r}releaseHull(e){let t=this.hullSlots.get(e);if(!t||--t.refs>0)return;this.hullSlots.delete(e),this.hullFree.push({offset:t.offset,size:t.size}),this.hullFree.sort((r,o)=>r.offset-o.offset);let i=[];for(let r of this.hullFree){let o=i[i.length-1];o&&o.offset+o.size===r.offset?o.size+=r.size:i.push({...r})}this.hullFree=i}growHulls(e){let t=this.hullCapacity;for(;t<e;)t*=2;let i=this.device.createBuffer({label:"hulls",size:t*16,usage:Pe()}),r=this.device.createCommandEncoder();r.copyBufferToBuffer(this.hullBuffer,0,i,0,this.hullCapacity*16),this.device.queue.submit([r.finish()]),this.hullBuffer.destroy(),this.hullBuffer=i,this.hullCapacity=t,this.contactBuffers&&this.rebuildBindings()}addBody(e){return this.addBodies([e])}addBodies(e){let t=Math.min(e.length,this.bodyCapacity-this.bodyCount);if(t<=0)return-1;let i=this.bodyCount;return this.bodyCount+=t,this.writeBodies(i,e.slice(0,t)),this.device.queue.writeBuffer(this.colorBuffer,i*4,new Uint32Array(t).fill(255)),this.adjScan.destroy(),this.adjScan=new tt(this.device,this.adjBuffer,0,this.bodyCount+1),i}appendJoint(e,t,i,r,o,n){let a=this.jointCount;a>=this.jointCapacity&&this.allocateJoints(this.jointCapacity*2),this.jointCount++;let l=new Float32Array(pe);l[ci+3]=$t(o),l[Hr+3]=$t(n),l[fr+3]=3e38,l.set([i[0],i[1],i[2]],ui),l.set([r[0],r[1],r[2]],hr);let c=e>=0?this.bodies[e].size:[0,0,0],u=this.bodies[t].size;return l[dr+3]=(c[0]+u[0])**2+(c[1]+u[1])**2+(c[2]+u[2])**2,this.info.set([Jr,e,t,0],a*4),this.device.queue.writeBuffer(this.jointBuffer,a*pe*4,l),this.device.queue.writeBuffer(this.infoBuffer,a*16,this.info,a*4,4),this.noCollide(e,t,a),a}appendJoints(e,t,i=!1){return this.appendConstraints(e.length,(r,o)=>{let{a:n,b:a,rA:l,rB:c,angular:u}=e[r];o[ci+3]=3e38,o[Hr+3]=u===void 0?3e38:$t(u),o[fr+3]=i?-$t(t):$t(t),o.set([l[0],l[1],l[2]],ui),o.set([c[0],c[1],c[2]],hr);let[f,d]=[this.bodies[n].size,this.bodies[a].size];return o[dr+3]=(f[0]+d[0])**2+(f[1]+d[1])**2+(f[2]+d[2])**2,[Jr,n,a]})}appendSprings(e){return this.appendConstraints(e.length,(t,i)=>{let{a:r,b:o,rA:n,rB:a,stiffness:l,rest:c}=e[t];return i[ci+3]=$t(l),i.set([n[0],n[1],n[2],c],ui),i.set([a[0],a[1],a[2]],hr),[gr,r,o]})}appendConstraints(e,t){let i=[];if(this.freeSlots.length)for(this.freeSlots.sort((a,l)=>l-a);i.length<e&&this.freeSlots.length;)i.push(this.freeSlots.pop());let r=e-i.length,o=this.jointCapacity;for(;this.jointCount+r>o;)o*=2;o>this.jointCapacity&&this.allocateJoints(o);for(let a=0;a<r;a++)i.push(this.jointCount++);let n=new Float32Array(e*pe);for(let a=0;a<e;a++){let[l,c,u]=t(a,n.subarray(a*pe,(a+1)*pe));this.info.set([l,c,u,0],i[a]*4),this.releasedSlots.delete(i[a]),this.noCollide(c,u,i[a])}for(let a=0;a<e;){let l=a+1;for(;l<e&&i[l]===i[l-1]+1;)l++;this.device.queue.writeBuffer(this.jointBuffer,i[a]*pe*4,n,a*pe,(l-a)*pe),this.device.queue.writeBuffer(this.infoBuffer,i[a]*16,this.info,i[a]*4,(l-a)*4),a=l}return i}releaseJoints(e){let t=[...new Set(Array.from(e))].filter(r=>r<this.jointCount&&this.info[r*4]!==0).sort((r,o)=>r-o);if(!t.length)return;for(let r of t)this.info.set([0,-1,-1,0],r*4),this.releasedSlots.add(r),this.freeSlots.push(r);let i=new Float32Array(0);for(let r=0;r<t.length;){let o=r+1;for(;o<t.length&&t[o]===t[o-1]+1;)o++;i.length<(o-r)*pe&&(i=new Float32Array((o-r)*pe)),this.device.queue.writeBuffer(this.jointBuffer,t[r]*pe*4,i,0,(o-r)*pe),this.device.queue.writeBuffer(this.infoBuffer,t[r]*16,this.info,t[r]*4,(o-r)*4),r=o}this.noCollideDirty=!0}rewriteBodies(e,t){for(let i=0;i<e.length;){let r=i+1;for(;r<e.length&&e[r]===e[r-1]+1;)r++;this.writeBodies(e[i],t.slice(i,r)),this.device.queue.writeBuffer(this.colorBuffer,e[i]*4,new Uint32Array(r-i).fill(255)),i=r}}setFilters(e,t,i){for(let r=0;r<e.length;){let o=r+1;for(;o<e.length&&e[o]===e[o-1]+1;)o++;let n=new Uint32Array(2*(o-r));for(let a=r;a<o;a++)n.set([t[a]>>>0,i[a]>>>0],2*(a-r));this.device.queue.writeBuffer(this.filterBuffer,e[r]*8,n),r=o}}setWorldAnchor(e,t){this.device.queue.writeBuffer(this.jointBuffer,(e*pe+ui)*4,new Float32Array([t[0],t[1],t[2]]))}disableConstraint(e){this.device.queue.writeBuffer(this.jointBuffer,(e*pe+ci)*4,new Float32Array(8)),this.device.queue.writeBuffer(this.jointBuffer,(e*pe+fr)*4,new Float32Array(3)),this.device.queue.writeBuffer(this.jointBuffer,(e*pe+dr)*4,new Float32Array(3))}profileNextStep(e){this.timing&&!this.timingBusy&&(this.timingCallback=e)}writeParams(){let e=this.params,t=this.bodyCapacity,i=new ArrayBuffer(es*4),r=new Float32Array(i),o=new Uint32Array(i);r[0]=e.dt,r[1]=e.gravity,r[2]=e.betaLin,r[3]=e.betaAng,r[4]=e.gamma,r[5]=e.alpha,o[6]=(e.matchNearest?Xr:0)|(e.faceBias?Yr:0)|(e.reuseContacts?Qr:0)|(e.startAtRest?Kr:0)|(e.massPenalty?Zr:0),o[7]=this.bodyCount,o[8]=this.jointCount,o[9]=this.colorCap,r[10]=this.cellSize,o[11]=this.tableSize-1,r[12]=this.maxSmallRadius,o[13]=this.largeCount,o[14]=this.noCollideCount,o[15]=this.pairCapacity,o[16]=this.contactCapacity,o[17]=this.hashSize-1,o[18]=t+1,o[19]=2*t+1,o[20]=this.tableSize+1,o[21]=2*this.tableSize+1,o[22]=2*this.tableSize+1+t,o[23]=t,o[24]=this.colorHistOffset,o[25]=2*t,o[26]=this.colorGroups,o[27]=2*t+65,o[28]=this.colorRounds,o[29]=this.manifoldCapacity,o[30]=this.stepCount;let n=a=>Math.min(31,Math.max(0,Math.round(Math.log2(a))));o[31]=n(this.primalLanes[0])|n(this.primalLanes[1])<<8|n(this.primalLanes[2])<<16,r.set([e.windSpeed*Math.cos(e.windAngle),e.windSpeed*Math.sin(e.windAngle),0,e.windPressure,e.windGust],32),r.set([e.up[0],e.up[1],e.up[2],0],40),this.device.queue.writeBuffer(this.paramsBuffer,0,i)}writePassConstants(e,t){let i=this.colorCap+1,r=Math.max(e*i,1);(r>this.passEntries||!this.passGroup)&&(this.passBuffer?.destroy(),this.passBuffer=this.device.createBuffer({label:"pass constants",size:r*256,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.passEntries=r,this.passGroup=this.device.createBindGroup({layout:this.layouts.pass,entries:[{binding:0,resource:{buffer:this.passBuffer,size:16}}]}));let o=new ArrayBuffer(r*256),n=new Uint32Array(o),a=new Float32Array(o);for(let l=0;l<e;l++)for(let c=0;c<=this.colorCap;c++){let u=(l*i+c)*256/4;n[u]=c,a[u+1]=t}this.device.queue.writeBuffer(this.passBuffer,0,o)}step(){(this.radiiDirty||this.noCollideDirty)&&this.uploadStatics();let e=this.params;this.fixedColors&&(this.device.queue.writeBuffer(this.colorBuffer,0,this.fixedColors),this.colorCap=Math.max(1,...this.fixedColors.map(y=>y===255?0:y+1))),this.stepCount++,this.writeParams(),this.writePassConstants(e.iterations,e.alpha);let t=this.parity,i=this.bodyCapacity,r=this.bodyCount,o=this.jointCount,n=this.device.createCommandEncoder({label:"avbd3d step"});n.clearBuffer(this.gridBuffer,0,(2*this.tableSize+1)*4),n.clearBuffer(this.tableBuffer),n.clearBuffer(this.adjBuffer,0,(2*i+1)*4);let a=this.timingCallback!==null&&this.timing!==null,l,c=0,u=a||this.splitPasses,f=()=>{l&&!u||(l?.end(),l=n.beginComputePass({label:u?Se[c]:"avbd3d step",timestampWrites:a?{querySet:this.timing.querySet,beginningOfPassWriteIndex:2*c,endOfPassWriteIndex:2*c+1}:void 0}),c++)},d=this.groups,p=(y,A,v)=>{v<=0||(l.setPipeline(this.pipes[y]),l.setBindGroup(0,A),l.dispatchWorkgroups(v))},m=(y,A,v)=>{l.setPipeline(this.pipes[y]),l.setBindGroup(0,A),l.dispatchWorkgroupsIndirect(this.argsBuffer,v*4)};if(f(),p("beginFrame",d.broad,1),e.reuseContacts&&p("updateRefs",d.refs,dt(r)),p("argsPrev",d.args,1),m("hashInsert",d.contacts[t],6),p("gridCount",d.broad,dt(r)),this.gridScan.encode(l),p("gridScatter",d.broad,dt(r)),p("findPairs",d.broad,dt(r)),p("argsPairs",d.args,1),m("narrowphase",d.contacts[t],0),p("argsContacts",d.args,1),f(),p("degreeJoints",d.topo[t],dt(o)),m("degreeContacts",d.topo[t],3),this.adjScan.encode(l),p("fillJoints",d.topo[t],dt(o)),m("fillContacts",d.topo[t],3),p("sortAdjacency",d.topo[t],dt(r)),f(),!this.fixedColors){p("colorCompact",d.topo[t],dt(r)),p("colorMark",d.topo[t],dt(r));for(let y=0;y<this.colorRounds;y++)p(y%2===0?"colorRoundAB":"colorRoundBA",d.topo[t],dt(r))}p("colorCount",d.topo[t],this.colorGroups),this.colorHistScan.encode(l),p("colorStarts",d.topo[t],1),p("argsColors",d.args,1),p("colorScatter",d.topo[t],this.colorGroups),f();let h=this.colorCap+1,g=y=>l.setBindGroup(1,this.passGroup,[y*256]);l.setBindGroup(0,d.solve[t]),g(0),o>0&&(l.setPipeline(this.pipes.warmStartJoints),l.dispatchWorkgroups(dt(o))),l.setPipeline(this.pipes.warmStartBodies),l.dispatchWorkgroups(dt(r));for(let y=0;y<e.iterations;y++){l.setPipeline(this.pipes.primal);for(let A=0;A<this.colorCap;A++)g(y*h+A),l.dispatchWorkgroupsIndirect(this.argsBuffer,(12+3*A)*4);g(y*h+this.colorCap),l.setPipeline(this.pipes.dual),l.dispatchWorkgroupsIndirect(this.argsBuffer,36)}l.setPipeline(this.pipes.updateVelocities),l.dispatchWorkgroups(dt(r)),l.end();let b=2*Se.length;if(a){let{querySet:y,resolve:A,read:v}=this.timing;n.resolveQuerySet(y,0,b,A,0),n.copyBufferToBuffer(A,0,v,0,b*8)}if(this.device.queue.submit([n.finish()]),this.parity=1-t,a){let y=this.timingCallback;this.timingCallback=null,this.timingBusy=!0;let A=this.timing.read;A.mapAsync(GPUMapMode.READ).then(()=>{let v=new BigUint64Array(A.getMappedRange()).slice();if(A.unmap(),this.timingBusy=!1,this.destroyed)return this.releaseTiming();let x=(B,L)=>Number(v[L]-v[B])/1e6,w={total:x(0,b-1)};Se.forEach((B,L)=>w[B]=x(2*L,2*L+1)),y(w)},()=>{this.timingBusy=!1,this.destroyed&&this.releaseTiming()})}}async readBodies(){return new Float32Array(await this.read(this.bodyBuffer,this.bodyCount*We*4))}async readJoints(){return new Float32Array(await this.read(this.jointBuffer,this.jointCount*pe*4))}async readCounters(){let e=new Uint32Array(await this.read(this.counterBuffer,64));return{pairs:e[0],contacts:e[1],manifolds:e[mr],overflow:e[3],clashes:e[4],colors:e[5]}}async readContactList(){let e=await this.readCounters(),t=Math.min(e.manifolds,this.manifoldCapacity),i=Math.min(e.contacts,this.contactCapacity),r=1-this.parity,[o,n]=await Promise.all([this.read(this.manifoldBuffers[r],t*Nt*4),this.read(this.contactBuffers[r],i*Ht*4)]),a=new Uint32Array(o),l=new Float32Array(o),c=new Uint32Array(n),u=new Float32Array(n),f=[];for(let d=0;d<t;d++){let p=d*Nt,m=[...l.subarray(p+Ws,p+Ws+3)];for(let h=a[p+2];h<a[p+2]+(a[p+3]&15);h++){let g=h*Ht,b=c[g+pr+3];f.push({a:a[p],b:a[p+1],feature:(b&~$r)>>>0,stick:(b&$r)!==0,rA:[...u.subarray(g+pr,g+pr+3)],rB:[...u.subarray(g+Hs,g+Hs+3)],pen:[...u.subarray(g+$s,g+$s+3)],lam:[...u.subarray(g+Js,g+Js+3)],normal:m})}}return f}async readPairs(){let{pairs:e}=await this.readCounters();return new Uint32Array(await this.read(this.pairBuffer,Math.min(e,this.pairCapacity)*8))}jointInfo(){return this.info.subarray(0,this.jointCount*4)}adapt(e){if(this.fixedColors)return;let t=e.colors;e.clashes>0&&(this.colorRounds=Math.min(32,this.colorRounds*2)),e.clashes>0||this.colorCap-t<2?(this.colorCap=Math.min(64,Math.max(t+Zs+2,this.colorCap+4)),this.shrinkVotes=0):t+Zs+2<this.colorCap||this.colorRounds>4?++this.shrinkVotes>=3&&(this.colorCap=Math.min(64,t+Zs),this.colorRounds=Math.max(4,this.colorRounds-4),this.shrinkVotes=0):this.shrinkVotes=0;let i=(a,l,c)=>(e.overflow&c)!==0||a>Xu*l?Math.max(Yu*a,1.25*l):l,r=i(e.contacts,this.contactCapacity,2),o=i(e.pairs,this.pairCapacity,1),n=i(e.manifolds,this.manifoldCapacity,4);this.capacityCanGrow(r,o,n)&&this.allocateContacts(r,o,n)}capacityCanGrow(e,t,i){let r=this.device.limits.maxStorageBufferBindingSize;return Math.min(e,r/(Ht*4))>this.contactCapacity||Math.min(t,r/8)>this.pairCapacity||Math.min(i,t,r/(Nt*4))>this.manifoldCapacity}async read(e,t){if(t===0)return new ArrayBuffer(0);let i=this.device.createBuffer({size:t,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),r=this.device.createCommandEncoder();r.copyBufferToBuffer(e,0,i,0,t),this.device.queue.submit([r.finish()]),await i.mapAsync(GPUMapMode.READ);let o=i.getMappedRange().slice(0);return i.unmap(),i.destroy(),o}releaseTiming(){this.timing?.resolve.destroy(),this.timing?.read.destroy(),this.timing?.querySet.destroy()}destroy(){this.ownsBodyBuffer&&this.bodyBuffer.destroy();let e=[this.jointBuffer,this.infoBuffer,...this.contactBuffers,...this.manifoldBuffers,this.pairBuffer,this.tableBuffer,this.gridBuffer,this.staticBuffer,this.counterBuffer,this.argsBuffer,this.adjBuffer,this.colorBuffer,this.paramsBuffer,this.refBuffer,this.hullBuffer,this.passBuffer,this.filterBuffer];for(let t of e)t?.destroy();this.destroyed=!0,this.timingBusy||this.releaseTiming(),this.gridScan.destroy(),this.colorHistScan.destroy(),this.adjScan?.destroy()}};var Tl=` e.C = vec3f(
2422
2422
  k.c0x * keep + dot(n, A.dLin) - dot(n, B.dLin) + dot(cross(e.rAW, n), A.dAng) + dot(cross(e.rBW, -n), B.dAng),
2423
2423
  k.c0y * keep + dot(t1, A.dLin) - dot(t1, B.dLin) + dot(cross(e.rAW, t1), A.dAng) + dot(cross(e.rBW, -t1), B.dAng),
2424
- k.c0z * keep + dot(t2, A.dLin) - dot(t2, B.dLin) + dot(cross(e.rAW, t2), A.dAng) + dot(cross(e.rBW, -t2), B.dAng));`;if(ze.split(rl).length!==2)throw Error("Pinned contact evaluation changed; review the app kernel variant");var Wr=ze.replace(rl,` let delta = A.dLin - B.dLin + cross(A.dAng, e.rAW) - cross(B.dAng, e.rBW);
2425
- e.C = vec3f(k.c0x, k.c0y, k.c0z) * keep + vec3f(dot(n, delta), dot(t1, delta), dot(t2, delta));`);function St(s,e,t){if(s.split(e).length!==2)throw Error("Pinned solve layout changed; review the app kernel variant");return s.replace(e,t)}var Ds=(()=>{let s=St(Wr," var e = adj[i] + lane;",` let begin = adj[i];
2424
+ k.c0z * keep + dot(t2, A.dLin) - dot(t2, B.dLin) + dot(cross(e.rAW, t2), A.dAng) + dot(cross(e.rBW, -t2), B.dAng));`;if(Ge.split(Tl).length!==2)throw Error("Pinned contact evaluation changed; review the app kernel variant");var is=Ge.replace(Tl,` let delta = A.dLin - B.dLin + cross(A.dAng, e.rAW) - cross(B.dAng, e.rBW);
2425
+ e.C = vec3f(k.c0x, k.c0y, k.c0z) * keep + vec3f(dot(n, delta), dot(t1, delta), dot(t2, delta));`);function St(s,e,t){if(s.split(e).length!==2)throw Error("Pinned solve layout changed; review the app kernel variant");return s.replace(e,t)}var to=(()=>{let s=St(is," var e = adj[i] + lane;",` let begin = adj[i];
2426
2426
  var e = begin;`);return s=St(s,` if (c == cEnd) {
2427
2427
  `,` if (c >= cEnd) {
2428
2428
  `),s=St(s,` e += lanes;
@@ -2435,19 +2435,19 @@ fn updateVelocities(@builtin(global_invocation_id) gid: vec3u) {
2435
2435
  if (c >= cEnd) { continue; }
2436
2436
  isA = i == mf.ids.x;`),s=St(s,` c = mf.ids.z;
2437
2437
  cEnd = mf.ids.z + pairCount(mf);
2438
- if (c == cEnd) { continue; }`,""),s=St(s," c++;"," c += lanes;"),s})();function Rn(s=ze){s=St(s,"fn manifoldCount() -> u32 {",`fn solverStepValid() -> bool {
2438
+ if (c == cEnd) { continue; }`,""),s=St(s," c++;"," c += lanes;"),s})();function Kn(s=Ge){s=St(s,"fn manifoldCount() -> u32 {",`fn solverStepValid() -> bool {
2439
2439
  return counters[C_OVERFLOW] == 0u && counters[C_CLASHES] == 0u;
2440
2440
  }
2441
2441
 
2442
2442
 
2443
2443
  fn manifoldCount() -> u32 {`);for(let[e,t]of[["warmStartJoints","global_invocation_id"],["warmStartBodies","global_invocation_id"],["dual","global_invocation_id"],["updateVelocities","global_invocation_id"]]){let i=`fn ${e}(@builtin(${t}) gid: vec3u) {`;s=St(s,i,`${i}
2444
- if (!solverStepValid()) { return; }`)}return St(s," let live = k < count;"," let live = k < count && solverStepValid();")}function On(s){return s=St(s," return qsub(rotA(a), bodies[b].rot) * k.lamAng.w;",` let rest = vec4f(k.c0Lin.w, k.c0Ang.w, k.rA.w, k.rB.w);
2444
+ if (!solverStepValid()) { return; }`)}return St(s," let live = k < count;"," let live = k < count && solverStepValid();")}function Zn(s){return s=St(s," return qsub(rotA(a), bodies[b].rot) * k.lamAng.w;",` let rest = vec4f(k.c0Lin.w, k.c0Ang.w, k.rA.w, k.rB.w);
2445
2445
  var restTarget = rotA(a);
2446
2446
  if (dot(rest, rest) > 0.5) {
2447
2447
  restTarget = vec4f(restTarget.w * rest.xyz + rest.w * restTarget.xyz + cross(restTarget.xyz, rest.xyz),
2448
2448
  restTarget.w * rest.w - dot(restTarget.xyz, rest.xyz));
2449
2449
  }
2450
- return qsub(restTarget, bodies[b].rot) * k.lamAng.w;`),s=St(s,"k.c0Lin = vec4f(jointLinC(k, a, b), 0.0);","k.c0Lin = vec4f(jointLinC(k, a, b), k.c0Lin.w);"),St(s,"k.c0Ang = vec4f(jointAngC(k, a, b), 0.0);","k.c0Ang = vec4f(jointAngC(k, a, b), k.c0Ang.w);")}var sl=`// Capture new constraints from live GPU poses; no stale mesh poses or readback.
2450
+ return qsub(restTarget, bodies[b].rot) * k.lamAng.w;`),s=St(s,"k.c0Lin = vec4f(jointLinC(k, a, b), 0.0);","k.c0Lin = vec4f(jointLinC(k, a, b), k.c0Lin.w);"),St(s,"k.c0Ang = vec4f(jointAngC(k, a, b), 0.0);","k.c0Ang = vec4f(jointAngC(k, a, b), k.c0Ang.w);")}var jl=`// Capture new constraints from live GPU poses; no stale mesh poses or readback.
2451
2451
  struct Body { pos:vec4f,rot:vec4f,initialPos:vec4f,initialRot:vec4f,size:vec4f,moment:vec4f,inertialPos:vec4f,inertialRot:vec4f,velocity:vec4f,angular:vec4f }
2452
2452
  struct Joint { penLin:vec4f,penAng:vec4f,lamLin:vec4f,lamAng:vec4f,c0Lin:vec4f,c0Ang:vec4f,rA:vec4f,rB:vec4f }
2453
2453
  @group(0) @binding(0) var<storage,read> bodies:array<Body>;
@@ -2472,7 +2472,7 @@ fn rotate(q:vec4f,v:vec3f)->vec3f {let t=2.*cross(q.xyz,v);return v+q.w*t+cross(
2472
2472
  joints[slot].rA.w=length(pa-pb);
2473
2473
  }
2474
2474
  }
2475
- `;var ol=`// Conservative GPU sleeping. Resting contacts form supports from the ground
2475
+ `;function hi(s){let e=new ArrayBuffer(s*4);return{f:new Float32Array(e),u:new Uint32Array(e),previous:new Uint32Array(s),buffer:null,uploads:0,bytes:0}}function Qt(s,e,t){let{u:i,previous:r}=t,o=0,n=i.length-1;if(t.buffer===e){for(;o<=n&&i[o]===r[o];)o++;for(;n>=o&&i[n]===r[n];)n--;if(o>n)return}s.queue.writeBuffer(e,o*4,i,o,n-o+1),r.set(i),t.buffer=e,t.uploads++,t.bytes+=(n-o+1)*4}var Dl=`// Conservative GPU sleeping. Resting contacts form supports from the ground
2476
2476
  // upward. Any impact, moving joint endpoint or explicit edit wakes the world.
2477
2477
  // This deliberately favors reliable waking over finely partitioned islands.
2478
2478
  struct Body { pos:vec4f,rot:vec4f,initialPos:vec4f,initialRot:vec4f,size:vec4f,moment:vec4f,inertialPos:vec4f,inertialRot:vec4f,velocity:vec4f,angular:vec4f }
@@ -2522,13 +2522,131 @@ fn impact(a:u32,b:u32) {
2522
2522
  }
2523
2523
  if(states[i].asleep!=0u){atomicAdd(&globals[1],1u);}
2524
2524
  }
2525
- `;var Tn=class{constructor(e){this.device=e,this.targets=new Map,this.bits=new Float32Array(1),this.words=new Uint32Array(this.bits.buffer)}target(e){let t=this.targets.get(e);return t||this.targets.set(e,t={pending:new Map}),t}uint(e,t,i){this.target(e).pending.set(t,i>>>0)}float(e,t,i){this.bits[0]=i,this.uint(e,t,this.words[0])}get pending(){for(let e of this.targets.values())if(e.pending.size)return!0;return!1}flush(e){let t=this.device,i=e,r=0,o=0,n=0,a=0;for(let[l,c]of this.targets){let u=c.pending.size;if(!u)continue;(!c.data||c.data.length<u*2)&&(c.data=new Uint32Array(Math.max(u*2,(c.data?.length??0)*2,128)));let f=Array.from(c.pending.keys()),d=!0;for(let g=1;g<u;g++)if(f[g]<f[g-1]){d=!1;break}d||f.sort((g,h)=>g-h);let p=1;for(let g=1;g<u;g++)f[g]!==f[g-1]+1&&p++;if(p<=4||u<=8){for(let g=0;g<u;g++)c.data[g]=c.pending.get(f[g]);for(let g=0;g<u;){let h=g+1;for(;h<u&&f[h]===f[h-1]+1;)h++;t.queue.writeBuffer(l,f[g]*4,c.data.buffer,g*4,(h-g)*4),r++,g=h}a+=u*4}else{let g=u*8,h=Math.min(t.limits.maxBufferSize,t.limits.maxStorageBufferBindingSize);if(g>h)throw Error("Property batch exceeds GPU buffer limits");for(let w=0;w<u;w++)c.data[w*2]=f[w],c.data[w*2+1]=c.pending.get(f[w]);(!c.upload||c.upload.size<g)&&(c.upload?.destroy(),c.upload=t.createBuffer({size:Math.min(h,g*2),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),c.group=null),t.queue.writeBuffer(c.upload,0,c.data.buffer,0,g),this.pipeline??=t.createComputePipeline({layout:"auto",compute:{entryPoint:"applyEdits",module:t.createShaderModule({code:`
2525
+ `;var Gl=`struct Body { pos:vec4f,rot:vec4f,initialPos:vec4f,initialRot:vec4f,size:vec4f,moment:vec4f,inertialPos:vec4f,inertialRot:vec4f,velocity:vec4f,angular:vec4f }\r
2526
+ struct State { mass:f32, quiet:f32, asleep:u32, support:atomic<u32>, eligible:u32, parent:atomic<u32>, wake:atomic<u32>, pad2:u32 }\r
2527
+ struct Manifold { ids:vec4u, geo:vec4f }\r
2528
+ struct Params { count:u32,joints:u32,manifolds:u32,forceWake:u32,speed:f32,delay:f32,dt:f32,gravity:f32,up:vec4f }\r
2529
+ @group(0) @binding(0) var<storage,read_write> bodies:array<Body>;\r
2530
+ @group(0) @binding(1) var<storage,read_write> states:array<State>;\r
2531
+ @group(0) @binding(2) var<storage,read> info:array<vec4i>;\r
2532
+ @group(0) @binding(3) var<storage,read> manifolds:array<Manifold>;\r
2533
+ @group(0) @binding(4) var<storage,read> counters:array<u32>;\r
2534
+ @group(0) @binding(5) var<storage,read_write> globals:array<atomic<u32>>;\r
2535
+ @group(0) @binding(6) var<uniform> params:Params;\r
2536
+ fn speed(i:u32)->f32 {return length(bodies[i].velocity.xyz)+length(bodies[i].angular.xyz)*bodies[i].moment.w;}\r
2537
+ fn wake(i:u32) {if(states[i].mass>0.){bodies[i].size.w=states[i].mass;states[i].asleep=0u;states[i].quiet=0.;}}\r
2538
+ @compute @workgroup_size(64) fn before(@builtin(global_invocation_id) id:vec3u) {\r
2539
+ let i=id.x;if(i>=params.count){return;}\r
2540
+ if(params.forceWake!=0u||atomicLoad(&globals[0])!=0u){wake(i);atomicStore(&states[i].parent,i);}\r
2541
+ atomicStore(&states[i].wake,0u);\r
2542
+ atomicStore(&states[i].support,0u);\r
2543
+ }\r
2544
+ @compute @workgroup_size(1) fn clear() {atomicStore(&globals[0],0u);atomicStore(&globals[1],0u);}\r
2545
+ fn impact(a:u32,b:u32) {\r
2546
+ if(states[a].asleep!=0u && states[b].asleep==0u && speed(b)>2.*params.speed){let r=root(a);if(r<params.count){atomicStore(&states[r].wake,1u);}else{atomicStore(&globals[0],1u);}}\r
2547
+ }\r
2548
+ @compute @workgroup_size(64) fn contacts(@builtin(global_invocation_id) id:vec3u) {\r
2549
+ let i=id.x;if(i>=min(counters[6],params.manifolds)){return;}\r
2550
+ let m=manifolds[i];if((m.ids.w&15u)==0u || (m.ids.w&0x80000000u)!=0u){return;}\r
2551
+ let a=m.ids.x;let b=m.ids.y;impact(a,b);impact(b,a);\r
2552
+ let up=dot(m.geo.xyz,params.up.xyz);\r
2553
+ if(bodies[b].size.w==0. && up>0.3){atomicStore(&states[a].support,1u);}\r
2554
+ if(bodies[a].size.w==0. && up < -0.3){atomicStore(&states[b].support,1u);}\r
2555
+ }\r
2556
+ @compute @workgroup_size(64) fn joints(@builtin(global_invocation_id) id:vec3u) {\r
2557
+ let i=id.x;if(i>=params.joints){return;}let j=info[i];if(j.x==0||j.y<0){return;}\r
2558
+ impact(u32(j.y),u32(j.z));impact(u32(j.z),u32(j.y));\r
2559
+ }\r
2560
+ @compute @workgroup_size(64) fn rest(@builtin(global_invocation_id) id:vec3u) {\r
2561
+ let i=id.x;if(i>=params.count||states[i].mass<=0.){return;}\r
2562
+ if(states[i].eligible==0u){wake(i);return;}\r
2563
+ let r=root(i);\r
2564
+ if(r>=params.count || atomicLoad(&states[min(r,params.count-1u)].wake)!=0u || atomicLoad(&globals[0])!=0u || counters[3]!=0u || counters[4]!=0u){wake(i);return;}\r
2565
+ if(states[i].asleep==0u){\r
2566
+ if(speed(i)<=params.speed && (params.gravity==0. || atomicLoad(&states[i].support)!=0u)) {states[i].quiet+=params.dt;}\r
2567
+ else {states[i].quiet=0.;}\r
2568
+ if(states[i].quiet>=params.delay){\r
2569
+ states[i].asleep=1u;bodies[i].size.w=0.;bodies[i].velocity=vec4f(0.);bodies[i].angular=vec4f(vec3f(0.),bodies[i].angular.w);\r
2570
+ }\r
2571
+ }\r
2572
+ if(states[i].asleep!=0u){atomicAdd(&globals[1],1u);}\r
2573
+ }\r
2574
+ \r
2575
+ // Dynamic connectivity is conservative: unions persist while asleep because\r
2576
+ // collision detection intentionally omits pairs of sleeping bodies. Explicit\r
2577
+ // edits wake the world and reset this history. Shared static ground never joins\r
2578
+ // otherwise independent piles. No thread waits for another workgroup.\r
2579
+ fn root(index:u32)->u32 {\r
2580
+ var i=index;\r
2581
+ for(var attempt=0u;attempt<256u;attempt++) {\r
2582
+ if(i>=params.count){atomicStore(&globals[0],1u);return params.count;}\r
2583
+ let p=atomicLoad(&states[i].parent);\r
2584
+ if(p==i){return i;}\r
2585
+ if(p>i){atomicStore(&globals[0],1u);return params.count;}\r
2586
+ let gp=atomicLoad(&states[p].parent);\r
2587
+ atomicMin(&states[i].parent,gp);\r
2588
+ i=gp;\r
2589
+ }\r
2590
+ // Excessive depth is a safe wake-all fallback, never a cross-group wait.\r
2591
+ atomicStore(&globals[0],1u);return params.count;\r
2592
+ }\r
2593
+ fn connect(a:u32,b:u32) {\r
2594
+ if(a>=params.count || b>=params.count || states[a].mass<=0. || states[b].mass<=0.){return;}\r
2595
+ for(var attempt=0u;attempt<256u;attempt++) {\r
2596
+ let ra=root(a);let rb=root(b);\r
2597
+ if(ra==rb || ra>=params.count || rb>=params.count){return;}\r
2598
+ let hi=max(ra,rb);let lo=min(ra,rb);\r
2599
+ let result=atomicCompareExchangeWeak(&states[hi].parent,hi,lo);\r
2600
+ if(result.exchanged){return;}\r
2601
+ }\r
2602
+ atomicStore(&globals[0],1u);\r
2603
+ }\r
2604
+ @compute @workgroup_size(64) fn connectContacts(@builtin(global_invocation_id) id:vec3u){\r
2605
+ let i=id.x;if(i>=min(counters[6],params.manifolds)){return;}\r
2606
+ let m=manifolds[i];if((m.ids.w&15u)==0u || (m.ids.w&0x80000000u)!=0u){return;}\r
2607
+ connect(m.ids.x,m.ids.y);\r
2608
+ }\r
2609
+ @compute @workgroup_size(64) fn connectJoints(@builtin(global_invocation_id) id:vec3u){\r
2610
+ let i=id.x;if(i>=params.joints){return;}let j=info[i];\r
2611
+ if(j.x!=0 && j.y>=0 && j.z>=0){connect(u32(j.y),u32(j.z));}\r
2612
+ }\r
2613
+ `;var ea=class{constructor(e){this.device=e,this.targets=new Map,this.bits=new Float32Array(1),this.words=new Uint32Array(this.bits.buffer)}target(e){let t=this.targets.get(e);return t||this.targets.set(e,t={pending:new Map}),t}uint(e,t,i){this.target(e).pending.set(t,i>>>0)}float(e,t,i){this.bits[0]=i,this.uint(e,t,this.words[0])}get pending(){for(let e of this.targets.values())if(e.pending.size)return!0;return!1}flush(e){let t=this.device,i=e,r=0,o=0,n=0,a=0;for(let[l,c]of this.targets){let u=c.pending.size;if(!u)continue;(!c.data||c.data.length<u*2)&&(c.data=new Uint32Array(Math.max(u*2,(c.data?.length??0)*2,128)));let f=Array.from(c.pending.keys()),d=!0;for(let m=1;m<u;m++)if(f[m]<f[m-1]){d=!1;break}d||f.sort((m,h)=>m-h);let p=1;for(let m=1;m<u;m++)f[m]!==f[m-1]+1&&p++;if(p<=4||u<=8){for(let m=0;m<u;m++)c.data[m]=c.pending.get(f[m]);for(let m=0;m<u;){let h=m+1;for(;h<u&&f[h]===f[h-1]+1;)h++;t.queue.writeBuffer(l,f[m]*4,c.data.buffer,m*4,(h-m)*4),r++,m=h}a+=u*4}else{let m=u*8,h=Math.min(t.limits.maxBufferSize,t.limits.maxStorageBufferBindingSize);if(m>h)throw Error("Property batch exceeds GPU buffer limits");for(let A=0;A<u;A++)c.data[A*2]=f[A],c.data[A*2+1]=c.pending.get(f[A]);(!c.upload||c.upload.size<m)&&(c.upload?.destroy(),c.upload=t.createBuffer({size:Math.min(h,m*2),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),c.group=null),t.queue.writeBuffer(c.upload,0,c.data.buffer,0,m),this.pipeline??=t.createComputePipeline({layout:"auto",compute:{entryPoint:"applyEdits",module:t.createShaderModule({code:`
2526
2614
  @group(0) @binding(0) var<storage,read_write> outputWords:array<u32>;
2527
2615
  @group(0) @binding(1) var<storage,read> edits:array<vec2u>;
2528
2616
  @compute @workgroup_size(64) fn applyEdits(@builtin(global_invocation_id) id:vec3u){
2529
2617
  let i=id.x+id.y*${t.limits.maxComputeWorkgroupsPerDimension*64}u;
2530
2618
  if(i>=arrayLength(&edits)){return;}let edit=edits[i];outputWords[edit.x]=edit.y;
2531
- }`})}}),(!c.group||c.bytes!==g)&&(c.group=t.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:l}},{binding:1,resource:{buffer:c.upload,size:g}}]}),c.bytes=g),i??=t.createCommandEncoder({label:"AVBD property edits"});let m=i.beginComputePass();m.setPipeline(this.pipeline),m.setBindGroup(0,c.group);let b=Math.ceil(u/64),v=t.limits.maxComputeWorkgroupsPerDimension;m.dispatchWorkgroups(Math.min(b,v),Math.ceil(b/v)),m.end(),r++,o++,a+=g}n+=u,c.pending.clear()}!e&&i&&t.queue.submit([i.finish()]),n&&(this.lastBatch={words:n,writes:r,dispatches:o,uploadedBytes:a,submissions:!e&&i?1:0})}destroy(){for(let e of this.targets.values())e.upload?.destroy();this.targets.clear()}forget(e){this.targets.get(e)?.upload?.destroy(),this.targets.delete(e)}};function le(s){return s.propertyEdits??=new Tn(s.device)}var Fi=class{constructor(e,t={}){if(this.world=e,this.device=e.device,this.speed=t.speedThreshold??.03,this.delay=t.timeThreshold??.5,!Number.isFinite(this.speed)||this.speed<=0||!Number.isFinite(this.delay)||this.delay<=0)throw Error("Sleep speedThreshold and timeThreshold must be positive and finite");let i=this.device,r=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC;this.state=i.createBuffer({size:e.capacity*32,usage:r}),this.globals=i.createBuffer({size:8,usage:r}),this.params=i.createBuffer({size:48,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let o=i.createShaderModule({code:ol});this.layout=i.createBindGroupLayout({entries:["storage","storage","read-only-storage","read-only-storage","read-only-storage","storage","uniform"].map((c,u)=>({binding:u,visibility:GPUShaderStage.COMPUTE,buffer:{type:c}}))});let n=i.createPipelineLayout({bindGroupLayouts:[this.layout]});this.pipelines=Object.fromEntries(["before","clear","contacts","joints","rest"].map(c=>[c,i.createComputePipeline({layout:n,compute:{module:o,entryPoint:c}})]));let a=new Float32Array(e.capacity*8),l=new Uint32Array(a.buffer);for(let c of e.aggregates)if(!c.disposed){let u=(c.gpuSlot??e.gpu.gpuIndex(c.index))*8;a[u]=c.rigid.mass,l[u+4]=c.allowSleep===!1||c.rigid.allowSleep===!1?0:1}i.queue.writeBuffer(this.state,0,a),this.wakeRequested=!1}register(e,t,i=!0){let r=new Float32Array([t,0,0,0,0,0,0,0]);new Uint32Array(r.buffer)[4]=i?1:0;let o=new Uint32Array(r.buffer),n=le(this.world.gpu);for(let a=0;a<8;a++)n.uint(this.state,e*8+a,o[a]);this.wakeRequested=!0}bindContacts(){let e=this.world.gpu,t=e.contactStorage,i=[e.bodyBuffer,this.state,e.infoBuffer,t.manifolds,t.counters,this.globals,this.params],r=this.groups?.find(o=>o.buffers.every((n,a)=>n===i[a]));r||(r={buffers:i,group:this.device.createBindGroup({layout:this.layout,entries:i.map((o,n)=>({binding:n,resource:{buffer:o}}))})},this.groups=[...(this.groups??[]).slice(-1),r]),this.group=r.group}before(e){this.world.gpu.flushPropertyEdits(e);let{gpu:t}=this.world,i=t.contactStorage,r=new ArrayBuffer(48),o=new Uint32Array(r),n=new Float32Array(r);o.set([t.bodyCount,t.jointCount,t.manifoldCapacity,this.wakeRequested?1:0]),n.set([this.speed,this.delay,t.params.dt,t.params.gravity],4),n.set(t.params.up,8),this.device.queue.writeBuffer(this.params,0,r),this.wakeRequested=!1,this.bindContacts(),this.run([["before",t.bodyCount],["clear",1]],e)}after(e){let t=this.world.gpu,i=t.contactStorage;this.bindContacts(),this.run([["contacts",t.manifoldCapacity],["joints",t.jointCount],["rest",t.bodyCount]],e)}run(e,t){let i=t??this.device.createCommandEncoder(),r=i.beginComputePass();r.setBindGroup(0,this.group);for(let[o,n]of e)n&&(r.setPipeline(this.pipelines[o]),r.dispatchWorkgroups(o==="clear"?1:Math.ceil(n/64)));r.end(),t||this.device.queue.submit([i.finish()])}async readStats(){let e=this.device,t=e.createBuffer({size:8,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ});try{let i=e.createCommandEncoder();i.copyBufferToBuffer(this.globals,0,t,0,8),e.queue.submit([i.finish()]),await t.mapAsync(GPUMapMode.READ);let r=new Uint32Array(t.getMappedRange());return{sleeping:r[1],wakeRequested:!!r[0]}}finally{t.destroy()}}dispose(){this.world.gpu.propertyEdits?.forget(this.state),this.state.destroy(),this.globals.destroy(),this.params.destroy()}};var jn=new WeakMap;function It(s={}){let e={};for(let t of["breakStrain","breakForce"]){let i=s[t]??1/0;if(i!==1/0&&(!Number.isFinite(i)||i<=0))throw Error(`${t} must be positive or Infinity`);e[t]=i}return e}function gr(s,e){let t=It(e);Number.isFinite(t.breakStrain)||Number.isFinite(t.breakForce)?jn.set(s,t):jn.delete(s)}var Gi=s=>jn.get(s);function Fs(s){let e="fn dualJoint(j: u32) {";if(s.split(e).length!==2)throw Error("Review spring fracture kernel integration");return s.replace(e,`${e}
2619
+ }`})}}),(!c.group||c.bytes!==m)&&(c.group=t.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:l}},{binding:1,resource:{buffer:c.upload,size:m}}]}),c.bytes=m),i??=t.createCommandEncoder({label:"AVBD property edits"});let g=i.beginComputePass();g.setPipeline(this.pipeline),g.setBindGroup(0,c.group);let b=Math.ceil(u/64),y=t.limits.maxComputeWorkgroupsPerDimension;g.dispatchWorkgroups(Math.min(b,y),Math.ceil(b/y)),g.end(),r++,o++,a+=m}n+=u,c.pending.clear()}!e&&i&&t.queue.submit([i.finish()]),n&&(this.lastBatch={words:n,writes:r,dispatches:o,uploadedBytes:a,submissions:!e&&i?1:0})}destroy(){for(let e of this.targets.values())e.upload?.destroy();this.targets.clear()}forget(e){this.targets.get(e)?.upload?.destroy(),this.targets.delete(e)}};function le(s){return s.propertyEdits??=new ea(s.device)}var Fi=class{constructor(e,t={}){if(this.world=e,this.device=e.device,this.speed=t.speedThreshold??.03,this.delay=t.timeThreshold??.5,t.islands!==void 0&&typeof t.islands!="boolean")throw Error("Sleep islands must be a boolean");if(this.islands=t.islands??(e.gpu.bodyCount>=4096&&e.gpu.jointCount===0&&!e.gpu.portableContactMath&&!e.gpu.dispatchIsolation),!Number.isFinite(this.speed)||this.speed<=0||!Number.isFinite(this.delay)||this.delay<=0)throw Error("Sleep speedThreshold and timeThreshold must be positive and finite");let i=this.device,r=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC;this.state=i.createBuffer({size:e.capacity*32,usage:r}),this.globals=i.createBuffer({size:8,usage:r}),this.params=i.createBuffer({size:48,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let o=i.createShaderModule({code:this.islands?Gl:Dl});this.layout=i.createBindGroupLayout({entries:["storage","storage","read-only-storage","read-only-storage","read-only-storage","storage","uniform"].map((c,u)=>({binding:u,visibility:GPUShaderStage.COMPUTE,buffer:{type:c}}))});let n=i.createPipelineLayout({bindGroupLayouts:[this.layout]});this.pipelines=Object.fromEntries(["before","clear",...this.islands?["connectContacts","connectJoints"]:[],"contacts","joints","rest"].map(c=>[c,i.createComputePipeline({layout:n,compute:{module:o,entryPoint:c}})]));let a=new Float32Array(e.capacity*8),l=new Uint32Array(a.buffer);for(let c of e.aggregates)if(!c.disposed){let u=(c.gpuSlot??e.gpu.gpuIndex(c.index))*8;a[u]=c.rigid.mass,l[u+4]=c.allowSleep===!1||c.rigid.allowSleep===!1?0:1,this.islands&&(l[u+5]=u/8)}i.queue.writeBuffer(this.state,0,a),this.wakeRequested=!1}register(e,t,i=!0){let r=new Float32Array([t,0,0,0,0,0,0,0]);new Uint32Array(r.buffer)[4]=i?1:0,this.islands&&(new Uint32Array(r.buffer)[5]=e);let o=new Uint32Array(r.buffer),n=le(this.world.gpu);for(let a=0;a<8;a++)n.uint(this.state,e*8+a,o[a]);this.wakeRequested=!0}bindContacts(){let e=this.world.gpu,t=e.contactStorage,i=[e.bodyBuffer,this.state,e.infoBuffer,t.manifolds,t.counters,this.globals,this.params],r=this.groups?.find(o=>o.buffers.every((n,a)=>n===i[a]));r||(r={buffers:i,group:this.device.createBindGroup({layout:this.layout,entries:i.map((o,n)=>({binding:n,resource:{buffer:o}}))})},this.groups=[...(this.groups??[]).slice(-1),r]),this.group=r.group}before(e){this.world.gpu.flushPropertyEdits(e);let{gpu:t}=this.world,i=this.paramData??=hi(12),{u:r,f:o}=i;r[0]=t.bodyCount,r[1]=t.jointCount,r[2]=t.manifoldCapacity,r[3]=Number(this.wakeRequested),o[4]=this.speed,o[5]=this.delay,o[6]=t.params.dt,o[7]=t.params.gravity,o[8]=t.params.up[0],o[9]=t.params.up[1],o[10]=t.params.up[2],Qt(this.device,this.params,i),this.wakeRequested=!1,this.bindContacts(),this.run([["before",t.bodyCount],["clear",1]],e)}after(e){let t=this.world.gpu;this.bindContacts(),this.run([...this.islands?[["connectContacts",t.manifoldCapacity],["connectJoints",t.jointCount]]:[],["contacts",t.manifoldCapacity],["joints",t.jointCount],["rest",t.bodyCount]],e)}run(e,t){let i=t??this.device.createCommandEncoder(),r=i.beginComputePass();r.setBindGroup(0,this.group);for(let[o,n]of e)n&&(r.setPipeline(this.pipelines[o]),r.dispatchWorkgroups(o==="clear"?1:Math.ceil(n/64)));r.end(),t||this.device.queue.submit([i.finish()])}async readStats(){let e=this.device,t=e.createBuffer({size:8,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ});try{let i=e.createCommandEncoder();i.copyBufferToBuffer(this.globals,0,t,0,8),e.queue.submit([i.finish()]),await t.mapAsync(GPUMapMode.READ);let r=new Uint32Array(t.getMappedRange());return{sleeping:r[1],wakeRequested:!!r[0]}}finally{t.destroy()}}dispose(){this.world.gpu.propertyEdits?.forget(this.state),this.state.destroy(),this.globals.destroy(),this.params.destroy()}};function nf(s){s=s.replaceAll("bodies[","localBodies["),s=s.replace("var<storage, read_write> bodies: array<Body>;","var<storage, read_write> globalBodies: array<Body>;");let e=s.indexOf(`@compute @workgroup_size(64)
2620
+ fn primal(`),t=s.indexOf(`
2621
+ /**`,e);if(e<0||t<e)throw Error("Review small-group primal integration");let i=s.slice(e,t).replace(`@compute @workgroup_size(64)
2622
+ `,"").replace("fn primal(@builtin(local_invocation_id) lid: vec3u, @builtin(workgroup_id) wid: vec3u)","fn localPrimal(lid: vec3u, wid: vec3u, col: u32)").replaceAll("pc.color","col");return s.slice(0,e)+i+s.slice(t)+`
2623
+ var<workgroup> localBodies: array<Body,32>;
2624
+ var<workgroup> bucketBlocks: u32;
2625
+ @compute @workgroup_size(64)
2626
+ fn smallGroup(@builtin(local_invocation_id) lid: vec3u) {
2627
+ if(lid.x<params.bodyCount){localBodies[lid.x]=globalBodies[lid.x];}
2628
+ workgroupBarrier();
2629
+ for(var it=0u;it<pc.pad0;it++) {
2630
+ for(var col=0u;col<params.colorCap;col++) {
2631
+ if(lid.x==0u){
2632
+ let start=color[params.colorStartOffset+col];
2633
+ let count=color[params.colorStartOffset+col+1u]-start;
2634
+ let perBlock=64u/lanesFor(count);
2635
+ bucketBlocks=(count+perBlock-1u)/perBlock;
2636
+ }
2637
+ let blocks=workgroupUniformLoad(&bucketBlocks);
2638
+ for(var block=0u;block<blocks;block++) {
2639
+ localPrimal(lid,vec3u(block,0u,0u),col);
2640
+ workgroupBarrier();
2641
+ }
2642
+ }
2643
+ for(var m=lid.x;m<manifoldCount();m+=64u){dualManifold(m);}
2644
+ storageBarrier();
2645
+ workgroupBarrier();
2646
+ }
2647
+ if(lid.x<params.bodyCount){globalBodies[lid.x]=localBodies[lid.x];}
2648
+ }
2649
+ `}function Fl(s){if(!(s.smallGroups!==!1&&s.bodyCount>0&&s.bodyCount<=32&&s.jointCount===0&&s.solverDecision.selected==="standard"&&!s.scalarPrimal&&!s.portableContactMath&&!s.dispatchIsolation)){s.smallGroupPipeline=null;return}let t=`${s.sensorsEnabled?1:0}`;if(s.smallGroupPipelines??=new Map,!s.smallGroupPipelines.has(t)){let i=nf(s.solveSource(Ge,"standard"));s.smallGroupPipelines.set(t,s.device.createComputePipeline({label:"AVBD closed small group",layout:s.device.createPipelineLayout({bindGroupLayouts:[s.layouts.solve,s.layouts.pass]}),compute:{module:s.device.createShaderModule({code:i}),entryPoint:"smallGroup"}}))}s.smallGroupPipeline=s.smallGroupPipelines.get(t)}var ta=new WeakMap;function It(s={}){let e={};for(let t of["breakStrain","breakForce"]){let i=s[t]??1/0;if(i!==1/0&&(!Number.isFinite(i)||i<=0))throw Error(`${t} must be positive or Infinity`);e[t]=i}return e}function vr(s,e){let t=It(e);Number.isFinite(t.breakStrain)||Number.isFinite(t.breakForce)?ta.set(s,t):ta.delete(s)}var Ui=s=>ta.get(s);function io(s){let e="fn dualJoint(j: u32) {";if(s.split(e).length!==2)throw Error("Review spring fracture kernel integration");return s.replace(e,`${e}
2532
2650
  if (info[j].x == T_SPRING) {
2533
2651
  var material = joints[j];
2534
2652
  let strainLimit = material.lamLin.w;
@@ -2550,7 +2668,7 @@ fn impact(a:u32,b:u32) {
2550
2668
  }
2551
2669
  }
2552
2670
  }
2553
- `)}var uu=["auto","standard","optimized","points"];function br({requested:s="auto",bodyCount:e,constraintCount:t=0,contactScheduling:i="manifolds",custom:r=!1}){if(!uu.includes(s))throw Error("solverMode must be 'auto', 'standard', 'optimized' or 'points'");if(!["manifolds","points"].includes(i))throw Error("contactScheduling must be 'manifolds' or 'points'");if(r&&s!=="auto")throw Error("A scene-specific solve shader cannot be replaced with a rigid-body solver mode");let o=r?"custom":s!=="auto"?s:t>0||e<5e4?"standard":i==="points"?"points":"optimized",n=r?"This scene supplies its own solver. Automatic keeps that implementation.":s!=="auto"?"Explicit implementation override (developer setting).":t>0?"Work layout selected for joints and springs.":e<5e4?"Work layout selected for smaller rigid scenes.":o==="points"?"Large rigid scene with a measured shared-contact-points layout.":"Work layout selected for large rigid scenes.";return{requested:s,selected:o,reason:n,bodyCount:e,constraintCount:t}}var Gs=`// Portable hierarchical PLOC: Morton ordering and independent SAH treelets.
2671
+ `)}var af=["auto","standard","optimized","points"];function xr({requested:s="auto",bodyCount:e,constraintCount:t=0,contactScheduling:i="manifolds",custom:r=!1}){if(!af.includes(s))throw Error("solverMode must be 'auto', 'standard', 'optimized' or 'points'");if(!["manifolds","points"].includes(i))throw Error("contactScheduling must be 'manifolds' or 'points'");if(r&&s!=="auto")throw Error("A scene-specific solve shader cannot be replaced with a rigid-body solver mode");let o=r?"custom":s!=="auto"?s:t>0||e<5e4?"standard":i==="points"?"points":"optimized",n=r?"This scene supplies its own solver. Automatic keeps that implementation.":s!=="auto"?"Explicit implementation override (developer setting).":t>0?"Work layout selected for joints and springs.":e<5e4?"Work layout selected for smaller rigid scenes.":o==="points"?"Large rigid scene with a measured shared-contact-points layout.":"Work layout selected for large rigid scenes.";return{requested:s,selected:o,reason:n,bodyCount:e,constraintCount:t}}var ro=`// Portable hierarchical PLOC: Morton ordering and independent SAH treelets.
2554
2672
  // Dispatch boundaries publish each hierarchy level; no cross-workgroup spin waits.
2555
2673
  struct Node {
2556
2674
  lo: vec3f,
@@ -2593,6 +2711,17 @@ fn bodyHalf(i: u32) -> vec3f {
2593
2711
  + abs(qrotate(b.rot, vec3f(0, 0, 1))) * h.z;
2594
2712
  }
2595
2713
 
2714
+ // Refit only consumes leaf bounds. Scene bounds and their workgroup reductions
2715
+ // are needed when Morton ordering is rebuilt, not on intervening steps.
2716
+ @compute @workgroup_size(128)
2717
+ fn refitLeaves(@builtin(global_invocation_id) gid: vec3u) {
2718
+ let i = gid.x;
2719
+ if (i >= build.count) { return; }
2720
+ let h = bodyHalf(i);
2721
+ let p = inputBodies[i].pos.xyz;
2722
+ nodes[i] = Node(p - h, i, p + h, END);
2723
+ }
2724
+
2596
2725
  @compute @workgroup_size(128)
2597
2726
  fn leaves(
2598
2727
  @builtin(global_invocation_id) gid: vec3u,
@@ -2806,8 +2935,8 @@ fn ropes(@builtin(global_invocation_id) gid: vec3u) {
2806
2935
  at = p;
2807
2936
  }
2808
2937
  links[build.escapeOffset + id] = escape;
2809
- }\r
2810
- `;var nl=`// Stable 4-bit GPU radix sort; PrefixScan scans digit-major block counts.
2938
+ }
2939
+ `;var Ul=`// Stable 4-bit GPU radix sort; PrefixScan scans digit-major block counts.
2811
2940
  struct SortSettings { count: u32, blocks: u32, shift: u32, _pad: u32 }
2812
2941
  @group(0) @binding(0) var<uniform> sort: SortSettings;
2813
2942
  @group(0) @binding(1) var<storage, read> input: array<vec2u>;
@@ -2855,15 +2984,16 @@ fn scatterDigits(
2855
2984
  }
2856
2985
  output[hist[digit * sort.blocks + wid.x] + rank] = value;
2857
2986
  }\r
2858
- `;var hu=()=>GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC,Rt=(s,e=128)=>Math.max(1,Math.ceil(s/e)),pu=4294967295,Dn=ui.indexOf(`@compute @workgroup_size(64)
2859
- fn gridCount`),Fn=ui.indexOf("/** Binary search"),al=ui.indexOf(`@compute @workgroup_size(64)
2860
- fn findPairs`);if(Dn<0||Fn<Dn||al<Fn)throw Error("Pinned broadphase changed; review H-PLOC integration");var mu=Gs.slice(0,Gs.indexOf("@group(0)")),gu=(ui.slice(0,Dn)+ui.slice(Fn,al)).replace("var<storage, read_write> grid: array<atomic<u32>>;","var<storage, read_write> tree: array<Node>;")+`
2861
- ${mu}
2987
+ `;var uf=()=>GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC,Rt=(s,e=128)=>Math.max(1,Math.ceil(s/e)),ff=4294967295,ia=fi.indexOf(`@compute @workgroup_size(64)
2988
+ fn gridCount`),ra=fi.indexOf("/** Binary search"),Nl=fi.indexOf(`@compute @workgroup_size(64)
2989
+ fn findPairs`);if(ia<0||ra<ia||Nl<ra)throw Error("Pinned broadphase changed; review H-PLOC integration");var df=ro.slice(0,ro.indexOf("@group(0)")),hf=(fi.slice(0,ia)+fi.slice(ra,Nl)).replace("var<storage, read_write> grid: array<atomic<u32>>;","var<storage, read_write> tree: array<Node>;")+`
2990
+ ${df}
2862
2991
  @group(1) @binding(0) var<uniform> build: BuildSettings;
2863
2992
  @group(1) @binding(1) var<storage,read> links: array<u32>;
2864
2993
  @compute @workgroup_size(64)
2865
2994
  fn findTreePairs(@builtin(global_invocation_id) gid:vec3u) {
2866
2995
  let i=gid.x; if(i>=params.bodyCount || build.root==0xffffffffu){return;}
2996
+ let collisionFilter=filters[i];if(collisionFilter.x==0u || collisionFilter.y==0u){return;}
2867
2997
  let P=probeOf(i);
2868
2998
  // Static/kinematic leaves are found from dynamic queries. Traversing a
2869
2999
  // scene-wide ground slab would otherwise serialize an entire tree in one lane.
@@ -2880,11 +3010,52 @@ fn findTreePairs(@builtin(global_invocation_id) gid:vec3u) {
2880
3010
  at=links[build.escapeOffset+at];
2881
3011
  } else {at=node.left;}
2882
3012
  }
2883
- }`,Ns=class{constructor(e,t,{rebuildInterval:i=64}={}){if(!Number.isInteger(i)||i<1)throw Error("BVH rebuildInterval must be a positive integer");if(this.device=e,this.capacity=t.bodyCapacity,this.capacity>16*e.limits.maxComputeWorkgroupsPerDimension)throw Error("H-PLOC capacity exceeds the adapter dispatch limit; select the grid");this.bodyBuffer=t.bodyBuffer,this.rebuildInterval=i,this.nodeCapacity=2*this.capacity+16*Math.ceil(Math.log2(Math.max(2,this.capacity)))+32,this.buffers=[],this.uniforms=[],this.stats={builds:0,refits:0,nodes:0,extraBytes:0};let r=(u,f,d=hu())=>{if(d&GPUBufferUsage.STORAGE&&f>e.limits.maxStorageBufferBindingSize)throw Error(`${u} exceeds the adapter storage binding limit`);let p=e.createBuffer({label:u,size:Math.max(16,f),usage:d});return this.buffers.push(p),this.stats.extraBytes+=p.size,p};this.nodes=r("H-PLOC nodes",this.nodeCapacity*32),this.links=r("H-PLOC parents and escape links",this.nodeCapacity*8),this.keys=[r("Morton keys A",this.capacity*8),r("Morton keys B",this.capacity*8)],this.clusters=r("H-PLOC level roots",this.capacity*8+128),this.bounds=r("H-PLOC scene bounds",(Rt(this.capacity)*2+256)*16),this.sortBlocks=Rt(this.capacity),this.hist=r("Morton radix counts",this.sortBlocks*16*4),this.scan=new tt(e,this.hist,0,this.sortBlocks*16);let o=(u,f)=>({binding:u,visibility:GPUShaderStage.COMPUTE,buffer:{type:f}});this.layout=e.createBindGroupLayout({entries:[o(0,"uniform"),o(1,"read-only-storage"),...Array.from({length:5},(u,f)=>o(f+2,"storage"))]}),this.extraLayout=e.createBindGroupLayout({entries:[o(0,"uniform"),o(1,"read-only-storage")]});let n=e.createShaderModule({label:"portable H-PLOC",code:Ae+Gs+`
3013
+ }`,so=class{constructor(e,t,{rebuildInterval:i=64}={}){if(!Number.isInteger(i)||i<1)throw Error("BVH rebuildInterval must be a positive integer");if(this.device=e,this.capacity=t.bodyCapacity,this.capacity>16*e.limits.maxComputeWorkgroupsPerDimension)throw Error("H-PLOC capacity exceeds the adapter dispatch limit; select the grid");this.bodyBuffer=t.bodyBuffer,this.rebuildInterval=i,this.nodeCapacity=2*this.capacity+16*Math.ceil(Math.log2(Math.max(2,this.capacity)))+32,this.buffers=[],this.uniforms=[],this.stats={builds:0,refits:0,nodes:0,extraBytes:0};let r=(u,f,d=uf())=>{if(d&GPUBufferUsage.STORAGE&&f>e.limits.maxStorageBufferBindingSize)throw Error(`${u} exceeds the adapter storage binding limit`);let p=e.createBuffer({label:u,size:Math.max(16,f),usage:d});return this.buffers.push(p),this.stats.extraBytes+=p.size,p};this.nodes=r("H-PLOC nodes",this.nodeCapacity*32),this.links=r("H-PLOC parents and escape links",this.nodeCapacity*8),this.keys=[r("Morton keys A",this.capacity*8),r("Morton keys B",this.capacity*8)],this.clusters=r("H-PLOC level roots",this.capacity*8+128),this.bounds=r("H-PLOC scene bounds",(Rt(this.capacity)*2+256)*16),this.sortBlocks=Rt(this.capacity),this.hist=r("Morton radix counts",this.sortBlocks*16*4),this.scan=new tt(e,this.hist,0,this.sortBlocks*16);let o=(u,f)=>({binding:u,visibility:GPUShaderStage.COMPUTE,buffer:{type:f}});this.layout=e.createBindGroupLayout({entries:[o(0,"uniform"),o(1,"read-only-storage"),...Array.from({length:5},(u,f)=>o(f+2,"storage"))]}),this.extraLayout=e.createBindGroupLayout({entries:[o(0,"uniform"),o(1,"read-only-storage")]});let n=e.createShaderModule({label:"portable H-PLOC",code:ge+ro+`
2884
3014
  @compute @workgroup_size(128)
2885
3015
  fn initializeLinks(@builtin(global_invocation_id) gid:vec3u){if(gid.x<build.escapeOffset){links[gid.x]=0xffffffffu;}}
2886
- `}),a=e.createPipelineLayout({bindGroupLayouts:[this.layout]});this.pipes=Object.fromEntries(["leaves","reduceBounds","mortonCodes","seedClusters","miniHploc","refitTreelets","ropes","initializeLinks"].map(u=>[u,e.createComputePipeline({layout:a,compute:{module:n,entryPoint:u}})]));let l=e.createShaderModule({label:"stable Morton radix",code:nl});this.sortLayout=e.createBindGroupLayout({entries:[o(0,"uniform"),o(1,"read-only-storage"),o(2,"storage"),o(3,"storage")]});let c=e.createPipelineLayout({bindGroupLayouts:[this.sortLayout]});this.sortPipes=Object.fromEntries(["countDigits","scatterDigits"].map(u=>[u,e.createComputePipeline({layout:c,compute:{module:l,entryPoint:u}})])),this.traverse=e.createComputePipeline({label:"H-PLOC collision traversal",layout:e.createPipelineLayout({bindGroupLayouts:[t.layouts.broad,this.extraLayout]}),compute:{module:e.createShaderModule({code:gu}),entryPoint:"findTreePairs"}}),this.configure(t.bodyCount)}uniform(e){let t=this.device.createBuffer({size:e.length*4,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});return new Uint32Array(t.getMappedRange()).set(e),t.unmap(),this.uniforms.push(t),t}configure(e){if(e===this.count)return;if(e>this.capacity)throw Error("H-PLOC body capacity exceeded");for(let d of this.uniforms)d.destroy();this.uniforms=[],this.count=e,this.built=!1,this.stepsSinceBuild=0;let t=[],i=e,r=e,o=0,n=e,a=e===0?pu:0;for(;i>1;){let d=Math.ceil(i/16);t.push({inputCount:i,nodeBase:r,inputOffset:o,outputOffset:n,blocks:d}),d===1&&(a=r+i-2),r+=d*15,o=n,n+=d,i=d}this.stats.nodes=e?2*e-1:0;let l=(d={})=>{let p=this.uniform([e,d.nodeBase??0,d.inputOffset??0,d.outputOffset??0,a,this.sortBlocks,0,d.boundsOffset??0,d.inputCount??e,this.nodeCapacity,0,0]);return{group:this.device.createBindGroup({layout:this.layout,entries:[p,this.bodyBuffer,this.nodes,this.keys[0],this.bounds,this.links,this.clusters].map((h,m)=>({binding:m,resource:{buffer:h}}))}),buffer:p}};this.base=l(),this.levels=t.map(d=>({...d,...l(d)})),this.reductions=[];let c=Rt(e),u=0,f=c*2;for(;c>1;){let d=Rt(c);this.reductions.push({blocks:d,...l({inputCount:c,inputOffset:u,outputOffset:f})}),u=f,f+=d*2,c=d}this.morton=l({boundsOffset:u}),this.sortGroups=Array.from({length:8},(d,p)=>{let g=this.uniform([e,this.sortBlocks,p*4,0]);return this.device.createBindGroup({layout:this.sortLayout,entries:[g,this.keys[p%2],this.keys[1-p%2],this.hist].map((h,m)=>({binding:m,resource:{buffer:h}}))})}),this.extra=this.device.createBindGroup({layout:this.extraLayout,entries:[{binding:0,resource:{buffer:this.base.buffer}},{binding:1,resource:{buffer:this.links}}]}),this.broadBuffers=null}encodeBuild(e){let t=(r,o,n)=>{e.setPipeline(this.pipes[r]),e.setBindGroup(0,o),e.dispatchWorkgroups(n)};t("leaves",this.base.group,Rt(this.count));let i=!this.built||this.stepsSinceBuild>=this.rebuildInterval;if(this.lastRebuilt=i,i){t("initializeLinks",this.base.group,Rt(this.nodeCapacity));for(let r of this.reductions)t("reduceBounds",r.group,r.blocks);t("mortonCodes",this.morton.group,Rt(this.count));for(let r of this.sortGroups)e.setPipeline(this.sortPipes.countDigits),e.setBindGroup(0,r),e.dispatchWorkgroups(this.sortBlocks),this.scan.encode(e),e.setPipeline(this.sortPipes.scatterDigits),e.setBindGroup(0,r),e.dispatchWorkgroups(this.sortBlocks);t("seedClusters",this.base.group,Rt(this.count));for(let r of this.levels)t("miniHploc",r.group,r.blocks);t("ropes",this.base.group,Rt(this.nodeCapacity)),this.built=!0,this.stepsSinceBuild=0,this.stats.builds++}else{for(let r of this.levels)t("refitTreelets",r.group,Rt(r.blocks,64));this.stats.refits++}this.stepsSinceBuild++}encodePairs(e,t){this.configure(t.bodyCount);let i=[t.paramsBuffer,t.bodyBuffer,this.nodes,t.pairBuffer,t.counterBuffer,t.staticBuffer,t.jointBuffer,t.filterBuffer];(!this.broadBuffers||i.some((r,o)=>r!==this.broadBuffers[o]))&&(this.broadBuffers=i,this.broad=this.device.createBindGroup({layout:t.layouts.broad,entries:i.map((r,o)=>({binding:o,resource:{buffer:r}}))})),e.setPipeline(this.traverse),e.setBindGroup(0,this.broad),e.setBindGroup(1,this.extra),e.dispatchWorkgroups(Rt(this.count,64))}destroy(){this.scan.destroy();for(let e of[...this.buffers,...this.uniforms])e.destroy()}};function ll(s,e={}){let t,i,r=!0,o=new Map,n=l=>{if(!i&&!l)return;let c=e.timestampWrites,u=s.beginComputePass({...e,timestampWrites:c&&(r||l)?{querySet:c.querySet,...r&&c.beginningOfPassWriteIndex!==void 0?{beginningOfPassWriteIndex:c.beginningOfPassWriteIndex}:{},...l&&c.endOfPassWriteIndex!==void 0?{endOfPassWriteIndex:c.endOfPassWriteIndex}:{}}:void 0});if(i){u.setPipeline(i.pipeline);for(let[f,d]of i.bindings)u.setBindGroup(f,...d);u[i.method](...i.args)}u.end(),i=null,r=!1},a=(l,c)=>{n(!1),i={pipeline:t,bindings:new Map(o),method:l,args:c}};return{setPipeline(l){t=l},setBindGroup(l,c,u){o.set(l,u===void 0?[c]:[c,[...u]])},dispatchWorkgroups(...l){a("dispatchWorkgroups",l)},dispatchWorkgroupsIndirect(...l){a("dispatchWorkgroupsIndirect",l)},end(){n(!0)}}}var dt=s=>Math.ceil(s/64);function cl(s){(s.radiiDirty||s.noCollideDirty)&&s.uploadStatics();let e=s.params;s.fixedColors&&(s.device.queue.writeBuffer(s.colorBuffer,0,s.fixedColors),s.colorCap=Math.max(1,...s.fixedColors.map(x=>x===255?0:x+1))),s.stepCount++,s.writeParams(),s.writePassConstants(e.iterations,e.alpha);let t=s.parity,i=s.bodyCapacity,r=s.bodyCount,o=s.jointCount,n=s.groups,a=s.device.createCommandEncoder({label:"AVBD app step"});s.encodeStepPrelude?.(a),s.bvh||a.clearBuffer(s.gridBuffer,0,(2*s.tableSize+1)*4),a.clearBuffer(s.tableBuffer),a.clearBuffer(s.adjBuffer,0,(2*i+1)*4);let l=!!s.detailCallback,c=l||s.timingCallback!==null&&s.timing!==null,u=c||s.splitPasses,f=l?s.detailTiming:s.timing,d=[],p,g,h=(x,B)=>{if(p&&!l&&(g===B||!u))return;p?.end(),g=B;let E=l?d.length:Se.indexOf(B);d.push({name:x,aggregate:B});let L={label:x,timestampWrites:c?{querySet:f.querySet,beginningOfPassWriteIndex:E*2,endOfPassWriteIndex:E*2+1}:void 0};p=s.dispatchIsolation?ll(a,L):a.beginComputePass(L)},m=(x,B,E)=>{E<=0||(p.setPipeline(s.pipes[x]),p.setBindGroup(0,B),p.dispatchWorkgroups(E))},b=(x,B,E)=>{p.setPipeline(s.pipes[x]),p.setBindGroup(0,B),p.dispatchWorkgroupsIndirect(s.argsBuffer,E*4)};if(h("contactCache","collision"),m("beginFrame",n.broad,1),e.reuseContacts&&m("updateRefs",n.refs,dt(r)),m("argsPrev",n.args,1),b("hashInsert",n.contacts[t],6),h("broadphaseBuild","collision"),s.bvh?(s.bvh.configure(r),s.bvh.encodeBuild(p)):(m("gridCount",n.broad,dt(r)),s.gridScan.encode(p),m("gridScatter",n.broad,dt(r))),h("broadphasePairs","collision"),s.bvh?s.bvh.encodePairs(p,s):m("findPairs",n.broad,dt(r)),h("narrowphase","collision"),m("argsPairs",n.args,1),b("narrowphase",n.contacts[t],0),m("argsContacts",n.args,1),h("adjacency","adjacency"),m("degreeJoints",n.topo[t],dt(o)),b("degreeContacts",n.topo[t],3),s.adjScan.encode(p),m("fillJoints",n.topo[t],dt(o)),b("fillContacts",n.topo[t],3),m("sortAdjacency",n.topo[t],dt(r)),h("coloring","coloring"),!s.fixedColors){m("colorCompact",n.topo[t],dt(r)),m("colorMark",n.topo[t],dt(r));for(let x=0;x<s.colorRounds;x++)m(x%2===0?"colorRoundAB":"colorRoundBA",n.topo[t],dt(r))}m("colorCount",n.topo[t],s.colorGroups),s.colorHistScan.encode(p),m("colorStarts",n.topo[t],1),m("argsColors",n.args,1),m("colorScatter",n.topo[t],s.colorGroups);let v=x=>p.setBindGroup(1,s.passGroup,[x*256]),w=()=>{p.setBindGroup(0,n.solve[t]),v(0)};h("warmStart","solve"),w(),o>0&&(p.setPipeline(s.pipes.warmStartJoints),p.dispatchWorkgroups(dt(o))),p.setPipeline(s.pipes.warmStartBodies),r&&p.dispatchWorkgroups(dt(r));for(let x=0;x<e.iterations;x++){h("bodySolve","solve"),w(),p.setPipeline(s.pipes.primal);for(let B=0;B<s.colorCap;B++)v(x*(s.colorCap+1)+B),p.dispatchWorkgroupsIndirect(s.argsBuffer,(12+3*B)*4);h("contactUpdate","solve"),w(),v(x*(s.colorCap+1)+s.colorCap),p.setPipeline(s.pipes.dual),p.dispatchWorkgroupsIndirect(s.argsBuffer,36)}h("velocities","solve"),w(),p.setPipeline(s.pipes.updateVelocities),r&&p.dispatchWorkgroups(dt(r)),p.end();let y=2*(l?d.length:Se.length);if(c&&(a.resolveQuerySet(f.querySet,0,y,f.resolve,0),a.copyBufferToBuffer(f.resolve,0,f.read,0,y*8)),s.parity=1-t,s.encodeStepPostlude?.(a),s.device.queue.submit([a.finish()]),!c)return;let A=l?s.detailCallback:s.timingCallback;l?s.detailCallback=null:s.timingCallback=null,s.timingBusy=!0,f.read.mapAsync(GPUMapMode.READ).then(()=>{let x=new BigUint64Array(f.read.getMappedRange()).slice();if(f.read.unmap(),s.timingBusy=!1,s.destroyed){s.releaseAppTiming(),s.releaseTiming();return}let B=(L,M)=>Number(x[M]-x[L])/1e6,E={total:B(0,y-1),broadphase:s.broadphase,bvhRebuilt:s.bvh?.lastRebuilt??!1};if(l){E.details={};for(let[L,M]of d.entries()){let z=B(L*2,L*2+1);E[M.aggregate]=(E[M.aggregate]??0)+z,E.details[M.name]=(E.details[M.name]??0)+z}}else Se.forEach((L,M)=>E[L]=B(M*2,M*2+1));A(E)},x=>{s.timingBusy=!1,s.profileErrors.push(x.message),s.destroyed&&(s.releaseAppTiming(),s.releaseTiming())})}var ul=` let list = params.adjListOffset;
2887
- for (var i = lo + 1u; i < hi; i++) {`,fl=Ri(Ae,mr);if(fl.split(ul).length!==2)throw Error("Pinned adjacency sort changed; review the cached-key variant");var dl=fl.replace(ul,`
3016
+ `}),a=e.createPipelineLayout({bindGroupLayouts:[this.layout]});this.pipes=Object.fromEntries(["leaves","refitLeaves","reduceBounds","mortonCodes","seedClusters","miniHploc","refitTreelets","ropes","initializeLinks"].map(u=>[u,e.createComputePipeline({layout:a,compute:{module:n,entryPoint:u}})]));let l=e.createShaderModule({label:"stable Morton radix",code:Ul});this.sortLayout=e.createBindGroupLayout({entries:[o(0,"uniform"),o(1,"read-only-storage"),o(2,"storage"),o(3,"storage")]});let c=e.createPipelineLayout({bindGroupLayouts:[this.sortLayout]});this.sortPipes=Object.fromEntries(["countDigits","scatterDigits"].map(u=>[u,e.createComputePipeline({layout:c,compute:{module:l,entryPoint:u}})])),this.traverse=e.createComputePipeline({label:"H-PLOC collision traversal",layout:e.createPipelineLayout({bindGroupLayouts:[t.layouts.broad,this.extraLayout]}),compute:{module:e.createShaderModule({code:hf}),entryPoint:"findTreePairs"}}),this.configure(t.bodyCount)}uniform(e){let t=this.device.createBuffer({size:e.length*4,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});return new Uint32Array(t.getMappedRange()).set(e),t.unmap(),this.uniforms.push(t),t}configure(e){if(e===this.count)return;if(e>this.capacity)throw Error("H-PLOC body capacity exceeded");for(let d of this.uniforms)d.destroy();this.uniforms=[],this.count=e,this.built=!1,this.stepsSinceBuild=0;let t=[],i=e,r=e,o=0,n=e,a=e===0?ff:0;for(;i>1;){let d=Math.ceil(i/16);t.push({inputCount:i,nodeBase:r,inputOffset:o,outputOffset:n,blocks:d}),d===1&&(a=r+i-2),r+=d*15,o=n,n+=d,i=d}this.stats.nodes=e?2*e-1:0;let l=(d={})=>{let p=this.uniform([e,d.nodeBase??0,d.inputOffset??0,d.outputOffset??0,a,this.sortBlocks,0,d.boundsOffset??0,d.inputCount??e,this.nodeCapacity,0,0]);return{group:this.device.createBindGroup({layout:this.layout,entries:[p,this.bodyBuffer,this.nodes,this.keys[0],this.bounds,this.links,this.clusters].map((h,g)=>({binding:g,resource:{buffer:h}}))}),buffer:p}};this.base=l(),this.levels=t.map(d=>({...d,...l(d)})),this.reductions=[];let c=Rt(e),u=0,f=c*2;for(;c>1;){let d=Rt(c);this.reductions.push({blocks:d,...l({inputCount:c,inputOffset:u,outputOffset:f})}),u=f,f+=d*2,c=d}this.morton=l({boundsOffset:u}),this.sortGroups=Array.from({length:8},(d,p)=>{let m=this.uniform([e,this.sortBlocks,p*4,0]);return this.device.createBindGroup({layout:this.sortLayout,entries:[m,this.keys[p%2],this.keys[1-p%2],this.hist].map((h,g)=>({binding:g,resource:{buffer:h}}))})}),this.extra=this.device.createBindGroup({layout:this.extraLayout,entries:[{binding:0,resource:{buffer:this.base.buffer}},{binding:1,resource:{buffer:this.links}}]}),this.broadBuffers=null}encodeBuild(e){let t=(r,o,n)=>{e.setPipeline(this.pipes[r]),e.setBindGroup(0,o),e.dispatchWorkgroups(n)},i=!this.built||this.stepsSinceBuild>=this.rebuildInterval;if(this.lastRebuilt=i,t(i?"leaves":"refitLeaves",this.base.group,Rt(this.count)),i){t("initializeLinks",this.base.group,Rt(this.nodeCapacity));for(let r of this.reductions)t("reduceBounds",r.group,r.blocks);t("mortonCodes",this.morton.group,Rt(this.count));for(let r of this.sortGroups)e.setPipeline(this.sortPipes.countDigits),e.setBindGroup(0,r),e.dispatchWorkgroups(this.sortBlocks),this.scan.encode(e),e.setPipeline(this.sortPipes.scatterDigits),e.setBindGroup(0,r),e.dispatchWorkgroups(this.sortBlocks);t("seedClusters",this.base.group,Rt(this.count));for(let r of this.levels)t("miniHploc",r.group,r.blocks);t("ropes",this.base.group,Rt(this.nodeCapacity)),this.built=!0,this.stepsSinceBuild=0,this.stats.builds++}else{for(let r of this.levels)t("refitTreelets",r.group,Rt(r.blocks,64));this.stats.refits++}this.stepsSinceBuild++}encodePairs(e,t){this.configure(t.bodyCount);let i=[t.paramsBuffer,t.bodyBuffer,this.nodes,t.pairBuffer,t.counterBuffer,t.staticBuffer,t.jointBuffer,t.filterBuffer];(!this.broadBuffers||i.some((r,o)=>r!==this.broadBuffers[o]))&&(this.broadBuffers=i,this.broad=this.device.createBindGroup({layout:t.layouts.broad,entries:i.map((r,o)=>({binding:o,resource:{buffer:r}}))})),e.setPipeline(this.traverse),e.setBindGroup(0,this.broad),e.setBindGroup(1,this.extra),e.dispatchWorkgroups(Rt(this.count,64))}destroy(){this.scan.destroy();for(let e of[...this.buffers,...this.uniforms])e.destroy()}};function ql(s,e={}){let t,i,r=!0,o=new Map,n=l=>{if(!i&&!l)return;let c=e.timestampWrites,u=s.beginComputePass({...e,timestampWrites:c&&(r||l)?{querySet:c.querySet,...r&&c.beginningOfPassWriteIndex!==void 0?{beginningOfPassWriteIndex:c.beginningOfPassWriteIndex}:{},...l&&c.endOfPassWriteIndex!==void 0?{endOfPassWriteIndex:c.endOfPassWriteIndex}:{}}:void 0});if(i){u.setPipeline(i.pipeline);for(let[f,d]of i.bindings)u.setBindGroup(f,...d);u[i.method](...i.args)}u.end(),i=null,r=!1},a=(l,c)=>{n(!1),i={pipeline:t,bindings:new Map(o),method:l,args:c}};return{setPipeline(l){t=l},setBindGroup(l,c,u){o.set(l,u===void 0?[c]:[c,[...u]])},dispatchWorkgroups(...l){a("dispatchWorkgroups",l)},dispatchWorkgroupsIndirect(...l){a("dispatchWorkgroupsIndirect",l)},end(){n(!0)}}}var pt=s=>Math.ceil(s/64);function Vl(s){(s.radiiDirty||s.noCollideDirty)&&s.uploadStatics();let e=s.params;s.fixedColors&&(s.device.queue.writeBuffer(s.colorBuffer,0,s.fixedColors),s.colorCap=Math.max(1,...s.fixedColors.map(k=>k===255?0:k+1))),s.stepCount++,s.writeParams(),s.writePassConstants(e.iterations,e.alpha);let t=s.parity,i=s.bodyCapacity,r=s.bodyCount,o=s.jointCount,n=s.groups,a=s.device.createCommandEncoder({label:"AVBD app step"});s.encodeStepPrelude?.(a),s.bvh||a.clearBuffer(s.gridBuffer,0,(2*s.tableSize+1)*4),a.clearBuffer(s.tableBuffer),a.clearBuffer(s.adjBuffer,0,(2*i+1)*4);let l=!!s.detailCallback,c=l||s.timingCallback!==null&&s.timing!==null,u=c||s.splitPasses,f=l?s.detailTiming:s.timing,d=[],p,m,h,g=(k,P)=>{if(p&&!l&&(m===P||!u))return;p?.end(),m=P;let C=l?d.length:Se.indexOf(P);d.push({name:k,aggregate:P});let _={label:k,timestampWrites:c?{querySet:f.querySet,beginningOfPassWriteIndex:C*2,endOfPassWriteIndex:C*2+1}:void 0};p=s.dispatchIsolation?ql(a,_):a.beginComputePass(_),h=void 0},b=k=>{h!==k&&(p.setBindGroup(0,k),h=k)},y=(k,P,C)=>{C<=0||(p.setPipeline(s.pipes[k]),b(P),p.dispatchWorkgroups(C))},A=(k,P,C)=>{p.setPipeline(s.pipes[k]),b(P),p.dispatchWorkgroupsIndirect(s.argsBuffer,C*4)};if(g("contactCache","collision"),y("beginFrame",n.broad,1),e.reuseContacts&&y("updateRefs",n.refs,pt(r)),y("argsPrev",n.args,1),A("hashInsert",n.contacts[t],6),g("broadphaseBuild","collision"),s.bvh?(s.bvh.configure(r),s.bvh.encodeBuild(p),h=void 0):(y("gridCount",n.broad,pt(r)),s.gridScan.encode(p),h=void 0,y("gridScatter",n.broad,pt(r))),g("broadphasePairs","collision"),s.bvh?(s.bvh.encodePairs(p,s),h=void 0):y("findPairs",n.broad,pt(r)),g("narrowphase","collision"),y("argsPairs",n.args,1),A("narrowphase",n.contacts[t],0),y("argsContacts",n.args,1),g("adjacency","adjacency"),y("degreeJoints",n.topo[t],pt(o)),A("degreeContacts",n.topo[t],3),s.adjScan.encode(p),h=void 0,y("fillJoints",n.topo[t],pt(o)),A("fillContacts",n.topo[t],3),y("sortAdjacency",n.topo[t],pt(r)),g("coloring","coloring"),!s.fixedColors){y("colorCompact",n.topo[t],pt(r)),y("colorMark",n.topo[t],pt(r));for(let k=0;k<s.colorRounds;k++)y(k%2===0?"colorRoundAB":"colorRoundBA",n.topo[t],pt(r))}y("colorCount",n.topo[t],s.colorGroups),s.colorHistScan.encode(p),h=void 0,y("colorStarts",n.topo[t],1),y("argsColors",n.args,1),y("colorScatter",n.topo[t],s.colorGroups);let v=s.passOffsets??=[0],x,w,B,L=k=>{w===p&&B===k||(v[0]=k*256,p.setBindGroup(1,s.passGroup,v),w=p,B=k)},M=()=>{x!==p&&(p.setBindGroup(0,n.solve[t]),x=p)};if(g("warmStart","solve"),M(),L(0),o>0&&(p.setPipeline(s.pipes.warmStartJoints),p.dispatchWorkgroups(pt(o))),p.setPipeline(s.pipes.warmStartBodies),r&&p.dispatchWorkgroups(pt(r)),s.smallGroupPipeline)g("smallGroupSolve","solve"),M(),L(0),p.setPipeline(s.smallGroupPipeline),p.dispatchWorkgroups(1);else for(let k=0;k<e.iterations;k++){g("bodySolve","solve"),M(),p.setPipeline(s.pipes.primal);for(let P=0;P<s.colorCap;P++)L(k*(s.colorCap+1)+P),p.dispatchWorkgroupsIndirect(s.argsBuffer,(12+3*P)*4);g("contactUpdate","solve"),M(),L(k*(s.colorCap+1)+s.colorCap),p.setPipeline(s.pipes.dual),p.dispatchWorkgroupsIndirect(s.argsBuffer,36)}g("velocities","solve"),M(),L(0),p.setPipeline(s.pipes.updateVelocities),r&&p.dispatchWorkgroups(pt(r)),p.end();let I=2*(l?d.length:Se.length);if(c&&(a.resolveQuerySet(f.querySet,0,I,f.resolve,0),a.copyBufferToBuffer(f.resolve,0,f.read,0,I*8)),s.parity=1-t,s.encodeStepPostlude?.(a),s.device.queue.submit([a.finish()]),!c)return;let E=l?s.detailCallback:s.timingCallback;l?s.detailCallback=null:s.timingCallback=null,s.timingBusy=!0,f.read.mapAsync(GPUMapMode.READ).then(()=>{let k=new BigUint64Array(f.read.getMappedRange()).slice();if(f.read.unmap(),s.timingBusy=!1,s.destroyed){s.releaseAppTiming(),s.releaseTiming();return}let P=(_,z)=>Number(k[z]-k[_])/1e6,C={total:P(0,I-1),broadphase:s.broadphase,bvhRebuilt:s.bvh?.lastRebuilt??!1};if(l){C.details={};for(let[_,z]of d.entries()){let R=P(_*2,_*2+1);C[z.aggregate]=(C[z.aggregate]??0)+R,C.details[z.name]=(C.details[z.name]??0)+R}}else Se.forEach((_,z)=>C[_]=P(z*2,z*2+1));E(C)},k=>{s.timingBusy=!1,s.profileErrors.push(k.message),s.destroyed&&(s.releaseAppTiming(),s.releaseTiming())})}function oo(s){let e=s.indexOf(`@compute @workgroup_size(256)
3017
+ fn colorCount(`),t=s.indexOf(`
3018
+ // 5.`,e);if(e<0||t<e)throw Error("Pinned color buckets changed; review the bitset rank kernel");return s.slice(0,e).replace(`var<workgroup> hist: array<atomic<u32>, 64>;
3019
+ var<workgroup> chunkColors: array<u32, 256>;
3020
+ `,"")+`
3021
+ var<workgroup> colorBits:array<atomic<u32>,512>;
3022
+ @compute @workgroup_size(256)
3023
+ fn colorCount(@builtin(global_invocation_id) gid:vec3u,
3024
+ @builtin(local_invocation_id) lid:vec3u,
3025
+ @builtin(workgroup_id) wid:vec3u) {
3026
+ atomicStore(&colorBits[lid.x],0u);
3027
+ atomicStore(&colorBits[lid.x+256u],0u);
3028
+ workgroupBarrier();
3029
+ let b=gid.x;
3030
+ var col=NO_COLOR;
3031
+ if(b<params.bodyCount && dynamicBody(i32(b))) {
3032
+ let s=state(0u,b);
3033
+ col=s&0xffu;
3034
+ if((s&PENDING)!=0u){atomicAdd(&counters[C_CLASHES],1u);}
3035
+ if (col == NO_COLOR) { col = params.colorCap - 1u; }
3036
+ atomicStore(&color[b],col);
3037
+ atomicMax(&counters[C_NUM_COLORS],col+1u);
3038
+ }
3039
+ let word=lid.x>>5u;
3040
+ let bit=lid.x&31u;
3041
+ if(col!=NO_COLOR){atomicOr(&colorBits[col*8u+word],1u<<bit);}
3042
+ workgroupBarrier();
3043
+ if(col!=NO_COLOR){
3044
+ var rank=0u;
3045
+ for(var k=0u;k<word;k++){rank+=countOneBits(atomicLoad(&colorBits[col*8u+k]));}
3046
+ rank+=countOneBits(atomicLoad(&colorBits[col*8u+word])&((1u<<bit)-1u));
3047
+ atomicStore(&color[params.stateBOffset+b],rank);
3048
+ }
3049
+ if(lid.x<MAX_COLORS){
3050
+ var count=0u;
3051
+ for(var k=0u;k<8u;k++){count+=countOneBits(atomicLoad(&colorBits[lid.x*8u+k]));}
3052
+ atomicStore(&color[params.colorHistOffset+lid.x*params.colorGroups+wid.x],count);
3053
+ }
3054
+ if(gid.x==0u){atomicStore(&color[params.colorHistOffset+MAX_COLORS*params.colorGroups],0u);}
3055
+ }
3056
+
3057
+ `+s.slice(t)}function no(s,e){let t=s.bodyCount>=1024;if(s.bitsetColorBuckets===t)return;let i=s.colorBucketPipelines??={scan:s.pipes.colorCount};t&&!i.bitset&&(i.bitset=s.device.createComputePipeline({label:"Stable bitset color buckets",layout:s.device.createPipelineLayout({bindGroupLayouts:[s.layouts.topo]}),compute:{module:s.device.createShaderModule({code:e}),entryPoint:"colorCount"}})),s.pipes.colorCount=t?i.bitset:i.scan,s.bitsetColorBuckets=t}var Wl=` let list = params.adjListOffset;
3058
+ for (var i = lo + 1u; i < hi; i++) {`,sa=Ti(ge,br),Hl=oo(sa);if(sa.split(Wl).length!==2)throw Error("Pinned adjacency sort changed; review the cached-key variant");var $l=sa.replace(Wl,`
2888
3059
  let list = params.adjListOffset;
2889
3060
  let count = hi - lo;
2890
3061
  if (count <= 16u) {
@@ -2913,13 +3084,13 @@ fn initializeLinks(@builtin(global_invocation_id) gid:vec3u){if(gid.x<build.esca
2913
3084
  }
2914
3085
  return;
2915
3086
  }
2916
- for (var i = lo + 1u; i < hi; i++) {`);function hl(s){return s.replace("return m.ids.w & 15u;","return select(m.ids.w & 15u, 0u, (m.ids.w & 0x80000000u) != 0u);").replace("bodies[i].initialPos = pos;","bodies[i].initialPos = vec4f(pos.xyz, bodies[i].initialPos.w);")}function Gn(s){return s.replace("let generated = prev.ids.w >> 4u;","let generated = (prev.ids.w >> 4u) & 0x07ffffffu;").replace("reuseContacts(a, b))","bodies[a].initialPos.w == 0.0 && bodies[b].initialPos.w == 0.0 && reuseContacts(a, b))").replace("count | (params.step << 4u)","count | ((params.step & 0x07ffffffu) << 4u) | select(0u, 0x80000000u, bodies[a].initialPos.w != 0.0 || bodies[b].initialPos.w != 0.0)")}function pl(s=Ri(Ae,mr)){return s.replaceAll("if (gid.x >= topoCount()) { return; }",`if (gid.x >= topoCount()) { return; }
2917
- if ((contacts[gid.x].ids.w & 0x80000000u) != 0u) { return; }`)}function ml(s){let e=s.device,t=e.createShaderModule({code:`
3087
+ for (var i = lo + 1u; i < hi; i++) {`);function oa(s){return s.replace("return m.ids.w & 15u;","return select(m.ids.w & 15u, 0u, (m.ids.w & 0x80000000u) != 0u);").replace("bodies[i].initialPos = pos;","bodies[i].initialPos = vec4f(pos.xyz, bodies[i].initialPos.w);")}function ao(s){return s.replace("let generated = prev.ids.w >> 4u;","let generated = (prev.ids.w >> 4u) & 0x07ffffffu;").replace("reuseContacts(a, b))","bodies[a].initialPos.w == 0.0 && bodies[b].initialPos.w == 0.0 && reuseContacts(a, b))").replace("count | (params.step << 4u)","count | ((params.step & 0x07ffffffu) << 4u) | select(0u, 0x80000000u, bodies[a].initialPos.w != 0.0 || bodies[b].initialPos.w != 0.0)")}function na(s=Ti(ge,br)){return s.replaceAll("if (gid.x >= topoCount()) { return; }",`if (gid.x >= topoCount()) { return; }
3088
+ if ((contacts[gid.x].ids.w & 0x80000000u) != 0u) { return; }`)}function aa(s){let e=s.device,t=e.createShaderModule({code:`
2918
3089
  @group(0) @binding(0) var<storage,read_write> records:array<vec4f>;
2919
3090
  @compute @workgroup_size(64) fn clear(@builtin(global_invocation_id) id:vec3u){
2920
3091
  if(id.x*10u+2u>=arrayLength(&records)){return;}
2921
3092
  records[id.x*10u+2u].w=0.;
2922
- }`}),i=e.createComputePipeline({layout:"auto",compute:{module:t,entryPoint:"clear"}}),r=e.createBindGroup({layout:i.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:s.bodyBuffer}}]}),o=e.createCommandEncoder(),n=o.beginComputePass();n.setPipeline(i),n.setBindGroup(0,r),n.dispatchWorkgroups(Math.ceil(s.bodyCount/64)),n.end(),e.queue.submit([o.finish()])}var bu=`
3093
+ }`}),i=e.createComputePipeline({layout:"auto",compute:{module:t,entryPoint:"clear"}}),r=e.createBindGroup({layout:i.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:s.bodyBuffer}}]}),o=e.createCommandEncoder(),n=o.beginComputePass();n.setPipeline(i),n.setBindGroup(0,r),n.dispatchWorkgroups(Math.ceil(s.bodyCount/64)),n.end(),e.queue.submit([o.finish()])}var pf=`
2923
3094
  fn contactGeneration(value: f32) -> u32 {
2924
3095
  return select(0u, bitcast<u32>(value) ^ 0x3f800000u, value != 0.0);
2925
3096
  }
@@ -2927,9 +3098,9 @@ fn contactMovedAfter(value: f32, generated: u32) -> bool {
2927
3098
  let age = (contactGeneration(value) - generated) & 0x07ffffffu;
2928
3099
  return age != 0u && age < 0x04000000u;
2929
3100
  }
2930
- `;function gl(s){let e="bodies[i].inertialPos.w = bitcast<f32>(params.step);";if(!s.includes(e))throw Error("Contact reference layout changed");return s.replace(e,"bodies[i].inertialPos.w = bitcast<f32>((params.step & 0x07ffffffu) ^ 0x3f800000u);")}function Nn(s){let e=` let moved = max(bitcast<u32>(bodies[a].inertialPos.w), bitcast<u32>(bodies[b].inertialPos.w));
2931
- if (count == 0u || generated < moved) { return false; }`;if(!s.includes(e))throw Error("Contact cache layout changed");return bu+s.replace(e,` let generation = generated & 0x07ffffffu;
2932
- if (count == 0u || contactMovedAfter(bodies[a].inertialPos.w, generation) || contactMovedAfter(bodies[b].inertialPos.w, generation)) { return false; }`)}var yu=`${Ae}
3101
+ `;function Jl(s){let e="bodies[i].inertialPos.w = bitcast<f32>(params.step);";if(!s.includes(e))throw Error("Contact reference layout changed");return s.replace(e,"bodies[i].inertialPos.w = bitcast<f32>((params.step & 0x07ffffffu) ^ 0x3f800000u);")}function Xl(s){let e=` let moved = max(bitcast<u32>(bodies[a].inertialPos.w), bitcast<u32>(bodies[b].inertialPos.w));
3102
+ if (count == 0u || generated < moved) { return false; }`;if(!s.includes(e))throw Error("Contact cache layout changed");return pf+s.replace(e,` let generation = generated & 0x07ffffffu;
3103
+ if (count == 0u || contactMovedAfter(bodies[a].inertialPos.w, generation) || contactMovedAfter(bodies[b].inertialPos.w, generation)) { return false; }`)}var mf=["captureIncoming"],gf=["captureSolved","initialize",...Array.from({length:12},()=>["pairs","apply"]).flat(),"writeBack"],bf=`${ge}
2933
3104
  struct Config { count:u32, joints:u32, capacity:u32, list:u32, threshold:f32, dt:f32, pad0:u32, pad1:u32 }
2934
3105
  struct Velocity { incoming:vec4f, incomingAngular:vec4f, linear:vec4f, angular:vec4f }
2935
3106
  struct Bounce { impulse:f32, delta:f32, reboundSpeed:f32, inverseMass:f32, rA:vec4f, rB:vec4f }
@@ -3005,7 +3176,7 @@ fn pointVelocity(i:u32,r:vec3f,incoming:bool)->vec3f {
3005
3176
  let i=id.x;if(i>=cfg.count || bodies[i].size.w<=0.){return;}
3006
3177
  bodies[i].vel=velocities[i].linear;bodies[i].angVel=velocities[i].angular;
3007
3178
  }
3008
- `;var yr=class{constructor(e,{code:t=yu,dimension:i=3}={}){this.solver=e,this.dimension=i,this.device=e.device,this.active=new Set;let r=this.device,o=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST;this.materials=r.createBuffer({size:e.bodyCapacity*4,usage:o}),this.velocities=r.createBuffer({size:e.bodyCapacity*64,usage:o}),this.params=r.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.layout=r.createBindGroupLayout({entries:["uniform","storage","storage","read-only-storage","read-only-storage","read-only-storage","read-only-storage","read-only-storage","storage"].map((l,c)=>({binding:c,visibility:GPUShaderStage.COMPUTE,buffer:{type:l}}))});let n=r.createShaderModule({code:t}),a=r.createPipelineLayout({bindGroupLayouts:[this.layout]});this.pipes=Object.fromEntries(["captureIncoming","captureSolved","initialize","pairs","apply","writeBack"].map(l=>[l,r.createComputePipeline({layout:a,compute:{module:n,entryPoint:l}})]))}set(e,t){if(!Number.isFinite(t)||t<0||t>1)throw Error("restitution must be between 0 and 1");t>0?this.active.add(e):this.active.delete(e),le(this.solver).float(this.materials,e,t)}bind(){let e=this.solver,t=this.device,i=this.dimension===3?e.contactStorage:{manifolds:e.contactBuffers[1-e.parity],contacts:e.contactBuffers[1-e.parity],counters:e.counterBuffer},r=this.dimension===3?e.manifoldCapacity:e.contactCapacity;this.capacity!==r&&(this.bounce?.destroy(),this.capacity=r,this.bounce=t.createBuffer({size:Math.max(1,this.capacity)*48,usage:GPUBufferUsage.STORAGE}));let o=[this.params,e.bodyBuffer,this.velocities,this.materials,i.manifolds,i.contacts,e.adjBuffer,i.counters,this.bounce];(!this.buffers||o.some((a,l)=>a!==this.buffers[l]))&&(this.buffers=o,this.group=t.createBindGroup({layout:this.layout,entries:o.map((a,l)=>({binding:l,resource:{buffer:a}}))}));let n=new Uint32Array([e.bodyCount,e.jointCount,r,2*e.bodyCapacity+1,0,0,0,0]);new Float32Array(n.buffer).set([1,e.params.dt],4),t.queue.writeBuffer(this.params,0,n)}run(e,t){this.bind();let i=t??this.device.createCommandEncoder(),r=i.beginComputePass();r.setBindGroup(0,this.group);for(let o of e)r.setPipeline(this.pipes[o]),r.dispatchWorkgroups(Math.max(1,Math.ceil((o==="initialize"||o==="pairs"?this.capacity:this.solver.bodyCount)/64)));r.end(),t||this.device.queue.submit([i.finish()])}before(e){this.active.size&&this.run(["captureIncoming"],e)}after(e){this.active.size&&this.run(["captureSolved","initialize",...Array.from({length:12},()=>["pairs","apply"]).flat(),"writeBack"],e)}destroy(){for(let e of["materials","velocities","params","bounce"])this[e]?.destroy()}};var bl=new WeakMap,Hr=s=>bl.get(s);function vr(s,e){bl.set(s,e)}var Un=(s,e,t)=>{if(s.split(e).length!==2)throw Error("Pinned angular solver layout changed");return s.replace(e,t)};function qn(s){return s=Un(s,"fn addJoint(acc: ptr<function, Acc>, j: u32, alpha: f32, i: u32) {",`
3179
+ `;var Ar=class{constructor(e,{code:t=bf,dimension:i=3}={}){this.solver=e,this.dimension=i,this.device=e.device,this.active=new Set;let r=this.device,o=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST;this.materials=r.createBuffer({size:e.bodyCapacity*4,usage:o}),this.velocities=r.createBuffer({size:e.bodyCapacity*64,usage:o}),this.params=r.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.layout=r.createBindGroupLayout({entries:["uniform","storage","storage","read-only-storage","read-only-storage","read-only-storage","read-only-storage","read-only-storage","storage"].map((l,c)=>({binding:c,visibility:GPUShaderStage.COMPUTE,buffer:{type:l}}))});let n=r.createShaderModule({code:t}),a=r.createPipelineLayout({bindGroupLayouts:[this.layout]});this.pipes=Object.fromEntries(["captureIncoming","captureSolved","initialize","pairs","apply","writeBack"].map(l=>[l,r.createComputePipeline({layout:a,compute:{module:n,entryPoint:l}})]))}set(e,t){if(!Number.isFinite(t)||t<0||t>1)throw Error("restitution must be between 0 and 1");t>0?this.active.add(e):this.active.delete(e),le(this.solver).float(this.materials,e,t)}bind(){let e=this.solver,t=this.device,i=this.dimension===3?e.contactStorage:{manifolds:e.contactBuffers[1-e.parity],contacts:e.contactBuffers[1-e.parity],counters:e.counterBuffer},r=this.dimension===3?e.manifoldCapacity:e.contactCapacity;this.capacity!==r&&(this.bounce?.destroy(),this.capacity=r,this.bounce=t.createBuffer({size:Math.max(1,this.capacity)*48,usage:GPUBufferUsage.STORAGE}));let o=[this.params,e.bodyBuffer,this.velocities,this.materials,i.manifolds,i.contacts,e.adjBuffer,i.counters,this.bounce];(!this.buffers||o.some((c,u)=>c!==this.buffers[u]))&&(this.buffers=o,this.group=t.createBindGroup({layout:this.layout,entries:o.map((c,u)=>({binding:u,resource:{buffer:c}}))}));let n=this.paramData??=hi(8),{u:a,f:l}=n;a[0]=e.bodyCount,a[1]=e.jointCount,a[2]=r,a[3]=2*e.bodyCapacity+1,l[4]=1,l[5]=e.params.dt,Qt(t,this.params,n)}run(e,t){this.bind();let i=t??this.device.createCommandEncoder(),r=i.beginComputePass();r.setBindGroup(0,this.group);for(let o of e)r.setPipeline(this.pipes[o]),r.dispatchWorkgroups(Math.max(1,Math.ceil((o==="initialize"||o==="pairs"?this.capacity:this.solver.bodyCount)/64)));r.end(),t||this.device.queue.submit([i.finish()])}before(e){this.active.size&&this.run(mf,e)}after(e){this.active.size&&this.run(gf,e)}destroy(){for(let e of["materials","velocities","params","bounce"])this[e]?.destroy()}};var Yl=new WeakMap,rs=s=>Yl.get(s);function wr(s,e){Yl.set(s,e)}var la=(s,e,t)=>{if(s.split(e).length!==2)throw Error("Pinned angular solver layout changed");return s.replace(e,t)};function ca(s){return s=la(s,"fn addJoint(acc: ptr<function, Acc>, j: u32, alpha: f32, i: u32) {",`
3009
3180
  fn angularFrame(k:Joint,a:i32,b:i32)->mat3x3f {
3010
3181
  let qa=rotA(a);let axis=qrotate(qa,k.rA.xyz);
3011
3182
  let ta=qrotate(qa,k.c0Lin.xyz);let tb=qrotate(bodies[b].rot,k.c0Ang.xyz);
@@ -3056,10 +3227,10 @@ fn dualAngular(j:u32){
3056
3227
  }
3057
3228
  `+`
3058
3229
  fn addJoint(acc: ptr<function, Acc>, j: u32, alpha: f32, i: u32) {
3059
- if(info[j].x==3 || info[j].x==4){if(joints[j].penLin.w!=0.){addAngular(acc,j,alpha,i);}return;}`),s=Un(s," if (j >= params.jointCount || info[j].x != T_JOINT) { return; }",` if(j>=params.jointCount){return;}
3230
+ if(info[j].x==3 || info[j].x==4){if(joints[j].penLin.w!=0.){addAngular(acc,j,alpha,i);}return;}`),s=la(s," if (j >= params.jointCount || info[j].x != T_JOINT) { return; }",` if(j>=params.jointCount){return;}
3060
3231
  if(info[j].x==3 || info[j].x==4){warmAngular(j);return;}
3061
- if(info[j].x!=T_JOINT){return;}`),Un(s,"fn dualJoint(j: u32) {",`fn dualJoint(j: u32) {
3062
- if(info[j].x==3 || info[j].x==4){dualAngular(j);return;}`)}function kt({type:s,axisA:e=[0,1,0],axisB:t=[0,1,0],speed:i=1,maxTorque:r=100,minAngle:o=-Math.PI,maxAngle:n=Math.PI}={}){let a=l=>{let c=l&&typeof l.x=="number"?[l.x,l.y,l.z]:Array.from(l),u=Math.hypot(...c);if(c.length!==3||!c.every(Number.isFinite)||u<1e-8)throw Error("Angular axis requires three finite, nonzero components");return c.map(f=>f/u)};if(s!=="motor"&&s!=="limit")throw Error("Invalid angular constraint type");if(!Number.isFinite(i)||!Number.isFinite(r)||r<0)throw Error("Motor speed must be finite and maxTorque nonnegative");if(!Number.isFinite(o)||!Number.isFinite(n)||o<-Math.PI||n>Math.PI||o>n)throw Error("Hinge angles must be ordered within -PI..PI radians");return{type:s,axisA:a(e),axisB:a(t),speed:i,maxTorque:r,minAngle:o,maxAngle:n}}var yl=`struct Body { pos:vec4f,rot:vec4f,initialPos:vec4f,initialRot:vec4f,size:vec4f,moment:vec4f,inertialPos:vec4f,inertialRot:vec4f,velocity:vec4f,angular:vec4f }
3232
+ if(info[j].x!=T_JOINT){return;}`),la(s,"fn dualJoint(j: u32) {",`fn dualJoint(j: u32) {
3233
+ if(info[j].x==3 || info[j].x==4){dualAngular(j);return;}`)}function kt({type:s,axisA:e=[0,1,0],axisB:t=[0,1,0],speed:i=1,maxTorque:r=100,minAngle:o=-Math.PI,maxAngle:n=Math.PI}={}){let a=l=>{let c=l&&typeof l.x=="number"?[l.x,l.y,l.z]:Array.from(l),u=Math.hypot(...c);if(c.length!==3||!c.every(Number.isFinite)||u<1e-8)throw Error("Angular axis requires three finite, nonzero components");return c.map(f=>f/u)};if(s!=="motor"&&s!=="limit")throw Error("Invalid angular constraint type");if(!Number.isFinite(i)||!Number.isFinite(r)||r<0)throw Error("Motor speed must be finite and maxTorque nonnegative");if(!Number.isFinite(o)||!Number.isFinite(n)||o<-Math.PI||n>Math.PI||o>n)throw Error("Hinge angles must be ordered within -PI..PI radians");return{type:s,axisA:a(e),axisB:a(t),speed:i,maxTorque:r,minAngle:o,maxAngle:n}}var Ql=`struct Body { pos:vec4f,rot:vec4f,initialPos:vec4f,initialRot:vec4f,size:vec4f,moment:vec4f,inertialPos:vec4f,inertialRot:vec4f,velocity:vec4f,angular:vec4f }
3063
3234
  struct Joint {penLin:vec4f,penAng:vec4f,lamLin:vec4f,lamAng:vec4f,c0Lin:vec4f,c0Ang:vec4f,rA:vec4f,rB:vec4f}
3064
3235
  @group(0) @binding(0) var<storage,read> bodies:array<Body>;
3065
3236
  @group(0) @binding(1) var<storage,read_write> joints:array<Joint>;
@@ -3077,7 +3248,7 @@ fn rotate(q:vec4f,v:vec3f)->vec3f{let t=2.*cross(q.xyz,v);return v+q.w*t+cross(q
3077
3248
  if(length(tangentB)<1.e-6){tangentB=select(vec3f(0.,-axisB.z,axisB.y),vec3f(-axisB.y,axisB.x,0.),abs(axisB.x)>abs(axisB.z));}
3078
3249
  joints[j].c0Lin=vec4f(tangent,0.);joints[j].c0Ang=vec4f(normalize(tangentB),0.);
3079
3250
  }
3080
- `;var vl=new WeakSet,He=s=>vl.has(s);function Ar(s,e,t,i=1,r=.6,o=[0,0,0]){if(!Number.isFinite(e)||e<=0||!Number.isFinite(t)||t<2*e)throw Error("Capsule height must be at least twice its positive radius");if(!Number.isFinite(i)||i<0)throw Error("Capsule density must be nonnegative");let n=new Ze(s,[2*e,t,2*e],i,r,o),a=t-2*e,l=Math.PI*e*e*a*i,c=4/3*Math.PI*e**3*i;n.mass=l+c;let u=l*e**2/2+c*2*e**2/5,f=l*(a**2/12+e**2/4)+c*(2*e**2/5+a**2/4+3*a*e/8);return n.moment.set([f,u,f]),n.radius=t/2,vl.add(n),n}var Al=`// Exact rounded capsule geometry. Shape -1: radius=size.x/2, segment along Y,
3251
+ `;var Kl=new WeakSet,Fe=s=>Kl.has(s);function Br(s,e,t,i=1,r=.6,o=[0,0,0]){if(!Number.isFinite(e)||e<=0||!Number.isFinite(t)||t<2*e)throw Error("Capsule height must be at least twice its positive radius");if(!Number.isFinite(i)||i<0)throw Error("Capsule density must be nonnegative");let n=new Ze(s,[2*e,t,2*e],i,r,o),a=t-2*e,l=Math.PI*e*e*a*i,c=4/3*Math.PI*e**3*i;n.mass=l+c;let u=l*e**2/2+c*2*e**2/5,f=l*(a**2/12+e**2/4)+c*(2*e**2/5+a**2/4+3*a*e/8);return n.moment.set([f,u,f]),n.radius=t/2,Kl.add(n),n}var Zl=`// Exact rounded capsule geometry. Shape -1: radius=size.x/2, segment along Y,
3081
3252
  // half-length=size.y/2-radius. No tessellation, endpoint-only collision test,
3082
3253
  // shape storage buffer or iterative support search for capsule/sphere/box.
3083
3254
  struct Capsule {a:vec3f,b:vec3f,r:f32}
@@ -3161,16 +3332,16 @@ fn capsuleBox(A:Capsule,B:Box,q:vec4f,sat:ptr<function,Sat>)->Found{
3161
3332
  if(ends.count==2u){return ends;}
3162
3333
  addFound(&found,B.c+qrotate(q,center)+n*A.r,B.c+qrotate(q,onBox),4u<<24u);return found;
3163
3334
  }
3164
- `;function xl(s){if(s.includes("fn capsuleOf"))throw Error("Capsule collision kernel installed twice");let e=`@compute @workgroup_size(64)
3165
- fn narrowphase`;if(!s.includes(e))throw Error("Pinned capsule narrowphase layout changed");let t=s.includes("struct Poly");t&&(s=s.replace(e,xu+`
3166
- `+e)),s=s.replace(e,Al+`
3335
+ `;function ua(s){if(s.includes("fn capsuleOf"))throw Error("Capsule collision kernel installed twice");let e=`@compute @workgroup_size(64)
3336
+ fn narrowphase`;if(!s.includes(e))throw Error("Pinned capsule narrowphase layout changed");let t=s.includes("struct Poly");t&&(s=s.replace(e,xf+`
3337
+ `+e)),s=s.replace(e,Zl+`
3167
3338
  `+e);let i=t?" else if(isHull(b)){found=capsulePoly(capsuleOf(a),polyOf(b),&sat);}":"",r=t?" else if(isHull(a)){found=capsulePoly(capsuleOf(b),polyOf(a),&sat);}":"";return s.replace("let anySphere = sphereA || sphereB;","let anySphere = sphereA || sphereB || capsuleA || capsuleB;").replace(" if (sphereA && sphereB) {",` let capsuleA=bodies[a].angVel.w == -1.;let capsuleB=bodies[b].angVel.w == -1.;
3168
3339
  if(capsuleA || capsuleB){
3169
3340
  if(capsuleA && capsuleB){found=capsuleCapsule(capsuleOf(a),capsuleOf(b),&sat);}
3170
3341
  else if(capsuleA){if(sphereB){found=capsuleSphere(capsuleOf(a),B.c,B.h.x,&sat);}${i} else{found=capsuleBox(capsuleOf(a),B,bodies[b].rot,&sat);}}
3171
3342
  else{if(sphereA){found=capsuleSphere(capsuleOf(b),A.c,A.h.x,&sat);}${r} else{found=capsuleBox(capsuleOf(b),A,bodies[a].rot,&sat);}
3172
3343
  sat.n=-sat.n;for(var c=0u;c<found.count;c++){let p=found.xA[c];found.xA[c]=found.xB[c];found.xB[c]=p;}}
3173
- } else if (sphereA && sphereB) {`)}var xu=`
3344
+ } else if (sphereA && sphereB) {`)}var xf=`
3174
3345
  fn capPolyAxis(A:Capsule,P:Poly,axis:vec3f,best:ptr<function,f32>,normal:ptr<function,vec3f>)->bool{
3175
3346
  let l=length(axis);if(l<1.e-8){return true;}let n=axis/l;
3176
3347
  let lo=min(dot(A.a,n),dot(A.b,n))-A.r;let hi=max(dot(A.a,n),dot(A.b,n))+A.r;
@@ -3202,7 +3373,7 @@ fn capsulePoly(A:Capsule,P:Poly,sat:ptr<function,Sat>)->Found{
3202
3373
  }
3203
3374
  (*sat).n=n;addFound(&found,points.a+n*A.r,points.b,4u<<24u);return found;
3204
3375
  }
3205
- `;var Vn=`// GPU queries against current poses. Rounded box/hull sweeps test offset faces
3376
+ `;var fa=`// GPU queries against current poses. Rounded box/hull sweeps test offset faces
3206
3377
  // and rounded edges, so expanding a bounding box cannot create corner hits.
3207
3378
  struct Query { origin:vec4f, direction:vec4f }
3208
3379
  struct Params { head:vec4u, flags:vec4u, ignored:array<vec4u,4> }
@@ -3356,7 +3527,42 @@ fn nearest(@builtin(global_invocation_id) id:vec3u){if(id.x>=params.head.x||igno
3356
3527
  fn owner(@builtin(global_invocation_id) id:vec3u){if(id.x>=params.head.x||ignored(id.x)){return;}let h=trace(id.x,queries[id.y]);if(h.t>=0.&&bitcast<u32>(max(0.,h.t))==atomicLoad(&best[id.y*2u])){atomicMin(&best[id.y*2u+1u],id.x);}}
3357
3528
  @compute @workgroup_size(64)
3358
3529
  fn finish(@builtin(global_invocation_id) id:vec3u){if(id.x>=params.head.y){return;}let index=atomicLoad(&best[id.x*2u+1u]);if(index==0xffffffffu){hits[id.x*2u]=vec4f(0.,0.,0.,-1.);return;}let h=trace(index,queries[id.x]);hits[id.x*2u]=vec4f(h.n,max(0.,h.t));hits[id.x*2u+1u]=vec4f(bitcast<f32>(index),0.,0.,0.);}
3359
- `;var di=class{constructor(e,t=3){this.solver=e,this.dimension=t,this.jobs=new Set,this.idle=[],this.destroyed=!1;let i=e.device,r=i.createShaderModule({label:`AVBD ${t}D queries`,code:t===2?Vn.replace("const DIM=3u;","const DIM=2u;").replace("const STRIDE=10u;","const STRIDE=6u;"):Vn});this.layout=i.createBindGroupLayout({entries:["read-only-storage","read-only-storage","read-only-storage","storage","storage","uniform","read-only-storage"].map((n,a)=>({binding:a,visibility:GPUShaderStage.COMPUTE,buffer:{type:n}}))});let o=i.createPipelineLayout({bindGroupLayouts:[this.layout]});this.pipes=Object.fromEntries(["nearest","owner","finish"].map(n=>[n,i.createComputePipeline({layout:o,compute:{module:r,entryPoint:n}})])),this.dummy=i.createBuffer({size:16,usage:GPUBufferUsage.STORAGE})}acquire(e){if(this.destroyed)throw Error("GPU queries have been destroyed");let t=this.idle.findIndex(r=>r.capacity>=e),i=t>=0?this.idle.splice(t,1)[0]:this.idle.pop()??{};if(!i.capacity||i.capacity<e){let r=Math.min(65535,Math.max(e,(i.capacity??0)*2,16));for(let[o,n,a]of[["queryBuffer",r*32,GPUBufferUsage.STORAGE],["best",r*8,GPUBufferUsage.STORAGE],["hits",r*32,GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC],["uniform",96,GPUBufferUsage.UNIFORM],["read",r*32,GPUBufferUsage.MAP_READ]])i[o]?.destroy(),i[o]=this.solver.device.createBuffer({size:n,usage:a|GPUBufferUsage.COPY_DST});i.capacity=r,i.buffers=null,i.data=new Float32Array(r*8),i.initial=new Uint32Array(r*2),i.params=new Uint32Array(24)}return this.jobs.add(i),i}release(e){if(e.read.unmap(),!this.destroyed&&e.capacity*104<=2*1024*1024&&this.idle.length<2)this.idle.push(e);else{for(let t of["queryBuffer","best","hits","uniform","read"])e[t].destroy();this.jobs.delete(e)}}async cast(e,{ignore:t=[],collidesWith:i=4294967295,includeTriggers:r=!0,maxDistance:o}={}){if(this.destroyed)throw Error("GPU queries have been destroyed");let n=this.solver,a=n.device,l=this.dimension;if(!Number.isInteger(i)||i<0||i>4294967295)throw Error("Query mask must be an unsigned 32-bit integer");if(typeof r!="boolean")throw Error("includeTriggers must be boolean");if(t.length>16||t.some(d=>!Number.isInteger(d)||d<0||d>=n.bodyCount))throw Error("Queries can ignore up to 16 live body indices");if(e.length>Math.min(65535,a.limits.maxComputeWorkgroupsPerDimension))throw Error("Too many queries in one batch");let c=e.map(d=>{let p=Array.from(d.origin),g=Array.from(d.direction),h=d.radius??0,m=d.maxDistance??o??3e38;if(p.length!==l||g.length!==l||![...p,...g].every(Number.isFinite)||Math.hypot(...g)===0)throw Error(`A query requires ${l} finite components and a nonzero direction`);if(!Number.isFinite(h)||h<0||!Number.isFinite(m)||m<0)throw Error("Query radius and maximum distance must be finite and nonnegative");let b=Math.hypot(...g);return{origin:p,direction:g.map(v=>v/b),radius:h,maxDistance:m}});if(!c.length)return[];let u=c.length,f=this.acquire(u);try{let d=f.data;c.forEach((M,z)=>{d.set([...M.origin,...Array(3-l).fill(0),M.maxDistance,...M.direction,...Array(3-l).fill(0),M.radius],z*8)});let p=f.params;p.fill(0),p.set([n.bodyCount,u,t.length,i,r?0:1,l===3||n.filters?1:0,n.sensorsEnabled?1:0,l===2&&n.shapeBuffer?1:0]),p.set(t,8);let g=f.initial;for(let M=0;M<u;M++)g.set([2139095040,4294967295],M*2);let{queryBuffer:h,best:m,hits:b,uniform:v,read:w}=f;a.queue.writeBuffer(h,0,d.buffer,0,u*32),a.queue.writeBuffer(m,0,g.buffer,0,u*8),a.queue.writeBuffer(v,0,p);let y=[n.bodyBuffer,l===3?n.hullStorage:n.shapeBuffer??this.dummy,h,m,b,v,l===3?n.filterStorage:n.filters??this.dummy];(!f.buffers||y.some((M,z)=>M!==f.buffers[z]))&&(f.group=a.createBindGroup({layout:this.layout,entries:y.map((M,z)=>({binding:z,resource:{buffer:M}}))}),f.buffers=y);let A=a.createCommandEncoder(),x=A.beginComputePass();x.setBindGroup(0,f.group);for(let M of["nearest","owner"])x.setPipeline(this.pipes[M]),x.dispatchWorkgroups(Math.ceil(n.bodyCount/64),u);x.setPipeline(this.pipes.finish),x.dispatchWorkgroups(Math.ceil(u/64)),x.end(),A.copyBufferToBuffer(b,0,w,0,u*32),a.queue.submit([A.finish()]),await w.mapAsync(GPUMapMode.READ,0,u*32);let B=w.getMappedRange(0,u*32),E=new Float32Array(B),L=new Uint32Array(B);return c.map((M,z)=>{let _=E[z*8+3];if(_<0)return null;let k=Array.from(E.slice(z*8,z*8+l)),S=M.origin.map((P,I)=>P+_*M.direction[I]);return{index:L[z*8+4],distance:_,normal:k,center:S,point:S.map((P,I)=>P-M.radius*k[I])}})}finally{this.release(f)}}destroy(){this.destroyed=!0;for(let e of this.jobs)for(let t of["queryBuffer","best","hits","uniform","read"])e[t].destroy();this.jobs.clear(),this.idle.length=0,this.dummy.destroy()}};function Us(s,e){let t=this.passConstantCache??={alphas:[]},i=t.iterations!==s||t.colors!==this.colorCap||t.buffer!==this.passBuffer||!this.passGroup;for(let a=0;a<s;a++){let l=typeof e=="function"?e(a):e;t.alphas[a]!==l&&(i=!0),t.alphas[a]=l}if(!i)return;let r=this.colorCap+1,o=Math.max(s*r,1),n=o*256;(o>this.passEntries||!this.passGroup)&&(this.passBuffer?.destroy(),this.passBuffer=this.device.createBuffer({label:"AVBD pass constants",size:n,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.passEntries=o,this.passGroup=this.device.createBindGroup({layout:this.layouts.pass,entries:[{binding:0,resource:{buffer:this.passBuffer,size:16}}]})),(!t.data||t.data.byteLength<n)&&(t.data=new ArrayBuffer(Math.max(n,(t.data?.byteLength??0)*2)),t.u32=new Uint32Array(t.data),t.f32=new Float32Array(t.data));for(let a=0;a<s;a++)for(let l=0;l<=this.colorCap;l++){let c=(a*r+l)*256/4;t.u32[c]=l,t.f32[c+1]=t.alphas[a]}this.device.queue.writeBuffer(this.passBuffer,0,t.data,0,n),t.iterations=s,t.colors=this.colorCap,t.buffer=this.passBuffer,t.uploads=(t.uploads??0)+1}var Wn=new WeakMap;function qs(s){return Wn.get(s)}function wl(s,e){e?Wn.set(s,Object.freeze({...e})):Wn.delete(s)}function Hn(s){let e=s.indexOf("/** A partial system per body slot handed between lanes (primal). */"),t=s.indexOf("fn accumulate(",e),i=s.lastIndexOf("/**",t);if(e<0||t<0||i<=e)throw Error("3D primal layout changed; review the compatibility kernel");return s.slice(0,e)+`
3530
+ `;var pi=class{constructor(e,t=3){this.solver=e,this.dimension=t,this.jobs=new Set,this.idle=[],this.destroyed=!1;let i=e.device,r=i.createShaderModule({label:`AVBD ${t}D queries`,code:t===2?fa.replace("const DIM=3u;","const DIM=2u;").replace("const STRIDE=10u;","const STRIDE=6u;"):fa});this.layout=i.createBindGroupLayout({entries:["read-only-storage","read-only-storage","read-only-storage","storage","storage","uniform","read-only-storage"].map((n,a)=>({binding:a,visibility:GPUShaderStage.COMPUTE,buffer:{type:n}}))});let o=i.createPipelineLayout({bindGroupLayouts:[this.layout]});this.pipes=Object.fromEntries(["nearest","owner","finish"].map(n=>[n,i.createComputePipeline({layout:o,compute:{module:r,entryPoint:n}})])),this.dummy=i.createBuffer({size:16,usage:GPUBufferUsage.STORAGE})}acquire(e){if(this.destroyed)throw Error("GPU queries have been destroyed");let t=this.idle.findIndex(r=>r.capacity>=e),i=t>=0?this.idle.splice(t,1)[0]:this.idle.pop()??{};if(!i.capacity||i.capacity<e){let r=Math.min(65535,Math.max(e,(i.capacity??0)*2,16));for(let[o,n,a]of[["queryBuffer",r*32,GPUBufferUsage.STORAGE],["best",r*8,GPUBufferUsage.STORAGE],["hits",r*32,GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC],["uniform",96,GPUBufferUsage.UNIFORM],["read",r*32,GPUBufferUsage.MAP_READ]])i[o]?.destroy(),i[o]=this.solver.device.createBuffer({size:n,usage:a|GPUBufferUsage.COPY_DST});i.capacity=r,i.buffers=null,i.data=new Float32Array(r*8),i.initial=new Uint32Array(r*2),i.params=new Uint32Array(24)}return this.jobs.add(i),i}release(e){if(e.read.unmap(),!this.destroyed&&e.capacity*104<=2*1024*1024&&this.idle.length<2)this.idle.push(e);else{for(let t of["queryBuffer","best","hits","uniform","read"])e[t].destroy();this.jobs.delete(e)}}async cast(e,{ignore:t=[],collidesWith:i=4294967295,includeTriggers:r=!0,maxDistance:o}={}){if(this.destroyed)throw Error("GPU queries have been destroyed");let n=this.solver,a=n.device,l=this.dimension;if(!Number.isInteger(i)||i<0||i>4294967295)throw Error("Query mask must be an unsigned 32-bit integer");if(typeof r!="boolean")throw Error("includeTriggers must be boolean");if(t.length>16||t.some(d=>!Number.isInteger(d)||d<0||d>=n.bodyCount))throw Error("Queries can ignore up to 16 live body indices");if(e.length>Math.min(65535,a.limits.maxComputeWorkgroupsPerDimension))throw Error("Too many queries in one batch");let c=e.map(d=>{let p=Array.from(d.origin),m=Array.from(d.direction),h=d.radius??0,g=d.maxDistance??o??3e38;if(p.length!==l||m.length!==l||![...p,...m].every(Number.isFinite)||Math.hypot(...m)===0)throw Error(`A query requires ${l} finite components and a nonzero direction`);if(!Number.isFinite(h)||h<0||!Number.isFinite(g)||g<0)throw Error("Query radius and maximum distance must be finite and nonnegative");let b=Math.hypot(...m);return{origin:p,direction:m.map(y=>y/b),radius:h,maxDistance:g}});if(!c.length)return[];let u=c.length,f=this.acquire(u);try{let d=f.data;c.forEach((I,E)=>{d.set([...I.origin,...Array(3-l).fill(0),I.maxDistance,...I.direction,...Array(3-l).fill(0),I.radius],E*8)});let p=f.params;p.fill(0),p.set([n.bodyCount,u,t.length,i,r?0:1,l===3||n.filters?1:0,n.sensorsEnabled?1:0,l===2&&n.shapeBuffer?1:0]),p.set(t,8);let m=f.initial;for(let I=0;I<u;I++)m.set([2139095040,4294967295],I*2);let{queryBuffer:h,best:g,hits:b,uniform:y,read:A}=f;a.queue.writeBuffer(h,0,d.buffer,0,u*32),a.queue.writeBuffer(g,0,m.buffer,0,u*8),a.queue.writeBuffer(y,0,p);let v=[n.bodyBuffer,l===3?n.hullStorage:n.shapeBuffer??this.dummy,h,g,b,y,l===3?n.filterStorage:n.filters??this.dummy];(!f.buffers||v.some((I,E)=>I!==f.buffers[E]))&&(f.group=a.createBindGroup({layout:this.layout,entries:v.map((I,E)=>({binding:E,resource:{buffer:I}}))}),f.buffers=v);let x=a.createCommandEncoder(),w=x.beginComputePass();w.setBindGroup(0,f.group);for(let I of["nearest","owner"])w.setPipeline(this.pipes[I]),w.dispatchWorkgroups(Math.ceil(n.bodyCount/64),u);w.setPipeline(this.pipes.finish),w.dispatchWorkgroups(Math.ceil(u/64)),w.end(),x.copyBufferToBuffer(b,0,A,0,u*32),a.queue.submit([x.finish()]),await A.mapAsync(GPUMapMode.READ,0,u*32);let B=A.getMappedRange(0,u*32),L=new Float32Array(B),M=new Uint32Array(B);return c.map((I,E)=>{let k=L[E*8+3];if(k<0)return null;let P=Array.from(L.slice(E*8,E*8+l)),C=I.origin.map((_,z)=>_+k*I.direction[z]);return{index:M[E*8+4],distance:k,normal:P,center:C,point:C.map((_,z)=>_-I.radius*P[z])}})}finally{this.release(f)}}destroy(){this.destroyed=!0;for(let e of this.jobs)for(let t of["queryBuffer","best","hits","uniform","read"])e[t].destroy();this.jobs.clear(),this.idle.length=0,this.dummy.destroy()}};function lo(s,e){let t=this.passConstantCache??={alphas:[]},i=t.iterations!==s||t.colors!==this.colorCap||t.buffer!==this.passBuffer||!this.passGroup;for(let a=0;a<s;a++){let l=typeof e=="function"?e(a):e;t.alphas[a]!==l&&(i=!0),t.alphas[a]=l}if(!i)return;let r=this.colorCap+1,o=Math.max(s*r,1),n=o*256;(o>this.passEntries||!this.passGroup)&&(this.passBuffer?.destroy(),this.passBuffer=this.device.createBuffer({label:"AVBD pass constants",size:n,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.passEntries=o,this.passGroup=this.device.createBindGroup({layout:this.layouts.pass,entries:[{binding:0,resource:{buffer:this.passBuffer,size:16}}]})),(!t.data||t.data.byteLength<n)&&(t.data=new ArrayBuffer(Math.max(n,(t.data?.byteLength??0)*2)),t.u32=new Uint32Array(t.data),t.f32=new Float32Array(t.data)),t.u32[2]=s;for(let a=0;a<s;a++)for(let l=0;l<=this.colorCap;l++){let c=(a*r+l)*256/4;t.u32[c]=l,t.u32[c+2]=s,t.f32[c+1]=t.alphas[a]}this.device.queue.writeBuffer(this.passBuffer,0,t.data,0,n),t.iterations=s,t.colors=this.colorCap,t.buffer=this.passBuffer,t.uploads=(t.uploads??0)+1}function sc(s,e){return s.stepParamsCache??=hi(e)}function oc(s,e,t){let i=s.bodyCapacity;t[7]=s.bodyCount,t[8]=s.jointCount,t[9]=s.colorCap,e[10]=s.cellSize,t[11]=s.tableSize-1,e[12]=s.maxSmallRadius,t[13]=s.largeCount,t[14]=s.noCollideCount,t[15]=s.pairCapacity,t[16]=s.contactCapacity,t[17]=s.hashSize-1,t[18]=i+1,t[19]=2*i+1,t[20]=s.tableSize+1,t[21]=2*s.tableSize+1,t[22]=2*s.tableSize+1+i,t[23]=i,t[24]=s.colorHistOffset,t[25]=2*i,t[26]=s.colorGroups,t[27]=2*i+65,t[28]=s.colorRounds}function nc(s,e){let t=sc(this,32),{f:i,u:r}=t,o=this.params;i[0]=o.dt,i[1]=o.gravity,i[2]=o.beta,i[3]=o.gamma,i[4]=s,i[5]=o.vbdStiffness,r[6]=(o.vbd?1:0)|(o.stiffnessRescale?2:0)|(e?4:0)|(o.matchNearest?8:0),oc(this,i,r),Qt(this.device,this.paramsBuffer,t)}function ac(){let s=sc(this,es),{f:e,u:t}=s,i=this.params;e[0]=i.dt,e[1]=i.gravity,e[2]=i.betaLin,e[3]=i.betaAng,e[4]=i.gamma,e[5]=i.alpha,t[6]=(i.matchNearest?Xr:0)|(i.faceBias?Yr:0)|(i.reuseContacts?Qr:0)|(i.startAtRest?Kr:0)|(i.massPenalty?Zr:0),oc(this,e,t),t[29]=this.manifoldCapacity,t[30]=this.stepCount;let r=o=>Math.min(31,Math.max(0,Math.round(Math.log2(o))));t[31]=r(this.primalLanes[0])|r(this.primalLanes[1])<<8|r(this.primalLanes[2])<<16,e[32]=i.windSpeed*Math.cos(i.windAngle),e[33]=i.windSpeed*Math.sin(i.windAngle),e[34]=0,e[35]=i.windPressure,e[36]=i.windGust,e[40]=i.up[0],e[41]=i.up[1],e[42]=i.up[2],e[43]=0,Qt(this.device,this.paramsBuffer,s)}function lc(s){let e=(i,r)=>{if(s.split(i).length!==2)throw Error("Review packed Newton accumulator integration");s=s.replace(i,r)};e(` lin: mat3x3f,
3531
+ ang: mat3x3f,`,` lin: mat2x3f,
3532
+ ang: mat2x3f,`),e("fn addRow(acc:",`fn symmetricOuter(v: vec3f) -> mat2x3f {
3533
+ return mat2x3f(v * v, vec3f(v.y * v.x, v.z * v.x, v.z * v.y));
3534
+ }
3535
+
3536
+ fn addRow(acc:`),e("outer(l, l) * k","symmetricOuter(l) * k"),e("outer(a, a) * k","symmetricOuter(a) * k"),e("mat3x3f(vec3f(g.x, 0.0, 0.0), vec3f(0.0, g.y, 0.0), vec3f(0.0, 0.0, g.z))","mat2x3f(g, vec3f(0.0))"),e("mat3x3f(vec3f(m, 0.0, 0.0), vec3f(0.0, m, 0.0), vec3f(0.0, 0.0, m))","mat2x3f(vec3f(m), vec3f(0.0))"),e("mat3x3f(vec3f(I.x, 0.0, 0.0), vec3f(0.0, I.y, 0.0), vec3f(0.0, 0.0, I.z))","mat2x3f(I, vec3f(0.0))");let t={"0][0":"0][0","0][1":"1][0","0][2":"1][1","1][1":"0][1","1][2":"1][2","2][2":"0][2"};return s=s.replace(/acc\.(lin|ang)\[(\d)\]\[(\d)\]/g,(i,r,o,n)=>{let a=t[`${o}][${n}`];if(!a)throw Error("Unexpected Newton accumulator entry");return`acc.${r}[${a}]`}),s}var ha=["pos","rot","initialPos","initialRot","size","moment","inertialPos","inertialRot","vel","angVel"],wf=/bodies\[([^\]]+)\]\.([A-Za-z]+)/g;function Bf(s){let e=new Map;for(let t of s.matchAll(/\bfn (\w+)\(/g)){let i=t.index,r=s.indexOf("{",i),o=1,n=r+1;for(;o&&n<s.length;n++)s[n]==="{"&&o++,s[n]==="}"&&o--;if(o)throw Error("Review compact body function boundaries");e.set(t[1],{start:i,brace:r,end:n,text:s.slice(i,n),body:s.slice(r+1,n-1)})}return e}function pa(s){let e=Bf(s),t=m=>{let h=e.get(m);if(!h)throw Error(`Review compact body integration: ${m}`);return h},i=(m,h)=>m.replace(wf,(g,b,y)=>{let A=ha.indexOf(y);if(A<0)throw Error(`Review compact body field: ${y}`);return h?`bodies[compactBodySlot(u32(${b}), ${A}u)]`:`bodies[u32(${b}) * 10u + ${A}u]`}),r=m=>[...m.matchAll(/\b(\w+)\s*\(/g)].map(h=>h[1]).filter(h=>e.has(h)),o=new Set([...e].filter(([,m])=>m.body.includes("bodies[")).map(([m])=>m)),n;do{n=!1;for(let[m,h]of e)!o.has(m)&&r(h.body).some(g=>o.has(g))&&(o.add(m),n=!0)}while(n);let a=new Set,l=m=>{for(let h of r(t(m).body))!o.has(h)||a.has(h)||(a.add(h),l(h))};l("warmStartJoints"),l("warmStartBodies");let c=m=>m.replace(/\b(\w+)(?=\s*\()/g,h=>a.has(h)?`${h}BodyRecords`:h),u=[...a].map(m=>c(i(t(m).text,!1))).join(`
3537
+
3538
+ `),f=(m,h)=>{let g=t(m).body;for(let y of[" if (!solverStepValid()) { return; }"," let i = gid.x;"," if (i >= params.bodyCount) { return; }"]){if(g.split(y).length!==2)throw Error(`Review compact body entry: ${m}`);g=g.replace(y,"")}g=g.replace(/bodies\[i\]\.([A-Za-z]+)/g,"value.$1"),h||(g=c(g));let b=(y,A)=>A?`compactBodySlot(i, ${y}u)`:`i * 10u + ${y}u`;return`fn ${m}(@builtin(global_invocation_id) gid: vec3u) {
3539
+ let i = gid.x;
3540
+ let allocated = i < params.stateBOffset;
3541
+ var value: Body;
3542
+ if (allocated) { value = Body(${ha.map((y,A)=>`bodies[${b(A,h)}]`).join(", ")}); }
3543
+ if (i < params.bodyCount && solverStepValid()) { ${g} }
3544
+ // All threads finish reading their tile before any thread overwrites it.
3545
+ // Inactive and unused records participate, including a partial final tile.
3546
+ storageBarrier();
3547
+ if (allocated) { ${ha.map((y,A)=>`bodies[${b(A,!h)}] = value.${y};`).join(`
3548
+ `)} }
3549
+ }`},d=[[t("warmStartJoints"),c(i(t("warmStartJoints").text,!1))],[t("warmStartBodies"),f("warmStartBodies",!1)],[t("updateVelocities"),f("updateVelocities",!0)]].sort(([m],[h])=>h.start-m.start);for(let[m,h]of d)s=s.slice(0,m.start)+h+s.slice(m.end);let p="var<storage, read_write> bodies: array<Body>;";if(s.split(p).length!==2)throw Error("Review compact body storage binding");return s=s.replace(p,"var<storage, read_write> bodies: array<vec4f>;"),i(s,!0)+`
3550
+ ${u}
3551
+ fn compactBodySlot(i: u32, field: u32) -> u32 {
3552
+ let tile = i / 64u * 64u;
3553
+ let width = min(64u, params.stateBOffset - tile);
3554
+ if (field < 4u) { return tile * 10u + (i % 64u) * 4u + field; }
3555
+ return tile * 10u + width * 4u + (i % 64u) * 6u + field - 4u;
3556
+ }
3557
+ `}var co=256;function cc(s){let e=(t,i)=>{if(s.split(t).length!==2)throw Error("Review parallel dual integration");s=s.replace(t,i)};return e("fn dualManifold(m: u32) {","fn dualManifold(m: u32, lane: u32) {"),e("for (var c = mf.ids.z; c < end; c++) {","for (var c = mf.ids.z + lane; c < end; c += 4u) {"),e(` let id = gid.x;
3558
+ if (id < params.jointCount) { dualJoint(id); }
3559
+ else if (id - params.jointCount < manifoldCount()) { dualManifold(id - params.jointCount); }`,` let id = (gid.x + gid.y * ${co*64}u) / 4u;
3560
+ let lane = gid.x % 4u;
3561
+ if (id < params.jointCount) { if (lane == 0u) { dualJoint(id); } }
3562
+ else if (id - params.jointCount < manifoldCount()) { dualManifold(id - params.jointCount, lane); }`),s}function ma(s,e){let t=s.dualArgPipelines??={serial:s.pipes.argsContacts};if(e&&!t.parallel){let i=Nr(ge,Ys),r="setArgs(IA_CONSTRAINTS, params.jointCount + items);";if(i.split(r).length!==2)throw Error("Review parallel contact dispatch sizing");let o=i.replace(r,`let blocks = groupsFor((params.jointCount + items) * 4u);
3563
+ args[IA_CONSTRAINTS] = min(blocks, ${co}u);
3564
+ args[IA_CONSTRAINTS + 1u] = max(1u, (blocks + ${co-1}u) / ${co}u);
3565
+ args[IA_CONSTRAINTS + 2u] = 1u;`);t.parallel=s.device.createComputePipeline({layout:s.device.createPipelineLayout({bindGroupLayouts:[s.layouts.args]}),compute:{module:s.device.createShaderModule({code:o}),entryPoint:"argsContacts"}})}s.pipes.argsContacts=e?t.parallel:t.serial,s.parallelDual=e}var ga=new WeakMap;function uo(s){return ga.get(s)}function uc(s,e){e?ga.set(s,Object.freeze({...e})):ga.delete(s)}function ba(s){let e=s.indexOf("/** A partial system per body slot handed between lanes (primal). */"),t=s.indexOf("fn accumulate(",e),i=s.lastIndexOf("/**",t);if(e<0||t<0||i<=e)throw Error("3D primal layout changed; review the compatibility kernel");return s.slice(0,e)+`
3360
3566
  @compute @workgroup_size(64)
3361
3567
  fn primal(@builtin(global_invocation_id) gid: vec3u) {
3362
3568
  let start = color[params.colorStartOffset + pc.color];
@@ -3366,18 +3572,18 @@ fn primal(@builtin(global_invocation_id) gid: vec3u) {
3366
3572
  finishBody(i, accumulate(i, 0u, 1u));
3367
3573
  }
3368
3574
 
3369
- `+s.slice(i)}function hi(s,e,t){if(s.split(e).length!==2)throw Error("3D contact layout changed; review the compatibility kernel");return s.replace(e,t)}function Vs(s,e,t){let i=new RegExp(`struct ${e} \\{[^}]*\\}`,"g");if([...s.matchAll(i)].length!==1)throw Error(`Expected one 3D ${e} layout`);return s.replace(i,t)}function Bl(s,e,t){let i=`fn ${e}(`;if(s.split(i).length!==2)throw Error(`Expected one 3D ${e} function`);let r=s.indexOf(i),n=s.indexOf("{",r)+1,a=1;for(;n<s.length&&a;n++)s[n]==="{"&&a++,s[n]==="}"&&a--;if(a)throw Error(`Incomplete 3D ${e} function`);return s.slice(0,r)+t(s.slice(r,n))+s.slice(n)}function Jn(s){s=Vs(s,"PairBody",`struct PairBody {
3575
+ `+s.slice(i)}function mi(s,e,t){if(s.split(e).length!==2)throw Error("3D contact layout changed; review the compatibility kernel");return s.replace(e,t)}function fo(s,e,t){let i=new RegExp(`struct ${e} \\{[^}]*\\}`,"g");if([...s.matchAll(i)].length!==1)throw Error(`Expected one 3D ${e} layout`);return s.replace(i,t)}function fc(s,e,t){let i=`fn ${e}(`;if(s.split(i).length!==2)throw Error(`Expected one 3D ${e} function`);let r=s.indexOf(i),n=s.indexOf("{",r)+1,a=1;for(;n<s.length&&a;n++)s[n]==="{"&&a++,s[n]==="}"&&a--;if(a)throw Error(`Incomplete 3D ${e} function`);return s.slice(0,r)+t(s.slice(r,n))+s.slice(n)}function ya(s){s=fo(s,"PairBody",`struct PairBody {
3370
3576
  ids: vec4u,
3371
3577
  rot: vec4f,
3372
3578
  dLin: vec4f,
3373
3579
  dAng: vec4f,
3374
- }`),s=hi(s,"return PairBody(i, rot, bodies[i].pos.xyz - bodies[i].initialPos.xyz, qsub(rot, bodies[i].initialRot));","return PairBody(vec4u(i, 0u, 0u, 0u), rot, vec4f(bodies[i].pos.xyz - bodies[i].initialPos.xyz, 0.0), vec4f(qsub(rot, bodies[i].initialRot), 0.0));"),s=s.replace(/\b(A|B)\.index\b/g,"$1.ids.x").replace(/\b(A|B)\.(dLin|dAng)\b/g,"$1.$2.xyz"),s=Vs(s,"Contact",`struct Contact {
3580
+ }`),s=mi(s,"return PairBody(i, rot, bodies[i].pos.xyz - bodies[i].initialPos.xyz, qsub(rot, bodies[i].initialRot));","return PairBody(vec4u(i, 0u, 0u, 0u), rot, vec4f(bodies[i].pos.xyz - bodies[i].initialPos.xyz, 0.0), vec4f(qsub(rot, bodies[i].initialRot), 0.0));"),s=s.replace(/\b(A|B)\.index\b/g,"$1.ids.x").replace(/\b(A|B)\.(dLin|dAng)\b/g,"$1.$2.xyz"),s=fo(s,"Contact",`struct Contact {
3375
3581
  anchorA: vec4u, // xyz: float bits, w: integer feature key
3376
3582
  anchorB: vec4f, // xyz: anchor, w: normal error
3377
3583
  penalty: vec4f, // xyz: penalties, w: first tangent error
3378
3584
  force: vec4f, // xyz: forces, w: second tangent error
3379
- }`);let e={rA:"bitcast<vec3f>(k.anchorA.xyz)",rB:"k.anchorB.xyz",key:"k.anchorA.w",c0x:"k.anchorB.w",c0y:"k.penalty.w",c0z:"k.force.w",pen:"k.penalty.xyz",lam:"k.force.xyz"};for(let t of["evalContact","accumulate","dualManifold"])s=Bl(s,t,i=>i.replace(/\bk\.(rA|rB|key|c0x|c0y|c0z|pen|lam)\b/g,(r,o)=>e[o]));return s=hi(s,"contacts[c].lam = e.F;","contacts[c].force = vec4f(e.F, k.force.w);"),s=hi(s,"contacts[c].key =","contacts[c].anchorA.w ="),s=hi(s,"contacts[c].pen = pen;","contacts[c].penalty = vec4f(pen, k.penalty.w);"),s=Bl(s,"evalContact",t=>{t=hi(t,` var e: ContactEval;
3380
- `,""),t=hi(t," e.rAW ="," let rAW ="),t=hi(t," e.rBW ="," let rBW ="),t=t.replaceAll("e.rAW","rAW").replaceAll("e.rBW","rBW"),t=hi(t," e.C ="," let C =");let i=t.indexOf(" var F ="),r=t.indexOf(" return e;",i);if(i<0||r<0)throw Error("Expected 3D contact force projection");return t.slice(0,i)+` let raw = k.penalty.xyz * C + k.force.xyz;
3585
+ }`);let e={rA:"bitcast<vec3f>(k.anchorA.xyz)",rB:"k.anchorB.xyz",key:"k.anchorA.w",c0x:"k.anchorB.w",c0y:"k.penalty.w",c0z:"k.force.w",pen:"k.penalty.xyz",lam:"k.force.xyz"};for(let t of["evalContact","accumulate","dualManifold"])s=fc(s,t,i=>i.replace(/\bk\.(rA|rB|key|c0x|c0y|c0z|pen|lam)\b/g,(r,o)=>e[o]));return s=mi(s,"contacts[c].lam = e.F;","contacts[c].force = vec4f(e.F, k.force.w);"),s=mi(s,"contacts[c].key =","contacts[c].anchorA.w ="),s=mi(s,"contacts[c].pen = pen;","contacts[c].penalty = vec4f(pen, k.penalty.w);"),s=fc(s,"evalContact",t=>{t=mi(t,` var e: ContactEval;
3586
+ `,""),t=mi(t," e.rAW ="," let rAW ="),t=mi(t," e.rBW ="," let rBW ="),t=t.replaceAll("e.rAW","rAW").replaceAll("e.rBW","rBW"),t=mi(t," e.C ="," let C =");let i=t.indexOf(" var F ="),r=t.indexOf(" return e;",i);if(i<0||r<0)throw Error("Expected 3D contact force projection");return t.slice(0,i)+` let raw = k.penalty.xyz * C + k.force.xyz;
3381
3587
  let normalForce = select(0.0, raw.x, raw.x < 0.0);
3382
3588
  let bounds = abs(normalForce) * friction;
3383
3589
  let frictionScale = length(raw.yz);
@@ -3388,13 +3594,13 @@ fn primal(@builtin(global_invocation_id) gid: vec3u) {
3388
3594
  let force = vec3f(normalForce, raw.yz * scale);
3389
3595
  return ContactEval(vec4f(rAW, 0.0), vec4f(rBW, 0.0),
3390
3596
  vec4f(C, 0.0), vec4f(force, 0.0), vec4f(frictionScale, bounds, 0.0, 0.0));
3391
- }`}),s=Vs(s,"ContactEval",`struct ContactEval {
3597
+ }`}),s=fo(s,"ContactEval",`struct ContactEval {
3392
3598
  rAW: vec4f,
3393
3599
  rBW: vec4f,
3394
3600
  C: vec4f,
3395
3601
  F: vec4f,
3396
3602
  limits: vec4f, // x: tangent force length, y: Coulomb bound
3397
- }`),s=s.replace(/\b(ev|e)\.(rAW|rBW|C|F)\b/g,"$1.$2.xyz").replace(/\be\.frictionScale\b/g,"e.limits.x").replace(/\be\.bounds\b/g,"e.limits.y"),s=Vs(s,"PassConstants","struct PassConstants { data: vec4u, }"),s.replaceAll("pc.color","pc.data.x").replaceAll("pc.alpha","bitcast<f32>(pc.data.y)")}function $n(s){if(!s.includes("struct Poly"))return s;let e=`@compute @workgroup_size(64)
3603
+ }`),s=s.replace(/\b(ev|e)\.(rAW|rBW|C|F)\b/g,"$1.$2.xyz").replace(/\be\.frictionScale\b/g,"e.limits.x").replace(/\be\.bounds\b/g,"e.limits.y"),s=fo(s,"PassConstants","struct PassConstants { data: vec4u, }"),s.replaceAll("pc.color","pc.data.x").replaceAll("pc.alpha","bitcast<f32>(pc.data.y)")}function dc(s){if(!s.includes("struct Poly"))return s;let e=`@compute @workgroup_size(64)
3398
3604
  fn narrowphase(@builtin(global_invocation_id) gid: vec3u)`;if(s.split(e).length!==2)throw Error("3D hull narrowphase changed; review the compatibility kernel");return s.replace(e,"fn narrowphasePair(gid: vec3u)")+`
3399
3605
  @compute @workgroup_size(32)
3400
3606
  fn narrowphase(@builtin(global_invocation_id) gid: vec3u) {
@@ -3402,9 +3608,9 @@ fn narrowphase(@builtin(global_invocation_id) gid: vec3u) {
3402
3608
  narrowphasePair(vec3u(gid.x * 2u + offset, 0u, 0u));
3403
3609
  }
3404
3610
  }
3405
- `}var pi=class extends js{writePassConstants(e,t){Us.call(this,e,t)}constructor(e,t,i={}){let r=qs(e),o=i.scalarPrimal??r?.scalarPrimal??!1,n=i.portableContactMath??r?.portableContactMath??!1,a=t.forces.some(m=>Hr(m)),l=t.forces.some(m=>{let b=Gi(m);return b&&(Number.isFinite(b.breakStrain)||Number.isFinite(b.breakForce))}),c={requested:i.solverMode??"auto",contactScheduling:i.contactScheduling??"manifolds",custom:!!i.shaders?.solve},u=br({...c,bodyCount:t.bodies.length,constraintCount:t.forces.filter(m=>m instanceof ke||m instanceof ut).length}),f=u.selected==="custom"?i.shaders.solve:u.selected==="optimized"?Wr:u.selected==="points"?Ds:void 0,d=r?.broadphase??i.broadphase??"auto";if(!["grid","hploc","auto"].includes(d))throw Error("broadphase must be 'grid', 'hploc' or 'auto'");let p=i.bvh?.rebuildInterval??64;if(!Number.isInteger(p)||p<1)throw Error("BVH rebuildInterval must be a positive integer");for(let[m,b]of[["minimumColors",64],["minimumColorRounds",32]]){let v=i[m]??0;if(!Number.isInteger(v)||v<0||v>b)throw Error(`${m} must be an integer between 0 and ${b}`);if(m==="minimumColorRounds"&&v%2)throw Error("minimumColorRounds must be even")}let g=Rn(On(a?qn(l?Fs(f??ze):f??ze):l?Fs(f??ze):f??ze));o&&(g=Hn(g)),n&&(g=Jn(g));let h=n&&!i.shaders?.contacts&&i.hulls!==!1&&e.limits.maxStorageBuffersPerShaderStage>=9&&t.bodies.some(m=>wt(m));if(super(e,t,{...i,shaders:{...i.shaders,contacts:h?$n(Ti(!0)):i.shaders?.contacts,solve:g}}),this.solverPolicy=c,this.scalarPrimal=o,this.portableContactMath=n,o&&(this.primalLanes=[1,1,1]),this.dispatchIsolation=r?.dispatchIsolation??!1,!i.shaders?.contacts){h&&(this.contactShaders.custom=!1,this.hullShaders=!0);let m=this.contactShaders.make;this.contactShaders.make=b=>m(n?$n(Nn(b)):Nn(b)),this.contactShaders.make(Ti(this.hullShaders??!1)),this.pipes.updateRefs=e.createComputePipeline({label:"Portable contact references",layout:e.createPipelineLayout({bindGroupLayouts:[this.layouts.refs]}),compute:{module:e.createShaderModule({code:gl(Rs)}),entryPoint:"updateRefs"}})}this.springFracture=l,this.angularConstraints=a,this.customSolveSource=i.shaders?.solve,t.forces.forEach((m,b)=>{let v=Gi(m);v&&this.setSpringMaterial(b,v)}),this.adaptiveScheduling=o?!1:i.adaptiveScheduling??!0,this.defaultPrimalLanes=[...this.primalLanes],this.cacheAdjacencyKeys=i.cacheAdjacencyKeys,this.adjacencyPipelines={original:this.pipes.sortAdjacency},this.selectAdjacencyPipeline(),this.solverDecision=u,this.solvePipelineCache=new Map([[u.selected,Object.fromEntries(["warmStartJoints","warmStartBodies","primal","dual","updateVelocities"].map(m=>[m,this.pipes[m]]))]]),this.minimumColors=i.minimumColors??0,this.minimumColorRounds=i.minimumColorRounds??4,this.colorCap=Math.max(this.minimumColors,this.colorCap),this.colorRounds=Math.max(this.minimumColorRounds,this.colorRounds),this.broadphaseRequested=d,this.broadphase=d==="hploc"?"hploc":"grid",this.bvhOptions=i.bvh??{},this.bvh=null,this.detailCallback=null,this.detailTiming=null,this.profileErrors=[],this.selectBroadphase(),t.forces.forEach((m,b)=>{let v=Hr(m);v&&this.setAngularConstraint(b,v)}),t.bodies.forEach((m,b)=>{He(m)&&this.installCapsule(this.gpuIndex(b))})}installCapsule(e){if(!this.capsulesEnabled){if(this.contactShaders.custom)throw Error("Analytic capsules require the built-in contact kernel");this.capsulesEnabled=!0;let t=this.contactShaders.make;this.contactShaders.make=i=>t(xl(i)),this.contactShaders.make(Ti(this.hullShaders??!1))}this.device.queue.writeBuffer(this.bodyBuffer,e*160+156,new Float32Array([-1]))}async raycast(e,t,i={}){let[r]=await this.raycastAll([{origin:e,direction:t,maxDistance:i.maxDistance}],i);return r}raycastAll(e,t={}){return this.flushPropertyEdits(),this.shapeQueries??=new di(this),this.shapeQueries.cast(e.map(i=>({...i,radius:0})),t)}async sphereCast(e,t,i,r={}){let[o]=await this.sphereCastAll([{origin:e,radius:t,direction:i,maxDistance:r.maxDistance}],r);return o}sphereCastAll(e,t={}){return this.flushPropertyEdits(),this.shapeQueries??=new di(this),this.shapeQueries.cast(e,t)}selectBroadphase(){if(this.broadphaseRequested!=="auto"){this.broadphaseDecision={requested:this.broadphaseRequested,selected:this.broadphase,reason:"Explicit selection"};return}let e=new Float64Array(this.bodyCount),t=0,i=0,r=0;for(let d=0;d<this.bodyCount;d++){let p=this.bodies[d];if(p.radius>0&&(e[t++]=p.radius),p.dynamic){i++;let[g,h,m]=p.size,b=Math.min(g,h,m),v=Math.max(g,h,m),w=g+h+m-b-v;!p.sphere&&!p.hull&&b<=.4*w&&w>=.5*v&&r++}}let o=t?Os(e.subarray(0,t),t>>1):1,n=this.cellSize/(2*o),a=this.jointCount-this.freeSlots.length,l=i?r/i:0,c=this.bodyCapacity<=16*this.device.limits.maxComputeWorkgroupsPerDimension&&(2*this.bodyCapacity+16*Math.ceil(Math.log2(Math.max(2,this.bodyCapacity)))+32)*32<=this.device.limits.maxStorageBufferBindingSize,u=a>=this.bodyCount&&l>=.25,f=c&&this.bodyCount>=1e4&&(n>=4||u);this.broadphase=f?"hploc":"grid",this.broadphaseDecision={requested:"auto",selected:this.broadphase,bodyCount:this.bodyCount,cellRatio:n,constraintCount:a,thinPlateFraction:l,reason:c?f?u?"Many linked thin plates; the tree avoids empty grid-cell space":"Large grid cells contain many smaller objects":"Grid retained for this body count and size distribution":"The GPU tree exceeds this adapter's limits; the grid is used"}}step(){this.selectAdjacencyPipeline(),this.selectSolver(),this.radiiDirty&&(this.uploadStatics(),this.selectBroadphase()),this.broadphaseRequested==="auto"&&this.broadphaseDecision.constraintCount!==this.jointCount-this.freeSlots.length&&this.selectBroadphase(),this.broadphase==="grid"&&this.bvh&&(this.bvh.destroy(),this.bvh=null),this.broadphase==="hploc"&&(!this.bvh||this.bvh.bodyBuffer!==this.bodyBuffer)&&(this.bvh?.destroy(),this.bvh=new Ns(this.device,this,this.bvhOptions)),this.dispatchIsolation||this.bvh||this.detailCallback||this.sleeping||this.restitution?.active.size||this.bodyCommands?.pending.size||this.propertyEdits?.pending||this.externalBeforeStep?cl(this):super.step()}encodeStepPrelude(e){this.flushPropertyEdits(e),this.sleeping?.before(e),this.bodyCommands?.flush(e),this.externalBeforeStep?.(e),this.restitution?.before(e)}encodeStepPostlude(e){this.restitution?.after(e),this.sleeping?.after(e),this.externalAfterStep?.(e)}setRestitution(e,t){if(this.destroyed)throw Error("The 3D solver has been destroyed");if(!Number.isInteger(e)||e<0||e>=this.bodyCount||!Number.isFinite(t)||t<0||t>1)throw Error("Restitution requires a live body index and a value between 0 and 1");t>0&&!this.restitution&&(this.restitution=new yr(this)),this.restitution?.set(e,t),this.wakeAll()}setSolverMode(e){return br({...this.solverPolicy,requested:e,bodyCount:this.bodyCount}),this.solverPolicy.requested=e,this.selectSolver(),this.solverDecision}solveSource(e){return this.springFracture&&(e=Fs(e)),this.angularConstraints&&(e=qn(e)),this.sensorsEnabled&&(e=hl(e)),e=Rn(On(e)),this.scalarPrimal&&(e=Hn(e)),this.portableContactMath&&(e=Jn(e)),e}setAngularConstraint(e,t){if(!Number.isInteger(e)||e<0||e>=this.jointCount)throw Error("Angular constraint needs a live slot");let i=kt(t);this.flushPropertyEdits(),this.angularConstraints||(this.angularConstraints=!0,this.rebuildSolvePipelines());let r=new Float32Array(32);r[0]=r[1]=1e3,r[3]=3e38,r.set(i.axisA,24),r.set(i.axisB,28),r[27]=i.type==="motor"?i.speed:i.minAngle,r[31]=i.type==="motor"?i.maxTorque:i.maxAngle,this.device.queue.writeBuffer(this.jointBuffer,e*128,r),this.info[e*4]=i.type==="motor"?3:4,this.device.queue.writeBuffer(this.infoBuffer,e*16,this.info.subarray(e*4,e*4+4)),this.captureAngularFrames([e]),this.wakeAll()}captureAngularFrames(e){if(!e.length)return;this.flushPropertyEdits();let t=this.device;this.angularFramePipeline??=t.createComputePipeline({layout:"auto",compute:{module:t.createShaderModule({code:`const DISPATCH_STRIDE = ${t.limits.maxComputeWorkgroupsPerDimension*64}u;
3406
- ${yl.replaceAll("id.x","(id.x+id.y*DISPATCH_STRIDE)")}`}),entryPoint:"capture"}}),this.runCapture("angular",this.angularFramePipeline,Uint32Array.from(e),e.length)}setMotor(e,{speed:t,maxTorque:i}={}){if(this.destroyed)throw Error("The 3D solver has been destroyed");if(this.info[e*4]!==3)throw Error("Motor needs an active motor slot");if(t!==void 0&&!Number.isFinite(t))throw Error("Motor speed must be finite");if(i!==void 0&&(!Number.isFinite(i)||i<0))throw Error("maxTorque must be nonnegative");t!==void 0&&le(this).float(this.jointBuffer,e*32+27,t),i!==void 0&&le(this).float(this.jointBuffer,e*32+31,i),this.wakeAll()}rebuildSolvePipelines(){this.solvePipelineCache.clear();let e=this.solverDecision.selected,t=e==="custom"?this.customSolveSource:e==="optimized"?Wr:e==="points"?Ds:ze,i=this.device.createShaderModule({code:this.solveSource(t)}),r=this.device.createPipelineLayout({bindGroupLayouts:[this.layouts.solve,this.layouts.pass]}),o=Object.fromEntries(["warmStartJoints","warmStartBodies","primal","dual","updateVelocities"].map(n=>[n,this.device.createComputePipeline({layout:r,compute:{module:i,entryPoint:n}})]));Object.assign(this.pipes,o),this.solvePipelineCache.set(e,o)}setSensor(e,t){if(this.destroyed)throw Error("The 3D solver has been destroyed");if(!Number.isInteger(e)||e<0||e>=this.bodyCount||typeof t!="boolean")throw Error("Sensor requires a live body index and boolean flag");if(t&&!this.sensorsEnabled){this.sensorsEnabled=!0,ml(this),this.rebuildSolvePipelines(),this.contactShaders.make(Gn(Ti(this.hullShaders??!1)));let i=this.contactShaders.make;this.contactShaders.make=n=>i(Gn(n));let r=this.device.createShaderModule({code:pl()}),o=this.device.createPipelineLayout({bindGroupLayouts:[this.layouts.topo]});for(let n of["degreeContacts","fillContacts"])this.pipes[n]=this.device.createComputePipeline({layout:o,compute:{module:r,entryPoint:n}})}this.sensorsEnabled&&le(this).float(this.bodyBuffer,e*40+11,t?1:0),this.wakeAll()}selectSolver(){let e=this.jointCount-this.freeSlots.length;this.adaptiveScheduling&&this.schedulingDecision?.dense&&(this.bodyCount<25e4||e>0)&&(this.primalLanes=[...this.defaultPrimalLanes],this.schedulingDecision={...this.schedulingDecision,dense:!1,reason:"Threads per body follow solve-group size"});let t=this.solverDecision;if(t.requested===this.solverPolicy.requested&&t.bodyCount===this.bodyCount&&t.constraintCount===e)return;let i=br({...this.solverPolicy,bodyCount:this.bodyCount,constraintCount:e});if(i.selected!==t.selected){let r=this.solvePipelineCache.get(i.selected);if(!r){let o=i.selected==="optimized"?Wr:i.selected==="points"?Ds:void 0,n=this.device.createShaderModule({code:this.solveSource(o??ze)}),a=this.device.createPipelineLayout({bindGroupLayouts:[this.layouts.solve,this.layouts.pass]});r=Object.fromEntries(["warmStartJoints","warmStartBodies","primal","dual","updateVelocities"].map(l=>[l,this.device.createComputePipeline({label:`${i.selected} ${l}`,layout:a,compute:{module:n,entryPoint:l}})])),this.solvePipelineCache.set(i.selected,r)}Object.assign(this.pipes,r)}this.solverDecision=i}profileDetailedNextStep(e){if(!this.device.features.has("timestamp-query")||this.timingBusy||this.timingCallback||this.detailCallback)return!1;let t=2*(9+2*this.params.iterations);return(!this.detailTiming||this.detailTiming.count<t)&&(this.releaseAppTiming(),this.detailTiming={count:t,querySet:this.device.createQuerySet({type:"timestamp",count:t}),resolve:this.device.createBuffer({size:t*8,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),read:this.device.createBuffer({size:t*8,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ})}),this.detailCallback=e,!0}captureConstraintFrames(e){if(e.length){this.flushPropertyEdits(),this.framePipeline||(this.framePipeline=this.device.createComputePipeline({layout:"auto",compute:{module:this.device.createShaderModule({code:`const DISPATCH_STRIDE = ${this.device.limits.maxComputeWorkgroupsPerDimension*64}u;
3407
- ${sl.replaceAll("id.x","(id.x+id.y*DISPATCH_STRIDE)")}`}),entryPoint:"capture"}})),(!this.frameData||this.frameData.length<e.length*4)&&(this.frameData=new Uint32Array(Math.max(e.length*4,(this.frameData?.length??0)*2,64)));for(let t=0;t<e.length;t++)this.frameData[t*4]=e[t].slot,this.frameData[t*4+1]=e[t].spring?1:0;this.runCapture("frame",this.framePipeline,this.frameData.subarray(0,e.length*4),e.length)}}runCapture(e,t,i,r){this.flushEdits?.();let o=this.device,n=(this.captureUploads??={})[e]??={};(!n.buffer||n.buffer.size<i.byteLength)&&(n.buffer?.destroy(),n.buffer=o.createBuffer({size:i.byteLength*2,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),n.buffers=null),o.queue.writeBuffer(n.buffer,0,i);let a=[this.bodyBuffer,this.jointBuffer,this.infoBuffer,n.buffer];(!n.buffers||a.some((d,p)=>d!==n.buffers[p])||n.bytes!==i.byteLength)&&(n.group=o.createBindGroup({layout:t.getBindGroupLayout(0),entries:a.map((d,p)=>({binding:p,resource:{buffer:d,...p===3?{size:i.byteLength}:{}}}))}),n.buffers=a,n.bytes=i.byteLength);let l=o.createCommandEncoder(),c=l.beginComputePass();c.setPipeline(t),c.setBindGroup(0,n.group);let u=Math.ceil(r/64),f=o.limits.maxComputeWorkgroupsPerDimension;c.dispatchWorkgroups(Math.min(u,f),Math.ceil(u/f)),c.end(),o.queue.submit([l.finish()])}setSpringMaterial(e,t={}){if(this.destroyed)throw Error("The 3D solver has been destroyed");if(!Number.isInteger(e)||e<0||e>=this.jointCount||this.info[e*4]!==pr)throw Error("Spring material requires an active spring slot");let i=It(t);!this.springFracture&&(Number.isFinite(i.breakStrain)||Number.isFinite(i.breakForce))&&(this.springFracture=!0,this.rebuildSolvePipelines());for(let[r,o]of[["breakStrain",11],["breakForce",15]])le(this).float(this.jointBuffer,e*32+o,i[r]===1/0?0:i[r]);this.wakeAll()}appendConstraints(...e){return this.flushPropertyEdits(),super.appendConstraints(...e)}appendJoint(e,t,i,r,o,n){let a=c=>c===1/0?3e38:c,[l]=this.appendConstraints(1,(c,u)=>{u[3]=a(o),u[7]=a(n),u[11]=3e38,u.set(i,24),u.set(r,28);let f=e>=0?this.bodies[e].size:[0,0,0],d=this.bodies[t].size;return u[15]=f.reduce((p,g,h)=>p+(g+d[h])**2,0),[1,e,t]});return this.wakeAll(),l}appendJoints(...e){let t=super.appendJoints(...e);return this.wakeAll(),t}appendSprings(...e){let t=super.appendSprings(...e);return this.wakeAll(),t}enableSleeping(e,t={}){this.sleeping||(this.sleeping=new Fi({device:this.device,gpu:this,capacity:this.bodyCapacity,aggregates:e.bodies.map((i,r)=>({rigid:i,index:r}))},t))}wakeAll(){this.sleeping&&(this.sleeping.wakeRequested=!0)}async readSleepStats(){return this.sleeping?this.sleeping.readStats():{sleeping:0,wakeRequested:!1}}addBodies(e){this.flushPropertyEdits();let t=super.addBodies(e);if(t>=0)for(let i=0;i<Math.min(e.length,this.bodyCount-t);i++)He(e[i])&&this.installCapsule(t+i);if(t>=0&&this.sleeping)for(let i=0;i<Math.min(e.length,this.bodyCount-t);i++)this.sleeping.register(t+i,e[i].mass,e[i].allowSleep!==!1);return t}rewriteBodies(e,t){this.flushPropertyEdits(),super.rewriteBodies(e,t);for(let i=0;i<e.length;i++)He(t[i])&&this.installCapsule(e[i]);if(this.sleeping)for(let i=0;i<e.length;i++)this.sleeping.register(e[i],t[i].mass,t[i].allowSleep!==!1)}releaseJoints(e){this.flushPropertyEdits(),super.releaseJoints(e),this.wakeAll()}setWorldAnchor(e,t){if(!Number.isInteger(e)||e<0||e>=this.jointCount||this.info[e*4+1]!==-1||t?.length!==3||!Array.from(t).every(Number.isFinite))throw Error("A world joint and finite xyz anchor are required");for(let i=0;i<3;i++)le(this).float(this.jointBuffer,e*32+24+i,t[i]);this.wakeAll()}disableConstraint(e){this.flushPropertyEdits(),super.disableConstraint(e),this.wakeAll()}setFilters(e,t,i){if(this.destroyed)throw Error("The 3D solver has been destroyed");if(e.length!==t.length||e.length!==i.length)throw Error("Each body index needs a group and collision mask");for(let o=0;o<e.length;o++){if(!Number.isInteger(e[o])||e[o]<0||e[o]>=this.bodyCount)throw Error("Collision filters require live body indices");for(let n of[t[o],i[o]])if(!Number.isInteger(n)||n<0||n>4294967295)throw Error("Collision masks must be unsigned 32-bit integers")}let r=le(this);for(let o=0;o<e.length;o++)r.uint(this.filterBuffer,e[o]*2,t[o]),r.uint(this.filterBuffer,e[o]*2+1,i[o]);this.wakeAll()}profileNextStep(e){return this.detailCallback?!1:super.profileNextStep(t=>e({...t,broadphase:this.broadphase,bvhRebuilt:this.bvh?.lastRebuilt??!1}))}flushPropertyEdits(e){this.propertyEdits?.flush(e)}readJoints(){return this.flushPropertyEdits(),super.readJoints()}releaseAppTiming(){if(this.detailTiming){for(let e of["querySet","resolve","read"])this.detailTiming[e].destroy();this.detailTiming=null}}destroy(){this.passConstantCache=null;for(let e of Object.values(this.captureUploads??{}))e.buffer.destroy();this.captureUploads=null,this.frameData=null,this.propertyEdits?.destroy(),this.shapeQueries?.destroy(),this.restitution?.destroy(),this.sleeping?.dispose(),this.bvh?.destroy(),this.bvh=null,this.timingBusy||this.releaseAppTiming(),super.destroy(),this.solvePipelineCache.clear(),this.adjacencyPipelines={}}adapt(e){if(super.adapt(e),this.colorCap=Math.max(this.minimumColors,this.colorCap),this.colorRounds=Math.max(this.minimumColorRounds,this.colorRounds),this.adaptiveScheduling){let t=this.bodyCount>=25e4&&this.jointCount-this.freeSlots.length===0&&e.manifolds>=1.75*this.bodyCount&&!e.overflow&&!e.clashes;this.primalLanes=t?[2**31,2**31,2**31]:[...this.defaultPrimalLanes],this.schedulingDecision={bodyCount:this.bodyCount,manifolds:e.manifolds,dense:t,cachedAdjacency:this.adjacencyCached,reason:t?"Eight threads share each dense body solve":"Threads per body follow solve-group size"}}}selectAdjacencyPipeline(){let e=this.cacheAdjacencyKeys??this.bodyCount>=25e4;this.adjacencyCached!==e&&(e&&!this.adjacencyPipelines.cached&&(this.adjacencyPipelines.cached=this.device.createComputePipeline({label:"Cached adjacency keys",layout:this.device.createPipelineLayout({bindGroupLayouts:[this.layouts.topo]}),compute:{module:this.device.createShaderModule({code:dl}),entryPoint:"sortAdjacency"}})),this.pipes.sortAdjacency=e?this.adjacencyPipelines.cached:this.adjacencyPipelines.original,this.adjacencyCached=e)}};var Xn=new WeakMap,Cl=[{name:"batched-grid",broadphase:"grid",dispatchIsolation:!1},{name:"isolated-grid",broadphase:"grid",dispatchIsolation:!0},{name:"batched-hploc",broadphase:"hploc",dispatchIsolation:!1},{name:"isolated-hploc",broadphase:"hploc",dispatchIsolation:!0},{name:"scalar-grid",broadphase:"grid",dispatchIsolation:!1,scalarPrimal:!0},{name:"scalar-isolated-grid",broadphase:"grid",dispatchIsolation:!0,scalarPrimal:!0},{name:"portable-contact-grid",broadphase:"grid",dispatchIsolation:!1,portableContactMath:!0},{name:"portable-contact-isolated-grid",broadphase:"grid",dispatchIsolation:!0,scalarPrimal:!0,portableContactMath:!0}];function Sl(s){return Xn.has(s)||Xn.set(s,Bu(s)),Xn.get(s)}async function Bu(s,e){let t=[];for(let i of Cl){let r=await Lu(s,i,e);if(t.push(r),!!r.passed)return wl(s,{dispatchIsolation:i.dispatchIsolation,scalarPrimal:i.scalarPrimal??!1,portableContactMath:i.portableContactMath??!1,broadphase:i.broadphase==="hploc"?"hploc":void 0}),{...r,selected:i.name,compatibility:i.name!==Cl[0].name,attempts:t}}return{...t[0],selected:null,compatibility:!1,attempts:t}}function Cu(s){let e=new ni;return e.iterations=5,s||(e.gravity=0),new Ze(e,[16,.25,16],0,.6,[0,-.125,0]),new Ze(e,[1,1,1],1,.6,[-2,s?2:.45,0]),or(e,.5,1,.6,[0,s?2.3:.45,0]),Ar(e,.25,1.6,1,.6,[2,s?2.5:.75,0]),e}async function mi(s,e,t=e.size){let i=s.createBuffer({size:t,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST});try{let r=s.createCommandEncoder();return r.copyBufferToBuffer(e,0,i,0,t),s.queue.submit([r.finish()]),await i.mapAsync(GPUMapMode.READ),i.getMappedRange().slice(0)}finally{i.destroy()}}async function Su(s){s.step();let e=await s.readCounters(),t=new Uint32Array(await mi(s.device,s.argsBuffer)),i=await Pu(s),r=new Uint32Array(i),o=new Float32Array(i),n=new Uint32Array(await mi(s.device,s.adjBuffer)),a=new Uint32Array(await mi(s.device,s.colorBuffer)),{manifolds:l,contacts:c}=s.contactStorage,u=await mi(s.device,l,Math.max(32,e.manifolds*32)),f=new Uint32Array(u),d=new Float32Array(u),p=new Float32Array(await mi(s.device,c,Math.max(64,e.contacts*64))),g=await s.readBodies(),h=e.manifolds>=3?await ku(s):[],m=h.some(({contactEvaluation:b})=>b.returnedForce===0&&b.independentForce<-1e-5);return{expectedFloorPairs:3,counters:e,pairs:e.pairs?Array.from(await s.readPairs()):[],narrowphaseWorkgroups:Array.from(t.subarray(0,3)),solver:{scalarPrimal:s.scalarPrimal,portableContactMath:s.portableContactMath,lanes:[...s.primalLanes],contactWorkgroups:Array.from(t.subarray(3,6)),dualWorkgroups:Array.from(t.subarray(9,12)),colorWorkgroups:Array.from(t.subarray(12,12+3*s.colorCap)),adjacencyStarts:Array.from(n.subarray(0,5)),adjacencyEntries:Array.from(n.subarray(2*s.bodyCapacity+1,2*s.bodyCapacity+1+n[4])),colorStarts:Array.from(a.subarray(2*s.bodyCapacity,2*s.bodyCapacity+s.colorCap+1)),colorBodies:Array.from(a.subarray(2*s.bodyCapacity+65,2*s.bodyCapacity+68)),positionsAfterOverlap:[1,2,3].map(b=>Array.from(g.subarray(b*40,b*40+3))),manifolds:Array.from({length:e.manifolds},(b,v)=>({ids:Array.from(f.subarray(v*8,v*8+4)),normalAndFriction:Array.from(d.subarray(v*8+4,v*8+8))})),contacts:Array.from({length:e.contacts},(b,v)=>({anchorA:Array.from(p.subarray(v*16,v*16+3)),anchorB:Array.from(p.subarray(v*16+4,v*16+7)),gap:p[v*16+7],penalty:Array.from(p.subarray(v*16+8,v*16+11)),force:Array.from(p.subarray(v*16+12,v*16+15))})),serialSystems:h,failure:m?"contact-evaluation":null},filters:Array.from(new Uint32Array(await mi(s.device,s.filterBuffer))),params:{bodyCount:r[0],largeCount:r[1],noCollideCount:r[2],pairCapacity:r[3],contactCapacity:r[4],dt:o[5],cellSize:o[6],maxSmallRadius:o[7],up:Array.from(o.subarray(8,11)),alpha:o[11]},stage:e.pairs<3?"collision-pairs":e.manifolds<3?"contact-generation":"contacts-created"}}async function ku(s){let e=s.portableContactMath?"bitcast<f32>(pc.data.y)":"pc.alpha",t=s.portableContactMath?"k.anchorB.w":"k.c0x",i=s.portableContactMath?"k.penalty.x":"k.pen.x",r=s.portableContactMath?"k.force.x":"k.lam.x",o=s.device.createShaderModule({code:s.solveSource(ze)+`
3611
+ `}function hc(s,e){return e==="points"&&(s=lc(s)),(e==="points"||e==="optimized")&&(s=cc(s)),s}var gi=class extends eo{writeParams(){ac.call(this)}writePassConstants(e,t){lo.call(this,e,t)}constructor(e,t,i={}){if(i.smallGroups!==void 0&&typeof i.smallGroups!="boolean")throw Error("smallGroups must be a boolean");let r=uo(e),o=i.scalarPrimal??r?.scalarPrimal??!1,n=i.portableContactMath??r?.portableContactMath??!1,a=t.forces.some(v=>rs(v)),l=t.forces.some(v=>{let x=Ui(v);return x&&(Number.isFinite(x.breakStrain)||Number.isFinite(x.breakForce))}),c={requested:i.solverMode??"auto",contactScheduling:i.contactScheduling??"manifolds",custom:!!i.shaders?.solve},u=xr({...c,bodyCount:t.bodies.length,constraintCount:t.forces.filter(v=>v instanceof ke||v instanceof ft).length}),f=u.selected==="custom"?i.shaders.solve:u.selected==="optimized"?is:u.selected==="points"?to:void 0,d=r?.broadphase??i.broadphase??"auto";if(!["grid","hploc","auto"].includes(d))throw Error("broadphase must be 'grid', 'hploc' or 'auto'");let p=i.bvh?.rebuildInterval??64;if(!Number.isInteger(p)||p<1)throw Error("BVH rebuildInterval must be a positive integer");for(let[v,x]of[["minimumColors",64],["minimumColorRounds",32]]){let w=i[v]??0;if(!Number.isInteger(w)||w<0||w>x)throw Error(`${v} must be an integer between 0 and ${x}`);if(v==="minimumColorRounds"&&w%2)throw Error("minimumColorRounds must be even")}let m=hc(f??Ge,u.selected),h=Kn(Zn(a?ca(l?io(m):m):l?io(m):m));o&&(h=ba(h)),n&&(h=ya(h)),u.selected==="points"&&!o&&!n&&!r?.dispatchIsolation&&(h=pa(h));let g=!i.shaders?.contacts&&i.hulls!==!1&&e.limits.maxStorageBuffersPerShaderStage>=9&&t.bodies.some(v=>Ct(v)),b=!i.shaders?.contacts&&t.bodies.some(v=>Fe(v)),y=!i.shaders?.contacts&&t.bodies.some(v=>v.isTrigger);y&&(h=oa(h));let A=v=>(b&&(v=ua(v)),y&&(v=ao(v)),v=Xl(v),n?dc(v):v);if(super(e,t,{...i,shaders:{...i.shaders,contacts:i.shaders?.contacts??A(yr(g)),solve:h,refs:i.shaders?.refs??(i.shaders?.contacts?void 0:Jl(Qs)),topology:i.shaders?.topology??(y?na():void 0)}}),this.solverPolicy=c,this.scalarPrimal=o,this.portableContactMath=n,y&&(this.sensorsEnabled=!0,aa(this)),o&&(this.primalLanes=[1,1,1]),this.dispatchIsolation=r?.dispatchIsolation??!1,!i.shaders?.contacts){this.contactShaders.custom=!1,this.hullShaders=g,this.capsulesEnabled=b;let v=this.contactShaders.make;this.contactShaders.make=x=>v(A(x))}this.springFracture=l,this.angularConstraints=a,this.customSolveSource=i.shaders?.solve,t.forces.forEach((v,x)=>{let w=Ui(v);w&&this.setSpringMaterial(x,w)}),this.adaptiveScheduling=o?!1:i.adaptiveScheduling??!0,this.defaultPrimalLanes=[...this.primalLanes],this.cacheAdjacencyKeys=i.cacheAdjacencyKeys,this.smallGroups=i.smallGroups,this.adjacencyPipelines={original:this.pipes.sortAdjacency},this.selectAdjacencyPipeline(),this.solverDecision=u,this.solvePipelineCache=new Map([[u.selected,Object.fromEntries(["warmStartJoints","warmStartBodies","primal","dual","updateVelocities"].map(v=>[v,this.pipes[v]]))]]),ma(this,u.selected==="points"||u.selected==="optimized"),this.minimumColors=i.minimumColors??0,this.minimumColorRounds=i.minimumColorRounds??4,this.colorCap=Math.max(this.minimumColors,this.colorCap),this.colorRounds=Math.max(this.minimumColorRounds,this.colorRounds),this.broadphaseRequested=d,this.broadphase=d==="hploc"?"hploc":"grid",this.bvhOptions=i.bvh??{},this.bvh=null,this.detailCallback=null,this.detailTiming=null,this.profileErrors=[],this.selectBroadphase(),t.forces.forEach((v,x)=>{let w=rs(v);w&&this.setAngularConstraint(x,w)}),t.bodies.forEach((v,x)=>{Fe(v)&&this.installCapsule(this.gpuIndex(x))})}installCapsule(e){if(!this.capsulesEnabled){if(this.contactShaders.custom)throw Error("Analytic capsules require the built-in contact kernel");this.capsulesEnabled=!0;let t=this.contactShaders.make;this.contactShaders.make=i=>t(ua(i)),this.contactShaders.make(yr(this.hullShaders??!1))}this.device.queue.writeBuffer(this.bodyBuffer,e*160+156,new Float32Array([-1]))}async raycast(e,t,i={}){let[r]=await this.raycastAll([{origin:e,direction:t,maxDistance:i.maxDistance}],i);return r}raycastAll(e,t={}){return this.flushPropertyEdits(),this.shapeQueries??=new pi(this),this.shapeQueries.cast(e.map(i=>({...i,radius:0})),t)}async sphereCast(e,t,i,r={}){let[o]=await this.sphereCastAll([{origin:e,radius:t,direction:i,maxDistance:r.maxDistance}],r);return o}sphereCastAll(e,t={}){return this.flushPropertyEdits(),this.shapeQueries??=new pi(this),this.shapeQueries.cast(e,t)}selectBroadphase(){if(this.broadphaseRequested!=="auto"){this.broadphaseDecision={requested:this.broadphaseRequested,selected:this.broadphase,reason:"Explicit selection"};return}let e=new Float64Array(this.bodyCount),t=0,i=0,r=0;for(let d=0;d<this.bodyCount;d++){let p=this.bodies[d];if(p.radius>0&&(e[t++]=p.radius),p.dynamic){i++;let[m,h,g]=p.size,b=Math.min(m,h,g),y=Math.max(m,h,g),A=m+h+g-b-y;!p.sphere&&!p.hull&&b<=.4*A&&A>=.5*y&&r++}}let o=t?Ks(e.subarray(0,t),t>>1):1,n=this.cellSize/(2*o),a=this.jointCount-this.freeSlots.length,l=i?r/i:0,c=this.bodyCapacity<=16*this.device.limits.maxComputeWorkgroupsPerDimension&&(2*this.bodyCapacity+16*Math.ceil(Math.log2(Math.max(2,this.bodyCapacity)))+32)*32<=this.device.limits.maxStorageBufferBindingSize,u=a>=this.bodyCount&&l>=.25,f=c&&this.bodyCount>=1e4&&(n>=4||u);this.broadphase=f?"hploc":"grid",this.broadphaseDecision={requested:"auto",selected:this.broadphase,bodyCount:this.bodyCount,cellRatio:n,constraintCount:a,thinPlateFraction:l,reason:c?f?u?"Many linked thin plates; the tree avoids empty grid-cell space":"Large grid cells contain many smaller objects":"Grid retained for this body count and size distribution":"The GPU tree exceeds this adapter's limits; the grid is used"}}step(){no(this,Hl),this.selectAdjacencyPipeline(),this.selectSolver(),Fl(this),this.radiiDirty&&(this.uploadStatics(),this.selectBroadphase()),this.broadphaseRequested==="auto"&&this.broadphaseDecision.constraintCount!==this.jointCount-this.freeSlots.length&&this.selectBroadphase(),this.broadphase==="grid"&&this.bvh&&(this.bvh.destroy(),this.bvh=null),this.broadphase==="hploc"&&(!this.bvh||this.bvh.bodyBuffer!==this.bodyBuffer)&&(this.bvh?.destroy(),this.bvh=new so(this.device,this,this.bvhOptions)),this.dispatchIsolation||this.smallGroupPipeline||this.bvh||this.detailCallback||this.sleeping||this.restitution?.active.size||this.bodyCommands?.pending.size||this.propertyEdits?.pending||this.externalBeforeStep?Vl(this):super.step()}encodeStepPrelude(e){this.flushPropertyEdits(e),this.sleeping?.before(e),this.bodyCommands?.flush(e),this.externalBeforeStep?.(e),this.restitution?.before(e)}encodeStepPostlude(e){this.restitution?.after(e),this.sleeping?.after(e),this.externalAfterStep?.(e)}setRestitution(e,t){if(this.destroyed)throw Error("The 3D solver has been destroyed");if(!Number.isInteger(e)||e<0||e>=this.bodyCount||!Number.isFinite(t)||t<0||t>1)throw Error("Restitution requires a live body index and a value between 0 and 1");t>0&&!this.restitution&&(this.restitution=new Ar(this)),this.restitution?.set(e,t),this.wakeAll()}setSolverMode(e){return xr({...this.solverPolicy,requested:e,bodyCount:this.bodyCount}),this.solverPolicy.requested=e,this.selectSolver(),this.solverDecision}solveSource(e,t=this.solverDecision.selected){return e=hc(e,t),this.springFracture&&(e=io(e)),this.angularConstraints&&(e=ca(e)),this.sensorsEnabled&&(e=oa(e)),e=Kn(Zn(e)),this.scalarPrimal&&(e=ba(e)),this.portableContactMath&&(e=ya(e)),t==="points"&&!this.scalarPrimal&&!this.portableContactMath&&!this.dispatchIsolation&&(e=pa(e)),e}setAngularConstraint(e,t){if(!Number.isInteger(e)||e<0||e>=this.jointCount)throw Error("Angular constraint needs a live slot");let i=kt(t);this.flushPropertyEdits(),this.angularConstraints||(this.angularConstraints=!0,this.rebuildSolvePipelines());let r=new Float32Array(32);r[0]=r[1]=1e3,r[3]=3e38,r.set(i.axisA,24),r.set(i.axisB,28),r[27]=i.type==="motor"?i.speed:i.minAngle,r[31]=i.type==="motor"?i.maxTorque:i.maxAngle,this.device.queue.writeBuffer(this.jointBuffer,e*128,r),this.info[e*4]=i.type==="motor"?3:4,this.device.queue.writeBuffer(this.infoBuffer,e*16,this.info.subarray(e*4,e*4+4)),this.captureAngularFrames([e]),this.wakeAll()}captureAngularFrames(e){if(!e.length)return;this.flushPropertyEdits();let t=this.device;this.angularFramePipeline??=t.createComputePipeline({layout:"auto",compute:{module:t.createShaderModule({code:`const DISPATCH_STRIDE = ${t.limits.maxComputeWorkgroupsPerDimension*64}u;
3612
+ ${Ql.replaceAll("id.x","(id.x+id.y*DISPATCH_STRIDE)")}`}),entryPoint:"capture"}}),this.runCapture("angular",this.angularFramePipeline,Uint32Array.from(e),e.length)}setMotor(e,{speed:t,maxTorque:i}={}){if(this.destroyed)throw Error("The 3D solver has been destroyed");if(this.info[e*4]!==3)throw Error("Motor needs an active motor slot");if(t!==void 0&&!Number.isFinite(t))throw Error("Motor speed must be finite");if(i!==void 0&&(!Number.isFinite(i)||i<0))throw Error("maxTorque must be nonnegative");t!==void 0&&le(this).float(this.jointBuffer,e*32+27,t),i!==void 0&&le(this).float(this.jointBuffer,e*32+31,i),this.wakeAll()}rebuildSolvePipelines(){this.solvePipelineCache.clear(),this.smallGroupPipelines?.clear(),this.smallGroupPipeline=null;let e=this.solverDecision.selected,t=e==="custom"?this.customSolveSource:e==="optimized"?is:e==="points"?to:Ge,i=this.device.createShaderModule({code:this.solveSource(t)}),r=this.device.createPipelineLayout({bindGroupLayouts:[this.layouts.solve,this.layouts.pass]}),o=Object.fromEntries(["warmStartJoints","warmStartBodies","primal","dual","updateVelocities"].map(n=>[n,this.device.createComputePipeline({layout:r,compute:{module:i,entryPoint:n}})]));Object.assign(this.pipes,o),this.solvePipelineCache.set(e,o)}setSensor(e,t){if(this.destroyed)throw Error("The 3D solver has been destroyed");if(!Number.isInteger(e)||e<0||e>=this.bodyCount||typeof t!="boolean")throw Error("Sensor requires a live body index and boolean flag");if(t&&!this.sensorsEnabled){this.sensorsEnabled=!0,aa(this),this.rebuildSolvePipelines(),this.contactShaders.make(ao(yr(this.hullShaders??!1)));let i=this.contactShaders.make;this.contactShaders.make=n=>i(ao(n));let r=this.device.createShaderModule({code:na()}),o=this.device.createPipelineLayout({bindGroupLayouts:[this.layouts.topo]});for(let n of["degreeContacts","fillContacts"])this.pipes[n]=this.device.createComputePipeline({layout:o,compute:{module:r,entryPoint:n}})}this.sensorsEnabled&&le(this).float(this.bodyBuffer,e*40+11,t?1:0),this.wakeAll()}selectSolver(){let e=this.jointCount-this.freeSlots.length;this.adaptiveScheduling&&this.schedulingDecision?.dense&&(this.bodyCount<25e4||e>0)&&(this.primalLanes=[...this.defaultPrimalLanes],this.schedulingDecision={...this.schedulingDecision,dense:!1,reason:"Threads per body follow solve-group size"});let t=this.solverDecision;if(t.requested===this.solverPolicy.requested&&t.bodyCount===this.bodyCount&&t.constraintCount===e)return;let i=xr({...this.solverPolicy,bodyCount:this.bodyCount,constraintCount:e});if(i.selected!==t.selected){let r=this.solvePipelineCache.get(i.selected);if(!r){let o=i.selected==="optimized"?is:i.selected==="points"?to:void 0,n=this.device.createShaderModule({code:this.solveSource(o??Ge,i.selected)}),a=this.device.createPipelineLayout({bindGroupLayouts:[this.layouts.solve,this.layouts.pass]});r=Object.fromEntries(["warmStartJoints","warmStartBodies","primal","dual","updateVelocities"].map(l=>[l,this.device.createComputePipeline({label:`${i.selected} ${l}`,layout:a,compute:{module:n,entryPoint:l}})])),this.solvePipelineCache.set(i.selected,r)}Object.assign(this.pipes,r)}this.solverDecision=i,ma(this,i.selected==="points"||i.selected==="optimized")}profileDetailedNextStep(e){if(!this.device.features.has("timestamp-query")||this.timingBusy||this.timingCallback||this.detailCallback)return!1;let t=2*(9+2*this.params.iterations);return(!this.detailTiming||this.detailTiming.count<t)&&(this.releaseAppTiming(),this.detailTiming={count:t,querySet:this.device.createQuerySet({type:"timestamp",count:t}),resolve:this.device.createBuffer({size:t*8,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),read:this.device.createBuffer({size:t*8,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ})}),this.detailCallback=e,!0}captureConstraintFrames(e){if(e.length){this.flushPropertyEdits(),this.framePipeline||(this.framePipeline=this.device.createComputePipeline({layout:"auto",compute:{module:this.device.createShaderModule({code:`const DISPATCH_STRIDE = ${this.device.limits.maxComputeWorkgroupsPerDimension*64}u;
3613
+ ${jl.replaceAll("id.x","(id.x+id.y*DISPATCH_STRIDE)")}`}),entryPoint:"capture"}})),(!this.frameData||this.frameData.length<e.length*4)&&(this.frameData=new Uint32Array(Math.max(e.length*4,(this.frameData?.length??0)*2,64)));for(let t=0;t<e.length;t++)this.frameData[t*4]=e[t].slot,this.frameData[t*4+1]=e[t].spring?1:0;this.runCapture("frame",this.framePipeline,this.frameData.subarray(0,e.length*4),e.length)}}runCapture(e,t,i,r){this.flushEdits?.();let o=this.device,n=(this.captureUploads??={})[e]??={};(!n.buffer||n.buffer.size<i.byteLength)&&(n.buffer?.destroy(),n.buffer=o.createBuffer({size:i.byteLength*2,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),n.buffers=null),o.queue.writeBuffer(n.buffer,0,i);let a=[this.bodyBuffer,this.jointBuffer,this.infoBuffer,n.buffer];(!n.buffers||a.some((d,p)=>d!==n.buffers[p])||n.bytes!==i.byteLength)&&(n.group=o.createBindGroup({layout:t.getBindGroupLayout(0),entries:a.map((d,p)=>({binding:p,resource:{buffer:d,...p===3?{size:i.byteLength}:{}}}))}),n.buffers=a,n.bytes=i.byteLength);let l=o.createCommandEncoder(),c=l.beginComputePass();c.setPipeline(t),c.setBindGroup(0,n.group);let u=Math.ceil(r/64),f=o.limits.maxComputeWorkgroupsPerDimension;c.dispatchWorkgroups(Math.min(u,f),Math.ceil(u/f)),c.end(),o.queue.submit([l.finish()])}setSpringMaterial(e,t={}){if(this.destroyed)throw Error("The 3D solver has been destroyed");if(!Number.isInteger(e)||e<0||e>=this.jointCount||this.info[e*4]!==gr)throw Error("Spring material requires an active spring slot");let i=It(t);!this.springFracture&&(Number.isFinite(i.breakStrain)||Number.isFinite(i.breakForce))&&(this.springFracture=!0,this.rebuildSolvePipelines());for(let[r,o]of[["breakStrain",11],["breakForce",15]])le(this).float(this.jointBuffer,e*32+o,i[r]===1/0?0:i[r]);this.wakeAll()}appendConstraints(...e){return this.flushPropertyEdits(),super.appendConstraints(...e)}appendJoint(e,t,i,r,o,n){let a=c=>c===1/0?3e38:c,[l]=this.appendConstraints(1,(c,u)=>{u[3]=a(o),u[7]=a(n),u[11]=3e38,u.set(i,24),u.set(r,28);let f=e>=0?this.bodies[e].size:[0,0,0],d=this.bodies[t].size;return u[15]=f.reduce((p,m,h)=>p+(m+d[h])**2,0),[1,e,t]});return this.wakeAll(),l}appendJoints(...e){let t=super.appendJoints(...e);return this.wakeAll(),t}appendSprings(...e){let t=super.appendSprings(...e);return this.wakeAll(),t}enableSleeping(e,t={}){this.sleeping||(this.sleeping=new Fi({device:this.device,gpu:this,capacity:this.bodyCapacity,aggregates:e.bodies.map((i,r)=>({rigid:i,index:r}))},t))}wakeAll(){this.sleeping&&(this.sleeping.wakeRequested=!0)}async readSleepStats(){return this.sleeping?this.sleeping.readStats():{sleeping:0,wakeRequested:!1}}addBodies(e){this.flushPropertyEdits();let t=super.addBodies(e);if(t>=0)for(let i=0;i<Math.min(e.length,this.bodyCount-t);i++)Fe(e[i])&&this.installCapsule(t+i);if(t>=0&&this.sleeping)for(let i=0;i<Math.min(e.length,this.bodyCount-t);i++)this.sleeping.register(t+i,e[i].mass,e[i].allowSleep!==!1);return t}rewriteBodies(e,t){this.flushPropertyEdits(),super.rewriteBodies(e,t);for(let i=0;i<e.length;i++)Fe(t[i])&&this.installCapsule(e[i]);if(this.sleeping)for(let i=0;i<e.length;i++)this.sleeping.register(e[i],t[i].mass,t[i].allowSleep!==!1)}releaseJoints(e){this.flushPropertyEdits(),super.releaseJoints(e),this.wakeAll()}setWorldAnchor(e,t){if(!Number.isInteger(e)||e<0||e>=this.jointCount||this.info[e*4+1]!==-1||t?.length!==3||!Array.from(t).every(Number.isFinite))throw Error("A world joint and finite xyz anchor are required");for(let i=0;i<3;i++)le(this).float(this.jointBuffer,e*32+24+i,t[i]);this.wakeAll()}disableConstraint(e){this.flushPropertyEdits(),super.disableConstraint(e),this.wakeAll()}setFilters(e,t,i){if(this.destroyed)throw Error("The 3D solver has been destroyed");if(e.length!==t.length||e.length!==i.length)throw Error("Each body index needs a group and collision mask");for(let o=0;o<e.length;o++){if(!Number.isInteger(e[o])||e[o]<0||e[o]>=this.bodyCount)throw Error("Collision filters require live body indices");for(let n of[t[o],i[o]])if(!Number.isInteger(n)||n<0||n>4294967295)throw Error("Collision masks must be unsigned 32-bit integers")}let r=le(this);for(let o=0;o<e.length;o++)r.uint(this.filterBuffer,e[o]*2,t[o]),r.uint(this.filterBuffer,e[o]*2+1,i[o]);this.wakeAll()}profileNextStep(e){return this.detailCallback?!1:super.profileNextStep(t=>e({...t,broadphase:this.broadphase,bvhRebuilt:this.bvh?.lastRebuilt??!1}))}flushPropertyEdits(e){this.propertyEdits?.flush(e)}readJoints(){return this.flushPropertyEdits(),super.readJoints()}releaseAppTiming(){if(this.detailTiming){for(let e of["querySet","resolve","read"])this.detailTiming[e].destroy();this.detailTiming=null}}destroy(){this.passConstantCache=null;for(let e of Object.values(this.captureUploads??{}))e.buffer.destroy();this.captureUploads=null,this.frameData=null,this.propertyEdits?.destroy(),this.shapeQueries?.destroy(),this.restitution?.destroy(),this.sleeping?.dispose(),this.bvh?.destroy(),this.bvh=null,this.timingBusy||this.releaseAppTiming(),super.destroy(),this.solvePipelineCache.clear(),this.adjacencyPipelines={}}adapt(e){if(super.adapt(e),this.colorCap=Math.max(this.minimumColors,this.colorCap),this.colorRounds=Math.max(this.minimumColorRounds,this.colorRounds),this.adaptiveScheduling){let t=this.bodyCount>=25e4&&this.jointCount-this.freeSlots.length===0&&e.manifolds>=1.75*this.bodyCount&&!e.overflow&&!e.clashes;this.primalLanes=t?[2**31,2**31,2**31]:[...this.defaultPrimalLanes],this.schedulingDecision={bodyCount:this.bodyCount,manifolds:e.manifolds,dense:t,cachedAdjacency:this.adjacencyCached,reason:t?"Eight threads share each dense body solve":"Threads per body follow solve-group size"}}}selectAdjacencyPipeline(){let e=this.cacheAdjacencyKeys??this.bodyCount>=25e4;this.adjacencyCached!==e&&(e&&!this.adjacencyPipelines.cached&&(this.adjacencyPipelines.cached=this.device.createComputePipeline({label:"Cached adjacency keys",layout:this.device.createPipelineLayout({bindGroupLayouts:[this.layouts.topo]}),compute:{module:this.device.createShaderModule({code:$l}),entryPoint:"sortAdjacency"}})),this.pipes.sortAdjacency=e?this.adjacencyPipelines.cached:this.adjacencyPipelines.original,this.adjacencyCached=e)}};var va=new WeakMap,pc=[{name:"batched-grid",broadphase:"grid",dispatchIsolation:!1},{name:"isolated-grid",broadphase:"grid",dispatchIsolation:!0},{name:"batched-hploc",broadphase:"hploc",dispatchIsolation:!1},{name:"isolated-hploc",broadphase:"hploc",dispatchIsolation:!0},{name:"scalar-grid",broadphase:"grid",dispatchIsolation:!1,scalarPrimal:!0},{name:"scalar-isolated-grid",broadphase:"grid",dispatchIsolation:!0,scalarPrimal:!0},{name:"portable-contact-grid",broadphase:"grid",dispatchIsolation:!1,portableContactMath:!0},{name:"portable-contact-isolated-grid",broadphase:"grid",dispatchIsolation:!0,scalarPrimal:!0,portableContactMath:!0}];function mc(s){return va.has(s)||va.set(s,Cf(s)),va.get(s)}async function Cf(s,e){let t=[];for(let i of pc){let r=await _f(s,i,e);if(t.push(r),!!r.passed)return uc(s,{dispatchIsolation:i.dispatchIsolation,scalarPrimal:i.scalarPrimal??!1,portableContactMath:i.portableContactMath??!1,broadphase:i.broadphase==="hploc"?"hploc":void 0}),{...r,selected:i.name,compatibility:i.name!==pc[0].name,attempts:t}}return{...t[0],selected:null,compatibility:!1,attempts:t}}function Sf(s){let e=new ai;return e.iterations=5,s||(e.gravity=0),new Ze(e,[16,.25,16],0,.6,[0,-.125,0]),new Ze(e,[1,1,1],1,.6,[-2,s?2:.45,0]),nr(e,.5,1,.6,[0,s?2.3:.45,0]),Br(e,.25,1.6,1,.6,[2,s?2.5:.75,0]),e}async function bi(s,e,t=e.size){let i=s.createBuffer({size:t,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST});try{let r=s.createCommandEncoder();return r.copyBufferToBuffer(e,0,i,0,t),s.queue.submit([r.finish()]),await i.mapAsync(GPUMapMode.READ),i.getMappedRange().slice(0)}finally{i.destroy()}}async function kf(s){s.step();let e=await s.readCounters(),t=new Uint32Array(await bi(s.device,s.argsBuffer)),i=await Lf(s),r=new Uint32Array(i),o=new Float32Array(i),n=new Uint32Array(await bi(s.device,s.adjBuffer)),a=new Uint32Array(await bi(s.device,s.colorBuffer)),{manifolds:l,contacts:c}=s.contactStorage,u=await bi(s.device,l,Math.max(32,e.manifolds*32)),f=new Uint32Array(u),d=new Float32Array(u),p=new Float32Array(await bi(s.device,c,Math.max(64,e.contacts*64))),m=await s.readBodies(),h=e.manifolds>=3?await Pf(s):[],g=h.some(({contactEvaluation:b})=>b.returnedForce===0&&b.independentForce<-1e-5);return{expectedFloorPairs:3,counters:e,pairs:e.pairs?Array.from(await s.readPairs()):[],narrowphaseWorkgroups:Array.from(t.subarray(0,3)),solver:{scalarPrimal:s.scalarPrimal,portableContactMath:s.portableContactMath,lanes:[...s.primalLanes],contactWorkgroups:Array.from(t.subarray(3,6)),dualWorkgroups:Array.from(t.subarray(9,12)),colorWorkgroups:Array.from(t.subarray(12,12+3*s.colorCap)),adjacencyStarts:Array.from(n.subarray(0,5)),adjacencyEntries:Array.from(n.subarray(2*s.bodyCapacity+1,2*s.bodyCapacity+1+n[4])),colorStarts:Array.from(a.subarray(2*s.bodyCapacity,2*s.bodyCapacity+s.colorCap+1)),colorBodies:Array.from(a.subarray(2*s.bodyCapacity+65,2*s.bodyCapacity+68)),positionsAfterOverlap:[1,2,3].map(b=>Array.from(m.subarray(b*40,b*40+3))),manifolds:Array.from({length:e.manifolds},(b,y)=>({ids:Array.from(f.subarray(y*8,y*8+4)),normalAndFriction:Array.from(d.subarray(y*8+4,y*8+8))})),contacts:Array.from({length:e.contacts},(b,y)=>({anchorA:Array.from(p.subarray(y*16,y*16+3)),anchorB:Array.from(p.subarray(y*16+4,y*16+7)),gap:p[y*16+7],penalty:Array.from(p.subarray(y*16+8,y*16+11)),force:Array.from(p.subarray(y*16+12,y*16+15))})),serialSystems:h,failure:g?"contact-evaluation":null},filters:Array.from(new Uint32Array(await bi(s.device,s.filterBuffer))),params:{bodyCount:r[0],largeCount:r[1],noCollideCount:r[2],pairCapacity:r[3],contactCapacity:r[4],dt:o[5],cellSize:o[6],maxSmallRadius:o[7],up:Array.from(o.subarray(8,11)),alpha:o[11]},stage:e.pairs<3?"collision-pairs":e.manifolds<3?"contact-generation":"contacts-created"}}async function Pf(s){let e=s.portableContactMath?"bitcast<f32>(pc.data.y)":"pc.alpha",t=s.portableContactMath?"k.anchorB.w":"k.c0x",i=s.portableContactMath?"k.penalty.x":"k.pen.x",r=s.portableContactMath?"k.force.x":"k.lam.x",o=s.device.createShaderModule({code:s.solveSource(Ge)+`
3408
3614
  @compute @workgroup_size(1) fn inspectSystems(@builtin(global_invocation_id) gid: vec3u) {
3409
3615
  let acc = accumulate(gid.x + 1u, 0u, 1u);
3410
3616
  joints[gid.x].penLin = vec4f(acc.lin[0][0], acc.lin[1][1], acc.lin[2][2], 0.0);
@@ -3428,7 +3634,7 @@ ${sl.replaceAll("id.x","(id.x+id.y*DISPATCH_STRIDE)")}`}),entryPoint:"capture"}}
3428
3634
  let raw = ${i} * expectedC + ${r};
3429
3635
  joints[gid.x].rA = vec4f(${t}, ${e}, result.C.x, result.F.x);
3430
3636
  joints[gid.x].rB = vec4f(${i}, ${r}, expectedC, min(raw, 0.0));
3431
- }`}),n=s.device.createComputePipeline({layout:s.device.createPipelineLayout({bindGroupLayouts:[s.layouts.solve,s.layouts.pass]}),compute:{module:o,entryPoint:"inspectSystems"}}),a=s.device.createCommandEncoder(),l=a.beginComputePass();l.setPipeline(n),l.setBindGroup(0,s.groups.solve[1-s.parity]),l.setBindGroup(1,s.passGroup,[0]),l.dispatchWorkgroups(3),l.end(),s.device.queue.submit([a.finish()]);let c=new Float32Array(await mi(s.device,s.jointBuffer,384));return[0,1,2].map(u=>({linearDiagonal:Array.from(c.subarray(u*32,u*32+3)),angularDiagonal:Array.from(c.subarray(u*32+4,u*32+7)),linearForce:Array.from(c.subarray(u*32+16,u*32+19)),angularForce:Array.from(c.subarray(u*32+20,u*32+23)),contactEvaluation:{inputGap:c[u*32+24],passAlpha:c[u*32+25],returnedError:c[u*32+26],returnedForce:c[u*32+27],inputPenalty:c[u*32+28],inputForce:c[u*32+29],independentError:c[u*32+30],independentForce:c[u*32+31]}}))}async function Pu(s){let{device:e}=s,t=e.createBuffer({size:48,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC});try{let i=e.createComputePipeline({layout:"auto",compute:{module:e.createShaderModule({code:Ae+`
3637
+ }`}),n=s.device.createComputePipeline({layout:s.device.createPipelineLayout({bindGroupLayouts:[s.layouts.solve,s.layouts.pass]}),compute:{module:o,entryPoint:"inspectSystems"}}),a=s.device.createCommandEncoder(),l=a.beginComputePass();l.setPipeline(n),l.setBindGroup(0,s.groups.solve[1-s.parity]),l.setBindGroup(1,s.passGroup,[0]),l.dispatchWorkgroups(3),l.end(),s.device.queue.submit([a.finish()]);let c=new Float32Array(await bi(s.device,s.jointBuffer,384));return[0,1,2].map(u=>({linearDiagonal:Array.from(c.subarray(u*32,u*32+3)),angularDiagonal:Array.from(c.subarray(u*32+4,u*32+7)),linearForce:Array.from(c.subarray(u*32+16,u*32+19)),angularForce:Array.from(c.subarray(u*32+20,u*32+23)),contactEvaluation:{inputGap:c[u*32+24],passAlpha:c[u*32+25],returnedError:c[u*32+26],returnedForce:c[u*32+27],inputPenalty:c[u*32+28],inputForce:c[u*32+29],independentError:c[u*32+30],independentForce:c[u*32+31]}}))}async function Lf(s){let{device:e}=s,t=e.createBuffer({size:48,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC});try{let i=e.createComputePipeline({layout:"auto",compute:{module:e.createShaderModule({code:ge+`
3432
3638
  @group(0) @binding(0) var<uniform> p: Params;
3433
3639
  @group(0) @binding(1) var<storage,read_write> out: array<u32>;
3434
3640
  @compute @workgroup_size(1) fn inspectParams() {
@@ -3437,7 +3643,7 @@ ${sl.replaceAll("id.x","(id.x+id.y*DISPATCH_STRIDE)")}`}),entryPoint:"capture"}}
3437
3643
  out[5]=bitcast<u32>(p.dt); out[6]=bitcast<u32>(p.cellSize); out[7]=bitcast<u32>(p.maxSmallRadius);
3438
3644
  out[8]=bitcast<u32>(p.up.x); out[9]=bitcast<u32>(p.up.y); out[10]=bitcast<u32>(p.up.z);
3439
3645
  out[11]=bitcast<u32>(p.alpha);
3440
- }`}),entryPoint:"inspectParams"}}),r=e.createBindGroup({layout:i.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:s.paramsBuffer}},{binding:1,resource:{buffer:t}}]}),o=e.createCommandEncoder(),n=o.beginComputePass();return n.setPipeline(i),n.setBindGroup(0,r),n.dispatchWorkgroups(1),n.end(),e.queue.submit([o.finish()]),await mi(e,t)}finally{t.destroy()}}async function Lu(s,e,t){let i={mode:e.name,passed:!1,steps:180,cases:[],errors:[],contactCache:"normal-float-generations-v1",diagnosticVersion:4,limits:{storageBindings:s.limits.maxStorageBuffersPerShaderStage,workgroupStorageBytes:s.limits.maxComputeWorkgroupStorageSize,workgroupInvocations:s.limits.maxComputeInvocationsPerWorkgroup,storageBindingBytes:s.limits.maxStorageBufferBindingSize}},r,o=n=>{let a=new pi(s,Cu(n),{spatialSort:!1,bodyCapacity:4,broadphase:e.broadphase,scalarPrimal:e.scalarPrimal??!1,portableContactMath:e.portableContactMath??!1,capacity:{pairs:32,manifolds:32,contacts:256,colors:8}});return a.params.up=[0,1,0],a.dispatchIsolation=e.dispatchIsolation,t?.(a,e,n),a};s.pushErrorScope("validation");try{if(r=o(!1),i.pipeline=await Su(r),i.pipeline.stage!=="contacts-created")i.reason=i.pipeline.stage==="collision-pairs"?"The GPU did not find the three known overlapping floor pairs.":"The GPU found overlapping pairs but did not create all floor contacts.";else{r.destroy(),r=o(!0);let n=0;i.samples=[];for(let l=0;l<i.steps;l++){if(r.step(),(l+1)%30&&l!==39)continue;let c=await r.readCounters();if(i.samples.push({step:l+1,...c}),c.manifolds&&n++,c.overflow||c.clashes)throw Error("Incomplete GPU contact graph")}let a=await r.readBodies();for(let l=1;l<4;l++){let c=l*40,[u,f,d,p]=a.subarray(c+4,c+8),g=l===1?.5*(Math.abs(2*(u*f+p*d))+Math.abs(1-2*(u*u+d*d))+Math.abs(2*(f*d-p*u))):l===2?.5:.25+.55*Math.abs(1-2*(u*u+d*d)),h=a[c+1]-g,m=a.subarray(c,c+40).every(Number.isFinite);i.cases.push({shape:["floor","box","sphere","capsule"][l],passed:m&&h>=-.06&&h<.12,floorGap:h,position:Array.from(a.subarray(c,c+3))})}i.contactSteps=n,i.passed=n>0&&i.cases.every(l=>l.passed),i.passed||(i.reason=i.pipeline.solver.failure==="contact-evaluation"?"The GPU created floor contacts but returned zero force where a push was required.":"The GPU did not keep all three falling shapes on the floor.")}}catch(n){i.errors.push(n.message)}finally{try{let n=await s.popErrorScope();n&&i.errors.push(n.message)}catch(n){i.errors.push(n.message)}r?.destroy()}return i.passed=i.passed&&!i.errors.length,i}async function Jr(s={}){if(!globalThis.navigator?.gpu)throw Error("WebGPU needs a supported browser on localhost or HTTPS");let e=await navigator.gpu.requestAdapter({powerPreference:s.powerPreference??"high-performance"});if(!e)throw Error("No WebGPU adapter is available");let t={};for(let[r,o]of Object.entries(s.preferredLimits??{})){if(!r.startsWith("max")||e.limits[r]===void 0||!Number.isSafeInteger(o)||o<0)throw Error(`Invalid preferred GPU limit: ${r}`);t[r]=Math.min(o,e.limits[r])}for(let[r,o]of Object.entries(s.requiredLimits??{})){if(e.limits[r]===void 0||!Number.isSafeInteger(o)||o<0)throw Error(`Invalid required GPU limit: ${r}`);let n=e.limits[r];if(r.startsWith("min")&&o<n||!r.startsWith("min")&&o>n)throw Error(`GPU limit ${r} requires ${o}; this adapter supports ${n}`);t[r]=o}let i=await e.requestDevice({requiredLimits:t,requiredFeatures:e.features.has("timestamp-query")?["timestamp-query"]:[]});if(s.validate3D)try{await xr(i)}catch(r){throw i.destroy(),r}return{adapter:e,device:i}}async function xr(s){if(qs(s))return s;let e=await Sl(s);if(!e.passed)throw Error(`GPU 3D contact check failed: ${e.reason??e.errors.join("; ")}`);return s}var kl=`struct Body { pos:vec4f,rot:vec4f,initialPos:vec4f,initialRot:vec4f,size:vec4f,moment:vec4f,inertialPos:vec4f,inertialRot:vec4f,velocity:vec4f,angular:vec4f }
3646
+ }`}),entryPoint:"inspectParams"}}),r=e.createBindGroup({layout:i.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:s.paramsBuffer}},{binding:1,resource:{buffer:t}}]}),o=e.createCommandEncoder(),n=o.beginComputePass();return n.setPipeline(i),n.setBindGroup(0,r),n.dispatchWorkgroups(1),n.end(),e.queue.submit([o.finish()]),await bi(e,t)}finally{t.destroy()}}async function _f(s,e,t){let i={mode:e.name,passed:!1,steps:180,cases:[],errors:[],contactCache:"normal-float-generations-v1",diagnosticVersion:4,limits:{storageBindings:s.limits.maxStorageBuffersPerShaderStage,workgroupStorageBytes:s.limits.maxComputeWorkgroupStorageSize,workgroupInvocations:s.limits.maxComputeInvocationsPerWorkgroup,storageBindingBytes:s.limits.maxStorageBufferBindingSize}},r,o=n=>{let a=new gi(s,Sf(n),{spatialSort:!1,bodyCapacity:4,smallGroups:!1,broadphase:e.broadphase,scalarPrimal:e.scalarPrimal??!1,portableContactMath:e.portableContactMath??!1,capacity:{pairs:32,manifolds:32,contacts:256,colors:8}});return a.params.up=[0,1,0],a.dispatchIsolation=e.dispatchIsolation,t?.(a,e,n),a};s.pushErrorScope("validation");try{if(r=o(!1),i.pipeline=await kf(r),i.pipeline.stage!=="contacts-created")i.reason=i.pipeline.stage==="collision-pairs"?"The GPU did not find the three known overlapping floor pairs.":"The GPU found overlapping pairs but did not create all floor contacts.";else{r.destroy(),r=o(!0);let n=0;i.samples=[];for(let l=0;l<i.steps;l++){if(r.step(),(l+1)%30&&l!==39)continue;let c=await r.readCounters();if(i.samples.push({step:l+1,...c}),c.manifolds&&n++,c.overflow||c.clashes)throw Error("Incomplete GPU contact graph")}let a=await r.readBodies();for(let l=1;l<4;l++){let c=l*40,[u,f,d,p]=a.subarray(c+4,c+8),m=l===1?.5*(Math.abs(2*(u*f+p*d))+Math.abs(1-2*(u*u+d*d))+Math.abs(2*(f*d-p*u))):l===2?.5:.25+.55*Math.abs(1-2*(u*u+d*d)),h=a[c+1]-m,g=a.subarray(c,c+40).every(Number.isFinite);i.cases.push({shape:["floor","box","sphere","capsule"][l],passed:g&&h>=-.06&&h<.12,floorGap:h,position:Array.from(a.subarray(c,c+3))})}i.contactSteps=n,i.passed=n>0&&i.cases.every(l=>l.passed),i.passed||(i.reason=i.pipeline.solver.failure==="contact-evaluation"?"The GPU created floor contacts but returned zero force where a push was required.":"The GPU did not keep all three falling shapes on the floor.")}}catch(n){i.errors.push(n.message)}finally{try{let n=await s.popErrorScope();n&&i.errors.push(n.message)}catch(n){i.errors.push(n.message)}r?.destroy()}return i.passed=i.passed&&!i.errors.length,i}async function ss(s={}){if(!globalThis.navigator?.gpu)throw Error("WebGPU needs a supported browser on localhost or HTTPS");let e=await navigator.gpu.requestAdapter({powerPreference:s.powerPreference??"high-performance"});if(!e)throw Error("No WebGPU adapter is available");let t={};for(let[r,o]of Object.entries(s.preferredLimits??{})){if(!r.startsWith("max")||e.limits[r]===void 0||!Number.isSafeInteger(o)||o<0)throw Error(`Invalid preferred GPU limit: ${r}`);t[r]=Math.min(o,e.limits[r])}for(let[r,o]of Object.entries(s.requiredLimits??{})){if(e.limits[r]===void 0||!Number.isSafeInteger(o)||o<0)throw Error(`Invalid required GPU limit: ${r}`);let n=e.limits[r];if(r.startsWith("min")&&o<n||!r.startsWith("min")&&o>n)throw Error(`GPU limit ${r} requires ${o}; this adapter supports ${n}`);t[r]=o}let i=await e.requestDevice({requiredLimits:t,requiredFeatures:e.features.has("timestamp-query")?["timestamp-query"]:[]});if(s.validate3D)try{await Cr(i)}catch(r){throw i.destroy(),r}return{adapter:e,device:i}}async function Cr(s){if(uo(s))return s;let e=await mc(s);if(!e.passed)throw Error(`GPU 3D contact check failed: ${e.reason??e.errors.join("; ")}`);return s}var gc=`struct Body { pos:vec4f,rot:vec4f,initialPos:vec4f,initialRot:vec4f,size:vec4f,moment:vec4f,inertialPos:vec4f,inertialRot:vec4f,velocity:vec4f,angular:vec4f }
3441
3647
  struct Command { index:u32,mask:u32,pad0:u32,pad1:u32,velocity:vec4f,angular:vec4f,impulse:vec4f,torque:vec4f,position:vec4f,rotation:vec4f,pointImpulse:vec4f }
3442
3648
  @group(0) @binding(0) var<storage,read_write> bodies:array<Body>;
3443
3649
  @group(0) @binding(1) var<storage,read> commands:array<Command>;
@@ -3455,11 +3661,17 @@ fn rotate(q:vec4f,v:vec3f)->vec3f {let t=2.*cross(q.xyz,v);return v+q.w*t+cross(
3455
3661
  let local=rotate(vec4f(-b.rot.xyz,b.rot.w),torque);
3456
3662
  b.angular=vec4f(b.angular.xyz+rotate(b.rot,local/max(b.moment.xyz,vec3f(1.e-10))),b.angular.w);
3457
3663
  }
3458
- if((c.mask&8u)!=0u){b.pos=vec4f(c.position.xyz,b.pos.w);b.rot=c.rotation;}
3664
+ if((c.mask&8u)!=0u){
3665
+ if((c.mask&32u)!=0u){
3666
+ // Position-only teleports preserve the live orientation, including the
3667
+ // principal-frame offset of meshes whose origin is not their mass centre.
3668
+ b.pos=vec4f(c.position.xyz+rotate(b.rot,c.rotation.xyz),b.pos.w);
3669
+ }else{b.pos=vec4f(c.position.xyz,b.pos.w);b.rot=c.rotation;}
3670
+ }
3459
3671
  if((c.mask&16u)!=0u){b.size.w=0.;b.moment=vec4f(vec3f(0),b.moment.w);b.velocity=vec4f(0);b.angular=vec4f(vec3f(0),b.angular.w);}
3460
3672
  bodies[c.index]=b;
3461
3673
  }
3462
- `;var Qt=class{constructor(e,t,i="linear"){this.solver=e,this.dimension=t,this.components=i==="angular"&&t===2?1:t;let r=e.device,o=t===3?10:6,n=t===3?i==="angular"?9:8:3;this.pipeline=r.createComputePipeline({layout:"auto",compute:{entryPoint:"setVelocities",module:r.createShaderModule({code:`
3674
+ `;var Kt=class{constructor(e,t,i="linear"){this.solver=e,this.dimension=t,this.components=i==="angular"&&t===2?1:t;let r=e.device,o=t===3?10:6,n=t===3?i==="angular"?9:8:3;this.pipeline=r.createComputePipeline({layout:"auto",compute:{entryPoint:"setVelocities",module:r.createShaderModule({code:`
3463
3675
  @group(0) @binding(0) var<storage,read_write> bodies:array<vec4f>;
3464
3676
  @group(0) @binding(1) var<storage,read> indices:array<u32>;
3465
3677
  @group(0) @binding(2) var<storage,read> velocities:array<f32>;
@@ -3470,7 +3682,7 @@ fn rotate(q:vec4f,v:vec3f)->vec3f {let t=2.*cross(q.xyz,v);return v+q.w*t+cross(
3470
3682
  var v=bodies[base];
3471
3683
  ${this.components===1?"v.z=velocities[i];":`v.x=velocities[i*${t}u];v.y=velocities[i*${t}u+1u];${t===3?"v.z=velocities[i*3u+2u];":""}`}
3472
3684
  bodies[base]=v;
3473
- }`})}})}set(e,t){let i=this.solver,r=i.device,o=e instanceof Uint32Array?e:Uint32Array.from(e),n=t instanceof Float32Array?t:Float32Array.from(t);if(n.length!==o.length*this.components)throw Error(`Provide ${this.components} velocity components per body`);let a=-1;for(let c=0;c<e.length;c++){if(i.liveIndex(e[c]),e[c]<=a)throw Error("Velocity batch indices must be unique and ascending GPU slots");a=e[c]}for(let c of n)if(!Number.isFinite(c))throw Error("Velocities must be finite Float32 values");let l=Math.min(r.limits.maxStorageBufferBindingSize,r.limits.maxBufferSize);if(o.byteLength>l||n.byteLength>l)throw Error("Velocity batch exceeds GPU buffer limits");o.length&&(i.wakeAll(),i.flushEdits(),this.submitValidated(o,n))}submitValidated(e,t,i){if(!e.length)return;let r=this.solver,o=r.device,n=Math.min(o.limits.maxStorageBufferBindingSize,o.limits.maxBufferSize);if(e.byteLength>n||t.byteLength>n)throw Error("Velocity batch exceeds GPU buffer limits");for(let[f,d]of[["indices",e],["values",t]])(!this[f]||this[f].size<d.byteLength)&&(this[f]?.destroy(),this[f]=o.createBuffer({size:Math.min(n,d.byteLength*2),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST})),o.queue.writeBuffer(this[f],0,d);let a=i??o.createCommandEncoder(),l=a.beginComputePass();l.setPipeline(this.pipeline),(!this.binding||this.boundBody!==r.bodyBuffer||this.boundIndices!==this.indices||this.boundValues!==this.values||this.boundBytes!==t.byteLength)&&(this.binding=o.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:r.bodyBuffer}},{binding:1,resource:{buffer:this.indices,size:e.byteLength}},{binding:2,resource:{buffer:this.values,size:t.byteLength}}]}),this.boundBody=r.bodyBuffer,this.boundIndices=this.indices,this.boundValues=this.values,this.boundBytes=t.byteLength),l.setBindGroup(0,this.binding);let c=Math.ceil(e.length/64),u=o.limits.maxComputeWorkgroupsPerDimension;l.dispatchWorkgroups(Math.min(c,u),Math.ceil(c/u)),l.end(),i||o.queue.submit([a.finish()]),this.lastBatch={bodies:e.length,uploadedBytes:e.byteLength+t.byteLength}}destroy(){this.indices?.destroy(),this.values?.destroy()}},gi=class{constructor(e,t){this.solver=e,this.dimension=t,this.wordsPerBody=t===3?8:5}set(e,{linear:t,angular:i}={}){let r=this.solver,o=this.dimension,n=o===3?3:1,a=e instanceof Uint32Array?e:Uint32Array.from(e),l=t===void 0?null:t instanceof Float32Array?t:Float32Array.from(t),c=i===void 0?null:i instanceof Float32Array?i:Float32Array.from(i);if(!l&&!c)throw Error("Provide linear and/or angular velocities");if(l&&l.length!==a.length*o)throw Error(`Provide ${o} linear components per body`);if(c&&c.length!==a.length*n)throw Error(`Provide ${n} angular components per body`);let u=-1;for(let p=0;p<e.length;p++){if(r.liveIndex(e[p]),e[p]<=u)throw Error("Velocity batch indices must be unique and ascending GPU slots");u=e[p]}for(let p of[l,c])if(p){for(let g of p)if(!Number.isFinite(g))throw Error("Velocities must be finite Float32 values")}let f=a.length*this.wordsPerBody,d=Math.min(r.device.limits.maxStorageBufferBindingSize,r.device.limits.maxBufferSize);if(f*4>d)throw Error("Motion batch exceeds GPU buffer limits");if(f){(!this.data||this.data.length<f)&&(this.data=new Uint32Array(Math.max(f,(this.data?.length??0)*2)),this.floats=new Float32Array(this.data.buffer));for(let p=0;p<a.length;p++){let g=p*this.wordsPerBody;if(this.data[g]=a[p],this.data[g+1]=(l?1:0)|(c?2:0),l)for(let h=0;h<o;h++)this.floats[g+2+h]=l[p*o+h];if(c)for(let h=0;h<n;h++)this.floats[g+2+o+h]=c[p*n+h]}r.wakeAll(),r.flushEdits(),this.submitValidated(this.data.subarray(0,f))}}submitValidated(e,t){if(!e.length)return;let i=this.solver,r=i.device,o=this.wordsPerBody,n=Math.min(r.limits.maxStorageBufferBindingSize,r.limits.maxBufferSize);if(e.byteLength>n)throw Error("Motion batch exceeds GPU buffer limits");(!this.buffer||this.buffer.size<e.byteLength)&&(this.buffer?.destroy(),this.buffer=r.createBuffer({size:Math.min(n,e.byteLength*2),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST})),r.queue.writeBuffer(this.buffer,0,e),this.pipeline??=r.createComputePipeline({layout:"auto",compute:{entryPoint:"edit",module:r.createShaderModule({code:`
3685
+ }`})}})}set(e,t){let i=this.solver,r=i.device,o=e instanceof Uint32Array?e:Uint32Array.from(e),n=t instanceof Float32Array?t:Float32Array.from(t);if(n.length!==o.length*this.components)throw Error(`Provide ${this.components} velocity components per body`);let a=-1;for(let c=0;c<e.length;c++){if(i.liveIndex(e[c]),e[c]<=a)throw Error("Velocity batch indices must be unique and ascending GPU slots");a=e[c]}for(let c of n)if(!Number.isFinite(c))throw Error("Velocities must be finite Float32 values");let l=Math.min(r.limits.maxStorageBufferBindingSize,r.limits.maxBufferSize);if(o.byteLength>l||n.byteLength>l)throw Error("Velocity batch exceeds GPU buffer limits");o.length&&(i.wakeAll(),i.flushEdits(),this.submitValidated(o,n))}submitValidated(e,t,i){if(!e.length)return;let r=this.solver,o=r.device,n=Math.min(o.limits.maxStorageBufferBindingSize,o.limits.maxBufferSize);if(e.byteLength>n||t.byteLength>n)throw Error("Velocity batch exceeds GPU buffer limits");for(let[f,d]of[["indices",e],["values",t]])(!this[f]||this[f].size<d.byteLength)&&(this[f]?.destroy(),this[f]=o.createBuffer({size:Math.min(n,d.byteLength*2),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST})),o.queue.writeBuffer(this[f],0,d);let a=i??o.createCommandEncoder(),l=a.beginComputePass();l.setPipeline(this.pipeline),(!this.binding||this.boundBody!==r.bodyBuffer||this.boundIndices!==this.indices||this.boundValues!==this.values||this.boundBytes!==t.byteLength)&&(this.binding=o.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:r.bodyBuffer}},{binding:1,resource:{buffer:this.indices,size:e.byteLength}},{binding:2,resource:{buffer:this.values,size:t.byteLength}}]}),this.boundBody=r.bodyBuffer,this.boundIndices=this.indices,this.boundValues=this.values,this.boundBytes=t.byteLength),l.setBindGroup(0,this.binding);let c=Math.ceil(e.length/64),u=o.limits.maxComputeWorkgroupsPerDimension;l.dispatchWorkgroups(Math.min(c,u),Math.ceil(c/u)),l.end(),i||o.queue.submit([a.finish()]),this.lastBatch={bodies:e.length,uploadedBytes:e.byteLength+t.byteLength}}destroy(){this.indices?.destroy(),this.values?.destroy()}},yi=class{constructor(e,t){this.solver=e,this.dimension=t,this.wordsPerBody=t===3?8:5}set(e,{linear:t,angular:i}={}){let r=this.solver,o=this.dimension,n=o===3?3:1,a=e instanceof Uint32Array?e:Uint32Array.from(e),l=t===void 0?null:t instanceof Float32Array?t:Float32Array.from(t),c=i===void 0?null:i instanceof Float32Array?i:Float32Array.from(i);if(!l&&!c)throw Error("Provide linear and/or angular velocities");if(l&&l.length!==a.length*o)throw Error(`Provide ${o} linear components per body`);if(c&&c.length!==a.length*n)throw Error(`Provide ${n} angular components per body`);let u=-1;for(let p=0;p<e.length;p++){if(r.liveIndex(e[p]),e[p]<=u)throw Error("Velocity batch indices must be unique and ascending GPU slots");u=e[p]}for(let p of[l,c])if(p){for(let m of p)if(!Number.isFinite(m))throw Error("Velocities must be finite Float32 values")}let f=a.length*this.wordsPerBody,d=Math.min(r.device.limits.maxStorageBufferBindingSize,r.device.limits.maxBufferSize);if(f*4>d)throw Error("Motion batch exceeds GPU buffer limits");if(f){(!this.data||this.data.length<f)&&(this.data=new Uint32Array(Math.max(f,(this.data?.length??0)*2)),this.floats=new Float32Array(this.data.buffer));for(let p=0;p<a.length;p++){let m=p*this.wordsPerBody;if(this.data[m]=a[p],this.data[m+1]=(l?1:0)|(c?2:0),l)for(let h=0;h<o;h++)this.floats[m+2+h]=l[p*o+h];if(c)for(let h=0;h<n;h++)this.floats[m+2+o+h]=c[p*n+h]}r.wakeAll(),r.flushEdits(),this.submitValidated(this.data.subarray(0,f))}}submitValidated(e,t){if(!e.length)return;let i=this.solver,r=i.device,o=this.wordsPerBody,n=Math.min(r.limits.maxStorageBufferBindingSize,r.limits.maxBufferSize);if(e.byteLength>n)throw Error("Motion batch exceeds GPU buffer limits");(!this.buffer||this.buffer.size<e.byteLength)&&(this.buffer?.destroy(),this.buffer=r.createBuffer({size:Math.min(n,e.byteLength*2),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST})),r.queue.writeBuffer(this.buffer,0,e),this.pipeline??=r.createComputePipeline({layout:"auto",compute:{entryPoint:"edit",module:r.createShaderModule({code:`
3474
3686
  @group(0) @binding(0) var<storage,read_write> bodies:array<vec4f>;
3475
3687
  @group(0) @binding(1) var<storage,read> commands:array<u32>;
3476
3688
  @compute @workgroup_size(64) fn edit(@builtin(global_invocation_id) id:vec3u) {
@@ -3482,14 +3694,14 @@ fn rotate(q:vec4f,v:vec3f)->vec3f {let t=2.*cross(q.xyz,v);return v+q.w*t+cross(
3482
3694
  if((mask&1u)!=0u){v.x=bitcast<f32>(commands[o+2u]);v.y=bitcast<f32>(commands[o+3u]);${this.dimension===3?"v.z=bitcast<f32>(commands[o+4u]);":""}}
3483
3695
  ${this.dimension===2?"if((mask&2u)!=0u){v.z=bitcast<f32>(commands[o+4u]);}":"if((mask&2u)!=0u){var a=bodies[b+9u];a.xyz=vec3f(bitcast<f32>(commands[o+5u]),bitcast<f32>(commands[o+6u]),bitcast<f32>(commands[o+7u]));bodies[b+9u]=a;}"}
3484
3696
  bodies[b+${this.dimension===3?8:3}u]=v;
3485
- }`})}}),(!this.binding||this.boundBody!==i.bodyBuffer||this.boundBuffer!==this.buffer||this.boundBytes!==e.byteLength)&&(this.binding=r.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:i.bodyBuffer}},{binding:1,resource:{buffer:this.buffer,size:e.byteLength}}]}),this.boundBody=i.bodyBuffer,this.boundBuffer=this.buffer,this.boundBytes=e.byteLength);let a=t??r.createCommandEncoder(),l=a.beginComputePass();l.setPipeline(this.pipeline),l.setBindGroup(0,this.binding);let c=Math.ceil(e.length/o/64),u=r.limits.maxComputeWorkgroupsPerDimension;l.dispatchWorkgroups(Math.min(c,u),Math.ceil(c/u)),l.end(),t||r.queue.submit([a.finish()]),this.lastBatch={bodies:e.length/o,uploadedBytes:e.byteLength}}destroy(){this.buffer?.destroy(),this.binding=null,this.data=this.floats=null}};function Ws(s,e={}){return br({...e,requested:e.solverMode??"auto",bodyCount:s.bodies.length,custom:!!e.shaders?.solve}),{...e,solverMode:e.solverMode??"auto"}}function wr(s,e){let t=s&&typeof s.x=="number"?[s.x,s.y,s.z]:Array.from(s);if(t.length!==3||!t.every(Number.isFinite))throw Error(`${e} requires three finite components`);return t}function Hs(s,e){if(s!==1/0&&(!Number.isFinite(s)||s<0))throw Error(`${e} must be nonnegative or Infinity`);return s}function Pl(s,e){let t=wr(e,"anchor");if(!s)return t;let i=s.aggregate,r=i.mesh.position.constructor;return new r(...t).subtract(i.localCenter).applyRotationQuaternion(i.localRotation.conjugate()).asArray()}var $r=class{constructor(e,t,i,r={}){e.assertAlive();for(let n of[t,i])if(n&&(n.assertAlive(),n.aggregate.world!==e))throw Error("Constraint bodies must belong to this world");if(!i||t===i)throw Error("A constraint needs a body B and distinct endpoints");let o=r.type??"ball";if(!["ball","fixed","spring","motor","limit"].includes(o))throw Error("Constraint type must be ball, fixed, spring, motor or limit");if(o==="spring"&&!t)throw Error("A spring requires two bodies; use a static aggregate for a world anchor");if(this.world=e,this.bodyA=t,this.bodyB=i,this.type=o,o==="motor"||o==="limit"){let n=(a,l)=>a?new a.aggregate.mesh.position.constructor(...wr(l,"axis")).applyRotationQuaternion(a.aggregate.localRotation.conjugate()).asArray():wr(l,"axis");this.angularMaterial=kt({...r,type:o,axisA:n(t,r.axisA??[0,1,0]),axisB:n(i,r.axisB??[0,1,0])})}if(this.anchorA=Pl(t,r.anchorA??[0,0,0]),this.anchorB=Pl(i,r.anchorB??[0,0,0]),this.linear=Hs(o==="spring"?r.stiffness??1e3:r.stiffness??1/0,"stiffness"),this.angular=o==="fixed"?Hs(r.angularStiffness??1/0,"angularStiffness"):0,this.breakForce=Hs(r.breakForce??1/0,"breakForce"),this.breakForce===0)throw Error("breakForce must be positive");if(this.material=It({breakForce:this.breakForce,breakStrain:r.breakStrain}),o!=="spring"&&r.breakStrain!==void 0)throw Error("breakStrain applies to springs only");if(this.breakOnPull=r.breakOnPull??!1,this.rest=r.rest,this.rest!==void 0&&(!Number.isFinite(this.rest)||this.rest<0))throw Error("Spring rest length must be nonnegative and finite");if(o==="spring"&&!Number.isFinite(this.linear))throw Error("Spring stiffness must be finite");e.gpu?(e.flushCommands(),this.attach()):this.force=o==="spring"?new ut(e.ref,t.aggregate.rigid,i.aggregate.rigid,this.anchorA,this.anchorB,this.linear,this.rest??-1):new ke(e.ref,t?.aggregate.rigid??null,i.aggregate.rigid,this.anchorA,this.anchorB,this.linear,this.angular,this.breakForce),this.force&&o==="spring"&&gr(this.force,this.material),this.force&&this.angularMaterial&&vr(this.force,this.angularMaterial),e.constraints.add(this),e.wakeAll?.()}attach(e,t=!0){let i=this.world.gpu;if(e!==void 0?this.slot=e:this.type==="spring"?[this.slot]=i.appendSprings([{a:this.bodyA.gpuIndex,b:this.bodyB.gpuIndex,rA:this.anchorA,rB:this.anchorB,stiffness:this.linear,rest:this.rest??0}]):this.slot=i.appendJoint(this.bodyA?.gpuIndex??-1,this.bodyB.gpuIndex,this.anchorA,this.anchorB,this.linear,this.angular),this.angularMaterial&&i.setAngularConstraint(this.slot,this.angularMaterial),this.type==="spring"&&(Number.isFinite(this.material.breakStrain)||Number.isFinite(this.material.breakForce))&&i.setSpringMaterial(this.slot,this.material),this.type!=="spring"&&Number.isFinite(this.breakForce)){let r=Number.isFinite(this.breakForce)?this.breakForce:1e30;i.device.queue.writeBuffer(i.jointBuffer,(this.slot*32+11)*4,new Float32Array([this.breakOnPull?-r:r]))}t&&(this.type==="fixed"||this.type==="spring"&&this.rest===void 0)&&i.captureConstraintFrames([{slot:this.slot,spring:this.type==="spring"}])}assertAlive(){if(this.world.assertAlive(),this.disposed)throw Error("Constraint is disposed")}setWorldAnchor(e){if(this.assertAlive(),this.bodyA||this.type==="spring")throw Error("Only world-anchored joints have a movable world anchor");return this.anchorA=wr(e,"world anchor"),this.world.gpu?this.world.gpu.setWorldAnchor(this.slot,this.anchorA):this.force.rA.set(this.anchorA),this.world.wakeAll?.(),this}async readState(){this.assertAlive(),this.world.initialize();let e=this.world.gpu,t=this.world.device,i=t.createBuffer({size:128,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ});try{let r=t.createCommandEncoder();r.copyBufferToBuffer(e.jointBuffer,this.slot*128,i,0,128),t.queue.submit([r.finish()]),await i.mapAsync(GPUMapMode.READ);let o=new Float32Array(i.getMappedRange().slice(0));return{broken:o[3]===0&&o[7]===0,linearForce:Array.from(o.subarray(8,11)),angularForce:Array.from(o.subarray(12,15))}}finally{i.destroy()}}setMotor(e){if(this.assertAlive(),this.type!=="motor")throw Error("setMotor requires a motor constraint");return this.angularMaterial=kt({...this.angularMaterial,...e}),this.world.gpu?this.world.gpu.setMotor(this.slot,e):vr(this.force,this.angularMaterial),this.world.wakeAll(),this}dispose(){this.disposed||(this.world.disposed||(this.world.gpu?this.world.gpu.releaseJoints([this.slot]):this.force.destroy(),this.world.wakeAll?.()),this.world.constraints.delete(this),this.disposed=!0)}},Xr=class{constructor(e,t,i,r={}){let o=kt({...r,type:"limit"}),n=r.span??1;if(!Number.isFinite(n)||n<=0)throw Error("Hinge span must be positive");let a=wr(r.anchorA??[0,0,0],"anchorA"),l=wr(r.anchorB??[0,0,0],"anchorB");r.motor&&kt({...r.motor,type:"motor",axisA:o.axisA,axisB:o.axisB}),this.world=e,this.bodyA=t,this.bodyB=i,this.disposed=!1,this.joints=[-1,1].map(c=>e.addJoint(t,i,{anchorA:a.map((u,f)=>u+c*n*.5*o.axisA[f]),anchorB:l.map((u,f)=>u+c*n*.5*o.axisB[f]),stiffness:r.stiffness??1/0})),(r.minAngle!==void 0||r.maxAngle!==void 0)&&(this.limit=e.addConstraint(t,i,{...o,type:"limit"})),r.motor&&(this.motor=e.addMotor(t,i,{axisA:o.axisA,axisB:o.axisB,...r.motor}))}dispose(){if(!this.disposed){for(let e of[...this.joints,this.limit,this.motor])e?.dispose();this.disposed=!0}}};var bi=class{constructor(e){this.device=e,this.pipelines=new Map,this.idle=[],this.jobs=new Set,this.destroyed=!1}acquire(e,t){if(this.destroyed)throw Error("Pose readback has been destroyed");let i=this.device;if(e>i.limits.maxStorageBufferBindingSize||t>Math.min(i.limits.maxStorageBufferBindingSize,i.limits.maxBufferSize))throw Error("Pose selection exceeds GPU buffer limits");let r=this.idle.findIndex(n=>n.selection.size>=e&&n.selected.size>=t),o=r>=0?this.idle.splice(r,1)[0]:this.idle.pop()??{};for(let[n,a,l]of[["selection",e,GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST],["selected",t,GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC],["staging",t,GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST]])(!o[n]||o[n].size<a)&&(o[n]?.destroy(),o[n]=i.createBuffer({size:a,usage:l}));return this.jobs.add(o),o}release(e){if(e.staging.unmap(),!this.destroyed&&e.selected.size<=8*1024*1024&&this.idle.length<2)this.idle.push(e);else{for(let t of["selection","selected","staging"])e[t].destroy();this.jobs.delete(e)}}destroy(){this.destroyed=!0;for(let e of this.jobs)for(let t of["selection","selected","staging"])e[t].destroy();this.jobs.clear(),this.idle.length=0}async read(e,t,i=!1,r=10){if(!t.length)return new Float32Array;let o=i?r===6?1:2:r,n=this.device,a=n.limits.maxComputeWorkgroupsPerDimension,l=`${r}:${o}`,c=this.pipelines.get(l);c||(c=n.createComputePipeline({layout:"auto",compute:{entryPoint:"gather",module:n.createShaderModule({code:`
3697
+ }`})}}),(!this.binding||this.boundBody!==i.bodyBuffer||this.boundBuffer!==this.buffer||this.boundBytes!==e.byteLength)&&(this.binding=r.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:i.bodyBuffer}},{binding:1,resource:{buffer:this.buffer,size:e.byteLength}}]}),this.boundBody=i.bodyBuffer,this.boundBuffer=this.buffer,this.boundBytes=e.byteLength);let a=t??r.createCommandEncoder(),l=a.beginComputePass();l.setPipeline(this.pipeline),l.setBindGroup(0,this.binding);let c=Math.ceil(e.length/o/64),u=r.limits.maxComputeWorkgroupsPerDimension;l.dispatchWorkgroups(Math.min(c,u),Math.ceil(c/u)),l.end(),t||r.queue.submit([a.finish()]),this.lastBatch={bodies:e.length/o,uploadedBytes:e.byteLength}}destroy(){this.buffer?.destroy(),this.binding=null,this.data=this.floats=null}};function ho(s,e={}){return xr({...e,requested:e.solverMode??"auto",bodyCount:s.bodies.length,custom:!!e.shaders?.solve}),{...e,solverMode:e.solverMode??"auto"}}function Sr(s,e){let t=s&&typeof s.x=="number"?[s.x,s.y,s.z]:Array.from(s);if(t.length!==3||!t.every(Number.isFinite))throw Error(`${e} requires three finite components`);return t}function po(s,e){if(s!==1/0&&(!Number.isFinite(s)||s<0))throw Error(`${e} must be nonnegative or Infinity`);return s}function bc(s,e){let t=Sr(e,"anchor");if(!s)return t;let i=s.aggregate,r=i.mesh.position.constructor;return new r(...t).subtract(i.localCenter).applyRotationQuaternion(i.localRotation.conjugate()).asArray()}var os=class{constructor(e,t,i,r={}){e.assertAlive();for(let n of[t,i])if(n&&(n.assertAlive(),n.aggregate.world!==e))throw Error("Constraint bodies must belong to this world");if(!i||t===i)throw Error("A constraint needs a body B and distinct endpoints");let o=r.type??"ball";if(!["ball","fixed","spring","motor","limit"].includes(o))throw Error("Constraint type must be ball, fixed, spring, motor or limit");if(o==="spring"&&!t)throw Error("A spring requires two bodies; use a static aggregate for a world anchor");if(this.world=e,this.bodyA=t,this.bodyB=i,this.type=o,o==="motor"||o==="limit"){let n=(a,l)=>a?new a.aggregate.mesh.position.constructor(...Sr(l,"axis")).applyRotationQuaternion(a.aggregate.localRotation.conjugate()).asArray():Sr(l,"axis");this.angularMaterial=kt({...r,type:o,axisA:n(t,r.axisA??[0,1,0]),axisB:n(i,r.axisB??[0,1,0])})}if(this.anchorA=bc(t,r.anchorA??[0,0,0]),this.anchorB=bc(i,r.anchorB??[0,0,0]),this.linear=po(o==="spring"?r.stiffness??1e3:r.stiffness??1/0,"stiffness"),this.angular=o==="fixed"?po(r.angularStiffness??1/0,"angularStiffness"):0,this.breakForce=po(r.breakForce??1/0,"breakForce"),this.breakForce===0)throw Error("breakForce must be positive");if(this.material=It({breakForce:this.breakForce,breakStrain:r.breakStrain}),o!=="spring"&&r.breakStrain!==void 0)throw Error("breakStrain applies to springs only");if(this.breakOnPull=r.breakOnPull??!1,this.rest=r.rest,this.rest!==void 0&&(!Number.isFinite(this.rest)||this.rest<0))throw Error("Spring rest length must be nonnegative and finite");if(o==="spring"&&!Number.isFinite(this.linear))throw Error("Spring stiffness must be finite");e.gpu?(e.flushCommands(),this.attach()):this.force=o==="spring"?new ft(e.ref,t.aggregate.rigid,i.aggregate.rigid,this.anchorA,this.anchorB,this.linear,this.rest??-1):new ke(e.ref,t?.aggregate.rigid??null,i.aggregate.rigid,this.anchorA,this.anchorB,this.linear,this.angular,this.breakForce),this.force&&o==="spring"&&vr(this.force,this.material),this.force&&this.angularMaterial&&wr(this.force,this.angularMaterial),e.constraints.add(this),e.wakeAll?.()}attach(e,t=!0){let i=this.world.gpu;if(e!==void 0?this.slot=e:this.type==="spring"?[this.slot]=i.appendSprings([{a:this.bodyA.gpuIndex,b:this.bodyB.gpuIndex,rA:this.anchorA,rB:this.anchorB,stiffness:this.linear,rest:this.rest??0}]):this.slot=i.appendJoint(this.bodyA?.gpuIndex??-1,this.bodyB.gpuIndex,this.anchorA,this.anchorB,this.linear,this.angular),this.angularMaterial&&i.setAngularConstraint(this.slot,this.angularMaterial),this.type==="spring"&&(Number.isFinite(this.material.breakStrain)||Number.isFinite(this.material.breakForce))&&i.setSpringMaterial(this.slot,this.material),this.type!=="spring"&&Number.isFinite(this.breakForce)){let r=Number.isFinite(this.breakForce)?this.breakForce:1e30;i.device.queue.writeBuffer(i.jointBuffer,(this.slot*32+11)*4,new Float32Array([this.breakOnPull?-r:r]))}t&&(this.type==="fixed"||this.type==="spring"&&this.rest===void 0)&&i.captureConstraintFrames([{slot:this.slot,spring:this.type==="spring"}])}assertAlive(){if(this.world.assertAlive(),this.disposed)throw Error("Constraint is disposed")}setWorldAnchor(e){if(this.assertAlive(),this.bodyA||this.type==="spring")throw Error("Only world-anchored joints have a movable world anchor");return this.anchorA=Sr(e,"world anchor"),this.world.gpu?this.world.gpu.setWorldAnchor(this.slot,this.anchorA):this.force.rA.set(this.anchorA),this.world.wakeAll?.(),this}async readState(){this.assertAlive(),this.world.initialize();let e=this.world.gpu,t=this.world.device,i=t.createBuffer({size:128,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ});try{let r=t.createCommandEncoder();r.copyBufferToBuffer(e.jointBuffer,this.slot*128,i,0,128),t.queue.submit([r.finish()]),await i.mapAsync(GPUMapMode.READ);let o=new Float32Array(i.getMappedRange().slice(0));return{broken:o[3]===0&&o[7]===0,linearForce:Array.from(o.subarray(8,11)),angularForce:Array.from(o.subarray(12,15))}}finally{i.destroy()}}setMotor(e){if(this.assertAlive(),this.type!=="motor")throw Error("setMotor requires a motor constraint");return this.angularMaterial=kt({...this.angularMaterial,...e}),this.world.gpu?this.world.gpu.setMotor(this.slot,e):wr(this.force,this.angularMaterial),this.world.wakeAll(),this}dispose(){this.disposed||(this.world.disposed||(this.world.gpu?this.world.gpu.releaseJoints([this.slot]):this.force.destroy(),this.world.wakeAll?.()),this.world.constraints.delete(this),this.disposed=!0)}},ns=class{constructor(e,t,i,r={}){let o=kt({...r,type:"limit"}),n=r.span??1;if(!Number.isFinite(n)||n<=0)throw Error("Hinge span must be positive");let a=Sr(r.anchorA??[0,0,0],"anchorA"),l=Sr(r.anchorB??[0,0,0],"anchorB");r.motor&&kt({...r.motor,type:"motor",axisA:o.axisA,axisB:o.axisB}),this.world=e,this.bodyA=t,this.bodyB=i,this.disposed=!1,this.joints=[-1,1].map(c=>e.addJoint(t,i,{anchorA:a.map((u,f)=>u+c*n*.5*o.axisA[f]),anchorB:l.map((u,f)=>u+c*n*.5*o.axisB[f]),stiffness:r.stiffness??1/0})),(r.minAngle!==void 0||r.maxAngle!==void 0)&&(this.limit=e.addConstraint(t,i,{...o,type:"limit"})),r.motor&&(this.motor=e.addMotor(t,i,{axisA:o.axisA,axisB:o.axisB,...r.motor}))}dispose(){if(!this.disposed){for(let e of[...this.joints,this.limit,this.motor])e?.dispose();this.disposed=!0}}};var vi=class{constructor(e){this.device=e,this.pipelines=new Map,this.idle=[],this.jobs=new Set,this.destroyed=!1}acquire(e,t){if(this.destroyed)throw Error("Pose readback has been destroyed");let i=this.device;if(e>i.limits.maxStorageBufferBindingSize||t>Math.min(i.limits.maxStorageBufferBindingSize,i.limits.maxBufferSize))throw Error("Pose selection exceeds GPU buffer limits");let r=this.idle.findIndex(n=>n.selection.size>=e&&n.selected.size>=t),o=r>=0?this.idle.splice(r,1)[0]:this.idle.pop()??{};for(let[n,a,l]of[["selection",e,GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST],["selected",t,GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC],["staging",t,GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST]])(!o[n]||o[n].size<a)&&(o[n]?.destroy(),o[n]=i.createBuffer({size:a,usage:l}));return this.jobs.add(o),o}release(e){if(e.staging.unmap(),!this.destroyed&&e.selected.size<=8*1024*1024&&this.idle.length<2)this.idle.push(e);else{for(let t of["selection","selected","staging"])e[t].destroy();this.jobs.delete(e)}}destroy(){this.destroyed=!0;for(let e of this.jobs)for(let t of["selection","selected","staging"])e[t].destroy();this.jobs.clear(),this.idle.length=0}async read(e,t,i=!1,r=10){if(!t.length)return new Float32Array;let o=i?r===6?1:2:r,n=this.device,a=n.limits.maxComputeWorkgroupsPerDimension,l=`${r}:${o}`,c=this.pipelines.get(l);c||(c=n.createComputePipeline({layout:"auto",compute:{entryPoint:"gather",module:n.createShaderModule({code:`
3486
3698
  @group(0) @binding(0) var<storage,read> bodies:array<vec4f>;
3487
3699
  @group(0) @binding(1) var<storage,read> indices:array<u32>;
3488
3700
  @group(0) @binding(2) var<storage,read_write> selected:array<vec4f>;
3489
3701
  @compute @workgroup_size(64) fn gather(@builtin(global_invocation_id) id:vec3u) {
3490
3702
  let i=id.x+id.y*${a*64}u; if(i>=arrayLength(&selected)){return;}
3491
3703
  selected[i]=bodies[indices[i/${o}u]*${r}u+i%${o}u];
3492
- }`})}}),this.pipelines.set(l,c));let u=t.length*o*16,f=this.acquire(t.length*4,u),{selection:d,selected:p,staging:g}=f;try{n.queue.writeBuffer(d,0,t instanceof Uint32Array?t:Uint32Array.from(t)),(!f.group||f.body!==e||f.pipeline!==c||f.boundSelection!==d||f.boundSelected!==p||f.indexBytes!==t.length*4||f.bytes!==u)&&(f.group=n.createBindGroup({layout:c.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:e}},{binding:1,resource:{buffer:d,size:t.length*4}},{binding:2,resource:{buffer:p,size:u}}]}),f.body=e,f.pipeline=c,f.boundSelection=d,f.boundSelected=p,f.indexBytes=t.length*4,f.bytes=u);let h=n.createCommandEncoder(),m=h.beginComputePass();m.setPipeline(c),m.setBindGroup(0,f.group);let b=Math.ceil(t.length*o/64);return m.dispatchWorkgroups(Math.min(b,a),Math.ceil(b/a)),m.end(),h.copyBufferToBuffer(p,0,g,0,u),n.queue.submit([h.finish()]),await g.mapAsync(GPUMapMode.READ,0,u),new Float32Array(g.getMappedRange(0,u).slice(0))}finally{this.release(f)}}};var Yn=4,Br=3,vi=1,Eu=2,Yr=`
3704
+ }`})}}),this.pipelines.set(l,c));let u=t.length*o*16,f=this.acquire(t.length*4,u),{selection:d,selected:p,staging:m}=f;try{n.queue.writeBuffer(d,0,t instanceof Uint32Array?t:Uint32Array.from(t)),(!f.group||f.body!==e||f.pipeline!==c||f.boundSelection!==d||f.boundSelected!==p||f.indexBytes!==t.length*4||f.bytes!==u)&&(f.group=n.createBindGroup({layout:c.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:e}},{binding:1,resource:{buffer:d,size:t.length*4}},{binding:2,resource:{buffer:p,size:u}}]}),f.body=e,f.pipeline=c,f.boundSelection=d,f.boundSelected=p,f.indexBytes=t.length*4,f.bytes=u);let h=n.createCommandEncoder(),g=h.beginComputePass();g.setPipeline(c),g.setBindGroup(0,f.group);let b=Math.ceil(t.length*o/64);return g.dispatchWorkgroups(Math.min(b,a),Math.ceil(b/a)),g.end(),h.copyBufferToBuffer(p,0,m,0,u),n.queue.submit([h.finish()]),await m.mapAsync(GPUMapMode.READ,0,u),new Float32Array(m.getMappedRange(0,u).slice(0))}finally{this.release(f)}}};var xa=4,kr=3,Ai=1,Mf=2,as=`
3493
3705
  struct Manifold { ids: vec4u, geo: vec4f } // a, b (a > b), first contact, count (low 4 bits); normal (b to a)
3494
3706
  struct Contact { rA: vec3f, key: u32, rB: vec3f, c0x: f32, pen: vec3f, c0y: f32, lam: vec3f, c0z: f32 }
3495
3707
  struct Params { prev: u32, now: u32, mask: u32, capacity: u32, pairs: u32, step: u32, dt: f32, pad: u32 }
@@ -3503,7 +3715,7 @@ struct Params { prev: u32, now: u32, mask: u32, capacity: u32, pairs: u32, step:
3503
3715
  @group(0) @binding(6) var<storage, read_write> events: array<vec4f>;
3504
3716
  @group(0) @binding(7) var<uniform> params: Params;
3505
3717
 
3506
- const STRIDE = ${qe/4}u;
3718
+ const STRIDE = ${We/4}u;
3507
3719
 
3508
3720
  fn hash32(x0: u32) -> u32 {
3509
3721
  var x = x0;
@@ -3518,7 +3730,7 @@ fn turn(q: vec4f, v: vec3f) -> vec3f {
3518
3730
  }
3519
3731
 
3520
3732
  fn slotOf(base: u32, h: u32) -> u32 {
3521
- return ${Yn}u + 2u * (base + h);
3733
+ return ${xa}u + 2u * (base + h);
3522
3734
  }
3523
3735
 
3524
3736
  fn insert(base: u32, a: u32, b: u32) {
@@ -3551,16 +3763,16 @@ fn has(base: u32, a: u32, b: u32) -> bool {
3551
3763
  fn emit(kind: u32, a: u32, b: u32, point: vec3f, impulse: f32, normal: vec3f) {
3552
3764
  let e = atomicAdd(&table[0], 1u);
3553
3765
  if (e >= params.capacity) { return; }
3554
- events[${Br}u * e] = bitcast<vec4f>(vec4u(kind, a, b, params.step));
3555
- events[${Br}u * e + 1u] = vec4f(point, impulse);
3556
- events[${Br}u * e + 2u] = vec4f(normal, 0.0);
3766
+ events[${kr}u * e] = bitcast<vec4f>(vec4u(kind, a, b, params.step));
3767
+ events[${kr}u * e + 1u] = vec4f(point, impulse);
3768
+ events[${kr}u * e + 2u] = vec4f(normal, 0.0);
3557
3769
  }
3558
3770
 
3559
3771
  /** Per pair this step: into this step's set, and a begin if it wasn't in last step's. */
3560
3772
  @compute @workgroup_size(64)
3561
3773
  fn touching(@builtin(global_invocation_id) id: vec3u) {
3562
3774
  let m = id.x;
3563
- if (m >= min(counters[${hr}u], params.pairs)) { return; }
3775
+ if (m >= min(counters[${mr}u], params.pairs)) { return; }
3564
3776
  let mf = manifolds[m];
3565
3777
  let count = mf.ids.w & 15u;
3566
3778
  let a = mf.ids.x;
@@ -3569,8 +3781,8 @@ fn touching(@builtin(global_invocation_id) id: vec3u) {
3569
3781
  insert(params.now, a, b);
3570
3782
  if (has(params.prev, a, b)) { return; }
3571
3783
  // Where (the points' average, on a) and how hard (the normal force over the step)
3572
- let pA = bodies[a * STRIDE + ${lr/4}u].xyz;
3573
- let qA = bodies[a * STRIDE + ${Gr/4}u];
3784
+ let pA = bodies[a * STRIDE + ${ur/4}u].xyz;
3785
+ let qA = bodies[a * STRIDE + ${Wr/4}u];
3574
3786
  var point = vec3f(0.0);
3575
3787
  var force = 0.0;
3576
3788
  for (var i = 0u; i < count; i++) {
@@ -3578,7 +3790,7 @@ fn touching(@builtin(global_invocation_id) id: vec3u) {
3578
3790
  point += turn(qA, k.rA) + pA;
3579
3791
  force += k.lam.x;
3580
3792
  }
3581
- emit(${vi}u, a, b, point / f32(count), abs(force) * params.dt, mf.geo.xyz);
3793
+ emit(${Ai}u, a, b, point / f32(count), abs(force) * params.dt, mf.geo.xyz);
3582
3794
  }
3583
3795
 
3584
3796
  /** Per slot of last step's set: an end if the pair isn't in this step's. */
@@ -3589,10 +3801,10 @@ fn ended(@builtin(global_invocation_id) id: vec3u) {
3589
3801
  let k = atomicLoad(&table[s]);
3590
3802
  if (k == 0u) { return; }
3591
3803
  let b = atomicLoad(&table[s + 1u]);
3592
- if (!has(params.now, k - 1u, b)) { emit(${Eu}u, k - 1u, b, vec3f(0.0), 0.0, vec3f(0.0)); }
3804
+ if (!has(params.now, k - 1u, b)) { emit(${Mf}u, k - 1u, b, vec3f(0.0), 0.0, vec3f(0.0)); }
3593
3805
  }
3594
- `,Mu=Yr.replace("struct Manifold { ids: vec4u, geo: vec4f }","struct Manifold { ids:vec4u, pl:vec4f, anchors:vec4f, geo:vec4f, misc:vec4f }").replace(`const STRIDE = ${qe/4}u;`,"const STRIDE = 6u;").replace(Yr.slice(Yr.indexOf(`@compute @workgroup_size(64)
3595
- fn touching`),Yr.indexOf("/** Per slot of last step")),`
3806
+ `,zf=as.replace("struct Manifold { ids: vec4u, geo: vec4f }","struct Manifold { ids:vec4u, pl:vec4f, anchors:vec4f, geo:vec4f, misc:vec4f }").replace(`const STRIDE = ${We/4}u;`,"const STRIDE = 6u;").replace(as.slice(as.indexOf(`@compute @workgroup_size(64)
3807
+ fn touching`),as.indexOf("/** Per slot of last step")),`
3596
3808
  @compute @workgroup_size(64) fn touching(@builtin(global_invocation_id) id:vec3u){
3597
3809
  let m=id.x;let count=min(counters[1u],params.pairs);if(m>=count){return;}
3598
3810
  let c=manifolds[m];let a=c.ids.x;let b=c.ids.y;
@@ -3601,12 +3813,12 @@ fn touching`),Yr.indexOf("/** Per slot of last step")),`
3601
3813
  insert(params.now,a,b);if(has(params.prev,a,b)){return;}
3602
3814
  let pose=bodies[a*STRIDE];let cs=cos(pose.z);let sn=sin(pose.z);
3603
3815
  let r=c.anchors.xy;let point=pose.xy+vec2f(cs*r.x-sn*r.y,sn*r.x+cs*r.y);
3604
- emit(${vi}u,a,b,vec3f(point,0.),abs(c.pl.z)*params.dt,vec3f(c.geo.zw,0.));
3816
+ emit(${Ai}u,a,b,vec3f(point,0.),abs(c.pl.z)*params.dt,vec3f(c.geo.zw,0.));
3605
3817
  }
3606
3818
 
3607
- `),yi=class{device;pipelines;layout;watch;table;events;params;setSlots;capacity;group=null;bound=[];flip=0;bodies;constructor(e,t,i,r,o,n=3){this.device=e,this.bodies=t,this.capacity=o,this.setSlots=2**Math.ceil(Math.log2(Math.max(64,2*r)));let a=e.createShaderModule({label:"contact events",code:n===2?Mu:Yr}),l=["read-only-storage","read-only-storage","read-only-storage","read-only-storage","read-only-storage","storage","storage","uniform"];this.layout=e.createBindGroupLayout({label:"contact events",entries:l.map((d,p)=>({binding:p,visibility:GPUShaderStage.COMPUTE,buffer:{type:d}}))});let c=e.createPipelineLayout({bindGroupLayouts:[this.layout]}),u=d=>e.createComputePipeline({label:`contact events ${d}`,layout:c,compute:{module:a,entryPoint:d}});this.pipelines={touching:u("touching"),ended:u("ended")};let f=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC;this.watch=e.createBuffer({label:"contact watch",size:Math.max(16,i*4),usage:f}),this.table=e.createBuffer({label:"contact sets",size:(Yn+4*this.setSlots)*4,usage:f}),this.events=e.createBuffer({label:"contact events",size:o*Br*16,usage:f}),this.params=e.createBuffer({label:"contact params",size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST})}setWatched(e,t){let i=e.map((r,o)=>[r,t[o]?1:0]).sort((r,o)=>r[0]-o[0]);for(let r=0;r<i.length;){let o=r+1;for(;o<i.length&&i[o][0]===i[o-1][0]+1;)o++;this.device.queue.writeBuffer(this.watch,i[r][0]*4,Uint32Array.from(i.slice(r,o),n=>n[1])),r=o}}run(e,t,i,r){let o=this.device,n=[this.bodies,e.manifolds,e.contacts,e.counters,this.watch,this.table,this.events,this.params];(!this.group||n.some((d,p)=>d!==this.bound[p]))&&(this.bound=n,this.group=o.createBindGroup({layout:this.layout,entries:n.map((d,p)=>({binding:p,resource:{buffer:d}}))})),this.flip=1-this.flip;let[a,l]=this.flip?[0,this.setSlots]:[this.setSlots,0],c=new Uint32Array([a,l,this.setSlots-1,this.capacity,t,i,0,0]);new Float32Array(c.buffer)[6]=r,o.queue.writeBuffer(this.params,0,c);let u=o.createCommandEncoder({label:"contact events"});u.clearBuffer(this.table,(Yn+2*l)*4,2*this.setSlots*4);let f=u.beginComputePass({label:"contact events"});f.setBindGroup(0,this.group),f.setPipeline(this.pipelines.touching),f.dispatchWorkgroups(Math.max(1,Math.ceil(t/64))),f.setPipeline(this.pipelines.ended),f.dispatchWorkgroups(Math.ceil(this.setSlots/64)),f.end(),o.queue.submit([u.finish()])}async read(){let e=this.device,t=16+this.capacity*Br*16,i=e.createBuffer({size:t,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),r=e.createCommandEncoder({label:"read contact events"});r.copyBufferToBuffer(this.table,0,i,0,16),r.copyBufferToBuffer(this.events,0,i,16,t-16),r.clearBuffer(this.table,0,16),e.queue.submit([r.finish()]),await i.mapAsync(GPUMapMode.READ);let o=i.getMappedRange().slice(0);i.unmap(),i.destroy();let n=new Uint32Array(o),a=new Float32Array(o),l=Math.min(n[0],this.capacity),c=[];for(let u=0;u<l;u++){let f=4+u*Br*4;c.push({kind:n[f],a:n[f+1],b:n[f+2],step:n[f+3],point:[a[f+4],a[f+5],a[f+6]],impulse:a[f+7],normal:[a[f+8],a[f+9],a[f+10]]})}return c.sort((u,f)=>u.step-f.step),{events:c,dropped:n[0]-l,full:n[1]!==0}}destroy(){for(let e of[this.watch,this.table,this.events,this.params])e.destroy()}};var ht=Object.freeze({BOX:"box",SPHERE:"sphere",CAPSULE:"capsule",CYLINDER:"cylinder",CONVEX_HULL:"convex-hull"}),Je=s=>s&&typeof s.x=="number"?[s.x,s.y,s.z,...typeof s.w=="number"?[s.w]:[]]:Array.from(s),Qr=new WeakMap,Cr=s=>{if(!Number.isInteger(s)||s<0||s>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");return s},Js=(s,e,t=!1)=>{if(!Number.isFinite(s)||(t?s<0:s<=0))throw Error(`${e} must be ${t?"nonnegative":"positive"} and finite`);return s},$s=class s{static async create({device:e,...t}={}){if(t.scene&&Qr.has(t.scene))throw Error("This scene already has an AVBD world");let i=!e;e||({device:e}=await Jr({preferredLimits:{maxStorageBuffersPerShaderStage:9,maxStorageBufferBindingSize:512*1024*1024,maxBufferSize:1024*1024*1024}}));let r;try{return await xr(e),r=new s(e,t),r.ownsDevice=i,r.scene&&r.autoAttach&&r.attachToScene(),r}catch(o){throw r?r.dispose():i&&e.destroy(),o}}constructor(e,{scene:t,gravity:i=[0,-10,0],timeStep:r=1/60,iterations:o=10,capacity:n=4096,syncMeshes:a=!0,maxSyncedBodies:l=2048,broadphase:c="auto",solverMode:u="auto",bvh:f={},autoAttach:d=!0,maxContactPairs:p=8192,maxContactEvents:g=4096,sleeping:h=!1}={}){if(this.device=e,this.scene=t,this.autoAttach=d,this.syncEnabled=a,this.maxSyncedBodies=l,!Number.isInteger(n)||n<1||!Number.isInteger(l)||l<0)throw Error("capacity and maxSyncedBodies must be valid integer counts");if(this.capacity=n,this.collisionOptions={broadphase:c,bvh:f,solverMode:u},this.ref=new ni,this.ref.dt=Js(r,"timeStep"),!Number.isInteger(o)||o<1)throw Error("iterations must be a positive integer");this.ref.iterations=o,this.aggregates=[],this.constraints=new Set,this.contactListeners=new Set;for(let[b,v]of Object.entries({maxContactPairs:p,maxContactEvents:g}))if(!Number.isInteger(v)||v<1)throw Error(`${b} must be a positive integer`);if(this.contactOptions={maxContactPairs:p,maxContactEvents:g},this.bodyReadback=new bi(e),this.sleepOptions=h,h!==!1&&h!==!0&&(typeof h!="object"||h===null))throw Error("sleeping must be a boolean or options object");this.commands=new Map,this.steps=0,this.errors=[],this.deviceLost=null;let m=new WeakRef(this);e.lost.then(b=>{let v=m.deref();!v||v.disposed||(v.deviceLost={reason:b.reason,message:b.message},v.errors.push(`WebGPU device lost: ${b.message||b.reason}`),v.dispose())}),this.setGravity(i),this.errorListener=b=>this.errors.push(b.error.message),e.addEventListener("uncapturederror",this.errorListener),t&&Qr.set(t,this)}setGravity(e){let t=Je(e);if(t.length!==3||!t.every(Number.isFinite))throw Error("gravity requires three finite components");let i=Math.hypot(...t);this.gravity=-i,this.up=i?t.map(r=>-r/i):[0,1,0],this.gpu&&(this.gpu.params.gravity=this.gravity,this.gpu.params.up=this.up),this.wakeAll()}get solverDecision(){return this.initialize(),{...this.gpu.solverDecision}}setSolverMode(e){this.initialize();let t=this.gpu.setSolverMode(e);return this.collisionOptions.solverMode=e,{...t}}initialize(){if(this.assertAlive(),this.gpu)return;if(this.syncEnabled&&this.aggregates.filter(r=>r.sync).length>this.maxSyncedBodies)throw Error("For large scenes use syncMeshes:false and draw the GPU body buffer directly");if(this.aggregates.length>this.capacity)throw Error(`Body capacity ${this.capacity} exceeded; size the world before initialization`);this.gpu=new pi(this.device,this.ref,Ws(this.ref,{bodyCapacity:Math.max(1,this.capacity),spatialSort:!0,...this.collisionOptions})),Object.assign(this.gpu.params,{gravity:this.gravity,up:this.up}),this.gpu.externalBeforeStep=r=>{this.sleepManager?.before(r),this.flushCommands(r)},this.gpu.externalAfterStep=r=>this.sleepManager?.after(r);let e=new Map([...this.constraints].map(r=>[r.force,r])),t=[],i=0;for(let r of this.ref.forces){let o=e.get(r);o&&(o.attach(i++,!1),(o.type==="fixed"||o.type==="spring"&&o.rest===void 0)&&t.push({slot:o.slot,spring:o.type==="spring"}))}this.gpu.captureConstraintFrames(t),this.byGpuIndex=new Map(this.aggregates.map(r=>[this.gpu.gpuIndex(r.index),r.body]));for(let r of this.aggregates)(r.disposed||r.group!==4294967295||r.collidesWith!==4294967295)&&this.gpu.setFilters([this.gpu.gpuIndex(r.index)],[r.disposed?0:r.group],[r.disposed?0:r.collidesWith]);for(let r of this.aggregates)r.isTrigger&&this.gpu.setSensor(r.body.gpuIndex,!0);for(let r of this.aggregates)r.restitution>0&&this.gpu.setRestitution(r.body.gpuIndex,r.restitution);this.contactListeners.size&&this.initializeContacts(),this.sleepOptions&&(this.sleepManager=new Fi(this,this.sleepOptions===!0?{}:this.sleepOptions))}addAggregate(e,t,i={}){return new Xs(e,t,i,this)}addAggregates(e){return e.map(({mesh:t,type:i,options:r})=>this.addAggregate(t,i,r))}addConstraint(e,t,i={}){return new $r(this,e,t,i)}addJoint(e,t,i={}){return this.addConstraint(e,t,{...i,type:i.type??"ball"})}addWeld(e,t,i={}){return this.addConstraint(e,t,{...i,type:"fixed"})}addSpring(e,t,i={}){return this.addConstraint(e,t,{...i,type:"spring"})}enableSleeping(e={}){return this.assertAlive(),this.sleepOptions=e,this.gpu&&!this.sleepManager&&(this.sleepManager=new Fi(this,e)),this}addMotor(e,t,i={}){return this.addConstraint(e,t,{...i,type:"motor"})}addHinge(e,t,i={}){return new Xr(this,e,t,i)}initializeContacts(){if(this.contactWatch)return;let{maxContactPairs:e,maxContactEvents:t}=this.contactOptions;this.contactWatch=new yi(this.device,this.gpu.bodyBuffer,this.capacity,e,t);let i=this.aggregates.filter(r=>!r.disposed);this.contactWatch.setWatched(i.map(r=>r.body.gpuIndex),i.map(()=>!0))}onContact(e){if(this.assertAlive(),typeof e!="function")throw Error("A contact callback is required");return this.contactListeners.add(e),this.gpu&&this.initializeContacts(),()=>this.contactListeners.delete(e)}async readContactEvents(){return this.initialize(),this.initializeContacts(),this.contactPending?this.contactPending:(this.contactPending=this.contactWatch.read().then(e=>({...e,events:e.events.map(t=>({...t,type:t.kind===vi?"begin":"end",isTrigger:!!(this.byGpuIndex.get(t.a)?.aggregate.isTrigger||this.byGpuIndex.get(t.b)?.aggregate.isTrigger),a:this.byGpuIndex.get(t.a),b:this.byGpuIndex.get(t.b)}))})).finally(()=>this.contactPending=null),this.contactPending)}async raycast(e,t,i={}){let[r]=await this.raycastAll([{origin:e,direction:t,maxDistance:i.maxDistance}],i);return r}async sphereCast(e,t,i,r={}){let[o]=await this.sphereCastAll([{origin:e,radius:t,direction:i,maxDistance:r.maxDistance}],r);return o}async sphereCastAll(e,{ignore:t=[],collidesWith:i=4294967295,includeTriggers:r=!0}={}){this.assertAlive(),Cr(i),this.initialize(),this.flushCommands();for(let n of t)if(n.aggregate.world!==this||n.disposed)throw Error("Ignored cast bodies must belong to this world and be alive");return(await this.gpu.sphereCastAll(e.map(n=>({...n,origin:Je(n.origin),direction:Je(n.direction)})),{ignore:t.map(n=>n.gpuIndex),collidesWith:i,includeTriggers:r})).map(n=>n?{...n,body:this.byGpuIndex.get(n.index)??null}:null)}async raycastAll(e,{ignore:t=[],collidesWith:i=4294967295,includeTriggers:r=!0}={}){Cr(i),this.initialize(),this.flushCommands();let o=e.map(a=>{let l=Je(a.origin),c=Je(a.direction);if(l.length!==3||c.length!==3||![...l,...c].every(Number.isFinite)||!Math.hypot(...c))throw Error("A ray requires a finite origin and nonzero direction");return a.maxDistance!==void 0&&Js(a.maxDistance,"maxDistance",!0),{...a,origin:l,direction:c}});for(let a of t)if(a.aggregate.world!==this)throw Error("Ignored ray bodies must belong to this world");return(await this.gpu.raycastAll(o,{ignore:t.map(a=>a.gpuIndex),collidesWith:i,includeTriggers:r})).map(a=>a?{...a,body:this.byGpuIndex.get(a.index)??null}:null)}getRenderBinding(e=this.device){if(this.initialize(),e!==this.device)throw Error("Direct GPU rendering must share the physics GPUDevice");return{device:e,buffer:this.bodyBuffer,stride:160,positionOffset:0,rotationOffset:16,sizeOffset:64,count:this.gpu.bodyCount}}wakeAll(){this.sleepManager&&(this.sleepManager.wakeRequested=!0)}async readSleepStats(){return this.initialize(),this.sleepManager?this.sleepManager.readStats():{sleeping:0,wakeRequested:!1}}assertAlive(){if(this.disposed)throw Error("AVBD world is disposed")}queue(e,t,i,r){this.assertAlive(),e.assertAlive();let o=Je(r);if(o.length!==(i==="rotation"?4:3)||!o.every(Number.isFinite))throw Error(`${i} requires ${i==="rotation"?4:3} finite components`);let n=this.commands.get(e);return n||this.commands.set(e,n={mask:0}),n.mask|=t,n[i]=o,this.wakeAll(),n}flushCommands(e){if(this.initialize(),this.gpu.flushPropertyEdits(e),!this.commands.size)return;this.sleepManager?.wakeRequested&&this.sleepManager.before(e);let t=this.commands.size,i=0;for(let h of this.commands.values())i|=h.mask;if(i===1||i===2){if(!this.velocityIndices||this.velocityIndices.length<t){let v=Math.max(t,(this.velocityIndices?.length??0)*2,64);this.velocityIndices=new Uint32Array(v),this.velocityValues=new Float32Array(v*3)}let h=0;for(let[v,w]of this.commands)this.velocityIndices[h]=v.aggregate.gpuSlot??this.gpu.gpuIndex(v.aggregate.index),this.velocityValues.set(i===2?w.angular:w.velocity,h++*3);let m=i===2?"angularVelocityBatch":"velocityBatch",b=this[m]??=new Qt(this.gpu,3,i===2?"angular":"linear");b.solver=this.gpu,b.submitValidated(this.velocityIndices.subarray(0,t),this.velocityValues.subarray(0,t*3),e),this.lastCommandBatch={bodies:t,path:i===2?"packed-angular-velocities":"packed-velocities",uploadedBytes:t*16},this.commands.clear();return}let r=!0;for(let h of this.commands.values())if((h.mask&-4)!==0){r=!1;break}if(r){(!this.motionData||this.motionData.length<t*8)&&(this.motionData=new Uint32Array(Math.max(t*8,(this.motionData?.length??0)*2,512)),this.motionFloats=new Float32Array(this.motionData.buffer));let h=0;for(let[m,b]of this.commands){let v=h++*8;this.motionData[v]=m.aggregate.gpuSlot??this.gpu.gpuIndex(m.aggregate.index),this.motionData[v+1]=b.mask,b.velocity&&this.motionFloats.set(b.velocity,v+2),b.angular&&this.motionFloats.set(b.angular,v+5)}this.motionBatch??=new gi(this.gpu,3),this.motionBatch.submitValidated(this.motionData.subarray(0,t*8),e),this.lastCommandBatch={bodies:t,path:"packed-motion",uploadedBytes:t*32},this.commands.clear();return}let o=t*128,n=Math.min(this.device.limits.maxStorageBufferBindingSize,this.device.limits.maxBufferSize);if(o>n)throw Error("Body command batch exceeds GPU buffer limits");(!this.commandData||this.commandData.byteLength<o)&&(this.commandData=new ArrayBuffer(Math.min(n,Math.max(o,(this.commandData?.byteLength??0)*2,128))));let a=this.commandData,l=new Float32Array(a),c=new Uint32Array(a);l.fill(0,0,t*32);let u=0;for(let[h,m]of this.commands){let b=u++*32;c[b]=h.aggregate.gpuSlot??this.gpu.gpuIndex(h.aggregate.index),c[b+1]=m.mask;for(let[v,w]of[["velocity",4],["angular",8],["impulse",12],["torque",16],["position",20],["rotation",24],["pointImpulse",28]])m[v]&&l.set(m[v],b+w)}this.commands.clear(),(!this.commandBuffer||this.commandBuffer.size<o)&&(this.commandBuffer?.destroy(),this.commandBuffer=this.device.createBuffer({size:Math.min(n,Math.max(o*2,128)),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST})),this.device.queue.writeBuffer(this.commandBuffer,0,a,0,o),this.commandPipeline??=this.device.createComputePipeline({layout:"auto",compute:{module:this.device.createShaderModule({code:`const DISPATCH_STRIDE = ${this.device.limits.maxComputeWorkgroupsPerDimension*64}u;
3608
- ${kl}`,label:"AVBD body commands"}),entryPoint:"applyCommands"}}),(!this.commandBinding||this.boundCommandBody!==this.gpu.bodyBuffer||this.boundCommandBuffer!==this.commandBuffer||this.boundCommandBytes!==o)&&(this.commandBinding=this.device.createBindGroup({layout:this.commandPipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:this.gpu.bodyBuffer}},{binding:1,resource:{buffer:this.commandBuffer,size:o}}]}),this.boundCommandBody=this.gpu.bodyBuffer,this.boundCommandBuffer=this.commandBuffer,this.boundCommandBytes=o);let f=e??this.device.createCommandEncoder(),d=f.beginComputePass();d.setPipeline(this.commandPipeline),d.setBindGroup(0,this.commandBinding);let p=Math.ceil(u/64),g=this.device.limits.maxComputeWorkgroupsPerDimension;d.dispatchWorkgroups(Math.min(p,g),Math.ceil(p/g)),d.end(),e||this.device.queue.submit([f.finish()]),this.lastCommandBatch={bodies:t,path:"aggregate-commands",uploadedBytes:o}}step(){this.initialize(),this.gpu.step(),this.steps++,this.contactWatch&&(this.contactWatch.run(this.gpu.contactStorage,this.gpu.manifoldCapacity,this.steps,this.ref.dt),this.contactListeners.size&&!this.contactPending&&this.readContactEvents().then(({events:e,dropped:t,full:i})=>{if(!this.disposed){(t||i)&&this.errors.push(`Contact event storage full: ${t} events dropped; increase maxContactEvents/maxContactPairs`);for(let r of e)for(let o of this.contactListeners)o(r)}}).catch(e=>{this.disposed||this.errors.push(e.message)})),this.syncEnabled&&!this.syncPending&&this.syncMeshes().catch(e=>this.errors.push(e.message)),this.steps%20===0&&!this.counterPending&&(this.counterPending=!0,this.gpu.readCounters().then(e=>{this.disposed||(this.counters=e,this.gpu.adapt(e),(e.overflow||e.clashes)&&this.errors.push(`Collision capacity/color conflict: ${JSON.stringify(e)}`))}).catch(e=>{this.disposed||this.errors.push(e.message)}).finally(()=>this.counterPending=!1))}async syncMeshes(){if(this.initialize(),this.flushCommands(),this.syncPending)return this.syncPending;let e=this.aggregates.filter(t=>t.sync&&!t.disposed);return this.syncPending=this.bodyReadback.read(this.bodyBuffer,e.map(t=>t.body.gpuIndex),!0).then(t=>{if(!this.disposed){for(let i=0;i<e.length;i++)e[i].disposed||e[i].syncPose(t,i*8);this.lastSyncBytes=t.byteLength}}).finally(()=>this.syncPending=null),this.syncPending}get bodyBuffer(){return this.initialize(),this.gpu.bodyBuffer}async readBodies(e){if(this.initialize(),this.flushCommands(),e){for(let t of e)if(t.aggregate.world!==this)throw Error("Selected bodies must belong to this world");return this.bodyReadback.read(this.bodyBuffer,e.map(t=>t.gpuIndex))}return this.gpu.readBodies()}dispose(){if(!this.disposed){this.disposed=!0,this.observer&&this.scene?.onBeforeRenderObservable.remove(this.observer),this.disposeObserver&&this.scene?.onDisposeObservable.remove(this.disposeObserver),this.scene&&Qr.get(this.scene)===this&&Qr.delete(this.scene),this.device.removeEventListener("uncapturederror",this.errorListener),this.gpu?.destroy(),this.contactWatch?.destroy(),this.sleepManager?.dispose(),this.commandBuffer?.destroy(),this.velocityBatch?.destroy(),this.angularVelocityBatch?.destroy(),this.motionBatch?.destroy(),this.bodyReadback.destroy(),this.commandData=this.velocityIndices=this.velocityValues=null,this.commandBinding=null;for(let e of this.aggregates)e.disposed=!0,e.body.disposed=!0;this.commands.clear(),this.contactListeners.clear();for(let e of this.constraints)e.disposed=!0;this.constraints.clear(),this.ownsDevice&&this.device.destroy()}}attachToScene(e=this.scene){if(this.assertAlive(),!e)throw Error("A Babylon scene is required");if(this.observer&&e===this.scene)return this;if(this.observer)throw Error("AVBD world is already attached to another scene");this.scene=e,this.disposeObserver=e.onDisposeObservable.addOnce(()=>this.dispose());let t=0;return this.observer=e.onBeforeRenderObservable.add(()=>{t+=Math.min(.05,e.getEngine().getDeltaTime()/1e3);for(let i=0;t>=this.ref.dt&&i<3;i++)this.step(),t-=this.ref.dt}),this}},Xs=class{constructor(e,t,{mass:i=1,friction:r=.6,restitution:o=0,allowSleep:n,isTrigger:a=!1,sync:l=!0,group:c=4294967295,collidesWith:u=4294967295}={},f){if(f=f instanceof $s?f:Qr.get(f??e.getScene()),!f)throw Error("Create an AVBD world for this scene before adding aggregates");if(f.assertAlive(),typeof t=="number"&&(t=[ht.SPHERE,ht.CAPSULE,ht.CYLINDER,ht.BOX,ht.CONVEX_HULL][t]),Js(i,"mass",!0),Js(r,"friction",!0),!Number.isFinite(o)||o<0||o>1)throw Error("restitution must be between 0 and 1");if(e.parent)throw Error("AVBD aggregate meshes must have no parent; bake the parent transform first");if(!Object.values(ht).includes(t))throw Error(`Unsupported AVBD shape: ${t}`);if(f.aggregates.length>=f.capacity)throw Error("AVBD body capacity exceeded");if(this.world=f,this.mesh=e,this.sync=l,this.type=t,n!==void 0&&typeof n!="boolean")throw Error("allowSleep must be a boolean");if(this.allowSleep=n??!0,typeof a!="boolean")throw Error("isTrigger must be a boolean");if(this.isTrigger=a,this.restitution=o,n===!0&&!f.sleepOptions&&f.enableSleeping(),this.group=Cr(c),this.collidesWith=Cr(u),f.gpu&&f.syncEnabled&&l&&f.aggregates.filter(y=>y.sync&&!y.disposed).length>=f.maxSyncedBodies)throw Error("For large scenes use syncMeshes:false and draw the GPU body buffer directly");if(![ht.BOX,ht.SPHERE,ht.CAPSULE].includes(t)&&f.device.limits.maxStorageBuffersPerShaderStage<9)throw Error("Convex hull collisions require nine storage buffer bindings");e.computeWorldMatrix(!0),e.refreshBoundingInfo();let d=e.getBoundingInfo().boundingBox,p=e.scaling;if([p.x,p.y,p.z].some(y=>y<=0))throw Error("Bake negative or zero mesh scaling before creating an aggregate");let g=d.maximum.subtract(d.minimum).multiply(p),h=d.center.multiply(p),m=e.rotationQuaternion?.clone()||e.rotation.toQuaternion();this.localCenter=h,this.localRotation=m.constructor.Identity();let b;if(t===ht.BOX)b=new Ze(f.ref,Je(g),1,r,[0,0,0]);else if(t===ht.SPHERE){if(Math.max(g.x,g.y,g.z)-Math.min(g.x,g.y,g.z)>1e-4)throw Error("Sphere aggregate requires uniform dimensions");b=or(f.ref,g.x/2,1,r,[0,0,0])}else if(t===ht.CAPSULE){if(Math.abs(g.x-g.z)>1e-4)throw Error("Capsule aggregate requires equal X and Z diameters; bake an upright Y-axis capsule mesh");b=Ar(f.ref,g.x/2,g.y,1,r,[0,0,0])}else{let y=e.getVerticesData("position");if(!y)throw Error("Hull aggregate requires mesh positions");let A=Float32Array.from(y,(B,E)=>B*[p.x,p.y,p.z][E%3]),x=jr(A);if(!x)throw Error("Hull aggregate requires a closed shape with nonzero volume");this.localCenter=new e.position.constructor(...x.center),this.localRotation=m.constructor.FromArray(x.rotation),b=Bs(f.ref,x,1,r,[0,0,0])}let v=i/b.mass;b.mass=i,b.moment.forEach((y,A)=>b.moment[A]=y*v);let w=e.position.add(this.localCenter.applyRotationQuaternion(m));if(b.positionLin.set(Je(w)),b.positionAng.set(m.multiply(this.localRotation).asArray()),this.rigid=b,this.index=f.aggregates.length,this.body=new Ys(this),f.aggregates.push(this),e.rotationQuaternion=m,f.gpu){if(this.gpuSlot=f.gpu.addBody(b),this.gpuSlot<0)throw Error("AVBD body capacity exceeded");f.byGpuIndex.set(this.gpuSlot,this.body),f.gpu.setFilters([this.gpuSlot],[this.group],[this.collidesWith]),(this.isTrigger||f.gpu.sensorsEnabled)&&f.gpu.setSensor(this.gpuSlot,this.isTrigger),this.restitution>0&&f.gpu.setRestitution(this.gpuSlot,this.restitution),f.contactWatch?.setWatched([this.gpuSlot],[!0]),f.sleepManager?.register(this.gpuSlot,b.mass,this.allowSleep),f.wakeAll?.()}}syncPose(e,t){let i=t??this.body.gpuIndex*40,r=this.localRotation.constructor.FromArray(e,i+4).multiply(this.localRotation.conjugate());this.mesh.rotationQuaternion.copyFrom(r),this.mesh.position.copyFrom(new this.mesh.position.constructor(...e.subarray(i,i+3)).subtract(this.localCenter.applyRotationQuaternion(r)))}dispose(){if(this.disposed)return;let e=this.world;for(let t of[...e.constraints])(t.bodyA===this.body||t.bodyB===this.body)&&t.dispose();if(e.gpu){let t=this.body.gpuIndex;e.queue(this.body,16,"velocity",[0,0,0]),e.gpu.setFilters([t],[0],[0]),e.gpu.setRestitution(t,0)}this.rigid.mass=0,this.rigid.moment.fill(0),this.sync=!1,this.disposed=this.body.disposed=!0,e.sleepManager?.register(this.gpuSlot??e.gpu?.gpuIndex(this.index)??this.index,0),e.wakeAll?.()}},Ys=class{constructor(e){this.aggregate=e}assertAlive(){if(this.disposed||this.aggregate.disposed)throw Error("AVBD body is disposed")}get gpuIndex(){this.assertAlive();let e=this.aggregate.world;return e.initialize(),this.aggregate.gpuSlot??e.gpu.gpuIndex(this.aggregate.index)}setLinearVelocity(e){return this.aggregate.world.queue(this,1,"velocity",e),this}setAngularVelocity(e){return this.aggregate.world.queue(this,2,"angular",e),this}applyImpulse(e,t){let i=t?Je(t):null;if(i&&(i.length!==3||!i.every(Number.isFinite)))throw Error("Impulse point requires three finite components");let r=this.aggregate.world,o=Je(e),n=r.commands.get(this),a=o.map((c,u)=>c+(n?.impulse?.[u]||0)),l=r.queue(this,4,"impulse",a);if(t){let c=[i[1]*o[2]-i[2]*o[1],i[2]*o[0]-i[0]*o[2],i[0]*o[1]-i[1]*o[0]],u=l.torque||[0,0,0];l.torque=Je(c).map((f,d)=>f+u[d]),l.pointImpulse=o.map((f,d)=>f+(l.pointImpulse?.[d]||0))}return this}applyAngularImpulse(e){let t=this.aggregate.world,i=t.commands.get(this)?.torque||[0,0,0];return t.queue(this,4,"torque",Je(e).map((r,o)=>r+i[o])),this}applyForce(e,t){return this.applyImpulse(Je(e).map(i=>i*this.aggregate.world.ref.dt),t)}applyTorque(e){return this.applyAngularImpulse(Je(e).map(t=>t*this.aggregate.world.ref.dt))}setCollisionGroups(e,t=4294967295){this.assertAlive();let i=this.aggregate,r=Cr(e),o=Cr(t);return i.group=r,i.collidesWith=o,i.world.gpu&&i.world.gpu.setFilters([this.gpuIndex],[i.group],[i.collidesWith]),i.world.wakeAll?.(),this}setTrigger(e){if(this.assertAlive(),typeof e!="boolean")throw Error("isTrigger must be a boolean");let t=this.aggregate;return t.isTrigger=e,t.world.gpu&&t.world.gpu.setSensor(this.gpuIndex,e),t.world.wakeAll(),this}setRestitution(e){if(this.assertAlive(),!Number.isFinite(e)||e<0||e>1)throw Error("restitution must be between 0 and 1");let t=this.aggregate;return t.restitution=e,t.world.gpu&&t.world.gpu.setRestitution(this.gpuIndex,e),t.world.wakeAll(),this}async readState(){let e=await this.aggregate.world.readBodies([this]),t=this.aggregate.rigid.mass;return{position:Array.from(e.subarray(0,3)),rotation:Array.from(e.subarray(4,8)),linearVelocity:Array.from(e.subarray(32,35)),angularVelocity:Array.from(e.subarray(36,39)),mass:t,effectiveMass:e[19],sleeping:t>0&&e[19]===0}}wakeUp(){return this.assertAlive(),this.aggregate.world.wakeAll(),this}setSleepEnabled(e){if(this.assertAlive(),typeof e!="boolean")throw Error("Sleep eligibility must be a boolean");let t=this.aggregate,i=t.world;return t.allowSleep=e,e&&!i.sleepOptions&&i.enableSleeping(),i.gpu&&i.sleepManager?.register(this.gpuIndex,t.rigid.mass,e),i.wakeAll(),this}teleport(e,t=this.aggregate.mesh.rotationQuaternion){let i=t.clone().normalize(),r=this.aggregate;return r.world.queue(this,8,"position",Je(e.add(r.localCenter.applyRotationQuaternion(i)))),r.world.queue(this,8,"rotation",i.multiply(r.localRotation).asArray()),this}};var Ni=class{solver;bodyA;bodyB;J=new Float64Array(12);H=new Float64Array(36);C=new Float64Array(4);fmin=new Float64Array(4).fill(-1/0);fmax=new Float64Array(4).fill(1/0);stiffness=new Float64Array(4).fill(1/0);fracture=new Float64Array(4).fill(1/0);penalty=new Float64Array(4);lambda=new Float64Array(4);constructor(e,t,i){this.solver=e,this.bodyA=t,this.bodyB=i,e.forces.push(this),t?.forces.push(this),i.forces.push(this)}destroy(){let e=this.solver.forces,t=e.indexOf(this);t>=0&&e.splice(t,1),this.unlinkFromBodies()}unlinkFromBodies(){for(let e of[this.bodyA,this.bodyB]){if(!e)continue;let t=e.forces.indexOf(this);t>=0&&e.forces.splice(t,1)}}disable(){this.stiffness.fill(0),this.penalty.fill(0),this.lambda.fill(0)}};var Ll=s=>s<0?-1:s>0?1:0,Sr=(s,e)=>s<e?s:e,zu=(s,e)=>s>e?s:e,kr=(s,e,t)=>zu(e,Sr(t,s));function Kr(s,e,t){let i=Math.cos(s),r=Math.sin(s);return[i*e-r*t,r*e+i*t]}function Ui(s,e,t){let i=Math.cos(s[2]),r=Math.sin(s[2]);return[i*e-r*t+s[0],r*e+i*t+s[1]]}function Kt(s,e,t,i,r){s[e*3]=t,s[e*3+1]=i,s[e*3+2]=r}var Qs=class extends Ni{rA;rB;C0=new Float64Array(3);torqueArm;restAngle;constructor(e,t,i,r,o,n=[1/0,1/0,1/0],a=1/0){super(e,t,i),this.rA=[r[0],r[1]],this.rB=[o[0],o[1]],this.stiffness[0]=n[0],this.stiffness[1]=n[1],this.stiffness[2]=n[2],this.fmax[2]=a,this.fmin[2]=-a,this.fracture[2]=a,this.restAngle=(t?t.position[2]:0)-i.position[2];let l=(t?t.size[0]:0)+i.size[0],c=(t?t.size[1]:0)+i.size[1];this.torqueArm=l*l+c*c}rows(){return 3}evaluate(e){let t=this.bodyA?Ui(this.bodyA.position,this.rA[0],this.rA[1]):this.rA,i=Ui(this.bodyB.position,this.rB[0],this.rB[1]);e[0]=t[0]-i[0],e[1]=t[1]-i[1],e[2]=((this.bodyA?this.bodyA.position[2]:0)-this.bodyB.position[2]-this.restAngle)*this.torqueArm}initialize(){return this.evaluate(this.C0),this.stiffness[0]!==0||this.stiffness[1]!==0||this.stiffness[2]!==0}Cn=new Float64Array(3);computeConstraint(e){this.evaluate(this.Cn);for(let t=0;t<3;t++)this.C[t]=this.stiffness[t]===1/0?this.Cn[t]-this.C0[t]*e:this.Cn[t]}computeDerivatives(e){let{J:t,H:i}=this;if(i.fill(0,0,27),e===this.bodyA){let r=Kr(e.position[2],this.rA[0],this.rA[1]);Kt(t,0,1,0,-r[1]),Kt(t,1,0,1,r[0]),Kt(t,2,0,0,this.torqueArm),i[8]=-r[0],i[17]=-r[1]}else{let r=Kr(e.position[2],this.rB[0],this.rB[1]);Kt(t,0,-1,0,r[1]),Kt(t,1,0,-1,-r[0]),Kt(t,2,0,0,-this.torqueArm),i[8]=r[0],i[17]=r[1]}}},Ks=class extends Ni{rA;rB;rest;constructor(e,t,i,r,o,n,a=-1){if(super(e,t,i),this.rA=[r[0],r[1]],this.rB=[o[0],o[1]],this.stiffness[0]=n,this.rest=a,this.rest<0){let l=Ui(t.position,r[0],r[1]),c=Ui(i.position,o[0],o[1]);this.rest=Math.hypot(l[0]-c[0],l[1]-c[1])}}rows(){return 1}initialize(){return!0}delta(){let e=Ui(this.bodyA.position,this.rA[0],this.rA[1]),t=Ui(this.bodyB.position,this.rB[0],this.rB[1]);return[e[0]-t[0],e[1]-t[1]]}computeConstraint(){let e=this.delta();this.C[0]=Math.hypot(e[0],e[1])-this.rest}computeDerivatives(e){let t=this.delta(),i=t[0]*t[0]+t[1]*t[1];if(i===0)return;let r=Math.sqrt(i),o=t[0]/r,n=t[1]/r,a=(1-o*o)/r,l=(0-o*n)/r,c=(0-n*o)/r,u=(1-n*n)/r,f=e===this.bodyA,d=f?this.rA:this.rB,p=Kr(e.position[2],-d[1],d[0]),g=Kr(e.position[2],d[0],d[1]),h=a*p[0]+l*p[1],m=c*p[0]+u*p[1],b=o*g[0]+n*g[1],v=o*p[0]+n*p[1];f?Kt(this.J,0,o,n,v):Kt(this.J,0,-o,-n,-v);let w=f?-b-b:b+b,y=this.H;y[0]=a,y[1]=l,y[2]=h,y[3]=c,y[4]=u,y[5]=m,y[6]=h,y[7]=m,y[8]=w}},Zs=class extends Ni{rows(){return 0}initialize(){return!0}computeConstraint(){}computeDerivatives(){}},eo=class extends Ni{speed;constructor(e,t,i,r,o){super(e,t,i),this.speed=r,this.fmax[0]=o,this.fmin[0]=-o}rows(){return 1}initialize(){return!0}computeConstraint(){let e=this.bodyA?this.bodyA.position[2]-this.bodyA.initial[2]:0,t=this.bodyB.position[2]-this.bodyB.initial[2];this.C[0]=e-t-this.speed*this.solver.dt}computeDerivatives(e){Kt(this.J,0,0,0,e===this.bodyA?1:-1),this.H.fill(0,0,9)}};var to=()=>({dt:1/60,gravity:-10,iterations:10,beta:1e5,alpha:.99,gamma:.99,postStabilize:!0,stiffnessRescale:!1,vbd:!1,vbdStiffness:1e6,matchNearest:!1}),io=()=>({...to(),postStabilize:!1,alpha:.95,matchNearest:!0});var Pr=(s,e)=>s>e?s*2097152+e:e*2097152+s;function Iu(s,e,t){let i=0,r=e;for(;i<r;){let o=i+r>>>1;s[o]<t?i=o+1:r=o}return i}function Qn(s,e,t){let i=Iu(s,e,t);return i<e&&s[i]===t}var ro=class{cellSize=1;pairs=new Float64Array(1024);pairCount=0;configuredFor=-1;large=new Int32Array(0);isLarge=new Uint8Array(0);cellX=new Int32Array(0);cellY=new Int32Array(0);tableSize=0;bucketStart=new Int32Array(0);sorted=new Int32Array(0);configure(e,t){this.configuredFor=e;let i=Float64Array.from({length:e},(a,l)=>t[l*4+1]).sort(),r=e>0?i[e>>1]:1,o=0;for(let a=0;a<e;a++)i[a]<=4*r&&(o=Math.max(o,i[a]));this.cellSize=Math.max(2*o,.001),this.isLarge=new Uint8Array(e);let n=[];for(let a=0;a<e;a++)t[a*4+1]>o&&(this.isLarge[a]=1,n.push(a));for(this.large=Int32Array.from(n),this.cellX=new Int32Array(e),this.cellY=new Int32Array(e),this.tableSize=1;this.tableSize<2*e;)this.tableSize<<=1;this.bucketStart=new Int32Array(this.tableSize+1),this.sorted=new Int32Array(e)}hash(e,t){return(Math.imul(e,73856093)^Math.imul(t,19349663))&this.tableSize-1}findPairs(e,t,i,r,o,n){e!==this.configuredFor&&this.configure(e,i),this.pairCount=0;let{cellX:a,cellY:l,isLarge:c,bucketStart:u,sorted:f}=this,d=1/this.cellSize;u.fill(0);for(let h=0;h<e;h++)c[h]||(a[h]=Math.floor(t[h*4]*d),l[h]=Math.floor(t[h*4+1]*d),u[this.hash(a[h],l[h])+1]++);for(let h=0;h<this.tableSize;h++)u[h+1]+=u[h];let p=u.slice(0,this.tableSize);for(let h=0;h<e;h++)c[h]||(f[p[this.hash(a[h],l[h])]++]=h);let g=(h,m)=>{if(!r[h]&&!r[m])return;let b=t[h*4]-t[m*4],v=t[h*4+1]-t[m*4+1],w=i[h*4+1]+i[m*4+1];if(b*b+v*v>w*w)return;let y=Pr(h,m);if(!Qn(o,n,y)){if(this.pairCount===this.pairs.length){let A=new Float64Array(this.pairs.length*2);A.set(this.pairs),this.pairs=A}this.pairs[this.pairCount++]=y}};for(let h=0;h<e;h++){if(c[h])continue;let m=a[h],b=l[h];for(let v=-1;v<=1;v++)for(let w=-1;w<=1;w++){let y=this.hash(m+w,b+v);for(let A=u[y];A<u[y+1];A++){let x=f[A];x>=h||a[x]!==m+w||l[x]!==b+v||g(h,x)}}}for(let h of this.large)for(let m=0;m<e;m++)m===h||c[m]&&m>h||g(h,m);this.pairs.subarray(0,this.pairCount).sort()}};var pt=new Float64Array(12),_l=new Float64Array(12),qi=new Float64Array(12);function qt(s,e,t,i,r,o,n,a){let l=e*6;s[l]=t,s[l+1]=i,s[l+2]=r,s[l+3]=o,s[l+4]=n,s[l+5]=a}function El(s,e,t,i,r,o){let n=0,a=t*e[0]+i*e[1]-r,l=t*e[6]+i*e[7]-r;if(a<=0){for(let c=0;c<6;c++)s[n*6+c]=e[c];n++}if(l<=0){for(let c=0;c<6;c++)s[n*6+c]=e[6+c];n++}if(a*l<0){let c=a/(a-l),u=e[0]+(e[6]-e[0])*c,f=e[1]+(e[7]-e[1])*c;a>0?qt(s,n,u,f,o,e[3],0,e[5]):qt(s,n,u,f,e[8],o,e[10],0),n++}return n}function so(s,e,t,i,r,o,n,a){let l=-(r*n+o*a),c=-(-o*n+r*a);Math.abs(l)>Math.abs(c)?l>0?(qt(pt,0,s,-e,0,0,3,4),qt(pt,1,s,e,0,0,4,1)):(qt(pt,0,-s,e,0,0,1,2),qt(pt,1,-s,-e,0,0,2,3)):c>0?(qt(pt,0,s,e,0,0,4,1),qt(pt,1,-s,e,0,0,1,2)):(qt(pt,0,-s,-e,0,0,2,3),qt(pt,1,s,-e,0,0,3,4));for(let u=0;u<2;u++){let f=u*6,d=pt[f],p=pt[f+1];pt[f]=t+r*d-o*p,pt[f+1]=i+o*d+r*p}}function oo(s,e,t,i,r,o,n,a,l,c,u){let f=Math.cos(t),d=Math.sin(t),p=Math.cos(a),g=Math.sin(a),h=o-s,m=n-e,b=f*h+d*m,v=-d*h+f*m,w=p*h+g*m,y=-g*h+p*m,A=Math.abs(f*p+d*g),x=Math.abs(f*-g+d*p),B=Math.abs(-d*p+f*g),E=Math.abs(-d*-g+f*p),L=Math.abs(b)-i-(A*l+x*c),M=Math.abs(v)-r-(B*l+E*c);if(L>0||M>0)return 0;let z=Math.abs(w)-(A*i+B*r)-l,_=Math.abs(y)-(x*i+E*r)-c;if(z>0||_>0)return 0;let k=0,S=L,P=b>0?f:-f,I=b>0?d:-d;M>.95*S+.01*r&&(k=1,S=M,P=v>0?-d:d,I=v>0?f:-f),z>.95*S+.01*l&&(k=2,S=z,P=w>0?p:-p,I=w>0?g:-g),_>.95*S+.01*c&&(k=3,S=_,P=y>0?-g:g,I=y>0?p:-p);let R,F,X,W,N,H,Z,he,we;if(k===0){R=P,F=I,X=s*R+e*F+i,W=-d,N=f;let J=s*W+e*N;H=-J+r,Z=J+r,he=3,we=1,so(l,c,o,n,p,g,R,F)}else if(k===1){R=P,F=I,X=s*R+e*F+r,W=f,N=d;let J=s*W+e*N;H=-J+i,Z=J+i,he=2,we=4,so(l,c,o,n,p,g,R,F)}else if(k===2){R=-P,F=-I,X=o*R+n*F+l,W=-g,N=p;let J=o*W+n*N;H=-J+c,Z=J+c,he=3,we=1,so(i,r,s,e,f,d,R,F)}else{R=-P,F=-I,X=o*R+n*F+c,W=p,N=g;let J=o*W+n*N;H=-J+l,Z=J+l,he=2,we=4,so(i,r,s,e,f,d,R,F)}if(El(_l,pt,-W,-N,H,he)<2||El(qi,_l,W,N,Z,we)<2)return 0;let Oe=0;for(let J=0;J<2;J++){let $e=J*6,Xe=qi[$e],Be=qi[$e+1],st=R*Xe+F*Be-X;if(st>0)continue;let ii=Xe-R*st,Ye=Be-F*st,ot=qi[$e+2],Qe=qi[$e+3],nt=qi[$e+4],At=qi[$e+5],Yi,Qi,Ki,Zi;k>=2?([ot,Qe,nt,At]=[nt,At,ot,Qe],Yi=Xe-s,Qi=Be-e,Ki=ii-o,Zi=Ye-n):(Yi=ii-s,Qi=Ye-e,Ki=Xe-o,Zi=Be-n);let Wt=Oe*7;u[Wt+0]=ot&255|(Qe&255)<<8|(nt&255)<<16|(At&255)<<24,u[Wt+1]=f*Yi+d*Qi,u[Wt+1+1]=-d*Yi+f*Qi,u[Wt+3]=p*Ki+g*Zi,u[Wt+3+1]=-g*Ki+p*Zi,u[Wt+5]=-P,u[Wt+5+1]=-I,Oe++}return Oe}var Ml=s=>31-Math.clz32(s&-s);function Ru(s){let e=s+2654435769;return e^=e>>>16,e=Math.imul(e,2146121005),e^=e>>>15,e=Math.imul(e,2221713035),e^=e>>>16,e>>>0}var Kn=(s,e,t,i)=>s>t||s===t&&e>i,no=class{colors=new Int32Array(0);colorStart=new Int32Array(65);colorBodies=new Int32Array(0);next=new Int32Array(0);pending=new Uint8Array(0);prio=new Uint32Array(0);resize(e){if(this.colors.length===e)return;let t=new Int32Array(e).fill(-1);t.set(this.colors.subarray(0,Math.min(e,this.colors.length))),this.colors=t,this.next=new Int32Array(e),this.pending=new Uint8Array(e),this.colorBodies=new Int32Array(e),this.prio=Uint32Array.from({length:e},(i,r)=>Ru(r))}run(e,t,i,r,o,n){this.resize(e);let{colors:a,next:l,pending:c,prio:u}=this,f=(y,A)=>{let x=o[y*4+1],B=x===A?o[y*4+2]:x;return B>=0&&t[B]?B:-1},d=(y,A)=>{let x=0,B=0;for(let E=i[y];E<i[y+1];E++){let L=f(r[E],y);if(L<0||A&&c[L])continue;let M=a[L];M<0||(M<32?x|=1<<M:B|=1<<M-32)}return~x!==0?Ml(~x):~B!==0?32+Ml(~B):63};for(let y=0;y<e;y++){if(l[y]=a[y],!t[y]||a[y]<0)continue;let A=!0;for(let x=i[y];x<i[y+1]&&A;x++){let B=f(r[x],y);B>=0&&!Kn(u[y],y,u[B],B)&&(A=!1)}A&&(l[y]=Math.min(a[y],d(y,!1)))}a.set(l);let p=()=>{let y=0;for(let A=0;A<e;A++)if(c[A]=0,!!t[A]){if(a[A]<0)c[A]=1;else for(let x=i[A];x<i[A+1];x++){let B=f(r[x],A);if(B>=0&&a[B]===a[A]&&Kn(u[B],B,u[A],A)){c[A]=1;break}}y+=c[A]}return y},g=p(),h=0;for(;g>0&&h<n;){h++;for(let y=0;y<e;y++){if(l[y]=-2,!c[y])continue;let A=!0;for(let x=i[y];x<i[y+1]&&A;x++){let B=f(r[x],y);B>=0&&c[B]&&!Kn(u[y],y,u[B],B)&&(A=!1)}A&&(l[y]=d(y,!0))}for(let y=0;y<e;y++)l[y]!==-2&&(a[y]=l[y],c[y]=0,g--)}let m=0;if(g>0){for(let y=0;y<e;y++)c[y]&&a[y]<0&&(a[y]=0);m=p()}let b=this.colorStart;b.fill(0);let v=0;for(let y=0;y<e;y++)t[y]&&(b[a[y]+1]++,v=Math.max(v,a[y]+1));for(let y=0;y<64;y++)b[y+1]+=b[y];let w=b.slice(0,64);for(let y=0;y<e;y++)t[y]&&(this.colorBodies[w[a[y]]++]=y);return{numColors:v,conflicts:m,rounds:h}}};var zl=0,xi=1,Il=2,uo=3,Zr=4,Rl=[0,3,1,1,2],ea=.05,j=4,O=32,se=0,te=3,Q=6,Le=9,xe=12,Pt=15,fe=18,U=21,Y=23,re=25,ge=26,Fe=27,Vi=28,Lr=class{params=to();options;bodyCount=0;pose;initial;inertial;velocity;prevVelocity;shape;props;dynamic=new Uint8Array(0);jointCount=0;contactCount=0;info=new Int32Array(0);data;handles=[];prevCount=0;prevKeys=new Float64Array(0);prevInfo=new Int32Array(0);prevData=new Float64Array(0);ignorePairs=[];noCollide=new Float64Array(0);noCollideCount=0;noCollideDirty=!0;adjStart=new Int32Array(1);adjList=new Int32Array(0);broadphase=new ro;coloring=new no;numColors=0;colorConflicts=0;colorRounds=0;profiling=!1;profile={};phaseStart=0;contactOut=new Float64Array(14);dxBuf=new Float64Array(0);constructor(e={}){this.options={precision:"f32",order:"colored",colorRounds:32,...e},this.pose=this.real(0),this.initial=this.real(0),this.inertial=this.real(0),this.velocity=this.real(0),this.prevVelocity=this.real(0),this.shape=this.real(0),this.props=this.real(0),this.data=this.real(0)}real(e){return this.options.precision==="f32"?new Float32Array(e):new Float64Array(e)}grow(e,t){if(e.length>=t)return e;let i=new e.constructor(Math.max(t,e.length*2,16));return i.set(e),i}clear(){this.bodyCount=0,this.jointCount=0,this.contactCount=0,this.prevCount=0,this.handles=[],this.ignorePairs=[],this.noCollideDirty=!0,this.coloring.resize(0)}addBody(e,t,i,r,o=[0,0,0]){let n=this.bodyCount++,a=this.bodyCount*4;this.pose=this.grow(this.pose,a),this.initial=this.grow(this.initial,a),this.inertial=this.grow(this.inertial,a),this.velocity=this.grow(this.velocity,a),this.prevVelocity=this.grow(this.prevVelocity,a),this.shape=this.grow(this.shape,a),this.props=this.grow(this.props,a),this.dynamic=this.grow(this.dynamic,this.bodyCount);let l=e[0]*e[1]*t;return this.pose.set([r[0],r[1],r[2]??0,0],n*4),this.velocity.set([o[0],o[1],o[2]??0,0],n*4),this.prevVelocity.set(this.velocity.subarray(n*4,n*4+4),n*4),this.shape.set([e[0],e[1],l,l*(e[0]*e[0]+e[1]*e[1])/12],n*4),this.props.set([i,Math.hypot(e[0]*.5,e[1]*.5),0,0],n*4),this.dynamic[n]=l>0?1:0,n}allocConstraint(){let e=this.jointCount++,t=this.jointCount+this.contactCount;this.info=this.grow(this.info,t*j),this.data=this.grow(this.data,t*O),this.contactCount>0&&(this.info.copyWithin((e+1)*j,e*j,(t-1)*j),this.data.copyWithin((e+1)*O,e*O,(t-1)*O)),this.data.fill(0,e*O,e*O+O);for(let i=0;i<3;i++)this.data[e*O+Q+i]=1/0,this.data[e*O+Le+i]=-1/0,this.data[e*O+xe+i]=1/0,this.data[e*O+Pt+i]=1/0;return this.handles[e]=null,this.noCollideDirty=!0,e}setInfo(e,t,i,r){this.info.set([t,i,r,0],e*j)}addJoint(e,t,i,r,o=[1/0,1/0,1/0],n=1/0){let a=this.allocConstraint();this.setInfo(a,xi,e,t);let l=this.data,c=a*O;l.set(o,c+Q),l[c+xe+2]=n,l[c+Le+2]=-n,l[c+Pt+2]=n,l.set(i,c+U),l.set(r,c+Y),l[c+re]=(e>=0?this.pose[e*4+2]:0)-this.pose[t*4+2];let u=(e>=0?this.shape[e*4]:0)+this.shape[t*4],f=(e>=0?this.shape[e*4+1]:0)+this.shape[t*4+1];l[c+ge]=u*u+f*f;let d={slot:a,alive:!0};return this.handles[a]=d,d}setJointWorldAnchor(e,t,i){e.alive&&(this.data[e.slot*O+U]=t,this.data[e.slot*O+U+1]=i)}removeJoint(e){e.alive&&(this.disable(e.slot),e.alive=!1)}addSpring(e,t,i,r,o,n){let a=this.allocConstraint();this.setInfo(a,Il,e,t);let l=a*O;this.data[l+Q]=o,this.data.set(i,l+U),this.data.set(r,l+Y),this.data[l+re]=n}addMotor(e,t,i,r){let o=this.allocConstraint();this.setInfo(o,uo,e,t);let n=o*O;this.data[n+xe]=r,this.data[n+Le]=-r,this.data[n+re]=i}ignoredPairs(){return this.ignorePairs}addIgnoreCollision(e,t){this.ignorePairs.push(Pr(e,t)),this.noCollideDirty=!0}loadFromReference(e){this.clear();let t=Object.keys(to());Object.assign(this.params,Object.fromEntries(t.map(r=>[r,e[r]])));let i=new Map(e.bodies.map((r,o)=>[r,o]));for(let r of e.bodies){let o=this.addBody(r.size,0,r.friction,r.position,r.velocity);this.shape[o*4+2]=r.mass,this.shape[o*4+3]=r.moment,this.dynamic[o]=r.mass>0?1:0}for(let r of e.forces){let o=r.bodyA?i.get(r.bodyA):-1,n=i.get(r.bodyB);if(r instanceof Qs){let a=this.addJoint(o,n,r.rA,r.rB,[r.stiffness[0],r.stiffness[1],r.stiffness[2]],r.fracture[2]);this.data[a.slot*O+re]=r.restAngle,this.data[a.slot*O+ge]=r.torqueArm}else r instanceof Ks?this.addSpring(o,n,r.rA,r.rB,r.stiffness[0],r.rest):r instanceof eo?this.addMotor(o,n,r.speed,r.fmax[0]):r instanceof Zs&&this.addIgnoreCollision(o,n)}}step(){let e=this.params,t=e.postStabilize&&!e.vbd,i=e.vbd?0:e.alpha;this.phaseStart=this.profiling?performance.now():0,this.saveContacts(),this.findPairs(),this.mark("broadphase"),this.initJoints(),this.narrowphase(),this.mark("narrowphase"),this.warmStartConstraints(t,i),this.buildAdjacency(),this.mark("adjacency"),this.colorBodies(),this.mark("coloring"),this.warmStartBodies();let r=e.iterations+(t?1:0);for(let o=0;o<r;o++){let n=t?o<e.iterations?1:0:i;this.primal(n),this.mark("primal"),o<e.iterations&&this.dual(n),o===e.iterations-1&&this.updateVelocities(),this.mark("dual")}t&&this.refreshStick()}mark(e){if(!this.profiling)return;let t=performance.now();this.profile[e]=(this.profile[e]??0)+t-this.phaseStart,this.phaseStart=t}resetProfile(){for(let e of Object.keys(this.profile))delete this.profile[e]}saveContacts(){let e=this.contactCount,t=this.jointCount;this.prevKeys.length<e&&(this.prevKeys=new Float64Array(e*2),this.prevInfo=new Int32Array(e*2*j),this.prevData=new Float64Array(e*2*O));for(let i=0;i<e;i++){let r=t+i;this.prevKeys[i]=Pr(this.info[r*j+1],this.info[r*j+2])}this.prevInfo.set(this.info.subarray(t*j,(t+e)*j)),this.prevData.set(this.data.subarray(t*O,(t+e)*O)),this.prevCount=e,this.contactCount=0}findPairs(){if(this.noCollideDirty){let e=[...this.ignorePairs];for(let t=0;t<this.jointCount;t++){let i=this.info[t*j+1],r=this.info[t*j+2];this.info[t*j]!==zl&&i>=0&&e.push(Pr(i,r))}this.noCollide=Float64Array.from(e).sort(),this.noCollideCount=e.length,this.noCollideDirty=!1}this.broadphase.findPairs(this.bodyCount,this.pose,this.props,this.dynamic,this.noCollide,this.noCollideCount)}initJoints(){let{info:e,data:t,pose:i}=this,r=0;for(let o=0;o<this.jointCount;o++){let n=o*O;if(e[o*j]===xi){if(t[n+Q]===0&&t[n+Q+1]===0&&t[n+Q+2]===0){let u=this.handles[o];u&&(u.alive=!1);continue}let l=e[o*j+1],c=e[o*j+2];this.jointC(l,c,n,i,t,n+fe)}r!==o&&(e.copyWithin(r*j,o*j,(o+1)*j),t.copyWithin(r*O,n,n+O),this.handles[r]=this.handles[o],this.handles[r]&&(this.handles[r].slot=r)),r++}if(r!==this.jointCount){for(let o=r;o<this.jointCount;o++)this.handles[o]=null;this.jointCount=r,this.noCollideDirty=!0}}jointC(e,t,i,r,o,n,a=o){let l,c,u;if(e>=0){let h=Math.cos(r[e*4+2]),m=Math.sin(r[e*4+2]),b=o[i+U],v=o[i+U+1];l=h*b-m*v+r[e*4],c=m*b+h*v+r[e*4+1],u=r[e*4+2]}else l=o[i+U],c=o[i+U+1],u=0;let f=Math.cos(r[t*4+2]),d=Math.sin(r[t*4+2]),p=o[i+Y],g=o[i+Y+1];a[n]=l-(f*p-d*g+r[t*4]),a[n+1]=c-(d*p+f*g+r[t*4+1]),a[n+2]=(u-r[t*4+2]-o[i+re])*o[i+ge]}narrowphase(){let{pose:e,shape:t,props:i}=this,r=this.broadphase.pairs,o=this.contactOut;for(let n=0;n<this.broadphase.pairCount;n++){let a=r[n],l=Math.floor(a/2097152),c=a-l*2097152,u=oo(e[l*4],e[l*4+1],e[l*4+2],t[l*4]*.5,t[l*4+1]*.5,e[c*4],e[c*4+1],e[c*4+2],t[c*4]*.5,t[c*4+1]*.5,o);if(u===0)continue;let f=0,d=this.prevCount;for(;f<d;){let h=f+d>>>1;this.prevKeys[h]<a?f=h+1:d=h}let p=f,g=Math.sqrt(i[l*4]*i[c*4]);for(let h=0;h<u;h++){let m=this.jointCount+this.contactCount++;this.info=this.grow(this.info,(m+1)*j),this.data=this.grow(this.data,(m+1)*O);let b=this.data,v=m*O,w=h*7,y=o[w+0];this.info.set([Zr,l,c,y],m*j),b.fill(0,v,v+O),b[v+Q]=b[v+Q+1]=1/0,b[v+Le]=-1/0,b[v+xe]=0,b[v+Pt]=b[v+Pt+1]=1/0,b[v+U]=o[w+1],b[v+U+1]=o[w+1+1],b[v+Y]=o[w+3],b[v+Y+1]=o[w+3+1],b[v+re]=g,b[v+ge]=o[w+5],b[v+Fe]=o[w+5+1];let A=-1;for(let S=p;S<this.prevCount&&this.prevKeys[S]===a;S++)this.prevInfo[S*j+3]===y&&(A=S);if(A<0&&this.params.matchNearest){let S=ea*Math.min(t[l*4],t[l*4+1],t[c*4],t[c*4+1]);for(let P=p;P<this.prevCount&&this.prevKeys[P]===a;P++){let I=Math.hypot(this.prevData[P*O+U]-b[v+U],this.prevData[P*O+U+1]-b[v+U+1]);I<=S&&(S=I,A=P)}}if(A>=0){let S=A*O;b[v+se]=this.prevData[S+se],b[v+se+1]=this.prevData[S+se+1],b[v+te]=this.prevData[S+te],b[v+te+1]=this.prevData[S+te+1],this.prevData[S+Vi]&&(b[v+U]=this.prevData[S+U],b[v+U+1]=this.prevData[S+U+1],b[v+Y]=this.prevData[S+Y],b[v+Y+1]=this.prevData[S+Y+1])}let[x,B]=Ai(e[l*4+2],b[v+U],b[v+U+1]),[E,L]=Ai(e[c*4+2],b[v+Y],b[v+Y+1]),M=b[v+ge],z=b[v+Fe],_=e[l*4]+x-e[c*4]-E,k=e[l*4+1]+B-e[c*4+1]-L;b[v+fe]=M*_+z*k+5e-4,b[v+fe+1]=z*_-M*k}}}warmStartConstraints(e,t){let i=this.params,r=this.data,o=this.jointCount+this.contactCount;for(let n=0;n<o;n++){let a=Rl[this.info[n*j]],l=n*O;for(let c=0;c<a;c++){if(i.vbd){r[l+se+c]=Sr(r[l+Q+c],i.vbdStiffness);continue}e||(r[l+te+c]=r[l+te+c]*t*i.gamma),r[l+se+c]=Sr(kr(r[l+se+c]*i.gamma,1,1e9),r[l+Q+c])}}}prepareTopology(){this.buildAdjacency(),this.colorBodies()}buildAdjacency(){let e=this.bodyCount,t=this.jointCount+this.contactCount;this.adjStart=this.grow(this.adjStart,e+1),this.adjList=this.grow(this.adjList,t*2);let i=this.adjStart;i.fill(0,0,e+1);for(let o=0;o<t;o++)for(let n=1;n<=2;n++){let a=this.info[o*j+n];a>=0&&this.dynamic[a]&&i[a+1]++}for(let o=0;o<e;o++)i[o+1]+=i[o];let r=i.slice(0,e);for(let o=0;o<t;o++)for(let n=1;n<=2;n++){let a=this.info[o*j+n];a>=0&&this.dynamic[a]&&(this.adjList[r[a]++]=o)}}colorBodies(){if(this.options.order!=="colored")return;let e=this.coloring.run(this.bodyCount,this.dynamic,this.adjStart,this.adjList,this.info,this.options.colorRounds);this.numColors=e.numColors,this.colorConflicts=e.conflicts,this.colorRounds=e.rounds}warmStartBodies(){let{dt:e,gravity:t}=this.params,{pose:i,velocity:r,initial:o,inertial:n,prevVelocity:a}=this;for(let l=0;l<this.bodyCount;l++){let c=l*4;r[c+2]=kr(r[c+2],-50,50),n[c]=i[c]+r[c]*e,n[c+1]=i[c+1]+r[c+1]*e,n[c+2]=i[c+2]+r[c+2]*e,this.dynamic[l]&&(n[c+1]+=t*e*e);let u=(r[c+1]-a[c+1])/e*Ll(t),f=kr(u/Math.abs(t),0,1);Number.isFinite(f)||(f=0),o[c]=i[c],o[c+1]=i[c+1],o[c+2]=i[c+2],i[c]=i[c]+r[c]*e,i[c+1]=i[c+1]+r[c+1]*e+t*f*e*e,i[c+2]=i[c+2]+r[c+2]*e}}eC=new Float64Array(3);eMin=new Float64Array(3);eMax=new Float64Array(3);eJ=new Float64Array(9);eG=new Float64Array(9);evalConstraint(e,t,i){let{info:r,data:o,pose:n,initial:a}=this,l=r[e*j],c=r[e*j+1],u=r[e*j+2],f=e*O,{eC:d,eMin:p,eMax:g,eJ:h,eG:m}=this,b=Rl[l];for(let w=0;w<b;w++)p[w]=o[f+Le+w],g[w]=o[f+xe+w];let v=i===c;if(m.fill(0),l===xi){this.jointC(c,u,f,n,o,0,d);for(let w=0;w<3;w++)o[f+Q+w]===1/0&&(d[w]-=o[f+fe+w]*t);if(i>=0){let w=n[i*4+2],[y,A]=Ai(w,o[f+(v?U:Y)],o[f+(v?U:Y)+1]),x=v?1:-1;h[0]=x,h[1]=0,h[2]=-x*A,h[3]=0,h[4]=x,h[5]=x*y,h[6]=0,h[7]=0,h[8]=x*o[f+ge],m[2]=Math.abs(y),m[5]=Math.abs(A)}}else if(l===Il){let[w,y]=Ol(n,c,o[f+U],o[f+U+1]),[A,x]=Ol(n,u,o[f+Y],o[f+Y+1]),B=w-A,E=y-x,L=B*B+E*E,M=Math.sqrt(L);if(d[0]=M-o[f+re],i>=0&&L!==0){let z=B/M,_=E/M,k=(1-z*z)/M,S=-z*_/M,P=(1-_*_)/M,I=n[i*4+2],R=v?U:Y,[F,X]=Ai(I,-o[f+R+1],o[f+R]),[W,N]=Ai(I,o[f+R],o[f+R+1]),H=k*F+S*X,Z=S*F+P*X,he=z*W+_*N,we=z*F+_*X,Oe=v?1:-1;h[0]=Oe*z,h[1]=Oe*_,h[2]=Oe*we;let J=v?-he-he:he+he;m[0]=Math.hypot(k,S,H),m[1]=Math.hypot(S,P,Z),m[2]=Math.hypot(H,Z,J)}else i>=0&&h.fill(0,0,3)}else if(l===uo){let w=c>=0?n[c*4+2]-a[c*4+2]:0,y=n[u*4+2]-a[u*4+2];d[0]=w-y-o[f+re]*this.params.dt,i>=0&&(h[0]=0,h[1]=0,h[2]=v?1:-1)}else if(l===Zr){let w=o[f+ge],y=o[f+Fe],A=y,x=-w,[B,E]=Ai(a[c*4+2],o[f+U],o[f+U+1]),[L,M]=Ai(a[u*4+2],o[f+Y],o[f+Y+1]),z=B*y-E*w,_=-(L*y-M*w),k=B*x-E*A,S=-(L*x-M*A),P=n[c*4]-a[c*4],I=n[c*4+1]-a[c*4+1],R=n[c*4+2]-a[c*4+2],F=n[u*4]-a[u*4],X=n[u*4+1]-a[u*4+1],W=n[u*4+2]-a[u*4+2];d[0]=o[f+fe]*(1-t)+w*P+y*I+z*R+-w*F+-y*X+_*W,d[1]=o[f+fe+1]*(1-t)+A*P+x*I+k*R+-A*F+-x*X+S*W;let N=Math.abs(o[f+te])*o[f+re];g[1]=N,p[1]=-N,i>=0&&(v?(h[0]=w,h[1]=y,h[2]=z,h[3]=A,h[4]=x,h[5]=k):(h[0]=-w,h[1]=-y,h[2]=_,h[3]=-A,h[4]=-x,h[5]=S))}return b}solveBody(e,t){let i=this.params,{shape:r,pose:o,inertial:n,data:a}=this,l=i.dt*i.dt,c=r[e*4+2]/l,u=r[e*4+3]/l,f=c,d=0,p=c,g=0,h=0,m=u,b=c*(o[e*4]-n[e*4]),v=c*(o[e*4+1]-n[e*4+1]),w=u*(o[e*4+2]-n[e*4+2]),{eC:y,eMin:A,eMax:x,eJ:B,eG:E}=this,L=this.adjStart,M=this.adjList;for(let H=L[e+1]-1;H>=L[e];H--){let Z=M[H],he=this.evalConstraint(Z,t,e),we=Z*O,Oe=!i.vbd;for(let J=0;J<he;J++){let $e=a[we+Q+J],Xe=Oe&&$e===1/0?a[we+te+J]:0,Be=a[we+se+J],st=y[J],ii=Be*st+Xe,Ye=kr(ii,A[J],x[J]),ot=Math.abs(Ye);i.stiffnessRescale&&st!==0&&(ii<A[J]?Be=Math.abs((A[J]-Xe)/st):ii>x[J]&&(Be=Math.abs((x[J]-Xe)/st)));let Qe=B[J*3],nt=B[J*3+1],At=B[J*3+2];b+=Qe*Ye,v+=nt*Ye,w+=At*Ye,f+=Qe*Qe*Be+E[J*3]*ot,d+=nt*Qe*Be,p+=nt*nt*Be+E[J*3+1]*ot,g+=At*Qe*Be,h+=At*nt*Be,m+=At*At*Be+E[J*3+2]*ot}}let z=f,_=d/f,k=g/f,S=p-_*_*z,P=(h-_*k*z)/S,I=m-(k*k*z+P*P*S),R=v-_*b,X=(w-k*b-P*R)/I,W=R/S-P*X,N=b/z-_*W-k*X;this.dxBuf[e*3]=N,this.dxBuf[e*3+1]=W,this.dxBuf[e*3+2]=X}applyDx(e){this.pose[e*4]-=this.dxBuf[e*3],this.pose[e*4+1]-=this.dxBuf[e*3+1],this.pose[e*4+2]-=this.dxBuf[e*3+2]}primal(e){if(this.dxBuf.length<this.bodyCount*3&&(this.dxBuf=new Float64Array(this.bodyCount*3)),this.options.order==="sequential"){for(let r=this.bodyCount-1;r>=0;r--)this.dynamic[r]&&(this.solveBody(r,e),this.applyDx(r));return}let{colorStart:t,colorBodies:i}=this.coloring;for(let r=0;r<this.numColors;r++){for(let o=t[r];o<t[r+1];o++)this.solveBody(i[o],e);for(let o=t[r];o<t[r+1];o++)this.applyDx(i[o])}}dual(e){let t=this.params,i=this.data,{eC:r,eMin:o,eMax:n}=this,a=this.jointCount+this.contactCount;for(let l=0;l<a;l++){let c=this.info[l*j];if(c===zl)continue;let u=this.evalConstraint(l,e,-1),f=l*O;c===Zr&&(i[f+Vi]=Math.abs(i[f+te+1])<n[1]&&Math.abs(i[f+fe+1])<.01?1:0);for(let d=0;d<u;d++){let p=i[f+Q+d],g=!t.vbd&&p===1/0?i[f+te+d]:0,h=kr(i[f+se+d]*r[d]+g,o[d],n[d]);i[f+te+d]=h,Math.abs(h)>=i[f+Pt+d]&&this.disable(l),!t.vbd&&h>o[d]&&h<n[d]&&(i[f+se+d]=Sr(i[f+se+d]+t.beta*Math.abs(r[d]),Sr(1e9,i[f+Q+d])))}}}refreshStick(){let e=this.data;for(let t=0;t<this.contactCount;t++){let i=(this.jointCount+t)*O,r=Math.abs(e[i+te])*e[i+re];e[i+Vi]=Math.abs(e[i+te+1])<r&&Math.abs(e[i+fe+1])<.01?1:0}}disable(e){let t=e*O;this.data.fill(0,t+se,t+se+3),this.data.fill(0,t+te,t+te+3),this.data.fill(0,t+Q,t+Q+3)}updateVelocities(){let{dt:e}=this.params,{pose:t,initial:i,velocity:r,prevVelocity:o}=this;for(let n=0;n<this.bodyCount;n++){let a=n*4;o[a]=r[a],o[a+1]=r[a+1],o[a+2]=r[a+2],this.dynamic[n]&&(r[a]=(t[a]-i[a])/e,r[a+1]=(t[a+1]-i[a+1])/e,r[a+2]=(t[a+2]-i[a+2])/e)}}pick(e,t){for(let i=this.bodyCount-1;i>=0;i--){let[r,o]=Ai(-this.pose[i*4+2],e-this.pose[i*4],t-this.pose[i*4+1]);if(Math.abs(r)<=this.shape[i*4]*.5&&Math.abs(o)<=this.shape[i*4+1]*.5)return{body:i,local:[r,o]}}return null}kineticEnergy(){let e=0;for(let t=0;t<this.bodyCount;t++){if(!this.dynamic[t])continue;let i=t*4,r=this.velocity;e+=.5*this.shape[i+2]*(r[i]*r[i]+r[i+1]*r[i+1])+.5*this.shape[i+3]*r[i+2]*r[i+2]}return e}maxJointError(){let e=0,t=new Float64Array(3);for(let i=0;i<this.jointCount;i++){if(this.info[i*j]!==xi)continue;let r=i*O;this.jointC(this.info[i*j+1],this.info[i*j+2],r,this.pose,this.data,0,t);for(let o=0;o<2;o++)this.data[r+Q+o]===1/0&&(e=Math.max(e,Math.abs(t[o])))}return e}isContactPairIgnored(e,t){return Qn(this.noCollide,this.noCollideCount,Pr(e,t))}};function Ai(s,e,t){let i=Math.cos(s),r=Math.sin(s);return[i*e-r*t,r*e+i*t]}function Ol(s,e,t,i){let r=Math.cos(s[e*4+2]),o=Math.sin(s[e*4+2]);return[r*t-o*i+s[e*4],o*t+r*i+s[e*4+1]]}var es=`
3609
- ${Nt}
3819
+ `),xi=class{device;pipelines;layout;watch;table;events;params;setSlots;capacity;group=null;bound=[];flip=0;bodies;constructor(e,t,i,r,o,n=3){this.device=e,this.bodies=t,this.capacity=o,this.setSlots=2**Math.ceil(Math.log2(Math.max(64,2*r)));let a=e.createShaderModule({label:"contact events",code:n===2?zf:as}),l=["read-only-storage","read-only-storage","read-only-storage","read-only-storage","read-only-storage","storage","storage","uniform"];this.layout=e.createBindGroupLayout({label:"contact events",entries:l.map((d,p)=>({binding:p,visibility:GPUShaderStage.COMPUTE,buffer:{type:d}}))});let c=e.createPipelineLayout({bindGroupLayouts:[this.layout]}),u=d=>e.createComputePipeline({label:`contact events ${d}`,layout:c,compute:{module:a,entryPoint:d}});this.pipelines={touching:u("touching"),ended:u("ended")};let f=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC;this.watch=e.createBuffer({label:"contact watch",size:Math.max(16,i*4),usage:f}),this.table=e.createBuffer({label:"contact sets",size:(xa+4*this.setSlots)*4,usage:f}),this.events=e.createBuffer({label:"contact events",size:o*kr*16,usage:f}),this.params=e.createBuffer({label:"contact params",size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST})}setWatched(e,t){let i=e.map((r,o)=>[r,t[o]?1:0]).sort((r,o)=>r[0]-o[0]);for(let r=0;r<i.length;){let o=r+1;for(;o<i.length&&i[o][0]===i[o-1][0]+1;)o++;this.device.queue.writeBuffer(this.watch,i[r][0]*4,Uint32Array.from(i.slice(r,o),n=>n[1])),r=o}}run(e,t,i,r){let o=this.device,n=[this.bodies,e.manifolds,e.contacts,e.counters,this.watch,this.table,this.events,this.params];(!this.group||n.some((d,p)=>d!==this.bound[p]))&&(this.bound=n,this.group=o.createBindGroup({layout:this.layout,entries:n.map((d,p)=>({binding:p,resource:{buffer:d}}))})),this.flip=1-this.flip;let[a,l]=this.flip?[0,this.setSlots]:[this.setSlots,0],c=new Uint32Array([a,l,this.setSlots-1,this.capacity,t,i,0,0]);new Float32Array(c.buffer)[6]=r,o.queue.writeBuffer(this.params,0,c);let u=o.createCommandEncoder({label:"contact events"});u.clearBuffer(this.table,(xa+2*l)*4,2*this.setSlots*4);let f=u.beginComputePass({label:"contact events"});f.setBindGroup(0,this.group),f.setPipeline(this.pipelines.touching),f.dispatchWorkgroups(Math.max(1,Math.ceil(t/64))),f.setPipeline(this.pipelines.ended),f.dispatchWorkgroups(Math.ceil(this.setSlots/64)),f.end(),o.queue.submit([u.finish()])}async read(){let e=this.device,t=16+this.capacity*kr*16,i=e.createBuffer({size:t,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),r=e.createCommandEncoder({label:"read contact events"});r.copyBufferToBuffer(this.table,0,i,0,16),r.copyBufferToBuffer(this.events,0,i,16,t-16),r.clearBuffer(this.table,0,16),e.queue.submit([r.finish()]),await i.mapAsync(GPUMapMode.READ);let o=i.getMappedRange().slice(0);i.unmap(),i.destroy();let n=new Uint32Array(o),a=new Float32Array(o),l=Math.min(n[0],this.capacity),c=[];for(let u=0;u<l;u++){let f=4+u*kr*4;c.push({kind:n[f],a:n[f+1],b:n[f+2],step:n[f+3],point:[a[f+4],a[f+5],a[f+6]],impulse:a[f+7],normal:[a[f+8],a[f+9],a[f+10]]})}return c.sort((u,f)=>u.step-f.step),{events:c,dropped:n[0]-l,full:n[1]!==0}}destroy(){for(let e of[this.watch,this.table,this.events,this.params])e.destroy()}};var yc=[0,1,2,3,5,4,0,3,4,0,4,1,1,4,5,1,5,2,2,5,3,2,3,0],Pr=yc.slice();for(let s=0;s<Pr.length;s+=3)[Pr[s+1],Pr[s+2]]=[Pr[s+2],Pr[s+1]];var mo=(s,e,t)=>{let i=Array.from(s??[]);if(i.length!==e||!i.every(Number.isFinite))throw Error(`${t} requires ${e} finite values`);return i},vc=(s,e)=>{if(!Number.isFinite(s)||s<=0)throw Error(`${e} must be positive and finite`);return s};function xc(s){let e=[0,1,2].map(u=>s.reduce((f,d)=>f+d[u],0)/s.length),[t,i,r,o]=s,n=i.map((u,f)=>u-t[f]),a=r.map((u,f)=>u-t[f]),l=(n[1]*a[2]-n[2]*a[1])*(t[0]-o[0])+(n[2]*a[0]-n[0]*a[2])*(t[1]-o[1])+(n[0]*a[1]-n[1]*a[0])*(t[2]-o[2]),c=zn(s.flatMap(u=>u.map((f,d)=>f-e[d])),l>0?yc:Pr);if(!c)throw Error("Terrain contains a degenerate collision piece");return{shape:c,position:c.center.map((u,f)=>u+e[f]),rotation:c.rotation}}function ls({heights:s,columns:e,rows:t,spacing:i=1,origin:r=[0,0,0],upAxis:o=1,baseHeight:n,holes:a}={}){for(let[g,b]of Object.entries({columns:e,rows:t}))if(!Number.isInteger(b)||b<2)throw Error(`${g} must be an integer >= 2`);let l=mo(s,e*t,"heights"),c=mo(r,3,"origin");if(![0,1,2].includes(o))throw Error("upAxis must be 0, 1 or 2");let u=typeof i=="number"?[i,i]:mo(i,2,"spacing");u.forEach(g=>vc(g,"spacing"));let f=n??l.reduce((g,b)=>Math.min(g,b),1/0)-2;if(!Number.isFinite(f)||l.some(g=>g<=f))throw Error("baseHeight must be below every terrain height");let d=(e-1)*(t-1);if(a&&a.length!==d)throw Error("holes requires one value per terrain cell");let p=[0,1,2].filter(g=>g!==o),m=[],h=(g,b)=>{let y=[...c];return y[p[0]]+=g*u[0],y[p[1]]+=b*u[1],y[o]+=l[b*e+g],y};for(let g=0;g<t-1;g++)for(let b=0;b<e-1;b++){if(a?.[g*(e-1)+b])continue;let y=h(b,g),A=h(b+1,g),v=h(b,g+1),x=h(b+1,g+1);for(let w of[[y,A,v],[A,x,v]])m.push(xc([...w,...w.map(B=>{let L=[...B];return L[o]=c[o]+f,L})]))}return{kind:"heightfield",pieces:m,triangleCount:m.length}}function cs({positions:s,indices:e,thickness:t=.1}={}){if(!s||s.length%3)throw Error("positions requires xyz triples");let i=mo(s,s.length,"positions"),r=i.length/3;if(e===void 0&&r%3)throw Error("Nonindexed positions require three vertices per triangle");let o=e===void 0?Array.from({length:r},(a,l)=>l):Array.from(e);if(!o.length||o.length%3||!o.every(a=>Number.isInteger(a)&&a>=0&&a<r))throw Error("indices requires valid triangle vertex indices");vc(t,"thickness");let n=[];for(let a=0;a<o.length;a+=3){let l=o.slice(a,a+3).map(g=>i.slice(g*3,g*3+3)),[c,u,f]=l,d=u.map((g,b)=>g-c[b]),p=f.map((g,b)=>g-c[b]),m=[d[1]*p[2]-d[2]*p[1],d[2]*p[0]-d[0]*p[2],d[0]*p[1]-d[1]*p[0]],h=Math.hypot(...m);h!==0&&n.push(xc([...l,...l.map(g=>g.map((b,y)=>b-m[y]*t/h))]))}if(!n.length)throw Error("Static mesh requires at least one nondegenerate triangle");return{kind:"static-mesh",pieces:n,triangleCount:n.length}}function go(s,e,t={}){if(t.mass!==void 0&&t.mass!==0)throw Error("Terrain is static and requires zero mass");let i=t.friction??.6,r=t.restitution??0;if(!Number.isFinite(i)||i<0)throw Error("friction must be nonnegative and finite");if(!Number.isFinite(r)||r<0||r>1)throw Error("restitution must be between 0 and 1");for(let o of["group","collidesWith"]){let n=t[o]??4294967295;if(!Number.isInteger(n)||n<0||n>4294967295)throw Error(`${o} must be an unsigned 32-bit integer`)}if(!e?.pieces?.length)throw Error("Terrain requires collision pieces");return e.pieces.map(o=>{let n=ar(s,o.shape,0,i,o.position,o.rotation);return Object.assign(n,{allowSleep:!1,isTrigger:!1,restitution:r,group:t.group??4294967295,collidesWith:t.collidesWith??4294967295}),n})}var mt=Object.freeze({BOX:"box",SPHERE:"sphere",CAPSULE:"capsule",CYLINDER:"cylinder",CONVEX_HULL:"convex-hull"}),Le=s=>s&&typeof s.x=="number"?[s.x,s.y,s.z,...typeof s.w=="number"?[s.w]:[]]:Array.from(s),us=new WeakMap,Lr=s=>{if(!Number.isInteger(s)||s<0||s>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");return s},bo=(s,e,t=!1)=>{if(!Number.isFinite(s)||(t?s<0:s<=0))throw Error(`${e} must be ${t?"nonnegative":"positive"} and finite`);return s},yo=class s{static async create({device:e,...t}={}){if(t.scene&&us.has(t.scene))throw Error("This scene already has an AVBD world");let i=!e;e||({device:e}=await ss({preferredLimits:{maxStorageBuffersPerShaderStage:9,maxStorageBufferBindingSize:512*1024*1024,maxBufferSize:1024*1024*1024}}));let r;try{return await Cr(e),r=new s(e,t),r.ownsDevice=i,r.scene&&r.autoAttach&&r.attachToScene(),r}catch(o){throw r?r.dispose():i&&e.destroy(),o}}constructor(e,{scene:t,gravity:i=[0,-10,0],timeStep:r=1/60,iterations:o=10,capacity:n=4096,syncMeshes:a=!0,maxSyncedBodies:l=2048,broadphase:c="auto",solverMode:u="auto",smallGroups:f,bvh:d={},autoAttach:p=!0,maxContactPairs:m=8192,maxContactEvents:h=4096,sleeping:g=!1}={}){if(this.device=e,this.scene=t,this.autoAttach=p,this.syncEnabled=a,this.maxSyncedBodies=l,!Number.isInteger(n)||n<1||!Number.isInteger(l)||l<0)throw Error("capacity and maxSyncedBodies must be valid integer counts");if(this.capacity=n,this.collisionOptions={broadphase:c,bvh:d,solverMode:u,smallGroups:f},this.ref=new ai,this.ref.dt=bo(r,"timeStep"),!Number.isInteger(o)||o<1)throw Error("iterations must be a positive integer");this.ref.iterations=o,this.aggregates=[],this.constraints=new Set,this.contactListeners=new Set;for(let[y,A]of Object.entries({maxContactPairs:m,maxContactEvents:h}))if(!Number.isInteger(A)||A<1)throw Error(`${y} must be a positive integer`);if(this.contactOptions={maxContactPairs:m,maxContactEvents:h},this.bodyReadback=new vi(e),this.sleepOptions=g,g!==!1&&g!==!0&&(typeof g!="object"||g===null))throw Error("sleeping must be a boolean or options object");this.commands=new Map,this.steps=0,this.errors=[],this.deviceLost=null;let b=new WeakRef(this);e.lost.then(y=>{let A=b.deref();!A||A.disposed||(A.deviceLost={reason:y.reason,message:y.message},A.errors.push(`WebGPU device lost: ${y.message||y.reason}`),A.dispose())}),this.setGravity(i),this.errorListener=y=>this.errors.push(y.error.message),e.addEventListener("uncapturederror",this.errorListener),t&&us.set(t,this)}setGravity(e){let t=Le(e);if(t.length!==3||!t.every(Number.isFinite))throw Error("gravity requires three finite components");let i=Math.hypot(...t);this.gravity=-i,this.up=i?t.map(r=>-r/i):[0,1,0],this.gpu&&(this.gpu.params.gravity=this.gravity,this.gpu.params.up=this.up),this.wakeAll()}get solverDecision(){return this.initialize(),{...this.gpu.solverDecision}}setSolverMode(e){this.initialize();let t=this.gpu.setSolverMode(e);return this.collisionOptions.solverMode=e,{...t}}initialize(){if(this.assertAlive(),this.gpu)return;if(this.syncEnabled&&this.aggregates.filter(r=>r.sync).length>this.maxSyncedBodies)throw Error("For large scenes use syncMeshes:false and draw the GPU body buffer directly");if(this.aggregates.length>this.capacity)throw Error(`Body capacity ${this.capacity} exceeded; size the world before initialization`);this.gpu=new gi(this.device,this.ref,ho(this.ref,{bodyCapacity:Math.max(1,this.capacity),spatialSort:!0,...this.collisionOptions})),Object.assign(this.gpu.params,{gravity:this.gravity,up:this.up}),this.gpu.externalBeforeStep=r=>{this.sleepManager?.before(r),this.flushCommands(r)},this.gpu.externalAfterStep=r=>this.sleepManager?.after(r);let e=new Map([...this.constraints].map(r=>[r.force,r])),t=[],i=0;for(let r of this.ref.forces){let o=e.get(r);o&&(o.attach(i++,!1),(o.type==="fixed"||o.type==="spring"&&o.rest===void 0)&&t.push({slot:o.slot,spring:o.type==="spring"}))}this.gpu.captureConstraintFrames(t),this.byGpuIndex=new Map(this.aggregates.map(r=>[this.gpu.gpuIndex(r.index),r.body]));for(let r of this.aggregates)(r.disposed||r.group!==4294967295||r.collidesWith!==4294967295)&&this.gpu.setFilters([this.gpu.gpuIndex(r.index)],[r.disposed?0:r.group],[r.disposed?0:r.collidesWith]);for(let r of this.aggregates)r.isTrigger&&this.gpu.setSensor(r.body.gpuIndex,!0);for(let r of this.aggregates)r.restitution>0&&this.gpu.setRestitution(r.body.gpuIndex,r.restitution);this.contactListeners.size&&this.initializeContacts(),this.sleepOptions&&(this.sleepManager=new Fi(this,this.sleepOptions===!0?{}:this.sleepOptions))}addAggregate(e,t,i={}){return new vo(e,t,i,this)}addAggregates(e){return e.map(({mesh:t,type:i,options:r})=>this.addAggregate(t,i,r))}addHeightfield(e){return this.addTerrain(ls(e),e)}addStaticMesh(e,t={}){e.computeWorldMatrix(!0);let i=e.getVerticesData("position"),r=e.getWorldMatrix().m;if(!i)throw Error("Static mesh requires vertex positions");let o=new Float64Array(i.length);for(let u=0;u<i.length;u+=3){let f=i[u],d=i[u+1],p=i[u+2];for(let m=0;m<3;m++)o[u+m]=r[m]*f+r[4+m]*d+r[8+m]*p+r[12+m]}let n=e.getIndices(),a=n?.length?Uint32Array.from(n):Uint32Array.from({length:i.length/3},(u,f)=>f),l=e.getVerticesData("normal"),c=e.getWorldMatrix().determinant()<0;for(let u=0;u<a.length;u+=3){let f=a[u]*3,d=a[u+1]*3,p=a[u+2]*3,m=[0,1,2].map(b=>i[d+b]-i[f+b]),h=[0,1,2].map(b=>i[p+b]-i[f+b]),g=!1;l?.length===i.length&&(g=[m[1]*h[2]-m[2]*h[1],m[2]*h[0]-m[0]*h[2],m[0]*h[1]-m[1]*h[0]].reduce((y,A,v)=>y+A*(l[f+v]+l[d+v]+l[p+v]),0)<0),g!==c&&([a[u+1],a[u+2]]=[a[u+2],a[u+1]])}return this.addTerrain(cs({positions:o,indices:a,thickness:t.thickness}),t)}addTerrain(e,t={}){if(this.assertAlive(),this.gpu)throw Error("Add static terrain before initializing the physics world");if(this.device.limits.maxStorageBuffersPerShaderStage<9)throw Error("Terrain collisions require nine storage buffer bindings");if(this.aggregates.length+(e?.pieces?.length??0)>this.capacity)throw Error("AVBD terrain exceeds body capacity; reserve space for its collision pieces");let r=go(this.ref,e,t).map(n=>new Aa(this,n)),o=!1;return{bodies:r.map(n=>n.body),triangleCount:e.triangleCount,kind:e.kind,dispose:()=>{if(o)return;o=!0;let n=new Set(r.map(a=>a.body));for(let a of[...this.constraints])(n.has(a.bodyA)||n.has(a.bodyB))&&a.dispose();if(this.gpu&&!this.disposed){let a=r.map(c=>c.body.gpuIndex),l=new Uint32Array(a.length);this.gpu.setFilters(a,l,l)}for(let a of r)a.disposed=a.body.disposed=!0,a.group=a.collidesWith=0,this.commands.delete(a.body);this.wakeAll()}}}addConstraint(e,t,i={}){return new os(this,e,t,i)}addJoint(e,t,i={}){return this.addConstraint(e,t,{...i,type:i.type??"ball"})}addWeld(e,t,i={}){return this.addConstraint(e,t,{...i,type:"fixed"})}addSpring(e,t,i={}){return this.addConstraint(e,t,{...i,type:"spring"})}enableSleeping(e={}){return this.assertAlive(),this.sleepOptions=e,this.gpu&&!this.sleepManager&&(this.sleepManager=new Fi(this,e)),this}disableSleeping(){return this.assertAlive(),this.sleepOptions=!1,this.gpu?(this.flushCommands(),this.sleepManager&&(this.sleepManager.wakeRequested=!0,this.sleepManager.before(),this.sleepManager.dispose(),this.sleepManager=null),this):this}addMotor(e,t,i={}){return this.addConstraint(e,t,{...i,type:"motor"})}addHinge(e,t,i={}){return new ns(this,e,t,i)}initializeContacts(){if(this.contactWatch)return;let{maxContactPairs:e,maxContactEvents:t}=this.contactOptions;this.contactWatch=new xi(this.device,this.gpu.bodyBuffer,this.capacity,e,t);let i=this.aggregates.filter(r=>!r.disposed);this.contactWatch.setWatched(i.map(r=>r.body.gpuIndex),i.map(()=>!0))}onContact(e){if(this.assertAlive(),typeof e!="function")throw Error("A contact callback is required");return this.contactListeners.add(e),this.gpu&&this.initializeContacts(),()=>this.contactListeners.delete(e)}async readContactEvents(){return this.initialize(),this.initializeContacts(),this.contactPending?this.contactPending:(this.contactPending=this.contactWatch.read().then(e=>({...e,events:e.events.map(t=>({...t,type:t.kind===Ai?"begin":"end",isTrigger:!!(this.byGpuIndex.get(t.a)?.aggregate.isTrigger||this.byGpuIndex.get(t.b)?.aggregate.isTrigger),a:this.byGpuIndex.get(t.a),b:this.byGpuIndex.get(t.b)}))})).finally(()=>this.contactPending=null),this.contactPending)}async raycast(e,t,i={}){let[r]=await this.raycastAll([{origin:e,direction:t,maxDistance:i.maxDistance}],i);return r}async sphereCast(e,t,i,r={}){let[o]=await this.sphereCastAll([{origin:e,radius:t,direction:i,maxDistance:r.maxDistance}],r);return o}async sphereCastAll(e,{ignore:t=[],collidesWith:i=4294967295,includeTriggers:r=!0}={}){this.assertAlive(),Lr(i),this.initialize(),this.flushCommands();for(let n of t)if(n.aggregate.world!==this||n.disposed)throw Error("Ignored cast bodies must belong to this world and be alive");return(await this.gpu.sphereCastAll(e.map(n=>({...n,origin:Le(n.origin),direction:Le(n.direction)})),{ignore:t.map(n=>n.gpuIndex),collidesWith:i,includeTriggers:r})).map(n=>n?{...n,body:this.byGpuIndex.get(n.index)??null}:null)}async raycastAll(e,{ignore:t=[],collidesWith:i=4294967295,includeTriggers:r=!0}={}){Lr(i),this.initialize(),this.flushCommands();let o=e.map(a=>{let l=Le(a.origin),c=Le(a.direction);if(l.length!==3||c.length!==3||![...l,...c].every(Number.isFinite)||!Math.hypot(...c))throw Error("A ray requires a finite origin and nonzero direction");return a.maxDistance!==void 0&&bo(a.maxDistance,"maxDistance",!0),{...a,origin:l,direction:c}});for(let a of t)if(a.aggregate.world!==this)throw Error("Ignored ray bodies must belong to this world");return(await this.gpu.raycastAll(o,{ignore:t.map(a=>a.gpuIndex),collidesWith:i,includeTriggers:r})).map(a=>a?{...a,body:this.byGpuIndex.get(a.index)??null}:null)}getRenderBinding(e=this.device){if(this.initialize(),e!==this.device)throw Error("Direct GPU rendering must share the physics GPUDevice");return{device:e,buffer:this.bodyBuffer,stride:160,positionOffset:0,rotationOffset:16,sizeOffset:64,count:this.gpu.bodyCount}}wakeAll(){this.sleepManager&&(this.sleepManager.wakeRequested=!0)}async readSleepStats(){return this.initialize(),this.sleepManager?this.sleepManager.readStats():{sleeping:0,wakeRequested:!1}}assertAlive(){if(this.disposed)throw Error("AVBD world is disposed")}queue(e,t,i,r){this.assertAlive(),e.assertAlive();let o=Le(r);if(o.length!==(i==="rotation"?4:3)||!o.every(Number.isFinite))throw Error(`${i} requires ${i==="rotation"?4:3} finite components`);let n=this.commands.get(e);return n||this.commands.set(e,n={mask:0}),n.mask|=t,n[i]=o,this.wakeAll(),n}flushCommands(e){if(this.initialize(),this.gpu.flushPropertyEdits(e),!this.commands.size)return;this.sleepManager?.wakeRequested&&this.sleepManager.before(e);let t=this.commands.size,i=0;for(let h of this.commands.values())i|=h.mask;if(i===1||i===2){if(!this.velocityIndices||this.velocityIndices.length<t){let y=Math.max(t,(this.velocityIndices?.length??0)*2,64);this.velocityIndices=new Uint32Array(y),this.velocityValues=new Float32Array(y*3)}let h=0;for(let[y,A]of this.commands)this.velocityIndices[h]=y.aggregate.gpuSlot??this.gpu.gpuIndex(y.aggregate.index),this.velocityValues.set(i===2?A.angular:A.velocity,h++*3);let g=i===2?"angularVelocityBatch":"velocityBatch",b=this[g]??=new Kt(this.gpu,3,i===2?"angular":"linear");b.solver=this.gpu,b.submitValidated(this.velocityIndices.subarray(0,t),this.velocityValues.subarray(0,t*3),e),this.lastCommandBatch={bodies:t,path:i===2?"packed-angular-velocities":"packed-velocities",uploadedBytes:t*16},this.commands.clear();return}let r=!0;for(let h of this.commands.values())if((h.mask&-4)!==0){r=!1;break}if(r){(!this.motionData||this.motionData.length<t*8)&&(this.motionData=new Uint32Array(Math.max(t*8,(this.motionData?.length??0)*2,512)),this.motionFloats=new Float32Array(this.motionData.buffer));let h=0;for(let[g,b]of this.commands){let y=h++*8;this.motionData[y]=g.aggregate.gpuSlot??this.gpu.gpuIndex(g.aggregate.index),this.motionData[y+1]=b.mask,b.velocity&&this.motionFloats.set(b.velocity,y+2),b.angular&&this.motionFloats.set(b.angular,y+5)}this.motionBatch??=new yi(this.gpu,3),this.motionBatch.submitValidated(this.motionData.subarray(0,t*8),e),this.lastCommandBatch={bodies:t,path:"packed-motion",uploadedBytes:t*32},this.commands.clear();return}let o=t*128,n=Math.min(this.device.limits.maxStorageBufferBindingSize,this.device.limits.maxBufferSize);if(o>n)throw Error("Body command batch exceeds GPU buffer limits");(!this.commandData||this.commandData.byteLength<o)&&(this.commandData=new ArrayBuffer(Math.min(n,Math.max(o,(this.commandData?.byteLength??0)*2,128))));let a=this.commandData,l=new Float32Array(a),c=new Uint32Array(a);l.fill(0,0,t*32);let u=0;for(let[h,g]of this.commands){let b=u++*32;c[b]=h.aggregate.gpuSlot??this.gpu.gpuIndex(h.aggregate.index),c[b+1]=g.mask;for(let[y,A]of[["velocity",4],["angular",8],["impulse",12],["torque",16],["position",20],["rotation",24],["pointImpulse",28]])g[y]&&l.set(g[y],b+A)}this.commands.clear(),(!this.commandBuffer||this.commandBuffer.size<o)&&(this.commandBuffer?.destroy(),this.commandBuffer=this.device.createBuffer({size:Math.min(n,Math.max(o*2,128)),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST})),this.device.queue.writeBuffer(this.commandBuffer,0,a,0,o),this.commandPipeline??=this.device.createComputePipeline({layout:"auto",compute:{module:this.device.createShaderModule({code:`const DISPATCH_STRIDE = ${this.device.limits.maxComputeWorkgroupsPerDimension*64}u;
3820
+ ${gc}`,label:"AVBD body commands"}),entryPoint:"applyCommands"}}),(!this.commandBinding||this.boundCommandBody!==this.gpu.bodyBuffer||this.boundCommandBuffer!==this.commandBuffer||this.boundCommandBytes!==o)&&(this.commandBinding=this.device.createBindGroup({layout:this.commandPipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:this.gpu.bodyBuffer}},{binding:1,resource:{buffer:this.commandBuffer,size:o}}]}),this.boundCommandBody=this.gpu.bodyBuffer,this.boundCommandBuffer=this.commandBuffer,this.boundCommandBytes=o);let f=e??this.device.createCommandEncoder(),d=f.beginComputePass();d.setPipeline(this.commandPipeline),d.setBindGroup(0,this.commandBinding);let p=Math.ceil(u/64),m=this.device.limits.maxComputeWorkgroupsPerDimension;d.dispatchWorkgroups(Math.min(p,m),Math.ceil(p/m)),d.end(),e||this.device.queue.submit([f.finish()]),this.lastCommandBatch={bodies:t,path:"aggregate-commands",uploadedBytes:o}}step(){this.initialize(),this.gpu.step(),this.steps++,this.contactWatch&&(this.contactWatch.run(this.gpu.contactStorage,this.gpu.manifoldCapacity,this.steps,this.ref.dt),this.contactListeners.size&&!this.contactPending&&this.readContactEvents().then(({events:e,dropped:t,full:i})=>{if(!this.disposed){(t||i)&&this.errors.push(`Contact event storage full: ${t} events dropped; increase maxContactEvents/maxContactPairs`);for(let r of e)for(let o of this.contactListeners)o(r)}}).catch(e=>{this.disposed||this.errors.push(e.message)})),this.syncEnabled&&!this.syncPending&&this.syncMeshes().catch(e=>this.errors.push(e.message)),this.steps%20===0&&!this.counterPending&&(this.counterPending=!0,this.gpu.readCounters().then(e=>{this.disposed||(this.counters=e,this.gpu.adapt(e),(e.overflow||e.clashes)&&this.errors.push(`Collision capacity/color conflict: ${JSON.stringify(e)}`))}).catch(e=>{this.disposed||this.errors.push(e.message)}).finally(()=>this.counterPending=!1))}async syncMeshes(){if(this.initialize(),this.flushCommands(),this.syncPending)return this.syncPending;let e=this.aggregates.filter(t=>t.sync&&!t.disposed);return this.syncPending=this.bodyReadback.read(this.bodyBuffer,e.map(t=>t.body.gpuIndex),!0).then(t=>{if(!this.disposed){for(let i=0;i<e.length;i++)e[i].disposed||e[i].syncPose(t,i*8);this.lastSyncBytes=t.byteLength}}).finally(()=>this.syncPending=null),this.syncPending}get bodyBuffer(){return this.initialize(),this.gpu.bodyBuffer}async readBodies(e){if(this.initialize(),this.flushCommands(),e){for(let t of e)if(t.aggregate.world!==this)throw Error("Selected bodies must belong to this world");return this.bodyReadback.read(this.bodyBuffer,e.map(t=>t.gpuIndex))}return this.gpu.readBodies()}dispose(){if(!this.disposed){this.disposed=!0,this.observer&&this.scene?.onBeforeRenderObservable.remove(this.observer),this.disposeObserver&&this.scene?.onDisposeObservable.remove(this.disposeObserver),this.scene&&us.get(this.scene)===this&&us.delete(this.scene),this.device.removeEventListener("uncapturederror",this.errorListener),this.gpu?.destroy(),this.contactWatch?.destroy(),this.sleepManager?.dispose(),this.commandBuffer?.destroy(),this.velocityBatch?.destroy(),this.angularVelocityBatch?.destroy(),this.motionBatch?.destroy(),this.bodyReadback.destroy(),this.commandData=this.velocityIndices=this.velocityValues=null,this.commandBinding=null;for(let e of this.aggregates)e.disposed=!0,e.body.disposed=!0;this.commands.clear(),this.contactListeners.clear();for(let e of this.constraints)e.disposed=!0;this.constraints.clear(),this.ownsDevice&&this.device.destroy()}}attachToScene(e=this.scene){if(this.assertAlive(),!e)throw Error("A Babylon scene is required");if(this.observer&&e===this.scene)return this;if(this.observer)throw Error("AVBD world is already attached to another scene");this.scene=e,this.disposeObserver=e.onDisposeObservable.addOnce(()=>this.dispose());let t=0;return this.observer=e.onBeforeRenderObservable.add(()=>{t+=Math.min(.05,e.getEngine().getDeltaTime()/1e3);for(let i=0;t>=this.ref.dt&&i<3;i++)this.step(),t-=this.ref.dt}),this}},vo=class{constructor(e,t,{mass:i=1,friction:r=.6,restitution:o=0,allowSleep:n,isTrigger:a=!1,sync:l=!0,group:c=4294967295,collidesWith:u=4294967295}={},f){if(f=f instanceof yo?f:us.get(f??e.getScene()),!f)throw Error("Create an AVBD world for this scene before adding aggregates");if(f.assertAlive(),typeof t=="number"&&(t=[mt.SPHERE,mt.CAPSULE,mt.CYLINDER,mt.BOX,mt.CONVEX_HULL][t]),bo(i,"mass",!0),bo(r,"friction",!0),!Number.isFinite(o)||o<0||o>1)throw Error("restitution must be between 0 and 1");if(e.parent)throw Error("AVBD aggregate meshes must have no parent; bake the parent transform first");if(!Object.values(mt).includes(t))throw Error(`Unsupported AVBD shape: ${t}`);if(f.aggregates.length>=f.capacity)throw Error("AVBD body capacity exceeded");if(this.world=f,this.mesh=e,this.sync=l,this.type=t,n!==void 0&&typeof n!="boolean")throw Error("allowSleep must be a boolean");if(this.allowSleep=n??!0,typeof a!="boolean")throw Error("isTrigger must be a boolean");if(this.isTrigger=a,this.restitution=o,n===!0&&!f.sleepOptions&&f.enableSleeping(),this.group=Lr(c),this.collidesWith=Lr(u),f.gpu&&f.syncEnabled&&l&&f.aggregates.filter(v=>v.sync&&!v.disposed).length>=f.maxSyncedBodies)throw Error("For large scenes use syncMeshes:false and draw the GPU body buffer directly");if(![mt.BOX,mt.SPHERE,mt.CAPSULE].includes(t)&&f.device.limits.maxStorageBuffersPerShaderStage<9)throw Error("Convex hull collisions require nine storage buffer bindings");e.computeWorldMatrix(!0),e.refreshBoundingInfo();let d=e.getBoundingInfo().boundingBox,p=e.scaling;if([p.x,p.y,p.z].some(v=>v<=0))throw Error("Bake negative or zero mesh scaling before creating an aggregate");let m=d.maximum.subtract(d.minimum).multiply(p),h=d.center.multiply(p),g=e.rotationQuaternion?.clone()||e.rotation.toQuaternion();this.localCenter=h,this.localRotation=g.constructor.Identity();let b;if(t===mt.BOX)b=new Ze(f.ref,Le(m),1,r,[0,0,0]);else if(t===mt.SPHERE){if(Math.max(m.x,m.y,m.z)-Math.min(m.x,m.y,m.z)>1e-4)throw Error("Sphere aggregate requires uniform dimensions");b=nr(f.ref,m.x/2,1,r,[0,0,0])}else if(t===mt.CAPSULE){if(Math.abs(m.x-m.z)>1e-4)throw Error("Capsule aggregate requires equal X and Z diameters; bake an upright Y-axis capsule mesh");b=Br(f.ref,m.x/2,m.y,1,r,[0,0,0])}else{let v=e.getVerticesData("position");if(!v)throw Error("Hull aggregate requires mesh positions");let x=Float32Array.from(v,(B,L)=>B*[p.x,p.y,p.z][L%3]),w=Ur(x);if(!w)throw Error("Hull aggregate requires a closed shape with nonzero volume");this.localCenter=new e.position.constructor(...w.center),this.localRotation=g.constructor.FromArray(w.rotation),b=ar(f.ref,w,1,r,[0,0,0])}let y=i/b.mass;b.mass=i,b.moment.forEach((v,x)=>b.moment[x]=v*y);let A=e.position.add(this.localCenter.applyRotationQuaternion(g));if(b.positionLin.set(Le(A)),b.positionAng.set(g.multiply(this.localRotation).asArray()),this.rigid=b,this.index=f.aggregates.length,this.body=new fs(this),f.aggregates.push(this),e.rotationQuaternion=g,f.gpu){if(this.gpuSlot=f.gpu.addBody(b),this.gpuSlot<0)throw Error("AVBD body capacity exceeded");f.byGpuIndex.set(this.gpuSlot,this.body),f.gpu.setFilters([this.gpuSlot],[this.group],[this.collidesWith]),(this.isTrigger||f.gpu.sensorsEnabled)&&f.gpu.setSensor(this.gpuSlot,this.isTrigger),this.restitution>0&&f.gpu.setRestitution(this.gpuSlot,this.restitution),f.contactWatch?.setWatched([this.gpuSlot],[!0]),f.sleepManager?.register(this.gpuSlot,b.mass,this.allowSleep),f.wakeAll?.()}}syncPose(e,t){let i=t??this.body.gpuIndex*40,r=this.localRotation.constructor.FromArray(e,i+4).multiply(this.localRotation.conjugate());this.mesh.rotationQuaternion.copyFrom(r),this.mesh.position.copyFrom(new this.mesh.position.constructor(...e.subarray(i,i+3)).subtract(this.localCenter.applyRotationQuaternion(r)))}dispose(){Ac(this)}},Aa=class{constructor(e,t){Object.assign(this,{world:e,rigid:t,index:e.aggregates.length,sync:!1,allowSleep:!1,isTrigger:!1,restitution:t.restitution,group:t.group,collidesWith:t.collidesWith,staticTerrain:!0}),this.body=new fs(this),e.aggregates.push(this)}dispose(){Ac(this)}};function Ac(s){if(s.disposed)return;let e=s.world;for(let t of[...e.constraints])(t.bodyA===s.body||t.bodyB===s.body)&&t.dispose();if(e.gpu){let t=s.body.gpuIndex;e.queue(s.body,16,"velocity",[0,0,0]),e.gpu.setFilters([t],[0],[0]),e.gpu.setRestitution(t,0)}s.rigid.mass=0,s.rigid.moment.fill(0),s.sync=!1,s.disposed=s.body.disposed=!0,e.sleepManager?.register(s.gpuSlot??e.gpu?.gpuIndex(s.index)??s.index,0),e.wakeAll?.()}var fs=class{constructor(e){this.aggregate=e}assertAlive(){if(this.disposed||this.aggregate.disposed)throw Error("AVBD body is disposed")}get gpuIndex(){this.assertAlive();let e=this.aggregate.world;return e.initialize(),this.aggregate.gpuSlot??e.gpu.gpuIndex(this.aggregate.index)}setLinearVelocity(e){return this.aggregate.world.queue(this,1,"velocity",e),this}setAngularVelocity(e){return this.aggregate.world.queue(this,2,"angular",e),this}applyImpulse(e,t){let i=t?Le(t):null;if(i&&(i.length!==3||!i.every(Number.isFinite)))throw Error("Impulse point requires three finite components");let r=this.aggregate.world,o=Le(e),n=r.commands.get(this),a=o.map((c,u)=>c+(n?.impulse?.[u]||0)),l=r.queue(this,4,"impulse",a);if(t){let c=[i[1]*o[2]-i[2]*o[1],i[2]*o[0]-i[0]*o[2],i[0]*o[1]-i[1]*o[0]],u=l.torque||[0,0,0];l.torque=Le(c).map((f,d)=>f+u[d]),l.pointImpulse=o.map((f,d)=>f+(l.pointImpulse?.[d]||0))}return this}applyAngularImpulse(e){let t=this.aggregate.world,i=t.commands.get(this)?.torque||[0,0,0];return t.queue(this,4,"torque",Le(e).map((r,o)=>r+i[o])),this}applyForce(e,t){return this.applyImpulse(Le(e).map(i=>i*this.aggregate.world.ref.dt),t)}applyTorque(e){return this.applyAngularImpulse(Le(e).map(t=>t*this.aggregate.world.ref.dt))}setCollisionGroups(e,t=4294967295){this.assertAlive();let i=this.aggregate,r=Lr(e),o=Lr(t);return i.group=r,i.collidesWith=o,i.world.gpu&&i.world.gpu.setFilters([this.gpuIndex],[i.group],[i.collidesWith]),i.world.wakeAll?.(),this}setTrigger(e){if(this.assertAlive(),typeof e!="boolean")throw Error("isTrigger must be a boolean");let t=this.aggregate;return t.isTrigger=e,t.world.gpu&&t.world.gpu.setSensor(this.gpuIndex,e),t.world.wakeAll(),this}setRestitution(e){if(this.assertAlive(),!Number.isFinite(e)||e<0||e>1)throw Error("restitution must be between 0 and 1");let t=this.aggregate;return t.restitution=e,t.world.gpu&&t.world.gpu.setRestitution(this.gpuIndex,e),t.world.wakeAll(),this}async readState(){let e=await this.aggregate.world.readBodies([this]),t=this.aggregate.rigid.mass;return{position:Array.from(e.subarray(0,3)),rotation:Array.from(e.subarray(4,8)),linearVelocity:Array.from(e.subarray(32,35)),angularVelocity:Array.from(e.subarray(36,39)),mass:t,effectiveMass:e[19],sleeping:t>0&&e[19]===0}}wakeUp(){return this.assertAlive(),this.aggregate.world.wakeAll(),this}setSleepEnabled(e){if(this.assertAlive(),typeof e!="boolean")throw Error("Sleep eligibility must be a boolean");let t=this.aggregate,i=t.world;return t.allowSleep=e,e&&!i.sleepOptions&&i.enableSleeping(),i.gpu&&i.sleepManager?.register(this.gpuIndex,t.rigid.mass,e),i.wakeAll(),this}teleport(e,t){if(this.assertAlive(),this.aggregate.staticTerrain)throw Error("Terrain is static; set its geometry transform before registration");let i=this.aggregate;if(t===void 0){let n=i.world.commands.get(this);if(n&&(n.mask&8)!==0&&(n.mask&32)===0){let a=i.mesh.rotationQuaternion.clone();a.copyFromFloats(...n.rotation);let l=i.localCenter.applyRotationQuaternion(i.localRotation.conjugate());i.world.queue(this,8,"position",Le(e.add(l.applyRotationQuaternion(a))))}else{let a=i.localCenter.applyRotationQuaternion(i.localRotation.conjugate());i.world.queue(this,40,"position",Le(e)),i.world.queue(this,40,"rotation",[...Le(a),0])}return this}let r=t.clone().normalize();i.world.queue(this,8,"position",Le(e.add(i.localCenter.applyRotationQuaternion(r))));let o=i.world.queue(this,8,"rotation",r.multiply(i.localRotation).asArray());return o.mask&=-33,this}};var Ni=class{solver;bodyA;bodyB;J=new Float64Array(12);H=new Float64Array(36);C=new Float64Array(4);fmin=new Float64Array(4).fill(-1/0);fmax=new Float64Array(4).fill(1/0);stiffness=new Float64Array(4).fill(1/0);fracture=new Float64Array(4).fill(1/0);penalty=new Float64Array(4);lambda=new Float64Array(4);constructor(e,t,i){this.solver=e,this.bodyA=t,this.bodyB=i,e.forces.push(this),t?.forces.push(this),i.forces.push(this)}destroy(){let e=this.solver.forces,t=e.indexOf(this);t>=0&&e.splice(t,1),this.unlinkFromBodies()}unlinkFromBodies(){for(let e of[this.bodyA,this.bodyB]){if(!e)continue;let t=e.forces.indexOf(this);t>=0&&e.forces.splice(t,1)}}disable(){this.stiffness.fill(0),this.penalty.fill(0),this.lambda.fill(0)}};var wc=s=>s<0?-1:s>0?1:0,_r=(s,e)=>s<e?s:e,If=(s,e)=>s>e?s:e,Er=(s,e,t)=>If(e,_r(t,s));function ds(s,e,t){let i=Math.cos(s),r=Math.sin(s);return[i*e-r*t,r*e+i*t]}function qi(s,e,t){let i=Math.cos(s[2]),r=Math.sin(s[2]);return[i*e-r*t+s[0],r*e+i*t+s[1]]}function Zt(s,e,t,i,r){s[e*3]=t,s[e*3+1]=i,s[e*3+2]=r}var xo=class extends Ni{rA;rB;C0=new Float64Array(3);torqueArm;restAngle;constructor(e,t,i,r,o,n=[1/0,1/0,1/0],a=1/0){super(e,t,i),this.rA=[r[0],r[1]],this.rB=[o[0],o[1]],this.stiffness[0]=n[0],this.stiffness[1]=n[1],this.stiffness[2]=n[2],this.fmax[2]=a,this.fmin[2]=-a,this.fracture[2]=a,this.restAngle=(t?t.position[2]:0)-i.position[2];let l=(t?t.size[0]:0)+i.size[0],c=(t?t.size[1]:0)+i.size[1];this.torqueArm=l*l+c*c}rows(){return 3}evaluate(e){let t=this.bodyA?qi(this.bodyA.position,this.rA[0],this.rA[1]):this.rA,i=qi(this.bodyB.position,this.rB[0],this.rB[1]);e[0]=t[0]-i[0],e[1]=t[1]-i[1],e[2]=((this.bodyA?this.bodyA.position[2]:0)-this.bodyB.position[2]-this.restAngle)*this.torqueArm}initialize(){return this.evaluate(this.C0),this.stiffness[0]!==0||this.stiffness[1]!==0||this.stiffness[2]!==0}Cn=new Float64Array(3);computeConstraint(e){this.evaluate(this.Cn);for(let t=0;t<3;t++)this.C[t]=this.stiffness[t]===1/0?this.Cn[t]-this.C0[t]*e:this.Cn[t]}computeDerivatives(e){let{J:t,H:i}=this;if(i.fill(0,0,27),e===this.bodyA){let r=ds(e.position[2],this.rA[0],this.rA[1]);Zt(t,0,1,0,-r[1]),Zt(t,1,0,1,r[0]),Zt(t,2,0,0,this.torqueArm),i[8]=-r[0],i[17]=-r[1]}else{let r=ds(e.position[2],this.rB[0],this.rB[1]);Zt(t,0,-1,0,r[1]),Zt(t,1,0,-1,-r[0]),Zt(t,2,0,0,-this.torqueArm),i[8]=r[0],i[17]=r[1]}}},Ao=class extends Ni{rA;rB;rest;constructor(e,t,i,r,o,n,a=-1){if(super(e,t,i),this.rA=[r[0],r[1]],this.rB=[o[0],o[1]],this.stiffness[0]=n,this.rest=a,this.rest<0){let l=qi(t.position,r[0],r[1]),c=qi(i.position,o[0],o[1]);this.rest=Math.hypot(l[0]-c[0],l[1]-c[1])}}rows(){return 1}initialize(){return!0}delta(){let e=qi(this.bodyA.position,this.rA[0],this.rA[1]),t=qi(this.bodyB.position,this.rB[0],this.rB[1]);return[e[0]-t[0],e[1]-t[1]]}computeConstraint(){let e=this.delta();this.C[0]=Math.hypot(e[0],e[1])-this.rest}computeDerivatives(e){let t=this.delta(),i=t[0]*t[0]+t[1]*t[1];if(i===0)return;let r=Math.sqrt(i),o=t[0]/r,n=t[1]/r,a=(1-o*o)/r,l=(0-o*n)/r,c=(0-n*o)/r,u=(1-n*n)/r,f=e===this.bodyA,d=f?this.rA:this.rB,p=ds(e.position[2],-d[1],d[0]),m=ds(e.position[2],d[0],d[1]),h=a*p[0]+l*p[1],g=c*p[0]+u*p[1],b=o*m[0]+n*m[1],y=o*p[0]+n*p[1];f?Zt(this.J,0,o,n,y):Zt(this.J,0,-o,-n,-y);let A=f?-b-b:b+b,v=this.H;v[0]=a,v[1]=l,v[2]=h,v[3]=c,v[4]=u,v[5]=g,v[6]=h,v[7]=g,v[8]=A}},wo=class extends Ni{rows(){return 0}initialize(){return!0}computeConstraint(){}computeDerivatives(){}},Bo=class extends Ni{speed;constructor(e,t,i,r,o){super(e,t,i),this.speed=r,this.fmax[0]=o,this.fmin[0]=-o}rows(){return 1}initialize(){return!0}computeConstraint(){let e=this.bodyA?this.bodyA.position[2]-this.bodyA.initial[2]:0,t=this.bodyB.position[2]-this.bodyB.initial[2];this.C[0]=e-t-this.speed*this.solver.dt}computeDerivatives(e){Zt(this.J,0,0,0,e===this.bodyA?1:-1),this.H.fill(0,0,9)}};var Co=()=>({dt:1/60,gravity:-10,iterations:10,beta:1e5,alpha:.99,gamma:.99,postStabilize:!0,stiffnessRescale:!1,vbd:!1,vbdStiffness:1e6,matchNearest:!1}),So=()=>({...Co(),postStabilize:!1,alpha:.95,matchNearest:!0});var Mr=(s,e)=>s>e?s*2097152+e:e*2097152+s;function Rf(s,e,t){let i=0,r=e;for(;i<r;){let o=i+r>>>1;s[o]<t?i=o+1:r=o}return i}function wa(s,e,t){let i=Rf(s,e,t);return i<e&&s[i]===t}var ko=class{cellSize=1;pairs=new Float64Array(1024);pairCount=0;configuredFor=-1;large=new Int32Array(0);isLarge=new Uint8Array(0);cellX=new Int32Array(0);cellY=new Int32Array(0);tableSize=0;bucketStart=new Int32Array(0);sorted=new Int32Array(0);configure(e,t){this.configuredFor=e;let i=Float64Array.from({length:e},(a,l)=>t[l*4+1]).sort(),r=e>0?i[e>>1]:1,o=0;for(let a=0;a<e;a++)i[a]<=4*r&&(o=Math.max(o,i[a]));this.cellSize=Math.max(2*o,.001),this.isLarge=new Uint8Array(e);let n=[];for(let a=0;a<e;a++)t[a*4+1]>o&&(this.isLarge[a]=1,n.push(a));for(this.large=Int32Array.from(n),this.cellX=new Int32Array(e),this.cellY=new Int32Array(e),this.tableSize=1;this.tableSize<2*e;)this.tableSize<<=1;this.bucketStart=new Int32Array(this.tableSize+1),this.sorted=new Int32Array(e)}hash(e,t){return(Math.imul(e,73856093)^Math.imul(t,19349663))&this.tableSize-1}findPairs(e,t,i,r,o,n){e!==this.configuredFor&&this.configure(e,i),this.pairCount=0;let{cellX:a,cellY:l,isLarge:c,bucketStart:u,sorted:f}=this,d=1/this.cellSize;u.fill(0);for(let h=0;h<e;h++)c[h]||(a[h]=Math.floor(t[h*4]*d),l[h]=Math.floor(t[h*4+1]*d),u[this.hash(a[h],l[h])+1]++);for(let h=0;h<this.tableSize;h++)u[h+1]+=u[h];let p=u.slice(0,this.tableSize);for(let h=0;h<e;h++)c[h]||(f[p[this.hash(a[h],l[h])]++]=h);let m=(h,g)=>{if(!r[h]&&!r[g])return;let b=t[h*4]-t[g*4],y=t[h*4+1]-t[g*4+1],A=i[h*4+1]+i[g*4+1];if(b*b+y*y>A*A)return;let v=Mr(h,g);if(!wa(o,n,v)){if(this.pairCount===this.pairs.length){let x=new Float64Array(this.pairs.length*2);x.set(this.pairs),this.pairs=x}this.pairs[this.pairCount++]=v}};for(let h=0;h<e;h++){if(c[h])continue;let g=a[h],b=l[h];for(let y=-1;y<=1;y++)for(let A=-1;A<=1;A++){let v=this.hash(g+A,b+y);for(let x=u[v];x<u[v+1];x++){let w=f[x];w>=h||a[w]!==g+A||l[w]!==b+y||m(h,w)}}}for(let h of this.large)for(let g=0;g<e;g++)g===h||c[g]&&g>h||m(h,g);this.pairs.subarray(0,this.pairCount).sort()}};var gt=new Float64Array(12),Bc=new Float64Array(12),Vi=new Float64Array(12);function qt(s,e,t,i,r,o,n,a){let l=e*6;s[l]=t,s[l+1]=i,s[l+2]=r,s[l+3]=o,s[l+4]=n,s[l+5]=a}function Cc(s,e,t,i,r,o){let n=0,a=t*e[0]+i*e[1]-r,l=t*e[6]+i*e[7]-r;if(a<=0){for(let c=0;c<6;c++)s[n*6+c]=e[c];n++}if(l<=0){for(let c=0;c<6;c++)s[n*6+c]=e[6+c];n++}if(a*l<0){let c=a/(a-l),u=e[0]+(e[6]-e[0])*c,f=e[1]+(e[7]-e[1])*c;a>0?qt(s,n,u,f,o,e[3],0,e[5]):qt(s,n,u,f,e[8],o,e[10],0),n++}return n}function Po(s,e,t,i,r,o,n,a){let l=-(r*n+o*a),c=-(-o*n+r*a);Math.abs(l)>Math.abs(c)?l>0?(qt(gt,0,s,-e,0,0,3,4),qt(gt,1,s,e,0,0,4,1)):(qt(gt,0,-s,e,0,0,1,2),qt(gt,1,-s,-e,0,0,2,3)):c>0?(qt(gt,0,s,e,0,0,4,1),qt(gt,1,-s,e,0,0,1,2)):(qt(gt,0,-s,-e,0,0,2,3),qt(gt,1,s,-e,0,0,3,4));for(let u=0;u<2;u++){let f=u*6,d=gt[f],p=gt[f+1];gt[f]=t+r*d-o*p,gt[f+1]=i+o*d+r*p}}function Lo(s,e,t,i,r,o,n,a,l,c,u){let f=Math.cos(t),d=Math.sin(t),p=Math.cos(a),m=Math.sin(a),h=o-s,g=n-e,b=f*h+d*g,y=-d*h+f*g,A=p*h+m*g,v=-m*h+p*g,x=Math.abs(f*p+d*m),w=Math.abs(f*-m+d*p),B=Math.abs(-d*p+f*m),L=Math.abs(-d*-m+f*p),M=Math.abs(b)-i-(x*l+w*c),I=Math.abs(y)-r-(B*l+L*c);if(M>0||I>0)return 0;let E=Math.abs(A)-(x*i+B*r)-l,k=Math.abs(v)-(w*i+L*r)-c;if(E>0||k>0)return 0;let P=0,C=M,_=b>0?f:-f,z=b>0?d:-d;I>.95*C+.01*r&&(P=1,C=I,_=y>0?-d:d,z=y>0?f:-f),E>.95*C+.01*l&&(P=2,C=E,_=A>0?p:-p,z=A>0?m:-m),k>.95*C+.01*c&&(P=3,C=k,_=v>0?-m:m,z=v>0?p:-p);let R,G,X,W,U,H,Z,he,we;if(P===0){R=_,G=z,X=s*R+e*G+i,W=-d,U=f;let $=s*W+e*U;H=-$+r,Z=$+r,he=3,we=1,Po(l,c,o,n,p,m,R,G)}else if(P===1){R=_,G=z,X=s*R+e*G+r,W=f,U=d;let $=s*W+e*U;H=-$+i,Z=$+i,he=2,we=4,Po(l,c,o,n,p,m,R,G)}else if(P===2){R=-_,G=-z,X=o*R+n*G+l,W=-m,U=p;let $=o*W+n*U;H=-$+c,Z=$+c,he=3,we=1,Po(i,r,s,e,f,d,R,G)}else{R=-_,G=-z,X=o*R+n*G+c,W=p,U=m;let $=o*W+n*U;H=-$+l,Z=$+l,he=2,we=4,Po(i,r,s,e,f,d,R,G)}if(Cc(Bc,gt,-W,-U,H,he)<2||Cc(Vi,Bc,W,U,Z,we)<2)return 0;let Oe=0;for(let $=0;$<2;$++){let Je=$*6,Xe=Vi[Je],Be=Vi[Je+1],ot=R*Xe+G*Be-X;if(ot>0)continue;let ri=Xe-R*ot,Ye=Be-G*ot,nt=Vi[Je+2],Qe=Vi[Je+3],at=Vi[Je+4],wt=Vi[Je+5],Qi,Ki,Zi,er;P>=2?([nt,Qe,at,wt]=[at,wt,nt,Qe],Qi=Xe-s,Ki=Be-e,Zi=ri-o,er=Ye-n):(Qi=ri-s,Ki=Ye-e,Zi=Xe-o,er=Be-n);let Wt=Oe*7;u[Wt+0]=nt&255|(Qe&255)<<8|(at&255)<<16|(wt&255)<<24,u[Wt+1]=f*Qi+d*Ki,u[Wt+1+1]=-d*Qi+f*Ki,u[Wt+3]=p*Zi+m*er,u[Wt+3+1]=-m*Zi+p*er,u[Wt+5]=-_,u[Wt+5+1]=-z,Oe++}return Oe}var Sc=s=>31-Math.clz32(s&-s);function Of(s){let e=s+2654435769;return e^=e>>>16,e=Math.imul(e,2146121005),e^=e>>>15,e=Math.imul(e,2221713035),e^=e>>>16,e>>>0}var Ba=(s,e,t,i)=>s>t||s===t&&e>i,_o=class{colors=new Int32Array(0);colorStart=new Int32Array(65);colorBodies=new Int32Array(0);next=new Int32Array(0);pending=new Uint8Array(0);prio=new Uint32Array(0);resize(e){if(this.colors.length===e)return;let t=new Int32Array(e).fill(-1);t.set(this.colors.subarray(0,Math.min(e,this.colors.length))),this.colors=t,this.next=new Int32Array(e),this.pending=new Uint8Array(e),this.colorBodies=new Int32Array(e),this.prio=Uint32Array.from({length:e},(i,r)=>Of(r))}run(e,t,i,r,o,n){this.resize(e);let{colors:a,next:l,pending:c,prio:u}=this,f=(v,x)=>{let w=o[v*4+1],B=w===x?o[v*4+2]:w;return B>=0&&t[B]?B:-1},d=(v,x)=>{let w=0,B=0;for(let L=i[v];L<i[v+1];L++){let M=f(r[L],v);if(M<0||x&&c[M])continue;let I=a[M];I<0||(I<32?w|=1<<I:B|=1<<I-32)}return~w!==0?Sc(~w):~B!==0?32+Sc(~B):63};for(let v=0;v<e;v++){if(l[v]=a[v],!t[v]||a[v]<0)continue;let x=!0;for(let w=i[v];w<i[v+1]&&x;w++){let B=f(r[w],v);B>=0&&!Ba(u[v],v,u[B],B)&&(x=!1)}x&&(l[v]=Math.min(a[v],d(v,!1)))}a.set(l);let p=()=>{let v=0;for(let x=0;x<e;x++)if(c[x]=0,!!t[x]){if(a[x]<0)c[x]=1;else for(let w=i[x];w<i[x+1];w++){let B=f(r[w],x);if(B>=0&&a[B]===a[x]&&Ba(u[B],B,u[x],x)){c[x]=1;break}}v+=c[x]}return v},m=p(),h=0;for(;m>0&&h<n;){h++;for(let v=0;v<e;v++){if(l[v]=-2,!c[v])continue;let x=!0;for(let w=i[v];w<i[v+1]&&x;w++){let B=f(r[w],v);B>=0&&c[B]&&!Ba(u[v],v,u[B],B)&&(x=!1)}x&&(l[v]=d(v,!0))}for(let v=0;v<e;v++)l[v]!==-2&&(a[v]=l[v],c[v]=0,m--)}let g=0;if(m>0){for(let v=0;v<e;v++)c[v]&&a[v]<0&&(a[v]=0);g=p()}let b=this.colorStart;b.fill(0);let y=0;for(let v=0;v<e;v++)t[v]&&(b[a[v]+1]++,y=Math.max(y,a[v]+1));for(let v=0;v<64;v++)b[v+1]+=b[v];let A=b.slice(0,64);for(let v=0;v<e;v++)t[v]&&(this.colorBodies[A[a[v]]++]=v);return{numColors:y,conflicts:g,rounds:h}}};var kc=0,Bi=1,Pc=2,Io=3,hs=4,Lc=[0,3,1,1,2],Sa=.05,j=4,O=32,se=0,te=3,Q=6,_e=9,Ae=12,Pt=15,fe=18,N=21,Y=23,re=25,be=26,Ue=27,Wi=28,zr=class{params=Co();options;bodyCount=0;pose;initial;inertial;velocity;prevVelocity;shape;props;dynamic=new Uint8Array(0);jointCount=0;contactCount=0;info=new Int32Array(0);data;handles=[];prevCount=0;prevKeys=new Float64Array(0);prevInfo=new Int32Array(0);prevData=new Float64Array(0);ignorePairs=[];noCollide=new Float64Array(0);noCollideCount=0;noCollideDirty=!0;adjStart=new Int32Array(1);adjList=new Int32Array(0);broadphase=new ko;coloring=new _o;numColors=0;colorConflicts=0;colorRounds=0;profiling=!1;profile={};phaseStart=0;contactOut=new Float64Array(14);dxBuf=new Float64Array(0);constructor(e={}){this.options={precision:"f32",order:"colored",colorRounds:32,...e},this.pose=this.real(0),this.initial=this.real(0),this.inertial=this.real(0),this.velocity=this.real(0),this.prevVelocity=this.real(0),this.shape=this.real(0),this.props=this.real(0),this.data=this.real(0)}real(e){return this.options.precision==="f32"?new Float32Array(e):new Float64Array(e)}grow(e,t){if(e.length>=t)return e;let i=new e.constructor(Math.max(t,e.length*2,16));return i.set(e),i}clear(){this.bodyCount=0,this.jointCount=0,this.contactCount=0,this.prevCount=0,this.handles=[],this.ignorePairs=[],this.noCollideDirty=!0,this.coloring.resize(0)}addBody(e,t,i,r,o=[0,0,0]){let n=this.bodyCount++,a=this.bodyCount*4;this.pose=this.grow(this.pose,a),this.initial=this.grow(this.initial,a),this.inertial=this.grow(this.inertial,a),this.velocity=this.grow(this.velocity,a),this.prevVelocity=this.grow(this.prevVelocity,a),this.shape=this.grow(this.shape,a),this.props=this.grow(this.props,a),this.dynamic=this.grow(this.dynamic,this.bodyCount);let l=e[0]*e[1]*t;return this.pose.set([r[0],r[1],r[2]??0,0],n*4),this.velocity.set([o[0],o[1],o[2]??0,0],n*4),this.prevVelocity.set(this.velocity.subarray(n*4,n*4+4),n*4),this.shape.set([e[0],e[1],l,l*(e[0]*e[0]+e[1]*e[1])/12],n*4),this.props.set([i,Math.hypot(e[0]*.5,e[1]*.5),0,0],n*4),this.dynamic[n]=l>0?1:0,n}allocConstraint(){let e=this.jointCount++,t=this.jointCount+this.contactCount;this.info=this.grow(this.info,t*j),this.data=this.grow(this.data,t*O),this.contactCount>0&&(this.info.copyWithin((e+1)*j,e*j,(t-1)*j),this.data.copyWithin((e+1)*O,e*O,(t-1)*O)),this.data.fill(0,e*O,e*O+O);for(let i=0;i<3;i++)this.data[e*O+Q+i]=1/0,this.data[e*O+_e+i]=-1/0,this.data[e*O+Ae+i]=1/0,this.data[e*O+Pt+i]=1/0;return this.handles[e]=null,this.noCollideDirty=!0,e}setInfo(e,t,i,r){this.info.set([t,i,r,0],e*j)}addJoint(e,t,i,r,o=[1/0,1/0,1/0],n=1/0){let a=this.allocConstraint();this.setInfo(a,Bi,e,t);let l=this.data,c=a*O;l.set(o,c+Q),l[c+Ae+2]=n,l[c+_e+2]=-n,l[c+Pt+2]=n,l.set(i,c+N),l.set(r,c+Y),l[c+re]=(e>=0?this.pose[e*4+2]:0)-this.pose[t*4+2];let u=(e>=0?this.shape[e*4]:0)+this.shape[t*4],f=(e>=0?this.shape[e*4+1]:0)+this.shape[t*4+1];l[c+be]=u*u+f*f;let d={slot:a,alive:!0};return this.handles[a]=d,d}setJointWorldAnchor(e,t,i){e.alive&&(this.data[e.slot*O+N]=t,this.data[e.slot*O+N+1]=i)}removeJoint(e){e.alive&&(this.disable(e.slot),e.alive=!1)}addSpring(e,t,i,r,o,n){let a=this.allocConstraint();this.setInfo(a,Pc,e,t);let l=a*O;this.data[l+Q]=o,this.data.set(i,l+N),this.data.set(r,l+Y),this.data[l+re]=n}addMotor(e,t,i,r){let o=this.allocConstraint();this.setInfo(o,Io,e,t);let n=o*O;this.data[n+Ae]=r,this.data[n+_e]=-r,this.data[n+re]=i}ignoredPairs(){return this.ignorePairs}addIgnoreCollision(e,t){this.ignorePairs.push(Mr(e,t)),this.noCollideDirty=!0}loadFromReference(e){this.clear();let t=Object.keys(Co());Object.assign(this.params,Object.fromEntries(t.map(r=>[r,e[r]])));let i=new Map(e.bodies.map((r,o)=>[r,o]));for(let r of e.bodies){let o=this.addBody(r.size,0,r.friction,r.position,r.velocity);this.shape[o*4+2]=r.mass,this.shape[o*4+3]=r.moment,this.dynamic[o]=r.mass>0?1:0}for(let r of e.forces){let o=r.bodyA?i.get(r.bodyA):-1,n=i.get(r.bodyB);if(r instanceof xo){let a=this.addJoint(o,n,r.rA,r.rB,[r.stiffness[0],r.stiffness[1],r.stiffness[2]],r.fracture[2]);this.data[a.slot*O+re]=r.restAngle,this.data[a.slot*O+be]=r.torqueArm}else r instanceof Ao?this.addSpring(o,n,r.rA,r.rB,r.stiffness[0],r.rest):r instanceof Bo?this.addMotor(o,n,r.speed,r.fmax[0]):r instanceof wo&&this.addIgnoreCollision(o,n)}}step(){let e=this.params,t=e.postStabilize&&!e.vbd,i=e.vbd?0:e.alpha;this.phaseStart=this.profiling?performance.now():0,this.saveContacts(),this.findPairs(),this.mark("broadphase"),this.initJoints(),this.narrowphase(),this.mark("narrowphase"),this.warmStartConstraints(t,i),this.buildAdjacency(),this.mark("adjacency"),this.colorBodies(),this.mark("coloring"),this.warmStartBodies();let r=e.iterations+(t?1:0);for(let o=0;o<r;o++){let n=t?o<e.iterations?1:0:i;this.primal(n),this.mark("primal"),o<e.iterations&&this.dual(n),o===e.iterations-1&&this.updateVelocities(),this.mark("dual")}t&&this.refreshStick()}mark(e){if(!this.profiling)return;let t=performance.now();this.profile[e]=(this.profile[e]??0)+t-this.phaseStart,this.phaseStart=t}resetProfile(){for(let e of Object.keys(this.profile))delete this.profile[e]}saveContacts(){let e=this.contactCount,t=this.jointCount;this.prevKeys.length<e&&(this.prevKeys=new Float64Array(e*2),this.prevInfo=new Int32Array(e*2*j),this.prevData=new Float64Array(e*2*O));for(let i=0;i<e;i++){let r=t+i;this.prevKeys[i]=Mr(this.info[r*j+1],this.info[r*j+2])}this.prevInfo.set(this.info.subarray(t*j,(t+e)*j)),this.prevData.set(this.data.subarray(t*O,(t+e)*O)),this.prevCount=e,this.contactCount=0}findPairs(){if(this.noCollideDirty){let e=[...this.ignorePairs];for(let t=0;t<this.jointCount;t++){let i=this.info[t*j+1],r=this.info[t*j+2];this.info[t*j]!==kc&&i>=0&&e.push(Mr(i,r))}this.noCollide=Float64Array.from(e).sort(),this.noCollideCount=e.length,this.noCollideDirty=!1}this.broadphase.findPairs(this.bodyCount,this.pose,this.props,this.dynamic,this.noCollide,this.noCollideCount)}initJoints(){let{info:e,data:t,pose:i}=this,r=0;for(let o=0;o<this.jointCount;o++){let n=o*O;if(e[o*j]===Bi){if(t[n+Q]===0&&t[n+Q+1]===0&&t[n+Q+2]===0){let u=this.handles[o];u&&(u.alive=!1);continue}let l=e[o*j+1],c=e[o*j+2];this.jointC(l,c,n,i,t,n+fe)}r!==o&&(e.copyWithin(r*j,o*j,(o+1)*j),t.copyWithin(r*O,n,n+O),this.handles[r]=this.handles[o],this.handles[r]&&(this.handles[r].slot=r)),r++}if(r!==this.jointCount){for(let o=r;o<this.jointCount;o++)this.handles[o]=null;this.jointCount=r,this.noCollideDirty=!0}}jointC(e,t,i,r,o,n,a=o){let l,c,u;if(e>=0){let h=Math.cos(r[e*4+2]),g=Math.sin(r[e*4+2]),b=o[i+N],y=o[i+N+1];l=h*b-g*y+r[e*4],c=g*b+h*y+r[e*4+1],u=r[e*4+2]}else l=o[i+N],c=o[i+N+1],u=0;let f=Math.cos(r[t*4+2]),d=Math.sin(r[t*4+2]),p=o[i+Y],m=o[i+Y+1];a[n]=l-(f*p-d*m+r[t*4]),a[n+1]=c-(d*p+f*m+r[t*4+1]),a[n+2]=(u-r[t*4+2]-o[i+re])*o[i+be]}narrowphase(){let{pose:e,shape:t,props:i}=this,r=this.broadphase.pairs,o=this.contactOut;for(let n=0;n<this.broadphase.pairCount;n++){let a=r[n],l=Math.floor(a/2097152),c=a-l*2097152,u=Lo(e[l*4],e[l*4+1],e[l*4+2],t[l*4]*.5,t[l*4+1]*.5,e[c*4],e[c*4+1],e[c*4+2],t[c*4]*.5,t[c*4+1]*.5,o);if(u===0)continue;let f=0,d=this.prevCount;for(;f<d;){let h=f+d>>>1;this.prevKeys[h]<a?f=h+1:d=h}let p=f,m=Math.sqrt(i[l*4]*i[c*4]);for(let h=0;h<u;h++){let g=this.jointCount+this.contactCount++;this.info=this.grow(this.info,(g+1)*j),this.data=this.grow(this.data,(g+1)*O);let b=this.data,y=g*O,A=h*7,v=o[A+0];this.info.set([hs,l,c,v],g*j),b.fill(0,y,y+O),b[y+Q]=b[y+Q+1]=1/0,b[y+_e]=-1/0,b[y+Ae]=0,b[y+Pt]=b[y+Pt+1]=1/0,b[y+N]=o[A+1],b[y+N+1]=o[A+1+1],b[y+Y]=o[A+3],b[y+Y+1]=o[A+3+1],b[y+re]=m,b[y+be]=o[A+5],b[y+Ue]=o[A+5+1];let x=-1;for(let C=p;C<this.prevCount&&this.prevKeys[C]===a;C++)this.prevInfo[C*j+3]===v&&(x=C);if(x<0&&this.params.matchNearest){let C=Sa*Math.min(t[l*4],t[l*4+1],t[c*4],t[c*4+1]);for(let _=p;_<this.prevCount&&this.prevKeys[_]===a;_++){let z=Math.hypot(this.prevData[_*O+N]-b[y+N],this.prevData[_*O+N+1]-b[y+N+1]);z<=C&&(C=z,x=_)}}if(x>=0){let C=x*O;b[y+se]=this.prevData[C+se],b[y+se+1]=this.prevData[C+se+1],b[y+te]=this.prevData[C+te],b[y+te+1]=this.prevData[C+te+1],this.prevData[C+Wi]&&(b[y+N]=this.prevData[C+N],b[y+N+1]=this.prevData[C+N+1],b[y+Y]=this.prevData[C+Y],b[y+Y+1]=this.prevData[C+Y+1])}let[w,B]=wi(e[l*4+2],b[y+N],b[y+N+1]),[L,M]=wi(e[c*4+2],b[y+Y],b[y+Y+1]),I=b[y+be],E=b[y+Ue],k=e[l*4]+w-e[c*4]-L,P=e[l*4+1]+B-e[c*4+1]-M;b[y+fe]=I*k+E*P+5e-4,b[y+fe+1]=E*k-I*P}}}warmStartConstraints(e,t){let i=this.params,r=this.data,o=this.jointCount+this.contactCount;for(let n=0;n<o;n++){let a=Lc[this.info[n*j]],l=n*O;for(let c=0;c<a;c++){if(i.vbd){r[l+se+c]=_r(r[l+Q+c],i.vbdStiffness);continue}e||(r[l+te+c]=r[l+te+c]*t*i.gamma),r[l+se+c]=_r(Er(r[l+se+c]*i.gamma,1,1e9),r[l+Q+c])}}}prepareTopology(){this.buildAdjacency(),this.colorBodies()}buildAdjacency(){let e=this.bodyCount,t=this.jointCount+this.contactCount;this.adjStart=this.grow(this.adjStart,e+1),this.adjList=this.grow(this.adjList,t*2);let i=this.adjStart;i.fill(0,0,e+1);for(let o=0;o<t;o++)for(let n=1;n<=2;n++){let a=this.info[o*j+n];a>=0&&this.dynamic[a]&&i[a+1]++}for(let o=0;o<e;o++)i[o+1]+=i[o];let r=i.slice(0,e);for(let o=0;o<t;o++)for(let n=1;n<=2;n++){let a=this.info[o*j+n];a>=0&&this.dynamic[a]&&(this.adjList[r[a]++]=o)}}colorBodies(){if(this.options.order!=="colored")return;let e=this.coloring.run(this.bodyCount,this.dynamic,this.adjStart,this.adjList,this.info,this.options.colorRounds);this.numColors=e.numColors,this.colorConflicts=e.conflicts,this.colorRounds=e.rounds}warmStartBodies(){let{dt:e,gravity:t}=this.params,{pose:i,velocity:r,initial:o,inertial:n,prevVelocity:a}=this;for(let l=0;l<this.bodyCount;l++){let c=l*4;r[c+2]=Er(r[c+2],-50,50),n[c]=i[c]+r[c]*e,n[c+1]=i[c+1]+r[c+1]*e,n[c+2]=i[c+2]+r[c+2]*e,this.dynamic[l]&&(n[c+1]+=t*e*e);let u=(r[c+1]-a[c+1])/e*wc(t),f=Er(u/Math.abs(t),0,1);Number.isFinite(f)||(f=0),o[c]=i[c],o[c+1]=i[c+1],o[c+2]=i[c+2],i[c]=i[c]+r[c]*e,i[c+1]=i[c+1]+r[c+1]*e+t*f*e*e,i[c+2]=i[c+2]+r[c+2]*e}}eC=new Float64Array(3);eMin=new Float64Array(3);eMax=new Float64Array(3);eJ=new Float64Array(9);eG=new Float64Array(9);evalConstraint(e,t,i){let{info:r,data:o,pose:n,initial:a}=this,l=r[e*j],c=r[e*j+1],u=r[e*j+2],f=e*O,{eC:d,eMin:p,eMax:m,eJ:h,eG:g}=this,b=Lc[l];for(let A=0;A<b;A++)p[A]=o[f+_e+A],m[A]=o[f+Ae+A];let y=i===c;if(g.fill(0),l===Bi){this.jointC(c,u,f,n,o,0,d);for(let A=0;A<3;A++)o[f+Q+A]===1/0&&(d[A]-=o[f+fe+A]*t);if(i>=0){let A=n[i*4+2],[v,x]=wi(A,o[f+(y?N:Y)],o[f+(y?N:Y)+1]),w=y?1:-1;h[0]=w,h[1]=0,h[2]=-w*x,h[3]=0,h[4]=w,h[5]=w*v,h[6]=0,h[7]=0,h[8]=w*o[f+be],g[2]=Math.abs(v),g[5]=Math.abs(x)}}else if(l===Pc){let[A,v]=_c(n,c,o[f+N],o[f+N+1]),[x,w]=_c(n,u,o[f+Y],o[f+Y+1]),B=A-x,L=v-w,M=B*B+L*L,I=Math.sqrt(M);if(d[0]=I-o[f+re],i>=0&&M!==0){let E=B/I,k=L/I,P=(1-E*E)/I,C=-E*k/I,_=(1-k*k)/I,z=n[i*4+2],R=y?N:Y,[G,X]=wi(z,-o[f+R+1],o[f+R]),[W,U]=wi(z,o[f+R],o[f+R+1]),H=P*G+C*X,Z=C*G+_*X,he=E*W+k*U,we=E*G+k*X,Oe=y?1:-1;h[0]=Oe*E,h[1]=Oe*k,h[2]=Oe*we;let $=y?-he-he:he+he;g[0]=Math.hypot(P,C,H),g[1]=Math.hypot(C,_,Z),g[2]=Math.hypot(H,Z,$)}else i>=0&&h.fill(0,0,3)}else if(l===Io){let A=c>=0?n[c*4+2]-a[c*4+2]:0,v=n[u*4+2]-a[u*4+2];d[0]=A-v-o[f+re]*this.params.dt,i>=0&&(h[0]=0,h[1]=0,h[2]=y?1:-1)}else if(l===hs){let A=o[f+be],v=o[f+Ue],x=v,w=-A,[B,L]=wi(a[c*4+2],o[f+N],o[f+N+1]),[M,I]=wi(a[u*4+2],o[f+Y],o[f+Y+1]),E=B*v-L*A,k=-(M*v-I*A),P=B*w-L*x,C=-(M*w-I*x),_=n[c*4]-a[c*4],z=n[c*4+1]-a[c*4+1],R=n[c*4+2]-a[c*4+2],G=n[u*4]-a[u*4],X=n[u*4+1]-a[u*4+1],W=n[u*4+2]-a[u*4+2];d[0]=o[f+fe]*(1-t)+A*_+v*z+E*R+-A*G+-v*X+k*W,d[1]=o[f+fe+1]*(1-t)+x*_+w*z+P*R+-x*G+-w*X+C*W;let U=Math.abs(o[f+te])*o[f+re];m[1]=U,p[1]=-U,i>=0&&(y?(h[0]=A,h[1]=v,h[2]=E,h[3]=x,h[4]=w,h[5]=P):(h[0]=-A,h[1]=-v,h[2]=k,h[3]=-x,h[4]=-w,h[5]=C))}return b}solveBody(e,t){let i=this.params,{shape:r,pose:o,inertial:n,data:a}=this,l=i.dt*i.dt,c=r[e*4+2]/l,u=r[e*4+3]/l,f=c,d=0,p=c,m=0,h=0,g=u,b=c*(o[e*4]-n[e*4]),y=c*(o[e*4+1]-n[e*4+1]),A=u*(o[e*4+2]-n[e*4+2]),{eC:v,eMin:x,eMax:w,eJ:B,eG:L}=this,M=this.adjStart,I=this.adjList;for(let H=M[e+1]-1;H>=M[e];H--){let Z=I[H],he=this.evalConstraint(Z,t,e),we=Z*O,Oe=!i.vbd;for(let $=0;$<he;$++){let Je=a[we+Q+$],Xe=Oe&&Je===1/0?a[we+te+$]:0,Be=a[we+se+$],ot=v[$],ri=Be*ot+Xe,Ye=Er(ri,x[$],w[$]),nt=Math.abs(Ye);i.stiffnessRescale&&ot!==0&&(ri<x[$]?Be=Math.abs((x[$]-Xe)/ot):ri>w[$]&&(Be=Math.abs((w[$]-Xe)/ot)));let Qe=B[$*3],at=B[$*3+1],wt=B[$*3+2];b+=Qe*Ye,y+=at*Ye,A+=wt*Ye,f+=Qe*Qe*Be+L[$*3]*nt,d+=at*Qe*Be,p+=at*at*Be+L[$*3+1]*nt,m+=wt*Qe*Be,h+=wt*at*Be,g+=wt*wt*Be+L[$*3+2]*nt}}let E=f,k=d/f,P=m/f,C=p-k*k*E,_=(h-k*P*E)/C,z=g-(P*P*E+_*_*C),R=y-k*b,X=(A-P*b-_*R)/z,W=R/C-_*X,U=b/E-k*W-P*X;this.dxBuf[e*3]=U,this.dxBuf[e*3+1]=W,this.dxBuf[e*3+2]=X}applyDx(e){this.pose[e*4]-=this.dxBuf[e*3],this.pose[e*4+1]-=this.dxBuf[e*3+1],this.pose[e*4+2]-=this.dxBuf[e*3+2]}primal(e){if(this.dxBuf.length<this.bodyCount*3&&(this.dxBuf=new Float64Array(this.bodyCount*3)),this.options.order==="sequential"){for(let r=this.bodyCount-1;r>=0;r--)this.dynamic[r]&&(this.solveBody(r,e),this.applyDx(r));return}let{colorStart:t,colorBodies:i}=this.coloring;for(let r=0;r<this.numColors;r++){for(let o=t[r];o<t[r+1];o++)this.solveBody(i[o],e);for(let o=t[r];o<t[r+1];o++)this.applyDx(i[o])}}dual(e){let t=this.params,i=this.data,{eC:r,eMin:o,eMax:n}=this,a=this.jointCount+this.contactCount;for(let l=0;l<a;l++){let c=this.info[l*j];if(c===kc)continue;let u=this.evalConstraint(l,e,-1),f=l*O;c===hs&&(i[f+Wi]=Math.abs(i[f+te+1])<n[1]&&Math.abs(i[f+fe+1])<.01?1:0);for(let d=0;d<u;d++){let p=i[f+Q+d],m=!t.vbd&&p===1/0?i[f+te+d]:0,h=Er(i[f+se+d]*r[d]+m,o[d],n[d]);i[f+te+d]=h,Math.abs(h)>=i[f+Pt+d]&&this.disable(l),!t.vbd&&h>o[d]&&h<n[d]&&(i[f+se+d]=_r(i[f+se+d]+t.beta*Math.abs(r[d]),_r(1e9,i[f+Q+d])))}}}refreshStick(){let e=this.data;for(let t=0;t<this.contactCount;t++){let i=(this.jointCount+t)*O,r=Math.abs(e[i+te])*e[i+re];e[i+Wi]=Math.abs(e[i+te+1])<r&&Math.abs(e[i+fe+1])<.01?1:0}}disable(e){let t=e*O;this.data.fill(0,t+se,t+se+3),this.data.fill(0,t+te,t+te+3),this.data.fill(0,t+Q,t+Q+3)}updateVelocities(){let{dt:e}=this.params,{pose:t,initial:i,velocity:r,prevVelocity:o}=this;for(let n=0;n<this.bodyCount;n++){let a=n*4;o[a]=r[a],o[a+1]=r[a+1],o[a+2]=r[a+2],this.dynamic[n]&&(r[a]=(t[a]-i[a])/e,r[a+1]=(t[a+1]-i[a+1])/e,r[a+2]=(t[a+2]-i[a+2])/e)}}pick(e,t){for(let i=this.bodyCount-1;i>=0;i--){let[r,o]=wi(-this.pose[i*4+2],e-this.pose[i*4],t-this.pose[i*4+1]);if(Math.abs(r)<=this.shape[i*4]*.5&&Math.abs(o)<=this.shape[i*4+1]*.5)return{body:i,local:[r,o]}}return null}kineticEnergy(){let e=0;for(let t=0;t<this.bodyCount;t++){if(!this.dynamic[t])continue;let i=t*4,r=this.velocity;e+=.5*this.shape[i+2]*(r[i]*r[i]+r[i+1]*r[i+1])+.5*this.shape[i+3]*r[i+2]*r[i+2]}return e}maxJointError(){let e=0,t=new Float64Array(3);for(let i=0;i<this.jointCount;i++){if(this.info[i*j]!==Bi)continue;let r=i*O;this.jointC(this.info[i*j+1],this.info[i*j+2],r,this.pose,this.data,0,t);for(let o=0;o<2;o++)this.data[r+Q+o]===1/0&&(e=Math.max(e,Math.abs(t[o])))}return e}isContactPairIgnored(e,t){return wa(this.noCollide,this.noCollideCount,Mr(e,t))}};function wi(s,e,t){let i=Math.cos(s),r=Math.sin(s);return[i*e-r*t,r*e+i*t]}function _c(s,e,t,i){let r=Math.cos(s[e*4+2]),o=Math.sin(s[e*4+2]);return[r*t-o*i+s[e*4],o*t+r*i+s[e*4+1]]}var ps=`
3821
+ ${Ut}
3610
3822
 
3611
3823
  @group(0) @binding(0) var<uniform> params: Params;
3612
3824
  @group(0) @binding(1) var<storage, read> bodies: array<Body>;
@@ -3745,8 +3957,8 @@ fn findPairs(@builtin(global_invocation_id) gid: vec3u) {
3745
3957
  testPair(l, i);
3746
3958
  }
3747
3959
  }
3748
- `,ts=`
3749
- ${Nt}
3960
+ `,ms=`
3961
+ ${Ut}
3750
3962
 
3751
3963
  @group(0) @binding(0) var<uniform> params: Params;
3752
3964
  @group(0) @binding(1) var<storage, read> bodies: array<Body>;
@@ -4072,8 +4284,8 @@ fn narrowphase(@builtin(global_invocation_id) gid: vec3u) {
4072
4284
  contacts[k] = rec;
4073
4285
  }
4074
4286
  }
4075
- `;var is=`
4076
- ${Nt}
4287
+ `;var gs=`
4288
+ ${Ut}
4077
4289
 
4078
4290
  // Per-dispatch constants, selected with a dynamic uniform offset
4079
4291
  struct PassConstants {
@@ -4445,7 +4657,7 @@ fn updateVelocities(@builtin(global_invocation_id) gid: vec3u) {
4445
4657
  if (b.shape.z > 0.0) { b.vel = vec4f((b.pose.xyz - b.initial.xyz) / params.dt, 0.0); }
4446
4658
  bodies[i] = b;
4447
4659
  }
4448
- `;var fo=s=>s===1/0?3e38:s===-1/0?-3e38:s,mt=s=>Math.ceil(s/64),Fl=s=>2**Math.ceil(Math.log2(Math.max(s,2))),Wu=s=>Math.max(s,1)*24*4,Hu=4,gt=()=>GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST,ho=class{device;params=io();topology;bodyCount=0;bodyCapacity;jointCount=0;jointCapacity=0;pairCapacity=0;contactCapacity=0;colorCap=12;splitPasses=!1;primalMode="bucket";shrinkVotes=0;get colorHistOffset(){return 3*this.bodyCapacity+65}colorRounds;bodyBuffer;ownsBodyBuffer;jointBuffer;infoBuffer;contactBuffers;pairBuffer;tableBuffer;gridBuffer;staticBuffer=null;counterBuffer;argsBuffer;adjBuffer=null;colorBuffer;paramsBuffer;passBuffer=null;passEntries=0;parity=0;tableSize;hashSize=0;cellSize=1;maxSmallRadius=0;largeCount=0;noCollideCount=0;staticsDirty=!0;layouts;pipes={};groups;passGroup=null;gridScan;colorHistScan;colorGroups;adjScan=null;timing;timingCallback=null;timingBusy=!1;destroyed=!1;constructor(e,t,i={}){if(this.device=e,this.topology=t,Object.assign(this.params,t.params),this.bodyCount=t.bodyCount,this.colorRounds=i.colorRounds??16,this.ownsBodyBuffer=!i.bodyBuffer,this.bodyCapacity=i.bodyBuffer?Math.floor(i.bodyBuffer.size/96):Math.max(i.bodyCapacity??this.bodyCount+1024,this.bodyCount,1),this.bodyCapacity<this.bodyCount)throw new Error("body buffer too small");this.bodyBuffer=i.bodyBuffer??e.createBuffer({label:"bodies",size:Wu(this.bodyCapacity),usage:gt()});let r=this.bodyCapacity;this.tableSize=Fl(2*r),this.gridBuffer=e.createBuffer({label:"grid",size:(2*this.tableSize+1+3*r)*4,usage:gt()}),this.counterBuffer=e.createBuffer({label:"counters",size:64,usage:gt()}),this.argsBuffer=e.createBuffer({label:"indirect args",size:816,usage:gt()|GPUBufferUsage.INDIRECT}),this.colorGroups=Math.ceil(r/256),this.colorBuffer=e.createBuffer({label:"colours",size:(3*r+65+64*this.colorGroups+1)*4,usage:gt()}),this.paramsBuffer=e.createBuffer({label:"params",size:128,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),e.queue.writeBuffer(this.colorBuffer,0,new Uint32Array(r).fill(255));let o=2*Se.length;this.timing=e.features.has("timestamp-query")?{querySet:e.createQuerySet({type:"timestamp",count:o}),resolve:e.createBuffer({size:o*8,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),read:e.createBuffer({size:o*8,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST})}:null,this.layouts=this.createLayouts(),this.createPipelines(),this.gridScan=new tt(e,this.gridBuffer,0,this.tableSize+1),this.colorHistScan=new tt(e,this.colorBuffer,this.colorHistOffset,64*this.colorGroups+1),this.jointCount=t.jointCount,this.allocateJoints(t.jointCount+256),this.uploadJoints(0,t.jointCount),this.allocateContacts(Math.max(4096,4*r)),this.uploadBodies()}createLayouts(){let e=this.device,t=(n,a)=>e.createBindGroupLayout({label:n,entries:a.map((l,c)=>({binding:c,visibility:GPUShaderStage.COMPUTE,buffer:{type:l}}))}),i="read-only-storage",r="storage",o="uniform";return{broad:t("broadphase",[o,i,r,r,r,i,i]),contacts:t("contacts",[o,i,i,r,i,r,r]),topo:t("topology",[o,i,i,i,i,r,r,r]),solve:t("solve",[o,r,r,i,r,i,i,i]),pass:e.createBindGroupLayout({label:"pass",entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform",hasDynamicOffset:!0,minBindingSize:16}}]}),args:t("args",[o,i,i,r])}}createPipelines(){let e=this.device,t=(r,o,n)=>{let a=e.createShaderModule({code:r}),l=e.createPipelineLayout({bindGroupLayouts:o});for(let c of n)this.pipes[c]=e.createComputePipeline({label:c,layout:l,compute:{module:a,entryPoint:c}})},i=this.layouts;t(es,[i.broad],["beginFrame","gridCount","gridScatter","findPairs"]),t(ts,[i.contacts],["hashInsert","narrowphase"]),t(Dr,[i.topo],["degreeJoints","degreeContacts","fillJoints","fillContacts","sortAdjacency","colorCompact","colorMark","colorRoundAB","colorRoundBA","colorCount","colorStarts","colorScatter"]),t(is,[i.solve,i.pass],["warmStartJoints","warmStartBodies","primal","primalScan","dual","refreshStick","updateVelocities"]),t(Cs,[i.args],["argsPrev","argsPairs","argsContacts","argsColors"])}allocateJoints(e){let t=this.device,i=t.createBuffer({label:"joints",size:Math.max(e,1)*36*4,usage:gt()}),r=t.createBuffer({label:"joint info",size:Math.max(e,1)*16,usage:gt()});if(this.jointBuffer){let o=t.createCommandEncoder();o.copyBufferToBuffer(this.jointBuffer,0,i,0,this.jointCapacity*36*4),o.copyBufferToBuffer(this.infoBuffer,0,r,0,this.jointCapacity*16),t.queue.submit([o.finish()]),this.jointBuffer.destroy(),this.infoBuffer.destroy()}this.jointBuffer=i,this.infoBuffer=r,this.jointCapacity=e,this.contactBuffers&&this.rebuildBindings()}allocateContacts(e,t=2*e){let i=this.device,r=i.limits.maxStorageBufferBindingSize,o=Math.min(e,Math.floor(r/80),Math.floor(r/16)),n=Math.min(t,Math.floor(r/8)),a=this.contactBuffers,l=this.contactCapacity;for(let c of[this.pairBuffer,this.tableBuffer])c?.destroy();if(this.contactCapacity=o,this.pairCapacity=n,this.hashSize=Fl(4*o),this.pairBuffer=i.createBuffer({label:"pairs",size:n*8,usage:gt()}),this.tableBuffer=i.createBuffer({label:"contact hash",size:this.hashSize*4,usage:gt()}),this.contactBuffers=[0,1].map(c=>i.createBuffer({label:`contacts ${c}`,size:o*20*4,usage:gt()})),a){let c=i.createCommandEncoder(),u=Math.min(l,o)*20*4;a.forEach((f,d)=>c.copyBufferToBuffer(f,0,this.contactBuffers[d],0,u)),i.queue.submit([c.finish()]),a.forEach(f=>f.destroy())}this.rebuildBindings()}rebuildBindings(){let e=this.device,t=this.bodyCapacity;this.adjBuffer?.destroy(),this.adjBuffer=e.createBuffer({label:"adjacency",size:(2*t+1+2*(this.jointCapacity+this.contactCapacity))*4,usage:gt()}),this.adjScan?.destroy(),this.adjScan=new tt(e,this.adjBuffer,0,this.bodyCount+1),this.staticBuffer??=e.createBuffer({label:"statics",size:16,usage:gt()});let i=(l,c)=>e.createBindGroup({layout:l,entries:c.map((u,f)=>({binding:f,resource:{buffer:u}}))}),r=this.paramsBuffer,[o,n]=this.contactBuffers,a=this.adjBuffer;this.groups={broad:i(this.layouts.broad,[r,this.bodyBuffer,this.gridBuffer,this.pairBuffer,this.counterBuffer,this.staticBuffer,this.jointBuffer]),contacts:[i(this.layouts.contacts,[r,this.bodyBuffer,this.pairBuffer,o,n,this.tableBuffer,this.counterBuffer]),i(this.layouts.contacts,[r,this.bodyBuffer,this.pairBuffer,n,o,this.tableBuffer,this.counterBuffer])],topo:[o,n].map(l=>i(this.layouts.topo,[r,this.bodyBuffer,this.jointBuffer,this.infoBuffer,l,this.counterBuffer,a,this.colorBuffer])),solve:[o,n].map(l=>i(this.layouts.solve,[r,this.bodyBuffer,this.jointBuffer,this.infoBuffer,l,a,this.colorBuffer,this.counterBuffer])),args:i(this.layouts.args,[r,this.counterBuffer,this.colorBuffer,this.argsBuffer])}}uploadBodies(e=0,t=this.topology.bodyCount-e){let i=this.topology,r=new Float32Array(Math.max(t,1)*24);for(let o=0;o<t;o++){let n=e+o,a=o*24;r.set(i.pose.subarray(n*4,n*4+3),a),r[a+3]=i.props[n*4],r.set(i.initial.subarray(n*4,n*4+4),a+4),r.set(i.inertial.subarray(n*4,n*4+4),a+8),r.set(i.velocity.subarray(n*4,n*4+4),a+12),r.set(i.prevVelocity.subarray(n*4,n*4+4),a+16),r.set(i.shape.subarray(n*4,n*4+4),a+20)}this.device.queue.writeBuffer(this.bodyBuffer,e*24*4,r),this.staticsDirty=!0}uploadJoints(e,t){if(t===0)return;let i=this.topology,r=new Float32Array(t*36);for(let o=0;o<t;o++){let n=(e+o)*O,a=o*36;for(let l=0;l<3;l++)r[a+0+l]=i.data[n+se+l],r[a+4+l]=i.data[n+te+l],r[a+8+l]=fo(i.data[n+Q+l]),r[a+12+l]=fo(i.data[n+Le+l]),r[a+16+l]=fo(i.data[n+xe+l]),r[a+20+l]=fo(i.data[n+Pt+l]),r[a+24+l]=i.data[n+fe+l];r[a+28]=i.data[n+U],r[a+28+1]=i.data[n+U+1],r[a+28+2]=i.data[n+Y],r[a+28+3]=i.data[n+Y+1],r[a+32]=i.data[n+re],r[a+32+1]=i.data[n+ge]}this.device.queue.writeBuffer(this.jointBuffer,e*36*4,r),this.device.queue.writeBuffer(this.infoBuffer,e*16,i.info,e*j,t*j)}uploadStatics(){let e=this.topology,t=this.bodyCount,i=Float64Array.from({length:t},(f,d)=>e.props[d*4+1]).sort(),r=t>0?i[t>>1]:1,o=0;for(let f=0;f<t;f++)i[f]<=Hu*r&&(o=Math.max(o,i[f]));let n=1/0;for(let f=0;f<t;f++)i[f]>o&&(n=Math.min(n,i[f]));let a=n===1/0?o*1.5:(o+n)/2;this.maxSmallRadius=a,this.cellSize=Math.max(2*o*(1+1e-4),.001);let l=[];for(let f=0;f<t;f++)e.props[f*4+1]>a&&l.push(f);let c=[];for(let f=0;f<e.jointCount;f++){let d=e.info[f*j+1],p=e.info[f*j+2];d>=0&&c.push([Math.max(d,p),Math.min(d,p),f])}for(let f of e.ignoredPairs()){let d=Math.floor(f/2097152);c.push([d,f-d*2097152,4294967295])}c.sort((f,d)=>f[0]-d[0]||f[1]-d[1]),this.largeCount=l.length,this.noCollideCount=c.length;let u=new Uint32Array(Math.max(l.length+3*c.length,4));u.set(l,0),c.forEach((f,d)=>u.set(f,l.length+3*d)),this.staticBuffer.size<u.byteLength&&(this.staticBuffer.destroy(),this.staticBuffer=this.device.createBuffer({label:"statics",size:u.byteLength,usage:gt()}),this.rebuildBindings()),this.device.queue.writeBuffer(this.staticBuffer,0,u),this.staticsDirty=!1}seedContactsFrom(e){let t=e.contactCount;if(t>this.contactCapacity)throw new Error("seedContactsFrom: too many contacts");let i=new ArrayBuffer(Math.max(t,1)*20*4),r=new Uint32Array(i),o=new Float32Array(i);for(let l=0;l<t;l++){let c=e.jointCount+l,u=c*O,f=l*20;r[f]=e.info[c*j+1],r[f+1]=e.info[c*j+2],r[f+2]=e.info[c*j+3],r[f+3]=e.data[u+Vi]?1:0,o.set([e.data[u+se],e.data[u+se+1],e.data[u+te],e.data[u+te+1]],f+4),o.set([e.data[u+U],e.data[u+U+1],e.data[u+Y],e.data[u+Y+1]],f+8),o.set([e.data[u+fe],e.data[u+fe+1],e.data[u+ge],e.data[u+Fe]],f+12),o[f+16]=e.data[u+re]}this.device.queue.writeBuffer(this.contactBuffers[1-this.parity],0,i);let n=new Uint32Array(16);n[1]=t,this.device.queue.writeBuffer(this.counterBuffer,0,n);let a=Uint32Array.from({length:this.bodyCount},(l,c)=>(e.coloring.colors[c]??-1)<0?255:e.coloring.colors[c]);this.device.queue.writeBuffer(this.colorBuffer,0,a)}addBody(e,t,i,r,o){if(this.bodyCount>=this.bodyCapacity)return-1;let n=this.topology.addBody(e,t,i,r,o);return this.bodyCount=this.topology.bodyCount,this.uploadBodies(n,1),this.device.queue.writeBuffer(this.colorBuffer,n*4,new Uint32Array([255])),this.adjScan.destroy(),this.adjScan=new tt(this.device,this.adjBuffer,0,this.bodyCount+1),n}appendJoint(e,t,i,r,o,n=1/0){let a=this.topology;if(a.contactCount>0)throw new Error("appendJoint: the CPU mirror must not hold contacts");let l=a.addJoint(e,t,i,r,o,n).slot;return l>=this.jointCapacity&&this.allocateJoints(Math.max(l+1,this.jointCapacity*2)),this.jointCount=l+1,this.uploadJoints(l,1),e>=0&&(this.staticsDirty=!0),l}setWorldAnchor(e,t,i){this.device.queue.writeBuffer(this.jointBuffer,(e*36+28)*4,new Float32Array([t,i]))}disableConstraint(e){this.device.queue.writeBuffer(this.jointBuffer,(e*36+0)*4,new Float32Array(12)),this.topology.data.fill(0,e*O+Q,e*O+Q+3)}profileNextStep(e){this.timing&&!this.timingBusy&&(this.timingCallback=e)}writeParams(e,t){let i=this.params,r=this.bodyCapacity,o=new ArrayBuffer(128),n=new Float32Array(o),a=new Uint32Array(o);n[0]=i.dt,n[1]=i.gravity,n[2]=i.beta,n[3]=i.gamma,n[4]=e,n[5]=i.vbdStiffness,a[6]=(i.vbd?1:0)|(i.stiffnessRescale?2:0)|(t?4:0)|(i.matchNearest?8:0),a[7]=this.bodyCount,a[8]=this.jointCount,a[9]=this.colorCap,n[10]=this.cellSize,a[11]=this.tableSize-1,n[12]=this.maxSmallRadius,a[13]=this.largeCount,a[14]=this.noCollideCount,a[15]=this.pairCapacity,a[16]=this.contactCapacity,a[17]=this.hashSize-1,a[18]=r+1,a[19]=2*r+1,a[20]=this.tableSize+1,a[21]=2*this.tableSize+1,a[22]=2*this.tableSize+1+r,a[23]=r,a[24]=this.colorHistOffset,a[25]=2*r,a[26]=this.colorGroups,a[27]=2*r+65,a[28]=this.colorRounds,this.device.queue.writeBuffer(this.paramsBuffer,0,o)}writePassConstants(e,t){let i=this.colorCap+1,r=e*i;(r>this.passEntries||!this.passGroup)&&(this.passBuffer?.destroy(),this.passBuffer=this.device.createBuffer({label:"pass constants",size:r*256,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.passEntries=r,this.passGroup=this.device.createBindGroup({layout:this.layouts.pass,entries:[{binding:0,resource:{buffer:this.passBuffer,size:16}}]}));let o=new ArrayBuffer(r*256),n=new Uint32Array(o),a=new Float32Array(o);for(let l=0;l<e;l++)for(let c=0;c<=this.colorCap;c++){let u=(l*i+c)*256/4;n[u]=c,a[u+1]=t(l)}this.device.queue.writeBuffer(this.passBuffer,0,o)}step(){this.staticsDirty&&this.uploadStatics();let e=this.params,t=e.postStabilize&&!e.vbd,i=e.vbd?0:e.alpha,r=e.iterations+(t?1:0);this.writeParams(i,t),this.writePassConstants(r,A=>t?A<e.iterations?1:0:i);let o=this.parity,n=this.bodyCapacity,a=this.bodyCount,l=this.jointCount,c=this.device.createCommandEncoder({label:"avbd2d step"});c.clearBuffer(this.gridBuffer,0,(2*this.tableSize+1)*4),c.clearBuffer(this.tableBuffer),c.clearBuffer(this.adjBuffer,0,(2*n+1)*4);let u=this.timingCallback!==null&&this.timing!==null,f,d=0,p=u||this.splitPasses,g=()=>{f&&!p||(f?.end(),f=c.beginComputePass({label:p?Se[d]:"avbd2d step",timestampWrites:u?{querySet:this.timing.querySet,beginningOfPassWriteIndex:2*d,endOfPassWriteIndex:2*d+1}:void 0}),d++)},h=this.groups,m=(A,x,B)=>{B<=0||(f.setPipeline(this.pipes[A]),f.setBindGroup(0,x),f.dispatchWorkgroups(B))},b=(A,x,B)=>{f.setPipeline(this.pipes[A]),f.setBindGroup(0,x),f.dispatchWorkgroupsIndirect(this.argsBuffer,B*4)};g(),m("beginFrame",h.broad,1),m("argsPrev",h.args,1),b("hashInsert",h.contacts[o],6),m("gridCount",h.broad,mt(a)),this.gridScan.encode(f),m("gridScatter",h.broad,mt(a)),m("findPairs",h.broad,mt(a)),m("argsPairs",h.args,1),b("narrowphase",h.contacts[o],0),m("argsContacts",h.args,1),g(),m("degreeJoints",h.topo[o],mt(l)),b("degreeContacts",h.topo[o],3),this.adjScan.encode(f),m("fillJoints",h.topo[o],mt(l)),b("fillContacts",h.topo[o],3),m("sortAdjacency",h.topo[o],mt(a)),g(),m("colorCompact",h.topo[o],mt(a)),m("colorMark",h.topo[o],mt(a));for(let A=0;A<this.colorRounds;A++)m(A%2===0?"colorRoundAB":"colorRoundBA",h.topo[o],mt(a));m("colorCount",h.topo[o],this.colorGroups),this.colorHistScan.encode(f),m("colorStarts",h.topo[o],1),m("argsColors",h.args,1),m("colorScatter",h.topo[o],this.colorGroups),g();let v=this.colorCap+1,w=A=>f.setBindGroup(1,this.passGroup,[A*256]);f.setBindGroup(0,h.solve[o]),w(0),l>0&&(f.setPipeline(this.pipes.warmStartJoints),f.dispatchWorkgroups(mt(l))),f.setPipeline(this.pipes.warmStartBodies),f.dispatchWorkgroups(mt(a));for(let A=0;A<r;A++){let x=this.primalMode==="scan";f.setPipeline(x?this.pipes.primalScan:this.pipes.primal);for(let B=0;B<this.colorCap;B++)w(A*v+B),x?f.dispatchWorkgroups(mt(a)):f.dispatchWorkgroupsIndirect(this.argsBuffer,(12+3*B)*4);A<e.iterations&&(w(A*v+this.colorCap),f.setPipeline(this.pipes.dual),f.dispatchWorkgroupsIndirect(this.argsBuffer,36)),A===e.iterations-1&&(f.setPipeline(this.pipes.updateVelocities),f.dispatchWorkgroups(mt(a)))}t&&(f.setPipeline(this.pipes.refreshStick),f.dispatchWorkgroupsIndirect(this.argsBuffer,12)),f.end();let y=2*Se.length;if(u){let{querySet:A,resolve:x,read:B}=this.timing;c.resolveQuerySet(A,0,y,x,0),c.copyBufferToBuffer(x,0,B,0,y*8)}if(this.device.queue.submit([c.finish()]),this.parity=1-o,u){let A=this.timingCallback;this.timingCallback=null,this.timingBusy=!0;let x=this.timing.read;x.mapAsync(GPUMapMode.READ).then(()=>{let B=new BigUint64Array(x.getMappedRange()).slice();if(x.unmap(),this.timingBusy=!1,this.destroyed)return this.releaseTiming();let E=(M,z)=>Number(B[z]-B[M])/1e6,L={total:E(0,y-1)};Se.forEach((M,z)=>L[M]=E(2*z,2*z+1)),A(L)},()=>{this.timingBusy=!1,this.destroyed&&this.releaseTiming()})}}async readBodies(){return new Float32Array(await this.read(this.bodyBuffer,this.bodyCount*24*4))}async readJoints(){return new Float32Array(await this.read(this.jointBuffer,this.jointCount*36*4))}async readCounters(){let e=new Uint32Array(await this.read(this.counterBuffer,64));return{pairs:e[0],contacts:e[1],overflow:e[3],clashes:e[4],colors:e[5]}}async readContacts(){let{contacts:e}=await this.readCounters(),t=Math.min(e,this.contactCapacity);return this.read(this.contactBuffers[1-this.parity],t*20*4)}async readPairs(){let{pairs:e}=await this.readCounters();return new Uint32Array(await this.read(this.pairBuffer,Math.min(e,this.pairCapacity)*8))}async readColors(){return new Uint32Array(await this.read(this.colorBuffer,this.bodyCount*4))}async readAdjacency(){let e=new Uint32Array(await this.read(this.adjBuffer,this.adjBuffer.size)),t=e.slice(0,this.bodyCount+1),i=2*this.bodyCapacity+1;return{start:t,list:e.slice(i,i+t[this.bodyCount])}}adapt(e){let t=e.colors;e.clashes>0||t>=this.colorCap-1?(this.colorCap=Math.min(64,Math.max(t+4,this.colorCap+4)),this.shrinkVotes=0):t+2<this.colorCap?++this.shrinkVotes>=3&&(this.colorCap=Math.min(64,Math.max(4,t+2)),this.shrinkVotes=0):this.shrinkVotes=0;let i=(e.overflow&2)!==0||e.contacts>.8*this.contactCapacity,r=(e.overflow&1)!==0||e.pairs>.8*this.pairCapacity,o=this.contactCapacity*(i?2:1),n=this.pairCapacity*(r?2:1);(i||r)&&this.capacityCanGrow(o,n)&&this.allocateContacts(o,n)}capacityCanGrow(e,t){let i=this.device.limits.maxStorageBufferBindingSize,r=Math.min(Math.floor(i/80),Math.floor(i/16));return Math.min(e,r)>this.contactCapacity||Math.min(t,Math.floor(i/8))>this.pairCapacity}async readStats(e){let[t,i]=await Promise.all([e??this.readBodies(),this.readJoints()]),r=0;for(let c=0;c<this.bodyCount;c++){let u=c*24,f=t[u+22],d=t[u+12],p=t[u+13],g=t[u+14];f>0&&(r+=.5*f*(d*d+p*p)+.5*t[u+23]*g*g)}let o=0,n=0,a=this.topology.info,l=(c,u,f)=>{let d=c*24,p=Math.cos(t[d+2]),g=Math.sin(t[d+2]);return[p*u-g*f+t[d],g*u+p*f+t[d+1]]};for(let c=0;c<this.jointCount;c++){if(a[c*j]!==xi)continue;let u=c*36;if(i[u+8]===0&&i[u+8+1]===0&&i[u+8+2]===0)continue;n++;let f=a[c*j+1],d=a[c*j+2],p=f>=0?l(f,i[u+28],i[u+28+1]):[i[u+28],i[u+28+1]],g=l(d,i[u+28+2],i[u+28+3]);for(let h=0;h<2;h++)i[u+8+h]>=1e30&&(o=Math.max(o,Math.abs(p[h]-g[h])))}return{kineticEnergy:r,maxJointError:o,joints:n}}async read(e,t){if(t===0)return new ArrayBuffer(0);let i=this.device.createBuffer({size:t,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),r=this.device.createCommandEncoder();r.copyBufferToBuffer(e,0,i,0,t),this.device.queue.submit([r.finish()]),await i.mapAsync(GPUMapMode.READ);let o=i.getMappedRange().slice(0);return i.unmap(),i.destroy(),o}releaseTiming(){this.timing?.resolve.destroy(),this.timing?.read.destroy(),this.timing?.querySet.destroy()}destroy(){this.ownsBodyBuffer&&this.bodyBuffer.destroy();let e=[this.jointBuffer,this.infoBuffer,...this.contactBuffers,this.pairBuffer,this.tableBuffer,this.gridBuffer,this.staticBuffer,this.counterBuffer,this.argsBuffer,this.adjBuffer,this.colorBuffer,this.paramsBuffer,this.passBuffer];for(let t of e)t?.destroy();this.destroyed=!0,this.timingBusy||this.releaseTiming(),this.gridScan.destroy(),this.colorHistScan.destroy(),this.adjScan?.destroy()}};var Ju=`${Nt}
4660
+ `;var Ro=s=>s===1/0?3e38:s===-1/0?-3e38:s,bt=s=>Math.ceil(s/64),zc=s=>2**Math.ceil(Math.log2(Math.max(s,2))),Nf=s=>Math.max(s,1)*24*4,qf=4,yt=()=>GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST,Oo=class{device;params=So();topology;bodyCount=0;bodyCapacity;jointCount=0;jointCapacity=0;pairCapacity=0;contactCapacity=0;colorCap=12;splitPasses=!1;primalMode="bucket";shrinkVotes=0;get colorHistOffset(){return 3*this.bodyCapacity+65}colorRounds;bodyBuffer;ownsBodyBuffer;jointBuffer;infoBuffer;contactBuffers;pairBuffer;tableBuffer;gridBuffer;staticBuffer=null;counterBuffer;argsBuffer;adjBuffer=null;colorBuffer;paramsBuffer;passBuffer=null;passEntries=0;parity=0;tableSize;hashSize=0;cellSize=1;maxSmallRadius=0;largeCount=0;noCollideCount=0;staticsDirty=!0;layouts;pipes={};groups;passGroup=null;gridScan;colorHistScan;colorGroups;adjScan=null;timing;timingCallback=null;timingBusy=!1;destroyed=!1;constructor(e,t,i={}){if(this.device=e,this.topology=t,Object.assign(this.params,t.params),this.bodyCount=t.bodyCount,this.colorRounds=i.colorRounds??16,this.ownsBodyBuffer=!i.bodyBuffer,this.bodyCapacity=i.bodyBuffer?Math.floor(i.bodyBuffer.size/96):Math.max(i.bodyCapacity??this.bodyCount+1024,this.bodyCount,1),this.bodyCapacity<this.bodyCount)throw new Error("body buffer too small");this.bodyBuffer=i.bodyBuffer??e.createBuffer({label:"bodies",size:Nf(this.bodyCapacity),usage:yt()});let r=this.bodyCapacity;this.tableSize=zc(2*r),this.gridBuffer=e.createBuffer({label:"grid",size:(2*this.tableSize+1+3*r)*4,usage:yt()}),this.counterBuffer=e.createBuffer({label:"counters",size:64,usage:yt()}),this.argsBuffer=e.createBuffer({label:"indirect args",size:816,usage:yt()|GPUBufferUsage.INDIRECT}),this.colorGroups=Math.ceil(r/256),this.colorBuffer=e.createBuffer({label:"colours",size:(3*r+65+64*this.colorGroups+1)*4,usage:yt()}),this.paramsBuffer=e.createBuffer({label:"params",size:128,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),e.queue.writeBuffer(this.colorBuffer,0,new Uint32Array(r).fill(255));let o=2*Se.length;this.timing=e.features.has("timestamp-query")?{querySet:e.createQuerySet({type:"timestamp",count:o}),resolve:e.createBuffer({size:o*8,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),read:e.createBuffer({size:o*8,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST})}:null,this.layouts=this.createLayouts(),this.createPipelines(),this.gridScan=new tt(e,this.gridBuffer,0,this.tableSize+1),this.colorHistScan=new tt(e,this.colorBuffer,this.colorHistOffset,64*this.colorGroups+1),this.jointCount=t.jointCount,this.allocateJoints(t.jointCount+256),this.uploadJoints(0,t.jointCount),this.allocateContacts(Math.max(4096,4*r)),this.uploadBodies()}createLayouts(){let e=this.device,t=(n,a)=>e.createBindGroupLayout({label:n,entries:a.map((l,c)=>({binding:c,visibility:GPUShaderStage.COMPUTE,buffer:{type:l}}))}),i="read-only-storage",r="storage",o="uniform";return{broad:t("broadphase",[o,i,r,r,r,i,i]),contacts:t("contacts",[o,i,i,r,i,r,r]),topo:t("topology",[o,i,i,i,i,r,r,r]),solve:t("solve",[o,r,r,i,r,i,i,i]),pass:e.createBindGroupLayout({label:"pass",entries:[{binding:0,visibility:GPUShaderStage.COMPUTE,buffer:{type:"uniform",hasDynamicOffset:!0,minBindingSize:16}}]}),args:t("args",[o,i,i,r])}}createPipelines(){let e=this.device,t=(r,o,n)=>{let a=e.createShaderModule({code:r}),l=e.createPipelineLayout({bindGroupLayouts:o});for(let c of n)this.pipes[c]=e.createComputePipeline({label:c,layout:l,compute:{module:a,entryPoint:c}})},i=this.layouts;t(ps,[i.broad],["beginFrame","gridCount","gridScatter","findPairs"]),t(ms,[i.contacts],["hashInsert","narrowphase"]),t(qr,[i.topo],["degreeJoints","degreeContacts","fillJoints","fillContacts","sortAdjacency","colorCompact","colorMark","colorRoundAB","colorRoundBA","colorCount","colorStarts","colorScatter"]),t(gs,[i.solve,i.pass],["warmStartJoints","warmStartBodies","primal","primalScan","dual","refreshStick","updateVelocities"]),t(Fs,[i.args],["argsPrev","argsPairs","argsContacts","argsColors"])}allocateJoints(e){let t=this.device,i=t.createBuffer({label:"joints",size:Math.max(e,1)*36*4,usage:yt()}),r=t.createBuffer({label:"joint info",size:Math.max(e,1)*16,usage:yt()});if(this.jointBuffer){let o=t.createCommandEncoder();o.copyBufferToBuffer(this.jointBuffer,0,i,0,this.jointCapacity*36*4),o.copyBufferToBuffer(this.infoBuffer,0,r,0,this.jointCapacity*16),t.queue.submit([o.finish()]),this.jointBuffer.destroy(),this.infoBuffer.destroy()}this.jointBuffer=i,this.infoBuffer=r,this.jointCapacity=e,this.contactBuffers&&this.rebuildBindings()}allocateContacts(e,t=2*e){let i=this.device,r=i.limits.maxStorageBufferBindingSize,o=Math.min(e,Math.floor(r/80),Math.floor(r/16)),n=Math.min(t,Math.floor(r/8)),a=this.contactBuffers,l=this.contactCapacity;for(let c of[this.pairBuffer,this.tableBuffer])c?.destroy();if(this.contactCapacity=o,this.pairCapacity=n,this.hashSize=zc(4*o),this.pairBuffer=i.createBuffer({label:"pairs",size:n*8,usage:yt()}),this.tableBuffer=i.createBuffer({label:"contact hash",size:this.hashSize*4,usage:yt()}),this.contactBuffers=[0,1].map(c=>i.createBuffer({label:`contacts ${c}`,size:o*20*4,usage:yt()})),a){let c=i.createCommandEncoder(),u=Math.min(l,o)*20*4;a.forEach((f,d)=>c.copyBufferToBuffer(f,0,this.contactBuffers[d],0,u)),i.queue.submit([c.finish()]),a.forEach(f=>f.destroy())}this.rebuildBindings()}rebuildBindings(){let e=this.device,t=this.bodyCapacity;this.adjBuffer?.destroy(),this.adjBuffer=e.createBuffer({label:"adjacency",size:(2*t+1+2*(this.jointCapacity+this.contactCapacity))*4,usage:yt()}),this.adjScan?.destroy(),this.adjScan=new tt(e,this.adjBuffer,0,this.bodyCount+1),this.staticBuffer??=e.createBuffer({label:"statics",size:16,usage:yt()});let i=(l,c)=>e.createBindGroup({layout:l,entries:c.map((u,f)=>({binding:f,resource:{buffer:u}}))}),r=this.paramsBuffer,[o,n]=this.contactBuffers,a=this.adjBuffer;this.groups={broad:i(this.layouts.broad,[r,this.bodyBuffer,this.gridBuffer,this.pairBuffer,this.counterBuffer,this.staticBuffer,this.jointBuffer]),contacts:[i(this.layouts.contacts,[r,this.bodyBuffer,this.pairBuffer,o,n,this.tableBuffer,this.counterBuffer]),i(this.layouts.contacts,[r,this.bodyBuffer,this.pairBuffer,n,o,this.tableBuffer,this.counterBuffer])],topo:[o,n].map(l=>i(this.layouts.topo,[r,this.bodyBuffer,this.jointBuffer,this.infoBuffer,l,this.counterBuffer,a,this.colorBuffer])),solve:[o,n].map(l=>i(this.layouts.solve,[r,this.bodyBuffer,this.jointBuffer,this.infoBuffer,l,a,this.colorBuffer,this.counterBuffer])),args:i(this.layouts.args,[r,this.counterBuffer,this.colorBuffer,this.argsBuffer])}}uploadBodies(e=0,t=this.topology.bodyCount-e){let i=this.topology,r=new Float32Array(Math.max(t,1)*24);for(let o=0;o<t;o++){let n=e+o,a=o*24;r.set(i.pose.subarray(n*4,n*4+3),a),r[a+3]=i.props[n*4],r.set(i.initial.subarray(n*4,n*4+4),a+4),r.set(i.inertial.subarray(n*4,n*4+4),a+8),r.set(i.velocity.subarray(n*4,n*4+4),a+12),r.set(i.prevVelocity.subarray(n*4,n*4+4),a+16),r.set(i.shape.subarray(n*4,n*4+4),a+20)}this.device.queue.writeBuffer(this.bodyBuffer,e*24*4,r),this.staticsDirty=!0}uploadJoints(e,t){if(t===0)return;let i=this.topology,r=new Float32Array(t*36);for(let o=0;o<t;o++){let n=(e+o)*O,a=o*36;for(let l=0;l<3;l++)r[a+0+l]=i.data[n+se+l],r[a+4+l]=i.data[n+te+l],r[a+8+l]=Ro(i.data[n+Q+l]),r[a+12+l]=Ro(i.data[n+_e+l]),r[a+16+l]=Ro(i.data[n+Ae+l]),r[a+20+l]=Ro(i.data[n+Pt+l]),r[a+24+l]=i.data[n+fe+l];r[a+28]=i.data[n+N],r[a+28+1]=i.data[n+N+1],r[a+28+2]=i.data[n+Y],r[a+28+3]=i.data[n+Y+1],r[a+32]=i.data[n+re],r[a+32+1]=i.data[n+be]}this.device.queue.writeBuffer(this.jointBuffer,e*36*4,r),this.device.queue.writeBuffer(this.infoBuffer,e*16,i.info,e*j,t*j)}uploadStatics(){let e=this.topology,t=this.bodyCount,i=Float64Array.from({length:t},(f,d)=>e.props[d*4+1]).sort(),r=t>0?i[t>>1]:1,o=0;for(let f=0;f<t;f++)i[f]<=qf*r&&(o=Math.max(o,i[f]));let n=1/0;for(let f=0;f<t;f++)i[f]>o&&(n=Math.min(n,i[f]));let a=n===1/0?o*1.5:(o+n)/2;this.maxSmallRadius=a,this.cellSize=Math.max(2*o*(1+1e-4),.001);let l=[];for(let f=0;f<t;f++)e.props[f*4+1]>a&&l.push(f);let c=[];for(let f=0;f<e.jointCount;f++){let d=e.info[f*j+1],p=e.info[f*j+2];d>=0&&c.push([Math.max(d,p),Math.min(d,p),f])}for(let f of e.ignoredPairs()){let d=Math.floor(f/2097152);c.push([d,f-d*2097152,4294967295])}c.sort((f,d)=>f[0]-d[0]||f[1]-d[1]),this.largeCount=l.length,this.noCollideCount=c.length;let u=new Uint32Array(Math.max(l.length+3*c.length,4));u.set(l,0),c.forEach((f,d)=>u.set(f,l.length+3*d)),this.staticBuffer.size<u.byteLength&&(this.staticBuffer.destroy(),this.staticBuffer=this.device.createBuffer({label:"statics",size:u.byteLength,usage:yt()}),this.rebuildBindings()),this.device.queue.writeBuffer(this.staticBuffer,0,u),this.staticsDirty=!1}seedContactsFrom(e){let t=e.contactCount;if(t>this.contactCapacity)throw new Error("seedContactsFrom: too many contacts");let i=new ArrayBuffer(Math.max(t,1)*20*4),r=new Uint32Array(i),o=new Float32Array(i);for(let l=0;l<t;l++){let c=e.jointCount+l,u=c*O,f=l*20;r[f]=e.info[c*j+1],r[f+1]=e.info[c*j+2],r[f+2]=e.info[c*j+3],r[f+3]=e.data[u+Wi]?1:0,o.set([e.data[u+se],e.data[u+se+1],e.data[u+te],e.data[u+te+1]],f+4),o.set([e.data[u+N],e.data[u+N+1],e.data[u+Y],e.data[u+Y+1]],f+8),o.set([e.data[u+fe],e.data[u+fe+1],e.data[u+be],e.data[u+Ue]],f+12),o[f+16]=e.data[u+re]}this.device.queue.writeBuffer(this.contactBuffers[1-this.parity],0,i);let n=new Uint32Array(16);n[1]=t,this.device.queue.writeBuffer(this.counterBuffer,0,n);let a=Uint32Array.from({length:this.bodyCount},(l,c)=>(e.coloring.colors[c]??-1)<0?255:e.coloring.colors[c]);this.device.queue.writeBuffer(this.colorBuffer,0,a)}addBody(e,t,i,r,o){if(this.bodyCount>=this.bodyCapacity)return-1;let n=this.topology.addBody(e,t,i,r,o);return this.bodyCount=this.topology.bodyCount,this.uploadBodies(n,1),this.device.queue.writeBuffer(this.colorBuffer,n*4,new Uint32Array([255])),this.adjScan.destroy(),this.adjScan=new tt(this.device,this.adjBuffer,0,this.bodyCount+1),n}appendJoint(e,t,i,r,o,n=1/0){let a=this.topology;if(a.contactCount>0)throw new Error("appendJoint: the CPU mirror must not hold contacts");let l=a.addJoint(e,t,i,r,o,n).slot;return l>=this.jointCapacity&&this.allocateJoints(Math.max(l+1,this.jointCapacity*2)),this.jointCount=l+1,this.uploadJoints(l,1),e>=0&&(this.staticsDirty=!0),l}setWorldAnchor(e,t,i){this.device.queue.writeBuffer(this.jointBuffer,(e*36+28)*4,new Float32Array([t,i]))}disableConstraint(e){this.device.queue.writeBuffer(this.jointBuffer,(e*36+0)*4,new Float32Array(12)),this.topology.data.fill(0,e*O+Q,e*O+Q+3)}profileNextStep(e){this.timing&&!this.timingBusy&&(this.timingCallback=e)}writeParams(e,t){let i=this.params,r=this.bodyCapacity,o=new ArrayBuffer(128),n=new Float32Array(o),a=new Uint32Array(o);n[0]=i.dt,n[1]=i.gravity,n[2]=i.beta,n[3]=i.gamma,n[4]=e,n[5]=i.vbdStiffness,a[6]=(i.vbd?1:0)|(i.stiffnessRescale?2:0)|(t?4:0)|(i.matchNearest?8:0),a[7]=this.bodyCount,a[8]=this.jointCount,a[9]=this.colorCap,n[10]=this.cellSize,a[11]=this.tableSize-1,n[12]=this.maxSmallRadius,a[13]=this.largeCount,a[14]=this.noCollideCount,a[15]=this.pairCapacity,a[16]=this.contactCapacity,a[17]=this.hashSize-1,a[18]=r+1,a[19]=2*r+1,a[20]=this.tableSize+1,a[21]=2*this.tableSize+1,a[22]=2*this.tableSize+1+r,a[23]=r,a[24]=this.colorHistOffset,a[25]=2*r,a[26]=this.colorGroups,a[27]=2*r+65,a[28]=this.colorRounds,this.device.queue.writeBuffer(this.paramsBuffer,0,o)}writePassConstants(e,t){let i=this.colorCap+1,r=e*i;(r>this.passEntries||!this.passGroup)&&(this.passBuffer?.destroy(),this.passBuffer=this.device.createBuffer({label:"pass constants",size:r*256,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.passEntries=r,this.passGroup=this.device.createBindGroup({layout:this.layouts.pass,entries:[{binding:0,resource:{buffer:this.passBuffer,size:16}}]}));let o=new ArrayBuffer(r*256),n=new Uint32Array(o),a=new Float32Array(o);for(let l=0;l<e;l++)for(let c=0;c<=this.colorCap;c++){let u=(l*i+c)*256/4;n[u]=c,a[u+1]=t(l)}this.device.queue.writeBuffer(this.passBuffer,0,o)}step(){this.staticsDirty&&this.uploadStatics();let e=this.params,t=e.postStabilize&&!e.vbd,i=e.vbd?0:e.alpha,r=e.iterations+(t?1:0);this.writeParams(i,t),this.writePassConstants(r,x=>t?x<e.iterations?1:0:i);let o=this.parity,n=this.bodyCapacity,a=this.bodyCount,l=this.jointCount,c=this.device.createCommandEncoder({label:"avbd2d step"});c.clearBuffer(this.gridBuffer,0,(2*this.tableSize+1)*4),c.clearBuffer(this.tableBuffer),c.clearBuffer(this.adjBuffer,0,(2*n+1)*4);let u=this.timingCallback!==null&&this.timing!==null,f,d=0,p=u||this.splitPasses,m=()=>{f&&!p||(f?.end(),f=c.beginComputePass({label:p?Se[d]:"avbd2d step",timestampWrites:u?{querySet:this.timing.querySet,beginningOfPassWriteIndex:2*d,endOfPassWriteIndex:2*d+1}:void 0}),d++)},h=this.groups,g=(x,w,B)=>{B<=0||(f.setPipeline(this.pipes[x]),f.setBindGroup(0,w),f.dispatchWorkgroups(B))},b=(x,w,B)=>{f.setPipeline(this.pipes[x]),f.setBindGroup(0,w),f.dispatchWorkgroupsIndirect(this.argsBuffer,B*4)};m(),g("beginFrame",h.broad,1),g("argsPrev",h.args,1),b("hashInsert",h.contacts[o],6),g("gridCount",h.broad,bt(a)),this.gridScan.encode(f),g("gridScatter",h.broad,bt(a)),g("findPairs",h.broad,bt(a)),g("argsPairs",h.args,1),b("narrowphase",h.contacts[o],0),g("argsContacts",h.args,1),m(),g("degreeJoints",h.topo[o],bt(l)),b("degreeContacts",h.topo[o],3),this.adjScan.encode(f),g("fillJoints",h.topo[o],bt(l)),b("fillContacts",h.topo[o],3),g("sortAdjacency",h.topo[o],bt(a)),m(),g("colorCompact",h.topo[o],bt(a)),g("colorMark",h.topo[o],bt(a));for(let x=0;x<this.colorRounds;x++)g(x%2===0?"colorRoundAB":"colorRoundBA",h.topo[o],bt(a));g("colorCount",h.topo[o],this.colorGroups),this.colorHistScan.encode(f),g("colorStarts",h.topo[o],1),g("argsColors",h.args,1),g("colorScatter",h.topo[o],this.colorGroups),m();let y=this.colorCap+1,A=x=>f.setBindGroup(1,this.passGroup,[x*256]);f.setBindGroup(0,h.solve[o]),A(0),l>0&&(f.setPipeline(this.pipes.warmStartJoints),f.dispatchWorkgroups(bt(l))),f.setPipeline(this.pipes.warmStartBodies),f.dispatchWorkgroups(bt(a));for(let x=0;x<r;x++){let w=this.primalMode==="scan";f.setPipeline(w?this.pipes.primalScan:this.pipes.primal);for(let B=0;B<this.colorCap;B++)A(x*y+B),w?f.dispatchWorkgroups(bt(a)):f.dispatchWorkgroupsIndirect(this.argsBuffer,(12+3*B)*4);x<e.iterations&&(A(x*y+this.colorCap),f.setPipeline(this.pipes.dual),f.dispatchWorkgroupsIndirect(this.argsBuffer,36)),x===e.iterations-1&&(f.setPipeline(this.pipes.updateVelocities),f.dispatchWorkgroups(bt(a)))}t&&(f.setPipeline(this.pipes.refreshStick),f.dispatchWorkgroupsIndirect(this.argsBuffer,12)),f.end();let v=2*Se.length;if(u){let{querySet:x,resolve:w,read:B}=this.timing;c.resolveQuerySet(x,0,v,w,0),c.copyBufferToBuffer(w,0,B,0,v*8)}if(this.device.queue.submit([c.finish()]),this.parity=1-o,u){let x=this.timingCallback;this.timingCallback=null,this.timingBusy=!0;let w=this.timing.read;w.mapAsync(GPUMapMode.READ).then(()=>{let B=new BigUint64Array(w.getMappedRange()).slice();if(w.unmap(),this.timingBusy=!1,this.destroyed)return this.releaseTiming();let L=(I,E)=>Number(B[E]-B[I])/1e6,M={total:L(0,v-1)};Se.forEach((I,E)=>M[I]=L(2*E,2*E+1)),x(M)},()=>{this.timingBusy=!1,this.destroyed&&this.releaseTiming()})}}async readBodies(){return new Float32Array(await this.read(this.bodyBuffer,this.bodyCount*24*4))}async readJoints(){return new Float32Array(await this.read(this.jointBuffer,this.jointCount*36*4))}async readCounters(){let e=new Uint32Array(await this.read(this.counterBuffer,64));return{pairs:e[0],contacts:e[1],overflow:e[3],clashes:e[4],colors:e[5]}}async readContacts(){let{contacts:e}=await this.readCounters(),t=Math.min(e,this.contactCapacity);return this.read(this.contactBuffers[1-this.parity],t*20*4)}async readPairs(){let{pairs:e}=await this.readCounters();return new Uint32Array(await this.read(this.pairBuffer,Math.min(e,this.pairCapacity)*8))}async readColors(){return new Uint32Array(await this.read(this.colorBuffer,this.bodyCount*4))}async readAdjacency(){let e=new Uint32Array(await this.read(this.adjBuffer,this.adjBuffer.size)),t=e.slice(0,this.bodyCount+1),i=2*this.bodyCapacity+1;return{start:t,list:e.slice(i,i+t[this.bodyCount])}}adapt(e){let t=e.colors;e.clashes>0||t>=this.colorCap-1?(this.colorCap=Math.min(64,Math.max(t+4,this.colorCap+4)),this.shrinkVotes=0):t+2<this.colorCap?++this.shrinkVotes>=3&&(this.colorCap=Math.min(64,Math.max(4,t+2)),this.shrinkVotes=0):this.shrinkVotes=0;let i=(e.overflow&2)!==0||e.contacts>.8*this.contactCapacity,r=(e.overflow&1)!==0||e.pairs>.8*this.pairCapacity,o=this.contactCapacity*(i?2:1),n=this.pairCapacity*(r?2:1);(i||r)&&this.capacityCanGrow(o,n)&&this.allocateContacts(o,n)}capacityCanGrow(e,t){let i=this.device.limits.maxStorageBufferBindingSize,r=Math.min(Math.floor(i/80),Math.floor(i/16));return Math.min(e,r)>this.contactCapacity||Math.min(t,Math.floor(i/8))>this.pairCapacity}async readStats(e){let[t,i]=await Promise.all([e??this.readBodies(),this.readJoints()]),r=0;for(let c=0;c<this.bodyCount;c++){let u=c*24,f=t[u+22],d=t[u+12],p=t[u+13],m=t[u+14];f>0&&(r+=.5*f*(d*d+p*p)+.5*t[u+23]*m*m)}let o=0,n=0,a=this.topology.info,l=(c,u,f)=>{let d=c*24,p=Math.cos(t[d+2]),m=Math.sin(t[d+2]);return[p*u-m*f+t[d],m*u+p*f+t[d+1]]};for(let c=0;c<this.jointCount;c++){if(a[c*j]!==Bi)continue;let u=c*36;if(i[u+8]===0&&i[u+8+1]===0&&i[u+8+2]===0)continue;n++;let f=a[c*j+1],d=a[c*j+2],p=f>=0?l(f,i[u+28],i[u+28+1]):[i[u+28],i[u+28+1]],m=l(d,i[u+28+2],i[u+28+3]);for(let h=0;h<2;h++)i[u+8+h]>=1e30&&(o=Math.max(o,Math.abs(p[h]-m[h])))}return{kineticEnergy:r,maxJointError:o,joints:n}}async read(e,t){if(t===0)return new ArrayBuffer(0);let i=this.device.createBuffer({size:t,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST}),r=this.device.createCommandEncoder();r.copyBufferToBuffer(e,0,i,0,t),this.device.queue.submit([r.finish()]),await i.mapAsync(GPUMapMode.READ);let o=i.getMappedRange().slice(0);return i.unmap(),i.destroy(),o}releaseTiming(){this.timing?.resolve.destroy(),this.timing?.read.destroy(),this.timing?.querySet.destroy()}destroy(){this.ownsBodyBuffer&&this.bodyBuffer.destroy();let e=[this.jointBuffer,this.infoBuffer,...this.contactBuffers,this.pairBuffer,this.tableBuffer,this.gridBuffer,this.staticBuffer,this.counterBuffer,this.argsBuffer,this.adjBuffer,this.colorBuffer,this.paramsBuffer,this.passBuffer];for(let t of e)t?.destroy();this.destroyed=!0,this.timingBusy||this.releaseTiming(),this.gridScan.destroy(),this.colorHistScan.destroy(),this.adjScan?.destroy()}};var Vf=`${Ut}
4449
4661
  struct Config { count:u32,joints:u32,capacity:u32,list:u32,threshold:f32,dt:f32,pad0:u32,pad1:u32 }
4450
4662
  struct Velocity { incoming:vec4f, incomingAngular:vec4f, linear:vec4f, angular:vec4f }
4451
4663
  struct Bounce { impulse:f32,delta:f32,reboundSpeed:f32,inverseMass:f32,rA:vec4f,rB:vec4f }
@@ -4491,9 +4703,9 @@ fn pointVelocity(i:u32,r:vec2f,incoming:bool)->vec2f{let v=select(velocities[i].
4491
4703
  velocities[i].linear+=vec4f(dv,0.);
4492
4704
  }
4493
4705
  @compute @workgroup_size(64) fn writeBack(@builtin(global_invocation_id) id:vec3u){let i=id.x;if(i>=cfg.count||bodies[i].shape.z<=0.){return;}bodies[i].vel=velocities[i].linear;}
4494
- `;var po=class extends yr{constructor(e){super(e,{code:Ju,dimension:2})}};function Gl(s){for(let e of["warmStartJoints","warmStartBodies","primal","primalScan","dual","refreshStick","updateVelocities"]){let t=`fn ${e}(@builtin(global_invocation_id) gid: vec3u) {`;if(s.split(t).length!==2)throw Error(`Pinned 2D ${e} signature changed; review the step guard`);s=s.replace(t,`${t}
4495
- if (counters[C_OVERFLOW] != 0u || counters[C_CLASHES] != 0u) { return; }`)}return s}function Nl(s){let e="if (col == NO_COLOR) { col = params.colorCap - 1u; }";if(s.split(e).length!==2)throw Error("Pinned 2D color-count layout changed; review the capacity guard");return s.replace(e,`${e}
4496
- if (col >= params.colorCap) { atomicAdd(&counters[C_CLASHES], 1u); }`)}var Ul=`// Sleeping is scheduling metadata in velocity.w; physical mass and inertia stay intact.
4706
+ `;var To=class extends Ar{constructor(e){super(e,{code:Vf,dimension:2})}};function Ic(s){for(let e of["warmStartJoints","warmStartBodies","primal","primalScan","dual","refreshStick","updateVelocities"]){let t=`fn ${e}(@builtin(global_invocation_id) gid: vec3u) {`;if(s.split(t).length!==2)throw Error(`Pinned 2D ${e} signature changed; review the step guard`);s=s.replace(t,`${t}
4707
+ if (counters[C_OVERFLOW] != 0u || counters[C_CLASHES] != 0u) { return; }`)}return s}function La(s){let e="if (col == NO_COLOR) { col = params.colorCap - 1u; }";if(s.split(e).length!==2)throw Error("Pinned 2D color-count layout changed; review the capacity guard");return s.replace(e,`${e}
4708
+ if (col >= params.colorCap) { atomicAdd(&counters[C_CLASHES], 1u); }`)}var Rc=`// Sleeping is scheduling metadata in velocity.w; physical mass and inertia stay intact.
4497
4709
  struct Body {pose:vec4f,initial:vec4f,inertial:vec4f,vel:vec4f,prev:vec4f,shape:vec4f}
4498
4710
  struct Joint {pen:vec4f,lam:vec4f,stiff:vec4f,fmin:vec4f,fmax:vec4f,frac:vec4f,c0:vec4f,anchors:vec4f,param:vec4f}
4499
4711
  struct Contact {ids:vec4u,pl:vec4f,anchors:vec4f,geo:vec4f,misc:vec4f}
@@ -4564,10 +4776,10 @@ fn rotate(angle:f32,p:vec2f)->vec2f{let c=cos(angle);let s=sin(angle);return vec
4564
4776
  }
4565
4777
  if(asleep(i)){atomicAdd(&globals[1],1u);}
4566
4778
  }
4567
- `;function go(s={}){if(s!==!0&&(typeof s!="object"||s===null))throw Error("sleeping must be a boolean or options object");let e=s.speedThreshold??.03,t=s.timeThreshold??.5;if(![e,t].every(i=>Number.isFinite(i)&&i>0))throw Error("Sleep thresholds must be positive and finite");return{speedThreshold:e,timeThreshold:t}}function ql(s){for(let e of["warmStartBodies","updateVelocities"])s=s.replace(`fn ${e}(@builtin(global_invocation_id) gid: vec3u) {`,`fn ${e}(@builtin(global_invocation_id) gid: vec3u) {
4779
+ `;function Do(s={}){if(s!==!0&&(typeof s!="object"||s===null))throw Error("sleeping must be a boolean or options object");let e=s.speedThreshold??.03,t=s.timeThreshold??.5;if(![e,t].every(i=>Number.isFinite(i)&&i>0))throw Error("Sleep thresholds must be positive and finite");return{speedThreshold:e,timeThreshold:t}}function Oc(s){for(let e of["warmStartBodies","updateVelocities"])s=s.replace(`fn ${e}(@builtin(global_invocation_id) gid: vec3u) {`,`fn ${e}(@builtin(global_invocation_id) gid: vec3u) {
4568
4780
  if(gid.x<params.bodyCount && bodies[gid.x].vel.w!=0.){return;}`);return s.replace("fn solveBody(i: u32) {",`fn solveBody(i: u32) {
4569
- if(bodies[i].vel.w!=0.){return;}`)}function Vl(s){return s.replace("return i >= 0 && bodies[i].shape.z > 0.0;","return i >= 0 && bodies[i].shape.z > 0.0 && bodies[i].vel.w==0.;")}var mo=class{constructor(e,t){this.gpu=e,this.device=e.device,this.options=go(t);let i=this.device,r=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC;this.state=i.createBuffer({size:e.bodyCapacity*16,usage:r}),this.globals=i.createBuffer({size:8,usage:r}),this.params=i.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let o=i.createShaderModule({code:Ul});this.layout=i.createBindGroupLayout({entries:["storage","storage","read-only-storage","read-only-storage","read-only-storage","read-only-storage","storage","uniform"].map((l,c)=>({binding:c,visibility:GPUShaderStage.COMPUTE,buffer:{type:l}}))});let n=i.createPipelineLayout({bindGroupLayouts:[this.layout]});this.pipes=Object.fromEntries(["clear","before","contactsWake","jointsWake","decide","applyWake","rest"].map(l=>[l,i.createComputePipeline({layout:n,compute:{module:o,entryPoint:l}})]));let a=new Uint32Array(e.bodyCapacity*4);for(let l=0;l<e.bodyCount;l++)a[l*4+1]=e.sleepEligible?.get(l)===!1?0:1;i.queue.writeBuffer(this.state,0,a),this.wakeRequested=!1}register(e,t=!0){let i=le(this.gpu);for(let r=0;r<4;r++)i.uint(this.state,e*4+r,r===1?Number(t):0);this.wakeRequested=!0}group(e){let t=this.gpu,i=[t.bodyBuffer,this.state,t.infoBuffer,t.jointBuffer,t.contactBuffers[e],t.counterBuffer,this.globals,this.params],r=this.groups?.find(o=>o.buffers.every((n,a)=>n===i[a]));return r||(r={buffers:i,group:this.device.createBindGroup({layout:this.layout,entries:i.map((o,n)=>({binding:n,resource:{buffer:o}}))})},this.groups=[...(this.groups??[]).slice(-1),r]),r.group}dispatch(e,t,i){e.setBindGroup(0,this.group(t));for(let[r,o]of i)o&&(e.setPipeline(this.pipes[r]),e.dispatchWorkgroups(Math.ceil(o/64)))}run(e,t){let i=t??this.device.createCommandEncoder(),r=i.beginComputePass();this.dispatch(r,1-this.gpu.parity,e),r.end(),t||this.device.queue.submit([i.finish()])}before(e){this.gpu.flushPropertyEdits(e);let t=this.gpu,i=new ArrayBuffer(32),r=new Uint32Array(i),o=new Float32Array(i);r.set([t.bodyCount,t.jointCount,t.contactCapacity,Number(this.wakeRequested)]),o.set([this.options.speedThreshold,this.options.timeThreshold,t.params.dt,t.params.gravity],4),this.device.queue.writeBuffer(this.params,0,i),this.wakeRequested=!1,this.run([["clear",1],["before",t.bodyCount]],e)}encodeWake(e,t){let i=this.gpu;this.dispatch(e,t,[["contactsWake",i.contactCapacity],["jointsWake",i.jointCount],["decide",i.bodyCount],["applyWake",i.bodyCount]])}after(e){this.run([["rest",this.gpu.bodyCount]],e)}async readStats(){let e=new Uint32Array(await this.gpu.read(this.globals,8));return{sleeping:e[1],wakeRequested:this.wakeRequested||!!e[0]}}destroy(){this.gpu.propertyEdits?.forget(this.state),this.state.destroy(),this.globals.destroy(),this.params.destroy()}};var bt=s=>Math.ceil(s/64);function Wl(){this.staticsDirty&&this.uploadStatics();let s=this.params,e=s.postStabilize&&!s.vbd,t=s.vbd?0:s.alpha,i=s.iterations+(e?1:0);this.writeParams(t,e),this.writePassConstants(i,y=>e?y<s.iterations?1:0:t);let r=this.parity,o=this.bodyCapacity,n=this.bodyCount,a=this.jointCount,l=this.device.createCommandEncoder({label:"avbd2d step"});this.encodeStepPrelude?.(l),l.clearBuffer(this.gridBuffer,0,(2*this.tableSize+1)*4),l.clearBuffer(this.tableBuffer),l.clearBuffer(this.adjBuffer,0,(2*o+1)*4);let c=this.timingCallback!==null&&this.timing!==null,u,f=0,d=c||this.splitPasses,p=()=>{u&&!d||(u?.end(),u=l.beginComputePass({label:d?Se[f]:"avbd2d step",timestampWrites:c?{querySet:this.timing.querySet,beginningOfPassWriteIndex:2*f,endOfPassWriteIndex:2*f+1}:void 0}),f++)},g=this.groups,h=(y,A,x)=>{x<=0||(u.setPipeline(this.pipes[y]),u.setBindGroup(0,A),u.dispatchWorkgroups(x))},m=(y,A,x)=>{u.setPipeline(this.pipes[y]),u.setBindGroup(0,A),u.dispatchWorkgroupsIndirect(this.argsBuffer,x*4)};p(),h("beginFrame",g.broad,1),h("argsPrev",g.args,1),m("hashInsert",g.contacts[r],6),h("gridCount",g.broad,bt(n)),this.gridScan.encode(u),h("gridScatter",g.broad,bt(n)),h("findPairs",g.broad,bt(n)),h("argsPairs",g.args,1),m("narrowphase",g.contacts[r],0),h("argsContacts",g.args,1),this.sleeping?.encodeWake(u,r),p(),h("degreeJoints",g.topo[r],bt(a)),m("degreeContacts",g.topo[r],3),this.adjScan.encode(u),h("fillJoints",g.topo[r],bt(a)),m("fillContacts",g.topo[r],3),h("sortAdjacency",g.topo[r],bt(n)),p(),h("colorCompact",g.topo[r],bt(n)),h("colorMark",g.topo[r],bt(n));for(let y=0;y<this.colorRounds;y++)h(y%2===0?"colorRoundAB":"colorRoundBA",g.topo[r],bt(n));h("colorCount",g.topo[r],this.colorGroups),this.colorHistScan.encode(u),h("colorStarts",g.topo[r],1),h("argsColors",g.args,1),h("colorScatter",g.topo[r],this.colorGroups),p();let b=this.colorCap+1,v=y=>u.setBindGroup(1,this.passGroup,[y*256]);u.setBindGroup(0,g.solve[r]),v(0),a>0&&(u.setPipeline(this.pipes.warmStartJoints),u.dispatchWorkgroups(bt(a))),u.setPipeline(this.pipes.warmStartBodies),u.dispatchWorkgroups(bt(n));for(let y=0;y<i;y++){let A=this.primalMode==="scan";u.setPipeline(A?this.pipes.primalScan:this.pipes.primal);for(let x=0;x<this.colorCap;x++)v(y*b+x),A?u.dispatchWorkgroups(bt(n)):u.dispatchWorkgroupsIndirect(this.argsBuffer,(12+3*x)*4);y<s.iterations&&(v(y*b+this.colorCap),u.setPipeline(this.pipes.dual),u.dispatchWorkgroupsIndirect(this.argsBuffer,36)),y===s.iterations-1&&(u.setPipeline(this.pipes.updateVelocities),u.dispatchWorkgroups(bt(n)))}e&&(u.setPipeline(this.pipes.refreshStick),u.dispatchWorkgroupsIndirect(this.argsBuffer,12)),u.end();let w=2*Se.length;if(c){let{querySet:y,resolve:A,read:x}=this.timing;l.resolveQuerySet(y,0,w,A,0),l.copyBufferToBuffer(A,0,x,0,w*8)}if(this.parity=1-r,this.encodeStepPostlude?.(l),this.device.queue.submit([l.finish()]),c){let y=this.timingCallback;this.timingCallback=null,this.timingBusy=!0;let A=this.timing.read;A.mapAsync(GPUMapMode.READ).then(()=>{let x=new BigUint64Array(A.getMappedRange()).slice();if(A.unmap(),this.timingBusy=!1,this.destroyed)return this.releaseTiming();let B=(L,M)=>Number(x[M]-x[L])/1e6,E={total:B(0,w-1)};Se.forEach((L,M)=>E[L]=B(2*M,2*M+1)),y(E)},()=>{this.timingBusy=!1,this.destroyed&&this.releaseTiming()})}}var bo=5;function Ci({minAngle:s=-Math.PI,maxAngle:e=Math.PI}={}){if(!Number.isFinite(s)||!Number.isFinite(e)||s>e)throw Error("Angle limits require finite minAngle <= maxAngle, in radians");return{minAngle:s,maxAngle:e}}function os(s,e,t){let i=e*O;s.info[e*j]=bo,s.data.set([1/0,1/0,0],i+Q),s.data.set([-1/0,0,0],i+Le),s.data.set([0,1/0,0],i+xe),s.data[i+ge]=t.minAngle,s.data[i+Fe]=t.maxAngle}function Hl(s){let e=s.topology;for(let t=0;t<e.jointCount;t++)e.info[t*j]===bo&&s.device.queue.writeBuffer(s.jointBuffer,(t*36+32)*4,new Float32Array([e.data[t*O+re],e.data[t*O+ge],e.data[t*O+Fe],0]))}var ss=(s,e,t)=>{if(s.split(e).length!==2)throw Error("Pinned 2D angular layout changed");return s.replace(e,t)};function Jl(s){return s=ss(s,"case T_JOINT: { return 3u; }",`case T_JOINT: { return 3u; }
4570
- case 5: { return 2u; }`),s=ss(s,"fn jointRowsC(j: u32, alpha: f32) -> vec3f {",`
4781
+ if(bodies[i].vel.w!=0.){return;}`)}function Tc(s){return s.replace("return i >= 0 && bodies[i].shape.z > 0.0;","return i >= 0 && bodies[i].shape.z > 0.0 && bodies[i].vel.w==0.;")}var jo=class{constructor(e,t){this.gpu=e,this.device=e.device,this.options=Do(t);let i=this.device,r=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC;this.state=i.createBuffer({size:e.bodyCapacity*16,usage:r}),this.globals=i.createBuffer({size:8,usage:r}),this.params=i.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST});let o=i.createShaderModule({code:Rc});this.layout=i.createBindGroupLayout({entries:["storage","storage","read-only-storage","read-only-storage","read-only-storage","read-only-storage","storage","uniform"].map((l,c)=>({binding:c,visibility:GPUShaderStage.COMPUTE,buffer:{type:l}}))});let n=i.createPipelineLayout({bindGroupLayouts:[this.layout]});this.pipes=Object.fromEntries(["clear","before","contactsWake","jointsWake","decide","applyWake","rest"].map(l=>[l,i.createComputePipeline({layout:n,compute:{module:o,entryPoint:l}})]));let a=new Uint32Array(e.bodyCapacity*4);for(let l=0;l<e.bodyCount;l++)a[l*4+1]=e.sleepEligible?.get(l)===!1?0:1;i.queue.writeBuffer(this.state,0,a),this.wakeRequested=!1}register(e,t=!0){let i=le(this.gpu);for(let r=0;r<4;r++)i.uint(this.state,e*4+r,r===1?Number(t):0);this.wakeRequested=!0}group(e){let t=this.gpu,i=[t.bodyBuffer,this.state,t.infoBuffer,t.jointBuffer,t.contactBuffers[e],t.counterBuffer,this.globals,this.params],r=this.groups?.find(o=>o.buffers.every((n,a)=>n===i[a]));return r||(r={buffers:i,group:this.device.createBindGroup({layout:this.layout,entries:i.map((o,n)=>({binding:n,resource:{buffer:o}}))})},this.groups=[...(this.groups??[]).slice(-1),r]),r.group}dispatch(e,t,i){e.setBindGroup(0,this.group(t));for(let[r,o]of i)o&&(e.setPipeline(this.pipes[r]),e.dispatchWorkgroups(Math.ceil(o/64)))}run(e,t){let i=t??this.device.createCommandEncoder(),r=i.beginComputePass();this.dispatch(r,1-this.gpu.parity,e),r.end(),t||this.device.queue.submit([i.finish()])}before(e){this.gpu.flushPropertyEdits(e);let t=this.gpu,i=this.paramData??=hi(8),{u:r,f:o}=i;r[0]=t.bodyCount,r[1]=t.jointCount,r[2]=t.contactCapacity,r[3]=Number(this.wakeRequested),o[4]=this.options.speedThreshold,o[5]=this.options.timeThreshold,o[6]=t.params.dt,o[7]=t.params.gravity,Qt(this.device,this.params,i),this.wakeRequested=!1,this.run([["clear",1],["before",t.bodyCount]],e)}encodeWake(e,t){let i=this.gpu;this.dispatch(e,t,[["contactsWake",i.contactCapacity],["jointsWake",i.jointCount],["decide",i.bodyCount],["applyWake",i.bodyCount]])}after(e){this.run([["rest",this.gpu.bodyCount]],e)}async readStats(){let e=new Uint32Array(await this.gpu.read(this.globals,8));return{sleeping:e[1],wakeRequested:this.wakeRequested||!!e[0]}}destroy(){this.gpu.propertyEdits?.forget(this.state),this.state.destroy(),this.globals.destroy(),this.params.destroy()}};var vt=s=>Math.ceil(s/64);function jc(){this.staticsDirty&&this.uploadStatics();let s=this.params,e=s.postStabilize&&!s.vbd,t=s.vbd?0:s.alpha,i=s.iterations+(e?1:0);this.writeParams(t,e),this.writePassConstants(i,L=>e?L<s.iterations?1:0:t);let r=this.parity,o=this.bodyCapacity,n=this.bodyCount,a=this.jointCount,l=this.device.createCommandEncoder({label:"avbd2d step"});this.encodeStepPrelude?.(l),l.clearBuffer(this.gridBuffer,0,(2*this.tableSize+1)*4),l.clearBuffer(this.tableBuffer),l.clearBuffer(this.adjBuffer,0,(2*o+1)*4);let c=this.timingCallback!==null&&this.timing!==null,u,f,d=0,p=c||this.splitPasses,m=()=>{u&&!p||(u?.end(),u=l.beginComputePass({label:p?Se[d]:"avbd2d step",timestampWrites:c?{querySet:this.timing.querySet,beginningOfPassWriteIndex:2*d,endOfPassWriteIndex:2*d+1}:void 0}),f=void 0,d++)},h=this.groups,g=L=>{f!==L&&(u.setBindGroup(0,L),f=L)},b=(L,M,I)=>{I<=0||(u.setPipeline(this.pipes[L]),g(M),u.dispatchWorkgroups(I))},y=(L,M,I)=>{u.setPipeline(this.pipes[L]),g(M),u.dispatchWorkgroupsIndirect(this.argsBuffer,I*4)};m(),b("beginFrame",h.broad,1),b("argsPrev",h.args,1),y("hashInsert",h.contacts[r],6),b("gridCount",h.broad,vt(n)),this.gridScan.encode(u),f=void 0,b("gridScatter",h.broad,vt(n)),b("findPairs",h.broad,vt(n)),b("argsPairs",h.args,1),y("narrowphase",h.contacts[r],0),b("argsContacts",h.args,1),this.sleeping?.encodeWake(u,r),f=void 0,m(),b("degreeJoints",h.topo[r],vt(a)),y("degreeContacts",h.topo[r],3),this.adjScan.encode(u),f=void 0,b("fillJoints",h.topo[r],vt(a)),y("fillContacts",h.topo[r],3),b("sortAdjacency",h.topo[r],vt(n)),m(),b("colorCompact",h.topo[r],vt(n)),b("colorMark",h.topo[r],vt(n));for(let L=0;L<this.colorRounds;L++)b(L%2===0?"colorRoundAB":"colorRoundBA",h.topo[r],vt(n));b("colorCount",h.topo[r],this.colorGroups),this.colorHistScan.encode(u),f=void 0,b("colorStarts",h.topo[r],1),b("argsColors",h.args,1),b("colorScatter",h.topo[r],this.colorGroups),m();let A=this.colorCap+1,v=this.passOffsets??=[0],x=-1,w=L=>{L!==x&&(v[0]=L*256,u.setBindGroup(1,this.passGroup,v),x=L)};u.setBindGroup(0,h.solve[r]),w(0),a>0&&(u.setPipeline(this.pipes.warmStartJoints),u.dispatchWorkgroups(vt(a))),u.setPipeline(this.pipes.warmStartBodies),u.dispatchWorkgroups(vt(n));for(let L=0;L<i;L++){let M=this.primalMode==="scan";u.setPipeline(M?this.pipes.primalScan:this.pipes.primal);for(let I=0;I<this.colorCap;I++)w(L*A+I),M?u.dispatchWorkgroups(vt(n)):u.dispatchWorkgroupsIndirect(this.argsBuffer,(12+3*I)*4);L<s.iterations&&(w(L*A+this.colorCap),u.setPipeline(this.pipes.dual),u.dispatchWorkgroupsIndirect(this.argsBuffer,36)),L===s.iterations-1&&(u.setPipeline(this.pipes.updateVelocities),u.dispatchWorkgroups(vt(n)))}e&&(u.setPipeline(this.pipes.refreshStick),u.dispatchWorkgroupsIndirect(this.argsBuffer,12)),u.end();let B=2*Se.length;if(c){let{querySet:L,resolve:M,read:I}=this.timing;l.resolveQuerySet(L,0,B,M,0),l.copyBufferToBuffer(M,0,I,0,B*8)}if(this.parity=1-r,this.encodeStepPostlude?.(l),this.device.queue.submit([l.finish()]),c){let L=this.timingCallback;this.timingCallback=null,this.timingBusy=!0;let M=this.timing.read;M.mapAsync(GPUMapMode.READ).then(()=>{let I=new BigUint64Array(M.getMappedRange()).slice();if(M.unmap(),this.timingBusy=!1,this.destroyed)return this.releaseTiming();let E=(P,C)=>Number(I[C]-I[P])/1e6,k={total:E(0,B-1)};Se.forEach((P,C)=>k[P]=E(2*C,2*C+1)),L(k)},()=>{this.timingBusy=!1,this.destroyed&&this.releaseTiming()})}}var Go=5;function ki({minAngle:s=-Math.PI,maxAngle:e=Math.PI}={}){if(!Number.isFinite(s)||!Number.isFinite(e)||s>e)throw Error("Angle limits require finite minAngle <= maxAngle, in radians");return{minAngle:s,maxAngle:e}}function vs(s,e,t){let i=e*O;s.info[e*j]=Go,s.data.set([1/0,1/0,0],i+Q),s.data.set([-1/0,0,0],i+_e),s.data.set([0,1/0,0],i+Ae),s.data[i+be]=t.minAngle,s.data[i+Ue]=t.maxAngle}function Dc(s){let e=s.topology;for(let t=0;t<e.jointCount;t++)e.info[t*j]===Go&&s.device.queue.writeBuffer(s.jointBuffer,(t*36+32)*4,new Float32Array([e.data[t*O+re],e.data[t*O+be],e.data[t*O+Ue],0]))}var ys=(s,e,t)=>{if(s.split(e).length!==2)throw Error("Pinned 2D angular layout changed");return s.replace(e,t)};function Gc(s){return s=ys(s,"case T_JOINT: { return 3u; }",`case T_JOINT: { return 3u; }
4782
+ case 5: { return 2u; }`),s=ys(s,"fn jointRowsC(j: u32, alpha: f32) -> vec3f {",`
4571
4783
  fn limitAngle2D(k:Joint,a:i32,b:i32)->f32 {
4572
4784
  var angleA=0.;if(a>=0){angleA=bodies[a].pose.z;}
4573
4785
  return angleA-bodies[b].pose.z-k.param.x;
@@ -4577,10 +4789,10 @@ fn limitRows2D(k:Joint,a:i32,b:i32,alpha:f32)->vec3f {
4577
4789
  return vec3f(angle-k.param.y,angle-k.param.z,0.)-alpha*k.c0.xyz;
4578
4790
  }
4579
4791
  `+`
4580
- fn jointRowsC(j: u32, alpha: f32) -> vec3f {`),s=ss(s,` if (t == T_JOINT) {
4792
+ fn jointRowsC(j: u32, alpha: f32) -> vec3f {`),s=ys(s,` if (t == T_JOINT) {
4581
4793
  // Hard rows`,` if(t==5){return limitRows2D(k,a,b,alpha);}
4582
4794
  if (t == T_JOINT) {
4583
- // Hard rows`),s=ss(s," let C = jointRowsC(j, alpha);",` let C = jointRowsC(j, alpha);
4795
+ // Hard rows`),s=ys(s," let C = jointRowsC(j, alpha);",` let C = jointRowsC(j, alpha);
4584
4796
  if(t==5){
4585
4797
  // Unilateral rows only contribute while their force is active. Inside the
4586
4798
  // interval a hinge has no angular stiffness and remains free to rotate.
@@ -4588,8 +4800,8 @@ fn jointRowsC(j: u32, alpha: f32) -> vec3f {`),s=ss(s,` if (t == T_JOINT) {
4588
4800
  if(F.x!=0.){addRow(acc,vec3f(0.,0.,sg),vec3f(0.),C.x,k.pen.x,k.lam.x,k.stiff.x,k.fmin.x,k.fmax.x);}
4589
4801
  if(F.y!=0.){addRow(acc,vec3f(0.,0.,sg),vec3f(0.),C.y,k.pen.y,k.lam.y,k.stiff.y,k.fmin.y,k.fmax.y);}
4590
4802
  return;
4591
- }`),s=ss(s," if (t == T_JOINT) { k.c0 = vec4f(jointC(k, info[j].y, info[j].z), 0.0); }",` if (t == T_JOINT) { k.c0 = vec4f(jointC(k, info[j].y, info[j].z), 0.0); }
4592
- if(t==5){let angle=limitAngle2D(k,info[j].y,info[j].z);k.c0=vec4f(min(0.,angle-k.param.y),max(0.,angle-k.param.z),0.,0.);}`),s}var $l=`// Analytic circles and capsules, finite two-sided segments and solid half-space planes.
4803
+ }`),s=ys(s," if (t == T_JOINT) { k.c0 = vec4f(jointC(k, info[j].y, info[j].z), 0.0); }",` if (t == T_JOINT) { k.c0 = vec4f(jointC(k, info[j].y, info[j].z), 0.0); }
4804
+ if(t==5){let angle=limitAngle2D(k,info[j].y,info[j].z);k.c0=vec4f(min(0.,angle-k.param.y),max(0.,angle-k.param.z),0.,0.);}`),s}var Fc=`// Analytic circles and capsules, finite two-sided segments and solid half-space planes.
4593
4805
  // Kind 4 stores bounding radius, vertex-record offset and vertex count.
4594
4806
  @group(0) @binding(7) var<storage,read> geometry:array<vec4f>;
4595
4807
  struct Face2D { a:vec2f, b:vec2f, feature:u32 }
@@ -4742,7 +4954,7 @@ fn collideShapes2D(a:u32,b:u32)->Collision {
4742
4954
  }
4743
4955
  out.count=count;return out;
4744
4956
  }
4745
- `;var ra=new WeakMap,_r=(s,e,t=!1)=>{if(!Number.isFinite(s)||(t?s<0:s<=0))throw Error(`${e} must be ${t?"nonnegative":"positive"} and finite`);return s},yo=(s,e)=>{if(!s||s.length!==2||!Array.from(s).every(Number.isFinite))throw Error(`${e} requires two finite components`);return Array.from(s)},Zt=s=>ra.get(s);function vo(s){let e=Array.from(s??[]),t=typeof e[0]=="number"?e:e.flatMap(x=>yo(x,"Hull point"));if(t.length<6||t.length%2||!t.every(Number.isFinite))throw Error("A 2D hull requires finite xy pairs spanning an area");let i=[];for(let x=0;x<t.length;x+=2)i.push([t[x],t[x+1]]);i.sort((x,B)=>x[0]-B[0]||x[1]-B[1]);let r=i.filter((x,B)=>!B||x[0]!==i[B-1][0]||x[1]!==i[B-1][1]),o=(x,B,E)=>(B[0]-x[0])*(E[1]-x[1])-(B[1]-x[1])*(E[0]-x[0]),n=x=>{let B=[];for(let E of x){for(;B.length>1&&o(B.at(-2),B.at(-1),E)<=0;)B.pop();B.push(E)}return B.slice(0,-1)},a=[...n(r),...n([...r].reverse())];if(a.length<3||a.length>32)throw Error("A 2D hull needs 3\u201332 boundary vertices spanning an area");let l=a[0],c=a.map(x=>[x[0]-l[0],x[1]-l[1]]),u=0,f=0,d=0;for(let x=0;x<c.length;x++){let B=c[x],E=c[(x+1)%c.length],L=B[0]*E[1]-E[0]*B[1];u+=L,f+=(B[0]+E[0])*L,d+=(B[1]+E[1])*L}if(!(u>0)||!Number.isFinite(u))throw Error("Hull area must be positive and finite");f/=3*u,d/=3*u;let p=c.map(x=>[x[0]-f,x[1]-d]),g=0,h=0,m=0,b=0,v=[];for(let x=0;x<p.length;x++){let B=p[x],E=p[(x+1)%p.length],L=B[0]*E[1]-E[0]*B[1];g+=L*(B[0]*B[0]+B[0]*E[0]+E[0]*E[0]+B[1]*B[1]+B[1]*E[1]+E[1]*E[1])/12;let M=E[0]-B[0],z=E[1]-B[1],_=Math.hypot(M,z);v.push(B[0],B[1],z/_,-M/_),h=Math.max(h,Math.hypot(...B)),m=Math.max(m,Math.abs(B[0])),b=Math.max(b,Math.abs(B[1]))}let w=u/2,y=g/w;if(![w,y,h,m,b,...v].every(x=>Number.isFinite(Math.fround(x)))||Math.fround(w)<=0||Math.fround(y)<=0)throw Error("Hull geometry exceeds GPU floating-point range");let A=[4,h,0,p.length];return A.vertices=v,{geometry:A,size:[2*m,2*b],area:w,momentPerMass:y,radius:h}}function Ao(s){let e=_r(s,"radius");return{geometry:[1,e,0,0],size:[2*e,2*e],area:Math.PI*e*e,momentPerMass:e*e/2,radius:e}}function xo(s,e){let t=_r(s,"radius");if(_r(e,"length"),e<2*t)throw Error("Capsule length must be at least twice its radius");return Xl((e-2*t)/2,t)}function Xl(s,e){let t=2*s,i=2*e*t,r=Math.PI*e*e,o=i+r,n=i*(t*t+4*e*e)/12+r*(t*t/4+e*e/2+4*t*e/(3*Math.PI));return{geometry:[2,e,s,0],size:[t+2*e,Math.max(2*e,1e-6)],area:o,momentPerMass:o?n/o:0,radius:s+e}}function wo(s,e,t={}){let i=yo(s,"start"),r=yo(e,"end"),o=r[0]-i[0],n=r[1]-i[1],a=Math.hypot(o,n),l=_r(t.radius??0,"radius",!0);if(_r(a,"segment length"),t.position!==void 0||t.angle!==void 0)throw Error("Segment position and angle come from its endpoints");if(l===0&&(t.density??0)!==0)throw Error("A zero-thickness segment must be static; give it a radius for a dynamic capsule");return{...Xl(a/2,l),options:{...t,density:t.density??0,position:[(i[0]+r[0])/2,(i[1]+r[1])/2],angle:Math.atan2(n,o)}}}function Bo(s,e=0,t={}){let i=yo(s,"normal"),r=_r(Math.hypot(...i),"normal length");if(!Number.isFinite(e))throw Error("Plane offset must be finite");if((t.density??0)!==0)throw Error("An infinite plane must be static");if(t.position!==void 0||t.angle!==void 0)throw Error("Plane position and angle come from its normal and offset");let o=i[0]/r,n=i[1]/r;return{geometry:[3,0,0,0],size:[1,1],area:0,momentPerMass:0,radius:0,options:{...t,density:0,position:[o*e,n*e],angle:Math.atan2(-o,n)}}}function Er(s,e,t,i){let r=ra.get(s);r||ra.set(s,r=new Map),r.set(e,t.geometry);let o=t.area*i,n=e*4;s.shape[n+2]=o,s.shape[n+3]=o*t.momentPerMass,s.props[n+1]=t.radius,s.dynamic[e]=+(o>0)}var Yl=`struct Body {pose:vec4f,initial:vec4f,inertial:vec4f,velocity:vec4f,previous:vec4f,shape:vec4f}
4957
+ `;var _a=new WeakMap,Ir=(s,e,t=!1)=>{if(!Number.isFinite(s)||(t?s<0:s<=0))throw Error(`${e} must be ${t?"nonnegative":"positive"} and finite`);return s},Fo=(s,e)=>{if(!s||s.length!==2||!Array.from(s).every(Number.isFinite))throw Error(`${e} requires two finite components`);return Array.from(s)},ei=s=>_a.get(s);function Uo(s){let e=Array.from(s??[]),t=typeof e[0]=="number"?e:e.flatMap(w=>Fo(w,"Hull point"));if(t.length<6||t.length%2||!t.every(Number.isFinite))throw Error("A 2D hull requires finite xy pairs spanning an area");let i=[];for(let w=0;w<t.length;w+=2)i.push([t[w],t[w+1]]);i.sort((w,B)=>w[0]-B[0]||w[1]-B[1]);let r=i.filter((w,B)=>!B||w[0]!==i[B-1][0]||w[1]!==i[B-1][1]),o=(w,B,L)=>(B[0]-w[0])*(L[1]-w[1])-(B[1]-w[1])*(L[0]-w[0]),n=w=>{let B=[];for(let L of w){for(;B.length>1&&o(B.at(-2),B.at(-1),L)<=0;)B.pop();B.push(L)}return B.slice(0,-1)},a=[...n(r),...n([...r].reverse())];if(a.length<3||a.length>32)throw Error("A 2D hull needs 3\u201332 boundary vertices spanning an area");let l=a[0],c=a.map(w=>[w[0]-l[0],w[1]-l[1]]),u=0,f=0,d=0;for(let w=0;w<c.length;w++){let B=c[w],L=c[(w+1)%c.length],M=B[0]*L[1]-L[0]*B[1];u+=M,f+=(B[0]+L[0])*M,d+=(B[1]+L[1])*M}if(!(u>0)||!Number.isFinite(u))throw Error("Hull area must be positive and finite");f/=3*u,d/=3*u;let p=c.map(w=>[w[0]-f,w[1]-d]),m=0,h=0,g=0,b=0,y=[];for(let w=0;w<p.length;w++){let B=p[w],L=p[(w+1)%p.length],M=B[0]*L[1]-L[0]*B[1];m+=M*(B[0]*B[0]+B[0]*L[0]+L[0]*L[0]+B[1]*B[1]+B[1]*L[1]+L[1]*L[1])/12;let I=L[0]-B[0],E=L[1]-B[1],k=Math.hypot(I,E);y.push(B[0],B[1],E/k,-I/k),h=Math.max(h,Math.hypot(...B)),g=Math.max(g,Math.abs(B[0])),b=Math.max(b,Math.abs(B[1]))}let A=u/2,v=m/A;if(![A,v,h,g,b,...y].every(w=>Number.isFinite(Math.fround(w)))||Math.fround(A)<=0||Math.fround(v)<=0)throw Error("Hull geometry exceeds GPU floating-point range");let x=[4,h,0,p.length];return x.vertices=y,{geometry:x,size:[2*g,2*b],area:A,momentPerMass:v,radius:h}}function No(s){let e=Ir(s,"radius");return{geometry:[1,e,0,0],size:[2*e,2*e],area:Math.PI*e*e,momentPerMass:e*e/2,radius:e}}function qo(s,e){let t=Ir(s,"radius");if(Ir(e,"length"),e<2*t)throw Error("Capsule length must be at least twice its radius");return Uc((e-2*t)/2,t)}function Uc(s,e){let t=2*s,i=2*e*t,r=Math.PI*e*e,o=i+r,n=i*(t*t+4*e*e)/12+r*(t*t/4+e*e/2+4*t*e/(3*Math.PI));return{geometry:[2,e,s,0],size:[t+2*e,Math.max(2*e,1e-6)],area:o,momentPerMass:o?n/o:0,radius:s+e}}function Vo(s,e,t={}){let i=Fo(s,"start"),r=Fo(e,"end"),o=r[0]-i[0],n=r[1]-i[1],a=Math.hypot(o,n),l=Ir(t.radius??0,"radius",!0);if(Ir(a,"segment length"),t.position!==void 0||t.angle!==void 0)throw Error("Segment position and angle come from its endpoints");if(l===0&&(t.density??0)!==0)throw Error("A zero-thickness segment must be static; give it a radius for a dynamic capsule");return{...Uc(a/2,l),options:{...t,density:t.density??0,position:[(i[0]+r[0])/2,(i[1]+r[1])/2],angle:Math.atan2(n,o)}}}function Wo(s,e=0,t={}){let i=Fo(s,"normal"),r=Ir(Math.hypot(...i),"normal length");if(!Number.isFinite(e))throw Error("Plane offset must be finite");if((t.density??0)!==0)throw Error("An infinite plane must be static");if(t.position!==void 0||t.angle!==void 0)throw Error("Plane position and angle come from its normal and offset");let o=i[0]/r,n=i[1]/r;return{geometry:[3,0,0,0],size:[1,1],area:0,momentPerMass:0,radius:0,options:{...t,density:0,position:[o*e,n*e],angle:Math.atan2(-o,n)}}}function Rr(s,e,t,i){let r=_a.get(s);r||_a.set(s,r=new Map),r.set(e,t.geometry);let o=t.area*i,n=e*4;s.shape[n+2]=o,s.shape[n+3]=o*t.momentPerMass,s.props[n+1]=t.radius,s.dynamic[e]=+(o>0)}var Nc=`struct Body {pose:vec4f,initial:vec4f,inertial:vec4f,velocity:vec4f,previous:vec4f,shape:vec4f}
4746
4958
  struct Command { header:vec4u, value:vec4f, point:vec4f }
4747
4959
  @group(0) @binding(0) var<storage,read_write> bodies:array<Body>;
4748
4960
  @group(0) @binding(1) var<storage,read> commands:array<Command>;
@@ -4778,11 +4990,11 @@ fn edit(@builtin(global_invocation_id) id:vec3u) {
4778
4990
  bodies[index]=b;
4779
4991
  }
4780
4992
  \r
4781
- `;function Vt(s,e){let t=s&&typeof s.x=="number"?[s.x,s.y]:Array.isArray(s)||ArrayBuffer.isView(s)&&!(s instanceof DataView)?s:Array.from(s??[]);if(t.length!==2||!t.every(Number.isFinite))throw Error(`${e} requires two finite components`);return t}var ei=class{constructor(){this.count=0,this.capacity=0}reserve(e){if(e<=this.capacity)return;let t=Math.max(e,this.capacity*2,64),i=new ArrayBuffer(t*48),r=new Float32Array(i),o=new Uint32Array(i);this.u32&&o.set(this.u32.subarray(0,this.count*12)),this.words=r,this.u32=o,this.capacity=t}append(e,t,i,r,o=!1){this.reserve(this.count+1),Ql(this.words,this.u32,this.count++*12,e,t,i,r,o)}};function Ql(s,e,t,i,r,o,n,a){e[t]=i,e[t+1]=r,e[t+2]=Number(a),e[t+3]=0;for(let l=0;l<4;l++)s[t+4+l]=o[l]??0,s[t+8+l]=n?.[l]??0}var Mr=class{constructor(e,t=Yl,i=2){this.solver=e,this.shader=t,this.dimension=i,this.pending=new Map,this.queue=new ei,this.requested=0,this.linearOnly=!0,this.angularOnly=!0,this.hasTeleports=!1,this.motionOnly=!0,this.freeRanges=[]}slot(e,t){this.requested++,this.linearOnly&&=t===0,this.angularOnly&&=t===1,this.motionOnly&&=t===0||t===1,this.hasTeleports||=t===4;let i=this.pending.get(e);if(i&&(t===0||t===1)&&this.queue.u32[i.tail*12+1]===t)return i.tail;if(this.queue.reserve(this.queue.count+1),!this.next||this.next.length<this.queue.capacity){let o=new Int32Array(this.queue.capacity);this.next&&o.set(this.next),this.next=o}let r=this.queue.count++;return this.next[r]=-1,i?(this.next[i.tail]=r,i.tail=r,i.length++):(i=this.freeRanges.pop()??{},i.head=i.tail=r,i.length=1,this.pending.set(e,i)),r}enqueue(e,t,i,r,o=!1){let n=this.slot(e,t);Ql(this.queue.words,this.queue.u32,n*12,e,t,i,r,o)}enqueueValidated(e){for(let t=0;t<e.count;t++){let i=t*12,r=this.slot(e.u32[i],e.u32[i+1])*12;for(let o=0;o<12;o++)this.queue.u32[r+o]=e.u32[i+o]}}flush(e){if(!this.pending.size)return;let t=this.solver.device,i=this.pending.size;if(this.linearOnly||this.angularOnly){let r=this.angularOnly&&this.dimension===2?1:this.dimension;if(!this.linearIndices||this.linearIndices.length<i){let l=Math.max(i,(this.linearIndices?.length??0)*2,64);this.linearIndices=new Uint32Array(l),this.linearValues=new Float32Array(l*this.dimension)}let o=0;for(let[l,c]of this.pending){this.linearIndices[o]=l;for(let u=0;u<r;u++)this.linearValues[o*r+u]=this.queue.words[c.tail*12+4+u];o++}let n=this.angularOnly?"angularVelocityBatch":"velocityBatch",a=this.solver[n]??=new Qt(this.solver,this.dimension,this.angularOnly?"angular":"linear");a.submitValidated(this.linearIndices.subarray(0,i),this.linearValues.subarray(0,i*r),e),this.lastBatch={bodies:i,commands:this.queue.count,requestedCommands:this.requested,uploadedBytes:a.lastBatch.uploadedBytes,path:this.angularOnly?"packed-angular-velocities":"packed-velocities",submissions:e?0:1}}else if(this.motionOnly){let r=this.motionBatch??=new gi(this.solver,this.dimension),o=r.wordsPerBody;(!this.motionData||this.motionData.length<i*o)&&(this.motionData=new Uint32Array(Math.max(i*o,(this.motionData?.length??0)*2,64*o)),this.motionFloats=new Float32Array(this.motionData.buffer));let n=0;for(let[a,l]of this.pending){let c=n++*o;this.motionData[c]=a;let u=0;for(let f=l.head;f!==-1;f=this.next[f]){let d=this.queue.u32[f*12+1];u|=1<<d;let p=c+(d===0?2:2+this.dimension),g=d===0||this.dimension===3?this.dimension:1;for(let h=0;h<g;h++)this.motionFloats[p+h]=this.queue.words[f*12+4+h]}this.motionData[c+1]=u}r.submitValidated(this.motionData.subarray(0,i*o),e),this.lastBatch={bodies:i,commands:this.queue.count,requestedCommands:this.requested,uploadedBytes:r.lastBatch.uploadedBytes,path:"packed-motion",submissions:e?0:1}}else{this.upload??=new ei,this.upload.count=0,this.upload.reserve(this.queue.count),(!this.rangeData||this.rangeData.length<i*2)&&(this.rangeData=new Uint32Array(Math.max(i*2,(this.rangeData?.length??0)*2,128)));let r=0,o=0;for(let p of this.pending.values()){this.rangeData[o++]=r,this.rangeData[o++]=p.length;for(let g=p.head;g!==-1;g=this.next[g]){for(let h=0;h<12;h++)this.upload.u32[r*12+h]=this.queue.u32[g*12+h];r++}}let n=r*48,a=i*8,l=Math.min(t.limits.maxStorageBufferBindingSize,t.limits.maxBufferSize);if(n>l||a>l)throw Error("Body command batch exceeds GPU buffer limits");for(let[p,g]of[["commands",n],["ranges",a]])(!this[p]||this[p].size<g)&&(this[p]?.destroy(),this[p]=t.createBuffer({size:Math.min(l,Math.max(g*2,16)),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}));t.queue.writeBuffer(this.commands,0,this.upload.words.buffer,0,n),t.queue.writeBuffer(this.ranges,0,this.rangeData.buffer,0,a),this.pipeline??=t.createComputePipeline({layout:"auto",compute:{entryPoint:"edit",module:t.createShaderModule({code:"const DISPATCH_STRIDE = "+t.limits.maxComputeWorkgroupsPerDimension*64+`u;
4782
- `+this.shader})}}),(!this.group||this.boundBody!==this.solver.bodyBuffer||this.boundCommands!==this.commands||this.boundRanges!==this.ranges||this.boundRangeBytes!==a)&&(this.group=t.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:this.solver.bodyBuffer}},{binding:1,resource:{buffer:this.commands}},{binding:2,resource:{buffer:this.ranges,size:a}}]}),this.boundBody=this.solver.bodyBuffer,this.boundCommands=this.commands,this.boundRanges=this.ranges,this.boundRangeBytes=a);let c=e??t.createCommandEncoder(),u=c.beginComputePass();u.setPipeline(this.pipeline),u.setBindGroup(0,this.group);let f=Math.ceil(i/64),d=t.limits.maxComputeWorkgroupsPerDimension;u.dispatchWorkgroups(Math.min(f,d),Math.ceil(f/d)),u.end(),this.encodeAfterEdits(c,i),e||t.queue.submit([c.finish()]),this.lastBatch={bodies:i,commands:r,requestedCommands:this.requested,uploadedBytes:n+a,path:"ordered-commands",submissions:e?0:1}}for(let r of this.pending.values())this.freeRanges.push(r);this.pending.clear(),this.queue.count=0,this.requested=0,this.linearOnly=!0,this.angularOnly=!0,this.motionOnly=!0,this.hasTeleports=!1}encodeAfterEdits(){}destroy(){this.commands?.destroy(),this.ranges?.destroy(),this.solver.velocityBatch?.destroy(),this.solver.angularVelocityBatch?.destroy(),this.motionBatch?.destroy(),this.freeRanges.length=0,this.pending.clear(),this.queue=this.upload=this.next=this.linearIndices=this.linearValues=this.rangeData=this.motionData=this.motionFloats=null,this.group=null}};var Co=class extends ho{writePassConstants(e,t){Us.call(this,e,t)}createPipelines(){let e=this.layouts;this.compile(es,[e.broad],["beginFrame","gridCount","gridScatter","findPairs"]),this.compile(ts,[e.contacts],["hashInsert","narrowphase"]),this.compile(Dr,[e.topo],["degreeJoints","degreeContacts","fillJoints","fillContacts","sortAdjacency","colorCompact","colorMark","colorRoundAB","colorRoundBA","colorCount","colorStarts","colorScatter"]),this.compile(is,[e.solve,e.pass],["warmStartJoints","warmStartBodies","primal","primalScan","dual","refreshStick","updateVelocities"]),this.compile(Cs,[e.args],["argsPrev","argsPairs","argsContacts","argsColors"])}constructor(e,t,i={}){i.sleeping!==void 0&&i.sleeping!==!1&&go(i.sleeping),super(e,t,i),this.sleepEligible=new Map(t.avbdSleepEligible??[]),Hl(this),Zt(t)?.size&&this.enableShapes(),(i.sleeping||[...this.sleepEligible.values()].some(r=>r===!0))&&this.enableSleeping(i.sleeping||{})}enableShapes(){this.shapeBuffer||(this.syncShapeGeometry(),this.shapeContactLayout=this.makeLayout(["uniform","read-only-storage","read-only-storage","storage","read-only-storage","storage","storage","read-only-storage"]),this.compileBroadphase(),this.compileContacts(),this.bindContacts(),this.staticsDirty=!0)}geometryBytes(e=0){let t=(this.geometryRecords??this.bodyCapacity)*4+e;if(this.geometryRecords===void 0)for(let r of Zt(this.topology)?.values()??[])t+=r.vertices?.length??0;let i=t*4;if(i>Math.min(this.device.limits.maxStorageBufferBindingSize,this.device.limits.maxBufferSize,16777216*16))throw Error("2D hull geometry exceeds this GPU's storage capacity");return i}syncShapeGeometry(){let e=this.geometryBytes(),t=new Float32Array(e/4);this.packedShapes=new Map;let i=this.bodyCapacity;for(let[r,o]of Zt(this.topology)??[]){let n=Array.from(o);o.vertices&&(n[2]=i,t.set(o.vertices,i*4),i+=o.vertices.length/4),t.set(n,r*4),this.packedShapes.set(r,n)}this.geometryRecords=i,this.shapeBuffer=this.createShapeBuffer(e),this.device.queue.writeBuffer(this.shapeBuffer,0,t)}createShapeBuffer(e){let t=Math.min(this.device.limits.maxStorageBufferBindingSize,this.device.limits.maxBufferSize,268435456);return this.device.createBuffer({label:"2D collider geometry",size:Math.min(t,Math.max(e,Math.ceil(e*1.5/16)*16)),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC})}appendShapeGeometry(e,t){let i=this.geometryBytes(t.vertices?.length??0);if(this.shapeBuffer.size<i){let o=this.shapeBuffer;this.shapeBuffer=this.createShapeBuffer(i);let n=this.device.createCommandEncoder();n.copyBufferToBuffer(o,0,this.shapeBuffer,0,this.geometryRecords*16),this.device.queue.submit([n.finish()]),o.destroy(),this.bindFilters(),this.bindContacts()}let r=Array.from(t);t.vertices&&(r[2]=this.geometryRecords,this.device.queue.writeBuffer(this.shapeBuffer,this.geometryRecords*16,new Float32Array(t.vertices)),this.geometryRecords+=t.vertices.length/4),this.packedShapes.set(e,r),this.device.queue.writeBuffer(this.shapeBuffer,e*16,new Float32Array(r))}makeLayout(e){return this.device.createBindGroupLayout({entries:e.map((t,i)=>({binding:i,visibility:GPUShaderStage.COMPUTE,buffer:{type:t}}))})}contactSource(){let e=ts;return this.shapeBuffer&&(e=e.replace(`@compute @workgroup_size(64)
4783
- fn narrowphase`,$l+`
4993
+ `;function Vt(s,e){let t=s&&typeof s.x=="number"?[s.x,s.y]:Array.isArray(s)||ArrayBuffer.isView(s)&&!(s instanceof DataView)?s:Array.from(s??[]);if(t.length!==2||!t.every(Number.isFinite))throw Error(`${e} requires two finite components`);return t}var ti=class{constructor(){this.count=0,this.capacity=0}reserve(e){if(e<=this.capacity)return;let t=Math.max(e,this.capacity*2,64),i=new ArrayBuffer(t*48),r=new Float32Array(i),o=new Uint32Array(i);this.u32&&o.set(this.u32.subarray(0,this.count*12)),this.words=r,this.u32=o,this.capacity=t}append(e,t,i,r,o=!1){this.reserve(this.count+1),qc(this.words,this.u32,this.count++*12,e,t,i,r,o)}};function qc(s,e,t,i,r,o,n,a){e[t]=i,e[t+1]=r,e[t+2]=Number(a),e[t+3]=0;for(let l=0;l<4;l++)s[t+4+l]=o[l]??0,s[t+8+l]=n?.[l]??0}var Or=class{constructor(e,t=Nc,i=2){this.solver=e,this.shader=t,this.dimension=i,this.pending=new Map,this.queue=new ti,this.requested=0,this.linearOnly=!0,this.angularOnly=!0,this.hasTeleports=!1,this.motionOnly=!0,this.freeRanges=[]}slot(e,t){this.requested++,this.linearOnly&&=t===0,this.angularOnly&&=t===1,this.motionOnly&&=t===0||t===1,this.hasTeleports||=t===4;let i=this.pending.get(e);if(i&&(t===0||t===1)&&this.queue.u32[i.tail*12+1]===t)return i.tail;if(this.queue.reserve(this.queue.count+1),!this.next||this.next.length<this.queue.capacity){let o=new Int32Array(this.queue.capacity);this.next&&o.set(this.next),this.next=o}let r=this.queue.count++;return this.next[r]=-1,i?(this.next[i.tail]=r,i.tail=r,i.length++):(i=this.freeRanges.pop()??{},i.head=i.tail=r,i.length=1,this.pending.set(e,i)),r}enqueue(e,t,i,r,o=!1){let n=this.slot(e,t);qc(this.queue.words,this.queue.u32,n*12,e,t,i,r,o)}enqueueValidated(e){for(let t=0;t<e.count;t++){let i=t*12,r=this.slot(e.u32[i],e.u32[i+1])*12;for(let o=0;o<12;o++)this.queue.u32[r+o]=e.u32[i+o]}}flush(e){if(!this.pending.size)return;let t=this.solver.device,i=this.pending.size;if(this.linearOnly||this.angularOnly){let r=this.angularOnly&&this.dimension===2?1:this.dimension;if(!this.linearIndices||this.linearIndices.length<i){let l=Math.max(i,(this.linearIndices?.length??0)*2,64);this.linearIndices=new Uint32Array(l),this.linearValues=new Float32Array(l*this.dimension)}let o=0;for(let[l,c]of this.pending){this.linearIndices[o]=l;for(let u=0;u<r;u++)this.linearValues[o*r+u]=this.queue.words[c.tail*12+4+u];o++}let n=this.angularOnly?"angularVelocityBatch":"velocityBatch",a=this.solver[n]??=new Kt(this.solver,this.dimension,this.angularOnly?"angular":"linear");a.submitValidated(this.linearIndices.subarray(0,i),this.linearValues.subarray(0,i*r),e),this.lastBatch={bodies:i,commands:this.queue.count,requestedCommands:this.requested,uploadedBytes:a.lastBatch.uploadedBytes,path:this.angularOnly?"packed-angular-velocities":"packed-velocities",submissions:e?0:1}}else if(this.motionOnly){let r=this.motionBatch??=new yi(this.solver,this.dimension),o=r.wordsPerBody;(!this.motionData||this.motionData.length<i*o)&&(this.motionData=new Uint32Array(Math.max(i*o,(this.motionData?.length??0)*2,64*o)),this.motionFloats=new Float32Array(this.motionData.buffer));let n=0;for(let[a,l]of this.pending){let c=n++*o;this.motionData[c]=a;let u=0;for(let f=l.head;f!==-1;f=this.next[f]){let d=this.queue.u32[f*12+1];u|=1<<d;let p=c+(d===0?2:2+this.dimension),m=d===0||this.dimension===3?this.dimension:1;for(let h=0;h<m;h++)this.motionFloats[p+h]=this.queue.words[f*12+4+h]}this.motionData[c+1]=u}r.submitValidated(this.motionData.subarray(0,i*o),e),this.lastBatch={bodies:i,commands:this.queue.count,requestedCommands:this.requested,uploadedBytes:r.lastBatch.uploadedBytes,path:"packed-motion",submissions:e?0:1}}else{this.upload??=new ti,this.upload.count=0,this.upload.reserve(this.queue.count),(!this.rangeData||this.rangeData.length<i*2)&&(this.rangeData=new Uint32Array(Math.max(i*2,(this.rangeData?.length??0)*2,128)));let r=0,o=0;for(let p of this.pending.values()){this.rangeData[o++]=r,this.rangeData[o++]=p.length;for(let m=p.head;m!==-1;m=this.next[m]){for(let h=0;h<12;h++)this.upload.u32[r*12+h]=this.queue.u32[m*12+h];r++}}let n=r*48,a=i*8,l=Math.min(t.limits.maxStorageBufferBindingSize,t.limits.maxBufferSize);if(n>l||a>l)throw Error("Body command batch exceeds GPU buffer limits");for(let[p,m]of[["commands",n],["ranges",a]])(!this[p]||this[p].size<m)&&(this[p]?.destroy(),this[p]=t.createBuffer({size:Math.min(l,Math.max(m*2,16)),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}));t.queue.writeBuffer(this.commands,0,this.upload.words.buffer,0,n),t.queue.writeBuffer(this.ranges,0,this.rangeData.buffer,0,a),this.pipeline??=t.createComputePipeline({layout:"auto",compute:{entryPoint:"edit",module:t.createShaderModule({code:"const DISPATCH_STRIDE = "+t.limits.maxComputeWorkgroupsPerDimension*64+`u;
4994
+ `+this.shader})}}),(!this.group||this.boundBody!==this.solver.bodyBuffer||this.boundCommands!==this.commands||this.boundRanges!==this.ranges||this.boundRangeBytes!==a)&&(this.group=t.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:this.solver.bodyBuffer}},{binding:1,resource:{buffer:this.commands}},{binding:2,resource:{buffer:this.ranges,size:a}}]}),this.boundBody=this.solver.bodyBuffer,this.boundCommands=this.commands,this.boundRanges=this.ranges,this.boundRangeBytes=a);let c=e??t.createCommandEncoder(),u=c.beginComputePass();u.setPipeline(this.pipeline),u.setBindGroup(0,this.group);let f=Math.ceil(i/64),d=t.limits.maxComputeWorkgroupsPerDimension;u.dispatchWorkgroups(Math.min(f,d),Math.ceil(f/d)),u.end(),this.encodeAfterEdits(c,i),e||t.queue.submit([c.finish()]),this.lastBatch={bodies:i,commands:r,requestedCommands:this.requested,uploadedBytes:n+a,path:"ordered-commands",submissions:e?0:1}}for(let r of this.pending.values())this.freeRanges.push(r);this.pending.clear(),this.queue.count=0,this.requested=0,this.linearOnly=!0,this.angularOnly=!0,this.motionOnly=!0,this.hasTeleports=!1}encodeAfterEdits(){}destroy(){this.commands?.destroy(),this.ranges?.destroy(),this.solver.velocityBatch?.destroy(),this.solver.angularVelocityBatch?.destroy(),this.motionBatch?.destroy(),this.freeRanges.length=0,this.pending.clear(),this.queue=this.upload=this.next=this.linearIndices=this.linearValues=this.rangeData=this.motionData=this.motionFloats=null,this.group=null}};var Ho=class extends Oo{writeParams(e,t){nc.call(this,e,t)}writePassConstants(e,t){lo.call(this,e,t)}createPipelines(){let e=this.layouts;this.compile(ps,[e.broad],["beginFrame","gridCount","gridScatter","findPairs"]),this.compile(ms,[e.contacts],["hashInsert","narrowphase"]),this.compile(qr,[e.topo],["degreeJoints","degreeContacts","fillJoints","fillContacts","sortAdjacency","colorCompact","colorMark","colorRoundAB","colorRoundBA","colorCount","colorStarts","colorScatter"]),this.compile(gs,[e.solve,e.pass],["warmStartJoints","warmStartBodies","primal","primalScan","dual","refreshStick","updateVelocities"]),this.compile(Fs,[e.args],["argsPrev","argsPairs","argsContacts","argsColors"])}constructor(e,t,i={}){if(i.minimumColors!==void 0&&(!Number.isInteger(i.minimumColors)||i.minimumColors<4||i.minimumColors>64))throw Error("minimumColors must be an integer from 4 to 64");i.sleeping!==void 0&&i.sleeping!==!1&&Do(i.sleeping),super(e,t,i),this.minimumColors=i.minimumColors??4,this.colorCap=Math.max(this.colorCap,this.minimumColors),this.sleepEligible=new Map(t.avbdSleepEligible??[]),Dc(this),ei(t)?.size&&this.enableShapes(),(i.sleeping||[...this.sleepEligible.values()].some(r=>r===!0))&&this.enableSleeping(i.sleeping||{})}enableShapes(){this.shapeBuffer||(this.syncShapeGeometry(),this.shapeContactLayout=this.makeLayout(["uniform","read-only-storage","read-only-storage","storage","read-only-storage","storage","storage","read-only-storage"]),this.compileBroadphase(),this.compileContacts(),this.bindContacts(),this.staticsDirty=!0)}geometryBytes(e=0){let t=(this.geometryRecords??this.bodyCapacity)*4+e;if(this.geometryRecords===void 0)for(let r of ei(this.topology)?.values()??[])t+=r.vertices?.length??0;let i=t*4;if(i>Math.min(this.device.limits.maxStorageBufferBindingSize,this.device.limits.maxBufferSize,16777216*16))throw Error("2D hull geometry exceeds this GPU's storage capacity");return i}syncShapeGeometry(){let e=this.geometryBytes(),t=new Float32Array(e/4);this.packedShapes=new Map;let i=this.bodyCapacity;for(let[r,o]of ei(this.topology)??[]){let n=Array.from(o);o.vertices&&(n[2]=i,t.set(o.vertices,i*4),i+=o.vertices.length/4),t.set(n,r*4),this.packedShapes.set(r,n)}this.geometryRecords=i,this.shapeBuffer=this.createShapeBuffer(e),this.device.queue.writeBuffer(this.shapeBuffer,0,t)}createShapeBuffer(e){let t=Math.min(this.device.limits.maxStorageBufferBindingSize,this.device.limits.maxBufferSize,268435456);return this.device.createBuffer({label:"2D collider geometry",size:Math.min(t,Math.max(e,Math.ceil(e*1.5/16)*16)),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC})}appendShapeGeometry(e,t){let i=this.geometryBytes(t.vertices?.length??0);if(this.shapeBuffer.size<i){let o=this.shapeBuffer;this.shapeBuffer=this.createShapeBuffer(i);let n=this.device.createCommandEncoder();n.copyBufferToBuffer(o,0,this.shapeBuffer,0,this.geometryRecords*16),this.device.queue.submit([n.finish()]),o.destroy(),this.bindFilters(),this.bindContacts()}let r=Array.from(t);t.vertices&&(r[2]=this.geometryRecords,this.device.queue.writeBuffer(this.shapeBuffer,this.geometryRecords*16,new Float32Array(t.vertices)),this.geometryRecords+=t.vertices.length/4),this.packedShapes.set(e,r),this.device.queue.writeBuffer(this.shapeBuffer,e*16,new Float32Array(r))}makeLayout(e){return this.device.createBindGroupLayout({entries:e.map((t,i)=>({binding:i,visibility:GPUShaderStage.COMPUTE,buffer:{type:t}}))})}contactSource(){let e=ms;return this.shapeBuffer&&(e=e.replace(`@compute @workgroup_size(64)
4995
+ fn narrowphase`,Fc+`
4784
4996
  @compute @workgroup_size(64)
4785
- fn narrowphase`).replace("let col = collideBoxes(A.pose.xyz, A.shape.xy * 0.5, B.pose.xyz, B.shape.xy * 0.5);","let col = collideShapes2D(a,b);")),this.sensorsEnabled&&(e=e.replace("rec.ids = vec4u(a, b, o.feature, 0u);","rec.ids = vec4u(a,b,o.feature,select(0u,0x80000000u,A.initial.w!=0.||B.initial.w!=0.));").replace("if (j >= 0) {","if (j >= 0 && rec.ids.w==0u && (prevContacts[j].ids.w&0x80000000u)==0u) {")),this.bodyCommands&&(e=e.replace("if (j >= 0","if (A.prevVel.w==0. && B.prevVel.w==0. && j >= 0")),e}compileContacts(){this.compile(this.contactSource(),[this.shapeContactLayout??this.layouts.contacts],["hashInsert","narrowphase"])}bindContacts(){this.shapeBuffer&&(this.groups.contacts=this.contactBuffers.map((e,t)=>this.device.createBindGroup({layout:this.shapeContactLayout,entries:[this.paramsBuffer,this.bodyBuffer,this.pairBuffer,e,this.contactBuffers[1-t],this.tableBuffer,this.counterBuffer,this.shapeBuffer].map((i,r)=>({binding:r,resource:{buffer:i}}))})))}compileBroadphase(){let e=["uniform","read-only-storage","storage","storage","storage","read-only-storage","read-only-storage"],t=es;if(this.shapeBuffer&&(e.push("read-only-storage"),t=t.replace(`fn radius(i: u32) -> f32 {
4997
+ fn narrowphase`).replace("let col = collideBoxes(A.pose.xyz, A.shape.xy * 0.5, B.pose.xyz, B.shape.xy * 0.5);","let col = collideShapes2D(a,b);")),this.sensorsEnabled&&(e=e.replace("rec.ids = vec4u(a, b, o.feature, 0u);","rec.ids = vec4u(a,b,o.feature,select(0u,0x80000000u,A.initial.w!=0.||B.initial.w!=0.));").replace("if (j >= 0) {","if (j >= 0 && rec.ids.w==0u && (prevContacts[j].ids.w&0x80000000u)==0u) {")),this.bodyCommands&&(e=e.replace("if (j >= 0","if (A.prevVel.w==0. && B.prevVel.w==0. && j >= 0")),e}compileContacts(){this.compile(this.contactSource(),[this.shapeContactLayout??this.layouts.contacts],["hashInsert","narrowphase"])}bindContacts(){this.shapeBuffer&&(this.groups.contacts=this.contactBuffers.map((e,t)=>this.device.createBindGroup({layout:this.shapeContactLayout,entries:[this.paramsBuffer,this.bodyBuffer,this.pairBuffer,e,this.contactBuffers[1-t],this.tableBuffer,this.counterBuffer,this.shapeBuffer].map((i,r)=>({binding:r,resource:{buffer:i}}))})))}compileBroadphase(){let e=["uniform","read-only-storage","storage","storage","storage","read-only-storage","read-only-storage"],t=ps;if(this.shapeBuffer&&(e.push("read-only-storage"),t=t.replace(`fn radius(i: u32) -> f32 {
4786
4998
  return 0.5 * length(bodies[i].shape.xy);
4787
4999
  }`,`@group(0) @binding(7) var<storage,read> geometry:array<vec4f>;
4788
5000
  fn radius(i:u32)->f32{let g=geometry[i];if(g.x==4.){return g.y;}if(g.x==1.||g.x==2.){return g.y+g.z;}return .5*length(bodies[i].shape.xy);}`).replace("return radius(i) > params.maxSmallRadius;","return geometry[i].x==3. || radius(i) > params.maxSmallRadius;").replace("if (dot(d, d) > r * r) { return; }",`if(geometry[a].x==3.||geometry[b].x==3.) {
@@ -4790,13 +5002,13 @@ let plane=select(b,a,geometry[a].x==3.);let other=select(a,b,geometry[a].x==3.);
4790
5002
  if(dot(bodies[other].pose.xy-bodies[plane].pose.xy,normal)>radius(other)){return;}
4791
5003
  } else if(dot(d,d)>r*r){return;}`)),this.filters){let i=e.length;e.push("read-only-storage"),t=t.replace("fn ignored(hi: u32, lo: u32) -> bool {",`@group(0) @binding(${i}) var<storage,read> filters:array<vec2u>;
4792
5004
  fn ignored(hi:u32,lo:u32)->bool{
4793
- if((filters[hi].x&filters[lo].y)==0u || (filters[lo].x&filters[hi].y)==0u){return true;}`)}this.filterLayout=this.makeLayout(e),this.compile(t,[this.filterLayout],["beginFrame","gridCount","gridScatter","findPairs"]),this.bindFilters()}uploadBodies(e=0,t=this.topology.bodyCount-e){this.flushPropertyEdits(),super.uploadBodies(e,t);for(let o=e;o<e+t;o++)this.sleeping?.register(o,this.sleepEligible?.get(o)!==!1);if(!this.shapeBuffer&&!this.triggers?.size)return;let i=this.shapeBuffer&&t>0?new Float32Array(t*4):null,r=this.packedShapes;for(let o=e;o<e+t;o++){let n=r?.get(o);i&&n&&i.set(n,(o-e)*4),this.triggers?.has(o)&&this.device.queue.writeBuffer(this.bodyBuffer,o*96+28,new Float32Array([1]))}i&&this.device.queue.writeBuffer(this.shapeBuffer,e*16,i)}uploadStatics(){if(!this.shapeBuffer)return super.uploadStatics();let e=this.topology,t=Zt(e),i=[];for(let f=0;f<this.bodyCount;f++)t?.get(f)?.[0]!==3&&i.push(e.props[f*4+1]);i.sort((f,d)=>f-d);let r=i[i.length>>1]??1,o=0,n=1/0;for(let f of i)f<=4*r&&(o=Math.max(o,f));for(let f of i)f>o&&(n=Math.min(n,f));let a=n===1/0?o*1.5:(o+n)/2;this.maxSmallRadius=a,this.cellSize=Math.max(2*o*(1+1e-4),.001);let l=[],c=[];for(let f=0;f<this.bodyCount;f++)(t?.get(f)?.[0]===3||e.props[f*4+1]>a)&&l.push(f);for(let f=0;f<e.jointCount;f++){let d=e.info[f*4+1],p=e.info[f*4+2];d>=0&&c.push([Math.max(d,p),Math.min(d,p),f])}for(let f of e.ignoredPairs()){let d=Math.floor(f/2097152);c.push([d,f-d*2097152,4294967295])}c.sort((f,d)=>f[0]-d[0]||f[1]-d[1]),this.largeCount=l.length,this.noCollideCount=c.length;let u=new Uint32Array(Math.max(l.length+3*c.length,4));u.set(l),c.forEach((f,d)=>u.set(f,l.length+3*d)),this.staticBuffer.size<u.byteLength&&(this.staticBuffer.destroy(),this.staticBuffer=this.device.createBuffer({label:"2D boundaries",size:u.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),this.rebuildBindings()),this.device.queue.writeBuffer(this.staticBuffer,0,u),this.staticsDirty=!1}async raycast(e,t,i={}){let[r]=await this.raycastAll([{origin:e,direction:t,maxDistance:i.maxDistance}],i);return r}raycastAll(e,t={}){return this.flushEdits(),this.shapeQueries??=new di(this,2),this.shapeQueries.cast(e.map(i=>({...i,radius:0})),t)}async circleCast(e,t,i,r={}){let[o]=await this.circleCastAll([{origin:e,radius:t,direction:i,maxDistance:r.maxDistance}],r);return o}circleCastAll(e,t={}){return this.flushEdits(),this.shapeQueries??=new di(this,2),this.shapeQueries.cast(e,t)}liveIndex(e){if(this.destroyed)throw Error("The 2D solver has been destroyed");if(!Number.isInteger(e)||e<0||e>=this.bodyCount)throw Error("A live 2D body index is required")}queueBodyCommand(e,t,i,r,o=!1){return this.liveIndex(e),this.prepareBodyCommands().enqueue(e,t,i,r,o),this}prepareBodyCommands(){return this.wakeAll(),this.bodyCommands||(this.bodyCommands=new Mr(this),this.compileContacts()),this.bodyCommands}setLinearVelocity(e,t){return this.queueBodyCommand(e,0,Vt(t,"velocity"))}setAngularVelocity(e,t){if(!Number.isFinite(t))throw Error("Angular velocity must be finite");return this.queueBodyCommand(e,1,[t,0,0,0])}applyImpulse(e,t,i){return this.queueBodyCommand(e,2,Vt(t,"impulse"),i===void 0?void 0:Vt(i,"point"),i!==void 0)}applyForce(e,t,i){return this.queueBodyCommand(e,3,[...Vt(t,"force"),0,this.params.dt],i===void 0?void 0:Vt(i,"point"),i!==void 0)}applyAngularImpulse(e,t){if(!Number.isFinite(t))throw Error("Angular impulse must be finite");return this.queueBodyCommand(e,5,[t,0,0,0])}applyTorque(e,t){if(!Number.isFinite(t))throw Error("Torque must be finite");return this.queueBodyCommand(e,6,[t,0,0,this.params.dt])}teleport(e,t,i){if(i!==void 0&&!Number.isFinite(i))throw Error("Angle must be finite");return this.queueBodyCommand(e,4,[...Vt(t,"position"),i??0,0],void 0,i!==void 0)}readBodies(){return this.flushEdits(),super.readBodies()}async readBodyState(e){this.liveIndex(e),this.flushEdits();let t=this.device,i=t.createBuffer({size:96,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ});try{let r=t.createCommandEncoder();r.copyBufferToBuffer(this.bodyBuffer,e*96,i,0,96),t.queue.submit([r.finish()]),await i.mapAsync(GPUMapMode.READ);let o=new Float32Array(i.getMappedRange());return{position:[o[0],o[1]],angle:o[2],linearVelocity:[o[12],o[13]],angularVelocity:o[14],mass:o[22],moment:o[23],sleeping:o[15]!==0}}finally{i.destroy()}}addBox(e,t={}){return this.addShape({size:Array.from(e)},t)}addCircle(e,t={}){return this.addShape(Ao(e),t)}addHull(e,t={}){return this.addShape(vo(e),t)}addCapsule(e,t,i={}){return this.addShape(xo(e,t),i)}addSegment(e,t,i={}){return this.addShape(wo(e,t,i))}addPlane(e=[0,1],t=0,i={}){return this.addShape(Bo(e,t,i))}addShape(e,t={}){t=e.options??t;let{density:i=1,friction:r=.6,position:o=[0,0],angle:n=0,velocity:a=[0,0,0],restitution:l=0,isTrigger:c=!1,group:u=4294967295,collidesWith:f=4294967295,allowSleep:d}=t;if(this.destroyed)throw Error("The 2D solver has been destroyed");if(d!==void 0&&typeof d!="boolean")throw Error("allowSleep must be boolean");if(this.bodyCount>=this.bodyCapacity)throw Error("2D body capacity reached; reserve bodyCapacity when creating the solver");if(e.size.length!==2||!e.size.every(h=>Number.isFinite(h)&&h>0)||!Number.isFinite(i)||i<0||!Number.isFinite(r)||r<0||!Number.isFinite(n))throw Error("Body dimensions must be positive, density and friction nonnegative, and angle finite");if(a.length!==3||!Array.from(a).every(Number.isFinite))throw Error("Velocity requires [x, y, angular] finite components");if(typeof c!="boolean"||!Number.isFinite(l)||l<0||l>1)throw Error("isTrigger must be boolean and restitution between zero and one");if([u,f].some(h=>!Number.isInteger(h)||h<0||h>4294967295))throw Error("Collision masks must be unsigned 32-bit integers");let p=Vt(o,"position");e.geometry&&this.geometryBytes(e.geometry.vertices?.length??0);let g=super.addBody(e.size,i,r,[...p,n],Array.from(a));return e.geometry&&(Er(this.topology,g,e,i),this.shapeBuffer?this.appendShapeGeometry(g,e.geometry):this.enableShapes(),this.uploadBodies(g,1)),l&&this.setRestitution(g,l),c&&this.setSensor(g,!0),(u!==4294967295||f!==4294967295)&&this.setFilters([g],[u],[f]),this.contactWatch?.setWatched([g],[!this.watchedIndices||this.watchedIndices.has(g)]),this.sleepEligible.set(g,d??!0),d===!0&&!this.sleeping&&this.enableSleeping(),this.sleeping?.register(g,d!==!1),this.wakeAll(),g}setRestitution(e,t){if(this.liveIndex(e),!Number.isInteger(e)||e<0||e>=this.bodyCount||!Number.isFinite(t)||t<0||t>1)throw Error("Restitution requires a live body index and a coefficient in 0..1");t>0&&!this.restitution&&(this.restitution=new po(this)),this.restitution?.set(e,t),this.wakeAll()}constraintSlot(e,t){if(this.destroyed)throw Error("The 2D solver has been destroyed");if(!Number.isInteger(e)||e<0||e>=this.jointCount||this.topology.handles[e]?.disposed)throw Error("A live 2D constraint slot is required");if(t!==void 0&&this.topology.info[e*j]!==t)throw Error("The constraint has a different type");return e}setMotor(e,{speed:t,maxTorque:i}={}){if(this.constraintSlot(e,uo),t!==void 0&&!Number.isFinite(t)||i!==void 0&&(!Number.isFinite(i)||i<0))throw Error("Motor speed must be finite and maximum torque nonnegative");let r=e*O,o=e*36;t!==void 0&&(this.topology.data[r+re]=t,le(this).float(this.jointBuffer,o+32,t)),i!==void 0&&(this.topology.data[r+Le]=-i,this.topology.data[r+xe]=i,le(this).float(this.jointBuffer,o+12,-i),le(this).float(this.jointBuffer,o+16,i)),this.wakeAll()}setAngleLimits(e,t){this.constraintSlot(e,bo);let i=Ci(t);this.topology.data[e*O+ge]=i.minAngle,this.topology.data[e*O+Fe]=i.maxAngle,le(this).float(this.jointBuffer,e*36+32+1,i.minAngle),le(this).float(this.jointBuffer,e*36+32+2,i.maxAngle);for(let r=4;r<8;r++)le(this).float(this.jointBuffer,e*36+r,0);this.wakeAll()}setWorldAnchor(e,t,i){if(this.constraintSlot(e,xi),this.topology.info[e*j+1]!==-1||!Number.isFinite(t)||!Number.isFinite(i))throw Error("A world joint and finite xy anchor are required");le(this).float(this.jointBuffer,e*36+28,t),le(this).float(this.jointBuffer,e*36+28+1,i),this.wakeAll()}disableConstraint(e){if(this.topology.handles[e]?.disposed)return;this.constraintSlot(e),this.flushPropertyEdits(),super.disableConstraint(e),this.wakeAll();let t=this.topology.handles[e];t&&(t.alive=!1,t.disposed=!0)}appendJoint(e,t,i,r,o,n=1/0){if(e!==-1&&this.liveIndex(e),this.liveIndex(t),e===t)throw Error("Constraint endpoints must differ");let a=Vt(i,"anchorA"),l=Vt(r,"anchorB");if(!o||o.length!==3||Array.from(o).some(u=>u!==1/0&&(!Number.isFinite(u)||u<0))||n!==1/0&&(!Number.isFinite(n)||n<0))throw Error("Joint stiffness and break force must be nonnegative or Infinity");this.flushPropertyEdits();let c=super.appendJoint(e,t,a,l,Array.from(o),n);return this.wakeAll(),c}setFilters(e,t,i){if(this.destroyed)throw Error("The 2D solver has been destroyed");if(e.length!==t.length||e.length!==i.length)throw Error("Each body index needs a group and collision mask");let r=a=>{if(!Number.isInteger(a)||a<0||a>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");return a},o=Array.from(e,(a,l)=>(this.liveIndex(a),[a,r(t[l]),r(i[l])]));if(this.wakeAll(),!this.filters){let a=this.device;this.filters=a.createBuffer({size:this.bodyCapacity*8,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),a.queue.writeBuffer(this.filters,0,new Uint32Array(this.bodyCapacity*2).fill(4294967295)),this.compileBroadphase()}let n=le(this);for(let[a,l,c]of o)n.uint(this.filters,a*2,l),n.uint(this.filters,a*2+1,c)}bindFilters(){this.filterLayout&&(this.groups.broad=this.device.createBindGroup({layout:this.filterLayout,entries:[this.paramsBuffer,this.bodyBuffer,this.gridBuffer,this.pairBuffer,this.counterBuffer,this.staticBuffer,this.jointBuffer,...this.shapeBuffer?[this.shapeBuffer]:[],...this.filters?[this.filters]:[]].map((e,t)=>({binding:t,resource:{buffer:e}}))}))}rebuildBindings(){super.rebuildBindings(),this.bindFilters(),this.bindContacts()}setSensor(e,t){if(this.liveIndex(e),typeof t!="boolean")throw Error("Sensor flag must be boolean");if(this.wakeAll(),t&&!this.sensorsEnabled){this.sensorsEnabled=!0;let i=this.device,r=i.createComputePipeline({layout:"auto",compute:{module:i.createShaderModule({code:"@group(0) @binding(0) var<storage,read_write> data:array<vec4f>; @compute @workgroup_size(64) fn clear(@builtin(global_invocation_id) id:vec3u){if(id.x*6u+1u<arrayLength(&data)){data[id.x*6u+1u].w=0.;}}"}),entryPoint:"clear"}}),o=i.createBindGroup({layout:r.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:this.bodyBuffer}}]}),n=i.createCommandEncoder(),a=n.beginComputePass();a.setPipeline(r),a.setBindGroup(0,o),a.dispatchWorkgroups(Math.ceil(this.bodyCount/64)),a.end(),i.queue.submit([n.finish()]),this.compileContacts();let l=is.replace("b.initial = b.pose;","b.initial = vec4f(b.pose.xyz,b.initial.w);").replace("fn addContact(acc: ptr<function, Acc>, c: u32, alpha: f32, i: u32) {",`fn addContact(acc: ptr<function, Acc>, c: u32, alpha: f32, i: u32) {
5005
+ if((filters[hi].x&filters[lo].y)==0u || (filters[lo].x&filters[hi].y)==0u){return true;}`)}this.filterLayout=this.makeLayout(e),this.compile(t,[this.filterLayout],["beginFrame","gridCount","gridScatter","findPairs"]),this.bindFilters()}uploadBodies(e=0,t=this.topology.bodyCount-e){this.flushPropertyEdits(),super.uploadBodies(e,t);for(let o=e;o<e+t;o++)this.sleeping?.register(o,this.sleepEligible?.get(o)!==!1);if(!this.shapeBuffer&&!this.triggers?.size)return;let i=this.shapeBuffer&&t>0?new Float32Array(t*4):null,r=this.packedShapes;for(let o=e;o<e+t;o++){let n=r?.get(o);i&&n&&i.set(n,(o-e)*4),this.triggers?.has(o)&&this.device.queue.writeBuffer(this.bodyBuffer,o*96+28,new Float32Array([1]))}i&&this.device.queue.writeBuffer(this.shapeBuffer,e*16,i)}uploadStatics(){if(!this.shapeBuffer)return super.uploadStatics();let e=this.topology,t=ei(e),i=[];for(let f=0;f<this.bodyCount;f++)t?.get(f)?.[0]!==3&&i.push(e.props[f*4+1]);i.sort((f,d)=>f-d);let r=i[i.length>>1]??1,o=0,n=1/0;for(let f of i)f<=4*r&&(o=Math.max(o,f));for(let f of i)f>o&&(n=Math.min(n,f));let a=n===1/0?o*1.5:(o+n)/2;this.maxSmallRadius=a,this.cellSize=Math.max(2*o*(1+1e-4),.001);let l=[],c=[];for(let f=0;f<this.bodyCount;f++)(t?.get(f)?.[0]===3||e.props[f*4+1]>a)&&l.push(f);for(let f=0;f<e.jointCount;f++){let d=e.info[f*4+1],p=e.info[f*4+2];d>=0&&c.push([Math.max(d,p),Math.min(d,p),f])}for(let f of e.ignoredPairs()){let d=Math.floor(f/2097152);c.push([d,f-d*2097152,4294967295])}c.sort((f,d)=>f[0]-d[0]||f[1]-d[1]),this.largeCount=l.length,this.noCollideCount=c.length;let u=new Uint32Array(Math.max(l.length+3*c.length,4));u.set(l),c.forEach((f,d)=>u.set(f,l.length+3*d)),this.staticBuffer.size<u.byteLength&&(this.staticBuffer.destroy(),this.staticBuffer=this.device.createBuffer({label:"2D boundaries",size:u.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),this.rebuildBindings()),this.device.queue.writeBuffer(this.staticBuffer,0,u),this.staticsDirty=!1}async raycast(e,t,i={}){let[r]=await this.raycastAll([{origin:e,direction:t,maxDistance:i.maxDistance}],i);return r}raycastAll(e,t={}){return this.flushEdits(),this.shapeQueries??=new pi(this,2),this.shapeQueries.cast(e.map(i=>({...i,radius:0})),t)}async circleCast(e,t,i,r={}){let[o]=await this.circleCastAll([{origin:e,radius:t,direction:i,maxDistance:r.maxDistance}],r);return o}circleCastAll(e,t={}){return this.flushEdits(),this.shapeQueries??=new pi(this,2),this.shapeQueries.cast(e,t)}liveIndex(e){if(this.destroyed)throw Error("The 2D solver has been destroyed");if(!Number.isInteger(e)||e<0||e>=this.bodyCount)throw Error("A live 2D body index is required")}queueBodyCommand(e,t,i,r,o=!1){return this.liveIndex(e),this.prepareBodyCommands().enqueue(e,t,i,r,o),this}prepareBodyCommands(){return this.wakeAll(),this.bodyCommands||(this.bodyCommands=new Or(this),this.compileContacts()),this.bodyCommands}setLinearVelocity(e,t){return this.queueBodyCommand(e,0,Vt(t,"velocity"))}setAngularVelocity(e,t){if(!Number.isFinite(t))throw Error("Angular velocity must be finite");return this.queueBodyCommand(e,1,[t,0,0,0])}applyImpulse(e,t,i){return this.queueBodyCommand(e,2,Vt(t,"impulse"),i===void 0?void 0:Vt(i,"point"),i!==void 0)}applyForce(e,t,i){return this.queueBodyCommand(e,3,[...Vt(t,"force"),0,this.params.dt],i===void 0?void 0:Vt(i,"point"),i!==void 0)}applyAngularImpulse(e,t){if(!Number.isFinite(t))throw Error("Angular impulse must be finite");return this.queueBodyCommand(e,5,[t,0,0,0])}applyTorque(e,t){if(!Number.isFinite(t))throw Error("Torque must be finite");return this.queueBodyCommand(e,6,[t,0,0,this.params.dt])}teleport(e,t,i){if(i!==void 0&&!Number.isFinite(i))throw Error("Angle must be finite");return this.queueBodyCommand(e,4,[...Vt(t,"position"),i??0,0],void 0,i!==void 0)}readBodies(){return this.flushEdits(),super.readBodies()}async readBodyState(e){this.liveIndex(e),this.flushEdits();let t=this.device,i=t.createBuffer({size:96,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ});try{let r=t.createCommandEncoder();r.copyBufferToBuffer(this.bodyBuffer,e*96,i,0,96),t.queue.submit([r.finish()]),await i.mapAsync(GPUMapMode.READ);let o=new Float32Array(i.getMappedRange());return{position:[o[0],o[1]],angle:o[2],linearVelocity:[o[12],o[13]],angularVelocity:o[14],mass:o[22],moment:o[23],sleeping:o[15]!==0}}finally{i.destroy()}}addBox(e,t={}){return this.addShape({size:Array.from(e)},t)}addCircle(e,t={}){return this.addShape(No(e),t)}addHull(e,t={}){return this.addShape(Uo(e),t)}addCapsule(e,t,i={}){return this.addShape(qo(e,t),i)}addSegment(e,t,i={}){return this.addShape(Vo(e,t,i))}addPlane(e=[0,1],t=0,i={}){return this.addShape(Wo(e,t,i))}addShape(e,t={}){t=e.options??t;let{density:i=1,friction:r=.6,position:o=[0,0],angle:n=0,velocity:a=[0,0,0],restitution:l=0,isTrigger:c=!1,group:u=4294967295,collidesWith:f=4294967295,allowSleep:d}=t;if(this.destroyed)throw Error("The 2D solver has been destroyed");if(d!==void 0&&typeof d!="boolean")throw Error("allowSleep must be boolean");if(this.bodyCount>=this.bodyCapacity)throw Error("2D body capacity reached; reserve bodyCapacity when creating the solver");if(e.size.length!==2||!e.size.every(h=>Number.isFinite(h)&&h>0)||!Number.isFinite(i)||i<0||!Number.isFinite(r)||r<0||!Number.isFinite(n))throw Error("Body dimensions must be positive, density and friction nonnegative, and angle finite");if(a.length!==3||!Array.from(a).every(Number.isFinite))throw Error("Velocity requires [x, y, angular] finite components");if(typeof c!="boolean"||!Number.isFinite(l)||l<0||l>1)throw Error("isTrigger must be boolean and restitution between zero and one");if([u,f].some(h=>!Number.isInteger(h)||h<0||h>4294967295))throw Error("Collision masks must be unsigned 32-bit integers");let p=Vt(o,"position");e.geometry&&this.geometryBytes(e.geometry.vertices?.length??0);let m=super.addBody(e.size,i,r,[...p,n],Array.from(a));return e.geometry&&(Rr(this.topology,m,e,i),this.shapeBuffer?this.appendShapeGeometry(m,e.geometry):this.enableShapes(),this.uploadBodies(m,1)),l&&this.setRestitution(m,l),c&&this.setSensor(m,!0),(u!==4294967295||f!==4294967295)&&this.setFilters([m],[u],[f]),this.contactWatch?.setWatched([m],[!this.watchedIndices||this.watchedIndices.has(m)]),this.sleepEligible.set(m,d??!0),d===!0&&!this.sleeping&&this.enableSleeping(),this.sleeping?.register(m,d!==!1),this.wakeAll(),m}setRestitution(e,t){if(this.liveIndex(e),!Number.isInteger(e)||e<0||e>=this.bodyCount||!Number.isFinite(t)||t<0||t>1)throw Error("Restitution requires a live body index and a coefficient in 0..1");t>0&&!this.restitution&&(this.restitution=new To(this)),this.restitution?.set(e,t),this.wakeAll()}constraintSlot(e,t){if(this.destroyed)throw Error("The 2D solver has been destroyed");if(!Number.isInteger(e)||e<0||e>=this.jointCount||this.topology.handles[e]?.disposed)throw Error("A live 2D constraint slot is required");if(t!==void 0&&this.topology.info[e*j]!==t)throw Error("The constraint has a different type");return e}setMotor(e,{speed:t,maxTorque:i}={}){if(this.constraintSlot(e,Io),t!==void 0&&!Number.isFinite(t)||i!==void 0&&(!Number.isFinite(i)||i<0))throw Error("Motor speed must be finite and maximum torque nonnegative");let r=e*O,o=e*36;t!==void 0&&(this.topology.data[r+re]=t,le(this).float(this.jointBuffer,o+32,t)),i!==void 0&&(this.topology.data[r+_e]=-i,this.topology.data[r+Ae]=i,le(this).float(this.jointBuffer,o+12,-i),le(this).float(this.jointBuffer,o+16,i)),this.wakeAll()}setAngleLimits(e,t){this.constraintSlot(e,Go);let i=ki(t);this.topology.data[e*O+be]=i.minAngle,this.topology.data[e*O+Ue]=i.maxAngle,le(this).float(this.jointBuffer,e*36+32+1,i.minAngle),le(this).float(this.jointBuffer,e*36+32+2,i.maxAngle);for(let r=4;r<8;r++)le(this).float(this.jointBuffer,e*36+r,0);this.wakeAll()}setWorldAnchor(e,t,i){if(this.constraintSlot(e,Bi),this.topology.info[e*j+1]!==-1||!Number.isFinite(t)||!Number.isFinite(i))throw Error("A world joint and finite xy anchor are required");le(this).float(this.jointBuffer,e*36+28,t),le(this).float(this.jointBuffer,e*36+28+1,i),this.wakeAll()}disableConstraint(e){if(this.topology.handles[e]?.disposed)return;this.constraintSlot(e),this.flushPropertyEdits(),super.disableConstraint(e),this.wakeAll();let t=this.topology.handles[e];t&&(t.alive=!1,t.disposed=!0)}appendJoint(e,t,i,r,o,n=1/0){if(e!==-1&&this.liveIndex(e),this.liveIndex(t),e===t)throw Error("Constraint endpoints must differ");let a=Vt(i,"anchorA"),l=Vt(r,"anchorB");if(!o||o.length!==3||Array.from(o).some(u=>u!==1/0&&(!Number.isFinite(u)||u<0))||n!==1/0&&(!Number.isFinite(n)||n<0))throw Error("Joint stiffness and break force must be nonnegative or Infinity");this.flushPropertyEdits();let c=super.appendJoint(e,t,a,l,Array.from(o),n);return this.wakeAll(),c}setFilters(e,t,i){if(this.destroyed)throw Error("The 2D solver has been destroyed");if(e.length!==t.length||e.length!==i.length)throw Error("Each body index needs a group and collision mask");let r=a=>{if(!Number.isInteger(a)||a<0||a>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");return a},o=Array.from(e,(a,l)=>(this.liveIndex(a),[a,r(t[l]),r(i[l])]));if(this.wakeAll(),!this.filters){let a=this.device;this.filters=a.createBuffer({size:this.bodyCapacity*8,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),a.queue.writeBuffer(this.filters,0,new Uint32Array(this.bodyCapacity*2).fill(4294967295)),this.compileBroadphase()}let n=le(this);for(let[a,l,c]of o)n.uint(this.filters,a*2,l),n.uint(this.filters,a*2+1,c)}bindFilters(){this.filterLayout&&(this.groups.broad=this.device.createBindGroup({layout:this.filterLayout,entries:[this.paramsBuffer,this.bodyBuffer,this.gridBuffer,this.pairBuffer,this.counterBuffer,this.staticBuffer,this.jointBuffer,...this.shapeBuffer?[this.shapeBuffer]:[],...this.filters?[this.filters]:[]].map((e,t)=>({binding:t,resource:{buffer:e}}))}))}rebuildBindings(){super.rebuildBindings(),this.bindFilters(),this.bindContacts()}setSensor(e,t){if(this.liveIndex(e),typeof t!="boolean")throw Error("Sensor flag must be boolean");if(this.wakeAll(),t&&!this.sensorsEnabled){this.sensorsEnabled=!0;let i=this.device,r=i.createComputePipeline({layout:"auto",compute:{module:i.createShaderModule({code:"@group(0) @binding(0) var<storage,read_write> data:array<vec4f>; @compute @workgroup_size(64) fn clear(@builtin(global_invocation_id) id:vec3u){if(id.x*6u+1u<arrayLength(&data)){data[id.x*6u+1u].w=0.;}}"}),entryPoint:"clear"}}),o=i.createBindGroup({layout:r.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:this.bodyBuffer}}]}),n=i.createCommandEncoder(),a=n.beginComputePass();a.setPipeline(r),a.setBindGroup(0,o),a.dispatchWorkgroups(Math.ceil(this.bodyCount/64)),a.end(),i.queue.submit([n.finish()]),this.compileContacts();let l=gs.replace("b.initial = b.pose;","b.initial = vec4f(b.pose.xyz,b.initial.w);").replace("fn addContact(acc: ptr<function, Acc>, c: u32, alpha: f32, i: u32) {",`fn addContact(acc: ptr<function, Acc>, c: u32, alpha: f32, i: u32) {
4794
5006
  if((contacts[c].ids.w&0x80000000u)!=0u){return;}`).replace("fn dualContact(c: u32) {",`fn dualContact(c: u32) {
4795
5007
  if((contacts[c].ids.w&0x80000000u)!=0u){return;}`).replace(` let k = contacts[c];
4796
5008
  let bound`,` let k = contacts[c];
4797
5009
  if((k.ids.w&0x80000000u)!=0u){return;}
4798
- let bound`);this.compile(l,[this.layouts.solve,this.layouts.pass],["warmStartJoints","warmStartBodies","primal","primalScan","dual","refreshStick","updateVelocities"]);let c=Dr.replaceAll("if (gid.x >= topoCount()) { return; }",`if (gid.x >= topoCount()) { return; }
4799
- if((contacts[gid.x].ids.w&0x80000000u)!=0u){return;}`);this.compile(c,[this.layouts.topo],["degreeContacts","fillContacts"])}this.sensorsEnabled&&le(this).float(this.bodyBuffer,e*24+7,t?1:0),this.triggers??=new Set,t?this.triggers.add(e):this.triggers.delete(e)}compile(e,t,i){e.includes("fn warmStartBodies(")&&(e=Gl(ql(Jl(e)))),e.includes("fn dynamicBody(")&&(e=Vl(e)),e.includes("fn colorCount(")&&(e=Nl(e));let r=this.device,o=r.createShaderModule({code:e}),n=r.createPipelineLayout({bindGroupLayouts:t});for(let a of i)this.pipes[a]=r.createComputePipeline({layout:n,compute:{module:o,entryPoint:a}})}watchContacts({maxPairs:e=8192,maxEvents:t=4096,indices:i}={}){if(this.destroyed)throw Error("The 2D solver has been destroyed");if(i!==void 0){if(!Array.isArray(i))throw Error("Watched indices must be an array of live body indices");for(let r of i)this.liveIndex(r)}for(let r of[e,t])if(!Number.isInteger(r)||r<1)throw Error("Contact capacities must be positive integers");return this.contactWatch||(this.contactWatch=new yi(this.device,this.bodyBuffer,this.bodyCapacity,e,t,2),i===void 0&&this.contactWatch.setWatched(Array.from({length:this.bodyCount},(r,o)=>o),Array(this.bodyCount).fill(!0))),i!==void 0&&(this.watchedIndices=new Set(i),this.contactWatch.setWatched(Array.from({length:this.bodyCount},(r,o)=>o),Array.from({length:this.bodyCount},(r,o)=>this.watchedIndices.has(o)))),this}async readContactEvents(){this.watchContacts();let e=await this.contactWatch.read();return{...e,events:e.events.map(t=>({...t,type:t.kind===vi?"begin":"end",isTrigger:!!(this.triggers?.has(t.a)||this.triggers?.has(t.b))}))}}step(){if(this.destroyed)throw Error("The 2D solver has been destroyed");this.sleeping||this.restitution?.active.size||this.bodyCommands?.pending.size||this.propertyEdits?.pending?Wl.call(this):super.step(),this.contactWatch&&this.contactWatch.run({manifolds:this.contactBuffers[1-this.parity],contacts:this.contactBuffers[1-this.parity],counters:this.counterBuffer},this.contactCapacity,this.eventStep=(this.eventStep??0)+1,this.params.dt)}encodeStepPrelude(e){this.flushPropertyEdits(e),this.sleeping?.before(e),this.bodyCommands?.flush(e),this.restitution?.before(e)}encodeStepPostlude(e){this.restitution?.after(e),this.sleeping?.after(e)}destroy(){this.passConstantCache=null,this.propertyEdits?.destroy(),!this.destroyed&&(this.detachFromScene(),this.shapeQueries?.destroy(),this.restitution?.destroy(),this.filters?.destroy(),this.shapeBuffer?.destroy(),this.bodyCommands?.destroy(),this.contactWatch?.destroy(),this.sleeping?.destroy(),super.destroy())}enableSleeping(e={}){if(this.destroyed)throw Error("The 2D solver has been destroyed");return this.sleeping?this.sleeping.options=go(e):this.sleeping=new mo(this,e),this}disableSleeping(){if(this.destroyed)throw Error("The 2D solver has been destroyed");return this.sleeping&&(this.sleeping.wakeRequested=!0,this.sleeping.before(),this.sleeping.destroy(),this.sleeping=null),this}setSleepEnabled(e,t){if(this.liveIndex(e),typeof t!="boolean")throw Error("Sleep flag must be boolean");return this.sleepEligible.set(e,t),t&&!this.sleeping&&this.enableSleeping(),this.sleeping?.register(e,t),this.wakeAll(),this}wakeAll(){return this.sleeping&&(this.sleeping.wakeRequested=!0),this}wakeUp(e){return this.liveIndex(e),this.wakeAll()}async readSleepStats(){return this.sleeping?this.sleeping.readStats():{sleeping:0,wakeRequested:!1}}flushEdits(){this.flushPropertyEdits(),this.sleeping?.wakeRequested&&this.sleeping.before(),this.bodyCommands?.flush()}flushPropertyEdits(e){this.propertyEdits?.flush(e)}readJoints(){return this.flushPropertyEdits(),super.readJoints()}attachToScene(e,{maxSubSteps:t=6,maxFrameTime:i=.05,afterStep:r}={}){if(this.destroyed)throw Error("The 2D solver has been destroyed");if(!e?.onBeforeRenderObservable?.add||!e?.onDisposeObservable?.addOnce||!e?.getEngine)throw Error("A Babylon scene is required");if(!Number.isInteger(t)||t<1||!Number.isFinite(i)||i<=0||r!==void 0&&typeof r!="function")throw Error("Scene stepping requires positive frame limits and an optional afterStep function");if(this.sceneBinding){if(this.sceneBinding.scene===e)return this;throw Error("The 2D solver is already attached to another scene")}let o=0,n=e.onBeforeRenderObservable.add(()=>{let l=this.params.dt;if(!(l>0)||!Number.isFinite(l))throw Error("Simulation timestep must be positive and finite");let c=e.getEngine().getDeltaTime()/1e3;o=Math.min(t*l,o+Math.min(i,Math.max(0,c)));for(let u=0;o+1e-12>=l&&u<t&&(this.step(),o=Math.max(0,o-l),r?.(this),!(!this.sceneBinding||this.destroyed));u++);}),a=e.onDisposeObservable.addOnce(()=>this.destroy());return this.sceneBinding={scene:e,before:n,dispose:a},this}detachFromScene(){let e=this.sceneBinding;return e&&(e.scene.onBeforeRenderObservable.remove(e.before),e.scene.onDisposeObservable.remove(e.dispose),this.sceneBinding=null),this}};var So=s=>{if(!Number.isInteger(s)||s<0||s>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");return s};function me(s,e,t){let i=s&&typeof s.x=="number"?[s.x,s.y,...e>=3?[s.z]:[],...e===4?[s.w]:[]]:Array.isArray(s)||ArrayBuffer.isView(s)&&!(s instanceof DataView)?s:Array.from(s??[]);if(i.length!==e||!i.every(Number.isFinite))throw Error(`${t} requires ${e} finite components`);return i}var Kl=["linearVelocity","angularVelocity","impulse","force","","angularImpulse","torque"];function Qu(s,e){if(this.destroyed)throw Error("The solver has been destroyed");let t=this.editInProgress,i=t?new ei:this.editStaging??=new ei;this.editInProgress=!0;try{return Ku.call(this,s,e,i)}finally{this.editInProgress=t}}function Ku(s,e,t){t.count=0;let i,r=(o,n)=>{if(e===3)return me(o,3,n);if(!Number.isFinite(o))throw Error(`${n} must be finite`);return[o,0,0]};for(let o of s){let n=this.bodyIndex(o.body),{isTrigger:a,restitution:l,group:c,collidesWith:u,allowSleep:f}=o;if(a!==void 0||l!==void 0||c!==void 0||u!==void 0||f!==void 0){if(a!==void 0&&typeof a!="boolean")throw Error("isTrigger must be a boolean");if(f!==void 0&&typeof f!="boolean")throw Error("allowSleep must be a boolean");if(l!==void 0&&(!Number.isFinite(l)||l<0||l>1))throw Error("restitution must be between 0 and 1");if(u!==void 0&&c===void 0)throw Error("A collision-mask edit requires group as well");c!==void 0&&So(c),u!==void 0&&So(u),(i??=[]).push({index:n,isTrigger:a,restitution:l,group:c,collidesWith:u??4294967295,allowSleep:f})}let d=o.worldPoint===void 0?void 0:me(o.worldPoint,e,"worldPoint");if(o.position!==void 0){let p=me(o.position,e,"position"),g;if(o.rotation!==void 0){if(g=e===3?me(o.rotation,4,"rotation"):[o.rotation],e===3){let h=Math.hypot(...g);if(!h)throw Error("rotation must be nonzero");g=g.map(m=>m/h)}else if(!Number.isFinite(o.rotation))throw Error("angle must be finite")}t.append(n,4,p,e===3?g:void 0,g!==void 0),e===2&&(t.words[(t.count-1)*12+6]=g?.[0]??0)}else if(o.rotation!==void 0)throw Error("A rotation edit requires position; use teleport for a full pose");for(let p=0;p<Kl.length;p++){if(p===4)continue;let g=Kl[p];if(o[g]===void 0)continue;let m=p===1||p>=5?r(o[g],g):me(o[g],e,g);t.append(n,p,m,p===2||p===3?d:void 0,(p===2||p===3)&&d!==void 0),(p===3||p===6)&&(t.words[(t.count-1)*12+7]=this.params.dt)}}if(this.destroyed)throw Error("The solver was destroyed while reading body edits");t.count&&this.prepareBodyCommands().enqueueValidated(t);for(let o of i??[])o.isTrigger!==void 0&&this.setSensor(o.index,o.isTrigger),o.restitution!==void 0&&this.setRestitution(o.index,o.restitution),o.group!==void 0&&this.setFilters([o.index],[o.group],[o.collidesWith]),o.allowSleep!==void 0&&this.setSleepEnabled(o.index,o.allowSleep);return this}var ko=class{constructor(e,t){this.solver=e,this.index=t}get gpuIndex(){return this.solver.liveIndex(this.index),this.index}setLinearVelocity(e){return this.solver.setLinearVelocity(this.gpuIndex,e),this}setAngularVelocity(e){return this.solver.setAngularVelocity(this.gpuIndex,e),this}applyImpulse(e,t){return this.solver.applyImpulse(this.gpuIndex,e,t),this}applyForce(e,t){return this.solver.applyForce(this.gpuIndex,e,t),this}applyAngularImpulse(e){return this.solver.applyAngularImpulse(this.gpuIndex,e),this}applyTorque(e){return this.solver.applyTorque(this.gpuIndex,e),this}teleport(e,t){return this.solver.teleport(this.gpuIndex,e,t),this}setTrigger(e){return this.solver.setSensor(this.gpuIndex,e),this.solver.wakeAll(),this}setRestitution(e){return this.solver.setRestitution(this.gpuIndex,e),this.solver.wakeAll(),this}setCollisionGroups(e,t=4294967295){return this.solver.setFilters([this.gpuIndex],[So(e)],[So(t)]),this.solver.wakeAll(),this}setSleepEnabled(e){return this.solver.setSleepEnabled(this.gpuIndex,e),this}wakeUp(){return this.solver.liveIndex(this.index),this.solver.wakeAll(),this}readState(){return this.solver.readBodyState(this.gpuIndex)}};function Zl(s,{maxSubSteps:e=6,maxFrameTime:t=.05}={}){if(!Number.isInteger(e)||e<1||!Number.isFinite(t)||t<=0)throw Error("Stepping limits must be positive");let i=s.params.dt;if(!Number.isFinite(i)||i<=0)throw Error("Simulation timestep must be positive and finite");return{dt:i,maxSubSteps:e,maxFrameTime:t}}function ec(s,e,t,i){if(s.destroyed)throw Error("The solver has been destroyed");if(!Number.isFinite(e)||e<0)throw Error("elapsed must be finite nonnegative seconds");let{dt:r,maxSubSteps:o,maxFrameTime:n}=Zl(s,t);s.timeAccumulator=Math.min(o*r,(s.timeAccumulator??0)+Math.min(n,e));let a=0;for(;s.timeAccumulator+1e-12>=r&&a<o;)s.step(),s.timeAccumulator=Math.max(0,s.timeAccumulator-r),a++,i?.(s);return a}function Zu(s,e){return ec(this,s,e)}function Po(s,{afterStep:e,...t}={}){if(this.destroyed)throw Error("The solver has been destroyed");if(!s?.onBeforeRenderObservable?.add||!s?.onDisposeObservable?.addOnce||!s?.getEngine)throw Error("A Babylon scene is required");if(e!==void 0&&typeof e!="function")throw Error("afterStep must be a function");if(Zl(this,t),this.sceneBinding){if(this.sceneBinding.scene===s)return this;throw Error("The solver is already attached to another scene")}let i=s.onBeforeRenderObservable.add(()=>{ec(this,Math.max(0,s.getEngine().getDeltaTime()/1e3),t,e)}),r=s.onDisposeObservable.addOnce(()=>this.destroy());return this.sceneBinding={scene:s,before:i,dispose:r},this}function Lo(){let s=this.sceneBinding;return s&&(s.scene.onBeforeRenderObservable.remove(s.before),s.scene.onDisposeObservable.remove(s.dispose),this.sceneBinding=null,this.timeAccumulator=0),this}function zr(s,e,t,i={}){s.advance=Zu;let r,o;s.bodyIndex=function(a){if(this.destroyed)throw Error("The solver has been destroyed");let l=a;if(a instanceof ko){if(a.solver!==this)throw Error("Body belongs to another solver");return a.gpuIndex}return typeof l!="number"&&t===3&&(o||(o=new WeakMap,e.bodies.forEach((c,u)=>o.set(c,this.gpuIndex(u)))),l=o.get(a)),this.liveIndex(l),l},s.body=function(a){let l=this.bodyIndex(a);return r??=new Map,r.has(l)||r.set(l,new ko(this,l)),r.get(l)},s.editBodies=function(a){return Qu.call(this,a,t)},s.setLinearVelocities=function(a,l){if(this.destroyed)throw Error("The solver has been destroyed");return i.setVelocities?i.setVelocities.call(this,a,{linear:l}):(this.velocityBatch??=new Qt(this,t),this.velocityBatch.set(a,l),this)},s.setVelocities=function(a,l){if(this.destroyed)throw Error("The solver has been destroyed");return i.setVelocities?i.setVelocities.call(this,a,l):l?.angular===void 0&&l?.linear!==void 0?this.setLinearVelocities(a,l.linear):l?.linear===void 0&&l?.angular!==void 0?this.setAngularVelocities(a,l.angular):(this.motionBatch??=new gi(this,t),this.motionBatch.set(a,l),this)},s.setAngularVelocities=function(a,l){if(this.destroyed)throw Error("The solver has been destroyed");return i.setVelocities?i.setVelocities.call(this,a,{angular:l}):(this.angularVelocityBatch??=new Qt(this,t,"angular"),this.angularVelocityBatch.set(a,l),this)};let n=s.destroy;return s.destroy=function(){this.destroyed||(this.velocityBatch?.destroy(),this.angularVelocityBatch?.destroy(),this.motionBatch?.destroy(),this.bodyReadback?.destroy(),this.editStaging=null,n.call(this),r?.clear(),o=null,e=null)},i.readSelectedBodies?s.readSelectedBodies=i.readSelectedBodies:t===2&&(s.readSelectedBodies=function(a,{posesOnly:l=!1}={}){let c=a instanceof Uint32Array?a:Array.from(a);return c.forEach(u=>this.liveIndex(u)),this.flushEdits(),this.bodyReadback??=new bi(this.device),this.bodyReadback.read(this.bodyBuffer,c,l,6)}),s}var _o=class extends Co{constructor(e,t,i){super(e,t,i),zr(this,null,2)}};var sa=`struct Body { pos:vec4f, rot:vec4f, initialPos:vec4f, initialRot:vec4f, size:vec4f, moment:vec4f, inertialPos:vec4f, inertialRot:vec4f, velocity:vec4f, angular:vec4f }
5010
+ let bound`);this.compile(l,[this.layouts.solve,this.layouts.pass],["warmStartJoints","warmStartBodies","primal","primalScan","dual","refreshStick","updateVelocities"]);let c=qr.replaceAll("if (gid.x >= topoCount()) { return; }",`if (gid.x >= topoCount()) { return; }
5011
+ if((contacts[gid.x].ids.w&0x80000000u)!=0u){return;}`);this.compile(c,[this.layouts.topo],["degreeContacts","fillContacts"])}this.sensorsEnabled&&le(this).float(this.bodyBuffer,e*24+7,t?1:0),this.triggers??=new Set,t?this.triggers.add(e):this.triggers.delete(e)}compile(e,t,i){e.includes("fn warmStartBodies(")&&(e=Ic(Oc(Gc(e)))),e.includes("fn dynamicBody(")&&(e=Tc(e));let r=e.includes("fn colorCount(");r&&(this.colorBucketSource=La(oo(e)),e=La(e));let o=this.device,n=o.createShaderModule({code:e}),a=o.createPipelineLayout({bindGroupLayouts:t});for(let l of i)this.pipes[l]=o.createComputePipeline({layout:a,compute:{module:n,entryPoint:l}});r&&i.includes("colorCount")&&(this.colorBucketPipelines={scan:this.pipes.colorCount},this.bitsetColorBuckets=void 0)}watchContacts({maxPairs:e=8192,maxEvents:t=4096,indices:i}={}){if(this.destroyed)throw Error("The 2D solver has been destroyed");if(i!==void 0){if(!Array.isArray(i))throw Error("Watched indices must be an array of live body indices");for(let r of i)this.liveIndex(r)}for(let r of[e,t])if(!Number.isInteger(r)||r<1)throw Error("Contact capacities must be positive integers");return this.contactWatch||(this.contactWatch=new xi(this.device,this.bodyBuffer,this.bodyCapacity,e,t,2),i===void 0&&this.contactWatch.setWatched(Array.from({length:this.bodyCount},(r,o)=>o),Array(this.bodyCount).fill(!0))),i!==void 0&&(this.watchedIndices=new Set(i),this.contactWatch.setWatched(Array.from({length:this.bodyCount},(r,o)=>o),Array.from({length:this.bodyCount},(r,o)=>this.watchedIndices.has(o)))),this}async readContactEvents(){this.watchContacts();let e=await this.contactWatch.read();return{...e,events:e.events.map(t=>({...t,type:t.kind===Ai?"begin":"end",isTrigger:!!(this.triggers?.has(t.a)||this.triggers?.has(t.b))}))}}step(){if(this.destroyed)throw Error("The 2D solver has been destroyed");no(this,this.colorBucketSource),this.sleeping||this.restitution?.active.size||this.bodyCommands?.pending.size||this.propertyEdits?.pending||this.externalBeforeStep||this.externalAfterStep?jc.call(this):super.step(),this.contactWatch&&this.contactWatch.run({manifolds:this.contactBuffers[1-this.parity],contacts:this.contactBuffers[1-this.parity],counters:this.counterBuffer},this.contactCapacity,this.eventStep=(this.eventStep??0)+1,this.params.dt)}adapt(e){super.adapt(e),this.colorCap=Math.max(this.colorCap,this.minimumColors)}encodeStepPrelude(e){this.flushPropertyEdits(e),this.sleeping?.before(e),this.bodyCommands?.flush(e),this.restitution?.before(e),this.externalBeforeStep?.(e)}encodeStepPostlude(e){this.restitution?.after(e),this.sleeping?.after(e),this.externalAfterStep?.(e)}destroy(){this.passConstantCache=null,this.propertyEdits?.destroy(),!this.destroyed&&(this.detachFromScene(),this.shapeQueries?.destroy(),this.restitution?.destroy(),this.filters?.destroy(),this.shapeBuffer?.destroy(),this.bodyCommands?.destroy(),this.contactWatch?.destroy(),this.sleeping?.destroy(),super.destroy())}enableSleeping(e={}){if(this.destroyed)throw Error("The 2D solver has been destroyed");return this.sleeping?this.sleeping.options=Do(e):this.sleeping=new jo(this,e),this}disableSleeping(){if(this.destroyed)throw Error("The 2D solver has been destroyed");return this.sleeping&&(this.sleeping.wakeRequested=!0,this.sleeping.before(),this.sleeping.destroy(),this.sleeping=null),this}setSleepEnabled(e,t){if(this.liveIndex(e),typeof t!="boolean")throw Error("Sleep flag must be boolean");return this.sleepEligible.set(e,t),t&&!this.sleeping&&this.enableSleeping(),this.sleeping?.register(e,t),this.wakeAll(),this}wakeAll(){return this.sleeping&&(this.sleeping.wakeRequested=!0),this}wakeUp(e){return this.liveIndex(e),this.wakeAll()}async readSleepStats(){return this.sleeping?this.sleeping.readStats():{sleeping:0,wakeRequested:!1}}flushEdits(){this.flushPropertyEdits(),this.sleeping?.wakeRequested&&this.sleeping.before(),this.bodyCommands?.flush()}flushPropertyEdits(e){this.propertyEdits?.flush(e)}readJoints(){return this.flushPropertyEdits(),super.readJoints()}attachToScene(e,{maxSubSteps:t=6,maxFrameTime:i=.05,afterStep:r}={}){if(this.destroyed)throw Error("The 2D solver has been destroyed");if(!e?.onBeforeRenderObservable?.add||!e?.onDisposeObservable?.addOnce||!e?.getEngine)throw Error("A Babylon scene is required");if(!Number.isInteger(t)||t<1||!Number.isFinite(i)||i<=0||r!==void 0&&typeof r!="function")throw Error("Scene stepping requires positive frame limits and an optional afterStep function");if(this.sceneBinding){if(this.sceneBinding.scene===e)return this;throw Error("The 2D solver is already attached to another scene")}let o=0,n=e.onBeforeRenderObservable.add(()=>{let l=this.params.dt;if(!(l>0)||!Number.isFinite(l))throw Error("Simulation timestep must be positive and finite");let c=e.getEngine().getDeltaTime()/1e3;o=Math.min(t*l,o+Math.min(i,Math.max(0,c)));for(let u=0;o+1e-12>=l&&u<t&&(this.step(),o=Math.max(0,o-l),r?.(this),!(!this.sceneBinding||this.destroyed));u++);}),a=e.onDisposeObservable.addOnce(()=>this.destroy());return this.sceneBinding={scene:e,before:n,dispose:a},this}detachFromScene(){let e=this.sceneBinding;return e&&(e.scene.onBeforeRenderObservable.remove(e.before),e.scene.onDisposeObservable.remove(e.dispose),this.sceneBinding=null),this}};var $o=s=>{if(!Number.isInteger(s)||s<0||s>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");return s};function me(s,e,t){let i=s&&typeof s.x=="number"?[s.x,s.y,...e>=3?[s.z]:[],...e===4?[s.w]:[]]:Array.isArray(s)||ArrayBuffer.isView(s)&&!(s instanceof DataView)?s:Array.from(s??[]);if(i.length!==e||!i.every(Number.isFinite))throw Error(`${t} requires ${e} finite components`);return i}var Vc=["linearVelocity","angularVelocity","impulse","force","","angularImpulse","torque"];function Jf(s,e){if(this.destroyed)throw Error("The solver has been destroyed");let t=this.editInProgress,i=t?new ti:this.editStaging??=new ti;this.editInProgress=!0;try{return Xf.call(this,s,e,i)}finally{this.editInProgress=t}}function Xf(s,e,t){t.count=0;let i,r=(o,n)=>{if(e===3)return me(o,3,n);if(!Number.isFinite(o))throw Error(`${n} must be finite`);return[o,0,0]};for(let o of s){let n=this.bodyIndex(o.body),{isTrigger:a,restitution:l,group:c,collidesWith:u,allowSleep:f}=o;if(a!==void 0||l!==void 0||c!==void 0||u!==void 0||f!==void 0){if(a!==void 0&&typeof a!="boolean")throw Error("isTrigger must be a boolean");if(f!==void 0&&typeof f!="boolean")throw Error("allowSleep must be a boolean");if(l!==void 0&&(!Number.isFinite(l)||l<0||l>1))throw Error("restitution must be between 0 and 1");if(u!==void 0&&c===void 0)throw Error("A collision-mask edit requires group as well");c!==void 0&&$o(c),u!==void 0&&$o(u),(i??=[]).push({index:n,isTrigger:a,restitution:l,group:c,collidesWith:u??4294967295,allowSleep:f})}let d=o.worldPoint===void 0?void 0:me(o.worldPoint,e,"worldPoint");if(o.position!==void 0){let p=me(o.position,e,"position"),m;if(o.rotation!==void 0){if(m=e===3?me(o.rotation,4,"rotation"):[o.rotation],e===3){let h=Math.hypot(...m);if(!h)throw Error("rotation must be nonzero");m=m.map(g=>g/h)}else if(!Number.isFinite(o.rotation))throw Error("angle must be finite")}t.append(n,4,p,e===3?m:void 0,m!==void 0),e===2&&(t.words[(t.count-1)*12+6]=m?.[0]??0)}else if(o.rotation!==void 0)throw Error("A rotation edit requires position; use teleport for a full pose");for(let p=0;p<Vc.length;p++){if(p===4)continue;let m=Vc[p];if(o[m]===void 0)continue;let g=p===1||p>=5?r(o[m],m):me(o[m],e,m);t.append(n,p,g,p===2||p===3?d:void 0,(p===2||p===3)&&d!==void 0),(p===3||p===6)&&(t.words[(t.count-1)*12+7]=this.params.dt)}}if(this.destroyed)throw Error("The solver was destroyed while reading body edits");t.count&&this.prepareBodyCommands().enqueueValidated(t);for(let o of i??[])o.isTrigger!==void 0&&this.setSensor(o.index,o.isTrigger),o.restitution!==void 0&&this.setRestitution(o.index,o.restitution),o.group!==void 0&&this.setFilters([o.index],[o.group],[o.collidesWith]),o.allowSleep!==void 0&&this.setSleepEnabled(o.index,o.allowSleep);return this}var Jo=class{constructor(e,t){this.solver=e,this.index=t}get gpuIndex(){return this.solver.liveIndex(this.index),this.index}setLinearVelocity(e){return this.solver.setLinearVelocity(this.gpuIndex,e),this}setAngularVelocity(e){return this.solver.setAngularVelocity(this.gpuIndex,e),this}applyImpulse(e,t){return this.solver.applyImpulse(this.gpuIndex,e,t),this}applyForce(e,t){return this.solver.applyForce(this.gpuIndex,e,t),this}applyAngularImpulse(e){return this.solver.applyAngularImpulse(this.gpuIndex,e),this}applyTorque(e){return this.solver.applyTorque(this.gpuIndex,e),this}teleport(e,t){return this.solver.teleport(this.gpuIndex,e,t),this}setTrigger(e){return this.solver.setSensor(this.gpuIndex,e),this.solver.wakeAll(),this}setRestitution(e){return this.solver.setRestitution(this.gpuIndex,e),this.solver.wakeAll(),this}setCollisionGroups(e,t=4294967295){return this.solver.setFilters([this.gpuIndex],[$o(e)],[$o(t)]),this.solver.wakeAll(),this}setSleepEnabled(e){return this.solver.setSleepEnabled(this.gpuIndex,e),this}wakeUp(){return this.solver.liveIndex(this.index),this.solver.wakeAll(),this}readState(){return this.solver.readBodyState(this.gpuIndex)}};function Wc(s,{maxSubSteps:e=6,maxFrameTime:t=.05}={}){if(!Number.isInteger(e)||e<1||!Number.isFinite(t)||t<=0)throw Error("Stepping limits must be positive");let i=s.params.dt;if(!Number.isFinite(i)||i<=0)throw Error("Simulation timestep must be positive and finite");return{dt:i,maxSubSteps:e,maxFrameTime:t}}function Hc(s,e,t,i){if(s.destroyed)throw Error("The solver has been destroyed");if(!Number.isFinite(e)||e<0)throw Error("elapsed must be finite nonnegative seconds");let{dt:r,maxSubSteps:o,maxFrameTime:n}=Wc(s,t);s.timeAccumulator=Math.min(o*r,(s.timeAccumulator??0)+Math.min(n,e));let a=0;for(;s.timeAccumulator+1e-12>=r&&a<o;)s.step(),s.timeAccumulator=Math.max(0,s.timeAccumulator-r),a++,i?.(s);return a}function Yf(s,e){return Hc(this,s,e)}function Xo(s,{afterStep:e,...t}={}){if(this.destroyed)throw Error("The solver has been destroyed");if(!s?.onBeforeRenderObservable?.add||!s?.onDisposeObservable?.addOnce||!s?.getEngine)throw Error("A Babylon scene is required");if(e!==void 0&&typeof e!="function")throw Error("afterStep must be a function");if(Wc(this,t),this.sceneBinding){if(this.sceneBinding.scene===s)return this;throw Error("The solver is already attached to another scene")}let i=s.onBeforeRenderObservable.add(()=>{Hc(this,Math.max(0,s.getEngine().getDeltaTime()/1e3),t,e)}),r=s.onDisposeObservable.addOnce(()=>this.destroy());return this.sceneBinding={scene:s,before:i,dispose:r},this}function Yo(){let s=this.sceneBinding;return s&&(s.scene.onBeforeRenderObservable.remove(s.before),s.scene.onDisposeObservable.remove(s.dispose),this.sceneBinding=null,this.timeAccumulator=0),this}function Tr(s,e,t,i={}){s.advance=Yf;let r,o;s.bodyIndex=function(a){if(this.destroyed)throw Error("The solver has been destroyed");let l=a;if(a instanceof Jo){if(a.solver!==this)throw Error("Body belongs to another solver");return a.gpuIndex}return typeof l!="number"&&t===3&&(o||(o=new WeakMap,e.bodies.forEach((c,u)=>o.set(c,this.gpuIndex(u)))),l=o.get(a)),this.liveIndex(l),l},s.body=function(a){let l=this.bodyIndex(a);return r??=new Map,r.has(l)||r.set(l,new Jo(this,l)),r.get(l)},s.editBodies=function(a){return Jf.call(this,a,t)},s.setLinearVelocities=function(a,l){if(this.destroyed)throw Error("The solver has been destroyed");return i.setVelocities?i.setVelocities.call(this,a,{linear:l}):(this.velocityBatch??=new Kt(this,t),this.velocityBatch.set(a,l),this)},s.setVelocities=function(a,l){if(this.destroyed)throw Error("The solver has been destroyed");return i.setVelocities?i.setVelocities.call(this,a,l):l?.angular===void 0&&l?.linear!==void 0?this.setLinearVelocities(a,l.linear):l?.linear===void 0&&l?.angular!==void 0?this.setAngularVelocities(a,l.angular):(this.motionBatch??=new yi(this,t),this.motionBatch.set(a,l),this)},s.setAngularVelocities=function(a,l){if(this.destroyed)throw Error("The solver has been destroyed");return i.setVelocities?i.setVelocities.call(this,a,{angular:l}):(this.angularVelocityBatch??=new Kt(this,t,"angular"),this.angularVelocityBatch.set(a,l),this)};let n=s.destroy;return s.destroy=function(){this.destroyed||(this.velocityBatch?.destroy(),this.angularVelocityBatch?.destroy(),this.motionBatch?.destroy(),this.bodyReadback?.destroy(),this.editStaging=null,n.call(this),r?.clear(),o=null,e=null)},i.readSelectedBodies?s.readSelectedBodies=i.readSelectedBodies:t===2&&(s.readSelectedBodies=function(a,{posesOnly:l=!1}={}){let c=a instanceof Uint32Array?a:Array.from(a);return c.forEach(u=>this.liveIndex(u)),this.flushEdits(),this.bodyReadback??=new vi(this.device),this.bodyReadback.read(this.bodyBuffer,c,l,6)}),s}var Qo=class extends Ho{constructor(e,t,i){super(e,t,i),Tr(this,null,2)}};var Ea=`struct Body { pos:vec4f, rot:vec4f, initialPos:vec4f, initialRot:vec4f, size:vec4f, moment:vec4f, inertialPos:vec4f, inertialRot:vec4f, velocity:vec4f, angular:vec4f }
4800
5012
  struct Command { header:vec4u, value:vec4f, point:vec4f }
4801
5013
  struct Manifold { ids:vec4u, geo:vec4f }
4802
5014
  @group(0) @binding(0) var<storage,read_write> bodies:array<Body>;
@@ -4849,26 +5061,26 @@ fn angularImpulse(b:Body,impulse:vec3f)->vec3f {
4849
5061
  let index=commands[ranges[i].x].header.x;
4850
5062
  if(bodies[index].initialPos.w<0.){bodies[index].initialPos.w=-bodies[index].initialPos.w-1.;}
4851
5063
  }
4852
- `;var oa=class extends Mr{constructor(e){super(e,sa,3)}encodeAfterEdits(e,t){if(!this.hasTeleports)return;let i=this.solver,r=i.device;if(!this.invalidate){let c=r.createShaderModule({code:`const DISPATCH_STRIDE = ${r.limits.maxComputeWorkgroupsPerDimension*64}u;
4853
- ${sa}`});this.invalidate=r.createComputePipeline({layout:"auto",compute:{module:c,entryPoint:"invalidate"}}),this.clearMarkers=r.createComputePipeline({layout:"auto",compute:{module:c,entryPoint:"clearMarkers"}})}(this.invalidateBody!==i.bodyBuffer||this.invalidateManifolds!==i.contactStorage.manifolds)&&(this.invalidateGroup=r.createBindGroup({layout:this.invalidate.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:i.bodyBuffer}},{binding:3,resource:{buffer:i.contactStorage.manifolds}}]}),this.invalidateBody=i.bodyBuffer,this.invalidateManifolds=i.contactStorage.manifolds);let o=e.beginComputePass();o.setPipeline(this.invalidate),o.setBindGroup(0,this.invalidateGroup);let n=Math.ceil(i.manifoldCapacity/64),a=r.limits.maxComputeWorkgroupsPerDimension;o.dispatchWorkgroups(Math.min(n,a),Math.ceil(n/a)),o.end(),(this.markerBody!==i.bodyBuffer||this.markerCommands!==this.commands||this.markerRanges!==this.ranges||this.markerBytes!==t*8)&&(this.markerGroup=r.createBindGroup({layout:this.clearMarkers.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:i.bodyBuffer}},{binding:1,resource:{buffer:this.commands}},{binding:2,resource:{buffer:this.ranges,size:t*8}}]}),this.markerBody=i.bodyBuffer,this.markerCommands=this.commands,this.markerRanges=this.ranges,this.markerBytes=t*8),o=e.beginComputePass(),o.setPipeline(this.clearMarkers),o.setBindGroup(0,this.markerGroup);let l=Math.ceil(t/64);o.dispatchWorkgroups(Math.min(l,a),Math.ceil(l/a)),o.end()}},Eo=class extends pi{constructor(e,t,i){super(e,t,i),this.nativeRef=t,zr(this,{bodies:t.bodies},3)}rigidAt(e){return this.nativeBodies||(this.nativeBodies=[],this.nativeRef.bodies.forEach((t,i)=>this.nativeBodies[this.gpuIndex(i)]=t)),this.nativeBodies[e]}rewriteBodies(e,t){if(super.rewriteBodies(e,t),this.nativeBodies)for(let i=0;i<e.length;i++)this.nativeBodies[e[i]]=t[i]}liveIndex(e){if(this.destroyed)throw Error("The 3D solver has been destroyed");if(!Number.isInteger(e)||e<0||e>=this.bodyCount)throw Error("A live 3D GPU body index is required")}queueBodyCommand(e,t,i,r,o=!1){return this.liveIndex(e),this.prepareBodyCommands(),this.bodyCommands.enqueue(e,t,i,r,o),this}prepareBodyCommands(){return this.wakeAll(),this.bodyCommands??=new oa(this)}setLinearVelocity(e,t){return this.queueBodyCommand(e,0,me(t,3,"velocity"))}setAngularVelocity(e,t){return this.queueBodyCommand(e,1,me(t,3,"angular velocity"))}applyImpulse(e,t,i){return this.queueBodyCommand(e,2,me(t,3,"impulse"),i===void 0?void 0:me(i,3,"point"),i!==void 0)}applyForce(e,t,i){return this.queueBodyCommand(e,3,[...me(t,3,"force"),this.params.dt],i===void 0?void 0:me(i,3,"point"),i!==void 0)}applyAngularImpulse(e,t){return this.queueBodyCommand(e,5,me(t,3,"angular impulse"))}applyTorque(e,t){return this.queueBodyCommand(e,6,[...me(t,3,"torque"),this.params.dt])}teleport(e,t,i){let r=me(t,3,"position"),o;if(i!==void 0){o=me(i,4,"rotation");let n=Math.hypot(...o);if(!n)throw Error("rotation must be nonzero");o=o.map(a=>a/n)}return this.queueBodyCommand(e,4,r,o,o!==void 0)}flushEdits(){if(this.destroyed)throw Error("The 3D solver has been destroyed");this.flushPropertyEdits(),this.sleeping?.wakeRequested&&this.sleeping.before(),this.bodyCommands?.flush()}readBodies(){return this.flushEdits(),super.readBodies()}readSelectedBodies(e,{posesOnly:t=!1}={}){let i=e instanceof Uint32Array?e:Array.from(e);return i.forEach(r=>this.liveIndex(r)),this.flushEdits(),this.bodyReadback??=new bi(this.device),this.bodyReadback.read(this.bodyBuffer,i,t)}async readBodyState(e){let t=await this.readSelectedBodies([e]),i=this.rigidAt(e)?.mass??t[19];return{position:Array.from(t.subarray(0,3)),rotation:Array.from(t.subarray(4,8)),linearVelocity:Array.from(t.subarray(32,35)),angularVelocity:Array.from(t.subarray(36,39)),mass:i,effectiveMass:t[19],sleeping:i>0&&t[19]===0}}raycastAll(...e){return this.flushEdits(),super.raycastAll(...e)}sphereCastAll(...e){return this.flushEdits(),super.sphereCastAll(...e)}watchContacts({maxPairs:e=8192,maxEvents:t=4096,indices:i}={}){if(this.destroyed)throw Error("The 3D solver has been destroyed");if(i!==void 0){if(!Array.isArray(i))throw Error("Watched indices must be an array");i.forEach(r=>this.liveIndex(r))}for(let r of[e,t])if(!Number.isInteger(r)||r<1)throw Error("Contact capacities must be positive integers");if(this.contactWatch||(this.contactWatch=new yi(this.device,this.bodyBuffer,this.bodyCapacity,e,t),i===void 0&&(i=Array.from({length:this.bodyCount},(r,o)=>o))),i!==void 0){let r=new Set(i);this.contactWatch.setWatched(Array.from({length:this.bodyCount},(o,n)=>n),Array.from({length:this.bodyCount},(o,n)=>r.has(n)))}return this}async readContactEvents(){this.watchContacts();let e=await this.contactWatch.read();return{...e,events:e.events.map(t=>({...t,type:t.kind===vi?"begin":"end",isTrigger:!!(this.triggers?.has(t.a)||this.triggers?.has(t.b))}))}}setSensor(e,t){super.setSensor(e,t),this.triggers??=new Set,t?this.triggers.add(e):this.triggers.delete(e)}setSleepEnabled(e,t){if(this.liveIndex(e),typeof t!="boolean")throw Error("Sleep flag must be boolean");let i=this.rigidAt(e);if(!i)throw Error("Sleep eligibility requires a scene body");return i.allowSleep=t,t&&!this.sleeping&&this.enableSleeping(),this.sleeping?.register(e,i.mass,t),this.wakeAll(),this}enableSleeping(e={},t={}){let i=e.bodies?e:this.nativeRef;return super.enableSleeping(i,e.bodies?t:e),this}disableSleeping(){return this.flushEdits(),this.sleeping&&(this.sleeping.wakeRequested=!0,this.sleeping.before(),this.sleeping.dispose(),this.sleeping=null),this}attachToScene(e,t){return Po.call(this,e,t)}detachFromScene(){return Lo.call(this)}step(){if(this.destroyed)throw Error("The 3D solver has been destroyed");super.step(),this.contactWatch?.run(this.contactStorage,this.manifoldCapacity,this.stepCount,this.params.dt)}destroy(){this.destroyed||(this.detachFromScene(),this.bodyCommands?.destroy(),this.contactWatch?.destroy(),super.destroy(),this.destroyed=!0)}};function ns(s,e,t){if(s.split(e).length!==2)throw Error("Pinned solver changed; review the cloth kernel integration");return s.replace(e,t)}var ti=ns(ze," if (j >= params.jointCount || info[j].x != T_JOINT) { return; }",` if (j >= params.jointCount) { return; }
5064
+ `;var Ma=class extends Or{constructor(e){super(e,Ea,3)}encodeAfterEdits(e,t){if(!this.hasTeleports)return;let i=this.solver,r=i.device;if(!this.invalidate){let c=r.createShaderModule({code:`const DISPATCH_STRIDE = ${r.limits.maxComputeWorkgroupsPerDimension*64}u;
5065
+ ${Ea}`});this.invalidate=r.createComputePipeline({layout:"auto",compute:{module:c,entryPoint:"invalidate"}}),this.clearMarkers=r.createComputePipeline({layout:"auto",compute:{module:c,entryPoint:"clearMarkers"}})}(this.invalidateBody!==i.bodyBuffer||this.invalidateManifolds!==i.contactStorage.manifolds)&&(this.invalidateGroup=r.createBindGroup({layout:this.invalidate.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:i.bodyBuffer}},{binding:3,resource:{buffer:i.contactStorage.manifolds}}]}),this.invalidateBody=i.bodyBuffer,this.invalidateManifolds=i.contactStorage.manifolds);let o=e.beginComputePass();o.setPipeline(this.invalidate),o.setBindGroup(0,this.invalidateGroup);let n=Math.ceil(i.manifoldCapacity/64),a=r.limits.maxComputeWorkgroupsPerDimension;o.dispatchWorkgroups(Math.min(n,a),Math.ceil(n/a)),o.end(),(this.markerBody!==i.bodyBuffer||this.markerCommands!==this.commands||this.markerRanges!==this.ranges||this.markerBytes!==t*8)&&(this.markerGroup=r.createBindGroup({layout:this.clearMarkers.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:i.bodyBuffer}},{binding:1,resource:{buffer:this.commands}},{binding:2,resource:{buffer:this.ranges,size:t*8}}]}),this.markerBody=i.bodyBuffer,this.markerCommands=this.commands,this.markerRanges=this.ranges,this.markerBytes=t*8),o=e.beginComputePass(),o.setPipeline(this.clearMarkers),o.setBindGroup(0,this.markerGroup);let l=Math.ceil(t/64);o.dispatchWorkgroups(Math.min(l,a),Math.ceil(l/a)),o.end()}},Ko=class extends gi{constructor(e,t,i){super(e,t,i),this.nativeRef=t,Tr(this,{bodies:t.bodies},3)}rigidAt(e){return this.nativeBodies||(this.nativeBodies=[],this.nativeRef.bodies.forEach((t,i)=>this.nativeBodies[this.gpuIndex(i)]=t)),this.nativeBodies[e]}rewriteBodies(e,t){if(super.rewriteBodies(e,t),this.nativeBodies)for(let i=0;i<e.length;i++)this.nativeBodies[e[i]]=t[i]}liveIndex(e){if(this.destroyed)throw Error("The 3D solver has been destroyed");if(!Number.isInteger(e)||e<0||e>=this.bodyCount)throw Error("A live 3D GPU body index is required")}queueBodyCommand(e,t,i,r,o=!1){return this.liveIndex(e),this.prepareBodyCommands(),this.bodyCommands.enqueue(e,t,i,r,o),this}prepareBodyCommands(){return this.wakeAll(),this.bodyCommands??=new Ma(this)}setLinearVelocity(e,t){return this.queueBodyCommand(e,0,me(t,3,"velocity"))}setAngularVelocity(e,t){return this.queueBodyCommand(e,1,me(t,3,"angular velocity"))}applyImpulse(e,t,i){return this.queueBodyCommand(e,2,me(t,3,"impulse"),i===void 0?void 0:me(i,3,"point"),i!==void 0)}applyForce(e,t,i){return this.queueBodyCommand(e,3,[...me(t,3,"force"),this.params.dt],i===void 0?void 0:me(i,3,"point"),i!==void 0)}applyAngularImpulse(e,t){return this.queueBodyCommand(e,5,me(t,3,"angular impulse"))}applyTorque(e,t){return this.queueBodyCommand(e,6,[...me(t,3,"torque"),this.params.dt])}teleport(e,t,i){let r=me(t,3,"position"),o;if(i!==void 0){o=me(i,4,"rotation");let n=Math.hypot(...o);if(!n)throw Error("rotation must be nonzero");o=o.map(a=>a/n)}return this.queueBodyCommand(e,4,r,o,o!==void 0)}flushEdits(){if(this.destroyed)throw Error("The 3D solver has been destroyed");this.flushPropertyEdits(),this.sleeping?.wakeRequested&&this.sleeping.before(),this.bodyCommands?.flush()}readBodies(){return this.flushEdits(),super.readBodies()}readSelectedBodies(e,{posesOnly:t=!1}={}){let i=e instanceof Uint32Array?e:Array.from(e);return i.forEach(r=>this.liveIndex(r)),this.flushEdits(),this.bodyReadback??=new vi(this.device),this.bodyReadback.read(this.bodyBuffer,i,t)}async readBodyState(e){let t=await this.readSelectedBodies([e]),i=this.rigidAt(e)?.mass??t[19];return{position:Array.from(t.subarray(0,3)),rotation:Array.from(t.subarray(4,8)),linearVelocity:Array.from(t.subarray(32,35)),angularVelocity:Array.from(t.subarray(36,39)),mass:i,effectiveMass:t[19],sleeping:i>0&&t[19]===0}}raycastAll(...e){return this.flushEdits(),super.raycastAll(...e)}sphereCastAll(...e){return this.flushEdits(),super.sphereCastAll(...e)}watchContacts({maxPairs:e=8192,maxEvents:t=4096,indices:i}={}){if(this.destroyed)throw Error("The 3D solver has been destroyed");if(i!==void 0){if(!Array.isArray(i))throw Error("Watched indices must be an array");i.forEach(r=>this.liveIndex(r))}for(let r of[e,t])if(!Number.isInteger(r)||r<1)throw Error("Contact capacities must be positive integers");if(this.contactWatch||(this.contactWatch=new xi(this.device,this.bodyBuffer,this.bodyCapacity,e,t),i===void 0&&(i=Array.from({length:this.bodyCount},(r,o)=>o))),i!==void 0){let r=new Set(i);this.contactWatch.setWatched(Array.from({length:this.bodyCount},(o,n)=>n),Array.from({length:this.bodyCount},(o,n)=>r.has(n)))}return this}async readContactEvents(){this.watchContacts();let e=await this.contactWatch.read();return{...e,events:e.events.map(t=>({...t,type:t.kind===Ai?"begin":"end",isTrigger:!!(this.triggers?.has(t.a)||this.triggers?.has(t.b))}))}}setSensor(e,t){super.setSensor(e,t),this.triggers??=new Set,t?this.triggers.add(e):this.triggers.delete(e)}setSleepEnabled(e,t){if(this.liveIndex(e),typeof t!="boolean")throw Error("Sleep flag must be boolean");let i=this.rigidAt(e);if(!i)throw Error("Sleep eligibility requires a scene body");return i.allowSleep=t,t&&!this.sleeping&&this.enableSleeping(),this.sleeping?.register(e,i.mass,t),this.wakeAll(),this}enableSleeping(e={},t={}){let i=e.bodies?e:this.nativeRef;return super.enableSleeping(i,e.bodies?t:e),this}disableSleeping(){return this.flushEdits(),this.sleeping&&(this.sleeping.wakeRequested=!0,this.sleeping.before(),this.sleeping.dispose(),this.sleeping=null),this}attachToScene(e,t){return Xo.call(this,e,t)}detachFromScene(){return Yo.call(this)}step(){if(this.destroyed)throw Error("The 3D solver has been destroyed");super.step(),this.contactWatch?.run(this.contactStorage,this.manifoldCapacity,this.stepCount,this.params.dt)}destroy(){this.destroyed||(this.detachFromScene(),this.bodyCommands?.destroy(),this.contactWatch?.destroy(),super.destroy(),this.destroyed=!0)}};function xs(s,e,t){if(s.split(e).length!==2)throw Error("Pinned solver changed; review the cloth kernel integration");return s.replace(e,t)}var ii=xs(Ge," if (j >= params.jointCount || info[j].x != T_JOINT) { return; }",` if (j >= params.jointCount) { return; }
4854
5066
  if (info[j].x == T_SPRING) {
4855
5067
  // Finite material stiffness: Eq. 16, with no hard-constraint multiplier.
4856
5068
  joints[j].penLin.x = min(joints[j].penLin.w, max(PENALTY_MIN, joints[j].penLin.x * params.gamma));
4857
5069
  return;
4858
5070
  }
4859
- if (info[j].x != T_JOINT) { return; }`);ti=ns(ti," let stiffness = k.penLin.w;"," let stiffness = k.penLin.x;");ti=ns(ti," addRow(acc, n * sg, cross(r, n) * sg, stiffness, stiffness * (len - k.rA.w));",` let force = stiffness * (len - k.rA.w);
5071
+ if (info[j].x != T_JOINT) { return; }`);ii=xs(ii," let stiffness = k.penLin.w;"," let stiffness = k.penLin.x;");ii=xs(ii," addRow(acc, n * sg, cross(r, n) * sg, stiffness, stiffness * (len - k.rA.w));",` let force = stiffness * (len - k.rA.w);
4860
5072
  addRow(acc, n * sg, cross(r, n) * sg, stiffness, force);
4861
5073
  // Eq. 17: positive diagonal lumping of the geometric Hessian's column
4862
5074
  // norms. For C=|xA-xB|-L, G=(force/len)(I-n*n^T).
4863
5075
  let g = abs(force / len) * sqrt(max(vec3f(0.0), vec3f(1.0) - n*n));
4864
- (*acc).lin += mat3x3f(vec3f(g.x,0.0,0.0), vec3f(0.0,g.y,0.0), vec3f(0.0,0.0,g.z));`);ti=ns(ti," if (t != T_JOINT) { return; }",` if (t == T_SPRING) {
5076
+ (*acc).lin += mat3x3f(vec3f(g.x,0.0,0.0), vec3f(0.0,g.y,0.0), vec3f(0.0,0.0,g.z));`);ii=xs(ii," if (t != T_JOINT) { return; }",` if (t == T_SPRING) {
4865
5077
  let a = info[j].y;
4866
5078
  let b = info[j].z;
4867
5079
  let C = length(anchorA(joints[j], a) - (qrotate(bodies[b].rot, joints[j].rB.xyz) + bodies[b].pos.xyz)) - joints[j].rA.w;
4868
5080
  joints[j].penLin.x = min(joints[j].penLin.w, joints[j].penLin.x + params.betaLin * abs(C));
4869
5081
  return;
4870
5082
  }
4871
- if (t != T_JOINT) { return; }`);ti=ns(ti,"fn finishBody(i: u32, acc: Acc) {",`fn finishBody(i: u32, acc: Acc) {
5083
+ if (t != T_JOINT) { return; }`);ii=xs(ii,"fn finishBody(i: u32, acc: Acc) {",`fn finishBody(i: u32, acc: Acc) {
4872
5084
  if (all(bodies[i].moment.xyz == vec3f(0.0))) {
4873
5085
  // LDL^T of the point's 3x3 SPD system, using the same pivot floor as
4874
5086
  // rigid bodies. Contact friction moves the point; it cannot spin it.
@@ -4886,4 +5098,251 @@ ${sa}`});this.invalidate=r.createComputePipeline({layout:"auto",compute:{module:
4886
5098
  let v1 = y1/d1 - l21*v2 - l31*v3;
4887
5099
  bodies[i].pos = vec4f(bodies[i].pos.xyz - vec3f(v1,v2,v3), bodies[i].pos.w);
4888
5100
  return;
4889
- }`);var tc=ti;var nc=8,ic=16,$i=1e-6,aa=1e-5,tf=1e-6,la=34028234663852886e22,Mo=0,ac=1,zo=2;function rc(s){let e=s.positionAng;return{center:s.positionLin,half:ne(C(),s.size,.5),axis:[ae(C(),e,[1,0,0]),ae(C(),e,[0,1,0]),ae(C(),e,[0,0,1])]}}var Ji=(s,e)=>Math.abs(V(s,e));function Io(s,e){let t=V(e,s.axis[0])>=0?1:-1,i=V(e,s.axis[1])>=0?1:-1,r=V(e,s.axis[2])>=0?1:-1,o=D(C(),s.center,s.axis[0],s.half[0]*t);return D(o,o,s.axis[1],s.half[1]*i),D(o,o,s.axis[2],s.half[2]*r)}function lc(s,e){return e===0?{u:s.axis[1],v:s.axis[2],extentU:s.half[1],extentV:s.half[2]}:e===1?{u:s.axis[0],v:s.axis[2],extentU:s.half[0],extentV:s.half[2]}:{u:s.axis[0],v:s.axis[1],extentU:s.half[0],extentV:s.half[1]}}function rf(s,e,t){let i=V(t,s.axis[e])>=0?1:-1,r=ne(C(),s.axis[e],i),o=D(C(),s.center,r,s.half[e]);return{normal:r,center:o,...lc(s,e)}}function sf(s,e){let t=0,i=-la;for(let r=0;r<3;r++){let o=Ji(s.axis[r],e);o>i&&(i=o,t=r)}return t}function of(s,e,t){let i=V(s.axis[e],t)>0?-1:1,r=ne(C(),s.axis[e],i),o=D(C(),s.center,r,s.half[e]),{u:n,v:a,extentU:l,extentV:c}=lc(s,e),u=(f,d)=>{let p=D(C(),o,n,f*l);return D(p,p,a,d*c)};return[u(1,1),u(-1,1),u(-1,-1),u(1,-1)]}function nf(s,e,t){let i=[];if(s.length===0)return i;let r=s[s.length-1],o=V(e,r)-t;for(let n of s){let a=V(e,n)-t,l=o<=aa,c=a<=aa;if(l!==c){let u=0,f=o-a;Math.abs(f)>$i&&(u=ce(o/f,0,1)),i.length<ic&&i.push(D(C(),r,$(C(),n,r),u))}c&&i.length<ic&&i.push(n),r=n,o=a}return i}var Ro=class{contacts=[];midpoints=[];bodyA;bodyB;constructor(e,t){this.bodyA=e,this.bodyB=t}add(e,t,i){let r=ne(C(),ki(C(),e,t),.5);for(let a of this.midpoints)if(Ge($(C(),r,a))<tf)return;if(this.contacts.length>=nc)return;let{bodyA:o,bodyB:n}=this;this.contacts.push({feature:i,rA:Te(C(),o.positionAng,$(C(),e,o.positionLin)),rB:Te(C(),n.positionAng,$(C(),t,n.positionLin))}),this.midpoints.push(r)}};function na(s,e,t,i,r,o,n,a){let l=Ge(i);if(l<$i)return!0;let c=1/Math.sqrt(l),u=ne(C(),i,c);V(u,t)<0&&ee(u,u);let f=Math.abs(V(t,u)),d=s.half[0]*Ji(u,s.axis[0])+s.half[1]*Ji(u,s.axis[1])+s.half[2]*Ji(u,s.axis[2]),p=e.half[0]*Ji(u,e.axis[0])+e.half[1]*Ji(u,e.axis[1])+e.half[2]*Ji(u,e.axis[2]),g=f-(d+p);return g>0?!1:((!a.valid||g>a.separation)&&(a.valid=!0,a.type=r,a.indexA=o,a.indexB=n,a.separation=g,a.normalAB=u),!0)}function sc(s,e,t){let i=(e+1)%3,r=(e+2)%3,o=V(t,s.axis[i])>=0?1:-1,n=V(t,s.axis[r])>=0?1:-1,a=D(C(),s.center,s.axis[i],s.half[i]*o);D(a,a,s.axis[r],s.half[r]*n);let l=ne(C(),s.axis[e],s.half[e]);return[$(C(),a,l),ki(C(),a,l)]}function af(s,e,t,i){let r=$(C(),e,s),o=$(C(),i,t),n=$(C(),s,t),a=V(r,r),l=V(o,o),c=V(o,n),u=0,f=0;if(a<=$i&&l<=$i)return[s,t];if(a<=$i)f=ce(c/l,0,1);else{let d=V(r,n);if(l<=$i)u=ce(-d/a,0,1);else{let p=V(r,o),g=a*l-p*p;Math.abs(g)>$i&&(u=ce((p*c-d*l)/g,0,1)),f=(p*u+c)/l,f<0?(f=0,u=ce(-d/a,0,1)):f>1&&(f=1,u=ce((p-d)/a,0,1))}}return[D(C(),s,r,u),D(C(),t,o,f)]}function oc(s,e,t,i,r,o,n){let a=r?t:i,l=r?i:t,c=r?n:ee(C(),n),u=rf(a,o,c),f=sf(l,u.normal),d=of(l,f,u.normal),p=[[u.u,u.extentU],[ee(C(),u.u),u.extentU],[u.v,u.extentV],[ee(C(),u.v),u.extentV]];for(let[m,b]of p)if(d=nf(d,m,V(m,u.center)+b),!d.length)return[];let g=new Ro(s,e),h=(r?Mo:ac)<<24|(o&255)<<16|(f&255)<<8;for(let m=0;m<d.length&&g.contacts.length<nc;m++){let b=d[m],v=V($(C(),b,u.center),u.normal);if(v>aa)continue;let w=D(C(),b,u.normal,-v),y=r?w:b,A=r?b:w;g.add(y,A,h|m&255)}return g.contacts.length||g.add(Io(t,n),Io(i,ee(C(),n)),h),g.contacts}function lf(s,e,t,i,r,o,n){let[a,l]=sc(t,r,n),[c,u]=sc(i,o,ee(C(),n)),[f,d]=af(a,l,c,u),p=new Ro(s,e),g=zo<<24|(r&255)<<8|o&255;return p.add(f,d,g),p.contacts.length||p.add(Io(t,n),Io(i,ee(C(),n)),g),p.contacts}function cc(s,e,t,i=!0){let r=rc(s),o=rc(e),n=$(C(),o.center,r.center),a={type:Mo,indexA:0,indexB:0,separation:-la,normalAB:C(),valid:!1},l={type:zo,indexA:0,indexB:0,separation:-la,normalAB:C(),valid:!1};for(let f=0;f<3;f++)if(!na(r,o,n,r.axis[f],Mo,f,-1,a))return[];for(let f=0;f<3;f++)if(!na(r,o,n,o.axis[f],ac,-1,f,a))return[];let c=C();for(let f=0;f<3;f++)for(let d=0;d<3;d++)if(Dt(c,r.axis[f],o.axis[d]),!na(r,o,n,c,zo,f,d,l))return[];if(!a.valid)return[];let u=a;return l.valid&&(i?l.separation>.95*a.separation+.01:.95*l.separation>a.separation+.01)&&(u=l),ds(t,ee(C(),u.normalAB)),u.type===zo?lf(s,e,r,o,u.indexA,u.indexB,u.normalAB):u.type===Mo?oc(s,e,r,o,!0,u.indexA,u.normalAB):oc(s,e,r,o,!1,u.indexB,u.normalAB)}var de=(s,e)=>s.map((t,i)=>t+e[i]),T=(s,e)=>s.map((t,i)=>t-e[i]),q=(s,e)=>s.map(t=>t*e),G=(s,e)=>s.reduce((t,i,r)=>t+i*e[r],0),yt=(s,e)=>[s[1]*e[2]-s[2]*e[1],s[2]*e[0]-s[0]*e[2],s[0]*e[1]-s[1]*e[0]],Tt=s=>q(s,1/(Math.hypot(...s)||1)),_e=(s,e)=>Array.from(ae(C(),s,e)),uc=(s,e)=>Te(C(),s.positionAng,T(e,s.positionLin)),Ot=(s,e)=>de(s.positionLin,_e(s.positionAng,e)),cf=[[1,3,7,5],[0,4,6,2],[2,6,7,3],[0,1,5,4],[4,5,7,6],[0,2,3,1]],uf=[[1,0,0],[-1,0,0],[0,1,0],[0,-1,0],[0,0,1],[0,0,-1]];function Ir(s){if(De(s)||He(s)){let n=(De(s),s.size[0]/2),a=He(s)?Math.max(0,s.size[1]/2-n):0;return{body:s,radius:n,spine:[Ot(s,[0,-a,0]),Ot(s,[0,a,0])]}}let e=wt(s),t=e?Array.from({length:e.vertices.length/3},(n,a)=>Ot(s,e.vertices.slice(a*3,a*3+3))):Array.from({length:8},(n,a)=>Ot(s,s.size.map((l,c)=>l/2*(a>>c&1?1:-1)))),i=e?e.faces.map(n=>({vertices:n.verts.map(a=>t[a]),normal:_e(s.positionAng,n.normal)})):cf.map((n,a)=>({vertices:n.map(l=>t[l]),normal:_e(s.positionAng,uf[a])})),r=[],o=new Set;for(let n of i)for(let a=0;a<n.vertices.length;a++){let l=n.vertices[a],c=n.vertices[(a+1)%n.vertices.length],u=t.indexOf(l),f=t.indexOf(c),d=`${Math.min(u,f)},${Math.max(u,f)}`;o.has(d)||(o.add(d),r.push([l,c]))}return{body:s,vertices:t,faces:i,edges:r}}function as(s,e){let t=s.spine??s.vertices,i=t[0];for(let r of t)G(r,e)>G(i,e)&&(i=r);return s.spine?de(i,q(e,s.radius)):i}function ff(s,e,t){let i=T(e,s);return de(s,q(i,Math.max(0,Math.min(1,G(T(t,s),i)/(G(i,i)||1)))))}function Oo([s,e],[t,i]){let r=T(e,s),o=T(i,t),n=T(s,t),a=G(r,r),l=G(o,o),c=G(o,n),u=0,f=0,d=p=>Math.max(0,Math.min(1,p));if(a<1e-16)f=l>1e-16?d(c/l):0;else{let p=G(r,n);if(l<1e-16)u=d(-p/a);else{let g=G(r,o),h=a*l-g*g;u=h>1e-12*a*l?d((g*c-p*l)/h):0,f=(g*u+c)/l,f<0?(f=0,u=d(-p/a)):f>1&&(f=1,u=d((g-p)/a))}}return[de(s,q(r,u)),de(t,q(o,f))]}function df(s,e,t){let i=[];for(let r=0;r<s.length;r++){let o=s[r],n=s[(r+1)%s.length],a=G(o,e)-t,l=G(n,e)-t;a<=1e-8&&i.push(o),a<0!=l<0&&i.push(de(o,q(T(n,o),a/(a-l))))}return i}function hf(s,e,t,i){let r=T(t,e),o=T(i,e),n=T(s,e),a=G(r,n),l=G(o,n);if(a<=0&&l<=0)return e;let c=T(s,t),u=G(r,c),f=G(o,c);if(u>=0&&f<=u)return t;let d=a*f-u*l;if(d<=0&&a>=0&&u<=0)return de(e,q(r,a/(a-u)));let p=T(s,i),g=G(r,p),h=G(o,p);if(h>=0&&g<=h)return i;let m=g*l-a*h;if(m<=0&&l>=0&&h<=0)return de(e,q(o,l/(l-h)));let b=u*h-g*f;if(b<=0&&f-u>=0&&g-h>=0)return de(t,q(T(i,t),(f-u)/(f-u+g-h)));let v=1/(b+m+d);return de(e,de(q(r,m*v),q(o,d*v)))}function pf(s,e){let t=null,i=1/0;for(let r of s.faces)for(let o=1;o<r.vertices.length-1;o++){let n=hf(e,r.vertices[0],r.vertices[o],r.vertices[o+1]),a=G(T(e,n),T(e,n));a<i&&(t=n,i=a)}return t}function fc(s,e,t,i,r){if(!De(s)&&!De(e)&&!He(s)&&!He(e)&&!wt(s)&&!wt(e))return cc(s,e,t,s.solver.faceBias!==!1);i??=Ir(s),r??=Ir(e);let o=-1/0,n=[0,0,1],a=null,l=(f,d=null)=>{if(Math.hypot(...f)<1e-9)return;let p=Tt(f),g=G(T(as(i,q(p,-1)),as(r,p)),p),h=G(T(as(r,q(p,-1)),as(i,p)),p);h>g&&(g=h,p=q(p,-1)),g>o+1e-7&&(o=g,n=p,a=d)};for(let f of[i,r])for(let d of f.faces??[])l(d.normal);if(i.edges&&r.edges)for(let f of i.edges)for(let d of r.edges)l(yt(T(f[1],f[0]),T(d[1],d[0])),[f,d]);if(i.spine&&r.spine){let f=Oo(i.spine,r.spine);l(T(...f))}for(let[f,d]of[[i,r],[r,i]])if(f.spine&&d.faces){for(let p of d.vertices)l(T(p,ff(...f.spine,p)));for(let p of d.edges){let g=Oo(f.spine,p);l(T(...g))}}if(o===-1/0&&l(T(s.positionLin,e.positionLin)),o>0)return[];o===-1/0&&(n=[0,0,1],o=-(i.radius+r.radius));let c=Tt(yt(n,Math.abs(n[0])<.7?[1,0,0]:[0,1,0]));t.set([...n,...c,...yt(n,c)]);let u=[];if(i.spine&&r.spine){let[f,d]=Oo(i.spine,r.spine);u=[[de(f,q(n,-i.radius)),de(d,q(n,r.radius))]]}else if(i.spine||r.spine){let f=i.spine?i:r,d=i.spine?r:i,p=i.spine?q(n,-1):n,g=as(f,p),h=pf(d,g);u=[i.spine?[g,h]:[h,g]]}else if(a)u=[Oo(...a)];else{let f=(w,y)=>w.faces.reduce((A,x)=>G(x.normal,y)>G(A.normal,y)?x:A,w.faces[0]),d=f(i,q(n,-1)),p=f(r,n),g=G(d.normal,q(n,-1))>=G(p.normal,n),h=g?d:p,b=f(g?r:i,q(h.normal,-1)).vertices,v=q(h.vertices.reduce((w,y)=>de(w,y),[0,0,0]),1/h.vertices.length);for(let w=0;w<h.vertices.length&&b.length;w++){let y=h.vertices[w],A=h.vertices[(w+1)%h.vertices.length],x=Tt(yt(T(A,y),h.normal));G(T(v,y),x)>0&&(x=q(x,-1)),b=df(b,x,G(y,x))}for(let w of b){let y=G(T(w,h.vertices[0]),h.normal);if(y<=1e-6){let A=T(w,q(h.normal,y));u.push(g?[A,w]:[w,A])}}}return u.slice(0,8).map(([f,d],p)=>({feature:p+1,rA:uc(s,f),rB:uc(e,d)}))}var To=(s,e,t)=>Math.max(e,Math.min(t,s)),mf=(s,e)=>[G(s.slice(0,3),e),G(s.slice(3,6),e),G(s.slice(6,9),e)];function fa(s,e=!1){if(e){s.rest=Math.hypot(...T(Ot(s.bodyA,s.rA),Ot(s.bodyB,s.rB)));return}let t=s.bodyA?.positionAng??[0,0,0,1];s.cpuRest=Or(jt(),Yo(jt(),t),s.bodyB.positionAng),s.evaluateAng=i=>{let r=Or(jt(),s.bodyA?.positionAng??[0,0,0,1],s.cpuRest);lt(i,r,s.bodyB.positionAng);for(let o=0;o<3;o++)i[o]*=s.torqueArm;return i}}var ca=class extends oi{initialize(){let e=this.bodyA,t=this.bodyB;if(!((e.group??4294967295)&(t.collidesWith??4294967295))||!((t.group??4294967295)&(e.collidesWith??4294967295)))return!1;let i=this.contacts,r=De(e)||De(t)||He(e)||He(t);this.friction=Math.sqrt(e.friction*t.friction),this.contacts=fc(e,t,this.basis,this.solver.cpuGeometry.get(e),this.solver.cpuGeometry.get(t)).map(o=>{let n=i.find(a=>a.feature===o.feature);return{feature:o.feature,rA:n?.stick&&!r?n.rA:o.rA,rB:n?.stick&&!r?n.rB:o.rB,C0:C(),penalty:n?n.penalty.slice():C(),lambda:n?n.lambda.slice():C(),stick:n?.stick??!1}});for(let o of this.contacts){o.C0.set(mf(this.basis,T(Ot(e,o.rA),Ot(t,o.rB)))),o.C0[0]+=ps;for(let n=0;n<3;n++)o.lambda[n]*=this.solver.alpha*this.solver.gamma,o.penalty[n]=To(o.penalty[n]*this.solver.gamma,Et,Ue);if(this.solver.massPenalty!==!1){let n=Math.min(e.mass>0?e.mass:1/0,t.mass>0?t.mass:1/0);o.penalty[0]=Math.max(o.penalty[0],To(n/this.solver.dt**2,Et,Ue))}}return this.contacts.length>0}updatePrimal(...e){!this.bodyA.isTrigger&&!this.bodyB.isTrigger&&super.updatePrimal(...e)}updateDual(...e){!this.bodyA.isTrigger&&!this.bodyB.isTrigger&&super.updateDual(...e)}},ua=class extends Gt{constructor(e,t,i){super(e,t.bodyA,t.bodyB),this.options={...i},this.pen=[Et,Et],this.lam=[0,0],this.source=t;let r=i.axisA;this.ta=Tt(Math.abs(r[0])>Math.abs(r[2])?[-r[1],r[0],0]:[0,-r[2],r[1]]);let o=this.bodyA?_e(this.bodyA.positionAng,this.ta):this.ta,n=Array.from(Te(C(),this.bodyB.positionAng,o));n=T(n,q(i.axisB,G(n,i.axisB))),this.tb=Tt(n)}frame(){let e=this.bodyA?_e(this.bodyA.positionAng,this.options.axisA):this.options.axisA,t=this.bodyA?_e(this.bodyA.positionAng,this.ta):this.ta,i=_e(this.bodyB.positionAng,this.tb);return{axis:e,angle:Math.atan2(G(e,yt(t,i)),G(t,i))}}initialize(){let e=this.frame().angle;this.c0=this.options.type==="motor"?[e,0]:[Math.min(0,e-this.options.minAngle),Math.max(0,e-this.options.maxAngle)];for(let t=0;t<2;t++)this.lam[t]*=this.solver.alpha*this.solver.gamma,this.pen[t]=To(this.pen[t]*this.solver.gamma,Et,Ue);return!this.source.broken}evaluate(e){let{angle:t}=this.frame(),i=this.options,r=i.type==="motor"?[Math.atan2(Math.sin(t-this.c0[0]),Math.cos(t-this.c0[0]))-i.speed*this.solver.dt,0]:[t-i.minAngle-e*this.c0[0],t-i.maxAngle-e*this.c0[1]],o=r.map((n,a)=>this.pen[a]*n+this.lam[a]);return{c:r,f:i.type==="motor"?[To(o[0],-i.maxTorque,i.maxTorque),0]:[Math.min(0,o[0]),Math.max(0,o[1])]}}updatePrimal(e,t,i){let{f:r}=this.evaluate(t),o=this.options;if(o.type==="motor"&&o.maxTorque===0)return;let n=q(this.frame().axis,e===this.bodyA?-1:1);for(let a=0;a<(o.type==="motor"?1:2);a++)if(!(o.type==="limit"&&r[a]===0))for(let l=0;l<3;l++){i.rhsAng[l]+=n[l]*r[a];for(let c=0;c<3;c++)i.lhsAng[l*3+c]+=n[l]*n[c]*this.pen[a]}}updateDual(e){let{c:t,f:i}=this.evaluate(e);this.lam=i;for(let r=0;r<2;r++)this.pen[r]=Math.min(Ue,this.pen[r]+this.solver.betaAng*(this.options.type==="motor"?Math.abs(t[r]):r===0?Math.max(0,-t[r]):Math.max(0,t[r])))}};function jo(s){if(!s.cpuPrepared){s.cpuPrepared=!0;for(let e of[...s.forces]){let t=Hr(e);if(t){e.unlinkFromBodies(),s.forces.splice(s.forces.indexOf(e),1),e.cpuAngular=new ua(s,e,t);continue}if(e instanceof ke&&e.stiffnessAng>0&&fa(e),e instanceof ut){let i=e.initialize.bind(e);e.initialize=()=>{if(e.broken)return!1;let r=Gi(e);if(r){let o=Math.max(0,Math.hypot(...T(Ot(e.bodyA,e.rA),Ot(e.bodyB,e.rB)))-e.rest);if(o/Math.max(e.rest,1e-6)>r.breakStrain||o*e.stiffness>r.breakForce)return e.broken=!0,!1}return i()}}}}}function dc(s){let e=s.bodies;s.cpuGeometry=new Map;for(let l of e)(De(l)||He(l)||wt(l))&&s.cpuGeometry.set(l,Ir(l));let t=e.filter(l=>l.mass>0).slice(0,1024).map(l=>l.radius).sort((l,c)=>l-c),i=Math.max(.1,(t[Math.floor(t.length/2)]??1)*2),r=new Map,o=[],n=new Set,a=(l,c)=>{if(l===c||e[l].mass<=0&&e[c].mass<=0)return;let u=Math.max(l,c),f=Math.min(l,c),d=u*e.length+f;if(n.has(d))return;n.add(d);let p=e[u],g=e[f];if(!((p.group??4294967295)&(g.collidesWith??4294967295))||!((g.group??4294967295)&(p.collidesWith??4294967295)))return;let h=p.radius+g.radius;G(T(p.positionLin,g.positionLin),T(p.positionLin,g.positionLin))<=h*h&&!p.constrainedTo(g)&&new ca(s,p,g)};for(let l=0;l<e.length;l++){let c=e[l],u=c.positionLin.map(d=>Math.floor((d-c.radius)/i)),f=c.positionLin.map(d=>Math.floor((d+c.radius)/i));if((f[0]-u[0]+1)*(f[1]-u[1]+1)*(f[2]-u[2]+1)>128){o.push(l);continue}for(let d=u[0];d<=f[0];d++)for(let p=u[1];p<=f[1];p++)for(let g=u[2];g<=f[2];g++){let h=`${d},${p},${g}`,m=r.get(h)??[];for(let b of m)a(l,b);m.push(l),r.set(h,m)}}for(let l of o)for(let c=0;c<e.length;c++)a(l,c)}function Do(s,e){if(!(e===3?s.bodies.some(r=>r.restitution>0):[...s.restitution.values()].some(r=>r>0)))return null;if(e===2)return Float64Array.from(s.velocity);let i=new Float64Array(s.bodies.length*6);return s.bodies.forEach((r,o)=>{i.set(r.velocityLin,o*6),i.set(r.velocityAng,o*6+3)}),i}function Fo(s,e,t){if(!t)return;let i=e===3?s.bodies.length:s.bodyCount,r=e===3?6:4,o=e===3?new Float64Array(i*r):s.velocity;e===3&&s.bodies.forEach((h,m)=>{o.set(h.velocityLin,m*r),o.set(h.velocityAng,m*r+3)});let n=h=>e===3?s.bodies[h].mass>0&&!s.bodies[h].sleeping?1/s.bodies[h].mass:0:s.dynamic[h]?1/s.shape[h*4+2]:0,a=(h,m)=>{if(!n(h))return e===3?[0,0,0]:0;if(e===2)return s.shape[h*4+3]>0?m/s.shape[h*4+3]:0;let b=s.bodies[h],v=b.positionAng,w=_e([-v[0],-v[1],-v[2],v[3]],m);return _e(v,w.map((y,A)=>b.moment[A]>0?y/b.moment[A]:0))},l=(h,m,b)=>{let v=m*r;return e===3?T(h.subarray(v,v+3),yt(b,h.subarray(v+3,v+6))):[h[v]-h[v+2]*b[1],h[v+1]+h[v+2]*b[0]]},c=(h,m)=>e===3?yt(h,m):h[0]*m[1]-h[1]*m[0],u=(h,m)=>e===3?G(h,m):h*m,f;if(e===3){let h=new Map(s.bodies.map((m,b)=>[m,b]));f=s.forces.filter(m=>m.contacts?.length&&!m.bodyA.isTrigger&&!m.bodyB.isTrigger).map(m=>{let b=(v,w)=>{let y=[0,0,0];for(let A of m.contacts){let x=_e(v.positionAng,A[w]);for(let B=0;B<3;B++)y[B]+=x[B]/m.contacts.length}return y};return{a:h.get(m.bodyA),b:h.get(m.bodyB),n:m.basis.slice(0,3),ra:b(m.bodyA,"rA"),rb:b(m.bodyB,"rB"),e:Math.max(m.bodyA.restitution??0,m.bodyB.restitution??0)}})}else{let h=(m,b)=>{let v=Math.cos(s.pose[m*4+2]),w=Math.sin(s.pose[m*4+2]);return[v*b[0]-w*b[1],w*b[0]+v*b[1]]};f=s.contactPairs.filter(m=>!s.sensors.has(m.a)&&!s.sensors.has(m.b)).map(m=>({...m,ra:h(m.a,m.ra),rb:h(m.b,m.rb),e:Math.max(s.restitution.get(m.a)??0,s.restitution.get(m.b)??0)}))}let d=new Uint32Array(i);if(e===3)s.bodies.forEach((h,m)=>{d[m]=h.forces.length});else for(let h=0;h<i;h++)d[h]=s.adjStart[h+1]-s.adjStart[h];let p=[];for(let h of f){if(h.e<=0)continue;let m=G(h.n,T(l(t,h.a,h.ra),l(t,h.b,h.rb)));if(m>=-1)continue;let b=c(h.ra,h.n),v=c(h.rb,h.n),w=a(h.a,b),y=a(h.b,v),A=n(h.a)+n(h.b)+u(b,w)+u(v,y);A>0&&p.push({...h,inertiaA:w,inertiaB:y,k:A,target:-h.e*m,impulse:0})}let g=new Float64Array(o.length);for(let h=0;h<12&&p.length;h++){g.fill(0);for(let m of p){let b=G(m.n,T(l(o,m.a,m.ra),l(o,m.b,m.rb))),v=Math.max(0,m.impulse+(m.target-b)/(m.k*Math.max(1,d[m.a],d[m.b]))),w=v-m.impulse;m.impulse=v;for(let[y,A,x]of[[m.a,1,m.inertiaA],[m.b,-1,m.inertiaB]]){let B=y*r,E=n(y);for(let L=0;L<e;L++)g[B+L]+=A*w*E*m.n[L];if(e===3)for(let L=0;L<3;L++)g[B+3+L]+=A*w*x[L];else g[B+2]+=A*w*x}}for(let m=0;m<o.length;m++)o[m]+=g[m]}e===3&&s.bodies.forEach((h,m)=>{h.velocityLin.set(o.subarray(m*r,m*r+3)),h.velocityAng.set(o.subarray(m*r+3,m*r+6))})}function hc(s,e,t){let i=e.windSpeed??0;if(!sr(s)||s.mass<=0||i===0)return null;let r=e.windAngle??0,o=[Math.cos(r),Math.sin(r),0],n=[-o[1],o[0],0],a=s.positionLin,l=t*e.dt,c=G(a,o),u=G(a,n),f=.5*Math.sin(1.1*l-.35*c+.2*u)+.3*Math.sin(2.9*l-.8*c+.6*a[2])+.2*Math.sin(6.1*l-1.7*c+1.3*a[2]+.9*u),d=.6*Math.sin(1.7*l-.6*c+.4*a[2])+.4*Math.sin(4.3*l-1.3*c-.7*a[2]),p=Math.sin(2.3*l-.9*c+1.1*u),g=e.windGust??.4,h=o.map((A,x)=>i*A*(1+g*f)+g*i*(n[x]*.25*d+(x===2?.1*p:0))-s.velocityLin[x]),m=_e(s.positionAng,[0,0,1]),b=(e.windPressure??.72)*s.size[0]*s.size[1]/s.mass,v=G(h,m),w=h.map((A,x)=>A-m[x]*v),y=b*v*Math.abs(v)/(1+2*e.dt*b*Math.abs(v));return m.map((A,x)=>A*y+w[x]*.06*b*Math.hypot(...w))}var gf=()=>({dt:1/60,gravity:-10,iterations:10,betaLin:1e4,betaAng:100,alpha:.99,gamma:.999}),Go=class{dt=1/60;gravity=-10;iterations=10;alpha=.99;betaLin=1e4;betaAng=100;gamma=.999;massPenalty=!0;faceBias=!0;up=[0,0,1];cpuStep=0;bodies=[];forces=[];constructor(){this.defaultParams()}defaultParams(){Object.assign(this,gf())}clear(){this.forces=[],this.bodies=[]}pick(e,t){let r=null,o=C(),n=C();for(let a=this.bodies.length-1;a>=0;a--){let l=this.bodies[a];if(l.mass<=0)continue;Te(o,l.positionAng,$(o,e,l.positionLin)),Te(n,l.positionAng,t);let c=0,u=1/0,f=!0;for(let p=0;p<3&&f;p++){let g=l.size[p]*.5;if(Math.abs(n[p])<1e-6){(o[p]<-g||o[p]>g)&&(f=!1);continue}let h=1/n[p],m=(-g-o[p])*h,b=(g-o[p])*h;m>b&&([m,b]=[b,m]),c=Math.max(c,m),u=Math.min(u,b),c>u&&(f=!1)}if(!f)continue;let d=c>=0?c:u;d<0||(!r||d<r.t)&&(r={body:l,local:D(C(),o,n,d),t:d})}return r}sys=ms();dxLin=C();dxAng=C();dp=C();accel=C();step(){let{dt:e,gravity:t,bodies:i,sys:r,dp:o}=this,n=Do(this,3);jo(this),dc(this);let a=[];for(let l of this.forces)l.initialize()?a.push(l):l.unlinkFromBodies();this.forces=a;for(let l=i.length-1;l>=0;l--){let c=i[l];D(c.inertialLin,c.positionLin,c.velocityLin,e),c.mass>0&&D(c.inertialLin,c.inertialLin,this.up,t*e*e);let u=hc(c,this,this.cpuStep);u&&D(c.inertialLin,c.inertialLin,u,e*e),ri(c.inertialAng,c.positionAng,pc(c.velocityAng,e)),_t(this.accel,$(this.accel,c.velocityLin,c.prevVelocityLin),e);let f=V(this.accel,this.up)*us(t),d=ce(f/Math.abs(t),0,1);Number.isFinite(d)||(d=0),c.initialLin.set(c.positionLin),c.initialAng.set(c.positionAng),c.mass>0&&!c.sleeping&&(D(c.positionLin,c.positionLin,c.velocityLin,e),D(c.positionLin,c.positionLin,this.up,t*d*e*e),ri(c.positionAng,c.positionAng,pc(c.velocityAng,e)))}for(let l=0;l<this.iterations;l++){for(let c=i.length-1;c>=0;c--){let u=i[c];if(u.mass<=0||u.sleeping)continue;let f=u.mass,d=u.moment;Ce(r.lhsLin,f/(e*e),f/(e*e),f/(e*e)),Ce(r.lhsAng,d[0]/(e*e),d[1]/(e*e),d[2]/(e*e)),r.lhsCross.fill(0),ue(r.rhsLin,r.lhsLin,$(o,u.positionLin,u.inertialLin)),ue(r.rhsAng,r.lhsAng,lt(o,u.positionAng,u.inertialAng));let p=u.forces;for(let h=p.length-1;h>=0;h--)p[h].updatePrimal(u,this.alpha,r);let g=u.moment.every(h=>h===0);g&&(Ce(r.lhsAng,1,1,1),r.lhsCross.fill(0),r.rhsAng.fill(0)),hs(r.lhsLin,r.lhsAng,r.lhsCross,ee(r.rhsLin,r.rhsLin),ee(r.rhsAng,r.rhsAng),this.dxLin,this.dxAng),D(u.positionLin,u.positionLin,this.dxLin,1),g||ri(u.positionAng,u.positionAng,this.dxAng)}for(let c of this.forces)c.updateDual(this.alpha)}for(let l of i)l.prevVelocityLin.set(l.velocityLin),l.mass>0&&!l.sleeping&&(_t(l.velocityLin,$(l.velocityLin,l.positionLin,l.initialLin),e),_t(l.velocityAng,lt(l.velocityAng,l.positionAng,l.initialAng),e));Fo(this,3,n),this.cpuStep++}},bf=C(),pc=(s,e)=>ne(bf,s,e);var cs=(s,e)=>s.map((t,i)=>t+e[i]),Re=(s,e)=>s.map((t,i)=>t-e[i]),Lt=(s,e)=>s.map(t=>t*e),rt=(s,e)=>s[0]*e[0]+s[1]*e[1],ls=(s,e)=>[Math.cos(s)*e[0]-Math.sin(s)*e[1],Math.sin(s)*e[0]+Math.cos(s)*e[1]],gc=s=>Math.max(0,Math.min(1,s)),mc=(s,e,t)=>cs(s,Lt(Re(e,s),gc(rt(Re(t,s),Re(e,s))/(rt(Re(e,s),Re(e,s))||1))));function No(s,e){let t=Zt(s)?.get(e)??[0,0,0,0],i=Array.from(s.pose.subarray(e*4,e*4+2)),r=s.pose[e*4+2],o=l=>cs(i,ls(r,l)),n=[s.shape[e*4]/2,s.shape[e*4+1]/2],a=t[0]===4?Array.from({length:t.vertices.length/4},(l,c)=>o(t.vertices.slice(c*4,c*4+2))):t[0]===0?[[-1,-1],[1,-1],[1,1],[-1,1]].map(l=>o([l[0]*n[0],l[1]*n[1]])):null;return{kind:t[0],p:i,angle:r,vertices:a,radius:t[1],spine:[o([-t[2]||0,0]),o([t[2]||0,0])]}}function Xi(s,e){if(s.vertices){let r=-1/0,o=[];for(let n of s.vertices){let a=rt(n,e);a>r+1e-7?(r=a,o=[n]):Math.abs(a-r)<1e-7&&o.push(n)}return[o[0],o.at(-1)]}let t=cs(s.spine[0],Lt(e,s.radius)),i=cs(s.spine[1],Lt(e,s.radius));return Math.abs(rt(t,e)-rt(i,e))<1e-7?[t,i]:rt(t,e)>rt(i,e)?[t,t]:[i,i]}function bc(s,e,t,i){let r=No(s,e),o=No(s,t),n=s.pose,a=s.shape;if(r.kind===0&&o.kind===0)return oo(...n.subarray(e*4,e*4+3),a[e*4]/2,a[e*4+1]/2,...n.subarray(t*4,t*4+3),a[t*4]/2,a[t*4+1]/2,i);let l=[];if(r.kind===3||o.kind===3){let u=r.kind===3,f=u?r:o,d=u?o:r;if(d.kind===3)return 0;let p=ls(f.angle,[0,1]),g=Xi(d,Lt(p,-1));for(let h of g){let m=rt(Re(h,f.p),p);if(m<=0){let b=Re(h,Lt(p,m));l.push({a:u?b:h,b:u?h:b,n:u?Lt(p,-1):p})}}}else{let u=-1/0,f=[0,1],d=A=>{let x=Math.hypot(...A);if(x<1e-9)return;let B=Lt(A,1/x),E=rt(Re(Xi(r,Lt(B,-1))[0],Xi(o,B)[0]),B),L=rt(Re(Xi(o,Lt(B,-1))[0],Xi(r,B)[0]),B);Math.max(E,L)>u+1e-7&&(u=Math.max(E,L),f=E>=L?B:Lt(B,-1))};for(let[A,x]of[[r,o],[o,r]])if(A.vertices)for(let B=0;B<A.vertices.length;B++){let E=Re(A.vertices[(B+1)%A.vertices.length],A.vertices[B]);d([E[1],-E[0]]),x.vertices||d(Re(A.vertices[B],mc(...x.spine,A.vertices[B])))}else if(d(ls(A.angle,[0,1])),!x.vertices)for(let B of A.spine)d(Re(B,mc(...x.spine,B)));if(u===-1/0&&d([0,1]),u>0)return 0;let p=Xi(r,Lt(f,-1)),g=Xi(o,f),h=[-f[1],f[0]],m=p.map(A=>rt(A,h)),b=g.map(A=>rt(A,h)),v=Math.max(Math.min(...m),Math.min(...b)),w=Math.min(Math.max(...m),Math.max(...b)),y=(A,x)=>{let B=rt(Re(A[1],A[0]),h);return Math.abs(B)<1e-9?A[0]:cs(A[0],Lt(Re(A[1],A[0]),gc((x-rt(A[0],h))/B)))};for(let A of w-v>1e-6?[v,w]:[(v+w)/2])l.push({a:y(p,A),b:y(g,A),n:f})}let c=0;for(let u of l){if(c&&Math.hypot(...Re(u.a,l[0].a))<1e-7)continue;let f=ls(-r.angle,Re(u.a,r.p)),d=ls(-o.angle,Re(u.b,o.p));if(i.set([268435456+c,...f,...d,...u.n],c*7),c++,c===2)break}return c}var yc=(s,e,t)=>[Math.cos(s)*e-Math.sin(s)*t,Math.sin(s)*e+Math.cos(s)*t],vc=function(){let{pose:s,shape:e,props:t}=this,i=this.broadphase.pairs,r=this.contactOut;for(let o=0;o<this.broadphase.pairCount;o++){let n=i[o],a=Math.floor(n/2097152),l=n-a*2097152,c=this.collideBodies(a,l,r);if(c===0)continue;let u=0,f=this.prevCount;for(;u<f;){let g=u+f>>>1;this.prevKeys[g]<n?u=g+1:f=g}let d=u,p=Math.sqrt(t[a*4]*t[l*4]);for(let g=0;g<c;g++){let h=this.jointCount+this.contactCount++;this.info=this.grow(this.info,(h+1)*j),this.data=this.grow(this.data,(h+1)*O);let m=this.data,b=h*O,v=g*7,w=r[v+0];this.info.set([Zr,a,l,w],h*j),m.fill(0,b,b+O),m[b+Q]=m[b+Q+1]=1/0,m[b+Le]=-1/0,m[b+xe]=0,m[b+Pt]=m[b+Pt+1]=1/0,m[b+U]=r[v+1],m[b+U+1]=r[v+1+1],m[b+Y]=r[v+3],m[b+Y+1]=r[v+3+1],m[b+re]=p,m[b+ge]=r[v+5],m[b+Fe]=r[v+5+1];let y=-1;for(let k=d;k<this.prevCount&&this.prevKeys[k]===n;k++)this.prevInfo[k*j+3]===w&&(y=k);if(y<0&&this.params.matchNearest){let k=ea*Math.min(e[a*4],e[a*4+1],e[l*4],e[l*4+1]);for(let S=d;S<this.prevCount&&this.prevKeys[S]===n;S++){let P=Math.hypot(this.prevData[S*O+U]-m[b+U],this.prevData[S*O+U+1]-m[b+U+1]);P<=k&&(k=P,y=S)}}if(y>=0){let k=y*O;m[b+se]=this.prevData[k+se],m[b+se+1]=this.prevData[k+se+1],m[b+te]=this.prevData[k+te],m[b+te+1]=this.prevData[k+te+1],this.prevData[k+Vi]&&(m[b+U]=this.prevData[k+U],m[b+U+1]=this.prevData[k+U+1],m[b+Y]=this.prevData[k+Y],m[b+Y+1]=this.prevData[k+Y+1])}let[A,x]=yc(s[a*4+2],m[b+U],m[b+U+1]),[B,E]=yc(s[l*4+2],m[b+Y],m[b+Y+1]),L=m[b+ge],M=m[b+Fe],z=s[a*4]+A-s[l*4]-B,_=s[a*4+1]+x-s[l*4+1]-E;m[b+fe]=L*z+M*_+5e-4,m[b+fe+1]=M*z-L*_}}};var Uo=class extends Lr{constructor(e,t,i){if(super({precision:i==="soa-colored"?"f32":"f64",order:i==="soa-colored"?"colored":"sequential"}),Object.assign(this,e),this.options={...this.options,precision:i==="soa-colored"?"f32":"f64",order:i==="soa-colored"?"colored":"sequential"},this.options.precision==="f64")for(let[r,o]of Object.entries(this))o instanceof Float32Array&&(this[r]=Float64Array.from(o));for(let[r,o]of Zt(e)??[]){let n=this.shape[r*4+2];Er(this,r,{geometry:o,area:n,momentPerMass:n>0?this.shape[r*4+3]/n:0,radius:this.props[r*4+1]},1)}this.filters=new Map(t?.filters??[]),this.sensors=new Set(t?.sensors??[]),this.restitution=new Map(t?.restitution??[]),this.contactPairs=[],t&&(t.topology=this)}narrowphase(){this.contactPairs=[],vc.call(this)}collideBodies(e,t,i){let r=this.filters.get(e)??[4294967295,4294967295],o=this.filters.get(t)??[4294967295,4294967295];if(!(r[0]&o[1])||!(o[0]&r[1]))return 0;let n=bc(this,e,t,i);if(n){let a=[i[5],i[6]],l=[0,0],c=[0,0];for(let p=0;p<n;p++)for(let g=0;g<2;g++)l[g]+=i[p*7+1+g]/n,c[g]+=i[p*7+3+g]/n;let u=this.pose[e*4+2],f=Math.cos(u),d=Math.sin(u);this.contactPairs.push({a:e,b:t,n:a,ra:l,rb:c,point:[this.pose[e*4]+f*l[0]-d*l[1],this.pose[e*4+1]+d*l[0]+f*l[1],0],impulse:0})}return this.sensors.has(e)||this.sensors.has(t)?0:n}initJoints(){for(let e=0;e<this.jointCount;e++){let t=e*O,i=this.info[e*j];if(this.data[t+Q]===0&&this.data[t+Q+1]===0&&this.data[t+Q+2]===0){i!==0&&(this.info[e*j]=0,this.noCollideDirty=!0,this.handles[e]&&(this.handles[e].alive=!1));continue}i===1&&this.jointC(this.info[e*j+1],this.info[e*j+2],t,this.pose,this.data,t+fe)}for(let e=0;e<this.jointCount;e++)if(this.info[e*j]===5){let t=e*O,i=this.info[e*j+1],r=this.info[e*j+2],o=(i<0?0:this.pose[i*4+2])-this.pose[r*4+2]-this.data[t+re];this.data[t+fe]=Math.min(0,o-this.data[t+ge]),this.data[t+fe+1]=Math.max(0,o-this.data[t+Fe])}}warmStartConstraints(e,t){let i=[];for(let r=0;r<this.jointCount;r++)this.info[r*j]===5&&(i.push(r),this.info[r*j]=4);super.warmStartConstraints(e,t);for(let r of i)this.info[r*j]=5}evalConstraint(e,t,i){if(this.info[e*j]!==5)return super.evalConstraint(e,t,i);let r=e*O,o=this.info[e*j+1],n=this.info[e*j+2],a=this.data,l=(o<0?0:this.pose[o*4+2])-this.pose[n*4+2]-a[r+re];this.eC[0]=l-a[r+ge]-t*a[r+fe],this.eC[1]=l-a[r+Fe]-t*a[r+fe+1],this.eG.fill(0),this.eJ.fill(0);for(let c=0;c<2;c++){this.eMin[c]=a[r+Le+c],this.eMax[c]=a[r+xe+c];let u=Math.max(this.eMin[c],Math.min(this.eMax[c],a[r+se+c]*this.eC[c]+a[r+te+c]));i>=0&&u!==0&&(this.eJ[c*3+2]=i===o?1:-1)}return 2}step(){let e=Do(this,2);super.step(),Fo(this,2,e);let t=new Map(this.contactPairs.map(i=>[`${i.a},${i.b}`,i]));for(let i=this.jointCount;i<this.jointCount+this.contactCount;i++){let r=t.get(`${this.info[i*j+1]},${this.info[i*j+2]}`);r&&(r.impulse+=Math.abs(this.data[i*O+te])*this.params.dt)}}};var Vo=(s,e,t)=>{let i=T(e,s);return de(s,q(i,Math.max(0,Math.min(1,G(T(t,s),i)/(G(i,i)||1)))))};function qo(s,e,t,i){let r=T(s,t),o=G(r,e),n=o*o-G(r,r)+i*i;if(n<0)return null;let a=-o-Math.sqrt(n);return a<0?null:{t:a,n:Tt(T(de(s,q(e,a)),t))}}function Rr(s,e){return e&&(!s||e.t<s.t)?e:s}function da(s,e,t,i,r){let o=T(i,t),n=T(s,t),a=G(o,o);if(a<1e-16)return qo(s,e,t,r);let l=G(o,e),c=G(o,n),u=G(n,e),f=a-l*l,d=a*u-c*l,p=a*G(n,n)-c*c-r*r*a,g=d*d-f*p,h=null;if(f>1e-12*a&&g>=0){let m=(-d-Math.sqrt(g))/f,b=c+m*l;m>=0&&b>=0&&b<=a&&(h={t:m,n:Tt(T(de(s,q(e,m)),de(t,q(o,b/a))))})}return Rr(Rr(h,qo(s,e,t,r)),qo(s,e,i,r))}function Ac(s,e){let t=q(e.vertices.reduce((i,r)=>de(i,r),[0,0,0]),1/e.vertices.length);for(let i=0;i<e.vertices.length;i++){let r=e.vertices[i],o=e.vertices[(i+1)%e.vertices.length],n=yt(T(o,r),e.normal);if(G(n,T(s,r))*(G(n,T(t,r))>=0?1:-1)<-1e-6)return!1}return!0}function yf(s,e,t,i){if(i===0){let a=-1/0,l=1/0,c=q(t,-1);for(let u of s.faces){let f=G(u.normal,t),d=G(u.normal,T(u.vertices[0],e));if(Math.abs(f)<1e-12){if(d<0)return null}else{let p=d/f;f<0?p>a&&(a=p,c=u.normal):l=Math.min(l,p)}if(a>l)return null}return l<0?null:{t:Math.max(0,a),n:a<=0?q(t,-1):c}}let r=!0,o=1/0,n=null;for(let a of s.faces){let l=G(a.normal,T(e,a.vertices[0]));l>0&&(r=!1),Ac(T(e,q(a.normal,l)),a)&&(o=Math.min(o,l*l));let c=G(a.normal,t);if(c<-1e-12){let u=(i-l)/c;u>=0&&Ac(T(de(e,q(t,u)),q(a.normal,i)),a)&&(n=Rr(n,{t:u,n:a.normal}))}}for(let[a,l]of s.edges){let c=T(e,Vo(a,l,e));o=Math.min(o,G(c,c)),n=Rr(n,da(e,t,a,l,i))}return r||o<=i*i?{t:0,n:q(t,-1)}:n}var vt=(s,e)=>s[0]*e[0]+s[1]*e[1];function vf(s,e,t,i){let r=!0,o=1/0,n=null;for(let a=0;a<s.vertices.length;a++){let l=s.vertices[a],c=s.vertices[(a+1)%s.vertices.length],u=T(c,l),f=Tt([u[1],-u[0]]),d=vt(T(e,l),f);d>0&&(r=!1);let p=T(e,Vo(l,c,e));o=Math.min(o,vt(p,p));let g=vt(t,f);if(g<-1e-12){let h=(i-d)/g,m=T(de(e,q(t,h)),q(f,i)),b=vt(T(m,l),u),v=1e-6*vt(u,u);h>=0&&b>=-v&&b<=vt(u,u)+v&&(n=Rr(n,{t:h,n:f}))}i>0&&(n=Rr(n,qo(e,t,l,i)))}return r||o<=i*i?{t:0,n:q(t,-1)}:n}function Af(s,e,t,i){if(s.vertices)return vf(s,e,t,i);if(s.kind===3){let p=[-Math.sin(s.angle),Math.cos(s.angle)],g=vt(T(e,s.p),p)-i,h=vt(t,p);return g<=0?{t:0,n:q(t,-1)}:h<-1e-12?{t:-g/h,n:p}:null}let r=s.kind===1?s.p:s.spine[0],o=s.kind===1?s.p:s.spine[1],n=i+s.radius,a=T(e,Vo(r,o,e));if(vt(a,a)<=n*n)return{t:0,n:q(t,-1)};if(n>0)return da(e,t,r,o,n);let l=T(o,r),c=t[0]*l[1]-t[1]*l[0];if(Math.abs(c)<1e-12){let p=T(e,r);if(Math.abs(p[0]*l[1]-p[1]*l[0])/Math.max(Math.hypot(...l),1e-20)>1e-6)return null;let h=Math.min(vt(T(r,e),t),vt(T(o,e),t));return Math.max(vt(T(r,e),t),vt(T(o,e),t))<0?null:{t:Math.max(0,h),n:q(t,-1)}}let u=T(r,e),f=(u[0]*l[1]-u[1]*l[0])/c,d=(u[0]*t[1]-u[1]*t[0])/c;return f>=0&&d>=0&&d<=1?{t:f,n:q(Tt([l[1],-l[0]]),c>0?-1:1)}:null}function xc(s,e,t,i,{maxDistance:r=1e30,ignore:o=[],collidesWith:n=4294967295,includeTriggers:a=!0}={}){let l=s.dimension,c=me(e,l,"origin"),u=me(i,l,"direction"),f=Math.hypot(...u);if(!f||!Number.isFinite(t)||t<0||!Number.isFinite(r)||r<0)throw Error("Provide a nonzero direction, finite nonnegative radius and distance");if(!Number.isInteger(n)||n<0||n>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");let d=new Set(o);for(let h of d)s.liveIndex(h);let p=u.map(h=>h/f),g=null;for(let h=0;h<s.bodyCount;h++){if(d.has(h))continue;let m=l===3?s.solver.bodies[h]:null,b=m?m.group??4294967295:s.solver.filters.get(h)?.[0]??4294967295,v=m?m.isTrigger:s.solver.sensors.has(h);if(!(b&n)||!a&&v)continue;let w;if(l===2)w=Af(No(s.solver,h),c,p,t);else{let A=Ir(m);if(A.spine){let x=A.radius+t,B=T(c,Vo(...A.spine,c));w=G(B,B)<=x*x?{t:0,n:q(p,-1)}:da(c,p,...A.spine,x)}else w=yf(A,c,p,t)}if(!w||w.t>r||g&&w.t>=g.distance)continue;let y=de(c,q(p,w.t));g={index:h,distance:w.t,normal:w.n,center:y,point:T(y,q(w.n,t))}}return g}var Wo=class{constructor(e,{speedThreshold:t=.08,timeThreshold:i=.6}={}){if(!Number.isFinite(t)||t<=0||!Number.isFinite(i)||i<=0)throw Error("Sleep thresholds must be positive and finite");this.world=e,this.speedThreshold=t,this.timeThreshold=i,this.time=new Float64Array(e.bodyCount),this.asleep=new Set}wake(){let e=this.world;for(let t of this.asleep)e.dimension===3?e.solver.bodies[t].sleeping=!1:e.solver.dynamic[t]=+(e.solver.shape[t*4+2]>0);this.asleep.clear(),this.time.fill(0)}after(){let e=this.world,t=e.solver,i=e.bodyCount,r=Int32Array.from({length:i},(d,p)=>p),o=new Set,n=[],a=d=>e.dimension===3?t.bodies[d].mass:t.shape[d*4+2],l=d=>{for(;r[d]!==d;)r[d]=r[r[d]],d=r[d];return d},c=(d,p)=>{if(d<0){o.add(p);return}a(d)<=0?o.add(p):a(p)<=0?o.add(d):r[l(d)]=l(p),n.push([d,p])};if(e.dimension===3){let d=new Map(t.bodies.map((p,g)=>[p,g]));for(let p of t.forces)!p.broken&&!p.bodyA?.isTrigger&&!p.bodyB?.isTrigger&&c(p.bodyA?d.get(p.bodyA):-1,d.get(p.bodyB))}else{for(let d of t.contactPairs)!t.sensors.has(d.a)&&!t.sensors.has(d.b)&&c(d.a,d.b);for(let d=0;d<t.jointCount;d++)(t.data[d*32+6]||t.data[d*32+7]||t.data[d*32+8])&&c(t.info[d*4+1],t.info[d*4+2])}let u=new Set([...o].map(l)),f=new Map;for(let d=0;d<i;d++)if(a(d)>0){let p=l(d),g=e.dimension===3?t.bodies[d]:null,h=g?g.allowSleep!==!1:t.avbdSleepEligible?.get(d)!==!1,m=g?Math.hypot(...g.velocityLin,...g.velocityAng):Math.hypot(...t.velocity.subarray(d*4,d*4+3));f.has(p)||f.set(p,u.has(p)),f.set(p,f.get(p)&&h&&m<=this.speedThreshold)}for(let d=0;d<i;d++)a(d)>0&&(this.time[d]=f.get(l(d))?this.time[d]+e.params.dt:0,this.time[d]>=this.timeThreshold&&(this.asleep.add(d),e.dimension===3?(t.bodies[d].sleeping=!0,t.bodies[d].velocityLin.fill(0),t.bodies[d].velocityAng.fill(0)):(t.dynamic[d]=0,t.velocity.fill(0,d*4,d*4+4))));n.some(([d,p])=>d>=0&&a(d)>0&&a(p)>0&&this.asleep.has(d)!==this.asleep.has(p))&&this.wake()}};var Ho=class{constructor(e,t,i={}){if(this.backend="cpu",this.dimension=t,this.scene=e,this.stepCount=0,this.pending=new ei,this.events=[],this.previous=new Map,this.watched=null,t===3){this.solver=Object.assign(new Go,e.ref),this.solver.up=[...e.up??[0,0,1]],this.nativeRef=e.ref,this.constraints=this.solver.forces.slice();for(let r of this.solver.bodies)r.solver=this.solver;for(let r of this.constraints)r.solver=this.solver;this.constraints.forEach((r,o)=>{let n=e.handles?.get(r);n&&(n.slot=o)}),jo(this.solver)}else this.solver=new Uo(e.topology,e,i.order==="colored"?"soa-colored":"soa-seq"),this.topology=this.solver,this.builder=Object.assign(Object.create(Object.getPrototypeOf(e)),{topology:this.solver,filters:this.solver.filters,sensors:this.solver.sensors,restitution:this.solver.restitution});this.params=t===3?this.solver:this.solver.params,zr(this,t===3?{bodies:this.solver.bodies}:null,t,{setVelocities:this.setPackedVelocities,readSelectedBodies:this.readSelectedBodies}),(i.sleeping||e.sleepOptIn||[...e.topology?.avbdSleepEligible?.values()??[]].some(Boolean))&&this.enableSleeping(i.sleeping===!0?{}:i.sleeping)}get bodyCount(){return this.dimension===3?this.solver.bodies.length:this.solver.bodyCount}get jointCount(){return this.dimension===3?this.constraints.length:this.solver.jointCount}gpuIndex(e){return this.liveIndex(e),e}liveIndex(e){if(this.assertLive(),!Number.isInteger(e)||e<0||e>=this.bodyCount)throw Error("A live body index is required")}assertLive(){if(this.destroyed)throw Error("The solver has been destroyed")}prepareBodyCommands(){return this.wakeAll(),{enqueueValidated:e=>{this.pending.reserve(this.pending.count+e.count),this.pending.u32.set(e.u32.subarray(0,e.count*12),this.pending.count*12),this.pending.count+=e.count}}}setLinearVelocity(e,t){return this.editBodies([{body:e,linearVelocity:t}])}setAngularVelocity(e,t){return this.editBodies([{body:e,angularVelocity:t}])}applyImpulse(e,t,i){return this.editBodies([{body:e,impulse:t,worldPoint:i}])}applyForce(e,t,i){return this.editBodies([{body:e,force:t,worldPoint:i}])}applyAngularImpulse(e,t){return this.editBodies([{body:e,angularImpulse:t}])}applyTorque(e,t){return this.editBodies([{body:e,torque:t}])}teleport(e,t,i){return this.editBodies([{body:e,position:t,rotation:i}])}setPackedVelocities(e,t){let i=Array.from(e),r=t?.linear,o=t?.angular,n=this.dimension,a=n===3?3:1;if(r===void 0&&o===void 0)throw Error("Provide linear or angular velocities");let l=-1;i.forEach(d=>{if(this.liveIndex(d),d<=l)throw Error("Velocity batch indices must be unique and ascending GPU slots");l=d});for(let[d,p]of[[r,n],[o,a]])if(d!==void 0&&(d.length!==i.length*p||!Array.from(d).every(g=>Number.isFinite(Math.fround(g)))))throw Error("Provide finite packed velocity components per body");let c=r===void 0?null:Array.from(r),u=o===void 0?null:Array.from(o),f=i.map((d,p)=>({body:d,...c===null?{}:{linearVelocity:c.slice(p*n,(p+1)*n)},...u===null?{}:{angularVelocity:n===3?u.slice(p*a,(p+1)*a):u[p]}}));return this.editBodies(f),this.flushEdits(),this}flushEdits(){if(this.destroyed)throw Error("The solver has been destroyed");let{words:e,u32:t,count:i}=this.pending,r=this.solver,o=this.dimension;for(let n=0;n<i;n++){let a=n*12,l=t[a],c=t[a+1],u=t[a+2]!==0,f=o===3?r.bodies[l]:null,d=f?.velocityLin??r.velocity.subarray(l*4,l*4+2),p=f?.mass??r.shape[l*4+2],g=f?.positionLin??r.pose.subarray(l*4,l*4+2),h=m=>{if(!(p<=0))if(o===2)r.velocity[l*4+2]+=m[0]/Math.max(1e-10,r.shape[l*4+3]);else{let b=f.positionAng,v=_e([-b[0],-b[1],-b[2],b[3]],m),w=_e(b,v.map((y,A)=>y/Math.max(1e-10,f.moment[A])));for(let y=0;y<3;y++)f.velocityAng[y]+=w[y]}};if(c===0)d.set(e.subarray(a+4,a+4+o));else if(c===1)f?f.velocityAng.set(e.subarray(a+4,a+7)):r.velocity[l*4+2]=e[a+4];else if(c===4)if(g.set(e.subarray(a+4,a+4+o)),f){u&&f.positionAng.set(e.subarray(a+8,a+12)),f.initialLin.set(g),f.inertialLin.set(g),f.initialAng.set(f.positionAng),f.inertialAng.set(f.positionAng);for(let m of[...f.forces])m.contacts&&m.destroy()}else u&&(r.pose[l*4+2]=e[a+6]),r.initial.set(r.pose.subarray(l*4,l*4+4),l*4),r.inertial.set(r.pose.subarray(l*4,l*4+4),l*4),r.prevCount=0;else if(c===2||c===3){if(p<=0)continue;let m=Array.from(e.subarray(a+4,a+4+o),b=>b*(c===3?e[a+7]:1));for(let b=0;b<o;b++)d[b]+=m[b]/p;if(u){let b=Array.from(e.subarray(a+8,a+8+o),(v,w)=>v-g[w]);h(o===3?yt(b,m):[b[0]*m[1]-b[1]*m[0]])}}else(c===5||c===6)&&h(Array.from(e.subarray(a+4,a+4+(o===3?3:1)),m=>m*(c===6?e[a+7]:1)))}this.pending.count=0}step(){this.flushEdits(),this.solver.step(),this.sleeping?.after(),this.stepCount++,this.captureEvents()}attachToScene(e,t){return Po.call(this,e,t)}detachFromScene(){return Lo.call(this)}setFilters(e,t,i){let r=Array.from(e),o=Array.from(t),n=Array.from(i);if(o.length!==r.length||n.length!==r.length)throw Error("Provide one group and mask per body");r.forEach(a=>this.liveIndex(a));for(let a of[...o,...n])if(!Number.isInteger(a)||a<0||a>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");r.forEach((a,l)=>{this.dimension===3?Object.assign(this.solver.bodies[a],{group:o[l],collidesWith:n[l]}):this.solver.filters.set(a,[o[l],n[l]])}),this.wakeAll()}setSensor(e,t){if(this.liveIndex(e),typeof t!="boolean")throw Error("Trigger flag must be boolean");this.dimension===3?this.solver.bodies[e].isTrigger=t:t?this.solver.sensors.add(e):this.solver.sensors.delete(e),this.wakeAll()}setRestitution(e,t){if(this.liveIndex(e),!Number.isFinite(t)||t<0||t>1)throw Error("restitution must be between 0 and 1");this.dimension===3?this.solver.bodies[e].restitution=t:this.solver.restitution.set(e,t),this.wakeAll()}setMotor(e,t){if(this.assertLive(),this.dimension===3){let i=this.constraints[e];if(!i?.cpuAngular)throw Error("A motor constraint is required");Object.assign(i.cpuAngular.options,kt({...i.cpuAngular.options,...t}))}else{let i=this.solver,r=e*O;if(!Number.isInteger(e)||e<0||e>=i.jointCount||i.info[e*4]!==3)throw Error("A motor constraint is required");let o=t.speed??i.data[r+re],n=t.maxTorque??i.data[r+xe];if(!Number.isFinite(o)||!Number.isFinite(n)||n<0)throw Error("Provide finite motor speed and nonnegative torque");i.data[r+re]=o,i.data[r+Le]=-n,i.data[r+xe]=n}this.wakeAll()}setAngleLimits(e,t){if(this.assertLive(),this.dimension!==2)throw Error("Use a 3D hinge constraint");if(this.solver.info[e*4]!==5)throw Error("An angular limit is required");os(this.solver,e,Ci(t)),this.wakeAll()}releaseJoints(e){for(let t of e)this.disableConstraint(t)}disableConstraint(e){if(this.assertLive(),!Number.isInteger(e)||e<0||e>=this.jointCount)throw Error("A live constraint slot is required");if(this.dimension===3){let t=this.constraints[e];t.broken=!0,(t.cpuAngular??t).destroy()}else this.solver.disable(e),this.solver.info[e*4]=0,this.solver.noCollideDirty=!0;this.wakeAll()}setWorldAnchor(e,t,i){if(this.assertLive(),this.dimension===2){let r=this.solver;if(!Number.isInteger(e)||e<0||e>=r.jointCount||r.info[e*4+1]!==-1)throw Error("A world-anchor constraint is required");r.data.set(me([t,i],2,"point"),e*O+21)}else{let r=this.constraints[e];if(!r||r.bodyA)throw Error("A world-anchor constraint is required");r.rA.set(me(t,3,"point"))}this.wakeAll()}addBox(...e){return this.addDynamic("addBox",e)}addCircle(...e){return this.addDynamic("addCircle",e)}addCapsule(...e){return this.addDynamic("addCapsule",e)}addHull(...e){return this.addDynamic("addHull",e)}addSegment(...e){return this.addDynamic("addSegment",e)}addPlane(...e){return this.addDynamic("addPlane",e)}addDynamic(e,t){if(this.destroyed)throw Error("The solver has been destroyed");if(this.dimension!==2)throw Error("Build 3D bodies before creating the solver");this.wakeAll();let i=this.sleeping?{speedThreshold:this.sleeping.speedThreshold,timeThreshold:this.sleeping.timeThreshold}:null,r=this.builder[e](...t);return i&&this.enableSleeping(i),r}appendJoint(e,t,i,r,o,n=1/0){if(this.assertLive(),this.dimension!==2)throw Error("Build 3D constraints before creating the solver");return this.wakeAll(),this.builder.addJoint(e,t,i,r,{stiffness:o,breakForce:n}).slot}captureConstraintFrames(e){if(this.assertLive(),this.dimension!==3)throw Error("Constraint frame capture requires a 3D world");let t=Array.from(e);for(let{slot:i,spring:r}of t){let o=this.constraints[i];if(!Number.isInteger(i)||!o||o.broken||o.cpuAngular||(r?o.rest===void 0:o.stiffnessAng===void 0))throw Error("A live spring or joint slot is required")}this.flushEdits();for(let{slot:i,spring:r}of t)fa(this.constraints[i],r);t.length&&this.wakeAll()}setSpringMaterial(e,t={}){this.assertLive();let i=this.constraints[e];if(!i||i.rest===void 0)throw Error("A spring constraint is required");gr(i,It(t)),this.wakeAll()}packBodyRecords(e,t=!1){let i=this.solver,r=this.dimension,o=t?r===3?8:4:r===3?40:24,n=e?.length??this.bodyCount,a=new Float32Array(n*o);for(let l=0;l<n;l++){let c=e?.[l]??l,u=l*o;if(t){if(r===3){let f=i.bodies[c];a.set(f.positionLin,u),a[u+3]=f.friction,a.set(f.positionAng,u+4)}else a.set(i.pose.subarray(c*4,c*4+4),u),a[u+3]=i.props[c*4];continue}if(r===3){let f=i.bodies[c];a.set(f.positionLin,u),a[u+3]=f.friction,a.set(f.positionAng,u+4),a.set(f.initialLin,u+8),a[u+11]=+!!f.isTrigger,a.set(f.initialAng,u+12),a.set(f.size,u+16),a[u+19]=f.sleeping?0:f.mass,a.set(f.moment,u+20),a[u+23]=f.radius,a.set(f.inertialLin,u+24),a.set(f.inertialAng,u+28),a.set(f.velocityLin,u+32),a[u+35]=f.prevVelocityLin.reduce((d,p,g)=>d+p*i.up[g],0),a.set(f.velocityAng,u+36),a[u+39]=De(f)?1:He(f)?-1:wt(f)?3:sr(f)?2:0}else a.set(i.pose.subarray(c*4,c*4+4),u),a[u+3]=i.props[c*4],a.set(i.initial.subarray(c*4,c*4+4),u+4),a.set(i.inertial.subarray(c*4,c*4+4),u+8),a.set(i.velocity.subarray(c*4,c*4+4),u+12),a.set(i.prevVelocity.subarray(c*4,c*4+4),u+16),a.set(i.shape.subarray(c*4,c*4+4),u+20)}return a}async readBodies(){return this.flushEdits(),this.packBodyRecords()}async readSelectedBodies(e,{posesOnly:t=!1}={}){let i=Array.from(e);return i.forEach(r=>this.liveIndex(r)),this.flushEdits(),this.packBodyRecords(i,t)}async readBodyState(e){this.liveIndex(e),this.flushEdits();let t=this.solver;if(this.dimension===3){let i=t.bodies[e],r=this.sleeping?.asleep.has(e)??!1;return{position:Array.from(i.positionLin),rotation:Array.from(i.positionAng),linearVelocity:Array.from(i.velocityLin),angularVelocity:Array.from(i.velocityAng),mass:i.mass,effectiveMass:r?0:i.mass,sleeping:r}}return{position:Array.from(t.pose.subarray(e*4,e*4+2)),angle:t.pose[e*4+2],linearVelocity:Array.from(t.velocity.subarray(e*4,e*4+2)),angularVelocity:t.velocity[e*4+2],mass:t.shape[e*4+2],moment:t.shape[e*4+3],sleeping:this.sleeping?.asleep.has(e)??!1}}async readJoints(){return this.flushEdits(),this.packJointRecords()}packJointRecords(){let e=this.dimension===3?32:36,t=new Float32Array(this.jointCount*e),i=r=>r===1/0?3e38:r===-1/0?-3e38:r;if(this.dimension===2){let r=this.solver.data;for(let o=0;o<this.jointCount;o++){let n=o*36,a=o*O;[se,te,Q,Le,xe,Pt,fe].forEach((l,c)=>{for(let u=0;u<3;u++)t[n+c*4+u]=i(r[a+l+u])}),t.set([r[a+U],r[a+U+1],r[a+Y],r[a+Y+1]],n+28),t.set([r[a+re],r[a+re+1],r[a+re+2],0],n+32)}}else this.constraints.forEach((r,o)=>{let n=o*32;if(r.cpuAngular){let a=r.cpuAngular,l=a.options;t.set(a.pen,n),t[n+3]=r.broken?0:1,t.set(a.lam,n+8),t.set(a.ta,n+16),t.set(a.tb,n+20),t.set(l.axisA,n+24),t.set(l.axisB,n+28),t[n+19]=a.c0?.[0]??0,t[n+23]=a.c0?.[1]??0,t[n+27]=l.type==="motor"?l.speed:l.minAngle,t[n+31]=l.type==="motor"?l.maxTorque:l.maxAngle;return}for(let[a,l]of[["penaltyLin",0],["penaltyAng",4],["lambdaLin",8],["lambdaAng",12],["C0Lin",16],["C0Ang",20],["rA",24],["rB",28]])r[a]&&t.set(r[a],n+l);if(t[n+3]=r.broken?0:i(r.stiffnessLin??r.stiffness??0),t[n+7]=r.broken?0:i(r.stiffnessAng??0),t[n+11]=i(r.fracture??0),t[n+15]=r.torqueArm??0,t[n+27]=r.rest??0,r.cpuRest&&(t[n+19]=r.cpuRest[0],t[n+23]=r.cpuRest[1],t[n+27]=r.cpuRest[2],t[n+31]=r.cpuRest[3]),r.rest!==void 0){let a=Gi(r);t[n+11]=Number.isFinite(a?.breakStrain)?a.breakStrain:0,t[n+15]=Number.isFinite(a?.breakForce)?a.breakForce:0}});return t}async readCounters(){this.assertLive();let e=this.dimension===2?this.solver.contactCount:this.solver.forces.reduce((i,r)=>i+(r.contacts?.length??0),0),t=this.dimension===2?this.solver.contactPairs.length:this.solver.forces.filter(i=>i.contacts?.length).length;return{pairs:t,contacts:e,manifolds:t,joints:this.jointCount,overflow:0,clashes:0,colors:0,sleeping:this.sleeping?.asleep.size??0}}adapt(){}watchContacts({indices:e,maxPairs:t=this.maxPairs??8192,maxEvents:i=this.maxEvents??4096}={}){if(this.assertLive(),!Number.isInteger(i)||i<1||!Number.isInteger(t)||t<1)throw Error("Contact capacities must be positive integers");return e!==void 0?(e.forEach(r=>this.liveIndex(r)),this.watched=new Set(e)):this.watched??=new Set(Array.from({length:this.bodyCount},(r,o)=>o)),this.maxEvents=i,this.maxPairs=t,this}captureEvents(){if(!this.watched)return;let e=this.dimension===3?new Map(this.solver.bodies.map((i,r)=>[i,r])):null,t=this.dimension===2?this.solver.contactPairs:this.solver.forces.filter(i=>i.contacts?.length).map(i=>{let r=Array.from(i.bodyA.positionLin);for(let o of i.contacts){let n=_e(i.bodyA.positionAng,o.rA);for(let a=0;a<3;a++)r[a]+=n[a]/i.contacts.length}return{a:e.get(i.bodyA),b:e.get(i.bodyB),point:r,normal:Array.from(i.basis.slice(0,3)),impulse:i.bodyA.isTrigger||i.bodyB.isTrigger?0:i.contacts.reduce((o,n)=>o+Math.abs(n.lambda[0])*this.params.dt,0)}});this.trackContactPairs(t)}trackContactPairs(e){let t=new Map,i=(n,a)=>{this.events.length<(this.maxEvents??4096)?this.events.push({...n,normal:n.normal??[...n.n,0],type:a,kind:a==="begin"?1:2,step:this.stepCount,isTrigger:n.isTrigger??(this.dimension===3?!!(this.solver.bodies[n.a].isTrigger||this.solver.bodies[n.b].isTrigger):this.solver.sensors.has(n.a)||this.solver.sensors.has(n.b))}):this.dropped=(this.dropped??0)+1},r=new Set,o=[];for(let n of e){if(!this.watched.has(n.a)&&!this.watched.has(n.b))continue;let a=`${Math.max(n.a,n.b)},${Math.min(n.a,n.b)}`;r.add(a),this.previous.has(a)&&t.size<this.maxPairs?t.set(a,n):o.push([a,n])}for(let[n,a]of o)if(!t.has(n)){if(t.size>=this.maxPairs){this.pairFull=!0;continue}t.set(n,a),this.previous.has(n)||i(a,"begin")}for(let[n,a]of this.previous)r.has(n)||i({...a,impulse:0},"end");this.previous=t}async readContactEvents(){this.watchContacts();let e={events:this.events,dropped:this.dropped??0,full:!!this.dropped||!!this.pairFull};return this.events=[],this.dropped=0,this.pairFull=!1,e}async raycast(e,t,i){return this.sphereCast(e,0,t,i)}async circleCast(e,t,i,r){return this.sphereCast(e,t,i,r)}async sphereCast(e,t,i,r){return this.flushEdits(),xc(this,e,t,i,r)}async raycastAll(e,t){return Promise.all(e.map(i=>this.raycast(i.origin,i.direction,{...t,maxDistance:i.maxDistance??t?.maxDistance})))}async sphereCastAll(e,t){return Promise.all(e.map(i=>this.sphereCast(i.origin,i.radius,i.direction,{...t,maxDistance:i.maxDistance??t?.maxDistance})))}async circleCastAll(e,t){return this.sphereCastAll(e,t)}setSleepEnabled(e,t){if(this.liveIndex(e),typeof t!="boolean")throw Error("Sleep flag must be boolean");return this.dimension===3?this.solver.bodies[e].allowSleep=t:(this.solver.avbdSleepEligible??=new Map,this.solver.avbdSleepEligible.set(e,t)),t&&!this.sleeping&&this.enableSleeping(),this.wakeAll(),this}enableSleeping(e={}){return this.assertLive(),this.disableSleeping(),this.sleeping=new Wo(this,e),this}disableSleeping(){return this.sleeping?.wake(),this.sleeping=null,this}async readSleepStats(){return this.assertLive(),{sleeping:this.sleeping?.asleep.size??0,wakeRequested:!1}}wakeUp(e){return this.liveIndex(e),this.wakeAll()}wakeAll(){return this.sleeping?.wake(),this}destroy(){this.destroyed||(this.detachFromScene(),this.disableSleeping(),this.pending.count=0,this.events=[],this.previous.clear(),this.destroyed=!0)}};var wc=new WeakSet,Jo=s=>s!==null&&typeof s=="object"&&wc.has(s),Bc=s=>wc.add(s);async function xf({backend:s="webgpu",device:e,gl:t,validate3D:i=!0,...r}={}){if(!["webgpu","cpu"].includes(s))throw Error(`Unsupported solver backend: ${s}`);if(s!=="webgpu"&&e!==void 0)throw Error("Only WebGPU initialization accepts a GPU device");if(t!==void 0)throw Error("Solver pipelines do not accept a WebGL context");let o,n=!1,a=!1;s==="webgpu"&&(e?i&&await xr(e):({device:e,adapter:o}=await Jr({...r,preferredLimits:{maxStorageBuffersPerShaderStage:9,maxStorageBufferBindingSize:512*1024*1024,maxBufferSize:1024*1024*1024,...r.preferredLimits},validate3D:i}),n=!0));let l=new Set,c={backend:s,device:e,adapter:o,createSolver(u,f={}){if(a)throw Error("The solver pipeline has been destroyed");if(!u||typeof u.assertEditable!="function"||!u.ref&&!u.topology)throw Error("An AVBD scene builder is required");u.assertEditable();let d;if(s==="webgpu")d=u.createSolver(e,f);else{let g=u.ref?3:u.topology?2:0;if(f.bodyBuffer!==void 0)throw Error("A GPU body buffer requires the WebGPU backend");d=new Ho(u,g,f),u.gpu=d,u.created=!0}Object.defineProperty(d,"backend",{value:s,configurable:!0}),l.add(d);let p=d.destroy;return d.destroy=function(){p.call(this),l.delete(this)},d},destroy(){if(!a){for(let u of l)u.destroy();l.clear(),n&&e.destroy(),a=!0}}};return Bc(c),c}var ie=(s,e,t)=>{let i=Array.from(s);if(i.length!==e||!i.every(Number.isFinite))throw Error(`${t} requires ${e} finite components`);return i},K=(s,e,t=!1)=>{if(!Number.isFinite(s)||(t?s<0:s<=0))throw Error(`${e} must be ${t?"nonnegative":"positive"} and finite`);return s},Cc=s=>{if(!Number.isInteger(s)||s<0||s>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");return s};function $o(s){for(let t of["allowSleep","isTrigger"])if(s[t]!==void 0&&typeof s[t]!="boolean")throw Error(`${t} must be a boolean`);let e=s.restitution??0;if(!Number.isFinite(e)||e<0||e>1)throw Error("restitution must be between 0 and 1");if(s.mass!==void 0&&(K(s.mass,"mass",!0),s.mass>0&&s.density===0))throw Error("A positive mass needs positive density");for(let t of["velocity","angularVelocity"])s[t]!==void 0&&ie(s[t],3,t);if(s.rotation!==void 0&&!Math.hypot(...ie(s.rotation,4,"rotation")))throw Error("rotation must be nonzero");Cc(s.group??4294967295),Cc(s.collidesWith??4294967295)}function Sc(s,e){if(e.timeStep!==void 0&&(s.dt=K(e.timeStep,"timeStep")),e.iterations!==void 0){if(K(e.iterations,"iterations"),!Number.isInteger(e.iterations))throw Error("iterations must be an integer");s.iterations=e.iterations}if(e.gravity!==void 0){if(!Number.isFinite(e.gravity))throw Error("gravity must be finite");s.gravity=e.gravity}}var ha=class{constructor(e={}){if(this.ref=new ni,Sc(this.ref,e),this.up=ie(e.up??[0,1,0],3,"up"),Math.abs(Math.hypot(...this.up)-1)>1e-5)throw Error("up must be a unit vector");this.points=!1,this.handles=new Map,this.bodySet=new Set}get bodies(){return this.ref.bodies}get constraints(){return[...this.handles.values()]}assertEditable(){if(this.created)throw Error("Build this scene before createSolver; use the solver's GPU edit methods afterwards")}addBox(e,t={}){this.assertEditable(),$o(t);let i=ie(e,3,"size");i.forEach(o=>K(o,"size"));let r=new Ze(this.ref,i,K(t.density??1,"density",!0),K(t.friction??.6,"friction",!0),ie(t.position??[0,0,0],3,"position"));return this.configure(r,t)}addSphere(e,t={}){return this.assertEditable(),$o(t),this.configure(or(this.ref,K(e,"radius"),K(t.density??1,"density",!0),K(t.friction??.6,"friction",!0),ie(t.position??[0,0,0],3,"position")),t)}addHull(e,t={}){if(this.assertEditable(),$o(t),e.length%3||!Array.from(e).every(Number.isFinite))throw Error("Hull points must contain finite xyz triples");let i=jr(e);if(!i)throw Error("A convex hull requires finite points spanning a volume");return this.hulls=!0,this.configure(Bs(this.ref,i,K(t.density??1,"density",!0),K(t.friction??.6,"friction",!0),ie(t.position??[0,0,0],3,"position")),t)}addCapsule(e,t,i={}){return this.assertEditable(),$o(i),this.configure(Ar(this.ref,e,t,K(i.density??1,"density",!0),K(i.friction??.6,"friction",!0),ie(i.position??[0,0,0],3,"position")),i)}configure(e,t){if(t.allowSleep!==void 0&&typeof t.allowSleep!="boolean")throw Error("allowSleep must be a boolean");e.allowSleep=t.allowSleep??!0,this.sleepOptIn||=t.allowSleep===!0;let i=t.restitution??0;if(!Number.isFinite(i)||i<0||i>1)throw Error("restitution must be between 0 and 1");if(e.restitution=i,t.isTrigger!==void 0&&typeof t.isTrigger!="boolean")throw Error("isTrigger must be a boolean");if(e.isTrigger=t.isTrigger??!1,e.group=t.group??4294967295,e.collidesWith=t.collidesWith??4294967295,t.mass!==void 0){let r=K(t.mass,"mass",!0);if(e.mass===0&&r>0)throw Error("A positive mass needs positive density");let o=e.mass>0?r/e.mass:0;e.mass=r,e.moment.forEach((n,a)=>e.moment[a]=n*o)}if(t.rotation){let r=ie(t.rotation,4,"rotation"),o=Math.hypot(...r);if(!o)throw Error("rotation must be nonzero");e.positionAng.set(r.map(n=>n/o))}return t.velocity&&e.velocityLin.set(ie(t.velocity,3,"velocity")),t.angularVelocity&&e.velocityAng.set(ie(t.angularVelocity,3,"angularVelocity")),this.bodySet.add(e),e}addPoint(e,{mass:t=.02,radius:i=.05,friction:r=.5}={}){let o=this.addSphere(i,{position:e,mass:t,friction:r});return o.moment.fill(0),this.points=!0,o}addFabric({columns:e=16,rows:t=16,spacing:i=.2,origin:r=[0,3,0],mass:o=.02,stiffness:n=1e3,anchorStiffness:a=n,materialAt:l,breakStrain:c=1/0,breakForce:u=1/0,bendingStiffness:f=Number.isFinite(c)||Number.isFinite(u)?0:n/50,pinCorners:d=!1,pinEdges:p=!d}={}){for(let[z,_]of Object.entries({columns:e,rows:t}))if(!Number.isInteger(_)||_<2)throw Error(`${z} must be an integer >= 2`);if(K(i,"spacing"),K(o,"mass"),K(n,"stiffness"),K(a,"anchorStiffness"),l!==void 0&&typeof l!="function")throw Error("materialAt must be a function");if(K(f,"bendingStiffness",!0),typeof d!="boolean"||typeof p!="boolean")throw Error("Fabric pin options must be boolean");let g=It({breakStrain:c,breakForce:u}),h=ie(r,3,"origin"),m=(z,_)=>`${Math.min(z,_)},${Math.max(z,_)}`;function*b(){for(let z=0;z<t;z++)for(let _=0;_<e;_++){let k=z*e+_;_&&(yield[k,k-1,n]),z&&(yield[k,k-e,n]),_&&z&&(yield[k,k-e-1,n/2],yield[k-1,k-e,n/2]),_>1&&f&&(yield[k,k-2,f]),z>1&&f&&(yield[k,k-2*e,f])}}let v=new Map;if(l)for(let[z,_]of b()){let k=l((z%e+_%e)/(2*(e-1)),(Math.floor(z/e)+Math.floor(_/e))/(2*(t-1)))??{};if(typeof k!="object"||Array.isArray(k))throw Error("materialAt must return a material object");v.set(m(z,_),{scale:K(k.stiffnessScale??1,"materialAt.stiffnessScale"),material:It({...g,...k})})}let w=Array.from({length:t},(z,_)=>Array.from({length:e},(k,S)=>this.addPoint([h[0]+(S-(e-1)/2)*i,h[1],h[2]+(_-(t-1)/2)*i],{mass:p&&(S===0||_===0||S===e-1||_===t-1)||d&&(S===0||S===e-1)&&(_===0||_===t-1)?0:o,radius:i/Math.SQRT2}))),y=w.flat(),A=new Map(y.map((z,_)=>[z,_])),x=[],B=new Map,E=(z,_,k)=>{(z.mass===0||_.mass===0)&&(k*=a/n);let S=A.get(z),P=A.get(_),I=v.get(m(S,P)),R=this.addSpring(z,_,[0,0,0],[0,0,0],{stiffness:k*(I?.scale??1),...I?.material??g});return B.set(m(A.get(z),A.get(_)),x.length),x.push(R),R};for(let[z,_,k]of b())E(y[z],y[_],k);let L=[];for(let z=0;z<t;z++)for(let _=0;_<e;_++)if(_&&z){let k=(z-1)*e+_-1,S=k+1,P=z*e+_-1,I=P+1;L.push(k,P,S,S,P,I)}let M=[];for(let z=0;z<L.length;z+=3){let[_,k,S]=L.slice(z,z+3);M.push(B.get(m(_,k)),B.get(m(k,S)),B.get(m(S,_)))}return{points:y,grid:w,indices:Uint32Array.from(L),connections:x,triangleConnections:Uint32Array.from(M)}}addRope({segments:e=12,length:t=12,origin:i=[0,12,0],width:r=.15,endMass:o=20}={}){if(!Number.isInteger(e)||e<1)throw Error("segments must be a positive integer");K(t,"length"),K(r,"width"),K(o,"endMass",!0);let n=ie(i,3,"origin"),a=t/e,l=this.addBox([r,r,r],{mass:0,position:n}),c=[];for(let u=0;u<e;u++){let f=this.addBox([r,a,r],{mass:1,position:[n[0],n[1]-(u+.5)*a,n[2]]});this.addJoint(u?c[u-1]:l,f,[0,u?-a/2:0,0],[0,a/2,0]),c.push(f)}if(o){let u=this.addBox([.6,.6,.6],{mass:o,position:[n[0],n[1]-t-.3,n[2]]});this.addJoint(c.at(-1),u,[0,-a/2,0],[0,.3,0]),c.push(u)}return{anchor:l,links:c}}addRagdoll({origin:e=[0,2,0],mass:t=10}={}){let i=ie(e,3,"origin");K(t,"mass");let r=(l,c)=>this.addBox(l,{mass:t/10,position:c.map((u,f)=>u+i[f])}),o=r([.7,1.2,.35],[0,2,0]),n=this.addSphere(.25,{mass:t/10,position:[i[0],i[1]+2.9,i[2]]}),a=[o,n];this.addJoint(o,n,[0,.6,0],[0,-.3,0]);for(let l of[-1,1]){let c=r([.3,.8,.3],[l*.5,1.95,0]),u=r([.26,.7,.26],[l*.5,1.2,0]);this.addJoint(o,c,[l*.35,.35,0],[-l*.15,.4,0]),this.addJoint(c,u,[0,-.4,0],[0,.35,0]);let f=r([.28,.8,.3],[l*.2,1,0]),d=r([.26,.75,.28],[l*.2,.225,0]);this.addJoint(o,f,[l*.2,-.6,0],[0,.4,0]),this.addJoint(f,d,[0,-.4,0],[0,.375,0]),a.push(c,u,f,d)}return{torso:o,head:n,bodies:a}}addJoint(e,t,i=[0,0,0],r=[0,0,0],{linearStiffness:o=1/0,angularStiffness:n=0,breakForce:a=1/0,breakOnPull:l=!1}={}){this.assertEditable(),this.checkBodies(e,t);for(let c of[o,n,a])c!==1/0&&K(c,"joint stiffness/breakForce",!0);return this.handle(new ke(this.ref,e,t,ie(i,3,"anchorA"),ie(r,3,"anchorB"),o,n,l&&a!==1/0?-a:a))}addSpring(e,t,i=[0,0,0],r=[0,0,0],{stiffness:o=1e3,rest:n=-1,breakStrain:a=1/0,breakForce:l=1/0}={}){if(this.assertEditable(),this.checkBodies(e,t),!e)throw Error("A spring requires two bodies");K(o,"stiffness",!0),n!==-1&&K(n,"rest",!0);let c=It({breakStrain:a,breakForce:l}),u=new ut(this.ref,e,t,ie(i,3,"anchorA"),ie(r,3,"anchorB"),o,n);return gr(u,c),this.handle(u)}checkBodies(e,t){if(!t||e===t||!this.bodySet.has(t)||e&&!this.bodySet.has(e))throw Error("Constraint endpoints must be distinct bodies in this scene")}addMotor(e,t,i={}){this.assertEditable(),this.checkBodies(e,t);let r=kt({...i,type:"motor"}),o=new ke(this.ref,e,t,[0,0,0],[0,0,0],1/0,0);return vr(o,r),this.handle(o)}addHinge(e,t,i={}){this.assertEditable(),this.checkBodies(e,t);let r=kt({...i,type:"limit"}),o=K(i.span??1,"span"),n=ie(i.anchorA??[0,0,0],3,"anchorA"),a=ie(i.anchorB??[0,0,0],3,"anchorB"),l=[-1,1].map(f=>this.addJoint(e,t,n.map((d,p)=>d+f*o*.5*r.axisA[p]),a.map((d,p)=>d+f*o*.5*r.axisB[p]))),c,u;if(i.minAngle!==void 0||i.maxAngle!==void 0){let f=new ke(this.ref,e,t,[0,0,0],[0,0,0],1/0,0);vr(f,r),c=this.handle(f)}return i.motor&&(u=this.addMotor(e,t,{axisA:r.axisA,axisB:r.axisB,...i.motor})),{joints:l,limit:c,motor:u,dispose(){for(let f of[...l,c,u])f?.dispose()}}}handle(e){let t={slot:-1,disposed:!1,dispose:()=>{t.disposed||(this.gpu?this.gpu.destroyed||this.gpu.releaseJoints([t.slot]):e.destroy(),this.handles.delete(e),t.disposed=!0)}};return t.destroy=t.dispose,this.handles.set(e,t),t}createSolver(e,t={}){if(Jo(e))return e.createSolver(this,t);if(this.assertEditable(),this.hulls&&e.limits.maxStorageBuffersPerShaderStage<9)throw Error("Hull collisions require nine storage buffer bindings");let i=new Eo(e,this.ref,Ws(this.ref,{...t,...this.points?{shaders:{...t.shaders,solve:tc}}:{}})),r=[];this.ref.forces.forEach((l,c)=>{this.handles.get(l).slot=c,l instanceof ke&&l.stiffnessAng>0&&r.push({slot:c})}),i.captureConstraintFrames(r),i.params.up=[...this.up];let o=[],n=[],a=[];for(let[l,c]of this.ref.bodies.entries())(c.group!==4294967295||c.collidesWith!==4294967295)&&(o.push(i.gpuIndex(l)),n.push(c.group),a.push(c.collidesWith)),c.isTrigger&&i.setSensor(i.gpuIndex(l),!0),c.restitution>0&&i.setRestitution(i.gpuIndex(l),c.restitution);return o.length&&i.setFilters(o,n,a),(t.sleeping||this.sleepOptIn)&&i.enableSleeping(this.ref,t.sleeping===!0?{}:t.sleeping),this.gpu=i,this.created=!0,i}},pa=class{constructor(e={}){if(this.topology=new Lr,Object.assign(this.topology.params,io()),Sc(this.topology.params,e),e.alpha!==void 0){if(!Number.isFinite(e.alpha)||e.alpha<0||e.alpha>1)throw Error("alpha must be between zero and one");this.topology.params.alpha=e.alpha}for(let t of["postStabilize","matchNearest"])if(e[t]!==void 0){if(typeof e[t]!="boolean")throw Error(`${t} must be boolean`);this.topology.params[t]=e[t]}}assertEditable(){if(this.created)throw Error("Build this scene before createSolver; use GPU edit methods afterwards")}get bodyCount(){return this.topology.bodyCount}addShape(e,t={}){let i=e.options??t,r=this.addBox(e.size,i);return Er(this.topology,r,e,i.density??1),r}addCircle(e,t={}){return this.addShape(Ao(e),t)}addHull(e,t={}){return this.addShape(vo(e),t)}addCapsule(e,t,i={}){return this.addShape(xo(e,t),i)}addSegment(e,t,i={}){return this.addShape(wo(e,t,i))}addPlane(e=[0,1],t=0,i={}){return this.addShape(Bo(e,t,i))}addBox(e,{density:t=1,friction:i=.6,position:r=[0,0],angle:o=0,velocity:n=[0,0,0],restitution:a=0,isTrigger:l=!1,group:c=4294967295,collidesWith:u=4294967295,allowSleep:f}={}){if(this.assertEditable(),f!==void 0&&typeof f!="boolean")throw Error("allowSleep must be boolean");let d=ie(e,2,"size");d.forEach(h=>K(h,"size"));let p=ie(r,2,"position");if(!Number.isFinite(o))throw Error("angle must be finite");if(!Number.isFinite(a)||a<0||a>1)throw Error("restitution must be between 0 and 1");if(typeof l!="boolean")throw Error("isTrigger must be boolean");for(let h of[c,u])if(!Number.isInteger(h)||h<0||h>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");let g=this.topology.addBody(d,K(t,"density",!0),K(i,"friction",!0),[...p,o],ie(n,3,"velocity"));return this.restitution??=new Map,a>0&&this.restitution.set(g,a),this.sensors??=new Set,l&&this.sensors.add(g),this.filters??=new Map,(c!==4294967295||u!==4294967295)&&this.filters.set(g,[c,u]),this.topology.avbdSleepEligible??=new Map,f!==void 0&&this.topology.avbdSleepEligible.set(g,f),g}checkBodies(e,t){if(!Number.isInteger(e)||!Number.isInteger(t)||e<-1||e>=this.bodyCount||t<0||t>=this.bodyCount||e===t)throw Error("Invalid 2D constraint endpoints")}addJoint(e,t,i=[0,0],r=[0,0],{stiffness:o=[1/0,1/0,0],breakForce:n=1/0}={}){if(this.assertEditable(),this.checkBodies(e,t),!o||o.length!==3||Array.from(o).some(l=>l!==1/0&&(!Number.isFinite(l)||l<0))||n!==1/0&&(!Number.isFinite(n)||n<0))throw Error("Joint stiffness and break force must be nonnegative or Infinity");let a=this.topology.addJoint(e,t,ie(i,2,"anchorA"),ie(r,2,"anchorB"),o,n);return this.constraintHandle(a.slot,a)}constraintHandle(e,t={}){return Object.assign(t,{slot:e,alive:!0,disposed:!1}),t.dispose=()=>{t.disposed||(this.gpu&&!this.gpu.destroyed?this.gpu.disableConstraint(e):this.gpu||this.topology.data.fill(0,e*O+Q,e*O+Q+3),t.alive=!1,t.disposed=!0)},t.destroy=t.dispose,this.topology.handles[e]=t,t}addSpring(e,t,i=[0,0],r=[0,0],{stiffness:o=1e3,rest:n=1}={}){if(this.assertEditable(),this.checkBodies(e,t),e<0)throw Error("A spring requires two bodies");let a=this.topology.jointCount;return this.topology.addSpring(e,t,ie(i,2,"anchorA"),ie(r,2,"anchorB"),K(o,"stiffness",!0),K(n,"rest",!0)),this.constraintHandle(a)}addMotor(e,t,{speed:i=1,maxTorque:r=100}={}){if(this.assertEditable(),this.checkBodies(e,t),!Number.isFinite(i))throw Error("speed must be finite");let o=this.topology.jointCount;return this.topology.addMotor(e,t,i,K(r,"maxTorque",!0)),this.constraintHandle(o)}addAngularLimit(e,t,i={}){this.assertEditable(),this.checkBodies(e,t);let r=Ci(i),o=this.topology.addJoint(e,t,[0,0],[0,0],[0,0,0]);os(this.topology,o.slot,r);let n=this.constraintHandle(o.slot,o);return n.setLimits=a=>{if(n.disposed)throw Error("The angular limit has been disposed");return this.gpu?this.gpu.setAngleLimits(n.slot,a):os(this.topology,n.slot,Ci(a)),n},n}addHinge(e,t,i=[0,0],r=[0,0],o={}){this.assertEditable(),this.checkBodies(e,t);let n=ie(i,2,"anchorA"),a=ie(r,2,"anchorB"),l=o.minAngle!==void 0||o.maxAngle!==void 0?Ci(o):null,c=o.motor;if(c){if(!Number.isFinite(c.speed??1))throw Error("speed must be finite");K(c.maxTorque??100,"maxTorque",!0)}let u=this.addJoint(e,t,n,a),f=l?this.addAngularLimit(e,t,l):null,d=c?this.addMotor(e,t,c):null;return{joint:u,limits:f,motor:d,disposed:!1,dispose(){this.disposed||(this.joint.dispose(),this.limits?.dispose(),this.motor?.dispose(),this.disposed=!0)},destroy(){this.dispose()}}}createSolver(e,t={}){if(Jo(e))return e.createSolver(this,t);this.assertEditable();let i=new _o(e,this.topology,t);for(let[r,o]of this.restitution??[])i.setRestitution(r,o);for(let r of this.sensors??[])i.setSensor(r,!0);for(let[r,o]of this.filters??[])i.setFilters([r],[o[0]],[o[1]]);return this.gpu=i,this.created=!0,i}};export{$s as AvbdPhysics,Xs as AvbdPhysicsAggregate,Ys as AvbdPhysicsBody,$r as AvbdPhysicsConstraint,Xr as AvbdPhysicsHinge,pa as AvbdScene2D,ha as AvbdScene3D,ht as AvbdShapeType,xf as createSolverPipeline,Jr as createWebGPUDevice,xr as prepareWebGPUDevice3D};
5101
+ }`);var $c=ii;var Kc=8,Jc=16,Xi=1e-6,Ia=1e-5,Kf=1e-6,Ra=34028234663852886e22,Zo=0,Zc=1,en=2;function Xc(s){let e=s.positionAng;return{center:s.positionLin,half:ne(S(),s.size,.5),axis:[ae(S(),e,[1,0,0]),ae(S(),e,[0,1,0]),ae(S(),e,[0,0,1])]}}var Ji=(s,e)=>Math.abs(V(s,e));function tn(s,e){let t=V(e,s.axis[0])>=0?1:-1,i=V(e,s.axis[1])>=0?1:-1,r=V(e,s.axis[2])>=0?1:-1,o=D(S(),s.center,s.axis[0],s.half[0]*t);return D(o,o,s.axis[1],s.half[1]*i),D(o,o,s.axis[2],s.half[2]*r)}function eu(s,e){return e===0?{u:s.axis[1],v:s.axis[2],extentU:s.half[1],extentV:s.half[2]}:e===1?{u:s.axis[0],v:s.axis[2],extentU:s.half[0],extentV:s.half[2]}:{u:s.axis[0],v:s.axis[1],extentU:s.half[0],extentV:s.half[1]}}function Zf(s,e,t){let i=V(t,s.axis[e])>=0?1:-1,r=ne(S(),s.axis[e],i),o=D(S(),s.center,r,s.half[e]);return{normal:r,center:o,...eu(s,e)}}function ed(s,e){let t=0,i=-Ra;for(let r=0;r<3;r++){let o=Ji(s.axis[r],e);o>i&&(i=o,t=r)}return t}function td(s,e,t){let i=V(s.axis[e],t)>0?-1:1,r=ne(S(),s.axis[e],i),o=D(S(),s.center,r,s.half[e]),{u:n,v:a,extentU:l,extentV:c}=eu(s,e),u=(f,d)=>{let p=D(S(),o,n,f*l);return D(p,p,a,d*c)};return[u(1,1),u(-1,1),u(-1,-1),u(1,-1)]}function id(s,e,t){let i=[];if(s.length===0)return i;let r=s[s.length-1],o=V(e,r)-t;for(let n of s){let a=V(e,n)-t,l=o<=Ia,c=a<=Ia;if(l!==c){let u=0,f=o-a;Math.abs(f)>Xi&&(u=ce(o/f,0,1)),i.length<Jc&&i.push(D(S(),r,J(S(),n,r),u))}c&&i.length<Jc&&i.push(n),r=n,o=a}return i}var rn=class{contacts=[];midpoints=[];bodyA;bodyB;constructor(e,t){this.bodyA=e,this.bodyB=t}add(e,t,i){let r=ne(S(),Li(S(),e,t),.5);for(let a of this.midpoints)if(Ne(J(S(),r,a))<Kf)return;if(this.contacts.length>=Kc)return;let{bodyA:o,bodyB:n}=this;this.contacts.push({feature:i,rA:Te(S(),o.positionAng,J(S(),e,o.positionLin)),rB:Te(S(),n.positionAng,J(S(),t,n.positionLin))}),this.midpoints.push(r)}};function za(s,e,t,i,r,o,n,a){let l=Ne(i);if(l<Xi)return!0;let c=1/Math.sqrt(l),u=ne(S(),i,c);V(u,t)<0&&ee(u,u);let f=Math.abs(V(t,u)),d=s.half[0]*Ji(u,s.axis[0])+s.half[1]*Ji(u,s.axis[1])+s.half[2]*Ji(u,s.axis[2]),p=e.half[0]*Ji(u,e.axis[0])+e.half[1]*Ji(u,e.axis[1])+e.half[2]*Ji(u,e.axis[2]),m=f-(d+p);return m>0?!1:((!a.valid||m>a.separation)&&(a.valid=!0,a.type=r,a.indexA=o,a.indexB=n,a.separation=m,a.normalAB=u),!0)}function Yc(s,e,t){let i=(e+1)%3,r=(e+2)%3,o=V(t,s.axis[i])>=0?1:-1,n=V(t,s.axis[r])>=0?1:-1,a=D(S(),s.center,s.axis[i],s.half[i]*o);D(a,a,s.axis[r],s.half[r]*n);let l=ne(S(),s.axis[e],s.half[e]);return[J(S(),a,l),Li(S(),a,l)]}function rd(s,e,t,i){let r=J(S(),e,s),o=J(S(),i,t),n=J(S(),s,t),a=V(r,r),l=V(o,o),c=V(o,n),u=0,f=0;if(a<=Xi&&l<=Xi)return[s,t];if(a<=Xi)f=ce(c/l,0,1);else{let d=V(r,n);if(l<=Xi)u=ce(-d/a,0,1);else{let p=V(r,o),m=a*l-p*p;Math.abs(m)>Xi&&(u=ce((p*c-d*l)/m,0,1)),f=(p*u+c)/l,f<0?(f=0,u=ce(-d/a,0,1)):f>1&&(f=1,u=ce((p-d)/a,0,1))}}return[D(S(),s,r,u),D(S(),t,o,f)]}function Qc(s,e,t,i,r,o,n){let a=r?t:i,l=r?i:t,c=r?n:ee(S(),n),u=Zf(a,o,c),f=ed(l,u.normal),d=td(l,f,u.normal),p=[[u.u,u.extentU],[ee(S(),u.u),u.extentU],[u.v,u.extentV],[ee(S(),u.v),u.extentV]];for(let[g,b]of p)if(d=id(d,g,V(g,u.center)+b),!d.length)return[];let m=new rn(s,e),h=(r?Zo:Zc)<<24|(o&255)<<16|(f&255)<<8;for(let g=0;g<d.length&&m.contacts.length<Kc;g++){let b=d[g],y=V(J(S(),b,u.center),u.normal);if(y>Ia)continue;let A=D(S(),b,u.normal,-y),v=r?A:b,x=r?b:A;m.add(v,x,h|g&255)}return m.contacts.length||m.add(tn(t,n),tn(i,ee(S(),n)),h),m.contacts}function sd(s,e,t,i,r,o,n){let[a,l]=Yc(t,r,n),[c,u]=Yc(i,o,ee(S(),n)),[f,d]=rd(a,l,c,u),p=new rn(s,e),m=en<<24|(r&255)<<8|o&255;return p.add(f,d,m),p.contacts.length||p.add(tn(t,n),tn(i,ee(S(),n)),m),p.contacts}function tu(s,e,t,i=!0){let r=Xc(s),o=Xc(e),n=J(S(),o.center,r.center),a={type:Zo,indexA:0,indexB:0,separation:-Ra,normalAB:S(),valid:!1},l={type:en,indexA:0,indexB:0,separation:-Ra,normalAB:S(),valid:!1};for(let f=0;f<3;f++)if(!za(r,o,n,r.axis[f],Zo,f,-1,a))return[];for(let f=0;f<3;f++)if(!za(r,o,n,o.axis[f],Zc,-1,f,a))return[];let c=S();for(let f=0;f<3;f++)for(let d=0;d<3;d++)if(Dt(c,r.axis[f],o.axis[d]),!za(r,o,n,c,en,f,d,l))return[];if(!a.valid)return[];let u=a;return l.valid&&(i?l.separation>.95*a.separation+.01:.95*l.separation>a.separation+.01)&&(u=l),_s(t,ee(S(),u.normalAB)),u.type===en?sd(s,e,r,o,u.indexA,u.indexB,u.normalAB):u.type===Zo?Qc(s,e,r,o,!0,u.indexA,u.normalAB):Qc(s,e,r,o,!1,u.indexB,u.normalAB)}var de=(s,e)=>s.map((t,i)=>t+e[i]),T=(s,e)=>s.map((t,i)=>t-e[i]),q=(s,e)=>s.map(t=>t*e),F=(s,e)=>s.reduce((t,i,r)=>t+i*e[r],0),xt=(s,e)=>[s[1]*e[2]-s[2]*e[1],s[2]*e[0]-s[0]*e[2],s[0]*e[1]-s[1]*e[0]],Tt=s=>q(s,1/(Math.hypot(...s)||1)),Ee=(s,e)=>Array.from(ae(S(),s,e)),iu=(s,e)=>Te(S(),s.positionAng,T(e,s.positionLin)),Ot=(s,e)=>de(s.positionLin,Ee(s.positionAng,e)),od=[[1,3,7,5],[0,4,6,2],[2,6,7,3],[0,1,5,4],[4,5,7,6],[0,2,3,1]],nd=[[1,0,0],[-1,0,0],[0,1,0],[0,-1,0],[0,0,1],[0,0,-1]];function jr(s){if(De(s)||Fe(s)){let n=(De(s),s.size[0]/2),a=Fe(s)?Math.max(0,s.size[1]/2-n):0;return{body:s,radius:n,spine:[Ot(s,[0,-a,0]),Ot(s,[0,a,0])]}}let e=Ct(s),t=e?Array.from({length:e.vertices.length/3},(n,a)=>Ot(s,e.vertices.slice(a*3,a*3+3))):Array.from({length:8},(n,a)=>Ot(s,s.size.map((l,c)=>l/2*(a>>c&1?1:-1)))),i=e?e.faces.map(n=>({vertices:n.verts.map(a=>t[a]),normal:Ee(s.positionAng,n.normal)})):od.map((n,a)=>({vertices:n.map(l=>t[l]),normal:Ee(s.positionAng,nd[a])})),r=[],o=new Set;for(let n of i)for(let a=0;a<n.vertices.length;a++){let l=n.vertices[a],c=n.vertices[(a+1)%n.vertices.length],u=t.indexOf(l),f=t.indexOf(c),d=`${Math.min(u,f)},${Math.max(u,f)}`;o.has(d)||(o.add(d),r.push([l,c]))}return{body:s,vertices:t,faces:i,edges:r}}function As(s,e){let t=s.spine??s.vertices,i=t[0];for(let r of t)F(r,e)>F(i,e)&&(i=r);return s.spine?de(i,q(e,s.radius)):i}function ad(s,e,t){let i=T(e,s);return de(s,q(i,Math.max(0,Math.min(1,F(T(t,s),i)/(F(i,i)||1)))))}function sn([s,e],[t,i]){let r=T(e,s),o=T(i,t),n=T(s,t),a=F(r,r),l=F(o,o),c=F(o,n),u=0,f=0,d=p=>Math.max(0,Math.min(1,p));if(a<1e-16)f=l>1e-16?d(c/l):0;else{let p=F(r,n);if(l<1e-16)u=d(-p/a);else{let m=F(r,o),h=a*l-m*m;u=h>1e-12*a*l?d((m*c-p*l)/h):0,f=(m*u+c)/l,f<0?(f=0,u=d(-p/a)):f>1&&(f=1,u=d((m-p)/a))}}return[de(s,q(r,u)),de(t,q(o,f))]}function ld(s,e,t){let i=[];for(let r=0;r<s.length;r++){let o=s[r],n=s[(r+1)%s.length],a=F(o,e)-t,l=F(n,e)-t;a<=1e-8&&i.push(o),a<0!=l<0&&i.push(de(o,q(T(n,o),a/(a-l))))}return i}function cd(s,e,t,i){let r=T(t,e),o=T(i,e),n=T(s,e),a=F(r,n),l=F(o,n);if(a<=0&&l<=0)return e;let c=T(s,t),u=F(r,c),f=F(o,c);if(u>=0&&f<=u)return t;let d=a*f-u*l;if(d<=0&&a>=0&&u<=0)return de(e,q(r,a/(a-u)));let p=T(s,i),m=F(r,p),h=F(o,p);if(h>=0&&m<=h)return i;let g=m*l-a*h;if(g<=0&&l>=0&&h<=0)return de(e,q(o,l/(l-h)));let b=u*h-m*f;if(b<=0&&f-u>=0&&m-h>=0)return de(t,q(T(i,t),(f-u)/(f-u+m-h)));let y=1/(b+g+d);return de(e,de(q(r,g*y),q(o,d*y)))}function ud(s,e){let t=null,i=1/0;for(let r of s.faces)for(let o=1;o<r.vertices.length-1;o++){let n=cd(e,r.vertices[0],r.vertices[o],r.vertices[o+1]),a=F(T(e,n),T(e,n));a<i&&(t=n,i=a)}return t}function ru(s,e,t,i,r){if(!De(s)&&!De(e)&&!Fe(s)&&!Fe(e)&&!Ct(s)&&!Ct(e))return tu(s,e,t,s.solver.faceBias!==!1);i??=jr(s),r??=jr(e);let o=-1/0,n=[0,0,1],a=null,l=(f,d=null)=>{if(Math.hypot(...f)<1e-9)return;let p=Tt(f),m=F(T(As(i,q(p,-1)),As(r,p)),p),h=F(T(As(r,q(p,-1)),As(i,p)),p);h>m&&(m=h,p=q(p,-1)),m>o+1e-7&&(o=m,n=p,a=d)};for(let f of[i,r])for(let d of f.faces??[])l(d.normal);if(i.edges&&r.edges)for(let f of i.edges)for(let d of r.edges)l(xt(T(f[1],f[0]),T(d[1],d[0])),[f,d]);if(i.spine&&r.spine){let f=sn(i.spine,r.spine);l(T(...f))}for(let[f,d]of[[i,r],[r,i]])if(f.spine&&d.faces){for(let p of d.vertices)l(T(p,ad(...f.spine,p)));for(let p of d.edges){let m=sn(f.spine,p);l(T(...m))}}if(o===-1/0&&l(T(s.positionLin,e.positionLin)),o>0)return[];o===-1/0&&(n=[0,0,1],o=-(i.radius+r.radius));let c=Tt(xt(n,Math.abs(n[0])<.7?[1,0,0]:[0,1,0]));t.set([...n,...c,...xt(n,c)]);let u=[];if(i.spine&&r.spine){let[f,d]=sn(i.spine,r.spine);u=[[de(f,q(n,-i.radius)),de(d,q(n,r.radius))]]}else if(i.spine||r.spine){let f=i.spine?i:r,d=i.spine?r:i,p=i.spine?q(n,-1):n,m=As(f,p),h=ud(d,m);u=[i.spine?[m,h]:[h,m]]}else if(a)u=[sn(...a)];else{let f=(A,v)=>A.faces.reduce((x,w)=>F(w.normal,v)>F(x.normal,v)?w:x,A.faces[0]),d=f(i,q(n,-1)),p=f(r,n),m=F(d.normal,q(n,-1))>=F(p.normal,n),h=m?d:p,b=f(m?r:i,q(h.normal,-1)).vertices,y=q(h.vertices.reduce((A,v)=>de(A,v),[0,0,0]),1/h.vertices.length);for(let A=0;A<h.vertices.length&&b.length;A++){let v=h.vertices[A],x=h.vertices[(A+1)%h.vertices.length],w=Tt(xt(T(x,v),h.normal));F(T(y,v),w)>0&&(w=q(w,-1)),b=ld(b,w,F(v,w))}for(let A of b){let v=F(T(A,h.vertices[0]),h.normal);if(v<=1e-6){let x=T(A,q(h.normal,v));u.push(m?[x,A]:[A,x])}}}return u.slice(0,8).map(([f,d],p)=>({feature:p+1,rA:iu(s,f),rB:iu(e,d)}))}var on=(s,e,t)=>Math.max(e,Math.min(t,s)),fd=(s,e)=>[F(s.slice(0,3),e),F(s.slice(3,6),e),F(s.slice(6,9),e)];function ja(s,e=!1){if(e){s.rest=Math.hypot(...T(Ot(s.bodyA,s.rA),Ot(s.bodyB,s.rB)));return}let t=s.bodyA?.positionAng??[0,0,0,1];s.cpuRest=Gr(jt(),xn(jt(),t),s.bodyB.positionAng),s.evaluateAng=i=>{let r=Gr(jt(),s.bodyA?.positionAng??[0,0,0,1],s.cpuRest);ct(i,r,s.bodyB.positionAng);for(let o=0;o<3;o++)i[o]*=s.torqueArm;return i}}var Oa=class extends ni{initialize(){let e=this.bodyA,t=this.bodyB;if(!((e.group??4294967295)&(t.collidesWith??4294967295))||!((t.group??4294967295)&(e.collidesWith??4294967295)))return!1;let i=this.contacts,r=De(e)||De(t)||Fe(e)||Fe(t);this.friction=Math.sqrt(e.friction*t.friction),this.contacts=ru(e,t,this.basis,this.solver.cpuGeometry.get(e),this.solver.cpuGeometry.get(t)).map(o=>{let n=i.find(a=>a.feature===o.feature);return{feature:o.feature,rA:n?.stick&&!r?n.rA:o.rA,rB:n?.stick&&!r?n.rB:o.rB,C0:S(),penalty:n?n.penalty.slice():S(),lambda:n?n.lambda.slice():S(),stick:n?.stick??!1}});for(let o of this.contacts){o.C0.set(fd(this.basis,T(Ot(e,o.rA),Ot(t,o.rB)))),o.C0[0]+=Ms;for(let n=0;n<3;n++)o.lambda[n]*=this.solver.alpha*this.solver.gamma,o.penalty[n]=on(o.penalty[n]*this.solver.gamma,Et,Ve);if(this.solver.massPenalty!==!1){let n=Math.min(e.mass>0?e.mass:1/0,t.mass>0?t.mass:1/0);o.penalty[0]=Math.max(o.penalty[0],on(n/this.solver.dt**2,Et,Ve))}}return this.contacts.length>0}updatePrimal(...e){!this.bodyA.isTrigger&&!this.bodyB.isTrigger&&super.updatePrimal(...e)}updateDual(...e){!this.bodyA.isTrigger&&!this.bodyB.isTrigger&&super.updateDual(...e)}},Ta=class extends Ft{constructor(e,t,i){super(e,t.bodyA,t.bodyB),this.options={...i},this.pen=[Et,Et],this.lam=[0,0],this.source=t;let r=i.axisA;this.ta=Tt(Math.abs(r[0])>Math.abs(r[2])?[-r[1],r[0],0]:[0,-r[2],r[1]]);let o=this.bodyA?Ee(this.bodyA.positionAng,this.ta):this.ta,n=Array.from(Te(S(),this.bodyB.positionAng,o));n=T(n,q(i.axisB,F(n,i.axisB))),this.tb=Tt(n)}frame(){let e=this.bodyA?Ee(this.bodyA.positionAng,this.options.axisA):this.options.axisA,t=this.bodyA?Ee(this.bodyA.positionAng,this.ta):this.ta,i=Ee(this.bodyB.positionAng,this.tb);return{axis:e,angle:Math.atan2(F(e,xt(t,i)),F(t,i))}}initialize(){let e=this.frame().angle;this.c0=this.options.type==="motor"?[e,0]:[Math.min(0,e-this.options.minAngle),Math.max(0,e-this.options.maxAngle)];for(let t=0;t<2;t++)this.lam[t]*=this.solver.alpha*this.solver.gamma,this.pen[t]=on(this.pen[t]*this.solver.gamma,Et,Ve);return!this.source.broken}evaluate(e){let{angle:t}=this.frame(),i=this.options,r=i.type==="motor"?[Math.atan2(Math.sin(t-this.c0[0]),Math.cos(t-this.c0[0]))-i.speed*this.solver.dt,0]:[t-i.minAngle-e*this.c0[0],t-i.maxAngle-e*this.c0[1]],o=r.map((n,a)=>this.pen[a]*n+this.lam[a]);return{c:r,f:i.type==="motor"?[on(o[0],-i.maxTorque,i.maxTorque),0]:[Math.min(0,o[0]),Math.max(0,o[1])]}}updatePrimal(e,t,i){let{f:r}=this.evaluate(t),o=this.options;if(o.type==="motor"&&o.maxTorque===0)return;let n=q(this.frame().axis,e===this.bodyA?-1:1);for(let a=0;a<(o.type==="motor"?1:2);a++)if(!(o.type==="limit"&&r[a]===0))for(let l=0;l<3;l++){i.rhsAng[l]+=n[l]*r[a];for(let c=0;c<3;c++)i.lhsAng[l*3+c]+=n[l]*n[c]*this.pen[a]}}updateDual(e){let{c:t,f:i}=this.evaluate(e);this.lam=i;for(let r=0;r<2;r++)this.pen[r]=Math.min(Ve,this.pen[r]+this.solver.betaAng*(this.options.type==="motor"?Math.abs(t[r]):r===0?Math.max(0,-t[r]):Math.max(0,t[r])))}};function nn(s){if(!s.cpuPrepared){s.cpuPrepared=!0;for(let e of[...s.forces]){let t=rs(e);if(t){e.unlinkFromBodies(),s.forces.splice(s.forces.indexOf(e),1),e.cpuAngular=new Ta(s,e,t);continue}if(e instanceof ke&&e.stiffnessAng>0&&ja(e),e instanceof ft){let i=e.initialize.bind(e);e.initialize=()=>{if(e.broken)return!1;let r=Ui(e);if(r){let o=Math.max(0,Math.hypot(...T(Ot(e.bodyA,e.rA),Ot(e.bodyB,e.rB)))-e.rest);if(o/Math.max(e.rest,1e-6)>r.breakStrain||o*e.stiffness>r.breakForce)return e.broken=!0,!1}return i()}}}}}function su(s){let e=s.bodies;s.cpuGeometry=new Map;for(let l of e)(De(l)||Fe(l)||Ct(l))&&s.cpuGeometry.set(l,jr(l));let t=e.filter(l=>l.mass>0).slice(0,1024).map(l=>l.radius).sort((l,c)=>l-c),i=Math.max(.1,(t[Math.floor(t.length/2)]??1)*2),r=new Map,o=[],n=new Set,a=(l,c)=>{if(l===c||e[l].mass<=0&&e[c].mass<=0)return;let u=Math.max(l,c),f=Math.min(l,c),d=u*e.length+f;if(n.has(d))return;n.add(d);let p=e[u],m=e[f];if(!((p.group??4294967295)&(m.collidesWith??4294967295))||!((m.group??4294967295)&(p.collidesWith??4294967295)))return;let h=p.radius+m.radius;F(T(p.positionLin,m.positionLin),T(p.positionLin,m.positionLin))<=h*h&&!p.constrainedTo(m)&&new Oa(s,p,m)};for(let l=0;l<e.length;l++){let c=e[l],u=c.positionLin.map(d=>Math.floor((d-c.radius)/i)),f=c.positionLin.map(d=>Math.floor((d+c.radius)/i));if((f[0]-u[0]+1)*(f[1]-u[1]+1)*(f[2]-u[2]+1)>128){o.push(l);continue}for(let d=u[0];d<=f[0];d++)for(let p=u[1];p<=f[1];p++)for(let m=u[2];m<=f[2];m++){let h=`${d},${p},${m}`,g=r.get(h)??[];for(let b of g)a(l,b);g.push(l),r.set(h,g)}}for(let l of o)for(let c=0;c<e.length;c++)a(l,c)}function an(s,e){if(!(e===3?s.bodies.some(r=>r.restitution>0):[...s.restitution.values()].some(r=>r>0)))return null;if(e===2)return Float64Array.from(s.velocity);let i=new Float64Array(s.bodies.length*6);return s.bodies.forEach((r,o)=>{i.set(r.velocityLin,o*6),i.set(r.velocityAng,o*6+3)}),i}function ln(s,e,t){if(!t)return;let i=e===3?s.bodies.length:s.bodyCount,r=e===3?6:4,o=e===3?new Float64Array(i*r):s.velocity;e===3&&s.bodies.forEach((h,g)=>{o.set(h.velocityLin,g*r),o.set(h.velocityAng,g*r+3)});let n=h=>e===3?s.bodies[h].mass>0&&!s.bodies[h].sleeping?1/s.bodies[h].mass:0:s.dynamic[h]?1/s.shape[h*4+2]:0,a=(h,g)=>{if(!n(h))return e===3?[0,0,0]:0;if(e===2)return s.shape[h*4+3]>0?g/s.shape[h*4+3]:0;let b=s.bodies[h],y=b.positionAng,A=Ee([-y[0],-y[1],-y[2],y[3]],g);return Ee(y,A.map((v,x)=>b.moment[x]>0?v/b.moment[x]:0))},l=(h,g,b)=>{let y=g*r;return e===3?T(h.subarray(y,y+3),xt(b,h.subarray(y+3,y+6))):[h[y]-h[y+2]*b[1],h[y+1]+h[y+2]*b[0]]},c=(h,g)=>e===3?xt(h,g):h[0]*g[1]-h[1]*g[0],u=(h,g)=>e===3?F(h,g):h*g,f;if(e===3){let h=new Map(s.bodies.map((g,b)=>[g,b]));f=s.forces.filter(g=>g.contacts?.length&&!g.bodyA.isTrigger&&!g.bodyB.isTrigger).map(g=>{let b=(y,A)=>{let v=[0,0,0];for(let x of g.contacts){let w=Ee(y.positionAng,x[A]);for(let B=0;B<3;B++)v[B]+=w[B]/g.contacts.length}return v};return{a:h.get(g.bodyA),b:h.get(g.bodyB),n:g.basis.slice(0,3),ra:b(g.bodyA,"rA"),rb:b(g.bodyB,"rB"),e:Math.max(g.bodyA.restitution??0,g.bodyB.restitution??0)}})}else{let h=(g,b)=>{let y=Math.cos(s.pose[g*4+2]),A=Math.sin(s.pose[g*4+2]);return[y*b[0]-A*b[1],A*b[0]+y*b[1]]};f=s.contactPairs.filter(g=>!s.sensors.has(g.a)&&!s.sensors.has(g.b)).map(g=>({...g,ra:h(g.a,g.ra),rb:h(g.b,g.rb),e:Math.max(s.restitution.get(g.a)??0,s.restitution.get(g.b)??0)}))}let d=new Uint32Array(i);if(e===3)s.bodies.forEach((h,g)=>{d[g]=h.forces.length});else for(let h=0;h<i;h++)d[h]=s.adjStart[h+1]-s.adjStart[h];let p=[];for(let h of f){if(h.e<=0)continue;let g=F(h.n,T(l(t,h.a,h.ra),l(t,h.b,h.rb)));if(g>=-1)continue;let b=c(h.ra,h.n),y=c(h.rb,h.n),A=a(h.a,b),v=a(h.b,y),x=n(h.a)+n(h.b)+u(b,A)+u(y,v);x>0&&p.push({...h,inertiaA:A,inertiaB:v,k:x,target:-h.e*g,impulse:0})}let m=new Float64Array(o.length);for(let h=0;h<12&&p.length;h++){m.fill(0);for(let g of p){let b=F(g.n,T(l(o,g.a,g.ra),l(o,g.b,g.rb))),y=Math.max(0,g.impulse+(g.target-b)/(g.k*Math.max(1,d[g.a],d[g.b]))),A=y-g.impulse;g.impulse=y;for(let[v,x,w]of[[g.a,1,g.inertiaA],[g.b,-1,g.inertiaB]]){let B=v*r,L=n(v);for(let M=0;M<e;M++)m[B+M]+=x*A*L*g.n[M];if(e===3)for(let M=0;M<3;M++)m[B+3+M]+=x*A*w[M];else m[B+2]+=x*A*w}}for(let g=0;g<o.length;g++)o[g]+=m[g]}e===3&&s.bodies.forEach((h,g)=>{h.velocityLin.set(o.subarray(g*r,g*r+3)),h.velocityAng.set(o.subarray(g*r+3,g*r+6))})}function ou(s,e,t){let i=e.windSpeed??0;if(!or(s)||s.mass<=0||i===0)return null;let r=e.windAngle??0,o=[Math.cos(r),Math.sin(r),0],n=[-o[1],o[0],0],a=s.positionLin,l=t*e.dt,c=F(a,o),u=F(a,n),f=.5*Math.sin(1.1*l-.35*c+.2*u)+.3*Math.sin(2.9*l-.8*c+.6*a[2])+.2*Math.sin(6.1*l-1.7*c+1.3*a[2]+.9*u),d=.6*Math.sin(1.7*l-.6*c+.4*a[2])+.4*Math.sin(4.3*l-1.3*c-.7*a[2]),p=Math.sin(2.3*l-.9*c+1.1*u),m=e.windGust??.4,h=o.map((x,w)=>i*x*(1+m*f)+m*i*(n[w]*.25*d+(w===2?.1*p:0))-s.velocityLin[w]),g=Ee(s.positionAng,[0,0,1]),b=(e.windPressure??.72)*s.size[0]*s.size[1]/s.mass,y=F(h,g),A=h.map((x,w)=>x-g[w]*y),v=b*y*Math.abs(y)/(1+2*e.dt*b*Math.abs(y));return g.map((x,w)=>x*v+A[w]*.06*b*Math.hypot(...A))}var dd=()=>({dt:1/60,gravity:-10,iterations:10,betaLin:1e4,betaAng:100,alpha:.99,gamma:.999}),cn=class{dt=1/60;gravity=-10;iterations=10;alpha=.99;betaLin=1e4;betaAng=100;gamma=.999;massPenalty=!0;faceBias=!0;up=[0,0,1];cpuStep=0;bodies=[];forces=[];constructor(){this.defaultParams()}defaultParams(){Object.assign(this,dd())}clear(){this.forces=[],this.bodies=[]}pick(e,t){let r=null,o=S(),n=S();for(let a=this.bodies.length-1;a>=0;a--){let l=this.bodies[a];if(l.mass<=0)continue;Te(o,l.positionAng,J(o,e,l.positionLin)),Te(n,l.positionAng,t);let c=0,u=1/0,f=!0;for(let p=0;p<3&&f;p++){let m=l.size[p]*.5;if(Math.abs(n[p])<1e-6){(o[p]<-m||o[p]>m)&&(f=!1);continue}let h=1/n[p],g=(-m-o[p])*h,b=(m-o[p])*h;g>b&&([g,b]=[b,g]),c=Math.max(c,g),u=Math.min(u,b),c>u&&(f=!1)}if(!f)continue;let d=c>=0?c:u;d<0||(!r||d<r.t)&&(r={body:l,local:D(S(),o,n,d),t:d})}return r}sys=zs();dxLin=S();dxAng=S();dp=S();accel=S();step(){let{dt:e,gravity:t,bodies:i,sys:r,dp:o}=this,n=an(this,3);nn(this),su(this);let a=[];for(let l of this.forces)l.initialize()?a.push(l):l.unlinkFromBodies();this.forces=a;for(let l=i.length-1;l>=0;l--){let c=i[l];D(c.inertialLin,c.positionLin,c.velocityLin,e),c.mass>0&&D(c.inertialLin,c.inertialLin,this.up,t*e*e);let u=ou(c,this,this.cpuStep);u&&D(c.inertialLin,c.inertialLin,u,e*e),si(c.inertialAng,c.positionAng,nu(c.velocityAng,e)),_t(this.accel,J(this.accel,c.velocityLin,c.prevVelocityLin),e);let f=V(this.accel,this.up)*Ps(t),d=ce(f/Math.abs(t),0,1);Number.isFinite(d)||(d=0),c.initialLin.set(c.positionLin),c.initialAng.set(c.positionAng),c.mass>0&&!c.sleeping&&(D(c.positionLin,c.positionLin,c.velocityLin,e),D(c.positionLin,c.positionLin,this.up,t*d*e*e),si(c.positionAng,c.positionAng,nu(c.velocityAng,e)))}for(let l=0;l<this.iterations;l++){for(let c=i.length-1;c>=0;c--){let u=i[c];if(u.mass<=0||u.sleeping)continue;let f=u.mass,d=u.moment;Ce(r.lhsLin,f/(e*e),f/(e*e),f/(e*e)),Ce(r.lhsAng,d[0]/(e*e),d[1]/(e*e),d[2]/(e*e)),r.lhsCross.fill(0),ue(r.rhsLin,r.lhsLin,J(o,u.positionLin,u.inertialLin)),ue(r.rhsAng,r.lhsAng,ct(o,u.positionAng,u.inertialAng));let p=u.forces;for(let h=p.length-1;h>=0;h--)p[h].updatePrimal(u,this.alpha,r);let m=u.moment.every(h=>h===0);m&&(Ce(r.lhsAng,1,1,1),r.lhsCross.fill(0),r.rhsAng.fill(0)),Es(r.lhsLin,r.lhsAng,r.lhsCross,ee(r.rhsLin,r.rhsLin),ee(r.rhsAng,r.rhsAng),this.dxLin,this.dxAng),D(u.positionLin,u.positionLin,this.dxLin,1),m||si(u.positionAng,u.positionAng,this.dxAng)}for(let c of this.forces)c.updateDual(this.alpha)}for(let l of i)l.prevVelocityLin.set(l.velocityLin),l.mass>0&&!l.sleeping&&(_t(l.velocityLin,J(l.velocityLin,l.positionLin,l.initialLin),e),_t(l.velocityAng,ct(l.velocityAng,l.positionAng,l.initialAng),e));ln(this,3,n),this.cpuStep++}},hd=S(),nu=(s,e)=>ne(hd,s,e);var Bs=(s,e)=>s.map((t,i)=>t+e[i]),Re=(s,e)=>s.map((t,i)=>t-e[i]),Lt=(s,e)=>s.map(t=>t*e),st=(s,e)=>s[0]*e[0]+s[1]*e[1],ws=(s,e)=>[Math.cos(s)*e[0]-Math.sin(s)*e[1],Math.sin(s)*e[0]+Math.cos(s)*e[1]],lu=s=>Math.max(0,Math.min(1,s)),au=(s,e,t)=>Bs(s,Lt(Re(e,s),lu(st(Re(t,s),Re(e,s))/(st(Re(e,s),Re(e,s))||1))));function un(s,e){let t=ei(s)?.get(e)??[0,0,0,0],i=Array.from(s.pose.subarray(e*4,e*4+2)),r=s.pose[e*4+2],o=l=>Bs(i,ws(r,l)),n=[s.shape[e*4]/2,s.shape[e*4+1]/2],a=t[0]===4?Array.from({length:t.vertices.length/4},(l,c)=>o(t.vertices.slice(c*4,c*4+2))):t[0]===0?[[-1,-1],[1,-1],[1,1],[-1,1]].map(l=>o([l[0]*n[0],l[1]*n[1]])):null;return{kind:t[0],p:i,angle:r,vertices:a,radius:t[1],spine:[o([-t[2]||0,0]),o([t[2]||0,0])]}}function Yi(s,e){if(s.vertices){let r=-1/0,o=[];for(let n of s.vertices){let a=st(n,e);a>r+1e-7?(r=a,o=[n]):Math.abs(a-r)<1e-7&&o.push(n)}return[o[0],o.at(-1)]}let t=Bs(s.spine[0],Lt(e,s.radius)),i=Bs(s.spine[1],Lt(e,s.radius));return Math.abs(st(t,e)-st(i,e))<1e-7?[t,i]:st(t,e)>st(i,e)?[t,t]:[i,i]}function cu(s,e,t,i){let r=un(s,e),o=un(s,t),n=s.pose,a=s.shape;if(r.kind===0&&o.kind===0)return Lo(...n.subarray(e*4,e*4+3),a[e*4]/2,a[e*4+1]/2,...n.subarray(t*4,t*4+3),a[t*4]/2,a[t*4+1]/2,i);let l=[];if(r.kind===3||o.kind===3){let u=r.kind===3,f=u?r:o,d=u?o:r;if(d.kind===3)return 0;let p=ws(f.angle,[0,1]),m=Yi(d,Lt(p,-1));for(let h of m){let g=st(Re(h,f.p),p);if(g<=0){let b=Re(h,Lt(p,g));l.push({a:u?b:h,b:u?h:b,n:u?Lt(p,-1):p})}}}else{let u=-1/0,f=[0,1],d=x=>{let w=Math.hypot(...x);if(w<1e-9)return;let B=Lt(x,1/w),L=st(Re(Yi(r,Lt(B,-1))[0],Yi(o,B)[0]),B),M=st(Re(Yi(o,Lt(B,-1))[0],Yi(r,B)[0]),B);Math.max(L,M)>u+1e-7&&(u=Math.max(L,M),f=L>=M?B:Lt(B,-1))};for(let[x,w]of[[r,o],[o,r]])if(x.vertices)for(let B=0;B<x.vertices.length;B++){let L=Re(x.vertices[(B+1)%x.vertices.length],x.vertices[B]);d([L[1],-L[0]]),w.vertices||d(Re(x.vertices[B],au(...w.spine,x.vertices[B])))}else if(d(ws(x.angle,[0,1])),!w.vertices)for(let B of x.spine)d(Re(B,au(...w.spine,B)));if(u===-1/0&&d([0,1]),u>0)return 0;let p=Yi(r,Lt(f,-1)),m=Yi(o,f),h=[-f[1],f[0]],g=p.map(x=>st(x,h)),b=m.map(x=>st(x,h)),y=Math.max(Math.min(...g),Math.min(...b)),A=Math.min(Math.max(...g),Math.max(...b)),v=(x,w)=>{let B=st(Re(x[1],x[0]),h);return Math.abs(B)<1e-9?x[0]:Bs(x[0],Lt(Re(x[1],x[0]),lu((w-st(x[0],h))/B)))};for(let x of A-y>1e-6?[y,A]:[(y+A)/2])l.push({a:v(p,x),b:v(m,x),n:f})}let c=0;for(let u of l){if(c&&Math.hypot(...Re(u.a,l[0].a))<1e-7)continue;let f=ws(-r.angle,Re(u.a,r.p)),d=ws(-o.angle,Re(u.b,o.p));if(i.set([268435456+c,...f,...d,...u.n],c*7),c++,c===2)break}return c}var uu=(s,e,t)=>[Math.cos(s)*e-Math.sin(s)*t,Math.sin(s)*e+Math.cos(s)*t],fu=function(){let{pose:s,shape:e,props:t}=this,i=this.broadphase.pairs,r=this.contactOut;for(let o=0;o<this.broadphase.pairCount;o++){let n=i[o],a=Math.floor(n/2097152),l=n-a*2097152,c=this.collideBodies(a,l,r);if(c===0)continue;let u=0,f=this.prevCount;for(;u<f;){let m=u+f>>>1;this.prevKeys[m]<n?u=m+1:f=m}let d=u,p=Math.sqrt(t[a*4]*t[l*4]);for(let m=0;m<c;m++){let h=this.jointCount+this.contactCount++;this.info=this.grow(this.info,(h+1)*j),this.data=this.grow(this.data,(h+1)*O);let g=this.data,b=h*O,y=m*7,A=r[y+0];this.info.set([hs,a,l,A],h*j),g.fill(0,b,b+O),g[b+Q]=g[b+Q+1]=1/0,g[b+_e]=-1/0,g[b+Ae]=0,g[b+Pt]=g[b+Pt+1]=1/0,g[b+N]=r[y+1],g[b+N+1]=r[y+1+1],g[b+Y]=r[y+3],g[b+Y+1]=r[y+3+1],g[b+re]=p,g[b+be]=r[y+5],g[b+Ue]=r[y+5+1];let v=-1;for(let P=d;P<this.prevCount&&this.prevKeys[P]===n;P++)this.prevInfo[P*j+3]===A&&(v=P);if(v<0&&this.params.matchNearest){let P=Sa*Math.min(e[a*4],e[a*4+1],e[l*4],e[l*4+1]);for(let C=d;C<this.prevCount&&this.prevKeys[C]===n;C++){let _=Math.hypot(this.prevData[C*O+N]-g[b+N],this.prevData[C*O+N+1]-g[b+N+1]);_<=P&&(P=_,v=C)}}if(v>=0){let P=v*O;g[b+se]=this.prevData[P+se],g[b+se+1]=this.prevData[P+se+1],g[b+te]=this.prevData[P+te],g[b+te+1]=this.prevData[P+te+1],this.prevData[P+Wi]&&(g[b+N]=this.prevData[P+N],g[b+N+1]=this.prevData[P+N+1],g[b+Y]=this.prevData[P+Y],g[b+Y+1]=this.prevData[P+Y+1])}let[x,w]=uu(s[a*4+2],g[b+N],g[b+N+1]),[B,L]=uu(s[l*4+2],g[b+Y],g[b+Y+1]),M=g[b+be],I=g[b+Ue],E=s[a*4]+x-s[l*4]-B,k=s[a*4+1]+w-s[l*4+1]-L;g[b+fe]=M*E+I*k+5e-4,g[b+fe+1]=I*E-M*k}}};var fn=class extends zr{constructor(e,t,i){if(super({precision:i==="soa-colored"?"f32":"f64",order:i==="soa-colored"?"colored":"sequential"}),Object.assign(this,e),this.options={...this.options,precision:i==="soa-colored"?"f32":"f64",order:i==="soa-colored"?"colored":"sequential"},this.options.precision==="f64")for(let[r,o]of Object.entries(this))o instanceof Float32Array&&(this[r]=Float64Array.from(o));for(let[r,o]of ei(e)??[]){let n=this.shape[r*4+2];Rr(this,r,{geometry:o,area:n,momentPerMass:n>0?this.shape[r*4+3]/n:0,radius:this.props[r*4+1]},1)}this.filters=new Map(t?.filters??[]),this.sensors=new Set(t?.sensors??[]),this.restitution=new Map(t?.restitution??[]),this.contactPairs=[],t&&(t.topology=this)}narrowphase(){this.contactPairs=[],fu.call(this)}collideBodies(e,t,i){let r=this.filters.get(e)??[4294967295,4294967295],o=this.filters.get(t)??[4294967295,4294967295];if(!(r[0]&o[1])||!(o[0]&r[1]))return 0;let n=cu(this,e,t,i);if(n){let a=[i[5],i[6]],l=[0,0],c=[0,0];for(let p=0;p<n;p++)for(let m=0;m<2;m++)l[m]+=i[p*7+1+m]/n,c[m]+=i[p*7+3+m]/n;let u=this.pose[e*4+2],f=Math.cos(u),d=Math.sin(u);this.contactPairs.push({a:e,b:t,n:a,ra:l,rb:c,point:[this.pose[e*4]+f*l[0]-d*l[1],this.pose[e*4+1]+d*l[0]+f*l[1],0],impulse:0})}return this.sensors.has(e)||this.sensors.has(t)?0:n}initJoints(){for(let e=0;e<this.jointCount;e++){let t=e*O,i=this.info[e*j];if(this.data[t+Q]===0&&this.data[t+Q+1]===0&&this.data[t+Q+2]===0){i!==0&&(this.info[e*j]=0,this.noCollideDirty=!0,this.handles[e]&&(this.handles[e].alive=!1));continue}i===1&&this.jointC(this.info[e*j+1],this.info[e*j+2],t,this.pose,this.data,t+fe)}for(let e=0;e<this.jointCount;e++)if(this.info[e*j]===5){let t=e*O,i=this.info[e*j+1],r=this.info[e*j+2],o=(i<0?0:this.pose[i*4+2])-this.pose[r*4+2]-this.data[t+re];this.data[t+fe]=Math.min(0,o-this.data[t+be]),this.data[t+fe+1]=Math.max(0,o-this.data[t+Ue])}}warmStartConstraints(e,t){let i=[];for(let r=0;r<this.jointCount;r++)this.info[r*j]===5&&(i.push(r),this.info[r*j]=4);super.warmStartConstraints(e,t);for(let r of i)this.info[r*j]=5}evalConstraint(e,t,i){if(this.info[e*j]!==5)return super.evalConstraint(e,t,i);let r=e*O,o=this.info[e*j+1],n=this.info[e*j+2],a=this.data,l=(o<0?0:this.pose[o*4+2])-this.pose[n*4+2]-a[r+re];this.eC[0]=l-a[r+be]-t*a[r+fe],this.eC[1]=l-a[r+Ue]-t*a[r+fe+1],this.eG.fill(0),this.eJ.fill(0);for(let c=0;c<2;c++){this.eMin[c]=a[r+_e+c],this.eMax[c]=a[r+Ae+c];let u=Math.max(this.eMin[c],Math.min(this.eMax[c],a[r+se+c]*this.eC[c]+a[r+te+c]));i>=0&&u!==0&&(this.eJ[c*3+2]=i===o?1:-1)}return 2}step(){let e=an(this,2);super.step(),ln(this,2,e);let t=new Map(this.contactPairs.map(i=>[`${i.a},${i.b}`,i]));for(let i=this.jointCount;i<this.jointCount+this.contactCount;i++){let r=t.get(`${this.info[i*j+1]},${this.info[i*j+2]}`);r&&(r.impulse+=Math.abs(this.data[i*O+te])*this.params.dt)}}};var hn=(s,e,t)=>{let i=T(e,s);return de(s,q(i,Math.max(0,Math.min(1,F(T(t,s),i)/(F(i,i)||1)))))};function dn(s,e,t,i){let r=T(s,t),o=F(r,e),n=o*o-F(r,r)+i*i;if(n<0)return null;let a=-o-Math.sqrt(n);return a<0?null:{t:a,n:Tt(T(de(s,q(e,a)),t))}}function Dr(s,e){return e&&(!s||e.t<s.t)?e:s}function Da(s,e,t,i,r){let o=T(i,t),n=T(s,t),a=F(o,o);if(a<1e-16)return dn(s,e,t,r);let l=F(o,e),c=F(o,n),u=F(n,e),f=a-l*l,d=a*u-c*l,p=a*F(n,n)-c*c-r*r*a,m=d*d-f*p,h=null;if(f>1e-12*a&&m>=0){let g=(-d-Math.sqrt(m))/f,b=c+g*l;g>=0&&b>=0&&b<=a&&(h={t:g,n:Tt(T(de(s,q(e,g)),de(t,q(o,b/a))))})}return Dr(Dr(h,dn(s,e,t,r)),dn(s,e,i,r))}function du(s,e){let t=q(e.vertices.reduce((i,r)=>de(i,r),[0,0,0]),1/e.vertices.length);for(let i=0;i<e.vertices.length;i++){let r=e.vertices[i],o=e.vertices[(i+1)%e.vertices.length],n=xt(T(o,r),e.normal);if(F(n,T(s,r))*(F(n,T(t,r))>=0?1:-1)<-1e-6)return!1}return!0}function pd(s,e,t,i){if(i===0){let a=-1/0,l=1/0,c=q(t,-1);for(let u of s.faces){let f=F(u.normal,t),d=F(u.normal,T(u.vertices[0],e));if(Math.abs(f)<1e-12){if(d<0)return null}else{let p=d/f;f<0?p>a&&(a=p,c=u.normal):l=Math.min(l,p)}if(a>l)return null}return l<0?null:{t:Math.max(0,a),n:a<=0?q(t,-1):c}}let r=!0,o=1/0,n=null;for(let a of s.faces){let l=F(a.normal,T(e,a.vertices[0]));l>0&&(r=!1),du(T(e,q(a.normal,l)),a)&&(o=Math.min(o,l*l));let c=F(a.normal,t);if(c<-1e-12){let u=(i-l)/c;u>=0&&du(T(de(e,q(t,u)),q(a.normal,i)),a)&&(n=Dr(n,{t:u,n:a.normal}))}}for(let[a,l]of s.edges){let c=T(e,hn(a,l,e));o=Math.min(o,F(c,c)),n=Dr(n,Da(e,t,a,l,i))}return r||o<=i*i?{t:0,n:q(t,-1)}:n}var At=(s,e)=>s[0]*e[0]+s[1]*e[1];function md(s,e,t,i){let r=!0,o=1/0,n=null;for(let a=0;a<s.vertices.length;a++){let l=s.vertices[a],c=s.vertices[(a+1)%s.vertices.length],u=T(c,l),f=Tt([u[1],-u[0]]),d=At(T(e,l),f);d>0&&(r=!1);let p=T(e,hn(l,c,e));o=Math.min(o,At(p,p));let m=At(t,f);if(m<-1e-12){let h=(i-d)/m,g=T(de(e,q(t,h)),q(f,i)),b=At(T(g,l),u),y=1e-6*At(u,u);h>=0&&b>=-y&&b<=At(u,u)+y&&(n=Dr(n,{t:h,n:f}))}i>0&&(n=Dr(n,dn(e,t,l,i)))}return r||o<=i*i?{t:0,n:q(t,-1)}:n}function gd(s,e,t,i){if(s.vertices)return md(s,e,t,i);if(s.kind===3){let p=[-Math.sin(s.angle),Math.cos(s.angle)],m=At(T(e,s.p),p)-i,h=At(t,p);return m<=0?{t:0,n:q(t,-1)}:h<-1e-12?{t:-m/h,n:p}:null}let r=s.kind===1?s.p:s.spine[0],o=s.kind===1?s.p:s.spine[1],n=i+s.radius,a=T(e,hn(r,o,e));if(At(a,a)<=n*n)return{t:0,n:q(t,-1)};if(n>0)return Da(e,t,r,o,n);let l=T(o,r),c=t[0]*l[1]-t[1]*l[0];if(Math.abs(c)<1e-12){let p=T(e,r);if(Math.abs(p[0]*l[1]-p[1]*l[0])/Math.max(Math.hypot(...l),1e-20)>1e-6)return null;let h=Math.min(At(T(r,e),t),At(T(o,e),t));return Math.max(At(T(r,e),t),At(T(o,e),t))<0?null:{t:Math.max(0,h),n:q(t,-1)}}let u=T(r,e),f=(u[0]*l[1]-u[1]*l[0])/c,d=(u[0]*t[1]-u[1]*t[0])/c;return f>=0&&d>=0&&d<=1?{t:f,n:q(Tt([l[1],-l[0]]),c>0?-1:1)}:null}function hu(s,e,t,i,{maxDistance:r=1e30,ignore:o=[],collidesWith:n=4294967295,includeTriggers:a=!0}={}){let l=s.dimension,c=me(e,l,"origin"),u=me(i,l,"direction"),f=Math.hypot(...u);if(!f||!Number.isFinite(t)||t<0||!Number.isFinite(r)||r<0)throw Error("Provide a nonzero direction, finite nonnegative radius and distance");if(!Number.isInteger(n)||n<0||n>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");let d=new Set(o);for(let h of d)s.liveIndex(h);let p=u.map(h=>h/f),m=null;for(let h=0;h<s.bodyCount;h++){if(d.has(h))continue;let g=l===3?s.solver.bodies[h]:null,b=g?g.group??4294967295:s.solver.filters.get(h)?.[0]??4294967295,y=g?g.isTrigger:s.solver.sensors.has(h);if(!(b&n)||!a&&y)continue;let A;if(l===2)A=gd(un(s.solver,h),c,p,t);else{let x=jr(g);if(x.spine){let w=x.radius+t,B=T(c,hn(...x.spine,c));A=F(B,B)<=w*w?{t:0,n:q(p,-1)}:Da(c,p,...x.spine,w)}else A=pd(x,c,p,t)}if(!A||A.t>r||m&&A.t>=m.distance)continue;let v=de(c,q(p,A.t));m={index:h,distance:A.t,normal:A.n,center:v,point:T(v,q(A.n,t))}}return m}var pn=class{constructor(e,{speedThreshold:t=.08,timeThreshold:i=.6}={}){if(!Number.isFinite(t)||t<=0||!Number.isFinite(i)||i<=0)throw Error("Sleep thresholds must be positive and finite");this.world=e,this.speedThreshold=t,this.timeThreshold=i,this.time=new Float64Array(e.bodyCount),this.asleep=new Set}wake(){let e=this.world;for(let t of this.asleep)e.dimension===3?e.solver.bodies[t].sleeping=!1:e.solver.dynamic[t]=+(e.solver.shape[t*4+2]>0);this.asleep.clear(),this.time.fill(0)}after(){let e=this.world,t=e.solver,i=e.bodyCount,r=Int32Array.from({length:i},(d,p)=>p),o=new Set,n=[],a=d=>e.dimension===3?t.bodies[d].mass:t.shape[d*4+2],l=d=>{for(;r[d]!==d;)r[d]=r[r[d]],d=r[d];return d},c=(d,p)=>{if(d<0){o.add(p);return}a(d)<=0?o.add(p):a(p)<=0?o.add(d):r[l(d)]=l(p),n.push([d,p])};if(e.dimension===3){let d=new Map(t.bodies.map((p,m)=>[p,m]));for(let p of t.forces)!p.broken&&!p.bodyA?.isTrigger&&!p.bodyB?.isTrigger&&c(p.bodyA?d.get(p.bodyA):-1,d.get(p.bodyB))}else{for(let d of t.contactPairs)!t.sensors.has(d.a)&&!t.sensors.has(d.b)&&c(d.a,d.b);for(let d=0;d<t.jointCount;d++)(t.data[d*32+6]||t.data[d*32+7]||t.data[d*32+8])&&c(t.info[d*4+1],t.info[d*4+2])}let u=new Set([...o].map(l)),f=new Map;for(let d=0;d<i;d++)if(a(d)>0){let p=l(d),m=e.dimension===3?t.bodies[d]:null,h=m?m.allowSleep!==!1:t.avbdSleepEligible?.get(d)!==!1,g=m?Math.hypot(...m.velocityLin,...m.velocityAng):Math.hypot(...t.velocity.subarray(d*4,d*4+3));f.has(p)||f.set(p,u.has(p)),f.set(p,f.get(p)&&h&&g<=this.speedThreshold)}for(let d=0;d<i;d++)a(d)>0&&(this.time[d]=f.get(l(d))?this.time[d]+e.params.dt:0,this.time[d]>=this.timeThreshold&&(this.asleep.add(d),e.dimension===3?(t.bodies[d].sleeping=!0,t.bodies[d].velocityLin.fill(0),t.bodies[d].velocityAng.fill(0)):(t.dynamic[d]=0,t.velocity.fill(0,d*4,d*4+4))));n.some(([d,p])=>d>=0&&a(d)>0&&a(p)>0&&this.asleep.has(d)!==this.asleep.has(p))&&this.wake()}};var mn=class{constructor(e,t,i={}){if(this.backend="cpu",this.dimension=t,this.scene=e,this.stepCount=0,this.pending=new ti,this.events=[],this.previous=new Map,this.watched=null,t===3){this.solver=Object.assign(new cn,e.ref),this.solver.up=[...e.up??[0,0,1]],this.nativeRef=e.ref,this.constraints=this.solver.forces.slice();for(let r of this.solver.bodies)r.solver=this.solver;for(let r of this.constraints)r.solver=this.solver;this.constraints.forEach((r,o)=>{let n=e.handles?.get(r);n&&(n.slot=o)}),nn(this.solver)}else this.solver=new fn(e.topology,e,i.order==="colored"?"soa-colored":"soa-seq"),this.topology=this.solver,this.builder=Object.assign(Object.create(Object.getPrototypeOf(e)),{topology:this.solver,filters:this.solver.filters,sensors:this.solver.sensors,restitution:this.solver.restitution});this.params=t===3?this.solver:this.solver.params,Tr(this,t===3?{bodies:this.solver.bodies}:null,t,{setVelocities:this.setPackedVelocities,readSelectedBodies:this.readSelectedBodies}),(i.sleeping||e.sleepOptIn||[...e.topology?.avbdSleepEligible?.values()??[]].some(Boolean))&&this.enableSleeping(i.sleeping===!0?{}:i.sleeping)}get bodyCount(){return this.dimension===3?this.solver.bodies.length:this.solver.bodyCount}get jointCount(){return this.dimension===3?this.constraints.length:this.solver.jointCount}gpuIndex(e){return this.liveIndex(e),e}liveIndex(e){if(this.assertLive(),!Number.isInteger(e)||e<0||e>=this.bodyCount)throw Error("A live body index is required")}assertLive(){if(this.destroyed)throw Error("The solver has been destroyed")}prepareBodyCommands(){return this.wakeAll(),{enqueueValidated:e=>{this.pending.reserve(this.pending.count+e.count),this.pending.u32.set(e.u32.subarray(0,e.count*12),this.pending.count*12),this.pending.count+=e.count}}}setLinearVelocity(e,t){return this.editBodies([{body:e,linearVelocity:t}])}setAngularVelocity(e,t){return this.editBodies([{body:e,angularVelocity:t}])}applyImpulse(e,t,i){return this.editBodies([{body:e,impulse:t,worldPoint:i}])}applyForce(e,t,i){return this.editBodies([{body:e,force:t,worldPoint:i}])}applyAngularImpulse(e,t){return this.editBodies([{body:e,angularImpulse:t}])}applyTorque(e,t){return this.editBodies([{body:e,torque:t}])}teleport(e,t,i){return this.editBodies([{body:e,position:t,rotation:i}])}setPackedVelocities(e,t){let i=Array.from(e),r=t?.linear,o=t?.angular,n=this.dimension,a=n===3?3:1;if(r===void 0&&o===void 0)throw Error("Provide linear or angular velocities");let l=-1;i.forEach(d=>{if(this.liveIndex(d),d<=l)throw Error("Velocity batch indices must be unique and ascending GPU slots");l=d});for(let[d,p]of[[r,n],[o,a]])if(d!==void 0&&(d.length!==i.length*p||!Array.from(d).every(m=>Number.isFinite(Math.fround(m)))))throw Error("Provide finite packed velocity components per body");let c=r===void 0?null:Array.from(r),u=o===void 0?null:Array.from(o),f=i.map((d,p)=>({body:d,...c===null?{}:{linearVelocity:c.slice(p*n,(p+1)*n)},...u===null?{}:{angularVelocity:n===3?u.slice(p*a,(p+1)*a):u[p]}}));return this.editBodies(f),this.flushEdits(),this}flushEdits(){if(this.destroyed)throw Error("The solver has been destroyed");let{words:e,u32:t,count:i}=this.pending,r=this.solver,o=this.dimension;for(let n=0;n<i;n++){let a=n*12,l=t[a],c=t[a+1],u=t[a+2]!==0,f=o===3?r.bodies[l]:null,d=f?.velocityLin??r.velocity.subarray(l*4,l*4+2),p=f?.mass??r.shape[l*4+2],m=f?.positionLin??r.pose.subarray(l*4,l*4+2),h=g=>{if(!(p<=0))if(o===2)r.velocity[l*4+2]+=g[0]/Math.max(1e-10,r.shape[l*4+3]);else{let b=f.positionAng,y=Ee([-b[0],-b[1],-b[2],b[3]],g),A=Ee(b,y.map((v,x)=>v/Math.max(1e-10,f.moment[x])));for(let v=0;v<3;v++)f.velocityAng[v]+=A[v]}};if(c===0)d.set(e.subarray(a+4,a+4+o));else if(c===1)f?f.velocityAng.set(e.subarray(a+4,a+7)):r.velocity[l*4+2]=e[a+4];else if(c===4)if(m.set(e.subarray(a+4,a+4+o)),f){u&&f.positionAng.set(e.subarray(a+8,a+12)),f.initialLin.set(m),f.inertialLin.set(m),f.initialAng.set(f.positionAng),f.inertialAng.set(f.positionAng);for(let g of[...f.forces])g.contacts&&g.destroy()}else u&&(r.pose[l*4+2]=e[a+6]),r.initial.set(r.pose.subarray(l*4,l*4+4),l*4),r.inertial.set(r.pose.subarray(l*4,l*4+4),l*4),r.prevCount=0;else if(c===2||c===3){if(p<=0)continue;let g=Array.from(e.subarray(a+4,a+4+o),b=>b*(c===3?e[a+7]:1));for(let b=0;b<o;b++)d[b]+=g[b]/p;if(u){let b=Array.from(e.subarray(a+8,a+8+o),(y,A)=>y-m[A]);h(o===3?xt(b,g):[b[0]*g[1]-b[1]*g[0]])}}else(c===5||c===6)&&h(Array.from(e.subarray(a+4,a+4+(o===3?3:1)),g=>g*(c===6?e[a+7]:1)))}this.pending.count=0}step(){this.flushEdits(),this.solver.step(),this.sleeping?.after(),this.stepCount++,this.captureEvents()}attachToScene(e,t){return Xo.call(this,e,t)}detachFromScene(){return Yo.call(this)}setFilters(e,t,i){let r=Array.from(e),o=Array.from(t),n=Array.from(i);if(o.length!==r.length||n.length!==r.length)throw Error("Provide one group and mask per body");r.forEach(a=>this.liveIndex(a));for(let a of[...o,...n])if(!Number.isInteger(a)||a<0||a>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");r.forEach((a,l)=>{this.dimension===3?Object.assign(this.solver.bodies[a],{group:o[l],collidesWith:n[l]}):this.solver.filters.set(a,[o[l],n[l]])}),this.wakeAll()}setSensor(e,t){if(this.liveIndex(e),typeof t!="boolean")throw Error("Trigger flag must be boolean");this.dimension===3?this.solver.bodies[e].isTrigger=t:t?this.solver.sensors.add(e):this.solver.sensors.delete(e),this.wakeAll()}setRestitution(e,t){if(this.liveIndex(e),!Number.isFinite(t)||t<0||t>1)throw Error("restitution must be between 0 and 1");this.dimension===3?this.solver.bodies[e].restitution=t:this.solver.restitution.set(e,t),this.wakeAll()}setMotor(e,t){if(this.assertLive(),this.dimension===3){let i=this.constraints[e];if(!i?.cpuAngular)throw Error("A motor constraint is required");Object.assign(i.cpuAngular.options,kt({...i.cpuAngular.options,...t}))}else{let i=this.solver,r=e*O;if(!Number.isInteger(e)||e<0||e>=i.jointCount||i.info[e*4]!==3)throw Error("A motor constraint is required");let o=t.speed??i.data[r+re],n=t.maxTorque??i.data[r+Ae];if(!Number.isFinite(o)||!Number.isFinite(n)||n<0)throw Error("Provide finite motor speed and nonnegative torque");i.data[r+re]=o,i.data[r+_e]=-n,i.data[r+Ae]=n}this.wakeAll()}setAngleLimits(e,t){if(this.assertLive(),this.dimension!==2)throw Error("Use a 3D hinge constraint");if(this.solver.info[e*4]!==5)throw Error("An angular limit is required");vs(this.solver,e,ki(t)),this.wakeAll()}releaseJoints(e){for(let t of e)this.disableConstraint(t)}disableConstraint(e){if(this.assertLive(),!Number.isInteger(e)||e<0||e>=this.jointCount)throw Error("A live constraint slot is required");if(this.dimension===3){let t=this.constraints[e];t.broken=!0,(t.cpuAngular??t).destroy()}else this.solver.disable(e),this.solver.info[e*4]=0,this.solver.noCollideDirty=!0;this.wakeAll()}setWorldAnchor(e,t,i){if(this.assertLive(),this.dimension===2){let r=this.solver;if(!Number.isInteger(e)||e<0||e>=r.jointCount||r.info[e*4+1]!==-1)throw Error("A world-anchor constraint is required");r.data.set(me([t,i],2,"point"),e*O+21)}else{let r=this.constraints[e];if(!r||r.bodyA)throw Error("A world-anchor constraint is required");r.rA.set(me(t,3,"point"))}this.wakeAll()}addBox(...e){return this.addDynamic("addBox",e)}addCircle(...e){return this.addDynamic("addCircle",e)}addCapsule(...e){return this.addDynamic("addCapsule",e)}addHull(...e){return this.addDynamic("addHull",e)}addSegment(...e){return this.addDynamic("addSegment",e)}addPlane(...e){return this.addDynamic("addPlane",e)}addDynamic(e,t){if(this.destroyed)throw Error("The solver has been destroyed");if(this.dimension!==2)throw Error("Build 3D bodies before creating the solver");this.wakeAll();let i=this.sleeping?{speedThreshold:this.sleeping.speedThreshold,timeThreshold:this.sleeping.timeThreshold}:null,r=this.builder[e](...t);return i&&this.enableSleeping(i),r}appendJoint(e,t,i,r,o,n=1/0){if(this.assertLive(),this.dimension!==2)throw Error("Build 3D constraints before creating the solver");return this.wakeAll(),this.builder.addJoint(e,t,i,r,{stiffness:o,breakForce:n}).slot}captureConstraintFrames(e){if(this.assertLive(),this.dimension!==3)throw Error("Constraint frame capture requires a 3D world");let t=Array.from(e);for(let{slot:i,spring:r}of t){let o=this.constraints[i];if(!Number.isInteger(i)||!o||o.broken||o.cpuAngular||(r?o.rest===void 0:o.stiffnessAng===void 0))throw Error("A live spring or joint slot is required")}this.flushEdits();for(let{slot:i,spring:r}of t)ja(this.constraints[i],r);t.length&&this.wakeAll()}setSpringMaterial(e,t={}){this.assertLive();let i=this.constraints[e];if(!i||i.rest===void 0)throw Error("A spring constraint is required");vr(i,It(t)),this.wakeAll()}packBodyRecords(e,t=!1){let i=this.solver,r=this.dimension,o=t?r===3?8:4:r===3?40:24,n=e?.length??this.bodyCount,a=new Float32Array(n*o);for(let l=0;l<n;l++){let c=e?.[l]??l,u=l*o;if(t){if(r===3){let f=i.bodies[c];a.set(f.positionLin,u),a[u+3]=f.friction,a.set(f.positionAng,u+4)}else a.set(i.pose.subarray(c*4,c*4+4),u),a[u+3]=i.props[c*4];continue}if(r===3){let f=i.bodies[c];a.set(f.positionLin,u),a[u+3]=f.friction,a.set(f.positionAng,u+4),a.set(f.initialLin,u+8),a[u+11]=+!!f.isTrigger,a.set(f.initialAng,u+12),a.set(f.size,u+16),a[u+19]=f.sleeping?0:f.mass,a.set(f.moment,u+20),a[u+23]=f.radius,a.set(f.inertialLin,u+24),a.set(f.inertialAng,u+28),a.set(f.velocityLin,u+32),a[u+35]=f.prevVelocityLin.reduce((d,p,m)=>d+p*i.up[m],0),a.set(f.velocityAng,u+36),a[u+39]=De(f)?1:Fe(f)?-1:Ct(f)?3:or(f)?2:0}else a.set(i.pose.subarray(c*4,c*4+4),u),a[u+3]=i.props[c*4],a.set(i.initial.subarray(c*4,c*4+4),u+4),a.set(i.inertial.subarray(c*4,c*4+4),u+8),a.set(i.velocity.subarray(c*4,c*4+4),u+12),a.set(i.prevVelocity.subarray(c*4,c*4+4),u+16),a.set(i.shape.subarray(c*4,c*4+4),u+20)}return a}async readBodies(){return this.flushEdits(),this.packBodyRecords()}async readSelectedBodies(e,{posesOnly:t=!1}={}){let i=Array.from(e);return i.forEach(r=>this.liveIndex(r)),this.flushEdits(),this.packBodyRecords(i,t)}async readBodyState(e){this.liveIndex(e),this.flushEdits();let t=this.solver;if(this.dimension===3){let i=t.bodies[e],r=this.sleeping?.asleep.has(e)??!1;return{position:Array.from(i.positionLin),rotation:Array.from(i.positionAng),linearVelocity:Array.from(i.velocityLin),angularVelocity:Array.from(i.velocityAng),mass:i.mass,effectiveMass:r?0:i.mass,sleeping:r}}return{position:Array.from(t.pose.subarray(e*4,e*4+2)),angle:t.pose[e*4+2],linearVelocity:Array.from(t.velocity.subarray(e*4,e*4+2)),angularVelocity:t.velocity[e*4+2],mass:t.shape[e*4+2],moment:t.shape[e*4+3],sleeping:this.sleeping?.asleep.has(e)??!1}}async readJoints(){return this.flushEdits(),this.packJointRecords()}packJointRecords(){let e=this.dimension===3?32:36,t=new Float32Array(this.jointCount*e),i=r=>r===1/0?3e38:r===-1/0?-3e38:r;if(this.dimension===2){let r=this.solver.data;for(let o=0;o<this.jointCount;o++){let n=o*36,a=o*O;[se,te,Q,_e,Ae,Pt,fe].forEach((l,c)=>{for(let u=0;u<3;u++)t[n+c*4+u]=i(r[a+l+u])}),t.set([r[a+N],r[a+N+1],r[a+Y],r[a+Y+1]],n+28),t.set([r[a+re],r[a+re+1],r[a+re+2],0],n+32)}}else this.constraints.forEach((r,o)=>{let n=o*32;if(r.cpuAngular){let a=r.cpuAngular,l=a.options;t.set(a.pen,n),t[n+3]=r.broken?0:1,t.set(a.lam,n+8),t.set(a.ta,n+16),t.set(a.tb,n+20),t.set(l.axisA,n+24),t.set(l.axisB,n+28),t[n+19]=a.c0?.[0]??0,t[n+23]=a.c0?.[1]??0,t[n+27]=l.type==="motor"?l.speed:l.minAngle,t[n+31]=l.type==="motor"?l.maxTorque:l.maxAngle;return}for(let[a,l]of[["penaltyLin",0],["penaltyAng",4],["lambdaLin",8],["lambdaAng",12],["C0Lin",16],["C0Ang",20],["rA",24],["rB",28]])r[a]&&t.set(r[a],n+l);if(t[n+3]=r.broken?0:i(r.stiffnessLin??r.stiffness??0),t[n+7]=r.broken?0:i(r.stiffnessAng??0),t[n+11]=i(r.fracture??0),t[n+15]=r.torqueArm??0,t[n+27]=r.rest??0,r.cpuRest&&(t[n+19]=r.cpuRest[0],t[n+23]=r.cpuRest[1],t[n+27]=r.cpuRest[2],t[n+31]=r.cpuRest[3]),r.rest!==void 0){let a=Ui(r);t[n+11]=Number.isFinite(a?.breakStrain)?a.breakStrain:0,t[n+15]=Number.isFinite(a?.breakForce)?a.breakForce:0}});return t}async readCounters(){this.assertLive();let e=this.dimension===2?this.solver.contactCount:this.solver.forces.reduce((i,r)=>i+(r.contacts?.length??0),0),t=this.dimension===2?this.solver.contactPairs.length:this.solver.forces.filter(i=>i.contacts?.length).length;return{pairs:t,contacts:e,manifolds:t,joints:this.jointCount,overflow:0,clashes:0,colors:0,sleeping:this.sleeping?.asleep.size??0}}adapt(){}watchContacts({indices:e,maxPairs:t=this.maxPairs??8192,maxEvents:i=this.maxEvents??4096}={}){if(this.assertLive(),!Number.isInteger(i)||i<1||!Number.isInteger(t)||t<1)throw Error("Contact capacities must be positive integers");return e!==void 0?(e.forEach(r=>this.liveIndex(r)),this.watched=new Set(e)):this.watched??=new Set(Array.from({length:this.bodyCount},(r,o)=>o)),this.maxEvents=i,this.maxPairs=t,this}captureEvents(){if(!this.watched)return;let e=this.dimension===3?new Map(this.solver.bodies.map((i,r)=>[i,r])):null,t=this.dimension===2?this.solver.contactPairs:this.solver.forces.filter(i=>i.contacts?.length).map(i=>{let r=Array.from(i.bodyA.positionLin);for(let o of i.contacts){let n=Ee(i.bodyA.positionAng,o.rA);for(let a=0;a<3;a++)r[a]+=n[a]/i.contacts.length}return{a:e.get(i.bodyA),b:e.get(i.bodyB),point:r,normal:Array.from(i.basis.slice(0,3)),impulse:i.bodyA.isTrigger||i.bodyB.isTrigger?0:i.contacts.reduce((o,n)=>o+Math.abs(n.lambda[0])*this.params.dt,0)}});this.trackContactPairs(t)}trackContactPairs(e){let t=new Map,i=(n,a)=>{this.events.length<(this.maxEvents??4096)?this.events.push({...n,normal:n.normal??[...n.n,0],type:a,kind:a==="begin"?1:2,step:this.stepCount,isTrigger:n.isTrigger??(this.dimension===3?!!(this.solver.bodies[n.a].isTrigger||this.solver.bodies[n.b].isTrigger):this.solver.sensors.has(n.a)||this.solver.sensors.has(n.b))}):this.dropped=(this.dropped??0)+1},r=new Set,o=[];for(let n of e){if(!this.watched.has(n.a)&&!this.watched.has(n.b))continue;let a=`${Math.max(n.a,n.b)},${Math.min(n.a,n.b)}`;r.add(a),this.previous.has(a)&&t.size<this.maxPairs?t.set(a,n):o.push([a,n])}for(let[n,a]of o)if(!t.has(n)){if(t.size>=this.maxPairs){this.pairFull=!0;continue}t.set(n,a),this.previous.has(n)||i(a,"begin")}for(let[n,a]of this.previous)r.has(n)||i({...a,impulse:0},"end");this.previous=t}async readContactEvents(){this.watchContacts();let e={events:this.events,dropped:this.dropped??0,full:!!this.dropped||!!this.pairFull};return this.events=[],this.dropped=0,this.pairFull=!1,e}async raycast(e,t,i){return this.sphereCast(e,0,t,i)}async circleCast(e,t,i,r){return this.sphereCast(e,t,i,r)}async sphereCast(e,t,i,r){return this.flushEdits(),hu(this,e,t,i,r)}async raycastAll(e,t){return Promise.all(e.map(i=>this.raycast(i.origin,i.direction,{...t,maxDistance:i.maxDistance??t?.maxDistance})))}async sphereCastAll(e,t){return Promise.all(e.map(i=>this.sphereCast(i.origin,i.radius,i.direction,{...t,maxDistance:i.maxDistance??t?.maxDistance})))}async circleCastAll(e,t){return this.sphereCastAll(e,t)}setSleepEnabled(e,t){if(this.liveIndex(e),typeof t!="boolean")throw Error("Sleep flag must be boolean");return this.dimension===3?this.solver.bodies[e].allowSleep=t:(this.solver.avbdSleepEligible??=new Map,this.solver.avbdSleepEligible.set(e,t)),t&&!this.sleeping&&this.enableSleeping(),this.wakeAll(),this}enableSleeping(e={}){return this.assertLive(),this.disableSleeping(),this.sleeping=new pn(this,e),this}disableSleeping(){return this.sleeping?.wake(),this.sleeping=null,this}async readSleepStats(){return this.assertLive(),{sleeping:this.sleeping?.asleep.size??0,wakeRequested:!1}}wakeUp(e){return this.liveIndex(e),this.wakeAll()}wakeAll(){return this.sleeping?.wake(),this}destroy(){this.destroyed||(this.detachFromScene(),this.disableSleeping(),this.pending.count=0,this.events=[],this.previous.clear(),this.destroyed=!0)}};var pu=new WeakSet,gn=s=>s!==null&&typeof s=="object"&&pu.has(s),mu=s=>pu.add(s);async function bd({backend:s="webgpu",device:e,gl:t,validate3D:i=!0,...r}={}){if(!["webgpu","cpu"].includes(s))throw Error(`Unsupported solver backend: ${s}`);if(s!=="webgpu"&&e!==void 0)throw Error("Only WebGPU initialization accepts a GPU device");if(t!==void 0)throw Error("Solver pipelines do not accept a WebGL context");let o,n=!1,a=!1;s==="webgpu"&&(e?i&&await Cr(e):({device:e,adapter:o}=await ss({...r,preferredLimits:{maxStorageBuffersPerShaderStage:9,maxStorageBufferBindingSize:512*1024*1024,maxBufferSize:1024*1024*1024,...r.preferredLimits},validate3D:i}),n=!0));let l=new Set,c={backend:s,device:e,adapter:o,createSolver(u,f={}){if(a)throw Error("The solver pipeline has been destroyed");if(!u||typeof u.assertEditable!="function"||!u.ref&&!u.topology)throw Error("An AVBD scene builder is required");u.assertEditable();let d;if(s==="webgpu")d=u.createSolver(e,f);else{let m=u.ref?3:u.topology?2:0;if(f.bodyBuffer!==void 0)throw Error("A GPU body buffer requires the WebGPU backend");d=new mn(u,m,f),u.gpu=d,u.created=!0}Object.defineProperty(d,"backend",{value:s,configurable:!0}),l.add(d);let p=d.destroy;return d.destroy=function(){p.call(this),l.delete(this)},d},destroy(){if(!a){for(let u of l)u.destroy();l.clear(),n&&e.destroy(),a=!0}}};return mu(c),c}var ie=(s,e,t)=>{let i=Array.from(s);if(i.length!==e||!i.every(Number.isFinite))throw Error(`${t} requires ${e} finite components`);return i},K=(s,e,t=!1)=>{if(!Number.isFinite(s)||(t?s<0:s<=0))throw Error(`${e} must be ${t?"nonnegative":"positive"} and finite`);return s},gu=s=>{if(!Number.isInteger(s)||s<0||s>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");return s};function bn(s){for(let t of["allowSleep","isTrigger"])if(s[t]!==void 0&&typeof s[t]!="boolean")throw Error(`${t} must be a boolean`);let e=s.restitution??0;if(!Number.isFinite(e)||e<0||e>1)throw Error("restitution must be between 0 and 1");if(s.mass!==void 0&&(K(s.mass,"mass",!0),s.mass>0&&s.density===0))throw Error("A positive mass needs positive density");for(let t of["velocity","angularVelocity"])s[t]!==void 0&&ie(s[t],3,t);if(s.rotation!==void 0&&!Math.hypot(...ie(s.rotation,4,"rotation")))throw Error("rotation must be nonzero");gu(s.group??4294967295),gu(s.collidesWith??4294967295)}function bu(s,e){if(e.timeStep!==void 0&&(s.dt=K(e.timeStep,"timeStep")),e.iterations!==void 0){if(K(e.iterations,"iterations"),!Number.isInteger(e.iterations))throw Error("iterations must be an integer");s.iterations=e.iterations}if(e.gravity!==void 0){if(!Number.isFinite(e.gravity))throw Error("gravity must be finite");s.gravity=e.gravity}}var Ga=class{constructor(e={}){if(this.ref=new ai,bu(this.ref,e),this.up=ie(e.up??[0,1,0],3,"up"),Math.abs(Math.hypot(...this.up)-1)>1e-5)throw Error("up must be a unit vector");this.points=!1,this.handles=new Map,this.bodySet=new Set}get bodies(){return this.ref.bodies}get constraints(){return[...this.handles.values()]}assertEditable(){if(this.created)throw Error("Build this scene before createSolver; use the solver's GPU edit methods afterwards")}addBox(e,t={}){this.assertEditable(),bn(t);let i=ie(e,3,"size");i.forEach(o=>K(o,"size"));let r=new Ze(this.ref,i,K(t.density??1,"density",!0),K(t.friction??.6,"friction",!0),ie(t.position??[0,0,0],3,"position"));return this.configure(r,t)}addSphere(e,t={}){return this.assertEditable(),bn(t),this.configure(nr(this.ref,K(e,"radius"),K(t.density??1,"density",!0),K(t.friction??.6,"friction",!0),ie(t.position??[0,0,0],3,"position")),t)}addHull(e,t={}){if(this.assertEditable(),bn(t),e.length%3||!Array.from(e).every(Number.isFinite))throw Error("Hull points must contain finite xyz triples");let i=Ur(e);if(!i)throw Error("A convex hull requires finite points spanning a volume");return this.hulls=!0,this.configure(ar(this.ref,i,K(t.density??1,"density",!0),K(t.friction??.6,"friction",!0),ie(t.position??[0,0,0],3,"position")),t)}addCapsule(e,t,i={}){return this.assertEditable(),bn(i),this.configure(Br(this.ref,e,t,K(i.density??1,"density",!0),K(i.friction??.6,"friction",!0),ie(i.position??[0,0,0],3,"position")),i)}addHeightfield(e){return this.addTerrain(ls(e),e)}addStaticMesh(e){return this.addTerrain(cs(e),e)}addTerrain(e,t={}){this.assertEditable();let i=this.ref.bodies.length,r=go(this.ref,e,t);r.forEach(n=>this.bodySet.add(n)),this.hulls=!0;let o=!1;return{bodies:r,triangleCount:e.triangleCount,kind:e.kind,dispose:()=>{if(!o&&(o=!0,r.forEach(n=>{n.group=0,n.collidesWith=0}),this.gpu&&!this.gpu.destroyed)){let n=r.map((a,l)=>this.gpu.gpuIndex(i+l));this.gpu.setFilters(n,n.map(()=>0),n.map(()=>0)),this.gpu.wakeAll?.()}}}}configure(e,t){if(t.allowSleep!==void 0&&typeof t.allowSleep!="boolean")throw Error("allowSleep must be a boolean");e.allowSleep=t.allowSleep??!0,this.sleepOptIn||=t.allowSleep===!0;let i=t.restitution??0;if(!Number.isFinite(i)||i<0||i>1)throw Error("restitution must be between 0 and 1");if(e.restitution=i,t.isTrigger!==void 0&&typeof t.isTrigger!="boolean")throw Error("isTrigger must be a boolean");if(e.isTrigger=t.isTrigger??!1,e.group=t.group??4294967295,e.collidesWith=t.collidesWith??4294967295,t.mass!==void 0){let r=K(t.mass,"mass",!0);if(e.mass===0&&r>0)throw Error("A positive mass needs positive density");let o=e.mass>0?r/e.mass:0;e.mass=r,e.moment.forEach((n,a)=>e.moment[a]=n*o)}if(t.rotation){let r=ie(t.rotation,4,"rotation"),o=Math.hypot(...r);if(!o)throw Error("rotation must be nonzero");e.positionAng.set(r.map(n=>n/o))}return t.velocity&&e.velocityLin.set(ie(t.velocity,3,"velocity")),t.angularVelocity&&e.velocityAng.set(ie(t.angularVelocity,3,"angularVelocity")),this.bodySet.add(e),e}addPoint(e,{mass:t=.02,radius:i=.05,friction:r=.5}={}){let o=this.addSphere(i,{position:e,mass:t,friction:r});return o.moment.fill(0),this.points=!0,o}addFabric({columns:e=16,rows:t=16,spacing:i=.2,origin:r=[0,3,0],mass:o=.02,stiffness:n=1e3,anchorStiffness:a=n,materialAt:l,breakStrain:c=1/0,breakForce:u=1/0,bendingStiffness:f=Number.isFinite(c)||Number.isFinite(u)?0:n/50,pinCorners:d=!1,pinEdges:p=!d}={}){for(let[E,k]of Object.entries({columns:e,rows:t}))if(!Number.isInteger(k)||k<2)throw Error(`${E} must be an integer >= 2`);if(K(i,"spacing"),K(o,"mass"),K(n,"stiffness"),K(a,"anchorStiffness"),l!==void 0&&typeof l!="function")throw Error("materialAt must be a function");if(K(f,"bendingStiffness",!0),typeof d!="boolean"||typeof p!="boolean")throw Error("Fabric pin options must be boolean");let m=It({breakStrain:c,breakForce:u}),h=ie(r,3,"origin"),g=(E,k)=>`${Math.min(E,k)},${Math.max(E,k)}`;function*b(){for(let E=0;E<t;E++)for(let k=0;k<e;k++){let P=E*e+k;k&&(yield[P,P-1,n]),E&&(yield[P,P-e,n]),k&&E&&(yield[P,P-e-1,n/2],yield[P-1,P-e,n/2]),k>1&&f&&(yield[P,P-2,f]),E>1&&f&&(yield[P,P-2*e,f])}}let y=new Map;if(l)for(let[E,k]of b()){let P=l((E%e+k%e)/(2*(e-1)),(Math.floor(E/e)+Math.floor(k/e))/(2*(t-1)))??{};if(typeof P!="object"||Array.isArray(P))throw Error("materialAt must return a material object");y.set(g(E,k),{scale:K(P.stiffnessScale??1,"materialAt.stiffnessScale"),material:It({...m,...P})})}let A=Array.from({length:t},(E,k)=>Array.from({length:e},(P,C)=>this.addPoint([h[0]+(C-(e-1)/2)*i,h[1],h[2]+(k-(t-1)/2)*i],{mass:p&&(C===0||k===0||C===e-1||k===t-1)||d&&(C===0||C===e-1)&&(k===0||k===t-1)?0:o,radius:i/Math.SQRT2}))),v=A.flat(),x=new Map(v.map((E,k)=>[E,k])),w=[],B=new Map,L=(E,k,P)=>{(E.mass===0||k.mass===0)&&(P*=a/n);let C=x.get(E),_=x.get(k),z=y.get(g(C,_)),R=this.addSpring(E,k,[0,0,0],[0,0,0],{stiffness:P*(z?.scale??1),...z?.material??m});return B.set(g(x.get(E),x.get(k)),w.length),w.push(R),R};for(let[E,k,P]of b())L(v[E],v[k],P);let M=[];for(let E=0;E<t;E++)for(let k=0;k<e;k++)if(k&&E){let P=(E-1)*e+k-1,C=P+1,_=E*e+k-1,z=_+1;M.push(P,_,C,C,_,z)}let I=[];for(let E=0;E<M.length;E+=3){let[k,P,C]=M.slice(E,E+3);I.push(B.get(g(k,P)),B.get(g(P,C)),B.get(g(C,k)))}return{points:v,grid:A,indices:Uint32Array.from(M),connections:w,triangleConnections:Uint32Array.from(I)}}addRope({segments:e=12,length:t=12,origin:i=[0,12,0],width:r=.15,endMass:o=20}={}){if(!Number.isInteger(e)||e<1)throw Error("segments must be a positive integer");K(t,"length"),K(r,"width"),K(o,"endMass",!0);let n=ie(i,3,"origin"),a=t/e,l=this.addBox([r,r,r],{mass:0,position:n}),c=[];for(let u=0;u<e;u++){let f=this.addBox([r,a,r],{mass:1,position:[n[0],n[1]-(u+.5)*a,n[2]]});this.addJoint(u?c[u-1]:l,f,[0,u?-a/2:0,0],[0,a/2,0]),c.push(f)}if(o){let u=this.addBox([.6,.6,.6],{mass:o,position:[n[0],n[1]-t-.3,n[2]]});this.addJoint(c.at(-1),u,[0,-a/2,0],[0,.3,0]),c.push(u)}return{anchor:l,links:c}}addRagdoll({origin:e=[0,2,0],mass:t=10}={}){let i=ie(e,3,"origin");K(t,"mass");let r=(l,c)=>this.addBox(l,{mass:t/10,position:c.map((u,f)=>u+i[f])}),o=r([.7,1.2,.35],[0,2,0]),n=this.addSphere(.25,{mass:t/10,position:[i[0],i[1]+2.9,i[2]]}),a=[o,n];this.addJoint(o,n,[0,.6,0],[0,-.3,0]);for(let l of[-1,1]){let c=r([.3,.8,.3],[l*.5,1.95,0]),u=r([.26,.7,.26],[l*.5,1.2,0]);this.addJoint(o,c,[l*.35,.35,0],[-l*.15,.4,0]),this.addJoint(c,u,[0,-.4,0],[0,.35,0]);let f=r([.28,.8,.3],[l*.2,1,0]),d=r([.26,.75,.28],[l*.2,.225,0]);this.addJoint(o,f,[l*.2,-.6,0],[0,.4,0]),this.addJoint(f,d,[0,-.4,0],[0,.375,0]),a.push(c,u,f,d)}return{torso:o,head:n,bodies:a}}addJoint(e,t,i=[0,0,0],r=[0,0,0],{linearStiffness:o=1/0,angularStiffness:n=0,breakForce:a=1/0,breakOnPull:l=!1}={}){this.assertEditable(),this.checkBodies(e,t);for(let c of[o,n,a])c!==1/0&&K(c,"joint stiffness/breakForce",!0);return this.handle(new ke(this.ref,e,t,ie(i,3,"anchorA"),ie(r,3,"anchorB"),o,n,l&&a!==1/0?-a:a))}addSpring(e,t,i=[0,0,0],r=[0,0,0],{stiffness:o=1e3,rest:n=-1,breakStrain:a=1/0,breakForce:l=1/0}={}){if(this.assertEditable(),this.checkBodies(e,t),!e)throw Error("A spring requires two bodies");K(o,"stiffness",!0),n!==-1&&K(n,"rest",!0);let c=It({breakStrain:a,breakForce:l}),u=new ft(this.ref,e,t,ie(i,3,"anchorA"),ie(r,3,"anchorB"),o,n);return vr(u,c),this.handle(u)}checkBodies(e,t){if(!t||e===t||!this.bodySet.has(t)||e&&!this.bodySet.has(e))throw Error("Constraint endpoints must be distinct bodies in this scene")}addMotor(e,t,i={}){this.assertEditable(),this.checkBodies(e,t);let r=kt({...i,type:"motor"}),o=new ke(this.ref,e,t,[0,0,0],[0,0,0],1/0,0);return wr(o,r),this.handle(o)}addHinge(e,t,i={}){this.assertEditable(),this.checkBodies(e,t);let r=kt({...i,type:"limit"}),o=K(i.span??1,"span"),n=ie(i.anchorA??[0,0,0],3,"anchorA"),a=ie(i.anchorB??[0,0,0],3,"anchorB"),l=[-1,1].map(f=>this.addJoint(e,t,n.map((d,p)=>d+f*o*.5*r.axisA[p]),a.map((d,p)=>d+f*o*.5*r.axisB[p]))),c,u;if(i.minAngle!==void 0||i.maxAngle!==void 0){let f=new ke(this.ref,e,t,[0,0,0],[0,0,0],1/0,0);wr(f,r),c=this.handle(f)}return i.motor&&(u=this.addMotor(e,t,{axisA:r.axisA,axisB:r.axisB,...i.motor})),{joints:l,limit:c,motor:u,dispose(){for(let f of[...l,c,u])f?.dispose()}}}handle(e){let t={slot:-1,disposed:!1,dispose:()=>{t.disposed||(this.gpu?this.gpu.destroyed||this.gpu.releaseJoints([t.slot]):e.destroy(),this.handles.delete(e),t.disposed=!0)}};return t.destroy=t.dispose,this.handles.set(e,t),t}createSolver(e,t={}){if(gn(e))return e.createSolver(this,t);if(this.assertEditable(),this.hulls&&e.limits.maxStorageBuffersPerShaderStage<9)throw Error("Hull collisions require nine storage buffer bindings");let i=new Ko(e,this.ref,ho(this.ref,{...t,...this.points?{shaders:{...t.shaders,solve:$c}}:{}})),r=[];this.ref.forces.forEach((l,c)=>{this.handles.get(l).slot=c,l instanceof ke&&l.stiffnessAng>0&&r.push({slot:c})}),i.captureConstraintFrames(r),i.params.up=[...this.up];let o=[],n=[],a=[];for(let[l,c]of this.ref.bodies.entries())(c.group!==4294967295||c.collidesWith!==4294967295)&&(o.push(i.gpuIndex(l)),n.push(c.group),a.push(c.collidesWith)),c.isTrigger&&i.setSensor(i.gpuIndex(l),!0),c.restitution>0&&i.setRestitution(i.gpuIndex(l),c.restitution);return o.length&&i.setFilters(o,n,a),(t.sleeping||this.sleepOptIn)&&i.enableSleeping(this.ref,t.sleeping===!0?{}:t.sleeping),this.gpu=i,this.created=!0,i}},Fa=class{constructor(e={}){if(this.topology=new zr,Object.assign(this.topology.params,So()),bu(this.topology.params,e),e.alpha!==void 0){if(!Number.isFinite(e.alpha)||e.alpha<0||e.alpha>1)throw Error("alpha must be between zero and one");this.topology.params.alpha=e.alpha}for(let t of["postStabilize","matchNearest"])if(e[t]!==void 0){if(typeof e[t]!="boolean")throw Error(`${t} must be boolean`);this.topology.params[t]=e[t]}}assertEditable(){if(this.created)throw Error("Build this scene before createSolver; use GPU edit methods afterwards")}get bodyCount(){return this.topology.bodyCount}addShape(e,t={}){let i=e.options??t,r=this.addBox(e.size,i);return Rr(this.topology,r,e,i.density??1),r}addCircle(e,t={}){return this.addShape(No(e),t)}addHull(e,t={}){return this.addShape(Uo(e),t)}addCapsule(e,t,i={}){return this.addShape(qo(e,t),i)}addSegment(e,t,i={}){return this.addShape(Vo(e,t,i))}addPlane(e=[0,1],t=0,i={}){return this.addShape(Wo(e,t,i))}addBox(e,{density:t=1,friction:i=.6,position:r=[0,0],angle:o=0,velocity:n=[0,0,0],restitution:a=0,isTrigger:l=!1,group:c=4294967295,collidesWith:u=4294967295,allowSleep:f}={}){if(this.assertEditable(),f!==void 0&&typeof f!="boolean")throw Error("allowSleep must be boolean");let d=ie(e,2,"size");d.forEach(h=>K(h,"size"));let p=ie(r,2,"position");if(!Number.isFinite(o))throw Error("angle must be finite");if(!Number.isFinite(a)||a<0||a>1)throw Error("restitution must be between 0 and 1");if(typeof l!="boolean")throw Error("isTrigger must be boolean");for(let h of[c,u])if(!Number.isInteger(h)||h<0||h>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");let m=this.topology.addBody(d,K(t,"density",!0),K(i,"friction",!0),[...p,o],ie(n,3,"velocity"));return this.restitution??=new Map,a>0&&this.restitution.set(m,a),this.sensors??=new Set,l&&this.sensors.add(m),this.filters??=new Map,(c!==4294967295||u!==4294967295)&&this.filters.set(m,[c,u]),this.topology.avbdSleepEligible??=new Map,f!==void 0&&this.topology.avbdSleepEligible.set(m,f),m}checkBodies(e,t){if(!Number.isInteger(e)||!Number.isInteger(t)||e<-1||e>=this.bodyCount||t<0||t>=this.bodyCount||e===t)throw Error("Invalid 2D constraint endpoints")}addJoint(e,t,i=[0,0],r=[0,0],{stiffness:o=[1/0,1/0,0],breakForce:n=1/0}={}){if(this.assertEditable(),this.checkBodies(e,t),!o||o.length!==3||Array.from(o).some(l=>l!==1/0&&(!Number.isFinite(l)||l<0))||n!==1/0&&(!Number.isFinite(n)||n<0))throw Error("Joint stiffness and break force must be nonnegative or Infinity");let a=this.topology.addJoint(e,t,ie(i,2,"anchorA"),ie(r,2,"anchorB"),o,n);return this.constraintHandle(a.slot,a)}constraintHandle(e,t={}){return Object.assign(t,{slot:e,alive:!0,disposed:!1}),t.dispose=()=>{t.disposed||(this.gpu&&!this.gpu.destroyed?this.gpu.disableConstraint(e):this.gpu||this.topology.data.fill(0,e*O+Q,e*O+Q+3),t.alive=!1,t.disposed=!0)},t.destroy=t.dispose,this.topology.handles[e]=t,t}addSpring(e,t,i=[0,0],r=[0,0],{stiffness:o=1e3,rest:n=1}={}){if(this.assertEditable(),this.checkBodies(e,t),e<0)throw Error("A spring requires two bodies");let a=this.topology.jointCount;return this.topology.addSpring(e,t,ie(i,2,"anchorA"),ie(r,2,"anchorB"),K(o,"stiffness",!0),K(n,"rest",!0)),this.constraintHandle(a)}addMotor(e,t,{speed:i=1,maxTorque:r=100}={}){if(this.assertEditable(),this.checkBodies(e,t),!Number.isFinite(i))throw Error("speed must be finite");let o=this.topology.jointCount;return this.topology.addMotor(e,t,i,K(r,"maxTorque",!0)),this.constraintHandle(o)}addAngularLimit(e,t,i={}){this.assertEditable(),this.checkBodies(e,t);let r=ki(i),o=this.topology.addJoint(e,t,[0,0],[0,0],[0,0,0]);vs(this.topology,o.slot,r);let n=this.constraintHandle(o.slot,o);return n.setLimits=a=>{if(n.disposed)throw Error("The angular limit has been disposed");return this.gpu?this.gpu.setAngleLimits(n.slot,a):vs(this.topology,n.slot,ki(a)),n},n}addHinge(e,t,i=[0,0],r=[0,0],o={}){this.assertEditable(),this.checkBodies(e,t);let n=ie(i,2,"anchorA"),a=ie(r,2,"anchorB"),l=o.minAngle!==void 0||o.maxAngle!==void 0?ki(o):null,c=o.motor;if(c){if(!Number.isFinite(c.speed??1))throw Error("speed must be finite");K(c.maxTorque??100,"maxTorque",!0)}let u=this.addJoint(e,t,n,a),f=l?this.addAngularLimit(e,t,l):null,d=c?this.addMotor(e,t,c):null;return{joint:u,limits:f,motor:d,disposed:!1,dispose(){this.disposed||(this.joint.dispose(),this.limits?.dispose(),this.motor?.dispose(),this.disposed=!0)},destroy(){this.dispose()}}}createSolver(e,t={}){if(gn(e))return e.createSolver(this,t);this.assertEditable();let i=new Qo(e,this.topology,t);for(let[r,o]of this.restitution??[])i.setRestitution(r,o);for(let r of this.sensors??[])i.setSensor(r,!0);for(let[r,o]of this.filters??[])i.setFilters([r],[o[0]],[o[1]]);return this.gpu=i,this.created=!0,i}};var Cs=class{constructor(e){if(this.device=e,this.latestMs=null,this.samples=0,this.slots=[],!!e.features.has("timestamp-query"))for(let t=0;t<3;t++)this.slots.push({query:e.createQuerySet({type:"timestamp",count:2}),resolve:e.createBuffer({size:256,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),read:e.createBuffer({size:16,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ}),busy:!1})}begin(){let e=this.slots.find(t=>!t.busy);return!e||this.disposed?null:(e.busy=!0,e)}descriptor(e){return e?{timestampWrites:{querySet:e.query,beginningOfPassWriteIndex:0,endOfPassWriteIndex:1}}:{}}encode(e,t){t&&(e.resolveQuerySet(t.query,0,2,t.resolve,0),e.copyBufferToBuffer(t.resolve,0,t.read,0,16))}resolve(e){if(e)return e.pending=e.read.mapAsync(GPUMapMode.READ).then(()=>{let t=new BigUint64Array(e.read.getMappedRange());this.latestMs=Number(t[1]-t[0])/1e6,this.samples++,e.read.unmap()}).catch(()=>{}).finally(()=>{e.busy=!1,e.pending=null}),e.pending}settled(){return Promise.all(this.slots.map(e=>e.pending))}destroy(){this.disposed=!0;for(let e of this.slots)e.query.destroy(),e.resolve.destroy(),e.read.destroy()}};var yu=(s,e)=>Math.ceil(s/e)*e,vu=s=>String(s>>>0),Ss=class{constructor(e,t={}){this.device=e,this.maxFreeBytes=t.maxFreeBytes??201326592,this.freeBytes=0,this.free=new Map,this.all=new Set}acquire(e,t,i="recycled-buffer"){let r=yu(Math.max(4,e),4),o=vu(t),n=this.free.get(o);if(n){let l=-1,c=1/0;for(let u=0;u<n.length;u+=1){let f=n[u];f.size>=r&&f.size<c&&(l=u,c=f.size)}if(l>=0){let[u]=n.splice(l,1);return this.freeBytes-=u.size,u.buffer}}let a=this.device.createBuffer({label:i,size:r,usage:t,mappedAtCreation:!1});return this.all.add(a),a}release(e,t,i){if(!e)return;let r=yu(Math.max(4,t),4);if(this.freeBytes+r>this.maxFreeBytes){e.destroy(),this.all.delete(e);return}let o=vu(i),n=this.free.get(o);n||(n=[],this.free.set(o,n)),n.push({buffer:e,size:r,usage:i}),this.freeBytes+=r}trim(e=this.maxFreeBytes){this.maxFreeBytes=e;for(let[t,i]of this.free.entries()){for(;this.freeBytes>this.maxFreeBytes&&i.length>0;){let r=i.pop();r.buffer.destroy(),this.all.delete(r.buffer),this.freeBytes-=r.size}i.length===0&&this.free.delete(t)}}destroy(){for(let e of this.all)e.destroy();this.free.clear(),this.all.clear(),this.freeBytes=0}};var xu=`const EPS : f32 = 1.0e-7;
5102
+
5103
+ struct Bullet {
5104
+ posLife: vec4<f32>,
5105
+ velRadius: vec4<f32>,
5106
+ seed: vec4<u32>,
5107
+ }
5108
+
5109
+ struct Triangle {
5110
+ a: vec4<f32>,
5111
+ b: vec4<f32>,
5112
+ c: vec4<f32>,
5113
+ }
5114
+
5115
+ struct Counters {
5116
+ hits: atomic<u32>,
5117
+ alive: atomic<u32>,
5118
+ _pad0: atomic<u32>,
5119
+ _pad1: atomic<u32>,
5120
+ }
5121
+
5122
+ struct Params {
5123
+ dt: f32,
5124
+ speed: f32,
5125
+ life: f32,
5126
+ bulletRadius: f32,
5127
+
5128
+ spawnRadius: f32,
5129
+ jitter: f32,
5130
+ targetCount: u32,
5131
+ triCount: u32,
5132
+
5133
+ frame: u32,
5134
+ dispatchWidth: u32,
5135
+ _pad1: u32,
5136
+ _pad2: u32,
5137
+ }
5138
+
5139
+ @group(0) @binding(0) var<storage, read_write> bullets : array<Bullet>;
5140
+ @group(0) @binding(1) var<storage, read> triangles : array<Triangle>;
5141
+ @group(0) @binding(2) var<storage, read_write> counters : Counters;
5142
+ @group(0) @binding(3) var<uniform> params : Params;
5143
+
5144
+ fn hashU32(xIn: u32) -> u32 {
5145
+ var x = xIn;
5146
+ x ^= x >> 16u;
5147
+ x *= 0x7feb352du;
5148
+ x ^= x >> 15u;
5149
+ x *= 0x846ca68bu;
5150
+ x ^= x >> 16u;
5151
+ return x;
5152
+ }
5153
+
5154
+ fn rand01(state: ptr<function, u32>) -> f32 {
5155
+ let h = hashU32((*state) + 0x9e3779b9u);
5156
+ *state = h;
5157
+ return f32(h) * 2.3283064365386963e-10;
5158
+ }
5159
+
5160
+ fn randSigned(state: ptr<function, u32>) -> f32 {
5161
+ return rand01(state) * 2.0 - 1.0;
5162
+ }
5163
+
5164
+ fn randomUnit(state: ptr<function, u32>) -> vec3<f32> {
5165
+ var v = vec3<f32>(1.0, 0.0, 0.0);
5166
+ var ok = false;
5167
+ for (var i = 0u; i < 12u; i += 1u) {
5168
+ let p = vec3<f32>(randSigned(state), randSigned(state), randSigned(state));
5169
+ let l2 = dot(p, p);
5170
+ if (!ok && l2 > 1.0e-5 && l2 <= 1.0) {
5171
+ v = p * inverseSqrt(l2);
5172
+ ok = true;
5173
+ }
5174
+ }
5175
+ return v;
5176
+ }
5177
+
5178
+ fn safeNormal(v: vec3<f32>) -> vec3<f32> {
5179
+ let l2 = dot(v, v);
5180
+ if (l2 > EPS) {
5181
+ return v * inverseSqrt(l2);
5182
+ }
5183
+ return vec3<f32>(1.0, 0.0, 0.0);
5184
+ }
5185
+
5186
+ fn makeBasis(dir: vec3<f32>) -> mat3x3<f32> {
5187
+ var helper = vec3<f32>(0.0, 1.0, 0.0);
5188
+ if (abs(dir.y) > 0.85) {
5189
+ helper = vec3<f32>(1.0, 0.0, 0.0);
5190
+ }
5191
+ let u = safeNormal(cross(helper, dir));
5192
+ let v = safeNormal(cross(dir, u));
5193
+ return mat3x3<f32>(u, v, dir);
5194
+ }
5195
+
5196
+ fn respawn(id: u32, frameSalt: u32) {
5197
+ var state = hashU32(id * 747796405u + frameSalt * 2891336453u + 0x68bc21ebu);
5198
+ let spawnDir = randomUnit(&state);
5199
+ let pos = spawnDir * params.spawnRadius;
5200
+ let jitter = randomUnit(&state) * params.jitter;
5201
+ let velDir = safeNormal(-pos + jitter);
5202
+ bullets[id].posLife = vec4<f32>(pos, params.life);
5203
+ bullets[id].velRadius = vec4<f32>(velDir * params.speed, params.bulletRadius);
5204
+ bullets[id].seed = vec4<u32>(state, frameSalt, id, 0u);
5205
+ }
5206
+
5207
+ fn rayTriHit(
5208
+ origin: vec3<f32>,
5209
+ dir: vec3<f32>,
5210
+ maxT: f32,
5211
+ a: vec3<f32>,
5212
+ b: vec3<f32>,
5213
+ c: vec3<f32>
5214
+ ) -> bool {
5215
+ let ab = b - a;
5216
+ let ac = c - a;
5217
+ let p = cross(dir, ac);
5218
+ let det = dot(ab, p);
5219
+ if (abs(det) < EPS) {
5220
+ return false;
5221
+ }
5222
+
5223
+ let invDet = 1.0 / det;
5224
+ let tvec = origin - a;
5225
+ let u = dot(tvec, p) * invDet;
5226
+ if (u < 0.0 || u > 1.0) {
5227
+ return false;
5228
+ }
5229
+
5230
+ let q = cross(tvec, ab);
5231
+ let v = dot(dir, q) * invDet;
5232
+ if (v < 0.0 || u + v > 1.0) {
5233
+ return false;
5234
+ }
5235
+
5236
+ let t = dot(ac, q) * invDet;
5237
+ return t >= 0.0 && t <= maxT;
5238
+ }
5239
+
5240
+ fn sweepTriangle(p0: vec3<f32>, p1: vec3<f32>, radius: f32, tri: Triangle) -> bool {
5241
+ let delta = p1 - p0;
5242
+ let len = length(delta);
5243
+ if (len < EPS) {
5244
+ return false;
5245
+ }
5246
+
5247
+ let dir = delta / len;
5248
+ let basis = makeBasis(dir);
5249
+ let u = basis[0] * radius * 0.85;
5250
+ let v = basis[1] * radius * 0.85;
5251
+ let maxT = len + radius * 2.75;
5252
+ let a = tri.a.xyz;
5253
+ let b = tri.b.xyz;
5254
+ let c = tri.c.xyz;
5255
+
5256
+ if (rayTriHit(p0, dir, maxT, a, b, c)) { return true; }
5257
+ if (rayTriHit(p0 + u, dir, maxT, a, b, c)) { return true; }
5258
+ if (rayTriHit(p0 - u, dir, maxT, a, b, c)) { return true; }
5259
+ if (rayTriHit(p0 + v, dir, maxT, a, b, c)) { return true; }
5260
+ if (rayTriHit(p0 - v, dir, maxT, a, b, c)) { return true; }
5261
+ return false;
5262
+ }
5263
+
5264
+ @compute @workgroup_size(128)
5265
+ fn collisionBenchmark(@builtin(global_invocation_id) gid: vec3<u32>) {
5266
+ let id = gid.x + gid.y * params.dispatchWidth;
5267
+ if (id >= params.targetCount) {
5268
+ if (id < arrayLength(&bullets)) {
5269
+ bullets[id].posLife.w = -1.0;
5270
+ }
5271
+ return;
5272
+ }
5273
+
5274
+ var b = bullets[id];
5275
+ if (b.posLife.w <= 0.0 || b.velRadius.w <= 0.0) {
5276
+ respawn(id, params.frame);
5277
+ atomicAdd(&counters.alive, 1u);
5278
+ return;
5279
+ }
5280
+
5281
+ let p0 = b.posLife.xyz;
5282
+ let p1 = p0 + b.velRadius.xyz * params.dt;
5283
+ var hit = false;
5284
+
5285
+ for (var triId = 0u; triId < params.triCount; triId += 1u) {
5286
+ if (!hit && sweepTriangle(p0, p1, b.velRadius.w, triangles[triId])) {
5287
+ hit = true;
5288
+ }
5289
+ }
5290
+
5291
+ if (hit) {
5292
+ atomicAdd(&counters.hits, 1u);
5293
+ respawn(id, params.frame + 97u);
5294
+ atomicAdd(&counters.alive, 1u);
5295
+ return;
5296
+ }
5297
+
5298
+ b.posLife = vec4<f32>(p1, b.posLife.w - params.dt);
5299
+ bullets[id] = b;
5300
+ atomicAdd(&counters.alive, 1u);
5301
+ }
5302
+ `;var yn=48,Ua=48,ks=16,Na=48,qa=class{constructor(e,t,i=3){this.device=e,this.recycler=t,this.slotCount=Math.max(2,i|0),this.usage=GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST,this.slots=[],this.cursor=0,this.latest={hits:0,alive:0};for(let r=0;r<this.slotCount;r+=1)this.slots.push({buffer:t.acquire(ks,this.usage,`collision-counter-readback-${r}`),pending:!1})}encodeCopy(e,t){let i=null;for(let r=0;r<this.slots.length;r+=1){let o=(this.cursor+r)%this.slots.length;if(!this.slots[o].pending){i=this.slots[o],this.cursor=(o+1)%this.slots.length;break}}return i?(i.pending=!0,e.copyBufferToBuffer(t,0,i.buffer,0,ks),i):null}resolve(e){return e?(e.buffer.mapAsync(GPUMapMode.READ).then(()=>{let t=new Uint32Array(e.buffer.getMappedRange(),0,4);this.latest={hits:t[0],alive:t[1]},e.buffer.unmap(),e.pending=!1}).catch(t=>{this.disposed||console.warn("Particle counter readback failed:",t),e.pending=!1}),this.latest):this.latest}destroy(){this.disposed=!0;for(let e of this.slots)e.pending||this.recycler.release(e.buffer,ks,this.usage);this.slots.length=0}},Va=class{constructor(e,{capacity:t,triangleCount:i,readback:r=!0}={}){let o=e.limits.maxComputeWorkgroupsPerDimension**2*128,n=Math.min(e.limits.maxStorageBufferBindingSize,e.limits.maxBufferSize);for(let[a,l,c]of[["capacity",t,yn],["triangleCount",i,Ua]])if(!Number.isSafeInteger(l)||l<1||l*c>n||a==="capacity"&&l>o)throw Error(`Invalid particle ${a}: exceeds GPU capacity or is not a positive integer`);this.device=e,this.timer=new Cs(e),this.capacity=t,this.triangleCount=i,this.frame=0,this.recycler=new Ss(e),this.storageUsage=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC,this.uniformUsage=GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,this.module=e.createShaderModule({label:"collision-benchmark-module",code:xu}),this.pipeline=e.createComputePipeline({label:"collision-benchmark-pipeline",layout:"auto",compute:{module:this.module,entryPoint:"collisionBenchmark"}}),this.particleBuffer=this.recycler.acquire(this.capacity*yn,this.storageUsage,"collision-bullets"),this.triangleBuffer=this.recycler.acquire(this.triangleCount*Ua,this.storageUsage,"collision-triangles"),this.counterBuffer=this.recycler.acquire(ks,this.storageUsage,"collision-counters"),this.paramBuffer=this.recycler.acquire(Na,this.uniformUsage,"collision-params"),this.params=new ArrayBuffer(Na),this.zeroCounters=new Uint32Array(4),this.readback=r?new qa(e,this.recycler,3):null,this.bindGroup=e.createBindGroup({label:"collision-benchmark-bg",layout:this.pipeline.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:this.particleBuffer}},{binding:1,resource:{buffer:this.triangleBuffer}},{binding:2,resource:{buffer:this.counterBuffer}},{binding:3,resource:{buffer:this.paramBuffer}}]}),this.clear()}clear(){if(this.disposed)throw Error("Particle system has been destroyed");let e=this.device.createCommandEncoder({label:"Clear surface particles"});e.clearBuffer(this.particleBuffer),this.device.queue.submit([e.finish()]),this.frame=0,this.readback&&(this.readback.latest={hits:0,alive:0})}writeTriangles(e){if(this.disposed)throw Error("Particle system has been destroyed");if(!(e instanceof Float32Array)||e.length!==this.triangleCount*12||!e.every(Number.isFinite))throw Error("Triangles require 12 finite float32 values per triangle: padded a, b, c vertices");this.device.queue.writeBuffer(this.triangleBuffer,0,e)}step(e){if(this.disposed)throw Error("Particle system has been destroyed");let t={speed:80,life:3,bulletRadius:.09,spawnRadius:32,jitter:4.8,...e,target:e.count??this.capacity,frame:e.frame??this.frame++};if(!Number.isSafeInteger(t.target)||t.target<1||t.target>this.capacity)throw Error("Particle count exceeds allocated capacity");for(let d of["dt","speed","life","bulletRadius","spawnRadius"])if(!Number.isFinite(t[d])||t[d]<=0)throw Error(`Particle ${d} must be positive and finite`);if(!Number.isFinite(t.jitter)||t.jitter<0)throw Error("Particle jitter must be nonnegative and finite");let i=new Float32Array(this.params),r=new Uint32Array(this.params);i.fill(0),i[0]=t.dt,i[1]=t.speed,i[2]=t.life,i[3]=t.bulletRadius,i[4]=t.spawnRadius,i[5]=t.jitter,r[6]=t.target>>>0,r[7]=this.triangleCount>>>0,r[8]=t.frame>>>0;let o=Math.ceil(t.target/128),n=Math.ceil(o/this.device.limits.maxComputeWorkgroupsPerDimension),a=Math.ceil(o/n);r[9]=a*128,this.device.queue.writeBuffer(this.paramBuffer,0,this.params),this.device.queue.writeBuffer(this.counterBuffer,0,this.zeroCounters);let l=this.device.createCommandEncoder({label:"collision-benchmark-encoder"}),c=this.timer.begin(),u=l.beginComputePass({label:"collision-benchmark-pass",...this.timer.descriptor(c)});u.setPipeline(this.pipeline),u.setBindGroup(0,this.bindGroup),u.dispatchWorkgroups(a,n),u.end(),this.timer.encode(l,c);let f=this.readback?.encodeCopy(l,this.counterBuffer);return this.device.queue.submit([l.finish()]),this.timer.resolve(c),this.readback?.resolve(f)??null}destroy(){this.disposed||(this.disposed=!0,this.timer.destroy(),this.readback?.destroy(),this.recycler.release(this.particleBuffer,this.capacity*yn,this.storageUsage),this.recycler.release(this.triangleBuffer,this.triangleCount*Ua,this.storageUsage),this.recycler.release(this.counterBuffer,ks,this.storageUsage),this.recycler.release(this.paramBuffer,Na,this.uniformUsage),this.recycler.destroy())}};var Au=`// Read the canonical solver's completed contact buffers directly. These layouts
5303
+ // match avbd3d/gpu/layout.ts; no contact data is copied to the CPU for this view.
5304
+ struct Body {pos:vec4f,rot:vec4f,initialPos:vec4f,initialRot:vec4f,size:vec4f,moment:vec4f,inertialPos:vec4f,inertialRot:vec4f,velocity:vec4f,angular:vec4f}
5305
+ struct Camera {vp:mat4x4f,eye:vec4f,light:vec4f}
5306
+ struct Manifold {ids:vec4u,geo:vec4f}
5307
+ struct Contact {rA:vec4f,rB:vec4f,pen:vec4f,lambda:vec4f}
5308
+ @group(0) @binding(0) var<storage,read> bodies:array<Body>;
5309
+ @group(0) @binding(1) var<uniform> camera:Camera;
5310
+ @group(0) @binding(2) var<storage,read> manifolds:array<Manifold>;
5311
+ @group(0) @binding(3) var<storage,read> contacts:array<Contact>;
5312
+ @group(0) @binding(4) var<storage,read> counters:array<u32>;
5313
+ const CORNERS=array<vec2f,6>(vec2f(-1,-1),vec2f(1,-1),vec2f(1,1),vec2f(-1,-1),vec2f(1,1),vec2f(-1,1));
5314
+ const MAX_MANIFOLDS=512u;
5315
+ fn rotate(q:vec4f,v:vec3f)->vec3f {let t=2.*cross(q.xyz,v);return v+q.w*t+cross(q.xyz,t);}
5316
+ @vertex fn vertexMain(@builtin(vertex_index) v:u32,@builtin(instance_index) instance:u32)->@builtin(position) vec4f {
5317
+ let hidden=vec4f(2,2,2,1);
5318
+ let count=min(counters[6],arrayLength(&manifolds));
5319
+ let slot=instance/4u;
5320
+ if(slot>=min(count,MAX_MANIFOLDS)){return hidden;}
5321
+ // Sample across the entire contact region when it exceeds the display budget.
5322
+ let index=select(slot,slot*count/MAX_MANIFOLDS,count>MAX_MANIFOLDS);
5323
+ let m=manifolds[index];let point=instance%4u;let k=m.ids.z+point;
5324
+ if(point>=(m.ids.w&15u)||k>=min(counters[1],arrayLength(&contacts))||m.ids.x>=arrayLength(&bodies)){return hidden;}
5325
+ let b=bodies[m.ids.x];let p=b.pos.xyz+rotate(b.rot,contacts[k].rA.xyz);
5326
+ var clip=camera.vp*vec4f(p.x,p.z,p.y,1);
5327
+ clip.x+=CORNERS[v].x*3./camera.light.x*clip.w;
5328
+ clip.y+=CORNERS[v].y*3./camera.light.y*clip.w;
5329
+ return clip;
5330
+ }
5331
+ @fragment fn fragmentMain()->@location(0) vec4f {return vec4f(.83,.25,.39,1);}
5332
+ `;var xd=Au.replace("@vertex fn vertexMain","fn samplePoint").replaceAll("@builtin(vertex_index) ","").replaceAll("@builtin(instance_index) ","").replace("->@builtin(position) vec4f","->vec4f").replace(/clip\.x\+=.*?;/,"").replace(/clip\.y\+=.*?;/,"")+`
5333
+ @group(0) @binding(5) var<storage,read_write> sampled:array<vec4f>;
5334
+ @compute @workgroup_size(64) fn gather(@builtin(global_invocation_id) id:vec3u) {
5335
+ if(id.x<arrayLength(&sampled)){sampled[id.x]=samplePoint(0u,id.x);}
5336
+ }`,Ad=`
5337
+ struct Camera {vp:mat4x4f,eye:vec4f,light:vec4f}
5338
+ @group(0) @binding(0) var<uniform> camera:Camera;
5339
+ @group(0) @binding(1) var<storage,read> points:array<vec4f>;
5340
+ const CORNERS=array<vec2f,6>(vec2f(-1,-1),vec2f(1,-1),vec2f(1,1),vec2f(-1,-1),vec2f(1,1),vec2f(-1,1));
5341
+ @vertex fn vertexMain(@builtin(vertex_index) v:u32,@builtin(instance_index) instance:u32)->@builtin(position) vec4f {
5342
+ var clip=points[instance];
5343
+ clip.x+=CORNERS[v].x*3./camera.light.x*clip.w;
5344
+ clip.y+=CORNERS[v].y*3./camera.light.y*clip.w;
5345
+ return clip;
5346
+ }
5347
+ @fragment fn fragmentMain()->@location(0) vec4f {return vec4f(.83,.25,.39,1);}
5348
+ `,Wa=class{constructor(e,{count:t=2048}={}){if(!Number.isSafeInteger(t)||t<1||Math.ceil(t/64)>e.limits.maxComputeWorkgroupsPerDimension)throw Error("Contact sample count exceeds GPU dispatch capacity");this.device=e,this.count=t,this.buffer=e.createBuffer({label:"AVBD sampled contact dots",size:this.count*16,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),this.pipeline=e.createComputePipeline({label:"AVBD contact overlay sampling",layout:"auto",compute:{module:e.createShaderModule({code:xd}),entryPoint:"gather"}}),this.bindings=[]}encode(e,{bodyBuffer:t,cameraBuffer:i,contactStorage:r}){let o=[t,i,r.manifolds,r.contacts,r.counters,this.buffer],n=this.bindings.find(l=>l.buffers.every((c,u)=>c===o[u]));n||(n={buffers:o,bind:this.device.createBindGroup({layout:this.pipeline.getBindGroupLayout(0),entries:o.map((l,c)=>({binding:c,resource:{buffer:l}}))})},this.bindings.push(n),this.bindings.length>2&&this.bindings.shift());let a=e.beginComputePass();a.setPipeline(this.pipeline),a.setBindGroup(0,n.bind),a.dispatchWorkgroups(Math.ceil(this.count/64)),a.end()}dispose(){this.buffer.destroy(),this.bindings.length=0}};function wd(s,e,t=8){let i=new Map(e.bodies.map((c,u)=>[c,u])),r=e.bodies.map(()=>new Set);for(let c of e.forces){let u=i.get(c.bodyA),f=i.get(c.bodyB);u===void 0||f===void 0||e.bodies[u].mass===0||e.bodies[f].mass===0||(r[u].add(f),r[f].add(u))}let o=e.bodies.map((c,u)=>u).filter(c=>e.bodies[c].mass>0).sort((c,u)=>r[u].size-r[c].size||c-u),n=new Uint32Array(s.bodyCapacity).fill(255),a=new Map,l=0;for(let c of o){let u=new Set([...r[c]].map(d=>a.get(d))),f=0;for(;u.has(f);)f++;if(f>=64)return;a.set(c,f),n[s.gpuIndex(c)]=f,l=Math.max(l,f+1)}s.device.queue.writeBuffer(s.colorBuffer,0,n),s.colorCap=Math.min(64,Math.max(t,l+3))}var Ha=new WeakMap;function Bd(s,{before:e,after:t}={}){if(!s.bodyBuffer||typeof s.step!="function")throw Error("GPU step passes require a WebGPU solver");if(!e&&!t||e!==void 0&&typeof e!="function"||t!==void 0&&typeof t!="function")throw Error("GPU step passes require synchronous before and/or after callbacks");let i=Ha.get(s);i||(i={hooks:new Set,previousBefore:s.externalBeforeStep,previousAfter:s.externalAfterStep},i.before=o=>{i.previousBefore?.call(s,o);for(let n of i.hooks)n.before?.(o,s)},i.after=o=>{i.previousAfter?.call(s,o);for(let n of i.hooks)n.after?.(o,s)},s.externalBeforeStep=i.before,s.externalAfterStep=i.after,Ha.set(s,i));let r={before:e,after:t};return i.hooks.add(r),()=>{i.hooks.delete(r)&&(i.hooks.size||(s.externalBeforeStep===i.before&&(s.externalBeforeStep=i.previousBefore),s.externalAfterStep===i.after&&(s.externalAfterStep=i.previousAfter),Ha.delete(s)))}}var $a=class{constructor(e,t,i){this.offscreenCanvas=e,this.events=new Map,this.resize(t,i)}resize(e,t){let i=Math.max(1,Math.floor(e)),r=Math.max(1,Math.floor(t));(i!==this.clientWidth||r!==this.clientHeight)&&(this.revision=(this.revision??0)+1),this.clientWidth=i,this.clientHeight=r}get width(){return this.offscreenCanvas.width}set width(e){this.offscreenCanvas.width=e}get height(){return this.offscreenCanvas.height}set height(e){this.offscreenCanvas.height=e}getContext(...e){return this.offscreenCanvas.getContext(...e)}getBoundingClientRect(){return{left:0,top:0,width:this.clientWidth,height:this.clientHeight}}addEventListener(e,t){this.events.has(e)||this.events.set(e,new Set),this.events.get(e).add(t)}removeEventListener(e,t){this.events.get(e)?.delete(t)}setPointerCapture(){}dispatch(e,t){let i={...t,preventDefault(){}};for(let r of this.events.get(e)??[])r(i)}};var Cd=9;function Sd(){return globalThis.crossOriginIsolated&&typeof SharedArrayBuffer=="function"?new Int32Array(new SharedArrayBuffer(36)):null}function kd(s,e,t=0){Atomics.add(s,0,1),[Math.round(e.clientX*1024),Math.round(e.clientY*1024),e.pointerId??1,e.buttons??0,e.altKey?1:0,e.shiftKey?1:0,e.ctrlKey?1:0,Math.round(t*1024)].forEach((r,o)=>Atomics.store(s,o+1,r)),Atomics.add(s,0,1)}function Pd(s,e=-1){let t=Atomics.load(s,0);if(t&1||t===e)return null;let i=Array.from({length:8},(r,o)=>Atomics.load(s,o+1));return Atomics.load(s,0)!==t?null:{sequence:t,event:{clientX:i[0]/1024,clientY:i[1]/1024,pointerId:i[2],buttons:i[3],altKey:!!i[4],shiftKey:!!i[5],ctrlKey:!!i[6]},wheel:i[7]/1024}}export{yo as AvbdPhysics,vo as AvbdPhysicsAggregate,fs as AvbdPhysicsBody,os as AvbdPhysicsConstraint,ns as AvbdPhysicsHinge,Fa as AvbdScene2D,Ga as AvbdScene3D,mt as AvbdShapeType,Ss as GPUBufferRecycler,Wa as GpuContactSample,Va as GpuSurfaceParticles,Cs as GpuTimer,Cd as INPUT_WORDS,yn as PARTICLE_BYTE_STRIDE,$a as WorkerCanvas,Bd as addGpuStepPass,ls as cookHeightfield,cs as cookStaticMesh,Sd as createSharedInput,bd as createSolverPipeline,ss as createWebGPUDevice,Cr as prepareWebGPUDevice3D,Pd as readSharedInput,Ad as sampledContactShader,wd as seedConstraintColoring,kd as writeSharedInput};