avbd-babylon 0.2.0 → 0.3.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.
@@ -1,4 +1,4 @@
1
- (()=>{var pl=Object.defineProperty;var ml=(o,e)=>{for(var t in e)pl(o,t,{get:e[t],enumerable:!0})};var Ys={};ml(Ys,{AvbdPhysics:()=>xr,AvbdPhysicsAggregate:()=>Ar,AvbdPhysicsBody:()=>Br,AvbdPhysicsConstraint:()=>$i,AvbdPhysicsHinge:()=>Xi,AvbdScene2D:()=>Xs,AvbdScene3D:()=>$s,AvbdShapeType:()=>Ue,createWebGPUDevice:()=>hs,prepareWebGPUDevice3D:()=>gr});var L=(o=0,e=0,t=0)=>Float64Array.of(o,e,t),Pi=(o=0,e=0,t=0,i=1)=>Float64Array.of(o,e,t,i),Y=()=>new Float64Array(9);var ua=o=>o<0?-1:o>0?1:0,tt=(o,e)=>o<e?o:e,bl=(o,e)=>o>e?o:e,Oe=(o,e,t)=>bl(e,tt(t,o)),Z=(o,e)=>o[0]*e[0]+o[1]*e[1]+o[2]*e[2],it=o=>Z(o,o),Li=o=>Math.sqrt(it(o));function He(o,e,t,i){return o[0]=e,o[1]=t,o[2]=i,o}var Mr=(o,e,t)=>He(o,e[0]+t[0],e[1]+t[1],e[2]+t[2]),X=(o,e,t)=>He(o,e[0]-t[0],e[1]-t[1],e[2]-t[2]),Ce=(o,e,t)=>He(o,e[0]*t,e[1]*t,e[2]*t),ei=(o,e,t)=>He(o,e[0]/t,e[1]/t,e[2]/t),he=(o,e)=>He(o,-e[0],-e[1],-e[2]),Qs=(o,e)=>He(o,Math.abs(e[0]),Math.abs(e[1]),Math.abs(e[2])),N=(o,e,t,i)=>He(o,e[0]+t[0]*i,e[1]+t[1]*i,e[2]+t[2]*i),gl=(o,e)=>ei(o,e,Li(e)),Mt=(o,e,t)=>He(o,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 ki(o,e,t,i,r){return o[0]=e,o[1]=t,o[2]=i,o[3]=r,o}function fa(o,e,t){let i=e[0],r=e[1],s=e[2],a=e[3],n=t[0],l=t[1],c=t[2],f=t[3];return ki(o,a*n+i*f+r*c-s*l,a*l-i*c+r*f+s*n,a*c+i*l-r*n+s*f,a*f-i*n-r*l-s*c)}var yl=(o,e)=>ki(o,-e[0],-e[1],-e[2],e[3]),da=o=>it(o)+o[3]*o[3];function vl(o,e){let t=da(e);return ki(o,-e[0]/t,-e[1]/t,-e[2]/t,e[3]/t)}function xl(o,e){let t=Math.sqrt(da(e));return ki(o,e[0]/t,e[1]/t,e[2]/t,e[3]/t)}var Si=new Float64Array(4),Zt=new Float64Array(4);function It(o,e,t){return fa(Si,e,vl(Si,t)),He(o,Si[0]*2,Si[1]*2,Si[2]*2)}function Ir(o,e,t){return ki(Zt,t[0],t[1],t[2],0),fa(Zt,Zt,e),xl(o,ki(o,e[0]+Zt[0]*.5,e[1]+Zt[1]*.5,e[2]+Zt[2]*.5,e[3]+Zt[3]*.5))}function ue(o,e,t){let i=e[0],r=e[1],s=e[2],a=e[3],n=(r*t[2]-s*t[1])*2,l=(s*t[0]-i*t[2])*2,c=(i*t[1]-r*t[0])*2;return He(o,t[0]+n*a+(r*c-s*l),t[1]+l*a+(s*n-i*c),t[2]+c*a+(i*l-r*n))}var ca=new Float64Array(3);function ht(o,e,t,i){return ue(ca,t,i),Mr(o,ca,e)}function _i(o,e,t){return ue(o,yl(Si,e),t)}function je(o,e,t,i){return o.fill(0),o[0]=e,o[4]=t,o[8]=i,o}function Ks(o,e){return o[0]=0,o[1]=-e[2],o[2]=e[1],o[3]=e[2],o[4]=0,o[5]=-e[0],o[6]=-e[1],o[7]=e[0],o[8]=0,o}function ti(o,e){let t=e[1],i=e[2],r=e[5];return o[0]=e[0],o[1]=e[3],o[2]=e[6],o[3]=t,o[4]=e[4],o[5]=e[7],o[6]=i,o[7]=r,o[8]=e[8],o}function Te(o,e,t){let i=e[0],r=e[1],s=e[2],a=e[3],n=e[4],l=e[5],c=e[6],f=e[7],u=e[8],d=t[0],p=t[1],m=t[2],h=t[3],b=t[4],y=t[5],v=t[6],w=t[7],g=t[8];return o[0]=i*d+r*h+s*v,o[1]=i*p+r*b+s*w,o[2]=i*m+r*y+s*g,o[3]=a*d+n*h+l*v,o[4]=a*p+n*b+l*w,o[5]=a*m+n*y+l*g,o[6]=c*d+f*h+u*v,o[7]=c*p+f*b+u*w,o[8]=c*m+f*y+u*g,o}function ie(o,e,t){let i=t[0],r=t[1],s=t[2];return He(o,e[0]*i+e[1]*r+e[2]*s,e[3]*i+e[4]*r+e[5]*s,e[6]*i+e[7]*r+e[8]*s)}function Se(o,e){for(let t=0;t<9;t++)o[t]+=e[t];return o}function ii(o,e,t){for(let i=0;i<9;i++)o[i]=e[i]*t;return o}function ha(o,e){for(let t=0;t<9;t++)o[t]=-e[t];return o}function Rr(o,e,t){for(let i=0;i<3;i++)for(let r=0;r<3;r++)o[i*3+r]=t[r]*e[i];return o}function pa(o,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 je(o,t,i,r)}function ma(o,e){let t=Math.abs(e[0])>Math.abs(e[2])?L(-e[1],e[0],0):L(0,-e[2],e[1]);gl(t,t);let i=Mt(L(),e,t);return o[0]=e[0],o[1]=e[1],o[2]=e[2],o.set(t,3),o.set(i,6),o}function ba(o,e,t,i,r,s,a){let n=o[0],l=o[3],c=o[4],f=o[6],u=o[7],d=o[8],p=t[0],m=t[1],h=t[2],b=e[0],y=t[3],v=t[4],w=t[5],g=e[3],A=e[4],x=t[6],B=t[7],E=t[8],k=e[6],z=e[7],M=e[8],P=l/n,_=f/n,C=p/n,S=y/n,R=x/n,I=n,O=c-P*P*I,q=(u-P*_*I)/O,G=(m-P*C*I)/O,j=(v-P*S*I)/O,F=(B-P*R*I)/O,H=d-(_*_*I+q*q*O),ee=(h-_*C*I-q*G*O)/H,le=(w-_*S*I-q*j*O)/H,xe=(E-_*R*I-q*F*O)/H,U=b-(C*C*I+G*G*O+ee*ee*H),ze=(g-C*S*I-G*j*O-ee*le*H)/U,Me=(k-C*R*I-G*F*O-ee*xe*H)/U,ce=A-(S*S*I+j*j*O+le*le*H+ze*ze*U),qe=(z-S*R*I-j*F*O-le*xe*H-ze*Me*U)/ce,zt=M-(R*R*I+F*F*O+xe*xe*H+Me*Me*U+qe*qe*ce),Ie=i[0],Ve=i[1]-P*Ie,Re=i[2]-_*Ie-q*Ve,We=r[0]-C*Ie-G*Ve-ee*Re,et=r[1]-S*Ie-j*Ve-le*Re-ze*We,Ai=r[2]-R*Ie-F*Ve-xe*Re-Me*We-qe*et,Bi=Ie/I,wi=Ve/O,Ci=Re/H,At=We/U,dl=et/ce,hl=Ai/zt;a[2]=hl,a[1]=dl-qe*a[2],a[0]=At-ze*a[1]-Me*a[2],s[2]=Ci-ee*a[0]-le*a[1]-xe*a[2],s[1]=wi-q*s[2]-G*a[0]-j*a[1]-F*a[2],s[0]=Bi-P*s[1]-_*s[2]-C*a[0]-S*a[1]-R*a[2]}var or=1,pt=1e10,ga=.01,ya=1e-5,De=class{solver;forces=[];positionLin;positionAng=Pi();initialLin=L();initialAng=Pi();inertialLin=L();inertialAng=Pi();velocityLin;velocityAng=L();prevVelocityLin;size;mass;moment;friction;radius;constructor(e,t,i,r,s,a=[0,0,0]){this.solver=e,this.size=L(t[0],t[1],t[2]),this.friction=r,this.positionLin=L(s[0],s[1],s[2]),this.velocityLin=L(a[0],a[1],a[2]),this.prevVelocityLin=L(a[0],a[1],a[2]);let[n,l,c]=this.size;this.mass=n*l*c*i,this.moment=L((l*l+c*c)/12*this.mass,(n*n+c*c)/12*this.mass,(n*n+l*l)/12*this.mass),this.radius=Li([n*.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}},va=()=>({lhsLin:Y(),lhsAng:Y(),lhsCross:Y(),rhsLin:L(),rhsAng:L()}),Rt=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,xa=16,si=1e-6,eo=1e-5,Al=1e-6,to=34028234663852886e22,Or=0,Sa=1,jr=2;function Aa(o){let e=o.positionAng;return{center:o.positionLin,half:Ce(L(),o.size,.5),axis:[ue(L(),e,[1,0,0]),ue(L(),e,[0,1,0]),ue(L(),e,[0,0,1])]}}var ri=(o,e)=>Math.abs(Z(o,e));function Tr(o,e){let t=Z(e,o.axis[0])>=0?1:-1,i=Z(e,o.axis[1])>=0?1:-1,r=Z(e,o.axis[2])>=0?1:-1,s=N(L(),o.center,o.axis[0],o.half[0]*t);return N(s,s,o.axis[1],o.half[1]*i),N(s,s,o.axis[2],o.half[2]*r)}function ka(o,e){return e===0?{u:o.axis[1],v:o.axis[2],extentU:o.half[1],extentV:o.half[2]}:e===1?{u:o.axis[0],v:o.axis[2],extentU:o.half[0],extentV:o.half[2]}:{u:o.axis[0],v:o.axis[1],extentU:o.half[0],extentV:o.half[1]}}function Bl(o,e,t){let i=Z(t,o.axis[e])>=0?1:-1,r=Ce(L(),o.axis[e],i),s=N(L(),o.center,r,o.half[e]);return{normal:r,center:s,...ka(o,e)}}function wl(o,e){let t=0,i=-to;for(let r=0;r<3;r++){let s=ri(o.axis[r],e);s>i&&(i=s,t=r)}return t}function Cl(o,e,t){let i=Z(o.axis[e],t)>0?-1:1,r=Ce(L(),o.axis[e],i),s=N(L(),o.center,r,o.half[e]),{u:a,v:n,extentU:l,extentV:c}=ka(o,e),f=(u,d)=>{let p=N(L(),s,a,u*l);return N(p,p,n,d*c)};return[f(1,1),f(-1,1),f(-1,-1),f(1,-1)]}function Sl(o,e,t){let i=[];if(o.length===0)return i;let r=o[o.length-1],s=Z(e,r)-t;for(let a of o){let n=Z(e,a)-t,l=s<=eo,c=n<=eo;if(l!==c){let f=0,u=s-n;Math.abs(u)>si&&(f=Oe(s/u,0,1)),i.length<xa&&i.push(N(L(),r,X(L(),a,r),f))}c&&i.length<xa&&i.push(a),r=a,s=n}return i}var Dr=class{contacts=[];midpoints=[];bodyA;bodyB;constructor(e,t){this.bodyA=e,this.bodyB=t}add(e,t,i){let r=Ce(L(),Mr(L(),e,t),.5);for(let n of this.midpoints)if(it(X(L(),r,n))<Al)return;if(this.contacts.length>=Ca)return;let{bodyA:s,bodyB:a}=this;this.contacts.push({feature:i,rA:_i(L(),s.positionAng,X(L(),e,s.positionLin)),rB:_i(L(),a.positionAng,X(L(),t,a.positionLin))}),this.midpoints.push(r)}};function Zs(o,e,t,i,r,s,a,n){let l=it(i);if(l<si)return!0;let c=1/Math.sqrt(l),f=Ce(L(),i,c);Z(f,t)<0&&he(f,f);let u=Math.abs(Z(t,f)),d=o.half[0]*ri(f,o.axis[0])+o.half[1]*ri(f,o.axis[1])+o.half[2]*ri(f,o.axis[2]),p=e.half[0]*ri(f,e.axis[0])+e.half[1]*ri(f,e.axis[1])+e.half[2]*ri(f,e.axis[2]),m=u-(d+p);return m>0?!1:((!n.valid||m>n.separation)&&(n.valid=!0,n.type=r,n.indexA=s,n.indexB=a,n.separation=m,n.normalAB=f),!0)}function Ba(o,e,t){let i=(e+1)%3,r=(e+2)%3,s=Z(t,o.axis[i])>=0?1:-1,a=Z(t,o.axis[r])>=0?1:-1,n=N(L(),o.center,o.axis[i],o.half[i]*s);N(n,n,o.axis[r],o.half[r]*a);let l=Ce(L(),o.axis[e],o.half[e]);return[X(L(),n,l),Mr(L(),n,l)]}function kl(o,e,t,i){let r=X(L(),e,o),s=X(L(),i,t),a=X(L(),o,t),n=Z(r,r),l=Z(s,s),c=Z(s,a),f=0,u=0;if(n<=si&&l<=si)return[o,t];if(n<=si)u=Oe(c/l,0,1);else{let d=Z(r,a);if(l<=si)f=Oe(-d/n,0,1);else{let p=Z(r,s),m=n*l-p*p;Math.abs(m)>si&&(f=Oe((p*c-d*l)/m,0,1)),u=(p*f+c)/l,u<0?(u=0,f=Oe(-d/n,0,1)):u>1&&(u=1,f=Oe((p-d)/n,0,1))}}return[N(L(),o,r,f),N(L(),t,s,u)]}function wa(o,e,t,i,r,s,a){let n=r?t:i,l=r?i:t,c=r?a:he(L(),a),f=Bl(n,s,c),u=wl(l,f.normal),d=Cl(l,u,f.normal),p=[[f.u,f.extentU],[he(L(),f.u),f.extentU],[f.v,f.extentV],[he(L(),f.v),f.extentV]];for(let[b,y]of p)if(d=Sl(d,b,Z(b,f.center)+y),!d.length)return[];let m=new Dr(o,e),h=(r?Or:Sa)<<24|(s&255)<<16|(u&255)<<8;for(let b=0;b<d.length&&m.contacts.length<Ca;b++){let y=d[b],v=Z(X(L(),y,f.center),f.normal);if(v>eo)continue;let w=N(L(),y,f.normal,-v),g=r?w:y,A=r?y:w;m.add(g,A,h|b&255)}return m.contacts.length||m.add(Tr(t,a),Tr(i,he(L(),a)),h),m.contacts}function Pl(o,e,t,i,r,s,a){let[n,l]=Ba(t,r,a),[c,f]=Ba(i,s,he(L(),a)),[u,d]=kl(n,l,c,f),p=new Dr(o,e),m=jr<<24|(r&255)<<8|s&255;return p.add(u,d,m),p.contacts.length||p.add(Tr(t,a),Tr(i,he(L(),a)),m),p.contacts}function Pa(o,e,t){let i=Aa(o),r=Aa(e),s=X(L(),r.center,i.center),a={type:Or,indexA:0,indexB:0,separation:-to,normalAB:L(),valid:!1},n={type:jr,indexA:0,indexB:0,separation:-to,normalAB:L(),valid:!1};for(let f=0;f<3;f++)if(!Zs(i,r,s,i.axis[f],Or,f,-1,a))return[];for(let f=0;f<3;f++)if(!Zs(i,r,s,r.axis[f],Sa,-1,f,a))return[];let l=L();for(let f=0;f<3;f++)for(let u=0;u<3;u++)if(Mt(l,i.axis[f],r.axis[u]),!Zs(i,r,s,l,jr,f,u,n))return[];if(!a.valid)return[];let c=a;return n.valid&&.95*n.separation>a.separation+.01&&(c=n),ma(t,he(L(),c.normalAB)),c.type===jr?Pl(o,e,i,r,c.indexA,c.indexB,c.normalAB):c.type===Or?wa(o,e,i,r,!0,c.indexA,c.normalAB):wa(o,e,i,r,!1,c.indexB,c.normalAB)}var La=L(),_a=L(),Ea=L(),za=L(),Ma=L(),Ia=L(),Gr=Y(),io=Y(),ro=Y(),Fr=Y(),so=Y(),oo=Y(),ao=Y(),Ur=Y(),pe=L(),Ae=L(),oi=L(),Ot=L(),Ra=L(),Oa=L(),Ei=0,ar=0;function ja(o,e,t){for(let i=0;i<3;i++)Ot[0]=t[i*3],Ot[1]=t[i*3+1],Ot[2]=t[i*3+2],Mt(Ot,e,Ot),o[i*3]=Ot[0],o[i*3+1]=Ot[1],o[i*3+2]=Ot[2];return o}var zi=class extends Rt{contacts=[];basis=Y();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(s=>{let a=r.find(n=>n.feature===s.feature);return a?{feature:s.feature,rA:a.stick?a.rA:s.rA,rB:a.stick?a.rB:s.rB,C0:L(),penalty:a.penalty.slice(),lambda:a.lambda.slice(),stick:a.stick}:{feature:s.feature,rA:s.rA,rB:s.rB,C0:L(),penalty:L(),lambda:L(),stick:!1}});for(let s of this.contacts){ht(Ra,e.positionLin,e.positionAng,s.rA),ht(Oa,t.positionLin,t.positionAng,s.rB),ie(s.C0,this.basis,X(oi,Ra,Oa)),s.C0[0]+=ga;for(let a=0;a<3;a++)s.lambda[a]=s.lambda[a]*i.alpha*i.gamma,s.penalty[a]=Oe(s.penalty[a]*i.gamma,or,pt)}return this.contacts.length>0}evaluate(e,t){let i=this.bodyA,r=this.bodyB,s=this.basis;ue(Ma,i.positionAng,e.rA),ue(Ia,r.positionAng,e.rB),ha(Gr,s),ja(io,Ma,s),ja(ro,Ia,Gr),je(Fr,e.penalty[0],e.penalty[1],e.penalty[2]),Ce(pe,e.C0,1-t),N(pe,pe,ie(oi,s,La),1),N(pe,pe,ie(oi,Gr,Ea),1),N(pe,pe,ie(oi,io,_a),1),N(pe,pe,ie(oi,ro,za),1),ie(Ae,Fr,pe),N(Ae,Ae,e.lambda,1),Ae[0]=tt(Ae[0],0),ar=Math.abs(Ae[0])*this.friction,Ei=Math.sqrt(Ae[1]*Ae[1]+Ae[2]*Ae[2]),Ei>ar&&Ei>0&&(Ae[1]*=ar/Ei,Ae[2]*=ar/Ei)}computeDisplacements(){let e=this.bodyA,t=this.bodyB;X(La,e.positionLin,e.initialLin),It(_a,e.positionAng,e.initialAng),X(Ea,t.positionLin,t.initialLin),It(za,t.positionAng,t.initialAng)}updatePrimal(e,t,i){this.computeDisplacements();let r=e===this.bodyA;for(let s of this.contacts){this.evaluate(s,t);let a=r?this.basis:Gr,n=r?io:ro;ti(so,a),ti(oo,n),Te(ao,oo,Fr),Se(i.lhsLin,Te(Ur,Te(Ur,so,Fr),a)),Se(i.lhsAng,Te(Ur,ao,n)),Se(i.lhsCross,Te(Ur,ao,a)),N(i.rhsLin,i.rhsLin,ie(oi,so,Ae),1),N(i.rhsAng,i.rhsAng,ie(oi,oo,Ae),1)}}updateDual(e){let{solver:t}=this;this.computeDisplacements();for(let i of this.contacts)this.evaluate(i,e),i.lambda.set(Ae),Ae[0]<0&&(i.penalty[0]=tt(i.penalty[0]+t.betaLin*Math.abs(pe[0]),pt)),Ei<=ar&&(i.penalty[1]=tt(i.penalty[1]+t.betaLin*Math.abs(pe[1]),pt),i.penalty[2]=tt(i.penalty[2]+t.betaLin*Math.abs(pe[2]),pt),i.stick=Math.sqrt(pe[1]*pe[1]+pe[2]*pe[2])<ya)}};var no=()=>({dt:1/60,gravity:-10,iterations:10,betaLin:1e4,betaAng:100,alpha:.99,gamma:.999}),jt=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,no())}clear(){this.forces=[],this.bodies=[]}pick(e,t){let r=null,s=L(),a=L();for(let n=this.bodies.length-1;n>=0;n--){let l=this.bodies[n];if(l.mass<=0)continue;_i(s,l.positionAng,X(s,e,l.positionLin)),_i(a,l.positionAng,t);let c=0,f=1/0,u=!0;for(let p=0;p<3&&u;p++){let m=l.size[p]*.5;if(Math.abs(a[p])<1e-6){(s[p]<-m||s[p]>m)&&(u=!1);continue}let h=1/a[p],b=(-m-s[p])*h,y=(m-s[p])*h;b>y&&([b,y]=[y,b]),c=Math.max(c,b),f=Math.min(f,y),c>f&&(u=!1)}if(!u)continue;let d=c>=0?c:f;d<0||(!r||d<r.t)&&(r={body:l,local:N(L(),s,a,d),t:d})}return r}sys=va();dxLin=L();dxAng=L();dp=L();accel=L();step(){let{dt:e,gravity:t,bodies:i,sys:r,dp:s}=this;for(let n=i.length-1;n>=0;n--){let l=i[n];for(let c=n-1;c>=0;c--){let f=i[c];X(s,l.positionLin,f.positionLin);let u=l.radius+f.radius;Z(s,s)<=u*u&&!l.constrainedTo(f)&&new zi(this,l,f)}}let a=[];for(let n of this.forces)n.initialize()?a.push(n):n.unlinkFromBodies();this.forces=a;for(let n=i.length-1;n>=0;n--){let l=i[n];N(l.inertialLin,l.positionLin,l.velocityLin,e),l.mass>0&&(l.inertialLin[2]+=t*(e*e)),Ir(l.inertialAng,l.positionAng,Ta(l.velocityAng,e)),ei(this.accel,X(this.accel,l.velocityLin,l.prevVelocityLin),e);let c=this.accel[2]*ua(t),f=Oe(c/Math.abs(t),0,1);Number.isFinite(f)||(f=0),l.initialLin.set(l.positionLin),l.initialAng.set(l.positionAng),l.mass>0&&(N(l.positionLin,l.positionLin,l.velocityLin,e),l.positionLin[2]+=t*(f*e*e),Ir(l.positionAng,l.positionAng,Ta(l.velocityAng,e)))}for(let n=0;n<this.iterations;n++){for(let l=i.length-1;l>=0;l--){let c=i[l];if(c.mass<=0)continue;let f=c.mass,u=c.moment;je(r.lhsLin,f/(e*e),f/(e*e),f/(e*e)),je(r.lhsAng,u[0]/(e*e),u[1]/(e*e),u[2]/(e*e)),r.lhsCross.fill(0),ie(r.rhsLin,r.lhsLin,X(s,c.positionLin,c.inertialLin)),ie(r.rhsAng,r.lhsAng,It(s,c.positionAng,c.inertialAng));let d=c.forces;for(let p=d.length-1;p>=0;p--)d[p].updatePrimal(c,this.alpha,r);ba(r.lhsLin,r.lhsAng,r.lhsCross,he(r.rhsLin,r.rhsLin),he(r.rhsAng,r.rhsAng),this.dxLin,this.dxAng),N(c.positionLin,c.positionLin,this.dxLin,1),Ir(c.positionAng,c.positionAng,this.dxAng)}for(let l of this.forces)l.updateDual(this.alpha)}for(let n of i)n.prevVelocityLin.set(n.velocityLin),n.mass>0&&(ei(n.velocityLin,X(n.velocityLin,n.positionLin,n.initialLin),e),ei(n.velocityAng,It(n.velocityAng,n.positionAng,n.initialAng),e))}},Ll=L(),Ta=(o,e)=>Ce(Ll,o,e);var oe=(o,e)=>[o[0]-e[0],o[1]-e[1],o[2]-e[2]],nt=(o,e)=>o[0]*e[0]+o[1]*e[1]+o[2]*e[2],ai=(o,e)=>[o[1]*e[2]-o[2]*e[1],o[2]*e[0]-o[0]*e[2],o[0]*e[1]-o[1]*e[0]],Ge=o=>Math.sqrt(nt(o,o));function nr(o){let e=Da(o);return!e||e.vertices.length/3<=32?e:Da(_l(e,32))}function _l(o,e){let[t,i,r,s]=o.rotation,a=u=>{let d=[2*(i*u[2]-r*u[1]),2*(r*u[0]-t*u[2]),2*(t*u[1]-i*u[0])];return[u[0]+s*d[0]+(i*d[2]-r*d[1])+o.center[0],u[1]+s*d[1]+(r*d[0]-t*d[2])+o.center[1],u[2]+s*d[2]+(t*d[1]-i*d[0])+o.center[2]]},n=[];for(let u=0;u<o.vertices.length;u+=3)n.push(a([o.vertices[u],o.vertices[u+1],o.vertices[u+2]]));let l=0;n.forEach((u,d)=>{Ge(oe(u,o.center))>Ge(oe(n[l],o.center))&&(l=d)});let c=[l],f=n.map(u=>Ge(oe(u,n[l])));for(;c.length<e;){let u=0;f.forEach((d,p)=>{d>f[u]&&(u=p)}),c.push(u),n.forEach((d,p)=>{f[p]=Math.min(f[p],Ge(oe(d,n[u])))})}return c.flatMap(u=>n[u])}function Da(o){let e=0;for(let g=0;g<o.length;g++)e=Math.max(e,Math.abs(o[g]));let t=Math.max(e,1e-9)*1e-6,i=new Set,r=[];for(let g=0;g+2<o.length;g+=3){let A=[o[g],o[g+1],o[g+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 s=Math.max(e,1e-9)*1e-10,a=0;for(let g=1;g<r.length;g++)r[g][0]<r[a][0]&&(a=g);let n=-1,l=0;for(let g=0;g<r.length;g++){let A=Ge(oe(r[g],r[a]));A>l&&(l=A,n=g)}if(n<0||l<s)return null;let c=-1;l=0;let f=oe(r[n],r[a]);for(let g=0;g<r.length;g++){let A=Ge(ai(f,oe(r[g],r[a])));A>l&&(l=A,c=g)}if(c<0||l<s*Ge(f))return null;let u=ai(f,oe(r[c],r[a])),d=-1;l=0;for(let g=0;g<r.length;g++){let A=Math.abs(nt(u,oe(r[g],r[a])));A>l&&(l=A,d=g)}if(d<0||l<s*Ge(u))return null;let p=[],m=(g,A,x)=>{let B=ai(oe(r[A],r[g]),oe(r[x],r[g])),E=Ge(B)||1,k=[B[0]/E,B[1]/E,B[2]/E];return{v:[g,A,x],n:k,d:nt(k,r[g])}},b=nt(u,oe(r[d],r[a]))>0?[a,c,n]:[a,n,c];p.push(m(b[0],b[1],b[2])),p.push(m(b[0],d,b[1])),p.push(m(b[1],d,b[2])),p.push(m(b[2],d,b[0]));let y=new Set([a,n,c,d]),v=r.map((g,A)=>A).filter(g=>!y.has(g)),w=[a,n,c,d].reduce((g,A)=>[g[0]+r[A][0]/4,g[1]+r[A][1]/4,g[2]+r[A][2]/4],[0,0,0]);v.sort((g,A)=>Ge(oe(r[A],w))-Ge(oe(r[g],w)));for(let g of v){let A=p.filter(P=>nt(P.n,r[g])-P.d>s);if(!A.length)continue;let x=new Map;for(let P of p)for(let _=0;_<3;_++)x.set(`${P.v[_]},${P.v[(_+1)%3]}`,P);let B=new Set(A),E=[...A];for(;E.length;){let P=E.pop();for(let _=0;_<3;_++){let C=x.get(`${P.v[(_+1)%3]},${P.v[_]}`);C&&!B.has(C)&&nt(C.n,r[g])-C.d>-s&&(B.add(C),E.push(C))}}let k=[...B],z=new Set;for(let P of k)for(let _=0;_<3;_++)z.add(`${P.v[_]},${P.v[(_+1)%3]}`);let M=[];for(let P of k)for(let _=0;_<3;_++){let C=P.v[_],S=P.v[(_+1)%3];z.has(`${S},${C}`)||M.push([C,S])}for(let P of k)p.splice(p.indexOf(P),1);for(let[P,_]of M)p.push(m(P,_,g))}return El(r.flat(),p.flatMap(g=>g.v))}function El(o,e){let t=[];for(let C=0;C+2<o.length;C+=3)t.push([o[C],o[C+1],o[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,s=[];for(let C=0;C+2<e.length;C+=3){let S=[e[C],e[C+1],e[C+2]],R=ai(oe(t[S[1]],t[S[0]]),oe(t[S[2]],t[S[0]])),I=Ge(R);if(!(I>0))continue;let O=[R[0]/I,R[1]/I,R[2]/I];s.push({v:S,n:O,d:nt(O,t[S[0]])})}let a=new Map;s.forEach((C,S)=>{for(let R=0;R<3;R++)a.set(`${C.v[R]},${C.v[(R+1)%3]}`,S)});let n=new Array(s.length).fill(-1),l=[];s.forEach((C,S)=>{if(n[S]>=0)return;let R=[S];n[S]=l.length;for(let I=0;I<R.length;I++){let O=s[R[I]];for(let q=0;q<3;q++){let G=a.get(`${O.v[(q+1)%3]},${O.v[q]}`);if(G===void 0||n[G]>=0)continue;let j=s[G];nt(C.n,j.n)>1-1e-5&&j.v.every(F=>Math.abs(nt(C.n,t[F])-C.d)<=r)&&(n[G]=l.length,R.push(G))}}l.push(R)});let c=[];for(let C of l){let S=new Set;for(let j of C)for(let F=0;F<3;F++)S.add(`${s[j].v[F]},${s[j].v[(F+1)%3]}`);let R=new Map;for(let j of C)for(let F=0;F<3;F++){let H=s[j].v[F],ee=s[j].v[(F+1)%3];if(!S.has(`${ee},${H}`)){if(R.has(H))return null;R.set(H,ee)}}let I=[0,0,0];for(let j of C){let F=s[j],H=ai(oe(t[F.v[1]],t[F.v[0]]),oe(t[F.v[2]],t[F.v[0]]));I[0]+=H[0],I[1]+=H[1],I[2]+=H[2]}let O=Ge(I)||1,q=R.keys().next().value,G=[q];for(let j=R.get(q);j!==q&&G.length<=R.size;j=R.get(j))G.push(j);if(G.length!==R.size)return null;c.push({n:[I[0]/O,I[1]/O,I[2]/O],verts:G})}let f=new Map,u=[];for(let C of c)for(let S of C.verts)f.has(S)||(f.set(S,u.length),u.push(t[S]));for(let C of c)C.verts=C.verts.map(S=>f.get(S));let d=new Set,p=0;for(let C of c)C.verts.forEach((S,R)=>{d.add(`${S},${C.verts[(R+1)%C.verts.length]}`),p++});if(d.size!==p||![...d].every(C=>{let[S,R]=C.split(",");return d.has(`${R},${S}`)})||u.length-d.size/2+c.length!==2)return null;let m=0,h=[0,0,0],b=[0,0,0,0,0,0];for(let C of c){let S=u[C.verts[0]];for(let R=1;R+1<C.verts.length;R++){let I=u[C.verts[R]],O=u[C.verts[R+1]],q=nt(S,ai(I,O));m+=q/6;for(let j=0;j<3;j++)h[j]+=q/24*(S[j]+I[j]+O[j]);let G=(j,F)=>q/120*(S[j]*S[F]+I[j]*I[F]+O[j]*O[F]+(S[j]+I[j]+O[j])*(S[F]+I[F]+O[F]));b[0]+=G(0,0),b[1]+=G(1,1),b[2]+=G(2,2),b[3]+=G(0,1),b[4]+=G(0,2),b[5]+=G(1,2)}}if(!(m>0))return null;for(let C=0;C<3;C++)h[C]/=m;b[0]-=m*h[0]*h[0],b[1]-=m*h[1]*h[1],b[2]-=m*h[2]*h[2],b[3]-=m*h[0]*h[1],b[4]-=m*h[0]*h[2],b[5]-=m*h[1]*h[2];let y=b[0]+b[1]+b[2],v=[[y-b[0],-b[3],-b[4]],[-b[3],y-b[1],-b[5]],[-b[4],-b[5],y-b[2]]],{values:w,vectors:g}=zl(v),A=g,x=C=>{let S=oe(C,h);return[A[0][0]*S[0]+A[1][0]*S[1]+A[2][0]*S[2],A[0][1]*S[0]+A[1][1]*S[1]+A[2][1]*S[2],A[0][2]*S[0]+A[1][2]*S[1]+A[2][2]*S[2]]},B=u.map(x),E=new Float32Array(B.flat()),k=c.map(C=>{let S=C.n,R=[A[0][0]*S[0]+A[1][0]*S[1]+A[2][0]*S[2],A[0][1]*S[0]+A[1][1]*S[1]+A[2][1]*S[2],A[0][2]*S[0]+A[1][2]*S[1]+A[2][2]*S[2]],I=-1/0;for(let O of C.verts)I=Math.max(I,nt(R,B[O]));return{normal:R,d:I,verts:C.verts}}),z=new Map;k.forEach((C,S)=>C.verts.forEach((R,I)=>z.set(`${R},${C.verts[(I+1)%C.verts.length]}`,S)));let M=[];k.forEach((C,S)=>C.verts.forEach((R,I)=>{let O=C.verts[(I+1)%C.verts.length],q=z.get(`${O},${R}`);R<O&&q!==void 0&&M.push([R,O,S,q])}));let P=[0,0,0],_=0;for(let C of B){for(let S=0;S<3;S++)P[S]=Math.max(P[S],2*Math.abs(C[S]));_=Math.max(_,Ge(C))}return{vertices:E,faces:k,edges:M,volume:m,moments:[w[0],w[1],w[2]],size:P,radius:_,center:h,rotation:Ml(A)}}function zl(o){let e=o.map(n=>[...n]),t=[[1,0,0],[0,1,0],[0,0,1]];for(let n=0;n<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));n++)for(let c=0;c<3;c++)for(let f=c+1;f<3;f++){if(Math.abs(e[c][f])<1e-300)continue;let u=(e[f][f]-e[c][c])/(2*e[c][f]),d=Math.sign(u||1)/(Math.abs(u)+Math.sqrt(u*u+1)),p=1/Math.sqrt(d*d+1),m=d*p;for(let h=0;h<3;h++){let b=e[h][c],y=e[h][f];e[h][c]=p*b-m*y,e[h][f]=m*b+p*y}for(let h=0;h<3;h++){let b=e[c][h],y=e[f][h];e[c][h]=p*b-m*y,e[f][h]=m*b+p*y}for(let h=0;h<3;h++){let b=t[h][c],y=t[h][f];t[h][c]=p*b-m*y,t[h][f]=m*b+p*y}}let i=[t[0][0],t[1][0],t[2][0]],r=[t[0][1],t[1][1],t[2][1]],s=ai(i,r),a=[[i[0],r[0],s[0]],[i[1],r[1],s[1]],[i[2],r[2],s[2]]];return{values:[e[0][0],e[1][1],e[2][2]],vectors:a}}function Ml(o){let e=o[0][0]+o[1][1]+o[2][2],t,i,r,s;if(e>0){let n=.5/Math.sqrt(e+1);s=.25/n,t=(o[2][1]-o[1][2])*n,i=(o[0][2]-o[2][0])*n,r=(o[1][0]-o[0][1])*n}else if(o[0][0]>o[1][1]&&o[0][0]>o[2][2]){let n=2*Math.sqrt(1+o[0][0]-o[1][1]-o[2][2]);s=(o[2][1]-o[1][2])/n,t=.25*n,i=(o[0][1]+o[1][0])/n,r=(o[0][2]+o[2][0])/n}else if(o[1][1]>o[2][2]){let n=2*Math.sqrt(1+o[1][1]-o[0][0]-o[2][2]);s=(o[0][2]-o[2][0])/n,t=(o[0][1]+o[1][0])/n,i=.25*n,r=(o[1][2]+o[2][1])/n}else{let n=2*Math.sqrt(1+o[2][2]-o[0][0]-o[1][1]);s=(o[1][0]-o[0][1])/n,t=(o[0][2]+o[2][0])/n,i=(o[1][2]+o[2][1])/n,r=.25*n}let a=Math.hypot(t,i,r,s);return[t/a,i/a,r/a,s/a]}var Fa=new WeakSet,lr=o=>Fa.has(o),Il=new WeakSet;var Ua=o=>Il.has(o);function Mi(o,e,t,i,r,s=[0,0,0]){let a=new De(o,[2*e,2*e,2*e],t,i,r,s);a.mass=t>0?4/3*Math.PI*e*e*e*t:0;let n=.4*a.mass*e*e;return a.moment.set([n,n,n]),a.radius=e,Fa.add(a),a}var Na=new WeakMap,Nr=o=>Na.get(o);function qr(o,e,t,i,r,s=[0,0,0,1],a=[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 n=new De(o,e.size,t,i,r,a);return n.positionAng.set([s[0],s[1],s[2],s[3]]),n.mass=t>0?e.volume*t:0,n.moment.set(e.moments.map(l=>l*Math.max(t,0))),n.radius=e.radius,Na.set(n,e),n}var lo=`
1
+ (()=>{var Ec=Object.defineProperty;var Mc=(s,e)=>{for(var t in e)Ec(s,t,{get:e[t],enumerable:!0})};var Qo={};Mc(Qo,{AvbdPhysics:()=>Kr,AvbdPhysicsAggregate:()=>Zr,AvbdPhysicsBody:()=>es,AvbdPhysicsConstraint:()=>Cr,AvbdPhysicsHinge:()=>Sr,AvbdScene2D:()=>Yo,AvbdScene3D:()=>Xo,AvbdShapeType:()=>it,createSolverPipeline:()=>Sc,createWebGPUDevice:()=>wr,prepareWebGPUDevice3D:()=>Ni});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 hs=s=>s<0?-1:s>0?1:0,xt=(s,e)=>s<e?s:e,zc=(s,e)=>s>e?s:e,ce=(s,e,t)=>zc(e,xt(t,s)),V=(s,e)=>s[0]*e[0]+s[1]*e[1]+s[2]*e[2],Ge=s=>V(s,s),rr=s=>Math.sqrt(Ge(s));function lt(s,e,t,i){return s[0]=e,s[1]=t,s[2]=i,s}var ki=(s,e,t)=>lt(s,e[0]+t[0],e[1]+t[1],e[2]+t[2]),$=(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]),Ko=(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),Ic=(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 Dr(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 Rc=(s,e)=>ir(s,-e[0],-e[1],-e[2],e[3]),ba=s=>Ge(s)+s[3]*s[3];function Zo(s,e){let t=ba(e);return ir(s,-e[0]/t,-e[1]/t,-e[2]/t,e[3]/t)}function Oc(s,e){let t=Math.sqrt(ba(e));return ir(s,e[0]/t,e[1]/t,e[2]/t,e[3]/t)}var tr=new Float64Array(4),Si=new Float64Array(4);function ct(s,e,t){return Dr(tr,e,Zo(tr,t)),lt(s,tr[0]*2,tr[1]*2,tr[2]*2)}function ri(s,e,t){return ir(Si,t[0],t[1],t[2],0),Dr(Si,Si,e),Oc(s,ir(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 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 ga=new Float64Array(3);function Ft(s,e,t,i){return ae(ga,t,i),ki(s,ga,e)}function Te(s,e,t){return ae(s,Rc(tr,e),t)}function Ce(s,e,t,i){return s.fill(0),s[0]=e,s[4]=t,s[8]=i,s}function en(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 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 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 ya(s,e){for(let t=0;t<9;t++)s[t]=-e[t];return s}function ps(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 va(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 ms(s,e){let t=Math.abs(e[0])>Math.abs(e[2])?C(-e[1],e[0],0):C(0,-e[2],e[1]);Ic(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 gs(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),ot=(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+ot*ot*Be),Ye=i[0],nt=i[1]-_*Ye,Qe=i[2]-k*Ye-X*nt,at=r[0]-S*Ye-W*nt-he*Qe,At=r[1]-P*Ye-N*nt-we*Qe-$e*at,Qi=r[2]-I*Ye-H*nt-Oe*Qe-Xe*at-ot*At,Ki=Ye/R,Zi=nt/F,er=Qe/Z,Wt=at/J,Lc=At/Be,_c=Qi/ii;n[2]=_c,n[1]=Lc-ot*n[2],n[0]=Wt-$e*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]-N*n[1]-H*n[2],o[0]=Ki-_*o[1]-k*o[2]-S*n[0]-P*n[1]-I*n[2]}var Et=1,Ue=1e10,bs=.01,Aa=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=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}},ys=()=>({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 Sa=8,xa=16,Ei=1e-6,rn=1e-5,Tc=1e-6,sn=34028234663852886e22,vs=0,ka=1,As=2;function wa(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 xs(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 Pa(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 jc(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,...Pa(s,e)}}function Dc(s,e){let t=0,i=-sn;for(let r=0;r<3;r++){let o=_i(s.axis[r],e);o>i&&(i=o,t=r)}return t}function Fc(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}=Pa(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 Gc(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<=rn,c=a<=rn;if(l!==c){let u=0,f=o-a;Math.abs(f)>Ei&&(u=ce(o/f,0,1)),i.length<xa&&i.push(D(C(),r,$(C(),n,r),u))}c&&i.length<xa&&i.push(n),r=n,o=a}return i}var ws=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))<Tc)return;if(this.contacts.length>=Sa)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 tn(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 Ba(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 Nc(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 Ca(s,e,t,i,r,o,n){let a=r?t:i,l=r?i:t,c=r?n:ee(C(),n),u=jc(a,o,c),f=Dc(l,u.normal),d=Fc(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=Gc(d,m,V(m,u.center)+b),!d.length)return[];let g=new ws(s,e),h=(r?vs:ka)<<24|(o&255)<<16|(f&255)<<8;for(let m=0;m<d.length&&g.contacts.length<Sa;m++){let b=d[m],v=V($(C(),b,u.center),u.normal);if(v>rn)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(xs(t,n),xs(i,ee(C(),n)),h),g.contacts}function Uc(s,e,t,i,r,o,n){let[a,l]=Ba(t,r,n),[c,u]=Ba(i,o,ee(C(),n)),[f,d]=Nc(a,l,c,u),p=new ws(s,e),g=As<<24|(r&255)<<8|o&255;return p.add(f,d,g),p.contacts.length||p.add(xs(t,n),xs(i,ee(C(),n)),g),p.contacts}function La(s,e,t){let i=wa(s),r=wa(e),o=$(C(),r.center,i.center),n={type:vs,indexA:0,indexB:0,separation:-sn,normalAB:C(),valid:!1},a={type:As,indexA:0,indexB:0,separation:-sn,normalAB:C(),valid:!1};for(let u=0;u<3;u++)if(!tn(i,r,o,i.axis[u],vs,u,-1,n))return[];for(let u=0;u<3;u++)if(!tn(i,r,o,r.axis[u],ka,-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]),!tn(i,r,o,l,As,u,f,a))return[];if(!n.valid)return[];let c=n;return a.valid&&.95*a.separation>n.separation+.01&&(c=a),ms(t,ee(C(),c.normalAB)),c.type===As?Uc(s,e,i,r,c.indexA,c.indexB,c.normalAB):c.type===vs?Ca(s,e,i,r,!0,c.indexA,c.normalAB):Ca(s,e,i,r,!1,c.indexB,c.normalAB)}var _a=C(),Ea=C(),Ma=C(),za=C(),Ia=C(),Ra=C(),Bs=oe(),on=oe(),nn=oe(),Cs=oe(),an=oe(),ln=oe(),cn=oe(),Ss=oe(),Ee=C(),je=C(),Mi=C(),si=C(),Oa=C(),Ta=C(),sr=0,Fr=0;function ja(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=La(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(Oa,e.positionLin,e.positionAng,o.rA),Ft(Ta,t.positionLin,t.positionAng,o.rB),ue(o.C0,this.basis,$(Mi,Oa,Ta)),o.C0[0]+=bs;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(Ia,i.positionAng,e.rA),ae(Ra,r.positionAng,e.rB),ya(Bs,o),ja(on,Ia,o),ja(nn,Ra,Bs),Ce(Cs,e.penalty[0],e.penalty[1],e.penalty[2]),ne(Ee,e.C0,1-t),D(Ee,Ee,ue(Mi,o,_a),1),D(Ee,Ee,ue(Mi,Bs,Ma),1),D(Ee,Ee,ue(Mi,on,Ea),1),D(Ee,Ee,ue(Mi,nn,za),1),ue(je,Cs,Ee),D(je,je,e.lambda,1),je[0]=xt(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;$(_a,e.positionLin,e.initialLin),ct(Ea,e.positionAng,e.initialAng),$(Ma,t.positionLin,t.initialLin),ct(za,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:Bs,a=r?on:nn;Pi(an,n),Pi(ln,a),Ke(cn,ln,Cs),Ne(i.lhsLin,Ke(Ss,Ke(Ss,an,Cs),n)),Ne(i.lhsAng,Ke(Ss,cn,a)),Ne(i.lhsCross,Ke(Ss,cn,n)),D(i.rhsLin,i.rhsLin,ue(Mi,an,je),1),D(i.rhsAng,i.rhsAng,ue(Mi,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]=xt(i.penalty[0]+t.betaLin*Math.abs(Ee[0]),Ue)),sr<=Fr&&(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])<Aa)}};var un=()=>({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,un())}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=ys();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,Da(l.velocityAng,e)),_t(this.accel,$(this.accel,l.velocityLin,l.prevVelocityLin),e);let c=this.accel[2]*hs(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,Da(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,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);gs(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,ct(a.velocityAng,a.positionAng,a.initialAng),e))}},qc=C(),Da=(s,e)=>ne(qc,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 Gr(s){let e=Fa(s);return!e||e.vertices.length/3<=32?e:Fa(Vc(e,32))}function Vc(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 Fa(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 Wc(r.flat(),p.flatMap(y=>y.v))}function Wc(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}=Hc(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:Jc(A)}}function Hc(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 Jc(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 Na=new WeakSet,De=s=>Na.has(s),$c=new WeakSet;var or=s=>$c.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,Na.add(n),n}var Ua=new WeakMap,wt=s=>Ua.get(s);function ks(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,Ua.set(a,e),a}var fn=`
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
- `,mt=`
41
+ `,Nt=`
42
42
  // Shared by every 2D module (layout.ts)
43
- ${lo}
43
+ ${fn}
44
44
  const T_JOINT = 1;
45
45
  const T_SPRING = 2;
46
46
  const T_MOTOR = 3;
@@ -148,8 +148,8 @@ 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
- `,co=(o,e={counter:"C_CONTACTS",prevCounter:"C_PREV_CONTACTS",capacity:"params.contactCapacity"})=>`
152
- ${o}
151
+ `,dn=(s,e={counter:"C_CONTACTS",prevCounter:"C_PREV_CONTACTS",capacity:"params.contactCapacity"})=>`
152
+ ${s}
153
153
  ${e.colorThreads??"fn colorThreads(bodies: u32) -> u32 { return bodies; }"}
154
154
 
155
155
  @group(0) @binding(0) var<uniform> params: Params;
@@ -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
- `,Vr=co(mt),fe=["collision","adjacency","coloring","solve"];var Rl=`
188
+ `,Ps=dn(Nt),Se=["collision","adjacency","coloring","solve"];var Xc=`
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
- `,Fe=class{levels=[];buffers=[];scanPipeline;addPipeline;constructor(e,t,i,r){let s=e.createShaderModule({label:"prefix scan",code:Rl}),a=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"}}]}),n=e.createPipelineLayout({bindGroupLayouts:[a]});this.scanPipeline=e.createComputePipeline({label:"scanBlocks",layout:n,compute:{module:s,entryPoint:"scanBlocks"}}),this.addPipeline=e.createComputePipeline({label:"addBlocks",layout:n,compute:{module:s,entryPoint:"addBlocks"}});let l=t,c=i,f=r;for(;;){let u=Math.max(1,Math.ceil(f/512)),d=e.createBuffer({label:`scan sums ${this.levels.length}`,size:Math.max(u,4)*4,usage:GPUBufferUsage.STORAGE}),p=e.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});new Uint32Array(p.getMappedRange()).set([c,f,0,0]),p.unmap(),this.buffers.push(d,p);let m=e.createBindGroup({layout:a,entries:[{binding:0,resource:{buffer:p}},{binding:1,resource:{buffer:l}},{binding:2,resource:{buffer:d}}]});if(this.levels.push({n:f,blocks:u,group:m}),u===1)break;l=d,c=0,f=u}}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 Ol=`
236
+ `,tt=class{levels=[];buffers=[];scanPipeline;addPipeline;constructor(e,t,i,r){let o=e.createShaderModule({label:"prefix scan",code:Xc}),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 Yc=`
237
237
  alias TopoItem = Contact;
238
238
 
239
239
  fn topoCount() -> u32 {
@@ -254,8 +254,8 @@ 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
- `,li=(o,e)=>`
258
- ${o}
257
+ `,Ri=(s,e)=>`
258
+ ${s}
259
259
  ${e}
260
260
 
261
261
  @group(0) @binding(0) var<uniform> params: Params;
@@ -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
- `,cr=li(mt,Ol);var jl=Pi(),lt=Y(),Wr=Y(),ci=Y(),uo=Y(),Ii=Y(),fo=Y(),Je=Y(),Hr=Y(),ur=Y(),re=L(),me=L(),se=L(),Tt=L(),Ri=L();function ho(o,e,t){return je(o,-t[e],-t[e],-t[e]),o[e]+=t[0],o[3+e]+=t[1],o[6+e]+=t[2],o}var Jr=(o,e,t)=>He(o,tt(e[0],t),tt(e[1],t),tt(e[2],t)),Be=class extends Rt{rA;rB;C0Lin=L();C0Ang=L();penaltyLin=L();penaltyAng=L();lambdaLin=L();lambdaAng=L();stiffnessLin;stiffnessAng;fracture;torqueArm;broken=!1;constructor(e,t,i,r,s,a=1/0,n=0,l=1/0){super(e,t,i),this.rA=L(r[0],r[1],r[2]),this.rB=L(s[0],s[1],s[2]),this.stiffnessLin=a,this.stiffnessAng=n,this.fracture=l;let c=t?t.size:[0,0,0];this.torqueArm=it([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?ht(Tt,t.positionLin,t.positionAng,this.rA):Tt.set(this.rA),X(e,Tt,ht(Ri,i.positionLin,i.positionAng,this.rB))}evaluateAng(e){return It(e,this.bodyA?this.bodyA.positionAng:jl,this.bodyB.positionAng),Ce(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]=Oe(this.penaltyLin[t]*e.gamma,or,pt),this.penaltyAng[t]=Oe(this.penaltyAng[t]*e.gamma,or,pt);return Jr(this.penaltyLin,this.penaltyLin,this.stiffnessLin),Jr(this.penaltyAng,this.penaltyAng,this.stiffnessAng),!this.broken}updatePrimal(e,t,i){let r=e===this.bodyA;if(it(this.penaltyLin)>0){je(lt,this.penaltyLin[0],this.penaltyLin[1],this.penaltyLin[2]),this.evaluateLin(re),this.stiffnessLin===1/0&&N(re,re,this.C0Lin,-t),ie(me,lt,re),N(me,me,this.lambdaLin,1);let s=r?1:-1;je(Wr,s,s,s),r?Ks(ci,he(se,ue(se,this.bodyA.positionAng,this.rA))):Ks(ci,ue(se,this.bodyB.positionAng,this.rB)),ti(uo,Wr),ti(Ii,ci),Te(fo,Ii,lt),Se(i.lhsLin,Te(Je,Te(Je,uo,lt),Wr)),Se(i.lhsAng,Te(Je,fo,ci)),Se(i.lhsCross,Te(Je,fo,Wr)),r?ue(se,this.bodyA.positionAng,this.rA):he(se,ue(se,this.bodyB.positionAng,this.rB)),ii(Hr,ho(ur,0,se),me[0]),Se(Hr,ii(ur,ho(ur,1,se),me[1])),Se(Hr,ii(ur,ho(ur,2,se),me[2])),Se(i.lhsAng,pa(Je,Hr)),N(i.rhsLin,i.rhsLin,ie(se,uo,me),1),N(i.rhsAng,i.rhsAng,ie(se,Ii,me),1)}if(it(this.penaltyAng)>0){je(lt,this.penaltyAng[0],this.penaltyAng[1],this.penaltyAng[2]),this.evaluateAng(re),this.stiffnessAng===1/0&&N(re,re,this.C0Ang,-t),ie(me,lt,re),N(me,me,this.lambdaAng,1);let s=(r?1:-1)*this.torqueArm;je(ci,s,s,s),ti(Ii,ci),Se(i.lhsAng,Te(Je,Te(Je,Ii,lt),ci)),N(i.rhsAng,i.rhsAng,ie(se,Ii,me),1)}}updateDual(e){let{solver:t}=this;it(this.penaltyLin)>0&&(je(lt,this.penaltyLin[0],this.penaltyLin[1],this.penaltyLin[2]),this.evaluateLin(re),this.stiffnessLin===1/0&&(N(re,re,this.C0Lin,-e),ie(me,lt,re),N(this.lambdaLin,me,this.lambdaLin,1)),N(this.penaltyLin,this.penaltyLin,Qs(se,re),t.betaLin),Jr(this.penaltyLin,this.penaltyLin,tt(this.stiffnessLin,pt))),it(this.penaltyAng)>0&&(je(lt,this.penaltyAng[0],this.penaltyAng[1],this.penaltyAng[2]),this.evaluateAng(re),this.stiffnessAng===1/0&&(N(re,re,this.C0Ang,-e),ie(me,lt,re),N(this.lambdaAng,me,this.lambdaAng,1)),N(this.penaltyAng,this.penaltyAng,Qs(se,re),t.betaAng),Jr(this.penaltyAng,this.penaltyAng,tt(this.stiffnessAng,pt))),it(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)}},ct=class extends Rt{rA;rB;rest;stiffness;constructor(e,t,i,r,s,a,n=-1){super(e,t,i),this.rA=L(r[0],r[1],r[2]),this.rB=L(s[0],s[1],s[2]),this.stiffness=a,this.rest=n,this.rest<0&&(ht(Tt,t.positionLin,t.positionAng,this.rA),ht(Ri,i.positionLin,i.positionAng,this.rB),this.rest=Li(X(re,Tt,Ri)))}initialize(){return!0}updatePrimal(e,t,i){let r=this.bodyA,s=this.bodyB;ht(Tt,r.positionLin,r.positionAng,this.rA),ht(Ri,s.positionLin,s.positionAng,this.rB);let a=X(re,Tt,Ri),n=Li(a);if(n<=1e-6)return;let l=ei(me,a,n),c=n-this.rest,f=this.stiffness*c,u=Tt,d=Ri;e===r?(ue(se,r.positionAng,this.rA),u.set(l),Mt(d,se,l)):(ue(se,s.positionAng,this.rB),he(u,l),he(d,Mt(d,se,l))),Se(i.lhsLin,ii(Je,Rr(Je,u,u),this.stiffness)),Se(i.lhsAng,ii(Je,Rr(Je,d,d),this.stiffness)),Se(i.lhsCross,ii(Je,Rr(Je,d,u),this.stiffness)),N(i.rhsLin,i.rhsLin,Ce(se,u,f),1),N(i.rhsAng,i.rhsAng,Ce(se,d,f),1)}updateDual(){}},$r=class extends Rt{initialize(){return!0}updatePrimal(){}updateDual(){}};var ke=40,Oi=0,fr=4,qa=8,Va=12,po=16,mo=20,Wa=24,Ha=28,bo=32,go=36,te=32,Dt=0,dr=4,ji=8,Ti=12,Ja=16,$a=20,Gt=24,Di=28,bt=8;var Xr=4,Bt=16,Gi=0,Yr=4,Qr=8,Kr=12,hr=2147483648,Fi=6,Tl=7,Xa=0,yo=1,vo=2,Zr=3,pr=1,Ui=2,xo=1,Ao=2,Bo=4,wo=8,Co=16,Dl=.1,Ya=.002,Qa=.002,Gl=.05,So=44,ae=`
535
+ `,Nr=Ri(Nt,Yc);var Qc=jt(),zt=oe(),Ls=oe(),Oi=oe(),hn=oe(),ar=oe(),pn=oe(),ut=oe(),_s=oe(),Ur=oe(),be=C(),Me=C(),ye=C(),ai=C(),lr=C();function mn(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 Es=(s,e,t)=>lt(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(lr,i.positionLin,i.positionAng,this.rB))}evaluateAng(e){return ct(e,this.bodyA?this.bodyA.positionAng:Qc,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 Es(this.penaltyLin,this.penaltyLin,this.stiffnessLin),Es(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(Ls,o,o,o),r?en(Oi,ee(ye,ae(ye,this.bodyA.positionAng,this.rA))):en(Oi,ae(ye,this.bodyB.positionAng,this.rB)),Pi(hn,Ls),Pi(ar,Oi),Ke(pn,ar,zt),Ne(i.lhsLin,Ke(ut,Ke(ut,hn,zt),Ls)),Ne(i.lhsAng,Ke(ut,pn,Oi)),Ne(i.lhsCross,Ke(ut,pn,Ls)),r?ae(ye,this.bodyA.positionAng,this.rA):ee(ye,ae(ye,this.bodyB.positionAng,this.rB)),Li(_s,mn(Ur,0,ye),Me[0]),Ne(_s,Li(Ur,mn(Ur,1,ye),Me[1])),Ne(_s,Li(Ur,mn(Ur,2,ye),Me[2])),Ne(i.lhsAng,va(ut,_s)),D(i.rhsLin,i.rhsLin,ue(ye,hn,Me),1),D(i.rhsAng,i.rhsAng,ue(ye,ar,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(ar,Oi),Ne(i.lhsAng,Ke(ut,Ke(ut,ar,zt),Oi)),D(i.rhsAng,i.rhsAng,ue(ye,ar,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,Ko(ye,be),t.betaLin),Es(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,Ko(ye,be),t.betaAng),Es(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)}},ft=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(lr,i.positionLin,i.positionAng,this.rB),this.rest=rr($(be,ai,lr)))}initialize(){return!0}updatePrimal(e,t,i){let r=this.bodyA,o=this.bodyB;Ft(ai,r.positionLin,r.positionAng,this.rA),Ft(lr,o.positionLin,o.positionAng,this.rB);let n=$(be,ai,lr),a=rr(n);if(a<=1e-6)return;let l=_t(Me,n,a),c=a-this.rest,u=this.stiffness*c,f=ai,d=lr;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(ut,ps(ut,f,f),this.stiffness)),Ne(i.lhsAng,Li(ut,ps(ut,d,d),this.stiffness)),Ne(i.lhsCross,Li(ut,ps(ut,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(){}},Ms=class extends Gt{initialize(){return!0}updatePrimal(){}updateDual(){}};var qe=40,cr=0,qr=4,qa=8,Va=12,gn=16,bn=20,Wa=24,Ha=28,yn=32,vn=36,pe=32,li=0,Vr=4,ur=8,fr=12,Ja=16,$a=20,ci=24,dr=28,Ut=8;var zs=4,Ht=16,hr=0,Is=4,Rs=8,Os=12,Wr=2147483648,pr=6,Kc=7,Xa=0,An=1,xn=2,Ts=3,Hr=1,mr=2,wn=1,Bn=2,Cn=4,Sn=8,kn=16,Zc=.1,Ya=.002,Qa=.002,eu=.05,Pn=44,Ae=`
536
536
  // Shared by every 3D module (avbd3d/gpu/layout.ts)
537
- ${lo}
538
- const T_JOINT = ${pr};
539
- const T_SPRING = ${Ui};
537
+ ${fn}
538
+ const T_JOINT = ${Hr};
539
+ const T_SPRING = ${mr};
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 = ${yo}.0;
549
- const SHAPE_SAIL = ${vo}.0;
550
- const SHAPE_HULL = ${Zr}.0;
551
- const STICK_BIT = ${hr}u;
552
- const C_MANIFOLDS = ${Fi}u;
553
- const C_PREV_MANIFOLDS = ${Tl}u;
548
+ const SHAPE_SPHERE = ${An}.0;
549
+ const SHAPE_SAIL = ${xn}.0;
550
+ const SHAPE_HULL = ${Ts}.0;
551
+ const STICK_BIT = ${Wr}u;
552
+ const C_MANIFOLDS = ${pr}u;
553
+ const C_PREV_MANIFOLDS = ${Kc}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 = ${xo}u;
558
- const FLAG_FACE_BIAS = ${Ao}u;
559
- const FLAG_REUSE_CONTACTS = ${Bo}u;
560
- const FLAG_START_AT_REST = ${wo}u;
561
- const FLAG_MASS_PENALTY = ${Co}u;
562
- const REST_SPEED = ${Dl};
563
- const NEAREST_FRACTION = ${Gl};
557
+ const FLAG_MATCH_NEAREST = ${wn}u;
558
+ const FLAG_FACE_BIAS = ${Bn}u;
559
+ const FLAG_REUSE_CONTACTS = ${Cn}u;
560
+ const FLAG_START_AT_REST = ${Sn}u;
561
+ const FLAG_MASS_PENALTY = ${kn}u;
562
+ const REST_SPEED = ${Zc};
563
+ const NEAREST_FRACTION = ${eu};
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
- `,Ni=`
681
+ `,gr=`
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
- `,ko=`
702
+ `,Ln=`
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
- `,Ka={counter:"C_MANIFOLDS",prevCounter:"C_PREV_MANIFOLDS",capacity:"params.manifoldCapacity",colorThreads:ko};var Za=`
714
+ `,Ka={counter:"C_MANIFOLDS",prevCounter:"C_PREV_MANIFOLDS",capacity:"params.manifoldCapacity",colorThreads:Ln};var Za=`
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 es=`
1099
- ${ae}
1098
+ `;var js=`
1099
+ ${Ae}
1100
1100
 
1101
1101
  struct RefPose {
1102
1102
  pos: vec4f,
@@ -1123,8 +1123,8 @@ fn updateRefs(@builtin(global_invocation_id) gid: vec3u) {
1123
1123
  bodies[i].inertialPos.w = bitcast<f32>(params.step);
1124
1124
  }
1125
1125
  }
1126
- `,Ft=`
1127
- ${ae}
1126
+ `,ui=`
1127
+ ${Ae}
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
- `,ui=o=>`
1335
- ${ae}
1334
+ `,Ti=s=>`
1335
+ ${Ae}
1336
1336
 
1337
1337
  @group(0) @binding(0) var<uniform> params: Params;
1338
1338
  @group(0) @binding(1) var<storage, read> bodies: array<Body>;
@@ -1343,7 +1343,7 @@ ${ae}
1343
1343
  @group(0) @binding(6) var<storage, read> prevManifolds: array<Manifold>;
1344
1344
  @group(0) @binding(7) var<storage, read_write> table: array<atomic<u32>>;
1345
1345
  @group(0) @binding(8) var<storage, read_write> counters: array<atomic<u32>>;
1346
- ${o?"@group(0) @binding(9) var<storage, read> hulls: array<vec4u>;":""}
1346
+ ${s?"@group(0) @binding(9) var<storage, read> hulls: array<vec4u>;":""}
1347
1347
 
1348
1348
  fn pairHash(a: u32, b: u32) -> u32 {
1349
1349
  return hash32((a * 0x9e3779b1u) ^ hash32(b));
@@ -1747,7 +1747,7 @@ fn reuseContacts(a: u32, b: u32) -> bool {
1747
1747
  return true;
1748
1748
  }
1749
1749
 
1750
- ${o?Za:"fn isHull(i: u32) -> bool { return false; }"}
1750
+ ${s?Za:"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) {
@@ -1764,7 +1764,7 @@ fn narrowphase(@builtin(global_invocation_id) gid: vec3u) {
1764
1764
  let sphereB = bodies[b].angVel.w == SHAPE_SPHERE;
1765
1765
  if (sphereA && sphereB) {
1766
1766
  found = sphereSphere(A, B, &sat);
1767
- }${o?` else if (isHull(a) || isHull(b)) {
1767
+ }${s?` else if (isHull(a) || isHull(b)) {
1768
1768
  if (sphereA || sphereB) {
1769
1769
  // sat.n points from A towards B
1770
1770
  if (sphereA) {
@@ -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
- `,en=ui(!1),tn=ui(!0);var be=`
1880
- ${ae}
1881
- ${ko}
1879
+ `,el=Ti(!1),tl=Ti(!0);var ze=`
1880
+ ${Ae}
1881
+ ${Ln}
1882
1882
 
1883
1883
  // Per-dispatch constants, selected with a dynamic uniform offset
1884
1884
  struct PassConstants {
@@ -2418,36 +2418,36 @@ fn updateVelocities(@builtin(global_invocation_id) gid: vec3u) {
2418
2418
  bodies[i].vel.w = prevUp;
2419
2419
  }
2420
2420
  }
2421
- `;function ts(o,e){let t=0,i=o.length-1;for(;t<i;){let r=o[e],s=t,a=i;do{for(;o[s]<r;)s++;for(;r<o[a];)a--;if(s<=a){let n=o[s];o[s]=o[a],o[a]=n,s++,a--}}while(s<=a);a<e&&(t=s),e<s&&(i=a)}return o[e]}function Po(o){let e=o.length,t=e>0?ts(o,e>>1):1,i=0;for(let r=0;r<e;r++)o[r]<=2*t&&(i=Math.max(i,o[r]));return e>64&&(i=Math.max(i,ts(o,e-64-1))),i}var wt=o=>o===1/0?3e38:o===-1/0?-3e38:o,$e=o=>Math.ceil(o/64),sn=o=>2**Math.ceil(Math.log2(Math.max(o,2))),Fl=o=>Math.max(o,1)*ke*4,Ul=8,is=3,Nl=8,ql=1.6,Vl=.8,Wl=2,Hl=[0,0,1],Jl=()=>({...no(),matchNearest:!0,faceBias:!0,reuseContacts:!0,startAtRest:!0,massPenalty:!0,windSpeed:0,windAngle:0,windGust:.4,windPressure:.72,up:[0,1,0]});function $l(o,e){let t=o.vertices.length/3,i=o.faces.length,r=o.faces.reduce((m,h)=>m+h.verts.length,0),s=Math.ceil(r/4),a=o.edges.length,n=new Float32Array((2+t+2*i+s+a)*4),l=new Uint32Array(n.buffer),c=e+2,f=c+t,u=f+2*i,d=u+s;l.set([c,t,f,i,d,a,u,0],0);for(let m=0;m<t;m++)n.set(o.vertices.subarray(m*3,m*3+3),(2+m)*4);let p=0;return o.faces.forEach((m,h)=>{let b=(2+t+2*h)*4;n.set(m.normal,b),n[b+3]=m.d,l[b+4]=p,l[b+5]=m.verts.length;for(let y of m.verts)l[(2+t+2*i)*4+p++]=y}),o.edges.forEach((m,h)=>l.set(m,(2+t+2*i+s+h)*4)),n}var Lo=.001;function Xl(o,e){let t=o.length,i=o.map(b=>[0,1,2].map(y=>{let v=[0,0,0];return v[y]=1,ue(L(),b.positionAng,v)})),r=o.map((b,y)=>{if(lr(b))return[b.radius,b.radius,b.radius];let v=[0,0,0];for(let w=0;w<3;w++)for(let g=0;g<3;g++)v[g]+=b.size[w]*.5*Math.abs(i[y][w][g]);return v}),s=Po(Float64Array.from(o,b=>b.radius)),a=Math.max(2*s,.001),n=(b,y)=>{let v=o[b],w=o[y];if(v.mass<=0&&w.mass<=0)return!1;let g=[0,1,2].map(x=>v.positionLin[x]-w.positionLin[x]),A=v.radius+w.radius;return g[0]*g[0]+g[1]*g[1]+g[2]*g[2]>A*A?!1:g.every((x,B)=>Math.abs(x)<=r[b][B]+r[y][B])},l=(b,y)=>b[0]*y[0]+b[1]*y[1]+b[2]*y[2],c=(b,y)=>{let v=o[b],w=o[y],g=[0,1,2].map(k=>w.positionLin[k]-v.positionLin[k]),[A,x]=[lr(v),lr(w)];if(A&&x)return Math.hypot(g[0],g[1],g[2])<=v.radius+w.radius+Lo;if(A||x){let[k,z,M]=A?[y,v.radius,-1]:[b,w.radius,1],P=0;for(let _=0;_<3;_++){let C=Math.abs(M*l(g,i[k][_]))-o[k].size[_]*.5;C>0&&(P+=C*C)}return P<=(z+Lo)**2}let B=(k,z)=>o[k].size[0]*.5*Math.abs(l(i[k][0],z))+o[k].size[1]*.5*Math.abs(l(i[k][1],z))+o[k].size[2]*.5*Math.abs(l(i[k][2],z)),E=k=>{let z=Math.hypot(k[0],k[1],k[2]);return z<1e-6?!1:Math.abs(l(g,k))-B(b,k)-B(y,k)>Lo*z};for(let k=0;k<3;k++)if(E(i[b][k])||E(i[y][k]))return!1;for(let k of i[b])for(let z of i[y])if(E([k[1]*z[2]-k[2]*z[1],k[2]*z[0]-k[0]*z[2],k[0]*z[1]-k[1]*z[0]]))return!1;return!0},f=new Set,u=new Map,d=(b,y,v)=>(b*73856093^y*19349663^v*83492791)>>>0,p=b=>[0,1,2].map(y=>Math.floor(o[b].positionLin[y]/a));for(let b=0;b<t;b++){if(o[b].radius>s){f.add(b);continue}let[y,v,w]=p(b),g=d(y,v,w),A=u.get(g);A?A.push(b):u.set(g,[b])}let m=0,h=0;for(let b=0;b<t;b++){if(f.has(b))continue;let[y,v,w]=p(b);for(let g=-1;g<=1;g++)for(let A=-1;A<=1;A++)for(let x=-1;x<=1;x++)for(let B of u.get(d(y+x,v+A,w+g))??[])B<b&&n(b,B)&&(m++,c(b,B)&&(h++,e[b]++,e[B]++))}for(let b of f)for(let y=0;y<t;y++)y!==b&&(!f.has(y)||y<b)&&n(b,y)&&(m++,c(b,y)&&(h++,e[b]++,e[y]++));return{pairs:m,touching:h}}function Yl(o){let e=[1/0,1/0,1/0],t=[-1/0,-1/0,-1/0];for(let s of o)for(let a=0;a<3;a++)e[a]=Math.min(e[a],s.positionLin[a]),t[a]=Math.max(t[a],s.positionLin[a]);let i=s=>{let a=s&1023;return a=(a|a<<16)&50331903,a=(a|a<<8)&50393103,a=(a|a<<4)&51130563,a=(a|a<<2)&153391689,a},r=o.map(s=>{let a=[0,1,2].map(n=>Math.min(1023,Math.floor((s.positionLin[n]-e[n])/Math.max(t[n]-e[n],1e-9)*1024)));return(i(a[0])|i(a[1])<<1|i(a[2])<<2)>>>0});return o.map((s,a)=>a).sort((s,a)=>r[s]-r[a]||s-a)}var de=()=>GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST,rs=class{device;params=Jl();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:s,iterations:a,alpha:n,betaLin:l,betaAng:c,gamma:f}=t;if(Object.assign(this.params,{dt:r,gravity:s,iterations:a,alpha:n,betaLin:l,betaAng:c,gamma:f,up:Hl}),this.bodyCount=t.bodies.length,this.colorRounds=i.colorRounds??16,this.ownsBodyBuffer=!i.bodyBuffer,this.bodyCapacity=i.bodyBuffer?Math.floor(i.bodyBuffer.size/(ke*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:Fl(this.bodyCapacity),usage:de()}),this.filterBuffer=e.createBuffer({label:"collision filters",size:Math.max(this.bodyCapacity,1)*8,usage:de()}),e.queue.writeBuffer(this.filterBuffer,0,new Uint32Array(Math.max(this.bodyCapacity,1)*2).fill(4294967295));let u=this.bodyCapacity;this.tableSize=sn(2*u),this.gridBuffer=e.createBuffer({label:"grid 3d",size:(2*this.tableSize+1+4*u)*4,usage:de()}),this.counterBuffer=e.createBuffer({label:"counters",size:64,usage:de()}),this.argsBuffer=e.createBuffer({label:"indirect args",size:816,usage:de()|GPUBufferUsage.INDIRECT}),this.colorGroups=Math.ceil(u/256),this.colorBuffer=e.createBuffer({label:"colours",size:(3*u+65+64*this.colorGroups+1)*4,usage:de()}),this.paramsBuffer=e.createBuffer({label:"params 3d",size:So*4,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.refBuffer=e.createBuffer({label:"reference poses",size:u*32,usage:de()}),this.hulls=(i.hulls??!0)&&e.limits.maxStorageBuffersPerShaderStage>=9,this.hullBuffer=e.createBuffer({label:"hulls",size:this.hullCapacity*16,usage:de()}),e.queue.writeBuffer(this.colorBuffer,0,new Uint32Array(u).fill(255));let d=2*fe.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 Fe(e,this.gridBuffer,0,this.tableSize+1),this.colorHistScan=new Fe(e,this.colorBuffer,this.colorHistOffset,64*this.colorGroups+1);let p=i.spatialSort===!1?t.bodies.map((x,B)=>B):Yl(t.bodies);this.refToGpu=new Int32Array(p.length),p.forEach((x,B)=>this.refToGpu[x]=B);let m=new Map(t.bodies.map((x,B)=>[x,this.refToGpu[B]])),h=t.forces.filter(x=>x instanceof Be||x instanceof ct);for(let x of t.forces){if(!(x instanceof $r))continue;let B=m.get(x.bodyA),E=m.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,m);let b=new Int32Array(t.bodies.length),{pairs:y,touching:v}=Xl(t.bodies,b),w=new Map(t.bodies.map((x,B)=>[x,B]));for(let x of h)x.bodyA&&b[w.get(x.bodyA)]++,b[w.get(x.bodyB)]++;let g=0;t.bodies.forEach((x,B)=>{x.mass>0&&(g=Math.max(g,b[B]))}),this.colorCap=Math.min(64,Math.max(Nl,g+1+is,i.capacity?.colors??0));let A=i.capacity??{};this.allocateContacts(Math.max(8192,4*u,Ul*v,A.contacts??0),Math.max(4096,4*u,2*y,A.pairs??0),Math.max(4096,u,ql*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=(a,n)=>e.createBindGroupLayout({label:a,entries:n.map((l,c)=>({binding:c,visibility:GPUShaderStage.COMPUTE,buffer:{type:l}}))}),i="read-only-storage",r="storage",s="uniform";return{broad:t("broadphase 3d",[s,i,r,r,r,i,i,i]),contacts:t("contacts 3d",[s,i,i,r,i,r,i,r,r,...this.hulls?[i]:[]]),topo:t("topology 3d",[s,i,i,i,i,r,r,r]),solve:t("solve 3d",[s,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",[s,i,i,r]),refs:t("refs 3d",[s,r,r])}}createPipelines(e){let t=this.device,i=(s,a,n)=>{let l=t.createShaderModule({code:s}),c=t.createPipelineLayout({bindGroupLayouts:a});for(let f of n)this.pipes[f]=t.createComputePipeline({label:f,layout:c,compute:{module:l,entryPoint:f}})},r=this.layouts;i(Ft,[r.broad],["beginFrame","gridCount","gridScatter","findPairs"]),i(es,[r.refs],["updateRefs"]),i(e.contacts??en,[r.contacts],["hashInsert","narrowphase"]),this.contactShaders={make:s=>i(s,[r.contacts],["hashInsert","narrowphase"]),custom:!!e.contacts},i(li(ae,Ni),[r.topo],["degreeJoints","degreeContacts","fillJoints","fillContacts","sortAdjacency","colorCompact","colorMark","colorRoundAB","colorRoundBA","colorCount","colorStarts","colorScatter"]),i(e.solve??be,[r.solve,r.pass],["warmStartJoints","warmStartBodies","primal","dual","updateVelocities"]),i(co(ae,Ka),[r.args],["argsPrev","argsPairs","argsContacts","argsColors"])}allocateJoints(e){let t=this.device,i=t.createBuffer({label:"joints 3d",size:Math.max(e,1)*te*4,usage:de()}),r=t.createBuffer({label:"joint info",size:Math.max(e,1)*16,usage:de()});if(this.jointBuffer){let a=t.createCommandEncoder();a.copyBufferToBuffer(this.jointBuffer,0,i,0,this.jointCapacity*te*4),a.copyBufferToBuffer(this.infoBuffer,0,r,0,this.jointCapacity*16),t.queue.submit([a.finish()]),this.jointBuffer.destroy(),this.infoBuffer.destroy()}let s=new Int32Array(e*4);s.set(this.info.subarray(0,Math.min(this.info.length,s.length))),this.info=s,this.jointBuffer=i,this.infoBuffer=r,this.jointCapacity=e,this.contactBuffers&&this.rebuildBindings()}allocateContacts(e,t,i){let r=this.device,s=r.limits.maxStorageBufferBindingSize,a=Math.min(Math.ceil(e),Math.floor(s/(Bt*4))),n=Math.min(Math.ceil(t),Math.floor(s/8)),l=Math.min(Math.ceil(i),n,Math.floor(s/(bt*4))),c={contacts:this.contactBuffers,manifolds:this.manifoldBuffers,contactCapacity:this.contactCapacity,manifoldCapacity:this.manifoldCapacity};for(let f of[this.pairBuffer,this.tableBuffer])f?.destroy();if(this.contactCapacity=a,this.pairCapacity=n,this.manifoldCapacity=l,this.hashSize=sn(2*l),this.pairBuffer=r.createBuffer({label:"pairs",size:n*8,usage:de()}),this.tableBuffer=r.createBuffer({label:"manifold hash",size:this.hashSize*4,usage:de()}),this.contactBuffers=[0,1].map(f=>r.createBuffer({label:`contacts 3d ${f}`,size:a*Bt*4,usage:de()})),this.manifoldBuffers=[0,1].map(f=>r.createBuffer({label:`manifolds 3d ${f}`,size:l*bt*4,usage:de()})),c.contacts){let f=r.createCommandEncoder(),u=Math.min(c.contactCapacity,a)*Bt*4,d=Math.min(c.manifoldCapacity,l)*bt*4;c.contacts.forEach((p,m)=>f.copyBufferToBuffer(p,0,this.contactBuffers[m],0,u)),c.manifolds.forEach((p,m)=>f.copyBufferToBuffer(p,0,this.manifoldBuffers[m],0,d)),r.queue.submit([f.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:de()}),this.adjScan?.destroy(),this.adjScan=new Fe(e,this.adjBuffer,0,this.bodyCount+1),this.staticBuffer??=e.createBuffer({label:"statics",size:16,usage:de()});let i=(d,p)=>e.createBindGroup({layout:d,entries:p.map((m,h)=>({binding:h,resource:{buffer:m}}))}),r=this.paramsBuffer,[s,a]=this.contactBuffers,[n,l]=this.manifoldBuffers,c=this.adjBuffer,f=this.tableBuffer,u=this.counterBuffer;this.groups={broad:i(this.layouts.broad,[r,this.bodyBuffer,this.gridBuffer,this.pairBuffer,u,this.staticBuffer,this.jointBuffer,this.filterBuffer]),contacts:[i(this.layouts.contacts,[r,this.bodyBuffer,this.pairBuffer,s,a,n,l,f,u,...this.hulls?[this.hullBuffer]:[]]),i(this.layouts.contacts,[r,this.bodyBuffer,this.pairBuffer,a,s,l,n,f,u,...this.hulls?[this.hullBuffer]:[]])],topo:[n,l].map(d=>i(this.layouts.topo,[r,this.bodyBuffer,this.jointBuffer,this.infoBuffer,d,u,c,this.colorBuffer])),solve:[0,1].map(d=>i(this.layouts.solve,[r,this.bodyBuffer,this.jointBuffer,this.infoBuffer,[s,a][d],c,this.colorBuffer,u,[n,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)*ke);t.forEach((r,s)=>{let a=this.pack(r,i,s*ke,this.bodies[e+s]?.hull);this.bodies[e+s]?.radius!==a.radius&&(this.radiiDirty=!0),this.bodies[e+s]=a}),this.device.queue.writeBuffer(this.bodyBuffer,e*ke*4,i,0,t.length*ke)}rewriteFixed(e,t,i,r,s){if(!e.length)return;let a=new Float32Array(ke),n={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(n,a,0);for(let c=0;c<e.length;){let f=c+1;for(;f<e.length&&e[f]===e[f-1]+1;)f++;let u=new Float32Array((f-c)*ke);for(let d=c;d<f;d++){let p=(d-c)*ke;u.set(a,p);for(let h=0;h<3;h++)u[p+Oi+h]=t[3*d+h];if(s)for(let h=0;h<4;h++)u[p+fr+h]=s[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]*ke*4,u),this.device.queue.writeBuffer(this.colorBuffer,e[c]*4,new Uint32Array(f-c).fill(255)),c=f}}pack(e,t,i,r){{t.set(e.positionLin,i+Oi),t[i+Oi+3]=e.friction,t.set(e.positionAng,i+fr),t.set(e.size,i+po),t[i+po+3]=e.mass,t.set(e.moment,i+mo),t[i+mo+3]=e.radius,t.set(e.initialLin,i+qa),t.set(e.initialAng,i+Va),t.set(e.inertialLin,i+Wa),t.set(e.inertialAng,i+Ha),t.set(e.velocityLin,i+bo);let s=this.params.up;t[i+bo+3]=e.prevVelocityLin[0]*s[0]+e.prevVelocityLin[1]*s[1]+e.prevVelocityLin[2]*s[2],t.set(e.velocityAng,i+go);let a=lr(e),n=this.hulls?Nr(e):void 0;r&&r!==n&&this.releaseHull(r);let l=n?r===n?this.hullSlots.get(n).offset:this.acquireHull(n):-1;return t[i+go+3]=a?yo:l>=0?Zr+l:Ua(e)?vo:Xa,{radius:e.radius,dynamic:e.mass>0,sphere:a,size:[e.size[0],e.size[1],e.size[2]],hull:n}}}writeJoint(e,t,i){let r=new Float32Array(te),s=t.bodyA?i.get(t.bodyA):-1,a=i.get(t.bodyB);t instanceof Be?(r.set(t.penaltyLin,Dt),r[Dt+3]=wt(t.broken?0:t.stiffnessLin),r.set(t.penaltyAng,dr),r[dr+3]=wt(t.broken?0:t.stiffnessAng),r.set(t.lambdaLin,ji),r[ji+3]=wt(t.fracture),r.set(t.lambdaAng,Ti),r[Ti+3]=t.torqueArm,r.set(t.C0Lin,Ja),r.set(t.C0Ang,$a),r.set(t.rA,Gt),r.set(t.rB,Di)):(r[Dt+3]=t.stiffness,r.set(t.rA,Gt),r[Gt+3]=t.rest,r.set(t.rB,Di)),this.info.set([t instanceof Be?pr:Ui,s,a,0],e*4),this.device.queue.writeBuffer(this.jointBuffer,e*te*4,r),this.device.queue.writeBuffer(this.infoBuffer,e*16,this.info,e*4,4),this.noCollide(s,a,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,s=new Float64Array(r);for(let c=0;c<r;c++)s[c]=this.bodies[c].radius;let a=Po(s),n=1/0;for(let c=0;c<r;c++)s[c]>a&&(n=Math.min(n,s[c]));let l=n===1/0?a*1.5:(a+n)/2;this.maxSmallRadius=l,this.cellSize=Math.max(2*a*(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],s=this.releasedSlots.size?this.entries.filter(l=>!this.releasedSlots.has(l[2])):this.entries;this.releasedSlots.clear();let a=this.pendingEntries.sort(r);this.pendingEntries=[];let n=[];for(let l=0,c=0;l<s.length||c<a.length;)c>=a.length||l<s.length&&r(s[l],a[c])<=0?n.push(s[l++]):n.push(a[c++]);this.entries=n,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,s)=>i.set(r,e.length+3*s)),this.staticBuffer.size<i.byteLength&&(this.staticBuffer.destroy(),this.staticBuffer=this.device.createBuffer({label:"statics",size:i.byteLength,usage:de()}),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 Be||m instanceof ct)&&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 zi),s=r.reduce((m,h)=>m+h.contacts.length,0);if(s>this.contactCapacity||r.length>this.manifoldCapacity)throw new Error("seedFrom: too many contacts");let a=new ArrayBuffer(Math.max(s,1)*Bt*4),n=new Uint32Array(a),l=new Float32Array(a),c=new ArrayBuffer(Math.max(r.length,1)*bt*4),f=new Uint32Array(c),u=new Float32Array(c),d=0;r.forEach((m,h)=>{f.set([t.get(m.bodyA),t.get(m.bodyB),d,m.contacts.length],h*bt),u.set([m.basis[0],m.basis[1],m.basis[2],m.friction],h*bt+Xr);for(let b of m.contacts){let y=d++*Bt;l.set(b.rA,y+Gi),n[y+Gi+3]=b.feature>>>0|(b.stick?hr:0),l.set([...b.rB,b.C0[0]],y+Yr),l.set([...b.penalty,b.C0[1]],y+Qr),l.set([...b.lambda,b.C0[2]],y+Kr)}}),this.device.queue.writeBuffer(this.contactBuffers[1-this.parity],0,a),this.device.queue.writeBuffer(this.manifoldBuffers[1-this.parity],0,c);let p=new Uint32Array(16);p[1]=s,p[Fi]=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(tn),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((a,n)=>a+n.verts.length,0)/4)+e.edges.length,r=-1,s=this.hullFree.findIndex(a=>a.size>=i);if(s>=0){let a=this.hullFree[s];r=a.offset,a.size===i?this.hullFree.splice(s,1):Object.assign(a,{offset:a.offset+i,size:a.size-i})}else r=this.hullTop,this.hullTop+=i,this.hullTop>this.hullCapacity&&this.growHulls(this.hullTop);if(r+Zr>=2**24)throw new Error("hull buffer beyond 2^24 vec4s");return this.device.queue.writeBuffer(this.hullBuffer,r*16,$l(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,s)=>r.offset-s.offset);let i=[];for(let r of this.hullFree){let s=i[i.length-1];s&&s.offset+s.size===r.offset?s.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:de()}),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 Fe(this.device,this.adjBuffer,0,this.bodyCount+1),i}appendJoint(e,t,i,r,s,a){let n=this.jointCount;n>=this.jointCapacity&&this.allocateJoints(this.jointCapacity*2),this.jointCount++;let l=new Float32Array(te);l[Dt+3]=wt(s),l[dr+3]=wt(a),l[ji+3]=3e38,l.set([i[0],i[1],i[2]],Gt),l.set([r[0],r[1],r[2]],Di);let c=e>=0?this.bodies[e].size:[0,0,0],f=this.bodies[t].size;return l[Ti+3]=(c[0]+f[0])**2+(c[1]+f[1])**2+(c[2]+f[2])**2,this.info.set([pr,e,t,0],n*4),this.device.queue.writeBuffer(this.jointBuffer,n*te*4,l),this.device.queue.writeBuffer(this.infoBuffer,n*16,this.info,n*4,4),this.noCollide(e,t,n),n}appendJoints(e,t,i=!1){return this.appendConstraints(e.length,(r,s)=>{let{a,b:n,rA:l,rB:c,angular:f}=e[r];s[Dt+3]=3e38,s[dr+3]=f===void 0?3e38:wt(f),s[ji+3]=i?-wt(t):wt(t),s.set([l[0],l[1],l[2]],Gt),s.set([c[0],c[1],c[2]],Di);let[u,d]=[this.bodies[a].size,this.bodies[n].size];return s[Ti+3]=(u[0]+d[0])**2+(u[1]+d[1])**2+(u[2]+d[2])**2,[pr,a,n]})}appendSprings(e){return this.appendConstraints(e.length,(t,i)=>{let{a:r,b:s,rA:a,rB:n,stiffness:l,rest:c}=e[t];return i[Dt+3]=wt(l),i.set([a[0],a[1],a[2],c],Gt),i.set([n[0],n[1],n[2]],Di),[Ui,r,s]})}appendConstraints(e,t){let i=[];if(this.freeSlots.length)for(this.freeSlots.sort((n,l)=>l-n);i.length<e&&this.freeSlots.length;)i.push(this.freeSlots.pop());let r=e-i.length,s=this.jointCapacity;for(;this.jointCount+r>s;)s*=2;s>this.jointCapacity&&this.allocateJoints(s);for(let n=0;n<r;n++)i.push(this.jointCount++);let a=new Float32Array(e*te);for(let n=0;n<e;n++){let[l,c,f]=t(n,a.subarray(n*te,(n+1)*te));this.info.set([l,c,f,0],i[n]*4),this.releasedSlots.delete(i[n]),this.noCollide(c,f,i[n])}for(let n=0;n<e;){let l=n+1;for(;l<e&&i[l]===i[l-1]+1;)l++;this.device.queue.writeBuffer(this.jointBuffer,i[n]*te*4,a,n*te,(l-n)*te),this.device.queue.writeBuffer(this.infoBuffer,i[n]*16,this.info,i[n]*4,(l-n)*4),n=l}return i}releaseJoints(e){let t=[...new Set(Array.from(e))].filter(r=>r<this.jointCount&&this.info[r*4]!==0).sort((r,s)=>r-s);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 s=r+1;for(;s<t.length&&t[s]===t[s-1]+1;)s++;i.length<(s-r)*te&&(i=new Float32Array((s-r)*te)),this.device.queue.writeBuffer(this.jointBuffer,t[r]*te*4,i,0,(s-r)*te),this.device.queue.writeBuffer(this.infoBuffer,t[r]*16,this.info,t[r]*4,(s-r)*4),r=s}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 s=r+1;for(;s<e.length&&e[s]===e[s-1]+1;)s++;let a=new Uint32Array(2*(s-r));for(let n=r;n<s;n++)a.set([t[n]>>>0,i[n]>>>0],2*(n-r));this.device.queue.writeBuffer(this.filterBuffer,e[r]*8,a),r=s}}setWorldAnchor(e,t){this.device.queue.writeBuffer(this.jointBuffer,(e*te+Gt)*4,new Float32Array([t[0],t[1],t[2]]))}disableConstraint(e){this.device.queue.writeBuffer(this.jointBuffer,(e*te+Dt)*4,new Float32Array(8)),this.device.queue.writeBuffer(this.jointBuffer,(e*te+ji)*4,new Float32Array(3)),this.device.queue.writeBuffer(this.jointBuffer,(e*te+Ti)*4,new Float32Array(3))}profileNextStep(e){this.timing&&!this.timingBusy&&(this.timingCallback=e)}writeParams(){let e=this.params,t=this.bodyCapacity,i=new ArrayBuffer(So*4),r=new Float32Array(i),s=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,s[6]=(e.matchNearest?xo:0)|(e.faceBias?Ao:0)|(e.reuseContacts?Bo:0)|(e.startAtRest?wo:0)|(e.massPenalty?Co:0),s[7]=this.bodyCount,s[8]=this.jointCount,s[9]=this.colorCap,r[10]=this.cellSize,s[11]=this.tableSize-1,r[12]=this.maxSmallRadius,s[13]=this.largeCount,s[14]=this.noCollideCount,s[15]=this.pairCapacity,s[16]=this.contactCapacity,s[17]=this.hashSize-1,s[18]=t+1,s[19]=2*t+1,s[20]=this.tableSize+1,s[21]=2*this.tableSize+1,s[22]=2*this.tableSize+1+t,s[23]=t,s[24]=this.colorHistOffset,s[25]=2*t,s[26]=this.colorGroups,s[27]=2*t+65,s[28]=this.colorRounds,s[29]=this.manifoldCapacity,s[30]=this.stepCount;let a=n=>Math.min(31,Math.max(0,Math.round(Math.log2(n))));s[31]=a(this.primalLanes[0])|a(this.primalLanes[1])<<8|a(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 s=new ArrayBuffer(r*256),a=new Uint32Array(s),n=new Float32Array(s);for(let l=0;l<e;l++)for(let c=0;c<=this.colorCap;c++){let f=(l*i+c)*256/4;a[f]=c,n[f+1]=t}this.device.queue.writeBuffer(this.passBuffer,0,s)}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,s=this.jointCount,a=this.device.createCommandEncoder({label:"avbd3d step"});a.clearBuffer(this.gridBuffer,0,(2*this.tableSize+1)*4),a.clearBuffer(this.tableBuffer),a.clearBuffer(this.adjBuffer,0,(2*i+1)*4);let n=this.timingCallback!==null&&this.timing!==null,l,c=0,f=n||this.splitPasses,u=()=>{l&&!f||(l?.end(),l=a.beginComputePass({label:f?fe[c]:"avbd3d step",timestampWrites:n?{querySet:this.timing.querySet,beginningOfPassWriteIndex:2*c,endOfPassWriteIndex:2*c+1}:void 0}),c++)},d=this.groups,p=(v,w,g)=>{g<=0||(l.setPipeline(this.pipes[v]),l.setBindGroup(0,w),l.dispatchWorkgroups(g))},m=(v,w,g)=>{l.setPipeline(this.pipes[v]),l.setBindGroup(0,w),l.dispatchWorkgroupsIndirect(this.argsBuffer,g*4)};if(u(),p("beginFrame",d.broad,1),e.reuseContacts&&p("updateRefs",d.refs,$e(r)),p("argsPrev",d.args,1),m("hashInsert",d.contacts[t],6),p("gridCount",d.broad,$e(r)),this.gridScan.encode(l),p("gridScatter",d.broad,$e(r)),p("findPairs",d.broad,$e(r)),p("argsPairs",d.args,1),m("narrowphase",d.contacts[t],0),p("argsContacts",d.args,1),u(),p("degreeJoints",d.topo[t],$e(s)),m("degreeContacts",d.topo[t],3),this.adjScan.encode(l),p("fillJoints",d.topo[t],$e(s)),m("fillContacts",d.topo[t],3),p("sortAdjacency",d.topo[t],$e(r)),u(),!this.fixedColors){p("colorCompact",d.topo[t],$e(r)),p("colorMark",d.topo[t],$e(r));for(let v=0;v<this.colorRounds;v++)p(v%2===0?"colorRoundAB":"colorRoundBA",d.topo[t],$e(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),u();let h=this.colorCap+1,b=v=>l.setBindGroup(1,this.passGroup,[v*256]);l.setBindGroup(0,d.solve[t]),b(0),s>0&&(l.setPipeline(this.pipes.warmStartJoints),l.dispatchWorkgroups($e(s))),l.setPipeline(this.pipes.warmStartBodies),l.dispatchWorkgroups($e(r));for(let v=0;v<e.iterations;v++){l.setPipeline(this.pipes.primal);for(let w=0;w<this.colorCap;w++)b(v*h+w),l.dispatchWorkgroupsIndirect(this.argsBuffer,(12+3*w)*4);b(v*h+this.colorCap),l.setPipeline(this.pipes.dual),l.dispatchWorkgroupsIndirect(this.argsBuffer,36)}l.setPipeline(this.pipes.updateVelocities),l.dispatchWorkgroups($e(r)),l.end();let y=2*fe.length;if(n){let{querySet:v,resolve:w,read:g}=this.timing;a.resolveQuerySet(v,0,y,w,0),a.copyBufferToBuffer(w,0,g,0,y*8)}if(this.device.queue.submit([a.finish()]),this.parity=1-t,n){let v=this.timingCallback;this.timingCallback=null,this.timingBusy=!0;let w=this.timing.read;w.mapAsync(GPUMapMode.READ).then(()=>{let g=new BigUint64Array(w.getMappedRange()).slice();if(w.unmap(),this.timingBusy=!1,this.destroyed)return this.releaseTiming();let A=(B,E)=>Number(g[E]-g[B])/1e6,x={total:A(0,y-1)};fe.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*ke*4))}async readJoints(){return new Float32Array(await this.read(this.jointBuffer,this.jointCount*te*4))}async readCounters(){let e=new Uint32Array(await this.read(this.counterBuffer,64));return{pairs:e[0],contacts:e[1],manifolds:e[Fi],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,[s,a]=await Promise.all([this.read(this.manifoldBuffers[r],t*bt*4),this.read(this.contactBuffers[r],i*Bt*4)]),n=new Uint32Array(s),l=new Float32Array(s),c=new Uint32Array(a),f=new Float32Array(a),u=[];for(let d=0;d<t;d++){let p=d*bt,m=[...l.subarray(p+Xr,p+Xr+3)];for(let h=n[p+2];h<n[p+2]+(n[p+3]&15);h++){let b=h*Bt,y=c[b+Gi+3];u.push({a:n[p],b:n[p+1],feature:(y&~hr)>>>0,stick:(y&hr)!==0,rA:[...f.subarray(b+Gi,b+Gi+3)],rB:[...f.subarray(b+Yr,b+Yr+3)],pen:[...f.subarray(b+Qr,b+Qr+3)],lam:[...f.subarray(b+Kr,b+Kr+3)],normal:m})}}return u}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+is+2,this.colorCap+4)),this.shrinkVotes=0):t+is+2<this.colorCap||this.colorRounds>4?++this.shrinkVotes>=3&&(this.colorCap=Math.min(64,t+is),this.colorRounds=Math.max(4,this.colorRounds-4),this.shrinkVotes=0):this.shrinkVotes=0;let i=(n,l,c)=>(e.overflow&c)!==0||n>Vl*l?Math.max(Wl*n,1.25*l):l,r=i(e.contacts,this.contactCapacity,2),s=i(e.pairs,this.pairCapacity,1),a=i(e.manifolds,this.manifoldCapacity,4);this.capacityCanGrow(r,s,a)&&this.allocateContacts(r,s,a)}capacityCanGrow(e,t,i){let r=this.device.limits.maxStorageBufferBindingSize;return Math.min(e,r/(Bt*4))>this.contactCapacity||Math.min(t,r/8)>this.pairCapacity||Math.min(i,t,r/(bt*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 s=i.getMappedRange().slice(0);return i.unmap(),i.destroy(),s}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 on=` e.C = vec3f(
2421
+ `;function Ds(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 _n(s){let e=s.length,t=e>0?Ds(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,Ds(s,e-64-1))),i}var Jt=s=>s===1/0?3e38:s===-1/0?-3e38:s,dt=s=>Math.ceil(s/64),rl=s=>2**Math.ceil(Math.log2(Math.max(s,2))),tu=s=>Math.max(s,1)*qe*4,iu=8,Fs=3,ru=8,su=1.6,ou=.8,nu=2,au=[0,0,1],lu=()=>({...un(),matchNearest:!0,faceBias:!0,reuseContacts:!0,startAtRest:!0,massPenalty:!0,windSpeed:0,windAngle:0,windGust:.4,windPressure:.72,up:[0,1,0]});function cu(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 En=.001;function uu(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=_n(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+En;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+En)**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)>En*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 fu(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,Gs=class{device;params=lu();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:au}),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:tu(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=rl(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:Pn*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):fu(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 ft);for(let x of t.forces){if(!(x instanceof Ms))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}=uu(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(ru,y+1+Fs,i.capacity?.colors??0));let A=i.capacity??{};this.allocateContacts(Math.max(8192,4*f,iu*v,A.contacts??0),Math.max(4096,4*f,2*b,A.pairs??0),Math.max(4096,f,su*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(js,[r.refs],["updateRefs"]),i(e.contacts??el,[r.contacts],["hashInsert","narrowphase"]),this.contactShaders={make:o=>i(o,[r.contacts],["hashInsert","narrowphase"]),custom:!!e.contacts},i(Ri(Ae,gr),[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(dn(Ae,Ka),[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=rl(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+cr+h]=t[3*d+h];if(o)for(let h=0;h<4;h++)f[p+qr+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+cr),t[i+cr+3]=e.friction,t.set(e.positionAng,i+qr),t.set(e.size,i+gn),t[i+gn+3]=e.mass,t.set(e.moment,i+bn),t[i+bn+3]=e.radius,t.set(e.initialLin,i+qa),t.set(e.initialAng,i+Va),t.set(e.inertialLin,i+Wa),t.set(e.inertialAng,i+Ha),t.set(e.velocityLin,i+yn);let o=this.params.up;t[i+yn+3]=e.prevVelocityLin[0]*o[0]+e.prevVelocityLin[1]*o[1]+e.prevVelocityLin[2]*o[2],t.set(e.velocityAng,i+vn);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+vn+3]=n?An:l>=0?Ts+l:or(e)?xn:Xa,{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,Vr),r[Vr+3]=Jt(t.broken?0:t.stiffnessAng),r.set(t.lambdaLin,ur),r[ur+3]=Jt(t.fracture),r.set(t.lambdaAng,fr),r[fr+3]=t.torqueArm,r.set(t.C0Lin,Ja),r.set(t.C0Ang,$a),r.set(t.rA,ci),r.set(t.rB,dr)):(r[li+3]=t.stiffness,r.set(t.rA,ci),r[ci+3]=t.rest,r.set(t.rB,dr)),this.info.set([t instanceof ke?Hr:mr,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=_n(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 ft)&&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+zs);for(let m of g.contacts){let b=d++*Ht;l.set(m.rA,b+hr),a[b+hr+3]=m.feature>>>0|(m.stick?Wr:0),l.set([...m.rB,m.C0[0]],b+Is),l.set([...m.penalty,m.C0[1]],b+Rs),l.set([...m.lambda,m.C0[2]],b+Os)}}),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[pr]=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(tl),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+Ts>=2**24)throw new Error("hull buffer beyond 2^24 vec4s");return this.device.queue.writeBuffer(this.hullBuffer,r*16,cu(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[Vr+3]=Jt(n),l[ur+3]=3e38,l.set([i[0],i[1],i[2]],ci),l.set([r[0],r[1],r[2]],dr);let c=e>=0?this.bodies[e].size:[0,0,0],u=this.bodies[t].size;return l[fr+3]=(c[0]+u[0])**2+(c[1]+u[1])**2+(c[2]+u[2])**2,this.info.set([Hr,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[Vr+3]=u===void 0?3e38:Jt(u),o[ur+3]=i?-Jt(t):Jt(t),o.set([l[0],l[1],l[2]],ci),o.set([c[0],c[1],c[2]],dr);let[f,d]=[this.bodies[n].size,this.bodies[a].size];return o[fr+3]=(f[0]+d[0])**2+(f[1]+d[1])**2+(f[2]+d[2])**2,[Hr,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]],dr),[mr,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+ur)*4,new Float32Array(3)),this.device.queue.writeBuffer(this.jointBuffer,(e*pe+fr)*4,new Float32Array(3))}profileNextStep(e){this.timing&&!this.timingBusy&&(this.timingCallback=e)}writeParams(){let e=this.params,t=this.bodyCapacity,i=new ArrayBuffer(Pn*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?wn:0)|(e.faceBias?Bn:0)|(e.reuseContacts?Cn:0)|(e.startAtRest?Sn:0)|(e.massPenalty?kn: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,dt(r)),p("argsPrev",d.args,1),g("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),g("narrowphase",d.contacts[t],0),p("argsContacts",d.args,1),f(),p("degreeJoints",d.topo[t],dt(o)),g("degreeContacts",d.topo[t],3),this.adjScan.encode(l),p("fillJoints",d.topo[t],dt(o)),g("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 v=0;v<this.colorRounds;v++)p(v%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,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(dt(o))),l.setPipeline(this.pipes.warmStartBodies),l.dispatchWorkgroups(dt(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(dt(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[pr],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+zs,p+zs+3)];for(let h=a[p+2];h<a[p+2]+(a[p+3]&15);h++){let m=h*Ht,b=c[m+hr+3];f.push({a:a[p],b:a[p+1],feature:(b&~Wr)>>>0,stick:(b&Wr)!==0,rA:[...u.subarray(m+hr,m+hr+3)],rB:[...u.subarray(m+Is,m+Is+3)],pen:[...u.subarray(m+Rs,m+Rs+3)],lam:[...u.subarray(m+Os,m+Os+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+Fs+2,this.colorCap+4)),this.shrinkVotes=0):t+Fs+2<this.colorCap||this.colorRounds>4?++this.shrinkVotes>=3&&(this.colorCap=Math.min(64,t+Fs),this.colorRounds=Math.max(4,this.colorRounds-4),this.shrinkVotes=0):this.shrinkVotes=0;let i=(a,l,c)=>(e.overflow&c)!==0||a>ou*l?Math.max(nu*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 sl=` 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(be.split(on).length!==2)throw Error("Pinned contact evaluation changed; review the app kernel variant");var br=be.replace(on,` 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 ot(o,e,t){if(o.split(e).length!==2)throw Error("Pinned solve layout changed; review the app kernel variant");return o.replace(e,t)}var ss=(()=>{let o=ot(br," var e = adj[i] + lane;",` let begin = adj[i];
2426
- var e = begin;`);return o=ot(o,` if (c == cEnd) {
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(sl).length!==2)throw Error("Pinned contact evaluation changed; review the app kernel variant");var $r=ze.replace(sl,` 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 Ns=(()=>{let s=St($r," var e = adj[i] + lane;",` let begin = adj[i];
2426
+ var e = begin;`);return s=St(s,` if (c == cEnd) {
2427
2427
  `,` if (c >= cEnd) {
2428
- `),o=ot(o,` e += lanes;
2428
+ `),s=St(s,` e += lanes;
2429
2429
  if (id < params.jointCount) {
2430
2430
  addJoint(&acc, id, pc.alpha, i);`,` e++;
2431
2431
  if (id < params.jointCount) {
2432
2432
  if ((e - begin - 1u) % lanes != lane) { continue; }
2433
- addJoint(&acc, id, pc.alpha, i);`),o=ot(o," isA = i == mf.ids.x;",` c = mf.ids.z + lane;
2433
+ addJoint(&acc, id, pc.alpha, i);`),s=St(s," isA = i == mf.ids.x;",` c = mf.ids.z + lane;
2434
2434
  cEnd = mf.ids.z + pairCount(mf);
2435
2435
  if (c >= cEnd) { continue; }
2436
- isA = i == mf.ids.x;`),o=ot(o,` c = mf.ids.z;
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; }`,""),o=ot(o," c++;"," c += lanes;"),o})();function Oo(o=be){o=ot(o,"fn manifoldCount() -> u32 {",`fn solverStepValid() -> bool {
2438
+ if (c == cEnd) { continue; }`,""),s=St(s," c++;"," c += lanes;"),s})();function jn(s=ze){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
- 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) {`;o=ot(o,i,`${i}
2444
- if (!solverStepValid()) { return; }`)}return ot(o," let live = k < count;"," let live = k < count && solverStepValid();")}function jo(o){return o=ot(o," 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);
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 Dn(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;`),o=ot(o,"k.c0Lin = vec4f(jointLinC(k, a, b), 0.0);","k.c0Lin = vec4f(jointLinC(k, a, b), k.c0Lin.w);"),ot(o,"k.c0Ang = vec4f(jointAngC(k, a, b), 0.0);","k.c0Ang = vec4f(jointAngC(k, a, b), k.c0Ang.w);")}var an=`// 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 ol=`// 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 nn=`// Conservative GPU sleeping. Resting contacts form supports from the ground
2475
+ `;var nl=`// 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,13 @@ fn impact(a:u32,b:u32) {
2522
2522
  }
2523
2523
  if(states[i].asleep!=0u){atomicAdd(&globals[1],1u);}
2524
2524
  }
2525
- `;var To=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,s=0,a=0,n=0;for(let[l,c]of this.targets){let f=c.pending.size;if(!f)continue;(!c.data||c.data.length<f*2)&&(c.data=new Uint32Array(Math.max(f*2,(c.data?.length??0)*2,128)));let u=Array.from(c.pending.keys()),d=!0;for(let m=1;m<f;m++)if(u[m]<u[m-1]){d=!1;break}d||u.sort((m,h)=>m-h);let p=1;for(let m=1;m<f;m++)u[m]!==u[m-1]+1&&p++;if(p<=4||f<=8){for(let m=0;m<f;m++)c.data[m]=c.pending.get(u[m]);for(let m=0;m<f;){let h=m+1;for(;h<f&&u[h]===u[h-1]+1;)h++;t.queue.writeBuffer(l,u[m]*4,c.data.buffer,m*4,(h-m)*4),r++,m=h}n+=f*4}else{let m=f*8,h=Math.min(t.limits.maxBufferSize,t.limits.maxStorageBufferBindingSize);if(m>h)throw Error("Property batch exceeds GPU buffer limits");for(let w=0;w<f;w++)c.data[w*2]=u[w],c.data[w*2+1]=c.pending.get(u[w]);(!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:`
2525
+ `;var Fn=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:`
2526
2526
  @group(0) @binding(0) var<storage,read_write> outputWords:array<u32>;
2527
2527
  @group(0) @binding(1) var<storage,read> edits:array<vec2u>;
2528
2528
  @compute @workgroup_size(64) fn applyEdits(@builtin(global_invocation_id) id:vec3u){
2529
2529
  let i=id.x+id.y*${t.limits.maxComputeWorkgroupsPerDimension*64}u;
2530
2530
  if(i>=arrayLength(&edits)){return;}let edit=edits[i];outputWords[edit.x]=edit.y;
2531
- }`})}}),(!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 b=i.beginComputePass();b.setPipeline(this.pipeline),b.setBindGroup(0,c.group);let y=Math.ceil(f/64),v=t.limits.maxComputeWorkgroupsPerDimension;b.dispatchWorkgroups(Math.min(y,v),Math.ceil(y/v)),b.end(),r++,s++,n+=m}a+=f,c.pending.clear()}!e&&i&&t.queue.submit([i.finish()]),a&&(this.lastBatch={words:a,writes:r,dispatches:s,uploadedBytes:n,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 Q(o){return o.propertyEdits??=new To(o.device)}var hi=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 s=i.createShaderModule({code:nn});this.layout=i.createBindGroupLayout({entries:["storage","storage","read-only-storage","read-only-storage","read-only-storage","storage","uniform"].map((c,f)=>({binding:f,visibility:GPUShaderStage.COMPUTE,buffer:{type:c}}))});let a=i.createPipelineLayout({bindGroupLayouts:[this.layout]});this.pipelines=Object.fromEntries(["before","clear","contacts","joints","rest"].map(c=>[c,i.createComputePipeline({layout:a,compute:{module:s,entryPoint:c}})]));let n=new Float32Array(e.capacity*8),l=new Uint32Array(n.buffer);for(let c of e.aggregates)if(!c.disposed){let f=(c.gpuSlot??e.gpu.gpuIndex(c.index))*8;n[f]=c.rigid.mass,l[f+4]=c.allowSleep===!1||c.rigid.allowSleep===!1?0:1}i.queue.writeBuffer(this.state,0,n),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 s=new Uint32Array(r.buffer),a=Q(this.world.gpu);for(let n=0;n<8;n++)a.uint(this.state,e*8+n,s[n]);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(s=>s.buffers.every((a,n)=>a===i[n]));r||(r={buffers:i,group:this.device.createBindGroup({layout:this.layout,entries:i.map((s,a)=>({binding:a,resource:{buffer:s}}))})},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),s=new Uint32Array(r),a=new Float32Array(r);s.set([t.bodyCount,t.jointCount,t.manifoldCapacity,this.wakeRequested?1:0]),a.set([this.speed,this.delay,t.params.dt,t.params.gravity],4),a.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[s,a]of e)a&&(r.setPipeline(this.pipelines[s]),r.dispatchWorkgroups(s==="clear"?1:Math.ceil(a/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 Do=new WeakMap;function Pt(o={}){let e={};for(let t of["breakStrain","breakForce"]){let i=o[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 os(o,e){let t=Pt(e);Number.isFinite(t.breakStrain)||Number.isFinite(t.breakForce)?Do.set(o,t):Do.delete(o)}var Go=o=>Do.get(o);function as(o){let e="fn dualJoint(j: u32) {";if(o.split(e).length!==2)throw Error("Review spring fracture kernel integration");return o.replace(e,`${e}
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 Fn(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:nl});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 Gn=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 br(s,e){let t=It(e);Number.isFinite(t.breakStrain)||Number.isFinite(t.breakForce)?Gn.set(s,t):Gn.delete(s)}var Gi=s=>Gn.get(s);function Us(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
2532
  if (info[j].x == T_SPRING) {
2533
2533
  var material = joints[j];
2534
2534
  let strainLimit = material.lamLin.w;
@@ -2550,7 +2550,7 @@ fn impact(a:u32,b:u32) {
2550
2550
  }
2551
2551
  }
2552
2552
  }
2553
- `)}var Zl=["auto","standard","optimized","points"];function qi({requested:o="auto",bodyCount:e,constraintCount:t=0,contactScheduling:i="manifolds",custom:r=!1}){if(!Zl.includes(o))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&&o!=="auto")throw Error("A scene-specific solve shader cannot be replaced with a rigid-body solver mode");let s=r?"custom":o!=="auto"?o:t>0||e<5e4?"standard":i==="points"?"points":"optimized",a=r?"This scene supplies its own solver. Automatic keeps that implementation.":o!=="auto"?"Explicit implementation override (developer setting).":t>0?"Work layout selected for joints and springs.":e<5e4?"Work layout selected for smaller rigid scenes.":s==="points"?"Large rigid scene with a measured shared-contact-points layout.":"Work layout selected for large rigid scenes.";return{requested:o,selected:s,reason:a,bodyCount:e,constraintCount:t}}var ns=`// Portable hierarchical PLOC: Morton ordering and independent SAH treelets.
2553
+ `)}var pu=["auto","standard","optimized","points"];function yr({requested:s="auto",bodyCount:e,constraintCount:t=0,contactScheduling:i="manifolds",custom:r=!1}){if(!pu.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 qs=`// Portable hierarchical PLOC: Morton ordering and independent SAH treelets.
2554
2554
  // Dispatch boundaries publish each hierarchy level; no cross-workgroup spin waits.
2555
2555
  struct Node {
2556
2556
  lo: vec3f,
@@ -2807,7 +2807,7 @@ fn ropes(@builtin(global_invocation_id) gid: vec3u) {
2807
2807
  }
2808
2808
  links[build.escapeOffset + id] = escape;
2809
2809
  }\r
2810
- `;var ln=`// Stable 4-bit GPU radix sort; PrefixScan scans digit-major block counts.
2810
+ `;var al=`// Stable 4-bit GPU radix sort; PrefixScan scans digit-major block counts.
2811
2811
  struct SortSettings { count: u32, blocks: u32, shift: u32, _pad: u32 }
2812
2812
  @group(0) @binding(0) var<uniform> sort: SortSettings;
2813
2813
  @group(0) @binding(1) var<storage, read> input: array<vec2u>;
@@ -2855,10 +2855,10 @@ fn scatterDigits(
2855
2855
  }
2856
2856
  output[hist[digit * sort.blocks + wid.x] + rank] = value;
2857
2857
  }\r
2858
- `;var ic=()=>GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC,ut=(o,e=128)=>Math.max(1,Math.ceil(o/e)),rc=4294967295,Fo=Ft.indexOf(`@compute @workgroup_size(64)
2859
- fn gridCount`),Uo=Ft.indexOf("/** Binary search"),cn=Ft.indexOf(`@compute @workgroup_size(64)
2860
- fn findPairs`);if(Fo<0||Uo<Fo||cn<Uo)throw Error("Pinned broadphase changed; review H-PLOC integration");var sc=ns.slice(0,ns.indexOf("@group(0)")),oc=(Ft.slice(0,Fo)+Ft.slice(Uo,cn)).replace("var<storage, read_write> grid: array<atomic<u32>>;","var<storage, read_write> tree: array<Node>;")+`
2861
- ${sc}
2858
+ `;var bu=()=>GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC,Rt=(s,e=128)=>Math.max(1,Math.ceil(s/e)),yu=4294967295,Nn=ui.indexOf(`@compute @workgroup_size(64)
2859
+ fn gridCount`),Un=ui.indexOf("/** Binary search"),ll=ui.indexOf(`@compute @workgroup_size(64)
2860
+ fn findPairs`);if(Nn<0||Un<Nn||ll<Un)throw Error("Pinned broadphase changed; review H-PLOC integration");var vu=qs.slice(0,qs.indexOf("@group(0)")),Au=(ui.slice(0,Nn)+ui.slice(Un,ll)).replace("var<storage, read_write> grid: array<atomic<u32>>;","var<storage, read_write> tree: array<Node>;")+`
2861
+ ${vu}
2862
2862
  @group(1) @binding(0) var<uniform> build: BuildSettings;
2863
2863
  @group(1) @binding(1) var<storage,read> links: array<u32>;
2864
2864
  @compute @workgroup_size(64)
@@ -2880,11 +2880,11 @@ fn findTreePairs(@builtin(global_invocation_id) gid:vec3u) {
2880
2880
  at=links[build.escapeOffset+at];
2881
2881
  } else {at=node.left;}
2882
2882
  }
2883
- }`,ls=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=(f,u,d=ic())=>{if(d&GPUBufferUsage.STORAGE&&u>e.limits.maxStorageBufferBindingSize)throw Error(`${f} exceeds the adapter storage binding limit`);let p=e.createBuffer({label:f,size:Math.max(16,u),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",(ut(this.capacity)*2+256)*16),this.sortBlocks=ut(this.capacity),this.hist=r("Morton radix counts",this.sortBlocks*16*4),this.scan=new Fe(e,this.hist,0,this.sortBlocks*16);let s=(f,u)=>({binding:f,visibility:GPUShaderStage.COMPUTE,buffer:{type:u}});this.layout=e.createBindGroupLayout({entries:[s(0,"uniform"),s(1,"read-only-storage"),...Array.from({length:5},(f,u)=>s(u+2,"storage"))]}),this.extraLayout=e.createBindGroupLayout({entries:[s(0,"uniform"),s(1,"read-only-storage")]});let a=e.createShaderModule({label:"portable H-PLOC",code:ae+ns+`
2883
+ }`,Vs=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=bu())=>{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+qs+`
2884
2884
  @compute @workgroup_size(128)
2885
2885
  fn initializeLinks(@builtin(global_invocation_id) gid:vec3u){if(gid.x<build.escapeOffset){links[gid.x]=0xffffffffu;}}
2886
- `}),n=e.createPipelineLayout({bindGroupLayouts:[this.layout]});this.pipes=Object.fromEntries(["leaves","reduceBounds","mortonCodes","seedClusters","miniHploc","refitTreelets","ropes","initializeLinks"].map(f=>[f,e.createComputePipeline({layout:n,compute:{module:a,entryPoint:f}})]));let l=e.createShaderModule({label:"stable Morton radix",code:ln});this.sortLayout=e.createBindGroupLayout({entries:[s(0,"uniform"),s(1,"read-only-storage"),s(2,"storage"),s(3,"storage")]});let c=e.createPipelineLayout({bindGroupLayouts:[this.sortLayout]});this.sortPipes=Object.fromEntries(["countDigits","scatterDigits"].map(f=>[f,e.createComputePipeline({layout:c,compute:{module:l,entryPoint:f}})])),this.traverse=e.createComputePipeline({label:"H-PLOC collision traversal",layout:e.createPipelineLayout({bindGroupLayouts:[t.layouts.broad,this.extraLayout]}),compute:{module:e.createShaderModule({code:oc}),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,s=0,a=e,n=e===0?rc:0;for(;i>1;){let d=Math.ceil(i/16);t.push({inputCount:i,nodeBase:r,inputOffset:s,outputOffset:a,blocks:d}),d===1&&(n=r+i-2),r+=d*15,s=a,a+=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,n,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,b)=>({binding:b,resource:{buffer:h}}))}),buffer:p}};this.base=l(),this.levels=t.map(d=>({...d,...l(d)})),this.reductions=[];let c=ut(e),f=0,u=c*2;for(;c>1;){let d=ut(c);this.reductions.push({blocks:d,...l({inputCount:c,inputOffset:f,outputOffset:u})}),f=u,u+=d*2,c=d}this.morton=l({boundsOffset:f}),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,b)=>({binding:b,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,s,a)=>{e.setPipeline(this.pipes[r]),e.setBindGroup(0,s),e.dispatchWorkgroups(a)};t("leaves",this.base.group,ut(this.count));let i=!this.built||this.stepsSinceBuild>=this.rebuildInterval;if(this.lastRebuilt=i,i){t("initializeLinks",this.base.group,ut(this.nodeCapacity));for(let r of this.reductions)t("reduceBounds",r.group,r.blocks);t("mortonCodes",this.morton.group,ut(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,ut(this.count));for(let r of this.levels)t("miniHploc",r.group,r.blocks);t("ropes",this.base.group,ut(this.nodeCapacity)),this.built=!0,this.stepsSinceBuild=0,this.stats.builds++}else{for(let r of this.levels)t("refitTreelets",r.group,ut(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,s)=>r!==this.broadBuffers[s]))&&(this.broadBuffers=i,this.broad=this.device.createBindGroup({layout:t.layouts.broad,entries:i.map((r,s)=>({binding:s,resource:{buffer:r}}))})),e.setPipeline(this.traverse),e.setBindGroup(0,this.broad),e.setBindGroup(1,this.extra),e.dispatchWorkgroups(ut(this.count,64))}destroy(){this.scan.destroy();for(let e of[...this.buffers,...this.uniforms])e.destroy()}};function un(o,e={}){let t,i,r=!0,s=new Map,a=l=>{if(!i&&!l)return;let c=e.timestampWrites,f=o.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){f.setPipeline(i.pipeline);for(let[u,d]of i.bindings)f.setBindGroup(u,...d);f[i.method](...i.args)}f.end(),i=null,r=!1},n=(l,c)=>{a(!1),i={pipeline:t,bindings:new Map(s),method:l,args:c}};return{setPipeline(l){t=l},setBindGroup(l,c,f){s.set(l,f===void 0?[c]:[c,[...f]])},dispatchWorkgroups(...l){n("dispatchWorkgroups",l)},dispatchWorkgroupsIndirect(...l){n("dispatchWorkgroupsIndirect",l)},end(){a(!0)}}}var Xe=o=>Math.ceil(o/64);function fn(o){(o.radiiDirty||o.noCollideDirty)&&o.uploadStatics();let e=o.params;o.fixedColors&&(o.device.queue.writeBuffer(o.colorBuffer,0,o.fixedColors),o.colorCap=Math.max(1,...o.fixedColors.map(x=>x===255?0:x+1))),o.stepCount++,o.writeParams(),o.writePassConstants(e.iterations,e.alpha);let t=o.parity,i=o.bodyCapacity,r=o.bodyCount,s=o.jointCount,a=o.groups,n=o.device.createCommandEncoder({label:"AVBD app step"});o.encodeStepPrelude?.(n),o.bvh||n.clearBuffer(o.gridBuffer,0,(2*o.tableSize+1)*4),n.clearBuffer(o.tableBuffer),n.clearBuffer(o.adjBuffer,0,(2*i+1)*4);let l=!!o.detailCallback,c=l||o.timingCallback!==null&&o.timing!==null,f=c||o.splitPasses,u=l?o.detailTiming:o.timing,d=[],p,m,h=(x,B)=>{if(p&&!l&&(m===B||!f))return;p?.end(),m=B;let E=l?d.length:fe.indexOf(B);d.push({name:x,aggregate:B});let k={label:x,timestampWrites:c?{querySet:u.querySet,beginningOfPassWriteIndex:E*2,endOfPassWriteIndex:E*2+1}:void 0};p=o.dispatchIsolation?un(n,k):n.beginComputePass(k)},b=(x,B,E)=>{E<=0||(p.setPipeline(o.pipes[x]),p.setBindGroup(0,B),p.dispatchWorkgroups(E))},y=(x,B,E)=>{p.setPipeline(o.pipes[x]),p.setBindGroup(0,B),p.dispatchWorkgroupsIndirect(o.argsBuffer,E*4)};if(h("contactCache","collision"),b("beginFrame",a.broad,1),e.reuseContacts&&b("updateRefs",a.refs,Xe(r)),b("argsPrev",a.args,1),y("hashInsert",a.contacts[t],6),h("broadphaseBuild","collision"),o.bvh?(o.bvh.configure(r),o.bvh.encodeBuild(p)):(b("gridCount",a.broad,Xe(r)),o.gridScan.encode(p),b("gridScatter",a.broad,Xe(r))),h("broadphasePairs","collision"),o.bvh?o.bvh.encodePairs(p,o):b("findPairs",a.broad,Xe(r)),h("narrowphase","collision"),b("argsPairs",a.args,1),y("narrowphase",a.contacts[t],0),b("argsContacts",a.args,1),h("adjacency","adjacency"),b("degreeJoints",a.topo[t],Xe(s)),y("degreeContacts",a.topo[t],3),o.adjScan.encode(p),b("fillJoints",a.topo[t],Xe(s)),y("fillContacts",a.topo[t],3),b("sortAdjacency",a.topo[t],Xe(r)),h("coloring","coloring"),!o.fixedColors){b("colorCompact",a.topo[t],Xe(r)),b("colorMark",a.topo[t],Xe(r));for(let x=0;x<o.colorRounds;x++)b(x%2===0?"colorRoundAB":"colorRoundBA",a.topo[t],Xe(r))}b("colorCount",a.topo[t],o.colorGroups),o.colorHistScan.encode(p),b("colorStarts",a.topo[t],1),b("argsColors",a.args,1),b("colorScatter",a.topo[t],o.colorGroups);let v=x=>p.setBindGroup(1,o.passGroup,[x*256]),w=()=>{p.setBindGroup(0,a.solve[t]),v(0)};h("warmStart","solve"),w(),s>0&&(p.setPipeline(o.pipes.warmStartJoints),p.dispatchWorkgroups(Xe(s))),p.setPipeline(o.pipes.warmStartBodies),r&&p.dispatchWorkgroups(Xe(r));for(let x=0;x<e.iterations;x++){h("bodySolve","solve"),w(),p.setPipeline(o.pipes.primal);for(let B=0;B<o.colorCap;B++)v(x*(o.colorCap+1)+B),p.dispatchWorkgroupsIndirect(o.argsBuffer,(12+3*B)*4);h("contactUpdate","solve"),w(),v(x*(o.colorCap+1)+o.colorCap),p.setPipeline(o.pipes.dual),p.dispatchWorkgroupsIndirect(o.argsBuffer,36)}h("velocities","solve"),w(),p.setPipeline(o.pipes.updateVelocities),r&&p.dispatchWorkgroups(Xe(r)),p.end();let g=2*(l?d.length:fe.length);if(c&&(n.resolveQuerySet(u.querySet,0,g,u.resolve,0),n.copyBufferToBuffer(u.resolve,0,u.read,0,g*8)),o.parity=1-t,o.encodeStepPostlude?.(n),o.device.queue.submit([n.finish()]),!c)return;let A=l?o.detailCallback:o.timingCallback;l?o.detailCallback=null:o.timingCallback=null,o.timingBusy=!0,u.read.mapAsync(GPUMapMode.READ).then(()=>{let x=new BigUint64Array(u.read.getMappedRange()).slice();if(u.read.unmap(),o.timingBusy=!1,o.destroyed){o.releaseAppTiming(),o.releaseTiming();return}let B=(k,z)=>Number(x[z]-x[k])/1e6,E={total:B(0,g-1),broadphase:o.broadphase,bvhRebuilt:o.bvh?.lastRebuilt??!1};if(l){E.details={};for(let[k,z]of d.entries()){let M=B(k*2,k*2+1);E[z.aggregate]=(E[z.aggregate]??0)+M,E.details[z.name]=(E.details[z.name]??0)+M}}else fe.forEach((k,z)=>E[k]=B(z*2,z*2+1));A(E)},x=>{o.timingBusy=!1,o.profileErrors.push(x.message),o.destroyed&&(o.releaseAppTiming(),o.releaseTiming())})}var dn=` let list = params.adjListOffset;
2887
- for (var i = lo + 1u; i < hi; i++) {`,hn=li(ae,Ni);if(hn.split(dn).length!==2)throw Error("Pinned adjacency sort changed; review the cached-key variant");var pn=hn.replace(dn,`
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:al});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:Au}),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?yu: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 cl(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 ht=s=>Math.ceil(s/64);function ul(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?cl(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,ht(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,ht(r)),s.gridScan.encode(p),m("gridScatter",n.broad,ht(r))),h("broadphasePairs","collision"),s.bvh?s.bvh.encodePairs(p,s):m("findPairs",n.broad,ht(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],ht(o)),b("degreeContacts",n.topo[t],3),s.adjScan.encode(p),m("fillJoints",n.topo[t],ht(o)),b("fillContacts",n.topo[t],3),m("sortAdjacency",n.topo[t],ht(r)),h("coloring","coloring"),!s.fixedColors){m("colorCompact",n.topo[t],ht(r)),m("colorMark",n.topo[t],ht(r));for(let x=0;x<s.colorRounds;x++)m(x%2===0?"colorRoundAB":"colorRoundBA",n.topo[t],ht(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(ht(o))),p.setPipeline(s.pipes.warmStartBodies),r&&p.dispatchWorkgroups(ht(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(ht(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 fl=` let list = params.adjListOffset;
2887
+ for (var i = lo + 1u; i < hi; i++) {`,dl=Ri(Ae,gr);if(dl.split(fl).length!==2)throw Error("Pinned adjacency sort changed; review the cached-key variant");var hl=dl.replace(fl,`
2888
2888
  let list = params.adjListOffset;
2889
2889
  let count = hi - lo;
2890
2890
  if (count <= 16u) {
@@ -2913,13 +2913,13 @@ fn initializeLinks(@builtin(global_invocation_id) gid:vec3u){if(gid.x<build.esca
2913
2913
  }
2914
2914
  return;
2915
2915
  }
2916
- for (var i = lo + 1u; i < hi; i++) {`);function mn(o){return o.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 No(o){return o.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 bn(o=li(ae,Ni)){return o.replaceAll("if (gid.x >= topoCount()) { return; }",`if (gid.x >= topoCount()) { return; }
2917
- if ((contacts[gid.x].ids.w & 0x80000000u) != 0u) { return; }`)}function gn(o){let e=o.device,t=e.createShaderModule({code:`
2916
+ for (var i = lo + 1u; i < hi; i++) {`);function pl(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 qn(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 ml(s=Ri(Ae,gr)){return s.replaceAll("if (gid.x >= topoCount()) { return; }",`if (gid.x >= topoCount()) { return; }
2917
+ if ((contacts[gid.x].ids.w & 0x80000000u) != 0u) { return; }`)}function gl(s){let e=s.device,t=e.createShaderModule({code:`
2918
2918
  @group(0) @binding(0) var<storage,read_write> records:array<vec4f>;
2919
2919
  @compute @workgroup_size(64) fn clear(@builtin(global_invocation_id) id:vec3u){
2920
2920
  if(id.x*10u+2u>=arrayLength(&records)){return;}
2921
2921
  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:o.bodyBuffer}}]}),s=e.createCommandEncoder(),a=s.beginComputePass();a.setPipeline(i),a.setBindGroup(0,r),a.dispatchWorkgroups(Math.ceil(o.bodyCount/64)),a.end(),e.queue.submit([s.finish()])}var ac=`
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 xu=`
2923
2923
  fn contactGeneration(value: f32) -> u32 {
2924
2924
  return select(0u, bitcast<u32>(value) ^ 0x3f800000u, value != 0.0);
2925
2925
  }
@@ -2927,9 +2927,9 @@ fn contactMovedAfter(value: f32, generated: u32) -> bool {
2927
2927
  let age = (contactGeneration(value) - generated) & 0x07ffffffu;
2928
2928
  return age != 0u && age < 0x04000000u;
2929
2929
  }
2930
- `;function yn(o){let e="bodies[i].inertialPos.w = bitcast<f32>(params.step);";if(!o.includes(e))throw Error("Contact reference layout changed");return o.replace(e,"bodies[i].inertialPos.w = bitcast<f32>((params.step & 0x07ffffffu) ^ 0x3f800000u);")}function qo(o){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(!o.includes(e))throw Error("Contact cache layout changed");return ac+o.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 nc=`${ae}
2930
+ `;function bl(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 Vn(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 xu+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 wu=`${Ae}
2933
2933
  struct Config { count:u32, joints:u32, capacity:u32, list:u32, threshold:f32, dt:f32, pad0:u32, pad1:u32 }
2934
2934
  struct Velocity { incoming:vec4f, incomingAngular:vec4f, linear:vec4f, angular:vec4f }
2935
2935
  struct Bounce { impulse:f32, delta:f32, reboundSpeed:f32, inverseMass:f32, rA:vec4f, rB:vec4f }
@@ -3005,7 +3005,7 @@ fn pointVelocity(i:u32,r:vec3f,incoming:bool)->vec3f {
3005
3005
  let i=id.x;if(i>=cfg.count || bodies[i].size.w<=0.){return;}
3006
3006
  bodies[i].vel=velocities[i].linear;bodies[i].angVel=velocities[i].angular;
3007
3007
  }
3008
- `,Vi=class{constructor(e,{code:t=nc,dimension:i=3}={}){this.solver=e,this.dimension=i,this.device=e.device,this.active=new Set;let r=this.device,s=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST;this.materials=r.createBuffer({size:e.bodyCapacity*4,usage:s}),this.velocities=r.createBuffer({size:e.bodyCapacity*64,usage:s}),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 a=r.createShaderModule({code:t}),n=r.createPipelineLayout({bindGroupLayouts:[this.layout]});this.pipes=Object.fromEntries(["captureIncoming","captureSolved","initialize","pairs","apply","writeBack"].map(l=>[l,r.createComputePipeline({layout:n,compute:{module:a,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),Q(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 s=[this.params,e.bodyBuffer,this.velocities,this.materials,i.manifolds,i.contacts,e.adjBuffer,i.counters,this.bounce];(!this.buffers||s.some((n,l)=>n!==this.buffers[l]))&&(this.buffers=s,this.group=t.createBindGroup({layout:this.layout,entries:s.map((n,l)=>({binding:l,resource:{buffer:n}}))}));let a=new Uint32Array([e.bodyCount,e.jointCount,r,2*e.bodyCapacity+1,0,0,0,0]);new Float32Array(a.buffer).set([1,e.params.dt],4),t.queue.writeBuffer(this.params,0,a)}run(e,t){this.bind();let i=t??this.device.createCommandEncoder(),r=i.beginComputePass();r.setBindGroup(0,this.group);for(let s of e)r.setPipeline(this.pipes[s]),r.dispatchWorkgroups(Math.max(1,Math.ceil((s==="initialize"||s==="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 vn=new WeakMap,Wo=o=>vn.get(o);function Wi(o,e){vn.set(o,e)}var Vo=(o,e,t)=>{if(o.split(e).length!==2)throw Error("Pinned angular solver layout changed");return o.replace(e,t)};function Ho(o){return o=Vo(o,"fn addJoint(acc: ptr<function, Acc>, j: u32, alpha: f32, i: u32) {",`
3008
+ `;var vr=class{constructor(e,{code:t=wu,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 yl=new WeakMap,Xr=s=>yl.get(s);function Ar(s,e){yl.set(s,e)}var Wn=(s,e,t)=>{if(s.split(e).length!==2)throw Error("Pinned angular solver layout changed");return s.replace(e,t)};function Hn(s){return s=Wn(s,"fn addJoint(acc: ptr<function, Acc>, j: u32, alpha: f32, i: u32) {",`
3009
3009
  fn angularFrame(k:Joint,a:i32,b:i32)->mat3x3f {
3010
3010
  let qa=rotA(a);let axis=qrotate(qa,k.rA.xyz);
3011
3011
  let ta=qrotate(qa,k.c0Lin.xyz);let tb=qrotate(bodies[b].rot,k.c0Ang.xyz);
@@ -3056,10 +3056,10 @@ fn dualAngular(j:u32){
3056
3056
  }
3057
3057
  `+`
3058
3058
  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;}`),o=Vo(o," if (j >= params.jointCount || info[j].x != T_JOINT) { return; }",` if(j>=params.jointCount){return;}
3059
+ if(info[j].x==3 || info[j].x==4){if(joints[j].penLin.w!=0.){addAngular(acc,j,alpha,i);}return;}`),s=Wn(s," if (j >= params.jointCount || info[j].x != T_JOINT) { return; }",` if(j>=params.jointCount){return;}
3060
3060
  if(info[j].x==3 || info[j].x==4){warmAngular(j);return;}
3061
- if(info[j].x!=T_JOINT){return;}`),Vo(o,"fn dualJoint(j: u32) {",`fn dualJoint(j: u32) {
3062
- if(info[j].x==3 || info[j].x==4){dualAngular(j);return;}`)}function gt({type:o,axisA:e=[0,1,0],axisB:t=[0,1,0],speed:i=1,maxTorque:r=100,minAngle:s=-Math.PI,maxAngle:a=Math.PI}={}){let n=l=>{let c=l&&typeof l.x=="number"?[l.x,l.y,l.z]:Array.from(l),f=Math.hypot(...c);if(c.length!==3||!c.every(Number.isFinite)||f<1e-8)throw Error("Angular axis requires three finite, nonzero components");return c.map(u=>u/f)};if(o!=="motor"&&o!=="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(s)||!Number.isFinite(a)||s<-Math.PI||a>Math.PI||s>a)throw Error("Hinge angles must be ordered within -PI..PI radians");return{type:o,axisA:n(e),axisB:n(t),speed:i,maxTorque:r,minAngle:s,maxAngle:a}}var xn=`struct Body { pos:vec4f,rot:vec4f,initialPos:vec4f,initialRot:vec4f,size:vec4f,moment:vec4f,inertialPos:vec4f,inertialRot:vec4f,velocity:vec4f,angular:vec4f }
3061
+ if(info[j].x!=T_JOINT){return;}`),Wn(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 vl=`struct Body { pos:vec4f,rot:vec4f,initialPos:vec4f,initialRot:vec4f,size:vec4f,moment:vec4f,inertialPos:vec4f,inertialRot:vec4f,velocity:vec4f,angular:vec4f }
3063
3063
  struct Joint {penLin:vec4f,penAng:vec4f,lamLin:vec4f,lamAng:vec4f,c0Lin:vec4f,c0Ang:vec4f,rA:vec4f,rB:vec4f}
3064
3064
  @group(0) @binding(0) var<storage,read> bodies:array<Body>;
3065
3065
  @group(0) @binding(1) var<storage,read_write> joints:array<Joint>;
@@ -3077,7 +3077,7 @@ fn rotate(q:vec4f,v:vec3f)->vec3f{let t=2.*cross(q.xyz,v);return v+q.w*t+cross(q
3077
3077
  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
3078
  joints[j].c0Lin=vec4f(tangent,0.);joints[j].c0Ang=vec4f(normalize(tangentB),0.);
3079
3079
  }
3080
- `;var An=new WeakSet,cs=o=>An.has(o);function Hi(o,e,t,i=1,r=.6,s=[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 a=new De(o,[2*e,t,2*e],i,r,s),n=t-2*e,l=Math.PI*e*e*n*i,c=4/3*Math.PI*e**3*i;a.mass=l+c;let f=l*e**2/2+c*2*e**2/5,u=l*(n**2/12+e**2/4)+c*(2*e**2/5+n**2/4+3*n*e/8);return a.moment.set([u,f,u]),a.radius=t/2,An.add(a),a}var Bn=`// Exact rounded capsule geometry. Shape -1: radius=size.x/2, segment along Y,
3080
+ `;var Al=new WeakSet,He=s=>Al.has(s);function xr(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,Al.add(n),n}var xl=`// Exact rounded capsule geometry. Shape -1: radius=size.x/2, segment along Y,
3081
3081
  // half-length=size.y/2-radius. No tessellation, endpoint-only collision test,
3082
3082
  // shape storage buffer or iterative support search for capsule/sphere/box.
3083
3083
  struct Capsule {a:vec3f,b:vec3f,r:f32}
@@ -3128,7 +3128,12 @@ fn capSegmentBox(a:vec3f,b:vec3f,h:vec3f)->SegmentPair{
3128
3128
  let lo=breaks[j];let hi=breaks[j+1u];let mid=.5*(lo+hi);let p=a+mid*d;var numerator=0.;var denominator=0.;
3129
3129
  for(var k=0u;k<3u;k++){if(p[k]<-h[k]||p[k]>h[k]){let edge=clamp(p[k],-h[k],h[k]);numerator+=d[k]*(a[k]-edge);denominator+=d[k]*d[k];}}
3130
3130
  var t=mid;if(denominator>1.e-20){t=clamp(-numerator/denominator,lo,hi);}let point=a+t*d;let box=clamp(point,-h,h);let dist=dot(point-box,point-box);
3131
- if(dist<best-1.e-12 || (abs(dist-best)<=1.e-12&&abs(t-.5)<abs(bestT-.5))){best=dist;bestT=t;result=SegmentPair(point,box);}
3131
+ // An exact segment/box intersection must win over a nearby exterior
3132
+ // sample. A distance tie alone can select roundoff-sized separation and
3133
+ // normalize it into an arbitrary contact normal.
3134
+ let exactIntersection=dist==0.;let previousIntersection=best==0.;
3135
+ if((exactIntersection&&!previousIntersection)||dist<best-1.e-12 ||
3136
+ (exactIntersection==previousIntersection&&abs(dist-best)<=1.e-12&&abs(t-.5)<abs(bestT-.5))){best=dist;bestT=t;result=SegmentPair(point,box);}
3132
3137
  }
3133
3138
  return result;
3134
3139
  }
@@ -3156,16 +3161,16 @@ fn capsuleBox(A:Capsule,B:Box,q:vec4f,sat:ptr<function,Sat>)->Found{
3156
3161
  if(ends.count==2u){return ends;}
3157
3162
  addFound(&found,B.c+qrotate(q,center)+n*A.r,B.c+qrotate(q,onBox),4u<<24u);return found;
3158
3163
  }
3159
- `;function wn(o){if(o.includes("fn capsuleOf"))throw Error("Capsule collision kernel installed twice");let e=`@compute @workgroup_size(64)
3160
- fn narrowphase`;if(!o.includes(e))throw Error("Pinned capsule narrowphase layout changed");let t=o.includes("struct Poly");t&&(o=o.replace(e,uc+`
3161
- `+e)),o=o.replace(e,Bn+`
3162
- `+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 o.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.;
3164
+ `;function wl(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,Su+`
3166
+ `+e)),s=s.replace(e,xl+`
3167
+ `+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.;
3163
3168
  if(capsuleA || capsuleB){
3164
3169
  if(capsuleA && capsuleB){found=capsuleCapsule(capsuleOf(a),capsuleOf(b),&sat);}
3165
3170
  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);}}
3166
3171
  else{if(sphereA){found=capsuleSphere(capsuleOf(b),A.c,A.h.x,&sat);}${r} else{found=capsuleBox(capsuleOf(b),A,bodies[a].rot,&sat);}
3167
3172
  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;}}
3168
- } else if (sphereA && sphereB) {`)}var uc=`
3173
+ } else if (sphereA && sphereB) {`)}var Su=`
3169
3174
  fn capPolyAxis(A:Capsule,P:Poly,axis:vec3f,best:ptr<function,f32>,normal:ptr<function,vec3f>)->bool{
3170
3175
  let l=length(axis);if(l<1.e-8){return true;}let n=axis/l;
3171
3176
  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;
@@ -3197,7 +3202,7 @@ fn capsulePoly(A:Capsule,P:Poly,sat:ptr<function,Sat>)->Found{
3197
3202
  }
3198
3203
  (*sat).n=n;addFound(&found,points.a+n*A.r,points.b,4u<<24u);return found;
3199
3204
  }
3200
- `;var Jo=`// GPU queries against current poses. Rounded box/hull sweeps test offset faces
3205
+ `;var Jn=`// GPU queries against current poses. Rounded box/hull sweeps test offset faces
3201
3206
  // and rounded edges, so expanding a bounding box cannot create corner hits.
3202
3207
  struct Query { origin:vec4f, direction:vec4f }
3203
3208
  struct Params { head:vec4u, flags:vec4u, ignored:array<vec4u,4> }
@@ -3351,7 +3356,7 @@ fn nearest(@builtin(global_invocation_id) id:vec3u){if(id.x>=params.head.x||igno
3351
3356
  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);}}
3352
3357
  @compute @workgroup_size(64)
3353
3358
  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.);}
3354
- `;var Nt=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?Jo.replace("const DIM=3u;","const DIM=2u;").replace("const STRIDE=10u;","const STRIDE=6u;"):Jo});this.layout=i.createBindGroupLayout({entries:["read-only-storage","read-only-storage","read-only-storage","storage","storage","uniform","read-only-storage"].map((a,n)=>({binding:n,visibility:GPUShaderStage.COMPUTE,buffer:{type:a}}))});let s=i.createPipelineLayout({bindGroupLayouts:[this.layout]});this.pipes=Object.fromEntries(["nearest","owner","finish"].map(a=>[a,i.createComputePipeline({layout:s,compute:{module:r,entryPoint:a}})])),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[s,a,n]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[s]?.destroy(),i[s]=this.solver.device.createBuffer({size:a,usage:n|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}={}){if(this.destroyed)throw Error("GPU queries have been destroyed");let s=this.solver,a=s.device,n=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(u=>!Number.isInteger(u)||u<0||u>=s.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 l=e.map(u=>{let d=Array.from(u.origin),p=Array.from(u.direction),m=u.radius??0,h=u.maxDistance??3e38;if(d.length!==n||p.length!==n||![...d,...p].every(Number.isFinite)||Math.hypot(...p)===0)throw Error(`A query requires ${n} finite components and a nonzero direction`);if(!Number.isFinite(m)||m<0||!Number.isFinite(h)||h<0)throw Error("Query radius and maximum distance must be finite and nonnegative");let b=Math.hypot(...p);return{origin:d,direction:p.map(y=>y/b),radius:m,maxDistance:h}});if(!l.length)return[];let c=l.length,f=this.acquire(c);try{let u=f.data;l.forEach((k,z)=>{u.set([...k.origin,...Array(3-n).fill(0),k.maxDistance,...k.direction,...Array(3-n).fill(0),k.radius],z*8)});let d=f.params;d.fill(0),d.set([s.bodyCount,c,t.length,i,r?0:1,n===3||s.filters?1:0,s.sensorsEnabled?1:0,n===2&&s.shapeBuffer?1:0]),d.set(t,8);let p=f.initial;for(let k=0;k<c;k++)p.set([2139095040,4294967295],k*2);let{queryBuffer:m,best:h,hits:b,uniform:y,read:v}=f;a.queue.writeBuffer(m,0,u.buffer,0,c*32),a.queue.writeBuffer(h,0,p.buffer,0,c*8),a.queue.writeBuffer(y,0,d);let w=[s.bodyBuffer,n===3?s.hullStorage:s.shapeBuffer??this.dummy,m,h,b,y,n===3?s.filterStorage:s.filters??this.dummy];(!f.buffers||w.some((k,z)=>k!==f.buffers[z]))&&(f.group=a.createBindGroup({layout:this.layout,entries:w.map((k,z)=>({binding:z,resource:{buffer:k}}))}),f.buffers=w);let g=a.createCommandEncoder(),A=g.beginComputePass();A.setBindGroup(0,f.group);for(let k of["nearest","owner"])A.setPipeline(this.pipes[k]),A.dispatchWorkgroups(Math.ceil(s.bodyCount/64),c);A.setPipeline(this.pipes.finish),A.dispatchWorkgroups(Math.ceil(c/64)),A.end(),g.copyBufferToBuffer(b,0,v,0,c*32),a.queue.submit([g.finish()]),await v.mapAsync(GPUMapMode.READ,0,c*32);let x=v.getMappedRange(0,c*32),B=new Float32Array(x),E=new Uint32Array(x);return l.map((k,z)=>{let M=B[z*8+3];if(M<0)return null;let P=Array.from(B.slice(z*8,z*8+n)),_=k.origin.map((C,S)=>C+M*k.direction[S]);return{index:E[z*8+4],distance:M,normal:P,center:_,point:_.map((C,S)=>C-k.radius*P[S])}})}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(o,e){let t=this.passConstantCache??={alphas:[]},i=t.iterations!==o||t.colors!==this.colorCap||t.buffer!==this.passBuffer||!this.passGroup;for(let n=0;n<o;n++){let l=typeof e=="function"?e(n):e;t.alphas[n]!==l&&(i=!0),t.alphas[n]=l}if(!i)return;let r=this.colorCap+1,s=Math.max(o*r,1),a=s*256;(s>this.passEntries||!this.passGroup)&&(this.passBuffer?.destroy(),this.passBuffer=this.device.createBuffer({label:"AVBD pass constants",size:a,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),this.passEntries=s,this.passGroup=this.device.createBindGroup({layout:this.layouts.pass,entries:[{binding:0,resource:{buffer:this.passBuffer,size:16}}]})),(!t.data||t.data.byteLength<a)&&(t.data=new ArrayBuffer(Math.max(a,(t.data?.byteLength??0)*2)),t.u32=new Uint32Array(t.data),t.f32=new Float32Array(t.data));for(let n=0;n<o;n++)for(let l=0;l<=this.colorCap;l++){let c=(n*r+l)*256/4;t.u32[c]=l,t.f32[c+1]=t.alphas[n]}this.device.queue.writeBuffer(this.passBuffer,0,t.data,0,a),t.iterations=o,t.colors=this.colorCap,t.buffer=this.passBuffer,t.uploads=(t.uploads??0)+1}var $o=new WeakMap;function fs(o){return $o.get(o)}function Cn(o,e){e?$o.set(o,Object.freeze({...e})):$o.delete(o)}function Xo(o){let e=o.indexOf("/** A partial system per body slot handed between lanes (primal). */"),t=o.indexOf("fn accumulate(",e),i=o.lastIndexOf("/**",t);if(e<0||t<0||i<=e)throw Error("3D primal layout changed; review the compatibility kernel");return o.slice(0,e)+`
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?Jn.replace("const DIM=3u;","const DIM=2u;").replace("const STRIDE=10u;","const STRIDE=6u;"):Jn});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 Ws(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 $n=new WeakMap;function Hs(s){return $n.get(s)}function Bl(s,e){e?$n.set(s,Object.freeze({...e})):$n.delete(s)}function Xn(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)+`
3355
3360
  @compute @workgroup_size(64)
3356
3361
  fn primal(@builtin(global_invocation_id) gid: vec3u) {
3357
3362
  let start = color[params.colorStartOffset + pc.color];
@@ -3361,18 +3366,18 @@ fn primal(@builtin(global_invocation_id) gid: vec3u) {
3361
3366
  finishBody(i, accumulate(i, 0u, 1u));
3362
3367
  }
3363
3368
 
3364
- `+o.slice(i)}function qt(o,e,t){if(o.split(e).length!==2)throw Error("3D contact layout changed; review the compatibility kernel");return o.replace(e,t)}function ds(o,e,t){let i=new RegExp(`struct ${e} \\{[^}]*\\}`,"g");if([...o.matchAll(i)].length!==1)throw Error(`Expected one 3D ${e} layout`);return o.replace(i,t)}function Sn(o,e,t){let i=`fn ${e}(`;if(o.split(i).length!==2)throw Error(`Expected one 3D ${e} function`);let r=o.indexOf(i),a=o.indexOf("{",r)+1,n=1;for(;a<o.length&&n;a++)o[a]==="{"&&n++,o[a]==="}"&&n--;if(n)throw Error(`Incomplete 3D ${e} function`);return o.slice(0,r)+t(o.slice(r,a))+o.slice(a)}function Yo(o){o=ds(o,"PairBody",`struct PairBody {
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 Js(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 Cl(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 Yn(s){s=Js(s,"PairBody",`struct PairBody {
3365
3370
  ids: vec4u,
3366
3371
  rot: vec4f,
3367
3372
  dLin: vec4f,
3368
3373
  dAng: vec4f,
3369
- }`),o=qt(o,"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));"),o=o.replace(/\b(A|B)\.index\b/g,"$1.ids.x").replace(/\b(A|B)\.(dLin|dAng)\b/g,"$1.$2.xyz"),o=ds(o,"Contact",`struct Contact {
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=Js(s,"Contact",`struct Contact {
3370
3375
  anchorA: vec4u, // xyz: float bits, w: integer feature key
3371
3376
  anchorB: vec4f, // xyz: anchor, w: normal error
3372
3377
  penalty: vec4f, // xyz: penalties, w: first tangent error
3373
3378
  force: vec4f, // xyz: forces, w: second tangent error
3374
- }`);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"])o=Sn(o,t,i=>i.replace(/\bk\.(rA|rB|key|c0x|c0y|c0z|pen|lam)\b/g,(r,s)=>e[s]));return o=qt(o,"contacts[c].lam = e.F;","contacts[c].force = vec4f(e.F, k.force.w);"),o=qt(o,"contacts[c].key =","contacts[c].anchorA.w ="),o=qt(o,"contacts[c].pen = pen;","contacts[c].penalty = vec4f(pen, k.penalty.w);"),o=Sn(o,"evalContact",t=>{t=qt(t,` var e: ContactEval;
3375
- `,""),t=qt(t," e.rAW ="," let rAW ="),t=qt(t," e.rBW ="," let rBW ="),t=t.replaceAll("e.rAW","rAW").replaceAll("e.rBW","rBW"),t=qt(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;
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=Cl(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=Cl(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;
3376
3381
  let normalForce = select(0.0, raw.x, raw.x < 0.0);
3377
3382
  let bounds = abs(normalForce) * friction;
3378
3383
  let frictionScale = length(raw.yz);
@@ -3383,23 +3388,23 @@ fn primal(@builtin(global_invocation_id) gid: vec3u) {
3383
3388
  let force = vec3f(normalForce, raw.yz * scale);
3384
3389
  return ContactEval(vec4f(rAW, 0.0), vec4f(rBW, 0.0),
3385
3390
  vec4f(C, 0.0), vec4f(force, 0.0), vec4f(frictionScale, bounds, 0.0, 0.0));
3386
- }`}),o=ds(o,"ContactEval",`struct ContactEval {
3391
+ }`}),s=Js(s,"ContactEval",`struct ContactEval {
3387
3392
  rAW: vec4f,
3388
3393
  rBW: vec4f,
3389
3394
  C: vec4f,
3390
3395
  F: vec4f,
3391
3396
  limits: vec4f, // x: tangent force length, y: Coulomb bound
3392
- }`),o=o.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"),o=ds(o,"PassConstants","struct PassConstants { data: vec4u, }"),o.replaceAll("pc.color","pc.data.x").replaceAll("pc.alpha","bitcast<f32>(pc.data.y)")}function Qo(o){if(!o.includes("struct Poly"))return o;let e=`@compute @workgroup_size(64)
3393
- fn narrowphase(@builtin(global_invocation_id) gid: vec3u)`;if(o.split(e).length!==2)throw Error("3D hull narrowphase changed; review the compatibility kernel");return o.replace(e,"fn narrowphasePair(gid: vec3u)")+`
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=Js(s,"PassConstants","struct PassConstants { data: vec4u, }"),s.replaceAll("pc.color","pc.data.x").replaceAll("pc.alpha","bitcast<f32>(pc.data.y)")}function Qn(s){if(!s.includes("struct Poly"))return s;let e=`@compute @workgroup_size(64)
3398
+ 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)")+`
3394
3399
  @compute @workgroup_size(32)
3395
3400
  fn narrowphase(@builtin(global_invocation_id) gid: vec3u) {
3396
3401
  for (var offset = 0u; offset < 2u; offset++) {
3397
3402
  narrowphasePair(vec3u(gid.x * 2u + offset, 0u, 0u));
3398
3403
  }
3399
3404
  }
3400
- `}var Vt=class extends rs{writePassConstants(e,t){us.call(this,e,t)}constructor(e,t,i={}){let r=fs(e),s=i.scalarPrimal??r?.scalarPrimal??!1,a=i.portableContactMath??r?.portableContactMath??!1,n=t.forces.some(b=>Wo(b)),l=t.forces.some(b=>{let y=Go(b);return y&&(Number.isFinite(y.breakStrain)||Number.isFinite(y.breakForce))}),c={requested:i.solverMode??"auto",contactScheduling:i.contactScheduling??"manifolds",custom:!!i.shaders?.solve},f=qi({...c,bodyCount:t.bodies.length,constraintCount:t.forces.filter(b=>b instanceof Be||b instanceof ct).length}),u=f.selected==="custom"?i.shaders.solve:f.selected==="optimized"?br:f.selected==="points"?ss: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[b,y]of[["minimumColors",64],["minimumColorRounds",32]]){let v=i[b]??0;if(!Number.isInteger(v)||v<0||v>y)throw Error(`${b} must be an integer between 0 and ${y}`);if(b==="minimumColorRounds"&&v%2)throw Error("minimumColorRounds must be even")}let m=Oo(jo(n?Ho(l?as(u??be):u??be):l?as(u??be):u??be));s&&(m=Xo(m)),a&&(m=Yo(m));let h=a&&!i.shaders?.contacts&&i.hulls!==!1&&e.limits.maxStorageBuffersPerShaderStage>=9&&t.bodies.some(b=>Nr(b));if(super(e,t,{...i,shaders:{...i.shaders,contacts:h?Qo(ui(!0)):i.shaders?.contacts,solve:m}}),this.solverPolicy=c,this.scalarPrimal=s,this.portableContactMath=a,s&&(this.primalLanes=[1,1,1]),this.dispatchIsolation=r?.dispatchIsolation??!1,!i.shaders?.contacts){h&&(this.contactShaders.custom=!1,this.hullShaders=!0);let b=this.contactShaders.make;this.contactShaders.make=y=>b(a?Qo(qo(y)):qo(y)),this.contactShaders.make(ui(this.hullShaders??!1)),this.pipes.updateRefs=e.createComputePipeline({label:"Portable contact references",layout:e.createPipelineLayout({bindGroupLayouts:[this.layouts.refs]}),compute:{module:e.createShaderModule({code:yn(es)}),entryPoint:"updateRefs"}})}this.springFracture=l,this.angularConstraints=n,this.customSolveSource=i.shaders?.solve,t.forces.forEach((b,y)=>{let v=Go(b);v&&this.setSpringMaterial(y,v)}),this.adaptiveScheduling=s?!1:i.adaptiveScheduling??!0,this.defaultPrimalLanes=[...this.primalLanes],this.cacheAdjacencyKeys=i.cacheAdjacencyKeys,this.adjacencyPipelines={original:this.pipes.sortAdjacency},this.selectAdjacencyPipeline(),this.solverDecision=f,this.solvePipelineCache=new Map([[f.selected,Object.fromEntries(["warmStartJoints","warmStartBodies","primal","dual","updateVelocities"].map(b=>[b,this.pipes[b]]))]]),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((b,y)=>{let v=Wo(b);v&&this.setAngularConstraint(y,v)}),t.bodies.forEach((b,y)=>{cs(b)&&this.installCapsule(this.gpuIndex(y))})}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(wn(i)),this.contactShaders.make(ui(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 Nt(this),this.shapeQueries.cast(e.map(i=>({...i,radius:0})),t)}async sphereCast(e,t,i,r={}){let[s]=await this.sphereCastAll([{origin:e,radius:t,direction:i,maxDistance:r.maxDistance}],r);return s}sphereCastAll(e,t={}){return this.flushPropertyEdits(),this.shapeQueries??=new Nt(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,b]=p.size,y=Math.min(m,h,b),v=Math.max(m,h,b),w=m+h+b-y-v;!p.sphere&&!p.hull&&y<=.4*w&&w>=.5*v&&r++}}let s=t?ts(e.subarray(0,t),t>>1):1,a=this.cellSize/(2*s),n=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,f=n>=this.bodyCount&&l>=.25,u=c&&this.bodyCount>=1e4&&(a>=4||f);this.broadphase=u?"hploc":"grid",this.broadphaseDecision={requested:"auto",selected:this.broadphase,bodyCount:this.bodyCount,cellRatio:a,constraintCount:n,thinPlateFraction:l,reason:c?u?f?"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 ls(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?fn(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 Vi(this)),this.restitution?.set(e,t),this.wakeAll()}setSolverMode(e){return qi({...this.solverPolicy,requested:e,bodyCount:this.bodyCount}),this.solverPolicy.requested=e,this.selectSolver(),this.solverDecision}solveSource(e){return this.springFracture&&(e=as(e)),this.angularConstraints&&(e=Ho(e)),this.sensorsEnabled&&(e=mn(e)),e=Oo(jo(e)),this.scalarPrimal&&(e=Xo(e)),this.portableContactMath&&(e=Yo(e)),e}setAngularConstraint(e,t){if(!Number.isInteger(e)||e<0||e>=this.jointCount)throw Error("Angular constraint needs a live slot");let i=gt(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;
3401
- ${xn.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&&Q(this).float(this.jointBuffer,e*32+27,t),i!==void 0&&Q(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"?br:e==="points"?ss:be,i=this.device.createShaderModule({code:this.solveSource(t)}),r=this.device.createPipelineLayout({bindGroupLayouts:[this.layouts.solve,this.layouts.pass]}),s=Object.fromEntries(["warmStartJoints","warmStartBodies","primal","dual","updateVelocities"].map(a=>[a,this.device.createComputePipeline({layout:r,compute:{module:i,entryPoint:a}})]));Object.assign(this.pipes,s),this.solvePipelineCache.set(e,s)}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,gn(this),this.rebuildSolvePipelines(),this.contactShaders.make(No(ui(this.hullShaders??!1)));let i=this.contactShaders.make;this.contactShaders.make=a=>i(No(a));let r=this.device.createShaderModule({code:bn()}),s=this.device.createPipelineLayout({bindGroupLayouts:[this.layouts.topo]});for(let a of["degreeContacts","fillContacts"])this.pipes[a]=this.device.createComputePipeline({layout:s,compute:{module:r,entryPoint:a}})}this.sensorsEnabled&&Q(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=qi({...this.solverPolicy,bodyCount:this.bodyCount,constraintCount:e});if(i.selected!==t.selected){let r=this.solvePipelineCache.get(i.selected);if(!r){let s=i.selected==="optimized"?br:i.selected==="points"?ss:void 0,a=this.device.createShaderModule({code:this.solveSource(s??be)}),n=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:n,compute:{module:a,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;
3402
- ${an.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 s=this.device,a=(this.captureUploads??={})[e]??={};(!a.buffer||a.buffer.size<i.byteLength)&&(a.buffer?.destroy(),a.buffer=s.createBuffer({size:i.byteLength*2,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),a.buffers=null),s.queue.writeBuffer(a.buffer,0,i);let n=[this.bodyBuffer,this.jointBuffer,this.infoBuffer,a.buffer];(!a.buffers||n.some((d,p)=>d!==a.buffers[p])||a.bytes!==i.byteLength)&&(a.group=s.createBindGroup({layout:t.getBindGroupLayout(0),entries:n.map((d,p)=>({binding:p,resource:{buffer:d,...p===3?{size:i.byteLength}:{}}}))}),a.buffers=n,a.bytes=i.byteLength);let l=s.createCommandEncoder(),c=l.beginComputePass();c.setPipeline(t),c.setBindGroup(0,a.group);let f=Math.ceil(r/64),u=s.limits.maxComputeWorkgroupsPerDimension;c.dispatchWorkgroups(Math.min(f,u),Math.ceil(f/u)),c.end(),s.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]!==Ui)throw Error("Spring material requires an active spring slot");let i=Pt(t);!this.springFracture&&(Number.isFinite(i.breakStrain)||Number.isFinite(i.breakForce))&&(this.springFracture=!0,this.rebuildSolvePipelines());for(let[r,s]of[["breakStrain",11],["breakForce",15]])Q(this).float(this.jointBuffer,e*32+s,i[r]===1/0?0:i[r]);this.wakeAll()}appendConstraints(...e){return this.flushPropertyEdits(),super.appendConstraints(...e)}appendJoint(e,t,i,r,s,a){let n=c=>c===1/0?3e38:c,[l]=this.appendConstraints(1,(c,f)=>{f[3]=n(s),f[7]=n(a),f[11]=3e38,f.set(i,24),f.set(r,28);let u=e>=0?this.bodies[e].size:[0,0,0],d=this.bodies[t].size;return f[15]=u.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 hi({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++)cs(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++)cs(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++)Q(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 s=0;s<e.length;s++){if(!Number.isInteger(e[s])||e[s]<0||e[s]>=this.bodyCount)throw Error("Collision filters require live body indices");for(let a of[t[s],i[s]])if(!Number.isInteger(a)||a<0||a>4294967295)throw Error("Collision masks must be unsigned 32-bit integers")}let r=Q(this);for(let s=0;s<e.length;s++)r.uint(this.filterBuffer,e[s]*2,t[s]),r.uint(this.filterBuffer,e[s]*2+1,i[s]);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:pn}),entryPoint:"sortAdjacency"}})),this.pipes.sortAdjacency=e?this.adjacencyPipelines.cached:this.adjacencyPipelines.original,this.adjacencyCached=e)}};var Ko=new WeakMap,kn=[{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 Pn(o){return Ko.has(o)||Ko.set(o,dc(o)),Ko.get(o)}async function dc(o,e){let t=[];for(let i of kn){let r=await gc(o,i,e);if(t.push(r),!!r.passed)return Cn(o,{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!==kn[0].name,attempts:t}}return{...t[0],selected:null,compatibility:!1,attempts:t}}function hc(o){let e=new jt;return e.iterations=5,o||(e.gravity=0),new De(e,[16,.25,16],0,.6,[0,-.125,0]),new De(e,[1,1,1],1,.6,[-2,o?2:.45,0]),Mi(e,.5,1,.6,[0,o?2.3:.45,0]),Hi(e,.25,1.6,1,.6,[2,o?2.5:.75,0]),e}async function Wt(o,e,t=e.size){let i=o.createBuffer({size:t,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST});try{let r=o.createCommandEncoder();return r.copyBufferToBuffer(e,0,i,0,t),o.queue.submit([r.finish()]),await i.mapAsync(GPUMapMode.READ),i.getMappedRange().slice(0)}finally{i.destroy()}}async function pc(o){o.step();let e=await o.readCounters(),t=new Uint32Array(await Wt(o.device,o.argsBuffer)),i=await bc(o),r=new Uint32Array(i),s=new Float32Array(i),a=new Uint32Array(await Wt(o.device,o.adjBuffer)),n=new Uint32Array(await Wt(o.device,o.colorBuffer)),{manifolds:l,contacts:c}=o.contactStorage,f=await Wt(o.device,l,Math.max(32,e.manifolds*32)),u=new Uint32Array(f),d=new Float32Array(f),p=new Float32Array(await Wt(o.device,c,Math.max(64,e.contacts*64))),m=await o.readBodies(),h=e.manifolds>=3?await mc(o):[],b=h.some(({contactEvaluation:y})=>y.returnedForce===0&&y.independentForce<-1e-5);return{expectedFloorPairs:3,counters:e,pairs:e.pairs?Array.from(await o.readPairs()):[],narrowphaseWorkgroups:Array.from(t.subarray(0,3)),solver:{scalarPrimal:o.scalarPrimal,portableContactMath:o.portableContactMath,lanes:[...o.primalLanes],contactWorkgroups:Array.from(t.subarray(3,6)),dualWorkgroups:Array.from(t.subarray(9,12)),colorWorkgroups:Array.from(t.subarray(12,12+3*o.colorCap)),adjacencyStarts:Array.from(a.subarray(0,5)),adjacencyEntries:Array.from(a.subarray(2*o.bodyCapacity+1,2*o.bodyCapacity+1+a[4])),colorStarts:Array.from(n.subarray(2*o.bodyCapacity,2*o.bodyCapacity+o.colorCap+1)),colorBodies:Array.from(n.subarray(2*o.bodyCapacity+65,2*o.bodyCapacity+68)),positionsAfterOverlap:[1,2,3].map(y=>Array.from(m.subarray(y*40,y*40+3))),manifolds:Array.from({length:e.manifolds},(y,v)=>({ids:Array.from(u.subarray(v*8,v*8+4)),normalAndFriction:Array.from(d.subarray(v*8+4,v*8+8))})),contacts:Array.from({length:e.contacts},(y,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:b?"contact-evaluation":null},filters:Array.from(new Uint32Array(await Wt(o.device,o.filterBuffer))),params:{bodyCount:r[0],largeCount:r[1],noCollideCount:r[2],pairCapacity:r[3],contactCapacity:r[4],dt:s[5],cellSize:s[6],maxSmallRadius:s[7],up:Array.from(s.subarray(8,11)),alpha:s[11]},stage:e.pairs<3?"collision-pairs":e.manifolds<3?"contact-generation":"contacts-created"}}async function mc(o){let e=o.portableContactMath?"bitcast<f32>(pc.data.y)":"pc.alpha",t=o.portableContactMath?"k.anchorB.w":"k.c0x",i=o.portableContactMath?"k.penalty.x":"k.pen.x",r=o.portableContactMath?"k.force.x":"k.lam.x",s=o.device.createShaderModule({code:o.solveSource(be)+`
3405
+ `}var pi=class extends Gs{writePassConstants(e,t){Ws.call(this,e,t)}constructor(e,t,i={}){let r=Hs(e),o=i.scalarPrimal??r?.scalarPrimal??!1,n=i.portableContactMath??r?.portableContactMath??!1,a=t.forces.some(m=>Xr(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=yr({...c,bodyCount:t.bodies.length,constraintCount:t.forces.filter(m=>m instanceof ke||m instanceof ft).length}),f=u.selected==="custom"?i.shaders.solve:u.selected==="optimized"?$r:u.selected==="points"?Ns: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=jn(Dn(a?Hn(l?Us(f??ze):f??ze):l?Us(f??ze):f??ze));o&&(g=Xn(g)),n&&(g=Yn(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?Qn(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?Qn(Vn(b)):Vn(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:bl(js)}),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=Xr(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(wl(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?Ds(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 Vs(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?ul(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 vr(this)),this.restitution?.set(e,t),this.wakeAll()}setSolverMode(e){return yr({...this.solverPolicy,requested:e,bodyCount:this.bodyCount}),this.solverPolicy.requested=e,this.selectSolver(),this.solverDecision}solveSource(e){return this.springFracture&&(e=Us(e)),this.angularConstraints&&(e=Hn(e)),this.sensorsEnabled&&(e=pl(e)),e=jn(Dn(e)),this.scalarPrimal&&(e=Xn(e)),this.portableContactMath&&(e=Yn(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
+ ${vl.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"?$r:e==="points"?Ns: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,gl(this),this.rebuildSolvePipelines(),this.contactShaders.make(qn(Ti(this.hullShaders??!1)));let i=this.contactShaders.make;this.contactShaders.make=n=>i(qn(n));let r=this.device.createShaderModule({code:ml()}),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=yr({...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"?$r:i.selected==="points"?Ns: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
+ ${ol.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]!==mr)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:hl}),entryPoint:"sortAdjacency"}})),this.pipes.sortAdjacency=e?this.adjacencyPipelines.cached:this.adjacencyPipelines.original,this.adjacencyCached=e)}};var Kn=new WeakMap,Sl=[{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 kl(s){return Kn.has(s)||Kn.set(s,Pu(s)),Kn.get(s)}async function Pu(s,e){let t=[];for(let i of Sl){let r=await zu(s,i,e);if(t.push(r),!!r.passed)return Bl(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!==Sl[0].name,attempts:t}}return{...t[0],selected:null,compatibility:!1,attempts:t}}function Lu(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]),nr(e,.5,1,.6,[0,s?2.3:.45,0]),xr(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 _u(s){s.step();let e=await s.readCounters(),t=new Uint32Array(await mi(s.device,s.argsBuffer)),i=await Mu(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 Eu(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 Eu(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)+`
3403
3408
  @compute @workgroup_size(1) fn inspectSystems(@builtin(global_invocation_id) gid: vec3u) {
3404
3409
  let acc = accumulate(gid.x + 1u, 0u, 1u);
3405
3410
  joints[gid.x].penLin = vec4f(acc.lin[0][0], acc.lin[1][1], acc.lin[2][2], 0.0);
@@ -3423,7 +3428,7 @@ ${an.replaceAll("id.x","(id.x+id.y*DISPATCH_STRIDE)")}`}),entryPoint:"capture"}}
3423
3428
  let raw = ${i} * expectedC + ${r};
3424
3429
  joints[gid.x].rA = vec4f(${t}, ${e}, result.C.x, result.F.x);
3425
3430
  joints[gid.x].rB = vec4f(${i}, ${r}, expectedC, min(raw, 0.0));
3426
- }`}),a=o.device.createComputePipeline({layout:o.device.createPipelineLayout({bindGroupLayouts:[o.layouts.solve,o.layouts.pass]}),compute:{module:s,entryPoint:"inspectSystems"}}),n=o.device.createCommandEncoder(),l=n.beginComputePass();l.setPipeline(a),l.setBindGroup(0,o.groups.solve[1-o.parity]),l.setBindGroup(1,o.passGroup,[0]),l.dispatchWorkgroups(3),l.end(),o.device.queue.submit([n.finish()]);let c=new Float32Array(await Wt(o.device,o.jointBuffer,384));return[0,1,2].map(f=>({linearDiagonal:Array.from(c.subarray(f*32,f*32+3)),angularDiagonal:Array.from(c.subarray(f*32+4,f*32+7)),linearForce:Array.from(c.subarray(f*32+16,f*32+19)),angularForce:Array.from(c.subarray(f*32+20,f*32+23)),contactEvaluation:{inputGap:c[f*32+24],passAlpha:c[f*32+25],returnedError:c[f*32+26],returnedForce:c[f*32+27],inputPenalty:c[f*32+28],inputForce:c[f*32+29],independentError:c[f*32+30],independentForce:c[f*32+31]}}))}async function bc(o){let{device:e}=o,t=e.createBuffer({size:48,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC});try{let i=e.createComputePipeline({layout:"auto",compute:{module:e.createShaderModule({code:ae+`
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 Mu(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+`
3427
3432
  @group(0) @binding(0) var<uniform> p: Params;
3428
3433
  @group(0) @binding(1) var<storage,read_write> out: array<u32>;
3429
3434
  @compute @workgroup_size(1) fn inspectParams() {
@@ -3432,7 +3437,7 @@ ${an.replaceAll("id.x","(id.x+id.y*DISPATCH_STRIDE)")}`}),entryPoint:"capture"}}
3432
3437
  out[5]=bitcast<u32>(p.dt); out[6]=bitcast<u32>(p.cellSize); out[7]=bitcast<u32>(p.maxSmallRadius);
3433
3438
  out[8]=bitcast<u32>(p.up.x); out[9]=bitcast<u32>(p.up.y); out[10]=bitcast<u32>(p.up.z);
3434
3439
  out[11]=bitcast<u32>(p.alpha);
3435
- }`}),entryPoint:"inspectParams"}}),r=e.createBindGroup({layout:i.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:o.paramsBuffer}},{binding:1,resource:{buffer:t}}]}),s=e.createCommandEncoder(),a=s.beginComputePass();return a.setPipeline(i),a.setBindGroup(0,r),a.dispatchWorkgroups(1),a.end(),e.queue.submit([s.finish()]),await Wt(e,t)}finally{t.destroy()}}async function gc(o,e,t){let i={mode:e.name,passed:!1,steps:180,cases:[],errors:[],contactCache:"normal-float-generations-v1",diagnosticVersion:4,limits:{storageBindings:o.limits.maxStorageBuffersPerShaderStage,workgroupStorageBytes:o.limits.maxComputeWorkgroupStorageSize,workgroupInvocations:o.limits.maxComputeInvocationsPerWorkgroup,storageBindingBytes:o.limits.maxStorageBufferBindingSize}},r,s=a=>{let n=new Vt(o,hc(a),{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 n.params.up=[0,1,0],n.dispatchIsolation=e.dispatchIsolation,t?.(n,e,a),n};o.pushErrorScope("validation");try{if(r=s(!1),i.pipeline=await pc(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=s(!0);let a=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&&a++,c.overflow||c.clashes)throw Error("Incomplete GPU contact graph")}let n=await r.readBodies();for(let l=1;l<4;l++){let c=l*40,[f,u,d,p]=n.subarray(c+4,c+8),m=l===1?.5*(Math.abs(2*(f*u+p*d))+Math.abs(1-2*(f*f+d*d))+Math.abs(2*(u*d-p*f))):l===2?.5:.25+.55*Math.abs(1-2*(f*f+d*d)),h=n[c+1]-m,b=n.subarray(c,c+40).every(Number.isFinite);i.cases.push({shape:["floor","box","sphere","capsule"][l],passed:b&&h>=-.06&&h<.12,floorGap:h,position:Array.from(n.subarray(c,c+3))})}i.contactSteps=a,i.passed=a>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(a){i.errors.push(a.message)}finally{try{let a=await o.popErrorScope();a&&i.errors.push(a.message)}catch(a){i.errors.push(a.message)}r?.destroy()}return i.passed=i.passed&&!i.errors.length,i}async function hs(o={}){if(!globalThis.navigator?.gpu)throw Error("WebGPU needs a supported browser on localhost or HTTPS");let e=await navigator.gpu.requestAdapter({powerPreference:o.powerPreference??"high-performance"});if(!e)throw Error("No WebGPU adapter is available");let t={};for(let[r,s]of Object.entries(o.preferredLimits??{})){if(!r.startsWith("max")||e.limits[r]===void 0||!Number.isSafeInteger(s)||s<0)throw Error(`Invalid preferred GPU limit: ${r}`);t[r]=Math.min(s,e.limits[r])}for(let[r,s]of Object.entries(o.requiredLimits??{})){if(e.limits[r]===void 0||!Number.isSafeInteger(s)||s<0)throw Error(`Invalid required GPU limit: ${r}`);let a=e.limits[r];if(r.startsWith("min")&&s<a||!r.startsWith("min")&&s>a)throw Error(`GPU limit ${r} requires ${s}; this adapter supports ${a}`);t[r]=s}let i=await e.requestDevice({requiredLimits:t,requiredFeatures:e.features.has("timestamp-query")?["timestamp-query"]:[]});if(o.validate3D)try{await gr(i)}catch(r){throw i.destroy(),r}return{adapter:e,device:i}}async function gr(o){if(fs(o))return o;let e=await Pn(o);if(!e.passed)throw Error(`GPU 3D contact check failed: ${e.reason??e.errors.join("; ")}`);return o}var Ln=`struct Body { pos:vec4f,rot:vec4f,initialPos:vec4f,initialRot:vec4f,size:vec4f,moment:vec4f,inertialPos:vec4f,inertialRot:vec4f,velocity:vec4f,angular:vec4f }
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 zu(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,Lu(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 _u(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 wr(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 Ni(i)}catch(r){throw i.destroy(),r}return{adapter:e,device:i}}async function Ni(s){if(Hs(s))return s;let e=await kl(s);if(!e.passed)throw Error(`GPU 3D contact check failed: ${e.reason??e.errors.join("; ")}`);return s}var Pl=`struct Body { pos:vec4f,rot:vec4f,initialPos:vec4f,initialRot:vec4f,size:vec4f,moment:vec4f,inertialPos:vec4f,inertialRot:vec4f,velocity:vec4f,angular:vec4f }
3436
3441
  struct Command { index:u32,mask:u32,pad0:u32,pad1:u32,velocity:vec4f,angular:vec4f,impulse:vec4f,torque:vec4f,position:vec4f,rotation:vec4f,pointImpulse:vec4f }
3437
3442
  @group(0) @binding(0) var<storage,read_write> bodies:array<Body>;
3438
3443
  @group(0) @binding(1) var<storage,read> commands:array<Command>;
@@ -3454,37 +3459,37 @@ fn rotate(q:vec4f,v:vec3f)->vec3f {let t=2.*cross(q.xyz,v);return v+q.w*t+cross(
3454
3459
  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);}
3455
3460
  bodies[c.index]=b;
3456
3461
  }
3457
- `;var Lt=class{constructor(e,t,i="linear"){this.solver=e,this.dimension=t,this.components=i==="angular"&&t===2?1:t;let r=e.device,s=t===3?10:6,a=t===3?i==="angular"?9:8:3;this.pipeline=r.createComputePipeline({layout:"auto",compute:{entryPoint:"setVelocities",module:r.createShaderModule({code:`
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:`
3458
3463
  @group(0) @binding(0) var<storage,read_write> bodies:array<vec4f>;
3459
3464
  @group(0) @binding(1) var<storage,read> indices:array<u32>;
3460
3465
  @group(0) @binding(2) var<storage,read> velocities:array<f32>;
3461
3466
  @compute @workgroup_size(64) fn setVelocities(@builtin(global_invocation_id) id:vec3u) {
3462
3467
  let i=id.x+id.y*${r.limits.maxComputeWorkgroupsPerDimension*64}u;
3463
3468
  if(i>=arrayLength(&indices)){return;}
3464
- let base=indices[i]*${s}u+${a}u;
3469
+ let base=indices[i]*${o}u+${n}u;
3465
3470
  var v=bodies[base];
3466
3471
  ${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];":""}`}
3467
3472
  bodies[base]=v;
3468
- }`})}})}set(e,t){let i=this.solver,r=i.device,s=e instanceof Uint32Array?e:Uint32Array.from(e),a=t instanceof Float32Array?t:Float32Array.from(t);if(a.length!==s.length*this.components)throw Error(`Provide ${this.components} velocity components per body`);let n=-1;for(let c=0;c<e.length;c++){if(i.liveIndex(e[c]),e[c]<=n)throw Error("Velocity batch indices must be unique and ascending GPU slots");n=e[c]}for(let c of a)if(!Number.isFinite(c))throw Error("Velocities must be finite Float32 values");let l=Math.min(r.limits.maxStorageBufferBindingSize,r.limits.maxBufferSize);if(s.byteLength>l||a.byteLength>l)throw Error("Velocity batch exceeds GPU buffer limits");s.length&&(i.wakeAll(),i.flushEdits(),this.submitValidated(s,a))}submitValidated(e,t,i){if(!e.length)return;let r=this.solver,s=r.device,a=Math.min(s.limits.maxStorageBufferBindingSize,s.limits.maxBufferSize);if(e.byteLength>a||t.byteLength>a)throw Error("Velocity batch exceeds GPU buffer limits");for(let[u,d]of[["indices",e],["values",t]])(!this[u]||this[u].size<d.byteLength)&&(this[u]?.destroy(),this[u]=s.createBuffer({size:Math.min(a,d.byteLength*2),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST})),s.queue.writeBuffer(this[u],0,d);let n=i??s.createCommandEncoder(),l=n.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=s.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),f=s.limits.maxComputeWorkgroupsPerDimension;l.dispatchWorkgroups(Math.min(c,f),Math.ceil(c/f)),l.end(),i||s.queue.submit([n.finish()]),this.lastBatch={bodies:e.length,uploadedBytes:e.byteLength+t.byteLength}}destroy(){this.indices?.destroy(),this.values?.destroy()}},Ht=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,s=this.dimension,a=s===3?3:1,n=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!==n.length*s)throw Error(`Provide ${s} linear components per body`);if(c&&c.length!==n.length*a)throw Error(`Provide ${a} angular components per body`);let f=-1;for(let p=0;p<e.length;p++){if(r.liveIndex(e[p]),e[p]<=f)throw Error("Velocity batch indices must be unique and ascending GPU slots");f=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 u=n.length*this.wordsPerBody,d=Math.min(r.device.limits.maxStorageBufferBindingSize,r.device.limits.maxBufferSize);if(u*4>d)throw Error("Motion batch exceeds GPU buffer limits");if(u){(!this.data||this.data.length<u)&&(this.data=new Uint32Array(Math.max(u,(this.data?.length??0)*2)),this.floats=new Float32Array(this.data.buffer));for(let p=0;p<n.length;p++){let m=p*this.wordsPerBody;if(this.data[m]=n[p],this.data[m+1]=(l?1:0)|(c?2:0),l)for(let h=0;h<s;h++)this.floats[m+2+h]=l[p*s+h];if(c)for(let h=0;h<a;h++)this.floats[m+2+s+h]=c[p*a+h]}r.wakeAll(),r.flushEdits(),this.submitValidated(this.data.subarray(0,u))}}submitValidated(e,t){if(!e.length)return;let i=this.solver,r=i.device,s=this.wordsPerBody,a=Math.min(r.limits.maxStorageBufferBindingSize,r.limits.maxBufferSize);if(e.byteLength>a)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(a,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:`
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:`
3469
3474
  @group(0) @binding(0) var<storage,read_write> bodies:array<vec4f>;
3470
3475
  @group(0) @binding(1) var<storage,read> commands:array<u32>;
3471
3476
  @compute @workgroup_size(64) fn edit(@builtin(global_invocation_id) id:vec3u) {
3472
3477
  let i=id.x+id.y*${r.limits.maxComputeWorkgroupsPerDimension*64}u;
3473
- let o=i*${s}u;if(o>=arrayLength(&commands)){return;}
3478
+ let o=i*${o}u;if(o>=arrayLength(&commands)){return;}
3474
3479
  let b=commands[o]*${this.dimension===3?10:6}u;
3475
3480
  let mask=commands[o+1u];
3476
3481
  var v=bodies[b+${this.dimension===3?8:3}u];
3477
3482
  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]);":""}}
3478
3483
  ${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;}"}
3479
3484
  bodies[b+${this.dimension===3?8:3}u]=v;
3480
- }`})}}),(!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 n=t??r.createCommandEncoder(),l=n.beginComputePass();l.setPipeline(this.pipeline),l.setBindGroup(0,this.binding);let c=Math.ceil(e.length/s/64),f=r.limits.maxComputeWorkgroupsPerDimension;l.dispatchWorkgroups(Math.min(c,f),Math.ceil(c/f)),l.end(),t||r.queue.submit([n.finish()]),this.lastBatch={bodies:e.length/s,uploadedBytes:e.byteLength}}destroy(){this.buffer?.destroy(),this.binding=null,this.data=this.floats=null}};function ps(o,e={}){return qi({...e,requested:e.solverMode??"auto",bodyCount:o.bodies.length,custom:!!e.shaders?.solve}),{...e,solverMode:e.solverMode??"auto"}}function Ji(o,e){let t=o&&typeof o.x=="number"?[o.x,o.y,o.z]:Array.from(o);if(t.length!==3||!t.every(Number.isFinite))throw Error(`${e} requires three finite components`);return t}function ms(o,e){if(o!==1/0&&(!Number.isFinite(o)||o<0))throw Error(`${e} must be nonnegative or Infinity`);return o}function _n(o,e){let t=Ji(e,"anchor");if(!o)return t;let i=o.aggregate,r=i.mesh.position.constructor;return new r(...t).subtract(i.localCenter).applyRotationQuaternion(i.localRotation.conjugate()).asArray()}var $i=class{constructor(e,t,i,r={}){e.assertAlive();for(let a of[t,i])if(a&&(a.assertAlive(),a.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 s=r.type??"ball";if(!["ball","fixed","spring","motor","limit"].includes(s))throw Error("Constraint type must be ball, fixed, spring, motor or limit");if(s==="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=s,s==="motor"||s==="limit"){let a=(n,l)=>n?new n.aggregate.mesh.position.constructor(...Ji(l,"axis")).applyRotationQuaternion(n.aggregate.localRotation.conjugate()).asArray():Ji(l,"axis");this.angularMaterial=gt({...r,type:s,axisA:a(t,r.axisA??[0,1,0]),axisB:a(i,r.axisB??[0,1,0])})}if(this.anchorA=_n(t,r.anchorA??[0,0,0]),this.anchorB=_n(i,r.anchorB??[0,0,0]),this.linear=ms(s==="spring"?r.stiffness??1e3:r.stiffness??1/0,"stiffness"),this.angular=s==="fixed"?ms(r.angularStiffness??1/0,"angularStiffness"):0,this.breakForce=ms(r.breakForce??1/0,"breakForce"),this.breakForce===0)throw Error("breakForce must be positive");if(this.material=Pt({breakForce:this.breakForce,breakStrain:r.breakStrain}),s!=="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(s==="spring"&&!Number.isFinite(this.linear))throw Error("Spring stiffness must be finite");e.gpu?(e.flushCommands(),this.attach()):this.force=s==="spring"?new ct(e.ref,t.aggregate.rigid,i.aggregate.rigid,this.anchorA,this.anchorB,this.linear,this.rest??-1):new Be(e.ref,t?.aggregate.rigid??null,i.aggregate.rigid,this.anchorA,this.anchorB,this.linear,this.angular,this.breakForce),this.force&&s==="spring"&&os(this.force,this.material),this.force&&this.angularMaterial&&Wi(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=Ji(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 s=new Float32Array(i.getMappedRange().slice(0));return{broken:s[3]===0&&s[7]===0,linearForce:Array.from(s.subarray(8,11)),angularForce:Array.from(s.subarray(12,15))}}finally{i.destroy()}}setMotor(e){if(this.assertAlive(),this.type!=="motor")throw Error("setMotor requires a motor constraint");return this.angularMaterial=gt({...this.angularMaterial,...e}),this.world.gpu?this.world.gpu.setMotor(this.slot,e):Wi(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)}},Xi=class{constructor(e,t,i,r={}){let s=gt({...r,type:"limit"}),a=r.span??1;if(!Number.isFinite(a)||a<=0)throw Error("Hinge span must be positive");let n=Ji(r.anchorA??[0,0,0],"anchorA"),l=Ji(r.anchorB??[0,0,0],"anchorB");r.motor&&gt({...r.motor,type:"motor",axisA:s.axisA,axisB:s.axisB}),this.world=e,this.bodyA=t,this.bodyB=i,this.disposed=!1,this.joints=[-1,1].map(c=>e.addJoint(t,i,{anchorA:n.map((f,u)=>f+c*a*.5*s.axisA[u]),anchorB:l.map((f,u)=>f+c*a*.5*s.axisB[u]),stiffness:r.stiffness??1/0})),(r.minAngle!==void 0||r.maxAngle!==void 0)&&(this.limit=e.addConstraint(t,i,{...s,type:"limit"})),r.motor&&(this.motor=e.addMotor(t,i,{axisA:s.axisA,axisB:s.axisB,...r.motor}))}dispose(){if(!this.disposed){for(let e of[...this.joints,this.limit,this.motor])e?.dispose();this.disposed=!0}}};var Jt=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(a=>a.selection.size>=e&&a.selected.size>=t),s=r>=0?this.idle.splice(r,1)[0]:this.idle.pop()??{};for(let[a,n,l]of[["selection",e,GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST],["selected",t,GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC],["staging",t,GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST]])(!s[a]||s[a].size<n)&&(s[a]?.destroy(),s[a]=i.createBuffer({size:n,usage:l}));return this.jobs.add(s),s}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 s=i?r===6?1:2:r,a=this.device,n=a.limits.maxComputeWorkgroupsPerDimension,l=`${r}:${s}`,c=this.pipelines.get(l);c||(c=a.createComputePipeline({layout:"auto",compute:{entryPoint:"gather",module:a.createShaderModule({code:`
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 $s(s,e={}){return yr({...e,requested:e.solverMode??"auto",bodyCount:s.bodies.length,custom:!!e.shaders?.solve}),{...e,solverMode:e.solverMode??"auto"}}function Br(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 Xs(s,e){if(s!==1/0&&(!Number.isFinite(s)||s<0))throw Error(`${e} must be nonnegative or Infinity`);return s}function Ll(s,e){let t=Br(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 Cr=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(...Br(l,"axis")).applyRotationQuaternion(a.aggregate.localRotation.conjugate()).asArray():Br(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=Ll(t,r.anchorA??[0,0,0]),this.anchorB=Ll(i,r.anchorB??[0,0,0]),this.linear=Xs(o==="spring"?r.stiffness??1e3:r.stiffness??1/0,"stiffness"),this.angular=o==="fixed"?Xs(r.angularStiffness??1/0,"angularStiffness"):0,this.breakForce=Xs(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"&&br(this.force,this.material),this.force&&this.angularMaterial&&Ar(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=Br(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):Ar(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)}},Sr=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=Br(r.anchorA??[0,0,0],"anchorA"),l=Br(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:`
3481
3486
  @group(0) @binding(0) var<storage,read> bodies:array<vec4f>;
3482
3487
  @group(0) @binding(1) var<storage,read> indices:array<u32>;
3483
3488
  @group(0) @binding(2) var<storage,read_write> selected:array<vec4f>;
3484
3489
  @compute @workgroup_size(64) fn gather(@builtin(global_invocation_id) id:vec3u) {
3485
- let i=id.x+id.y*${n*64}u; if(i>=arrayLength(&selected)){return;}
3486
- selected[i]=bodies[indices[i/${s}u]*${r}u+i%${s}u];
3487
- }`})}}),this.pipelines.set(l,c));let f=t.length*s*16,u=this.acquire(t.length*4,f),{selection:d,selected:p,staging:m}=u;try{a.queue.writeBuffer(d,0,t instanceof Uint32Array?t:Uint32Array.from(t)),(!u.group||u.body!==e||u.pipeline!==c||u.boundSelection!==d||u.boundSelected!==p||u.indexBytes!==t.length*4||u.bytes!==f)&&(u.group=a.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:f}}]}),u.body=e,u.pipeline=c,u.boundSelection=d,u.boundSelected=p,u.indexBytes=t.length*4,u.bytes=f);let h=a.createCommandEncoder(),b=h.beginComputePass();b.setPipeline(c),b.setBindGroup(0,u.group);let y=Math.ceil(t.length*s/64);return b.dispatchWorkgroups(Math.min(y,n),Math.ceil(y/n)),b.end(),h.copyBufferToBuffer(p,0,m,0,f),a.queue.submit([h.finish()]),await m.mapAsync(GPUMapMode.READ,0,f),new Float32Array(m.getMappedRange(0,f).slice(0))}finally{this.release(u)}}};var Zo=4,Yi=3,Xt=1,vc=2,yr=`
3490
+ let i=id.x+id.y*${a*64}u; if(i>=arrayLength(&selected)){return;}
3491
+ 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 Zn=4,kr=3,vi=1,Ru=2,Yr=`
3488
3493
  struct Manifold { ids: vec4u, geo: vec4f } // a, b (a > b), first contact, count (low 4 bits); normal (b to a)
3489
3494
  struct Contact { rA: vec3f, key: u32, rB: vec3f, c0x: f32, pen: vec3f, c0y: f32, lam: vec3f, c0z: f32 }
3490
3495
  struct Params { prev: u32, now: u32, mask: u32, capacity: u32, pairs: u32, step: u32, dt: f32, pad: u32 }
@@ -3498,7 +3503,7 @@ struct Params { prev: u32, now: u32, mask: u32, capacity: u32, pairs: u32, step:
3498
3503
  @group(0) @binding(6) var<storage, read_write> events: array<vec4f>;
3499
3504
  @group(0) @binding(7) var<uniform> params: Params;
3500
3505
 
3501
- const STRIDE = ${ke/4}u;
3506
+ const STRIDE = ${qe/4}u;
3502
3507
 
3503
3508
  fn hash32(x0: u32) -> u32 {
3504
3509
  var x = x0;
@@ -3513,7 +3518,7 @@ fn turn(q: vec4f, v: vec3f) -> vec3f {
3513
3518
  }
3514
3519
 
3515
3520
  fn slotOf(base: u32, h: u32) -> u32 {
3516
- return ${Zo}u + 2u * (base + h);
3521
+ return ${Zn}u + 2u * (base + h);
3517
3522
  }
3518
3523
 
3519
3524
  fn insert(base: u32, a: u32, b: u32) {
@@ -3546,16 +3551,16 @@ fn has(base: u32, a: u32, b: u32) -> bool {
3546
3551
  fn emit(kind: u32, a: u32, b: u32, point: vec3f, impulse: f32, normal: vec3f) {
3547
3552
  let e = atomicAdd(&table[0], 1u);
3548
3553
  if (e >= params.capacity) { return; }
3549
- events[${Yi}u * e] = bitcast<vec4f>(vec4u(kind, a, b, params.step));
3550
- events[${Yi}u * e + 1u] = vec4f(point, impulse);
3551
- events[${Yi}u * e + 2u] = vec4f(normal, 0.0);
3554
+ events[${kr}u * e] = bitcast<vec4f>(vec4u(kind, a, b, params.step));
3555
+ events[${kr}u * e + 1u] = vec4f(point, impulse);
3556
+ events[${kr}u * e + 2u] = vec4f(normal, 0.0);
3552
3557
  }
3553
3558
 
3554
3559
  /** Per pair this step: into this step's set, and a begin if it wasn't in last step's. */
3555
3560
  @compute @workgroup_size(64)
3556
3561
  fn touching(@builtin(global_invocation_id) id: vec3u) {
3557
3562
  let m = id.x;
3558
- if (m >= min(counters[${Fi}u], params.pairs)) { return; }
3563
+ if (m >= min(counters[${pr}u], params.pairs)) { return; }
3559
3564
  let mf = manifolds[m];
3560
3565
  let count = mf.ids.w & 15u;
3561
3566
  let a = mf.ids.x;
@@ -3564,8 +3569,8 @@ fn touching(@builtin(global_invocation_id) id: vec3u) {
3564
3569
  insert(params.now, a, b);
3565
3570
  if (has(params.prev, a, b)) { return; }
3566
3571
  // Where (the points' average, on a) and how hard (the normal force over the step)
3567
- let pA = bodies[a * STRIDE + ${Oi/4}u].xyz;
3568
- let qA = bodies[a * STRIDE + ${fr/4}u];
3572
+ let pA = bodies[a * STRIDE + ${cr/4}u].xyz;
3573
+ let qA = bodies[a * STRIDE + ${qr/4}u];
3569
3574
  var point = vec3f(0.0);
3570
3575
  var force = 0.0;
3571
3576
  for (var i = 0u; i < count; i++) {
@@ -3573,7 +3578,7 @@ fn touching(@builtin(global_invocation_id) id: vec3u) {
3573
3578
  point += turn(qA, k.rA) + pA;
3574
3579
  force += k.lam.x;
3575
3580
  }
3576
- emit(${Xt}u, a, b, point / f32(count), abs(force) * params.dt, mf.geo.xyz);
3581
+ emit(${vi}u, a, b, point / f32(count), abs(force) * params.dt, mf.geo.xyz);
3577
3582
  }
3578
3583
 
3579
3584
  /** Per slot of last step's set: an end if the pair isn't in this step's. */
@@ -3584,10 +3589,10 @@ fn ended(@builtin(global_invocation_id) id: vec3u) {
3584
3589
  let k = atomicLoad(&table[s]);
3585
3590
  if (k == 0u) { return; }
3586
3591
  let b = atomicLoad(&table[s + 1u]);
3587
- if (!has(params.now, k - 1u, b)) { emit(${vc}u, k - 1u, b, vec3f(0.0), 0.0, vec3f(0.0)); }
3592
+ if (!has(params.now, k - 1u, b)) { emit(${Ru}u, k - 1u, b, vec3f(0.0), 0.0, vec3f(0.0)); }
3588
3593
  }
3589
- `,xc=yr.replace("struct Manifold { ids: vec4u, geo: vec4f }","struct Manifold { ids:vec4u, pl:vec4f, anchors:vec4f, geo:vec4f, misc:vec4f }").replace(`const STRIDE = ${ke/4}u;`,"const STRIDE = 6u;").replace(yr.slice(yr.indexOf(`@compute @workgroup_size(64)
3590
- fn touching`),yr.indexOf("/** Per slot of last step")),`
3594
+ `,Ou=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")),`
3591
3596
  @compute @workgroup_size(64) fn touching(@builtin(global_invocation_id) id:vec3u){
3592
3597
  let m=id.x;let count=min(counters[1u],params.pairs);if(m>=count){return;}
3593
3598
  let c=manifolds[m];let a=c.ids.x;let b=c.ids.y;
@@ -3596,12 +3601,12 @@ fn touching`),yr.indexOf("/** Per slot of last step")),`
3596
3601
  insert(params.now,a,b);if(has(params.prev,a,b)){return;}
3597
3602
  let pose=bodies[a*STRIDE];let cs=cos(pose.z);let sn=sin(pose.z);
3598
3603
  let r=c.anchors.xy;let point=pose.xy+vec2f(cs*r.x-sn*r.y,sn*r.x+cs*r.y);
3599
- emit(${Xt}u,a,b,vec3f(point,0.),abs(c.pl.z)*params.dt,vec3f(c.geo.zw,0.));
3604
+ emit(${vi}u,a,b,vec3f(point,0.),abs(c.pl.z)*params.dt,vec3f(c.geo.zw,0.));
3600
3605
  }
3601
3606
 
3602
- `),$t=class{device;pipelines;layout;watch;table;events;params;setSlots;capacity;group=null;bound=[];flip=0;bodies;constructor(e,t,i,r,s,a=3){this.device=e,this.bodies=t,this.capacity=s,this.setSlots=2**Math.ceil(Math.log2(Math.max(64,2*r)));let n=e.createShaderModule({label:"contact events",code:a===2?xc: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]}),f=d=>e.createComputePipeline({label:`contact events ${d}`,layout:c,compute:{module:n,entryPoint:d}});this.pipelines={touching:f("touching"),ended:f("ended")};let u=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC;this.watch=e.createBuffer({label:"contact watch",size:Math.max(16,i*4),usage:u}),this.table=e.createBuffer({label:"contact sets",size:(Zo+4*this.setSlots)*4,usage:u}),this.events=e.createBuffer({label:"contact events",size:s*Yi*16,usage:u}),this.params=e.createBuffer({label:"contact params",size:32,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST})}setWatched(e,t){let i=e.map((r,s)=>[r,t[s]?1:0]).sort((r,s)=>r[0]-s[0]);for(let r=0;r<i.length;){let s=r+1;for(;s<i.length&&i[s][0]===i[s-1][0]+1;)s++;this.device.queue.writeBuffer(this.watch,i[r][0]*4,Uint32Array.from(i.slice(r,s),a=>a[1])),r=s}}run(e,t,i,r){let s=this.device,a=[this.bodies,e.manifolds,e.contacts,e.counters,this.watch,this.table,this.events,this.params];(!this.group||a.some((d,p)=>d!==this.bound[p]))&&(this.bound=a,this.group=s.createBindGroup({layout:this.layout,entries:a.map((d,p)=>({binding:p,resource:{buffer:d}}))})),this.flip=1-this.flip;let[n,l]=this.flip?[0,this.setSlots]:[this.setSlots,0],c=new Uint32Array([n,l,this.setSlots-1,this.capacity,t,i,0,0]);new Float32Array(c.buffer)[6]=r,s.queue.writeBuffer(this.params,0,c);let f=s.createCommandEncoder({label:"contact events"});f.clearBuffer(this.table,(Zo+2*l)*4,2*this.setSlots*4);let u=f.beginComputePass({label:"contact events"});u.setBindGroup(0,this.group),u.setPipeline(this.pipelines.touching),u.dispatchWorkgroups(Math.max(1,Math.ceil(t/64))),u.setPipeline(this.pipelines.ended),u.dispatchWorkgroups(Math.ceil(this.setSlots/64)),u.end(),s.queue.submit([f.finish()])}async read(){let e=this.device,t=16+this.capacity*Yi*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 s=i.getMappedRange().slice(0);i.unmap(),i.destroy();let a=new Uint32Array(s),n=new Float32Array(s),l=Math.min(a[0],this.capacity),c=[];for(let f=0;f<l;f++){let u=4+f*Yi*4;c.push({kind:a[u],a:a[u+1],b:a[u+2],step:a[u+3],point:[n[u+4],n[u+5],n[u+6]],impulse:n[u+7],normal:[n[u+8],n[u+9],n[u+10]]})}return c.sort((f,u)=>f.step-u.step),{events:c,dropped:a[0]-l,full:a[1]!==0}}destroy(){for(let e of[this.watch,this.table,this.events,this.params])e.destroy()}};var Ue=Object.freeze({BOX:"box",SPHERE:"sphere",CAPSULE:"capsule",CYLINDER:"cylinder",CONVEX_HULL:"convex-hull"}),_e=o=>o&&typeof o.x=="number"?[o.x,o.y,o.z,...typeof o.w=="number"?[o.w]:[]]:Array.from(o),vr=new WeakMap,Qi=o=>{if(!Number.isInteger(o)||o<0||o>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");return o},bs=(o,e,t=!1)=>{if(!Number.isFinite(o)||(t?o<0:o<=0))throw Error(`${e} must be ${t?"nonnegative":"positive"} and finite`);return o},xr=class o{static async create({device:e,...t}={}){if(t.scene&&vr.has(t.scene))throw Error("This scene already has an AVBD world");let i=!e;e||({device:e}=await hs({preferredLimits:{maxStorageBuffersPerShaderStage:9,maxStorageBufferBindingSize:512*1024*1024,maxBufferSize:1024*1024*1024}}));let r;try{return await gr(e),r=new o(e,t),r.ownsDevice=i,r.scene&&r.autoAttach&&r.attachToScene(),r}catch(s){throw r?r.dispose():i&&e.destroy(),s}}constructor(e,{scene:t,gravity:i=[0,-10,0],timeStep:r=1/60,iterations:s=10,capacity:a=4096,syncMeshes:n=!0,maxSyncedBodies:l=2048,broadphase:c="auto",solverMode:f="auto",bvh:u={},autoAttach:d=!0,maxContactPairs:p=8192,maxContactEvents:m=4096,sleeping:h=!1}={}){if(this.device=e,this.scene=t,this.autoAttach=d,this.syncEnabled=n,this.maxSyncedBodies=l,!Number.isInteger(a)||a<1||!Number.isInteger(l)||l<0)throw Error("capacity and maxSyncedBodies must be valid integer counts");if(this.capacity=a,this.collisionOptions={broadphase:c,bvh:u,solverMode:f},this.ref=new jt,this.ref.dt=bs(r,"timeStep"),!Number.isInteger(s)||s<1)throw Error("iterations must be a positive integer");this.ref.iterations=s,this.aggregates=[],this.constraints=new Set,this.contactListeners=new Set;for(let[y,v]of Object.entries({maxContactPairs:p,maxContactEvents:m}))if(!Number.isInteger(v)||v<1)throw Error(`${y} must be a positive integer`);if(this.contactOptions={maxContactPairs:p,maxContactEvents:m},this.bodyReadback=new Jt(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 b=new WeakRef(this);e.lost.then(y=>{let v=b.deref();!v||v.disposed||(v.deviceLost={reason:y.reason,message:y.message},v.errors.push(`WebGPU device lost: ${y.message||y.reason}`),v.dispose())}),this.setGravity(i),this.errorListener=y=>this.errors.push(y.error.message),e.addEventListener("uncapturederror",this.errorListener),t&&vr.set(t,this)}setGravity(e){let t=_e(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 Vt(this.device,this.ref,ps(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 s=e.get(r);s&&(s.attach(i++,!1),(s.type==="fixed"||s.type==="spring"&&s.rest===void 0)&&t.push({slot:s.slot,spring:s.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 hi(this,this.sleepOptions===!0?{}:this.sleepOptions))}addAggregate(e,t,i={}){return new Ar(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 $i(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 hi(this,e)),this}addMotor(e,t,i={}){return this.addConstraint(e,t,{...i,type:"motor"})}addHinge(e,t,i={}){return new Xi(this,e,t,i)}initializeContacts(){if(this.contactWatch)return;let{maxContactPairs:e,maxContactEvents:t}=this.contactOptions;this.contactWatch=new $t(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===Xt?"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[s]=await this.sphereCastAll([{origin:e,radius:t,direction:i,maxDistance:r.maxDistance}],r);return s}async sphereCastAll(e,{ignore:t=[],collidesWith:i=4294967295,includeTriggers:r=!0}={}){this.assertAlive(),Qi(i),this.initialize(),this.flushCommands();for(let a of t)if(a.aggregate.world!==this||a.disposed)throw Error("Ignored cast bodies must belong to this world and be alive");return(await this.gpu.sphereCastAll(e.map(a=>({...a,origin:_e(a.origin),direction:_e(a.direction)})),{ignore:t.map(a=>a.gpuIndex),collidesWith:i,includeTriggers:r})).map(a=>a?{...a,body:this.byGpuIndex.get(a.index)??null}:null)}async raycastAll(e,{ignore:t=[],collidesWith:i=4294967295,includeTriggers:r=!0}={}){Qi(i),this.initialize(),this.flushCommands();let s=e.map(n=>{let l=_e(n.origin),c=_e(n.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 n.maxDistance!==void 0&&bs(n.maxDistance,"maxDistance",!0),{...n,origin:l,direction:c}});for(let n of t)if(n.aggregate.world!==this)throw Error("Ignored ray bodies must belong to this world");return(await this.gpu.raycastAll(s,{ignore:t.map(n=>n.gpuIndex),collidesWith:i,includeTriggers:r})).map(n=>n?{...n,body:this.byGpuIndex.get(n.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 s=_e(r);if(s.length!==(i==="rotation"?4:3)||!s.every(Number.isFinite))throw Error(`${i} requires ${i==="rotation"?4:3} finite components`);let a=this.commands.get(e);return a||this.commands.set(e,a={mask:0}),a.mask|=t,a[i]=s,this.wakeAll(),a}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 b=i===2?"angularVelocityBatch":"velocityBatch",y=this[b]??=new Lt(this.gpu,3,i===2?"angular":"linear");y.solver=this.gpu,y.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[b,y]of this.commands){let v=h++*8;this.motionData[v]=b.aggregate.gpuSlot??this.gpu.gpuIndex(b.aggregate.index),this.motionData[v+1]=y.mask,y.velocity&&this.motionFloats.set(y.velocity,v+2),y.angular&&this.motionFloats.set(y.angular,v+5)}this.motionBatch??=new Ht(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 s=t*128,a=Math.min(this.device.limits.maxStorageBufferBindingSize,this.device.limits.maxBufferSize);if(s>a)throw Error("Body command batch exceeds GPU buffer limits");(!this.commandData||this.commandData.byteLength<s)&&(this.commandData=new ArrayBuffer(Math.min(a,Math.max(s,(this.commandData?.byteLength??0)*2,128))));let n=this.commandData,l=new Float32Array(n),c=new Uint32Array(n);l.fill(0,0,t*32);let f=0;for(let[h,b]of this.commands){let y=f++*32;c[y]=h.aggregate.gpuSlot??this.gpu.gpuIndex(h.aggregate.index),c[y+1]=b.mask;for(let[v,w]of[["velocity",4],["angular",8],["impulse",12],["torque",16],["position",20],["rotation",24],["pointImpulse",28]])b[v]&&l.set(b[v],y+w)}this.commands.clear(),(!this.commandBuffer||this.commandBuffer.size<s)&&(this.commandBuffer?.destroy(),this.commandBuffer=this.device.createBuffer({size:Math.min(a,Math.max(s*2,128)),usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST})),this.device.queue.writeBuffer(this.commandBuffer,0,n,0,s),this.commandPipeline??=this.device.createComputePipeline({layout:"auto",compute:{module:this.device.createShaderModule({code:`const DISPATCH_STRIDE = ${this.device.limits.maxComputeWorkgroupsPerDimension*64}u;
3603
- ${Ln}`,label:"AVBD body commands"}),entryPoint:"applyCommands"}}),(!this.commandBinding||this.boundCommandBody!==this.gpu.bodyBuffer||this.boundCommandBuffer!==this.commandBuffer||this.boundCommandBytes!==s)&&(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:s}}]}),this.boundCommandBody=this.gpu.bodyBuffer,this.boundCommandBuffer=this.commandBuffer,this.boundCommandBytes=s);let u=e??this.device.createCommandEncoder(),d=u.beginComputePass();d.setPipeline(this.commandPipeline),d.setBindGroup(0,this.commandBinding);let p=Math.ceil(f/64),m=this.device.limits.maxComputeWorkgroupsPerDimension;d.dispatchWorkgroups(Math.min(p,m),Math.ceil(p/m)),d.end(),e||this.device.queue.submit([u.finish()]),this.lastCommandBatch={bodies:t,path:"aggregate-commands",uploadedBytes:s}}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 s of this.contactListeners)s(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&&vr.get(this.scene)===this&&vr.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}},Ar=class{constructor(e,t,{mass:i=1,friction:r=.6,restitution:s=0,allowSleep:a,isTrigger:n=!1,sync:l=!0,group:c=4294967295,collidesWith:f=4294967295}={},u){if(u=u instanceof xr?u:vr.get(u??e.getScene()),!u)throw Error("Create an AVBD world for this scene before adding aggregates");if(u.assertAlive(),typeof t=="number"&&(t=[Ue.SPHERE,Ue.CAPSULE,Ue.CYLINDER,Ue.BOX,Ue.CONVEX_HULL][t]),bs(i,"mass",!0),bs(r,"friction",!0),!Number.isFinite(s)||s<0||s>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(Ue).includes(t))throw Error(`Unsupported AVBD shape: ${t}`);if(u.aggregates.length>=u.capacity)throw Error("AVBD body capacity exceeded");if(this.world=u,this.mesh=e,this.sync=l,this.type=t,a!==void 0&&typeof a!="boolean")throw Error("allowSleep must be a boolean");if(this.allowSleep=a??!0,typeof n!="boolean")throw Error("isTrigger must be a boolean");if(this.isTrigger=n,this.restitution=s,a===!0&&!u.sleepOptions&&u.enableSleeping(),this.group=Qi(c),this.collidesWith=Qi(f),u.gpu&&u.syncEnabled&&l&&u.aggregates.filter(g=>g.sync&&!g.disposed).length>=u.maxSyncedBodies)throw Error("For large scenes use syncMeshes:false and draw the GPU body buffer directly");if(![Ue.BOX,Ue.SPHERE,Ue.CAPSULE].includes(t)&&u.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(g=>g<=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),b=e.rotationQuaternion?.clone()||e.rotation.toQuaternion();this.localCenter=h,this.localRotation=b.constructor.Identity();let y;if(t===Ue.BOX)y=new De(u.ref,_e(m),1,r,[0,0,0]);else if(t===Ue.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");y=Mi(u.ref,m.x/2,1,r,[0,0,0])}else if(t===Ue.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");y=Hi(u.ref,m.x/2,m.y,1,r,[0,0,0])}else{let g=e.getVerticesData("position");if(!g)throw Error("Hull aggregate requires mesh positions");let A=Float32Array.from(g,(B,E)=>B*[p.x,p.y,p.z][E%3]),x=nr(A);if(!x)throw Error("Hull aggregate requires a closed shape with nonzero volume");this.localCenter=new e.position.constructor(...x.center),this.localRotation=b.constructor.FromArray(x.rotation),y=qr(u.ref,x,1,r,[0,0,0])}let v=i/y.mass;y.mass=i,y.moment.forEach((g,A)=>y.moment[A]=g*v);let w=e.position.add(this.localCenter.applyRotationQuaternion(b));if(y.positionLin.set(_e(w)),y.positionAng.set(b.multiply(this.localRotation).asArray()),this.rigid=y,this.index=u.aggregates.length,this.body=new Br(this),u.aggregates.push(this),e.rotationQuaternion=b,u.gpu){if(this.gpuSlot=u.gpu.addBody(y),this.gpuSlot<0)throw Error("AVBD body capacity exceeded");u.byGpuIndex.set(this.gpuSlot,this.body),u.gpu.setFilters([this.gpuSlot],[this.group],[this.collidesWith]),(this.isTrigger||u.gpu.sensorsEnabled)&&u.gpu.setSensor(this.gpuSlot,this.isTrigger),this.restitution>0&&u.gpu.setRestitution(this.gpuSlot,this.restitution),u.contactWatch?.setWatched([this.gpuSlot],[!0]),u.sleepManager?.register(this.gpuSlot,y.mass,this.allowSleep),u.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?.()}},Br=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?_e(t):null;if(i&&(i.length!==3||!i.every(Number.isFinite)))throw Error("Impulse point requires three finite components");let r=this.aggregate.world,s=_e(e),a=r.commands.get(this),n=s.map((c,f)=>c+(a?.impulse?.[f]||0)),l=r.queue(this,4,"impulse",n);if(t){let c=[i[1]*s[2]-i[2]*s[1],i[2]*s[0]-i[0]*s[2],i[0]*s[1]-i[1]*s[0]],f=l.torque||[0,0,0];l.torque=_e(c).map((u,d)=>u+f[d]),l.pointImpulse=s.map((u,d)=>u+(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",_e(e).map((r,s)=>r+i[s])),this}applyForce(e,t){return this.applyImpulse(_e(e).map(i=>i*this.aggregate.world.ref.dt),t)}applyTorque(e){return this.applyAngularImpulse(_e(e).map(t=>t*this.aggregate.world.ref.dt))}setCollisionGroups(e,t=4294967295){this.assertAlive();let i=this.aggregate,r=Qi(e),s=Qi(t);return i.group=r,i.collidesWith=s,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",_e(e.add(r.localCenter.applyRotationQuaternion(i)))),r.world.queue(this,8,"rotation",i.multiply(r.localRotation).asArray()),this}};var pi=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 En=o=>o<0?-1:o>0?1:0,Ki=(o,e)=>o<e?o:e,Ac=(o,e)=>o>e?o:e,Zi=(o,e,t)=>Ac(e,Ki(t,o));function wr(o,e,t){let i=Math.cos(o),r=Math.sin(o);return[i*e-r*t,r*e+i*t]}function mi(o,e,t){let i=Math.cos(o[2]),r=Math.sin(o[2]);return[i*e-r*t+o[0],r*e+i*t+o[1]]}function _t(o,e,t,i,r){o[e*3]=t,o[e*3+1]=i,o[e*3+2]=r}var gs=class extends pi{rA;rB;C0=new Float64Array(3);torqueArm;restAngle;constructor(e,t,i,r,s,a=[1/0,1/0,1/0],n=1/0){super(e,t,i),this.rA=[r[0],r[1]],this.rB=[s[0],s[1]],this.stiffness[0]=a[0],this.stiffness[1]=a[1],this.stiffness[2]=a[2],this.fmax[2]=n,this.fmin[2]=-n,this.fracture[2]=n,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?mi(this.bodyA.position,this.rA[0],this.rA[1]):this.rA,i=mi(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=wr(e.position[2],this.rA[0],this.rA[1]);_t(t,0,1,0,-r[1]),_t(t,1,0,1,r[0]),_t(t,2,0,0,this.torqueArm),i[8]=-r[0],i[17]=-r[1]}else{let r=wr(e.position[2],this.rB[0],this.rB[1]);_t(t,0,-1,0,r[1]),_t(t,1,0,-1,-r[0]),_t(t,2,0,0,-this.torqueArm),i[8]=r[0],i[17]=r[1]}}},ys=class extends pi{rA;rB;rest;constructor(e,t,i,r,s,a,n=-1){if(super(e,t,i),this.rA=[r[0],r[1]],this.rB=[s[0],s[1]],this.stiffness[0]=a,this.rest=n,this.rest<0){let l=mi(t.position,r[0],r[1]),c=mi(i.position,s[0],s[1]);this.rest=Math.hypot(l[0]-c[0],l[1]-c[1])}}rows(){return 1}initialize(){return!0}delta(){let e=mi(this.bodyA.position,this.rA[0],this.rA[1]),t=mi(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),s=t[0]/r,a=t[1]/r,n=(1-s*s)/r,l=(0-s*a)/r,c=(0-a*s)/r,f=(1-a*a)/r,u=e===this.bodyA,d=u?this.rA:this.rB,p=wr(e.position[2],-d[1],d[0]),m=wr(e.position[2],d[0],d[1]),h=n*p[0]+l*p[1],b=c*p[0]+f*p[1],y=s*m[0]+a*m[1],v=s*p[0]+a*p[1];u?_t(this.J,0,s,a,v):_t(this.J,0,-s,-a,-v);let w=u?-y-y:y+y,g=this.H;g[0]=n,g[1]=l,g[2]=h,g[3]=c,g[4]=f,g[5]=b,g[6]=h,g[7]=b,g[8]=w}},vs=class extends pi{rows(){return 0}initialize(){return!0}computeConstraint(){}computeDerivatives(){}},xs=class extends pi{speed;constructor(e,t,i,r,s){super(e,t,i),this.speed=r,this.fmax[0]=s,this.fmin[0]=-s}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){_t(this.J,0,0,0,e===this.bodyA?1:-1),this.H.fill(0,0,9)}};var As=()=>({dt:1/60,gravity:-10,iterations:10,beta:1e5,alpha:.99,gamma:.99,postStabilize:!0,stiffnessRescale:!1,vbd:!1,vbdStiffness:1e6,matchNearest:!1}),Bs=()=>({...As(),postStabilize:!1,alpha:.95,matchNearest:!0});var er=(o,e)=>o>e?o*2097152+e:e*2097152+o;function Bc(o,e,t){let i=0,r=e;for(;i<r;){let s=i+r>>>1;o[s]<t?i=s+1:r=s}return i}function ea(o,e,t){let i=Bc(o,e,t);return i<e&&o[i]===t}var ws=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},(n,l)=>t[l*4+1]).sort(),r=e>0?i[e>>1]:1,s=0;for(let n=0;n<e;n++)i[n]<=4*r&&(s=Math.max(s,i[n]));this.cellSize=Math.max(2*s,.001),this.isLarge=new Uint8Array(e);let a=[];for(let n=0;n<e;n++)t[n*4+1]>s&&(this.isLarge[n]=1,a.push(n));for(this.large=Int32Array.from(a),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,s,a){e!==this.configuredFor&&this.configure(e,i),this.pairCount=0;let{cellX:n,cellY:l,isLarge:c,bucketStart:f,sorted:u}=this,d=1/this.cellSize;f.fill(0);for(let h=0;h<e;h++)c[h]||(n[h]=Math.floor(t[h*4]*d),l[h]=Math.floor(t[h*4+1]*d),f[this.hash(n[h],l[h])+1]++);for(let h=0;h<this.tableSize;h++)f[h+1]+=f[h];let p=f.slice(0,this.tableSize);for(let h=0;h<e;h++)c[h]||(u[p[this.hash(n[h],l[h])]++]=h);let m=(h,b)=>{if(!r[h]&&!r[b])return;let y=t[h*4]-t[b*4],v=t[h*4+1]-t[b*4+1],w=i[h*4+1]+i[b*4+1];if(y*y+v*v>w*w)return;let g=er(h,b);if(!ea(s,a,g)){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++]=g}};for(let h=0;h<e;h++){if(c[h])continue;let b=n[h],y=l[h];for(let v=-1;v<=1;v++)for(let w=-1;w<=1;w++){let g=this.hash(b+w,y+v);for(let A=f[g];A<f[g+1];A++){let x=u[A];x>=h||n[x]!==b+w||l[x]!==y+v||m(h,x)}}}for(let h of this.large)for(let b=0;b<e;b++)b===h||c[b]&&b>h||m(h,b);this.pairs.subarray(0,this.pairCount).sort()}};var Ye=new Float64Array(12),zn=new Float64Array(12),bi=new Float64Array(12);function yt(o,e,t,i,r,s,a,n){let l=e*6;o[l]=t,o[l+1]=i,o[l+2]=r,o[l+3]=s,o[l+4]=a,o[l+5]=n}function Mn(o,e,t,i,r,s){let a=0,n=t*e[0]+i*e[1]-r,l=t*e[6]+i*e[7]-r;if(n<=0){for(let c=0;c<6;c++)o[a*6+c]=e[c];a++}if(l<=0){for(let c=0;c<6;c++)o[a*6+c]=e[6+c];a++}if(n*l<0){let c=n/(n-l),f=e[0]+(e[6]-e[0])*c,u=e[1]+(e[7]-e[1])*c;n>0?yt(o,a,f,u,s,e[3],0,e[5]):yt(o,a,f,u,e[8],s,e[10],0),a++}return a}function Cs(o,e,t,i,r,s,a,n){let l=-(r*a+s*n),c=-(-s*a+r*n);Math.abs(l)>Math.abs(c)?l>0?(yt(Ye,0,o,-e,0,0,3,4),yt(Ye,1,o,e,0,0,4,1)):(yt(Ye,0,-o,e,0,0,1,2),yt(Ye,1,-o,-e,0,0,2,3)):c>0?(yt(Ye,0,o,e,0,0,4,1),yt(Ye,1,-o,e,0,0,1,2)):(yt(Ye,0,-o,-e,0,0,2,3),yt(Ye,1,o,-e,0,0,3,4));for(let f=0;f<2;f++){let u=f*6,d=Ye[u],p=Ye[u+1];Ye[u]=t+r*d-s*p,Ye[u+1]=i+s*d+r*p}}function In(o,e,t,i,r,s,a,n,l,c,f){let u=Math.cos(t),d=Math.sin(t),p=Math.cos(n),m=Math.sin(n),h=s-o,b=a-e,y=u*h+d*b,v=-d*h+u*b,w=p*h+m*b,g=-m*h+p*b,A=Math.abs(u*p+d*m),x=Math.abs(u*-m+d*p),B=Math.abs(-d*p+u*m),E=Math.abs(-d*-m+u*p),k=Math.abs(y)-i-(A*l+x*c),z=Math.abs(v)-r-(B*l+E*c);if(k>0||z>0)return 0;let M=Math.abs(w)-(A*i+B*r)-l,P=Math.abs(g)-(x*i+E*r)-c;if(M>0||P>0)return 0;let _=0,C=k,S=y>0?u:-u,R=y>0?d:-d;z>.95*C+.01*r&&(_=1,C=z,S=v>0?-d:d,R=v>0?u:-u),M>.95*C+.01*l&&(_=2,C=M,S=w>0?p:-p,R=w>0?m:-m),P>.95*C+.01*c&&(_=3,C=P,S=g>0?-m:m,R=g>0?p:-p);let I,O,q,G,j,F,H,ee,le;if(_===0){I=S,O=R,q=o*I+e*O+i,G=-d,j=u;let U=o*G+e*j;F=-U+r,H=U+r,ee=3,le=1,Cs(l,c,s,a,p,m,I,O)}else if(_===1){I=S,O=R,q=o*I+e*O+r,G=u,j=d;let U=o*G+e*j;F=-U+i,H=U+i,ee=2,le=4,Cs(l,c,s,a,p,m,I,O)}else if(_===2){I=-S,O=-R,q=s*I+a*O+l,G=-m,j=p;let U=s*G+a*j;F=-U+c,H=U+c,ee=3,le=1,Cs(i,r,o,e,u,d,I,O)}else{I=-S,O=-R,q=s*I+a*O+c,G=p,j=m;let U=s*G+a*j;F=-U+l,H=U+l,ee=2,le=4,Cs(i,r,o,e,u,d,I,O)}if(Mn(zn,Ye,-G,-j,F,ee)<2||Mn(bi,zn,G,j,H,le)<2)return 0;let xe=0;for(let U=0;U<2;U++){let ze=U*6,Me=bi[ze],ce=bi[ze+1],qe=I*Me+O*ce-q;if(qe>0)continue;let zt=Me-I*qe,Ie=ce-O*qe,Ve=bi[ze+2],Re=bi[ze+3],We=bi[ze+4],et=bi[ze+5],Ai,Bi,wi,Ci;_>=2?([Ve,Re,We,et]=[We,et,Ve,Re],Ai=Me-o,Bi=ce-e,wi=zt-s,Ci=Ie-a):(Ai=zt-o,Bi=Ie-e,wi=Me-s,Ci=ce-a);let At=xe*7;f[At+0]=Ve&255|(Re&255)<<8|(We&255)<<16|(et&255)<<24,f[At+1]=u*Ai+d*Bi,f[At+1+1]=-d*Ai+u*Bi,f[At+3]=p*wi+m*Ci,f[At+3+1]=-m*wi+p*Ci,f[At+5]=-S,f[At+5+1]=-R,xe++}return xe}var Rn=o=>31-Math.clz32(o&-o);function wc(o){let e=o+2654435769;return e^=e>>>16,e=Math.imul(e,2146121005),e^=e>>>15,e=Math.imul(e,2221713035),e^=e>>>16,e>>>0}var ta=(o,e,t,i)=>o>t||o===t&&e>i,Ss=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)=>wc(r))}run(e,t,i,r,s,a){this.resize(e);let{colors:n,next:l,pending:c,prio:f}=this,u=(g,A)=>{let x=s[g*4+1],B=x===A?s[g*4+2]:x;return B>=0&&t[B]?B:-1},d=(g,A)=>{let x=0,B=0;for(let E=i[g];E<i[g+1];E++){let k=u(r[E],g);if(k<0||A&&c[k])continue;let z=n[k];z<0||(z<32?x|=1<<z:B|=1<<z-32)}return~x!==0?Rn(~x):~B!==0?32+Rn(~B):63};for(let g=0;g<e;g++){if(l[g]=n[g],!t[g]||n[g]<0)continue;let A=!0;for(let x=i[g];x<i[g+1]&&A;x++){let B=u(r[x],g);B>=0&&!ta(f[g],g,f[B],B)&&(A=!1)}A&&(l[g]=Math.min(n[g],d(g,!1)))}n.set(l);let p=()=>{let g=0;for(let A=0;A<e;A++)if(c[A]=0,!!t[A]){if(n[A]<0)c[A]=1;else for(let x=i[A];x<i[A+1];x++){let B=u(r[x],A);if(B>=0&&n[B]===n[A]&&ta(f[B],B,f[A],A)){c[A]=1;break}}g+=c[A]}return g},m=p(),h=0;for(;m>0&&h<a;){h++;for(let g=0;g<e;g++){if(l[g]=-2,!c[g])continue;let A=!0;for(let x=i[g];x<i[g+1]&&A;x++){let B=u(r[x],g);B>=0&&c[B]&&!ta(f[g],g,f[B],B)&&(A=!1)}A&&(l[g]=d(g,!0))}for(let g=0;g<e;g++)l[g]!==-2&&(n[g]=l[g],c[g]=0,m--)}let b=0;if(m>0){for(let g=0;g<e;g++)c[g]&&n[g]<0&&(n[g]=0);b=p()}let y=this.colorStart;y.fill(0);let v=0;for(let g=0;g<e;g++)t[g]&&(y[n[g]+1]++,v=Math.max(v,n[g]+1));for(let g=0;g<64;g++)y[g+1]+=y[g];let w=y.slice(0,64);for(let g=0;g<e;g++)t[g]&&(this.colorBodies[w[n[g]]++]=g);return{numColors:v,conflicts:b,rounds:h}}};var Gn=0,Qt=1,Fn=2,ks=3,ia=4,Un=[0,3,1,1,2],Pc=.05,D=4,T=32,ge=0,ne=3,$=6,ft=9,dt=12,gi=15,at=18,W=21,K=23,ye=25,Ee=26,vt=27,Cr=28,Ps=class{params=As();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 ws;coloring=new Ss;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,s=[0,0,0]){let a=this.bodyCount++,n=this.bodyCount*4;this.pose=this.grow(this.pose,n),this.initial=this.grow(this.initial,n),this.inertial=this.grow(this.inertial,n),this.velocity=this.grow(this.velocity,n),this.prevVelocity=this.grow(this.prevVelocity,n),this.shape=this.grow(this.shape,n),this.props=this.grow(this.props,n),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],a*4),this.velocity.set([s[0],s[1],s[2]??0,0],a*4),this.prevVelocity.set(this.velocity.subarray(a*4,a*4+4),a*4),this.shape.set([e[0],e[1],l,l*(e[0]*e[0]+e[1]*e[1])/12],a*4),this.props.set([i,Math.hypot(e[0]*.5,e[1]*.5),0,0],a*4),this.dynamic[a]=l>0?1:0,a}allocConstraint(){let e=this.jointCount++,t=this.jointCount+this.contactCount;this.info=this.grow(this.info,t*D),this.data=this.grow(this.data,t*T),this.contactCount>0&&(this.info.copyWithin((e+1)*D,e*D,(t-1)*D),this.data.copyWithin((e+1)*T,e*T,(t-1)*T)),this.data.fill(0,e*T,e*T+T);for(let i=0;i<3;i++)this.data[e*T+$+i]=1/0,this.data[e*T+ft+i]=-1/0,this.data[e*T+dt+i]=1/0,this.data[e*T+gi+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*D)}addJoint(e,t,i,r,s=[1/0,1/0,1/0],a=1/0){let n=this.allocConstraint();this.setInfo(n,Qt,e,t);let l=this.data,c=n*T;l.set(s,c+$),l[c+dt+2]=a,l[c+ft+2]=-a,l[c+gi+2]=a,l.set(i,c+W),l.set(r,c+K),l[c+ye]=(e>=0?this.pose[e*4+2]:0)-this.pose[t*4+2];let f=(e>=0?this.shape[e*4]:0)+this.shape[t*4],u=(e>=0?this.shape[e*4+1]:0)+this.shape[t*4+1];l[c+Ee]=f*f+u*u;let d={slot:n,alive:!0};return this.handles[n]=d,d}setJointWorldAnchor(e,t,i){e.alive&&(this.data[e.slot*T+W]=t,this.data[e.slot*T+W+1]=i)}removeJoint(e){e.alive&&(this.disable(e.slot),e.alive=!1)}addSpring(e,t,i,r,s,a){let n=this.allocConstraint();this.setInfo(n,Fn,e,t);let l=n*T;this.data[l+$]=s,this.data.set(i,l+W),this.data.set(r,l+K),this.data[l+ye]=a}addMotor(e,t,i,r){let s=this.allocConstraint();this.setInfo(s,ks,e,t);let a=s*T;this.data[a+dt]=r,this.data[a+ft]=-r,this.data[a+ye]=i}ignoredPairs(){return this.ignorePairs}addIgnoreCollision(e,t){this.ignorePairs.push(er(e,t)),this.noCollideDirty=!0}loadFromReference(e){this.clear();let t=Object.keys(As());Object.assign(this.params,Object.fromEntries(t.map(r=>[r,e[r]])));let i=new Map(e.bodies.map((r,s)=>[r,s]));for(let r of e.bodies){let s=this.addBody(r.size,0,r.friction,r.position,r.velocity);this.shape[s*4+2]=r.mass,this.shape[s*4+3]=r.moment,this.dynamic[s]=r.mass>0?1:0}for(let r of e.forces){let s=r.bodyA?i.get(r.bodyA):-1,a=i.get(r.bodyB);if(r instanceof gs){let n=this.addJoint(s,a,r.rA,r.rB,[r.stiffness[0],r.stiffness[1],r.stiffness[2]],r.fracture[2]);this.data[n.slot*T+ye]=r.restAngle,this.data[n.slot*T+Ee]=r.torqueArm}else r instanceof ys?this.addSpring(s,a,r.rA,r.rB,r.stiffness[0],r.rest):r instanceof xs?this.addMotor(s,a,r.speed,r.fmax[0]):r instanceof vs&&this.addIgnoreCollision(s,a)}}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 s=0;s<r;s++){let a=t?s<e.iterations?1:0:i;this.primal(a),this.mark("primal"),s<e.iterations&&this.dual(a),s===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*D),this.prevData=new Float64Array(e*2*T));for(let i=0;i<e;i++){let r=t+i;this.prevKeys[i]=er(this.info[r*D+1],this.info[r*D+2])}this.prevInfo.set(this.info.subarray(t*D,(t+e)*D)),this.prevData.set(this.data.subarray(t*T,(t+e)*T)),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*D+1],r=this.info[t*D+2];this.info[t*D]!==Gn&&i>=0&&e.push(er(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 s=0;s<this.jointCount;s++){let a=s*T;if(e[s*D]===Qt){if(t[a+$]===0&&t[a+$+1]===0&&t[a+$+2]===0){let f=this.handles[s];f&&(f.alive=!1);continue}let l=e[s*D+1],c=e[s*D+2];this.jointC(l,c,a,i,t,a+at)}r!==s&&(e.copyWithin(r*D,s*D,(s+1)*D),t.copyWithin(r*T,a,a+T),this.handles[r]=this.handles[s],this.handles[r]&&(this.handles[r].slot=r)),r++}if(r!==this.jointCount){for(let s=r;s<this.jointCount;s++)this.handles[s]=null;this.jointCount=r,this.noCollideDirty=!0}}jointC(e,t,i,r,s,a,n=s){let l,c,f;if(e>=0){let h=Math.cos(r[e*4+2]),b=Math.sin(r[e*4+2]),y=s[i+W],v=s[i+W+1];l=h*y-b*v+r[e*4],c=b*y+h*v+r[e*4+1],f=r[e*4+2]}else l=s[i+W],c=s[i+W+1],f=0;let u=Math.cos(r[t*4+2]),d=Math.sin(r[t*4+2]),p=s[i+K],m=s[i+K+1];n[a]=l-(u*p-d*m+r[t*4]),n[a+1]=c-(d*p+u*m+r[t*4+1]),n[a+2]=(f-r[t*4+2]-s[i+ye])*s[i+Ee]}narrowphase(){let{pose:e,shape:t,props:i}=this,r=this.broadphase.pairs,s=this.contactOut;for(let a=0;a<this.broadphase.pairCount;a++){let n=r[a],l=Math.floor(n/2097152),c=n-l*2097152,f=In(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,s);if(f===0)continue;let u=0,d=this.prevCount;for(;u<d;){let h=u+d>>>1;this.prevKeys[h]<n?u=h+1:d=h}let p=u,m=Math.sqrt(i[l*4]*i[c*4]);for(let h=0;h<f;h++){let b=this.jointCount+this.contactCount++;this.info=this.grow(this.info,(b+1)*D),this.data=this.grow(this.data,(b+1)*T);let y=this.data,v=b*T,w=h*7,g=s[w+0];this.info.set([ia,l,c,g],b*D),y.fill(0,v,v+T),y[v+$]=y[v+$+1]=1/0,y[v+ft]=-1/0,y[v+dt]=0,y[v+gi]=y[v+gi+1]=1/0,y[v+W]=s[w+1],y[v+W+1]=s[w+1+1],y[v+K]=s[w+3],y[v+K+1]=s[w+3+1],y[v+ye]=m,y[v+Ee]=s[w+5],y[v+vt]=s[w+5+1];let A=-1;for(let C=p;C<this.prevCount&&this.prevKeys[C]===n;C++)this.prevInfo[C*D+3]===g&&(A=C);if(A<0&&this.params.matchNearest){let C=Pc*Math.min(t[l*4],t[l*4+1],t[c*4],t[c*4+1]);for(let S=p;S<this.prevCount&&this.prevKeys[S]===n;S++){let R=Math.hypot(this.prevData[S*T+W]-y[v+W],this.prevData[S*T+W+1]-y[v+W+1]);R<=C&&(C=R,A=S)}}if(A>=0){let C=A*T;y[v+ge]=this.prevData[C+ge],y[v+ge+1]=this.prevData[C+ge+1],y[v+ne]=this.prevData[C+ne],y[v+ne+1]=this.prevData[C+ne+1],this.prevData[C+Cr]&&(y[v+W]=this.prevData[C+W],y[v+W+1]=this.prevData[C+W+1],y[v+K]=this.prevData[C+K],y[v+K+1]=this.prevData[C+K+1])}let[x,B]=Yt(e[l*4+2],y[v+W],y[v+W+1]),[E,k]=Yt(e[c*4+2],y[v+K],y[v+K+1]),z=y[v+Ee],M=y[v+vt],P=e[l*4]+x-e[c*4]-E,_=e[l*4+1]+B-e[c*4+1]-k;y[v+at]=z*P+M*_+5e-4,y[v+at+1]=M*P-z*_}}}warmStartConstraints(e,t){let i=this.params,r=this.data,s=this.jointCount+this.contactCount;for(let a=0;a<s;a++){let n=Un[this.info[a*D]],l=a*T;for(let c=0;c<n;c++){if(i.vbd){r[l+ge+c]=Ki(r[l+$+c],i.vbdStiffness);continue}e||(r[l+ne+c]=r[l+ne+c]*t*i.gamma),r[l+ge+c]=Ki(Zi(r[l+ge+c]*i.gamma,1,1e9),r[l+$+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 s=0;s<t;s++)for(let a=1;a<=2;a++){let n=this.info[s*D+a];n>=0&&this.dynamic[n]&&i[n+1]++}for(let s=0;s<e;s++)i[s+1]+=i[s];let r=i.slice(0,e);for(let s=0;s<t;s++)for(let a=1;a<=2;a++){let n=this.info[s*D+a];n>=0&&this.dynamic[n]&&(this.adjList[r[n]++]=s)}}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:s,inertial:a,prevVelocity:n}=this;for(let l=0;l<this.bodyCount;l++){let c=l*4;r[c+2]=Zi(r[c+2],-50,50),a[c]=i[c]+r[c]*e,a[c+1]=i[c+1]+r[c+1]*e,a[c+2]=i[c+2]+r[c+2]*e,this.dynamic[l]&&(a[c+1]+=t*e*e);let f=(r[c+1]-n[c+1])/e*En(t),u=Zi(f/Math.abs(t),0,1);Number.isFinite(u)||(u=0),s[c]=i[c],s[c+1]=i[c+1],s[c+2]=i[c+2],i[c]=i[c]+r[c]*e,i[c+1]=i[c+1]+r[c+1]*e+t*u*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:s,pose:a,initial:n}=this,l=r[e*D],c=r[e*D+1],f=r[e*D+2],u=e*T,{eC:d,eMin:p,eMax:m,eJ:h,eG:b}=this,y=Un[l];for(let w=0;w<y;w++)p[w]=s[u+ft+w],m[w]=s[u+dt+w];let v=i===c;if(b.fill(0),l===Qt){this.jointC(c,f,u,a,s,0,d);for(let w=0;w<3;w++)s[u+$+w]===1/0&&(d[w]-=s[u+at+w]*t);if(i>=0){let w=a[i*4+2],[g,A]=Yt(w,s[u+(v?W:K)],s[u+(v?W:K)+1]),x=v?1:-1;h[0]=x,h[1]=0,h[2]=-x*A,h[3]=0,h[4]=x,h[5]=x*g,h[6]=0,h[7]=0,h[8]=x*s[u+Ee],b[2]=Math.abs(g),b[5]=Math.abs(A)}}else if(l===Fn){let[w,g]=Nn(a,c,s[u+W],s[u+W+1]),[A,x]=Nn(a,f,s[u+K],s[u+K+1]),B=w-A,E=g-x,k=B*B+E*E,z=Math.sqrt(k);if(d[0]=z-s[u+ye],i>=0&&k!==0){let M=B/z,P=E/z,_=(1-M*M)/z,C=-M*P/z,S=(1-P*P)/z,R=a[i*4+2],I=v?W:K,[O,q]=Yt(R,-s[u+I+1],s[u+I]),[G,j]=Yt(R,s[u+I],s[u+I+1]),F=_*O+C*q,H=C*O+S*q,ee=M*G+P*j,le=M*O+P*q,xe=v?1:-1;h[0]=xe*M,h[1]=xe*P,h[2]=xe*le;let U=v?-ee-ee:ee+ee;b[0]=Math.hypot(_,C,F),b[1]=Math.hypot(C,S,H),b[2]=Math.hypot(F,H,U)}else i>=0&&h.fill(0,0,3)}else if(l===ks){let w=c>=0?a[c*4+2]-n[c*4+2]:0,g=a[f*4+2]-n[f*4+2];d[0]=w-g-s[u+ye]*this.params.dt,i>=0&&(h[0]=0,h[1]=0,h[2]=v?1:-1)}else if(l===ia){let w=s[u+Ee],g=s[u+vt],A=g,x=-w,[B,E]=Yt(n[c*4+2],s[u+W],s[u+W+1]),[k,z]=Yt(n[f*4+2],s[u+K],s[u+K+1]),M=B*g-E*w,P=-(k*g-z*w),_=B*x-E*A,C=-(k*x-z*A),S=a[c*4]-n[c*4],R=a[c*4+1]-n[c*4+1],I=a[c*4+2]-n[c*4+2],O=a[f*4]-n[f*4],q=a[f*4+1]-n[f*4+1],G=a[f*4+2]-n[f*4+2];d[0]=s[u+at]*(1-t)+w*S+g*R+M*I+-w*O+-g*q+P*G,d[1]=s[u+at+1]*(1-t)+A*S+x*R+_*I+-A*O+-x*q+C*G;let j=Math.abs(s[u+ne])*s[u+ye];m[1]=j,p[1]=-j,i>=0&&(v?(h[0]=w,h[1]=g,h[2]=M,h[3]=A,h[4]=x,h[5]=_):(h[0]=-w,h[1]=-g,h[2]=P,h[3]=-A,h[4]=-x,h[5]=C))}return y}solveBody(e,t){let i=this.params,{shape:r,pose:s,inertial:a,data:n}=this,l=i.dt*i.dt,c=r[e*4+2]/l,f=r[e*4+3]/l,u=c,d=0,p=c,m=0,h=0,b=f,y=c*(s[e*4]-a[e*4]),v=c*(s[e*4+1]-a[e*4+1]),w=f*(s[e*4+2]-a[e*4+2]),{eC:g,eMin:A,eMax:x,eJ:B,eG:E}=this,k=this.adjStart,z=this.adjList;for(let F=k[e+1]-1;F>=k[e];F--){let H=z[F],ee=this.evalConstraint(H,t,e),le=H*T,xe=!i.vbd;for(let U=0;U<ee;U++){let ze=n[le+$+U],Me=xe&&ze===1/0?n[le+ne+U]:0,ce=n[le+ge+U],qe=g[U],zt=ce*qe+Me,Ie=Zi(zt,A[U],x[U]),Ve=Math.abs(Ie);i.stiffnessRescale&&qe!==0&&(zt<A[U]?ce=Math.abs((A[U]-Me)/qe):zt>x[U]&&(ce=Math.abs((x[U]-Me)/qe)));let Re=B[U*3],We=B[U*3+1],et=B[U*3+2];y+=Re*Ie,v+=We*Ie,w+=et*Ie,u+=Re*Re*ce+E[U*3]*Ve,d+=We*Re*ce,p+=We*We*ce+E[U*3+1]*Ve,m+=et*Re*ce,h+=et*We*ce,b+=et*et*ce+E[U*3+2]*Ve}}let M=u,P=d/u,_=m/u,C=p-P*P*M,S=(h-P*_*M)/C,R=b-(_*_*M+S*S*C),I=v-P*y,q=(w-_*y-S*I)/R,G=I/C-S*q,j=y/M-P*G-_*q;this.dxBuf[e*3]=j,this.dxBuf[e*3+1]=G,this.dxBuf[e*3+2]=q}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 s=t[r];s<t[r+1];s++)this.solveBody(i[s],e);for(let s=t[r];s<t[r+1];s++)this.applyDx(i[s])}}dual(e){let t=this.params,i=this.data,{eC:r,eMin:s,eMax:a}=this,n=this.jointCount+this.contactCount;for(let l=0;l<n;l++){let c=this.info[l*D];if(c===Gn)continue;let f=this.evalConstraint(l,e,-1),u=l*T;c===ia&&(i[u+Cr]=Math.abs(i[u+ne+1])<a[1]&&Math.abs(i[u+at+1])<.01?1:0);for(let d=0;d<f;d++){let p=i[u+$+d],m=!t.vbd&&p===1/0?i[u+ne+d]:0,h=Zi(i[u+ge+d]*r[d]+m,s[d],a[d]);i[u+ne+d]=h,Math.abs(h)>=i[u+gi+d]&&this.disable(l),!t.vbd&&h>s[d]&&h<a[d]&&(i[u+ge+d]=Ki(i[u+ge+d]+t.beta*Math.abs(r[d]),Ki(1e9,i[u+$+d])))}}}refreshStick(){let e=this.data;for(let t=0;t<this.contactCount;t++){let i=(this.jointCount+t)*T,r=Math.abs(e[i+ne])*e[i+ye];e[i+Cr]=Math.abs(e[i+ne+1])<r&&Math.abs(e[i+at+1])<.01?1:0}}disable(e){let t=e*T;this.data.fill(0,t+ge,t+ge+3),this.data.fill(0,t+ne,t+ne+3),this.data.fill(0,t+$,t+$+3)}updateVelocities(){let{dt:e}=this.params,{pose:t,initial:i,velocity:r,prevVelocity:s}=this;for(let a=0;a<this.bodyCount;a++){let n=a*4;s[n]=r[n],s[n+1]=r[n+1],s[n+2]=r[n+2],this.dynamic[a]&&(r[n]=(t[n]-i[n])/e,r[n+1]=(t[n+1]-i[n+1])/e,r[n+2]=(t[n+2]-i[n+2])/e)}}pick(e,t){for(let i=this.bodyCount-1;i>=0;i--){let[r,s]=Yt(-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(s)<=this.shape[i*4+1]*.5)return{body:i,local:[r,s]}}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*D]!==Qt)continue;let r=i*T;this.jointC(this.info[i*D+1],this.info[i*D+2],r,this.pose,this.data,0,t);for(let s=0;s<2;s++)this.data[r+$+s]===1/0&&(e=Math.max(e,Math.abs(t[s])))}return e}isContactPairIgnored(e,t){return ea(this.noCollide,this.noCollideCount,er(e,t))}};function Yt(o,e,t){let i=Math.cos(o),r=Math.sin(o);return[i*e-r*t,r*e+i*t]}function Nn(o,e,t,i){let r=Math.cos(o[e*4+2]),s=Math.sin(o[e*4+2]);return[r*t-s*i+o[e*4],s*t+r*i+o[e*4+1]]}var Sr=`
3604
- ${mt}
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?Ou: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:(Zn+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,(Zn+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 it=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,Pr=s=>{if(!Number.isInteger(s)||s<0||s>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");return s},Ys=(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},Kr=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 wr({preferredLimits:{maxStorageBuffersPerShaderStage:9,maxStorageBufferBindingSize:512*1024*1024,maxBufferSize:1024*1024*1024}}));let r;try{return await Ni(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=Ys(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,$s(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 Zr(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 Cr(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 Sr(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(),Pr(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}={}){Pr(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&&Ys(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
+ ${Pl}`,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}},Zr=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 Kr?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=[it.SPHERE,it.CAPSULE,it.CYLINDER,it.BOX,it.CONVEX_HULL][t]),Ys(i,"mass",!0),Ys(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(it).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=Pr(c),this.collidesWith=Pr(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(![it.BOX,it.SPHERE,it.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===it.BOX)b=new Ze(f.ref,Je(g),1,r,[0,0,0]);else if(t===it.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=nr(f.ref,g.x/2,1,r,[0,0,0])}else if(t===it.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=xr(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=Gr(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=ks(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 es(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?.()}},es=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=Pr(e),o=Pr(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 Ui=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 _l=s=>s<0?-1:s>0?1:0,Lr=(s,e)=>s<e?s:e,Tu=(s,e)=>s>e?s:e,_r=(s,e,t)=>Tu(e,Lr(t,s));function ts(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 Kt(s,e,t,i,r){s[e*3]=t,s[e*3+1]=i,s[e*3+2]=r}var Qs=class extends Ui{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=ts(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=ts(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 Ui{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=ts(e.position[2],-d[1],d[0]),g=ts(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 Ui{rows(){return 0}initialize(){return!0}computeConstraint(){}computeDerivatives(){}},eo=class extends Ui{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 Er=(s,e)=>s>e?s*2097152+e:e*2097152+s;function ju(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 ea(s,e,t){let i=ju(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=Er(h,m);if(!ea(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),El=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 Ml(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(Ml(El,pt,-W,-N,H,he)<2||Ml(Vi,El,W,N,Z,we)<2)return 0;let Oe=0;for(let J=0;J<2;J++){let $e=J*6,Xe=Vi[$e],Be=Vi[$e+1],ot=R*Xe+F*Be-X;if(ot>0)continue;let ii=Xe-R*ot,Ye=Be-F*ot,nt=Vi[$e+2],Qe=Vi[$e+3],at=Vi[$e+4],At=Vi[$e+5],Qi,Ki,Zi,er;k>=2?([nt,Qe,at,At]=[at,At,nt,Qe],Qi=Xe-s,Ki=Be-e,Zi=ii-o,er=Ye-n):(Qi=ii-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|(At&255)<<24,u[Wt+1]=f*Qi+d*Ki,u[Wt+1+1]=-d*Qi+f*Ki,u[Wt+3]=p*Zi+g*er,u[Wt+3+1]=-g*Zi+p*er,u[Wt+5]=-P,u[Wt+5+1]=-I,Oe++}return Oe}var zl=s=>31-Math.clz32(s&-s);function Du(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 ta=(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)=>Du(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?zl(~x):~B!==0?32+zl(~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&&!ta(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]&&ta(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]&&!ta(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 Il=0,xi=1,Rl=2,uo=3,is=4,Ol=[0,3,1,1,2],ra=.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,Wi=28,Mr=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,Rl,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(Er(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]=Er(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]!==Il&&i>=0&&e.push(Er(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([is,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=ra*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+Wi]&&(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=Ol[this.info[n*j]],l=n*O;for(let c=0;c<a;c++){if(i.vbd){r[l+se+c]=Lr(r[l+Q+c],i.vbdStiffness);continue}e||(r[l+te+c]=r[l+te+c]*t*i.gamma),r[l+se+c]=Lr(_r(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]=_r(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*_l(t),f=_r(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=Ol[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===Rl){let[w,y]=Tl(n,c,o[f+U],o[f+U+1]),[A,x]=Tl(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===is){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],ot=y[J],ii=Be*ot+Xe,Ye=_r(ii,A[J],x[J]),nt=Math.abs(Ye);i.stiffnessRescale&&ot!==0&&(ii<A[J]?Be=Math.abs((A[J]-Xe)/ot):ii>x[J]&&(Be=Math.abs((x[J]-Xe)/ot)));let Qe=B[J*3],at=B[J*3+1],At=B[J*3+2];b+=Qe*Ye,v+=at*Ye,w+=At*Ye,f+=Qe*Qe*Be+E[J*3]*nt,d+=at*Qe*Be,p+=at*at*Be+E[J*3+1]*nt,g+=At*Qe*Be,h+=At*at*Be,m+=At*At*Be+E[J*3+2]*nt}}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===Il)continue;let u=this.evalConstraint(l,e,-1),f=l*O;c===is&&(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],g=!t.vbd&&p===1/0?i[f+te+d]:0,h=_r(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]=Lr(i[f+se+d]+t.beta*Math.abs(r[d]),Lr(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]=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 ea(this.noCollide,this.noCollideCount,Er(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 Tl(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 rs=`
3609
+ ${Nt}
3605
3610
 
3606
3611
  @group(0) @binding(0) var<uniform> params: Params;
3607
3612
  @group(0) @binding(1) var<storage, read> bodies: array<Body>;
@@ -3740,8 +3745,8 @@ fn findPairs(@builtin(global_invocation_id) gid: vec3u) {
3740
3745
  testPair(l, i);
3741
3746
  }
3742
3747
  }
3743
- `,kr=`
3744
- ${mt}
3748
+ `,ss=`
3749
+ ${Nt}
3745
3750
 
3746
3751
  @group(0) @binding(0) var<uniform> params: Params;
3747
3752
  @group(0) @binding(1) var<storage, read> bodies: array<Body>;
@@ -4067,8 +4072,8 @@ fn narrowphase(@builtin(global_invocation_id) gid: vec3u) {
4067
4072
  contacts[k] = rec;
4068
4073
  }
4069
4074
  }
4070
- `;var Pr=`
4071
- ${mt}
4075
+ `;var os=`
4076
+ ${Nt}
4072
4077
 
4073
4078
  // Per-dispatch constants, selected with a dynamic uniform offset
4074
4079
  struct PassConstants {
@@ -4440,7 +4445,7 @@ fn updateVelocities(@builtin(global_invocation_id) gid: vec3u) {
4440
4445
  if (b.shape.z > 0.0) { b.vel = vec4f((b.pose.xyz - b.initial.xyz) / params.dt, 0.0); }
4441
4446
  bodies[i] = b;
4442
4447
  }
4443
- `;var Ls=o=>o===1/0?3e38:o===-1/0?-3e38:o,Qe=o=>Math.ceil(o/64),Wn=o=>2**Math.ceil(Math.log2(Math.max(o,2))),Oc=o=>Math.max(o,1)*24*4,jc=4,Ke=()=>GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST,_s=class{device;params=Bs();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:Oc(this.bodyCapacity),usage:Ke()});let r=this.bodyCapacity;this.tableSize=Wn(2*r),this.gridBuffer=e.createBuffer({label:"grid",size:(2*this.tableSize+1+3*r)*4,usage:Ke()}),this.counterBuffer=e.createBuffer({label:"counters",size:64,usage:Ke()}),this.argsBuffer=e.createBuffer({label:"indirect args",size:816,usage:Ke()|GPUBufferUsage.INDIRECT}),this.colorGroups=Math.ceil(r/256),this.colorBuffer=e.createBuffer({label:"colours",size:(3*r+65+64*this.colorGroups+1)*4,usage:Ke()}),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 s=2*fe.length;this.timing=e.features.has("timestamp-query")?{querySet:e.createQuerySet({type:"timestamp",count:s}),resolve:e.createBuffer({size:s*8,usage:GPUBufferUsage.QUERY_RESOLVE|GPUBufferUsage.COPY_SRC}),read:e.createBuffer({size:s*8,usage:GPUBufferUsage.MAP_READ|GPUBufferUsage.COPY_DST})}:null,this.layouts=this.createLayouts(),this.createPipelines(),this.gridScan=new Fe(e,this.gridBuffer,0,this.tableSize+1),this.colorHistScan=new Fe(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=(a,n)=>e.createBindGroupLayout({label:a,entries:n.map((l,c)=>({binding:c,visibility:GPUShaderStage.COMPUTE,buffer:{type:l}}))}),i="read-only-storage",r="storage",s="uniform";return{broad:t("broadphase",[s,i,r,r,r,i,i]),contacts:t("contacts",[s,i,i,r,i,r,r]),topo:t("topology",[s,i,i,i,i,r,r,r]),solve:t("solve",[s,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",[s,i,i,r])}}createPipelines(){let e=this.device,t=(r,s,a)=>{let n=e.createShaderModule({code:r}),l=e.createPipelineLayout({bindGroupLayouts:s});for(let c of a)this.pipes[c]=e.createComputePipeline({label:c,layout:l,compute:{module:n,entryPoint:c}})},i=this.layouts;t(Sr,[i.broad],["beginFrame","gridCount","gridScatter","findPairs"]),t(kr,[i.contacts],["hashInsert","narrowphase"]),t(cr,[i.topo],["degreeJoints","degreeContacts","fillJoints","fillContacts","sortAdjacency","colorCompact","colorMark","colorRoundAB","colorRoundBA","colorCount","colorStarts","colorScatter"]),t(Pr,[i.solve,i.pass],["warmStartJoints","warmStartBodies","primal","primalScan","dual","refreshStick","updateVelocities"]),t(Vr,[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:Ke()}),r=t.createBuffer({label:"joint info",size:Math.max(e,1)*16,usage:Ke()});if(this.jointBuffer){let s=t.createCommandEncoder();s.copyBufferToBuffer(this.jointBuffer,0,i,0,this.jointCapacity*36*4),s.copyBufferToBuffer(this.infoBuffer,0,r,0,this.jointCapacity*16),t.queue.submit([s.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,s=Math.min(e,Math.floor(r/80),Math.floor(r/16)),a=Math.min(t,Math.floor(r/8)),n=this.contactBuffers,l=this.contactCapacity;for(let c of[this.pairBuffer,this.tableBuffer])c?.destroy();if(this.contactCapacity=s,this.pairCapacity=a,this.hashSize=Wn(4*s),this.pairBuffer=i.createBuffer({label:"pairs",size:a*8,usage:Ke()}),this.tableBuffer=i.createBuffer({label:"contact hash",size:this.hashSize*4,usage:Ke()}),this.contactBuffers=[0,1].map(c=>i.createBuffer({label:`contacts ${c}`,size:s*20*4,usage:Ke()})),n){let c=i.createCommandEncoder(),f=Math.min(l,s)*20*4;n.forEach((u,d)=>c.copyBufferToBuffer(u,0,this.contactBuffers[d],0,f)),i.queue.submit([c.finish()]),n.forEach(u=>u.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:Ke()}),this.adjScan?.destroy(),this.adjScan=new Fe(e,this.adjBuffer,0,this.bodyCount+1),this.staticBuffer??=e.createBuffer({label:"statics",size:16,usage:Ke()});let i=(l,c)=>e.createBindGroup({layout:l,entries:c.map((f,u)=>({binding:u,resource:{buffer:f}}))}),r=this.paramsBuffer,[s,a]=this.contactBuffers,n=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,s,a,this.tableBuffer,this.counterBuffer]),i(this.layouts.contacts,[r,this.bodyBuffer,this.pairBuffer,a,s,this.tableBuffer,this.counterBuffer])],topo:[s,a].map(l=>i(this.layouts.topo,[r,this.bodyBuffer,this.jointBuffer,this.infoBuffer,l,this.counterBuffer,n,this.colorBuffer])),solve:[s,a].map(l=>i(this.layouts.solve,[r,this.bodyBuffer,this.jointBuffer,this.infoBuffer,l,n,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 s=0;s<t;s++){let a=e+s,n=s*24;r.set(i.pose.subarray(a*4,a*4+3),n),r[n+3]=i.props[a*4],r.set(i.initial.subarray(a*4,a*4+4),n+4),r.set(i.inertial.subarray(a*4,a*4+4),n+8),r.set(i.velocity.subarray(a*4,a*4+4),n+12),r.set(i.prevVelocity.subarray(a*4,a*4+4),n+16),r.set(i.shape.subarray(a*4,a*4+4),n+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 s=0;s<t;s++){let a=(e+s)*T,n=s*36;for(let l=0;l<3;l++)r[n+0+l]=i.data[a+ge+l],r[n+4+l]=i.data[a+ne+l],r[n+8+l]=Ls(i.data[a+$+l]),r[n+12+l]=Ls(i.data[a+ft+l]),r[n+16+l]=Ls(i.data[a+dt+l]),r[n+20+l]=Ls(i.data[a+gi+l]),r[n+24+l]=i.data[a+at+l];r[n+28]=i.data[a+W],r[n+28+1]=i.data[a+W+1],r[n+28+2]=i.data[a+K],r[n+28+3]=i.data[a+K+1],r[n+32]=i.data[a+ye],r[n+32+1]=i.data[a+Ee]}this.device.queue.writeBuffer(this.jointBuffer,e*36*4,r),this.device.queue.writeBuffer(this.infoBuffer,e*16,i.info,e*D,t*D)}uploadStatics(){let e=this.topology,t=this.bodyCount,i=Float64Array.from({length:t},(u,d)=>e.props[d*4+1]).sort(),r=t>0?i[t>>1]:1,s=0;for(let u=0;u<t;u++)i[u]<=jc*r&&(s=Math.max(s,i[u]));let a=1/0;for(let u=0;u<t;u++)i[u]>s&&(a=Math.min(a,i[u]));let n=a===1/0?s*1.5:(s+a)/2;this.maxSmallRadius=n,this.cellSize=Math.max(2*s*(1+1e-4),.001);let l=[];for(let u=0;u<t;u++)e.props[u*4+1]>n&&l.push(u);let c=[];for(let u=0;u<e.jointCount;u++){let d=e.info[u*D+1],p=e.info[u*D+2];d>=0&&c.push([Math.max(d,p),Math.min(d,p),u])}for(let u of e.ignoredPairs()){let d=Math.floor(u/2097152);c.push([d,u-d*2097152,4294967295])}c.sort((u,d)=>u[0]-d[0]||u[1]-d[1]),this.largeCount=l.length,this.noCollideCount=c.length;let f=new Uint32Array(Math.max(l.length+3*c.length,4));f.set(l,0),c.forEach((u,d)=>f.set(u,l.length+3*d)),this.staticBuffer.size<f.byteLength&&(this.staticBuffer.destroy(),this.staticBuffer=this.device.createBuffer({label:"statics",size:f.byteLength,usage:Ke()}),this.rebuildBindings()),this.device.queue.writeBuffer(this.staticBuffer,0,f),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),s=new Float32Array(i);for(let l=0;l<t;l++){let c=e.jointCount+l,f=c*T,u=l*20;r[u]=e.info[c*D+1],r[u+1]=e.info[c*D+2],r[u+2]=e.info[c*D+3],r[u+3]=e.data[f+Cr]?1:0,s.set([e.data[f+ge],e.data[f+ge+1],e.data[f+ne],e.data[f+ne+1]],u+4),s.set([e.data[f+W],e.data[f+W+1],e.data[f+K],e.data[f+K+1]],u+8),s.set([e.data[f+at],e.data[f+at+1],e.data[f+Ee],e.data[f+vt]],u+12),s[u+16]=e.data[f+ye]}this.device.queue.writeBuffer(this.contactBuffers[1-this.parity],0,i);let a=new Uint32Array(16);a[1]=t,this.device.queue.writeBuffer(this.counterBuffer,0,a);let n=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,n)}addBody(e,t,i,r,s){if(this.bodyCount>=this.bodyCapacity)return-1;let a=this.topology.addBody(e,t,i,r,s);return this.bodyCount=this.topology.bodyCount,this.uploadBodies(a,1),this.device.queue.writeBuffer(this.colorBuffer,a*4,new Uint32Array([255])),this.adjScan.destroy(),this.adjScan=new Fe(this.device,this.adjBuffer,0,this.bodyCount+1),a}appendJoint(e,t,i,r,s,a=1/0){let n=this.topology;if(n.contactCount>0)throw new Error("appendJoint: the CPU mirror must not hold contacts");let l=n.addJoint(e,t,i,r,s,a).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*T+$,e*T+$+3)}profileNextStep(e){this.timing&&!this.timingBusy&&(this.timingCallback=e)}writeParams(e,t){let i=this.params,r=this.bodyCapacity,s=new ArrayBuffer(128),a=new Float32Array(s),n=new Uint32Array(s);a[0]=i.dt,a[1]=i.gravity,a[2]=i.beta,a[3]=i.gamma,a[4]=e,a[5]=i.vbdStiffness,n[6]=(i.vbd?1:0)|(i.stiffnessRescale?2:0)|(t?4:0)|(i.matchNearest?8:0),n[7]=this.bodyCount,n[8]=this.jointCount,n[9]=this.colorCap,a[10]=this.cellSize,n[11]=this.tableSize-1,a[12]=this.maxSmallRadius,n[13]=this.largeCount,n[14]=this.noCollideCount,n[15]=this.pairCapacity,n[16]=this.contactCapacity,n[17]=this.hashSize-1,n[18]=r+1,n[19]=2*r+1,n[20]=this.tableSize+1,n[21]=2*this.tableSize+1,n[22]=2*this.tableSize+1+r,n[23]=r,n[24]=this.colorHistOffset,n[25]=2*r,n[26]=this.colorGroups,n[27]=2*r+65,n[28]=this.colorRounds,this.device.queue.writeBuffer(this.paramsBuffer,0,s)}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 s=new ArrayBuffer(r*256),a=new Uint32Array(s),n=new Float32Array(s);for(let l=0;l<e;l++)for(let c=0;c<=this.colorCap;c++){let f=(l*i+c)*256/4;a[f]=c,n[f+1]=t(l)}this.device.queue.writeBuffer(this.passBuffer,0,s)}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 s=this.parity,a=this.bodyCapacity,n=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*a+1)*4);let f=this.timingCallback!==null&&this.timing!==null,u,d=0,p=f||this.splitPasses,m=()=>{u&&!p||(u?.end(),u=c.beginComputePass({label:p?fe[d]:"avbd2d step",timestampWrites:f?{querySet:this.timing.querySet,beginningOfPassWriteIndex:2*d,endOfPassWriteIndex:2*d+1}:void 0}),d++)},h=this.groups,b=(A,x,B)=>{B<=0||(u.setPipeline(this.pipes[A]),u.setBindGroup(0,x),u.dispatchWorkgroups(B))},y=(A,x,B)=>{u.setPipeline(this.pipes[A]),u.setBindGroup(0,x),u.dispatchWorkgroupsIndirect(this.argsBuffer,B*4)};m(),b("beginFrame",h.broad,1),b("argsPrev",h.args,1),y("hashInsert",h.contacts[s],6),b("gridCount",h.broad,Qe(n)),this.gridScan.encode(u),b("gridScatter",h.broad,Qe(n)),b("findPairs",h.broad,Qe(n)),b("argsPairs",h.args,1),y("narrowphase",h.contacts[s],0),b("argsContacts",h.args,1),m(),b("degreeJoints",h.topo[s],Qe(l)),y("degreeContacts",h.topo[s],3),this.adjScan.encode(u),b("fillJoints",h.topo[s],Qe(l)),y("fillContacts",h.topo[s],3),b("sortAdjacency",h.topo[s],Qe(n)),m(),b("colorCompact",h.topo[s],Qe(n)),b("colorMark",h.topo[s],Qe(n));for(let A=0;A<this.colorRounds;A++)b(A%2===0?"colorRoundAB":"colorRoundBA",h.topo[s],Qe(n));b("colorCount",h.topo[s],this.colorGroups),this.colorHistScan.encode(u),b("colorStarts",h.topo[s],1),b("argsColors",h.args,1),b("colorScatter",h.topo[s],this.colorGroups),m();let v=this.colorCap+1,w=A=>u.setBindGroup(1,this.passGroup,[A*256]);u.setBindGroup(0,h.solve[s]),w(0),l>0&&(u.setPipeline(this.pipes.warmStartJoints),u.dispatchWorkgroups(Qe(l))),u.setPipeline(this.pipes.warmStartBodies),u.dispatchWorkgroups(Qe(n));for(let A=0;A<r;A++){let x=this.primalMode==="scan";u.setPipeline(x?this.pipes.primalScan:this.pipes.primal);for(let B=0;B<this.colorCap;B++)w(A*v+B),x?u.dispatchWorkgroups(Qe(n)):u.dispatchWorkgroupsIndirect(this.argsBuffer,(12+3*B)*4);A<e.iterations&&(w(A*v+this.colorCap),u.setPipeline(this.pipes.dual),u.dispatchWorkgroupsIndirect(this.argsBuffer,36)),A===e.iterations-1&&(u.setPipeline(this.pipes.updateVelocities),u.dispatchWorkgroups(Qe(n)))}t&&(u.setPipeline(this.pipes.refreshStick),u.dispatchWorkgroupsIndirect(this.argsBuffer,12)),u.end();let g=2*fe.length;if(f){let{querySet:A,resolve:x,read:B}=this.timing;c.resolveQuerySet(A,0,g,x,0),c.copyBufferToBuffer(x,0,B,0,g*8)}if(this.device.queue.submit([c.finish()]),this.parity=1-s,f){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=(z,M)=>Number(B[M]-B[z])/1e6,k={total:E(0,g-1)};fe.forEach((z,M)=>k[z]=E(2*M,2*M+1)),A(k)},()=>{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,s=this.contactCapacity*(i?2:1),a=this.pairCapacity*(r?2:1);(i||r)&&this.capacityCanGrow(s,a)&&this.allocateContacts(s,a)}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 f=c*24,u=t[f+22],d=t[f+12],p=t[f+13],m=t[f+14];u>0&&(r+=.5*u*(d*d+p*p)+.5*t[f+23]*m*m)}let s=0,a=0,n=this.topology.info,l=(c,f,u)=>{let d=c*24,p=Math.cos(t[d+2]),m=Math.sin(t[d+2]);return[p*f-m*u+t[d],m*f+p*u+t[d+1]]};for(let c=0;c<this.jointCount;c++){if(n[c*D]!==Qt)continue;let f=c*36;if(i[f+8]===0&&i[f+8+1]===0&&i[f+8+2]===0)continue;a++;let u=n[c*D+1],d=n[c*D+2],p=u>=0?l(u,i[f+28],i[f+28+1]):[i[f+28],i[f+28+1]],m=l(d,i[f+28+2],i[f+28+3]);for(let h=0;h<2;h++)i[f+8+h]>=1e30&&(s=Math.max(s,Math.abs(p[h]-m[h])))}return{kineticEnergy:r,maxJointError:s,joints:a}}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 s=i.getMappedRange().slice(0);return i.unmap(),i.destroy(),s}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 Tc=`${mt}
4448
+ `;var fo=s=>s===1/0?3e38:s===-1/0?-3e38:s,mt=s=>Math.ceil(s/64),Gl=s=>2**Math.ceil(Math.log2(Math.max(s,2))),Xu=s=>Math.max(s,1)*24*4,Yu=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:Xu(this.bodyCapacity),usage:gt()});let r=this.bodyCapacity;this.tableSize=Gl(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(rs,[i.broad],["beginFrame","gridCount","gridScatter","findPairs"]),t(ss,[i.contacts],["hashInsert","narrowphase"]),t(Nr,[i.topo],["degreeJoints","degreeContacts","fillJoints","fillContacts","sortAdjacency","colorCompact","colorMark","colorRoundAB","colorRoundBA","colorCount","colorStarts","colorScatter"]),t(os,[i.solve,i.pass],["warmStartJoints","warmStartBodies","primal","primalScan","dual","refreshStick","updateVelocities"]),t(Ps,[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=Gl(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]<=Yu*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+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+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 Qu=`${Nt}
4444
4449
  struct Config { count:u32,joints:u32,capacity:u32,list:u32,threshold:f32,dt:f32,pad0:u32,pad1:u32 }
4445
4450
  struct Velocity { incoming:vec4f, incomingAngular:vec4f, linear:vec4f, angular:vec4f }
4446
4451
  struct Bounce { impulse:f32,delta:f32,reboundSpeed:f32,inverseMass:f32,rA:vec4f,rB:vec4f }
@@ -4486,9 +4491,9 @@ fn pointVelocity(i:u32,r:vec2f,incoming:bool)->vec2f{let v=select(velocities[i].
4486
4491
  velocities[i].linear+=vec4f(dv,0.);
4487
4492
  }
4488
4493
  @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;}
4489
- `,Es=class extends Vi{constructor(e){super(e,{code:Tc,dimension:2})}};function Hn(o){for(let e of["warmStartJoints","warmStartBodies","primal","primalScan","dual","refreshStick","updateVelocities"]){let t=`fn ${e}(@builtin(global_invocation_id) gid: vec3u) {`;if(o.split(t).length!==2)throw Error(`Pinned 2D ${e} signature changed; review the step guard`);o=o.replace(t,`${t}
4490
- if (counters[C_OVERFLOW] != 0u || counters[C_CLASHES] != 0u) { return; }`)}return o}function Jn(o){let e="if (col == NO_COLOR) { col = params.colorCap - 1u; }";if(o.split(e).length!==2)throw Error("Pinned 2D color-count layout changed; review the capacity guard");return o.replace(e,`${e}
4491
- if (col >= params.colorCap) { atomicAdd(&counters[C_CLASHES], 1u); }`)}var $n=`// Sleeping is scheduling metadata in velocity.w; physical mass and inertia stay intact.
4494
+ `;var po=class extends vr{constructor(e){super(e,{code:Qu,dimension:2})}};function Nl(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 Ul(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 ql=`// Sleeping is scheduling metadata in velocity.w; physical mass and inertia stay intact.
4492
4497
  struct Body {pose:vec4f,initial:vec4f,inertial:vec4f,vel:vec4f,prev:vec4f,shape:vec4f}
4493
4498
  struct Joint {pen:vec4f,lam:vec4f,stiff:vec4f,fmin:vec4f,fmax:vec4f,frac:vec4f,c0:vec4f,anchors:vec4f,param:vec4f}
4494
4499
  struct Contact {ids:vec4u,pl:vec4f,anchors:vec4f,geo:vec4f,misc:vec4f}
@@ -4559,10 +4564,10 @@ fn rotate(angle:f32,p:vec2f)->vec2f{let c=cos(angle);let s=sin(angle);return vec
4559
4564
  }
4560
4565
  if(asleep(i)){atomicAdd(&globals[1],1u);}
4561
4566
  }
4562
- `;function Ms(o={}){if(o!==!0&&(typeof o!="object"||o===null))throw Error("sleeping must be a boolean or options object");let e=o.speedThreshold??.03,t=o.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 Xn(o){for(let e of["warmStartBodies","updateVelocities"])o=o.replace(`fn ${e}(@builtin(global_invocation_id) gid: vec3u) {`,`fn ${e}(@builtin(global_invocation_id) gid: vec3u) {
4563
- if(gid.x<params.bodyCount && bodies[gid.x].vel.w!=0.){return;}`);return o.replace("fn solveBody(i: u32) {",`fn solveBody(i: u32) {
4564
- if(bodies[i].vel.w!=0.){return;}`)}function Yn(o){return o.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 zs=class{constructor(e,t){this.gpu=e,this.device=e.device,this.options=Ms(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 s=i.createShaderModule({code:$n});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 a=i.createPipelineLayout({bindGroupLayouts:[this.layout]});this.pipes=Object.fromEntries(["clear","before","contactsWake","jointsWake","decide","applyWake","rest"].map(l=>[l,i.createComputePipeline({layout:a,compute:{module:s,entryPoint:l}})]));let n=new Uint32Array(e.bodyCapacity*4);for(let l=0;l<e.bodyCount;l++)n[l*4+1]=e.sleepEligible?.get(l)===!1?0:1;i.queue.writeBuffer(this.state,0,n),this.wakeRequested=!1}register(e,t=!0){let i=Q(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(s=>s.buffers.every((a,n)=>a===i[n]));return r||(r={buffers:i,group:this.device.createBindGroup({layout:this.layout,entries:i.map((s,a)=>({binding:a,resource:{buffer:s}}))})},this.groups=[...(this.groups??[]).slice(-1),r]),r.group}dispatch(e,t,i){e.setBindGroup(0,this.group(t));for(let[r,s]of i)s&&(e.setPipeline(this.pipes[r]),e.dispatchWorkgroups(Math.ceil(s/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),s=new Float32Array(i);r.set([t.bodyCount,t.jointCount,t.contactCapacity,Number(this.wakeRequested)]),s.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 Ze=o=>Math.ceil(o/64);function Qn(){this.staticsDirty&&this.uploadStatics();let o=this.params,e=o.postStabilize&&!o.vbd,t=o.vbd?0:o.alpha,i=o.iterations+(e?1:0);this.writeParams(t,e),this.writePassConstants(i,g=>e?g<o.iterations?1:0:t);let r=this.parity,s=this.bodyCapacity,a=this.bodyCount,n=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*s+1)*4);let c=this.timingCallback!==null&&this.timing!==null,f,u=0,d=c||this.splitPasses,p=()=>{f&&!d||(f?.end(),f=l.beginComputePass({label:d?fe[u]:"avbd2d step",timestampWrites:c?{querySet:this.timing.querySet,beginningOfPassWriteIndex:2*u,endOfPassWriteIndex:2*u+1}:void 0}),u++)},m=this.groups,h=(g,A,x)=>{x<=0||(f.setPipeline(this.pipes[g]),f.setBindGroup(0,A),f.dispatchWorkgroups(x))},b=(g,A,x)=>{f.setPipeline(this.pipes[g]),f.setBindGroup(0,A),f.dispatchWorkgroupsIndirect(this.argsBuffer,x*4)};p(),h("beginFrame",m.broad,1),h("argsPrev",m.args,1),b("hashInsert",m.contacts[r],6),h("gridCount",m.broad,Ze(a)),this.gridScan.encode(f),h("gridScatter",m.broad,Ze(a)),h("findPairs",m.broad,Ze(a)),h("argsPairs",m.args,1),b("narrowphase",m.contacts[r],0),h("argsContacts",m.args,1),this.sleeping?.encodeWake(f,r),p(),h("degreeJoints",m.topo[r],Ze(n)),b("degreeContacts",m.topo[r],3),this.adjScan.encode(f),h("fillJoints",m.topo[r],Ze(n)),b("fillContacts",m.topo[r],3),h("sortAdjacency",m.topo[r],Ze(a)),p(),h("colorCompact",m.topo[r],Ze(a)),h("colorMark",m.topo[r],Ze(a));for(let g=0;g<this.colorRounds;g++)h(g%2===0?"colorRoundAB":"colorRoundBA",m.topo[r],Ze(a));h("colorCount",m.topo[r],this.colorGroups),this.colorHistScan.encode(f),h("colorStarts",m.topo[r],1),h("argsColors",m.args,1),h("colorScatter",m.topo[r],this.colorGroups),p();let y=this.colorCap+1,v=g=>f.setBindGroup(1,this.passGroup,[g*256]);f.setBindGroup(0,m.solve[r]),v(0),n>0&&(f.setPipeline(this.pipes.warmStartJoints),f.dispatchWorkgroups(Ze(n))),f.setPipeline(this.pipes.warmStartBodies),f.dispatchWorkgroups(Ze(a));for(let g=0;g<i;g++){let A=this.primalMode==="scan";f.setPipeline(A?this.pipes.primalScan:this.pipes.primal);for(let x=0;x<this.colorCap;x++)v(g*y+x),A?f.dispatchWorkgroups(Ze(a)):f.dispatchWorkgroupsIndirect(this.argsBuffer,(12+3*x)*4);g<o.iterations&&(v(g*y+this.colorCap),f.setPipeline(this.pipes.dual),f.dispatchWorkgroupsIndirect(this.argsBuffer,36)),g===o.iterations-1&&(f.setPipeline(this.pipes.updateVelocities),f.dispatchWorkgroups(Ze(a)))}e&&(f.setPipeline(this.pipes.refreshStick),f.dispatchWorkgroupsIndirect(this.argsBuffer,12)),f.end();let w=2*fe.length;if(c){let{querySet:g,resolve:A,read:x}=this.timing;l.resolveQuerySet(g,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 g=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=(k,z)=>Number(x[z]-x[k])/1e6,E={total:B(0,w-1)};fe.forEach((k,z)=>E[k]=B(2*z,2*z+1)),g(E)},()=>{this.timingBusy=!1,this.destroyed&&this.releaseTiming()})}}var Is=5;function ir({minAngle:o=-Math.PI,maxAngle:e=Math.PI}={}){if(!Number.isFinite(o)||!Number.isFinite(e)||o>e)throw Error("Angle limits require finite minAngle <= maxAngle, in radians");return{minAngle:o,maxAngle:e}}function oa(o,e,t){let i=e*T;o.info[e*D]=Is,o.data.set([1/0,1/0,0],i+$),o.data.set([-1/0,0,0],i+ft),o.data.set([0,1/0,0],i+dt),o.data[i+Ee]=t.minAngle,o.data[i+vt]=t.maxAngle}function Kn(o){let e=o.topology;for(let t=0;t<e.jointCount;t++)e.info[t*D]===Is&&o.device.queue.writeBuffer(o.jointBuffer,(t*36+32)*4,new Float32Array([e.data[t*T+ye],e.data[t*T+Ee],e.data[t*T+vt],0]))}var _r=(o,e,t)=>{if(o.split(e).length!==2)throw Error("Pinned 2D angular layout changed");return o.replace(e,t)};function Zn(o){return o=_r(o,"case T_JOINT: { return 3u; }",`case T_JOINT: { return 3u; }
4565
- case 5: { return 2u; }`),o=_r(o,"fn jointRowsC(j: u32, alpha: f32) -> vec3f {",`
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 Vl(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
+ 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 Wl(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:ql});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 Hl(){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 ls(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 Jl(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 as=(s,e,t)=>{if(s.split(e).length!==2)throw Error("Pinned 2D angular layout changed");return s.replace(e,t)};function $l(s){return s=as(s,"case T_JOINT: { return 3u; }",`case T_JOINT: { return 3u; }
4570
+ case 5: { return 2u; }`),s=as(s,"fn jointRowsC(j: u32, alpha: f32) -> vec3f {",`
4566
4571
  fn limitAngle2D(k:Joint,a:i32,b:i32)->f32 {
4567
4572
  var angleA=0.;if(a>=0){angleA=bodies[a].pose.z;}
4568
4573
  return angleA-bodies[b].pose.z-k.param.x;
@@ -4572,10 +4577,10 @@ fn limitRows2D(k:Joint,a:i32,b:i32,alpha:f32)->vec3f {
4572
4577
  return vec3f(angle-k.param.y,angle-k.param.z,0.)-alpha*k.c0.xyz;
4573
4578
  }
4574
4579
  `+`
4575
- fn jointRowsC(j: u32, alpha: f32) -> vec3f {`),o=_r(o,` if (t == T_JOINT) {
4580
+ fn jointRowsC(j: u32, alpha: f32) -> vec3f {`),s=as(s,` if (t == T_JOINT) {
4576
4581
  // Hard rows`,` if(t==5){return limitRows2D(k,a,b,alpha);}
4577
4582
  if (t == T_JOINT) {
4578
- // Hard rows`),o=_r(o," let C = jointRowsC(j, alpha);",` let C = jointRowsC(j, alpha);
4583
+ // Hard rows`),s=as(s," let C = jointRowsC(j, alpha);",` let C = jointRowsC(j, alpha);
4579
4584
  if(t==5){
4580
4585
  // Unilateral rows only contribute while their force is active. Inside the
4581
4586
  // interval a hinge has no angular stiffness and remains free to rotate.
@@ -4583,8 +4588,8 @@ fn jointRowsC(j: u32, alpha: f32) -> vec3f {`),o=_r(o,` if (t == T_JOINT) {
4583
4588
  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);}
4584
4589
  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);}
4585
4590
  return;
4586
- }`),o=_r(o," 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); }
4587
- 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.);}`),o}var el=`// Analytic circles and capsules, finite two-sided segments and solid half-space planes.
4591
+ }`),s=as(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 Xl=`// Analytic circles and capsules, finite two-sided segments and solid half-space planes.
4588
4593
  // Kind 4 stores bounding radius, vertex-record offset and vertex count.
4589
4594
  @group(0) @binding(7) var<storage,read> geometry:array<vec4f>;
4590
4595
  struct Face2D { a:vec2f, b:vec2f, feature:u32 }
@@ -4737,7 +4742,7 @@ fn collideShapes2D(a:u32,b:u32)->Collision {
4737
4742
  }
4738
4743
  out.count=count;return out;
4739
4744
  }
4740
- `;var aa=new WeakMap,rr=(o,e,t=!1)=>{if(!Number.isFinite(o)||(t?o<0:o<=0))throw Error(`${e} must be ${t?"nonnegative":"positive"} and finite`);return o},Rs=(o,e)=>{if(!o||o.length!==2||!Array.from(o).every(Number.isFinite))throw Error(`${e} requires two finite components`);return Array.from(o)},Er=o=>aa.get(o);function Os(o){let e=Array.from(o??[]),t=typeof e[0]=="number"?e:e.flatMap(x=>Rs(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]),s=(x,B,E)=>(B[0]-x[0])*(E[1]-x[1])-(B[1]-x[1])*(E[0]-x[0]),a=x=>{let B=[];for(let E of x){for(;B.length>1&&s(B.at(-2),B.at(-1),E)<=0;)B.pop();B.push(E)}return B.slice(0,-1)},n=[...a(r),...a([...r].reverse())];if(n.length<3||n.length>32)throw Error("A 2D hull needs 3\u201332 boundary vertices spanning an area");let l=n[0],c=n.map(x=>[x[0]-l[0],x[1]-l[1]]),f=0,u=0,d=0;for(let x=0;x<c.length;x++){let B=c[x],E=c[(x+1)%c.length],k=B[0]*E[1]-E[0]*B[1];f+=k,u+=(B[0]+E[0])*k,d+=(B[1]+E[1])*k}if(!(f>0)||!Number.isFinite(f))throw Error("Hull area must be positive and finite");u/=3*f,d/=3*f;let p=c.map(x=>[x[0]-u,x[1]-d]),m=0,h=0,b=0,y=0,v=[];for(let x=0;x<p.length;x++){let B=p[x],E=p[(x+1)%p.length],k=B[0]*E[1]-E[0]*B[1];m+=k*(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 z=E[0]-B[0],M=E[1]-B[1],P=Math.hypot(z,M);v.push(B[0],B[1],M/P,-z/P),h=Math.max(h,Math.hypot(...B)),b=Math.max(b,Math.abs(B[0])),y=Math.max(y,Math.abs(B[1]))}let w=f/2,g=m/w;if(![w,g,h,b,y,...v].every(x=>Number.isFinite(Math.fround(x)))||Math.fround(w)<=0||Math.fround(g)<=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*b,2*y],area:w,momentPerMass:g,radius:h}}function js(o){let e=rr(o,"radius");return{geometry:[1,e,0,0],size:[2*e,2*e],area:Math.PI*e*e,momentPerMass:e*e/2,radius:e}}function Ts(o,e){let t=rr(o,"radius");if(rr(e,"length"),e<2*t)throw Error("Capsule length must be at least twice its radius");return tl((e-2*t)/2,t)}function tl(o,e){let t=2*o,i=2*e*t,r=Math.PI*e*e,s=i+r,a=i*(t*t+4*e*e)/12+r*(t*t/4+e*e/2+4*t*e/(3*Math.PI));return{geometry:[2,e,o,0],size:[t+2*e,Math.max(2*e,1e-6)],area:s,momentPerMass:s?a/s:0,radius:o+e}}function Ds(o,e,t={}){let i=Rs(o,"start"),r=Rs(e,"end"),s=r[0]-i[0],a=r[1]-i[1],n=Math.hypot(s,a),l=rr(t.radius??0,"radius",!0);if(rr(n,"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{...tl(n/2,l),options:{...t,density:t.density??0,position:[(i[0]+r[0])/2,(i[1]+r[1])/2],angle:Math.atan2(a,s)}}}function Gs(o,e=0,t={}){let i=Rs(o,"normal"),r=rr(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 s=i[0]/r,a=i[1]/r;return{geometry:[3,0,0,0],size:[1,1],area:0,momentPerMass:0,radius:0,options:{...t,density:0,position:[s*e,a*e],angle:Math.atan2(-s,a)}}}function Fs(o,e,t,i){let r=aa.get(o);r||aa.set(o,r=new Map),r.set(e,t.geometry);let s=t.area*i,a=e*4;o.shape[a+2]=s,o.shape[a+3]=s*t.momentPerMass,o.props[a+1]=t.radius,o.dynamic[e]=+(s>0)}var il=`struct Body {pose:vec4f,initial:vec4f,inertial:vec4f,velocity:vec4f,previous:vec4f,shape:vec4f}
4745
+ `;var na=new WeakMap,zr=(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=>na.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=zr(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=zr(s,"radius");if(zr(e,"length"),e<2*t)throw Error("Capsule length must be at least twice its radius");return Yl((e-2*t)/2,t)}function Yl(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=zr(t.radius??0,"radius",!0);if(zr(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{...Yl(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=zr(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 Ir(s,e,t,i){let r=na.get(s);r||na.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 Ql=`struct Body {pose:vec4f,initial:vec4f,inertial:vec4f,velocity:vec4f,previous:vec4f,shape:vec4f}
4741
4746
  struct Command { header:vec4u, value:vec4f, point:vec4f }
4742
4747
  @group(0) @binding(0) var<storage,read_write> bodies:array<Body>;
4743
4748
  @group(0) @binding(1) var<storage,read> commands:array<Command>;
@@ -4773,11 +4778,11 @@ fn edit(@builtin(global_invocation_id) id:vec3u) {
4773
4778
  bodies[index]=b;
4774
4779
  }
4775
4780
  \r
4776
- `;function xt(o,e){let t=o&&typeof o.x=="number"?[o.x,o.y]:Array.isArray(o)||ArrayBuffer.isView(o)&&!(o instanceof DataView)?o:Array.from(o??[]);if(t.length!==2||!t.every(Number.isFinite))throw Error(`${e} requires two finite components`);return t}var xi=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),s=new Uint32Array(i);this.u32&&s.set(this.u32.subarray(0,this.count*12)),this.words=r,this.u32=s,this.capacity=t}append(e,t,i,r,s=!1){this.reserve(this.count+1),rl(this.words,this.u32,this.count++*12,e,t,i,r,s)}};function rl(o,e,t,i,r,s,a,n){e[t]=i,e[t+1]=r,e[t+2]=Number(n),e[t+3]=0;for(let l=0;l<4;l++)o[t+4+l]=s[l]??0,o[t+8+l]=a?.[l]??0}var sr=class{constructor(e,t=il,i=2){this.solver=e,this.shader=t,this.dimension=i,this.pending=new Map,this.queue=new xi,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 s=new Int32Array(this.queue.capacity);this.next&&s.set(this.next),this.next=s}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,s=!1){let a=this.slot(e,t);rl(this.queue.words,this.queue.u32,a*12,e,t,i,r,s)}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 s=0;s<12;s++)this.queue.u32[r+s]=e.u32[i+s]}}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 s=0;for(let[l,c]of this.pending){this.linearIndices[s]=l;for(let f=0;f<r;f++)this.linearValues[s*r+f]=this.queue.words[c.tail*12+4+f];s++}let a=this.angularOnly?"angularVelocityBatch":"velocityBatch",n=this.solver[a]??=new Lt(this.solver,this.dimension,this.angularOnly?"angular":"linear");n.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:n.lastBatch.uploadedBytes,path:this.angularOnly?"packed-angular-velocities":"packed-velocities",submissions:e?0:1}}else if(this.motionOnly){let r=this.motionBatch??=new Ht(this.solver,this.dimension),s=r.wordsPerBody;(!this.motionData||this.motionData.length<i*s)&&(this.motionData=new Uint32Array(Math.max(i*s,(this.motionData?.length??0)*2,64*s)),this.motionFloats=new Float32Array(this.motionData.buffer));let a=0;for(let[n,l]of this.pending){let c=a++*s;this.motionData[c]=n;let f=0;for(let u=l.head;u!==-1;u=this.next[u]){let d=this.queue.u32[u*12+1];f|=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[u*12+4+h]}this.motionData[c+1]=f}r.submitValidated(this.motionData.subarray(0,i*s),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 xi,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,s=0;for(let p of this.pending.values()){this.rangeData[s++]=r,this.rangeData[s++]=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 a=r*48,n=i*8,l=Math.min(t.limits.maxStorageBufferBindingSize,t.limits.maxBufferSize);if(a>l||n>l)throw Error("Body command batch exceeds GPU buffer limits");for(let[p,m]of[["commands",a],["ranges",n]])(!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,a),t.queue.writeBuffer(this.ranges,0,this.rangeData.buffer,0,n),this.pipeline??=t.createComputePipeline({layout:"auto",compute:{entryPoint:"edit",module:t.createShaderModule({code:"const DISPATCH_STRIDE = "+t.limits.maxComputeWorkgroupsPerDimension*64+`u;
4777
- `+this.shader})}}),(!this.group||this.boundBody!==this.solver.bodyBuffer||this.boundCommands!==this.commands||this.boundRanges!==this.ranges||this.boundRangeBytes!==n)&&(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:n}}]}),this.boundBody=this.solver.bodyBuffer,this.boundCommands=this.commands,this.boundRanges=this.ranges,this.boundRangeBytes=n);let c=e??t.createCommandEncoder(),f=c.beginComputePass();f.setPipeline(this.pipeline),f.setBindGroup(0,this.group);let u=Math.ceil(i/64),d=t.limits.maxComputeWorkgroupsPerDimension;f.dispatchWorkgroups(Math.min(u,d),Math.ceil(u/d)),f.end(),this.encodeAfterEdits(c,i),e||t.queue.submit([c.finish()]),this.lastBatch={bodies:i,commands:r,requestedCommands:this.requested,uploadedBytes:a+n,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 Us=class extends _s{writePassConstants(e,t){us.call(this,e,t)}createPipelines(){let e=this.layouts;this.compile(Sr,[e.broad],["beginFrame","gridCount","gridScatter","findPairs"]),this.compile(kr,[e.contacts],["hashInsert","narrowphase"]),this.compile(cr,[e.topo],["degreeJoints","degreeContacts","fillJoints","fillContacts","sortAdjacency","colorCompact","colorMark","colorRoundAB","colorRoundBA","colorCount","colorStarts","colorScatter"]),this.compile(Pr,[e.solve,e.pass],["warmStartJoints","warmStartBodies","primal","primalScan","dual","refreshStick","updateVelocities"]),this.compile(Vr,[e.args],["argsPrev","argsPairs","argsContacts","argsColors"])}constructor(e,t,i={}){i.sleeping!==void 0&&i.sleeping!==!1&&Ms(i.sleeping),super(e,t,i),this.sleepEligible=new Map(t.avbdSleepEligible??[]),Kn(this),Er(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 Er(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,s]of Er(this.topology)??[]){let a=Array.from(s);s.vertices&&(a[2]=i,t.set(s.vertices,i*4),i+=s.vertices.length/4),t.set(a,r*4),this.packedShapes.set(r,a)}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 s=this.shapeBuffer;this.shapeBuffer=this.createShapeBuffer(i);let a=this.device.createCommandEncoder();a.copyBufferToBuffer(s,0,this.shapeBuffer,0,this.geometryRecords*16),this.device.queue.submit([a.finish()]),s.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=kr;return this.shapeBuffer&&(e=e.replace(`@compute @workgroup_size(64)
4778
- fn narrowphase`,el+`
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),Kl(this.words,this.u32,this.count++*12,e,t,i,r,o)}};function Kl(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 Rr=class{constructor(e,t=Ql,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);Kl(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){Ws.call(this,e,t)}createPipelines(){let e=this.layouts;this.compile(rs,[e.broad],["beginFrame","gridCount","gridScatter","findPairs"]),this.compile(ss,[e.contacts],["hashInsert","narrowphase"]),this.compile(Nr,[e.topo],["degreeJoints","degreeContacts","fillJoints","fillContacts","sortAdjacency","colorCompact","colorMark","colorRoundAB","colorRoundBA","colorCount","colorStarts","colorScatter"]),this.compile(os,[e.solve,e.pass],["warmStartJoints","warmStartBodies","primal","primalScan","dual","refreshStick","updateVelocities"]),this.compile(Ps,[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??[]),Jl(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=ss;return this.shapeBuffer&&(e=e.replace(`@compute @workgroup_size(64)
4783
+ fn narrowphase`,Xl+`
4779
4784
  @compute @workgroup_size(64)
4780
- 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=Sr;if(this.shapeBuffer&&(e.push("read-only-storage"),t=t.replace(`fn radius(i: u32) -> f32 {
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=rs;if(this.shapeBuffer&&(e.push("read-only-storage"),t=t.replace(`fn radius(i: u32) -> f32 {
4781
4786
  return 0.5 * length(bodies[i].shape.xy);
4782
4787
  }`,`@group(0) @binding(7) var<storage,read> geometry:array<vec4f>;
4783
4788
  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.) {
@@ -4785,13 +4790,13 @@ let plane=select(b,a,geometry[a].x==3.);let other=select(a,b,geometry[a].x==3.);
4785
4790
  if(dot(bodies[other].pose.xy-bodies[plane].pose.xy,normal)>radius(other)){return;}
4786
4791
  } 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>;
4787
4792
  fn ignored(hi:u32,lo:u32)->bool{
4788
- 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 s=e;s<e+t;s++)this.sleeping?.register(s,this.sleepEligible?.get(s)!==!1);if(!this.shapeBuffer&&!this.triggers?.size)return;let i=this.shapeBuffer&&t>0?new Float32Array(t*4):null,r=this.packedShapes;for(let s=e;s<e+t;s++){let a=r?.get(s);i&&a&&i.set(a,(s-e)*4),this.triggers?.has(s)&&this.device.queue.writeBuffer(this.bodyBuffer,s*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=Er(e),i=[];for(let u=0;u<this.bodyCount;u++)t?.get(u)?.[0]!==3&&i.push(e.props[u*4+1]);i.sort((u,d)=>u-d);let r=i[i.length>>1]??1,s=0,a=1/0;for(let u of i)u<=4*r&&(s=Math.max(s,u));for(let u of i)u>s&&(a=Math.min(a,u));let n=a===1/0?s*1.5:(s+a)/2;this.maxSmallRadius=n,this.cellSize=Math.max(2*s*(1+1e-4),.001);let l=[],c=[];for(let u=0;u<this.bodyCount;u++)(t?.get(u)?.[0]===3||e.props[u*4+1]>n)&&l.push(u);for(let u=0;u<e.jointCount;u++){let d=e.info[u*4+1],p=e.info[u*4+2];d>=0&&c.push([Math.max(d,p),Math.min(d,p),u])}for(let u of e.ignoredPairs()){let d=Math.floor(u/2097152);c.push([d,u-d*2097152,4294967295])}c.sort((u,d)=>u[0]-d[0]||u[1]-d[1]),this.largeCount=l.length,this.noCollideCount=c.length;let f=new Uint32Array(Math.max(l.length+3*c.length,4));f.set(l),c.forEach((u,d)=>f.set(u,l.length+3*d)),this.staticBuffer.size<f.byteLength&&(this.staticBuffer.destroy(),this.staticBuffer=this.device.createBuffer({label:"2D boundaries",size:f.byteLength,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),this.rebuildBindings()),this.device.queue.writeBuffer(this.staticBuffer,0,f),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 Nt(this,2),this.shapeQueries.cast(e.map(i=>({...i,radius:0})),t)}async circleCast(e,t,i,r={}){let[s]=await this.circleCastAll([{origin:e,radius:t,direction:i,maxDistance:r.maxDistance}],r);return s}circleCastAll(e,t={}){return this.flushEdits(),this.shapeQueries??=new Nt(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,s=!1){return this.liveIndex(e),this.prepareBodyCommands().enqueue(e,t,i,r,s),this}prepareBodyCommands(){return this.wakeAll(),this.bodyCommands||(this.bodyCommands=new sr(this),this.compileContacts()),this.bodyCommands}setLinearVelocity(e,t){return this.queueBodyCommand(e,0,xt(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,xt(t,"impulse"),i===void 0?void 0:xt(i,"point"),i!==void 0)}applyForce(e,t,i){return this.queueBodyCommand(e,3,[...xt(t,"force"),0,this.params.dt],i===void 0?void 0:xt(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,[...xt(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 s=new Float32Array(i.getMappedRange());return{position:[s[0],s[1]],angle:s[2],linearVelocity:[s[12],s[13]],angularVelocity:s[14],mass:s[22],moment:s[23],sleeping:s[15]!==0}}finally{i.destroy()}}addBox(e,t={}){return this.addShape({size:Array.from(e)},t)}addCircle(e,t={}){return this.addShape(js(e),t)}addHull(e,t={}){return this.addShape(Os(e),t)}addCapsule(e,t,i={}){return this.addShape(Ts(e,t),i)}addSegment(e,t,i={}){return this.addShape(Ds(e,t,i))}addPlane(e=[0,1],t=0,i={}){return this.addShape(Gs(e,t,i))}addShape(e,t={}){t=e.options??t;let{density:i=1,friction:r=.6,position:s=[0,0],angle:a=0,velocity:n=[0,0,0],restitution:l=0,isTrigger:c=!1,group:f=4294967295,collidesWith:u=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(a))throw Error("Body dimensions must be positive, density and friction nonnegative, and angle finite");if(n.length!==3||!Array.from(n).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([f,u].some(h=>!Number.isInteger(h)||h<0||h>4294967295))throw Error("Collision masks must be unsigned 32-bit integers");let p=xt(s,"position");e.geometry&&this.geometryBytes(e.geometry.vertices?.length??0);let m=super.addBody(e.size,i,r,[...p,a],Array.from(n));return e.geometry&&(Fs(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),(f!==4294967295||u!==4294967295)&&this.setFilters([m],[f],[u]),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 Es(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*D]!==t)throw Error("The constraint has a different type");return e}setMotor(e,{speed:t,maxTorque:i}={}){if(this.constraintSlot(e,ks),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*T,s=e*36;t!==void 0&&(this.topology.data[r+ye]=t,Q(this).float(this.jointBuffer,s+32,t)),i!==void 0&&(this.topology.data[r+ft]=-i,this.topology.data[r+dt]=i,Q(this).float(this.jointBuffer,s+12,-i),Q(this).float(this.jointBuffer,s+16,i)),this.wakeAll()}setAngleLimits(e,t){this.constraintSlot(e,Is);let i=ir(t);this.topology.data[e*T+Ee]=i.minAngle,this.topology.data[e*T+vt]=i.maxAngle,Q(this).float(this.jointBuffer,e*36+32+1,i.minAngle),Q(this).float(this.jointBuffer,e*36+32+2,i.maxAngle);for(let r=4;r<8;r++)Q(this).float(this.jointBuffer,e*36+r,0);this.wakeAll()}setWorldAnchor(e,t,i){if(this.constraintSlot(e,Qt),this.topology.info[e*D+1]!==-1||!Number.isFinite(t)||!Number.isFinite(i))throw Error("A world joint and finite xy anchor are required");Q(this).float(this.jointBuffer,e*36+28,t),Q(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,s,a=1/0){if(e!==-1&&this.liveIndex(e),this.liveIndex(t),e===t)throw Error("Constraint endpoints must differ");let n=xt(i,"anchorA"),l=xt(r,"anchorB");if(!s||s.length!==3||Array.from(s).some(f=>f!==1/0&&(!Number.isFinite(f)||f<0))||a!==1/0&&(!Number.isFinite(a)||a<0))throw Error("Joint stiffness and break force must be nonnegative or Infinity");this.flushPropertyEdits();let c=super.appendJoint(e,t,n,l,Array.from(s),a);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=n=>{if(!Number.isInteger(n)||n<0||n>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");return n},s=Array.from(e,(n,l)=>(this.liveIndex(n),[n,r(t[l]),r(i[l])]));if(this.wakeAll(),!this.filters){let n=this.device;this.filters=n.createBuffer({size:this.bodyCapacity*8,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST}),n.queue.writeBuffer(this.filters,0,new Uint32Array(this.bodyCapacity*2).fill(4294967295)),this.compileBroadphase()}let a=Q(this);for(let[n,l,c]of s)a.uint(this.filters,n*2,l),a.uint(this.filters,n*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"}}),s=i.createBindGroup({layout:r.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:this.bodyBuffer}}]}),a=i.createCommandEncoder(),n=a.beginComputePass();n.setPipeline(r),n.setBindGroup(0,s),n.dispatchWorkgroups(Math.ceil(this.bodyCount/64)),n.end(),i.queue.submit([a.finish()]),this.compileContacts();let l=Pr.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) {
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 Rr(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&&(Ir(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=os.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) {
4789
4794
  if((contacts[c].ids.w&0x80000000u)!=0u){return;}`).replace("fn dualContact(c: u32) {",`fn dualContact(c: u32) {
4790
4795
  if((contacts[c].ids.w&0x80000000u)!=0u){return;}`).replace(` let k = contacts[c];
4791
4796
  let bound`,` let k = contacts[c];
4792
4797
  if((k.ids.w&0x80000000u)!=0u){return;}
4793
- let bound`);this.compile(l,[this.layouts.solve,this.layouts.pass],["warmStartJoints","warmStartBodies","primal","primalScan","dual","refreshStick","updateVelocities"]);let c=cr.replaceAll("if (gid.x >= topoCount()) { return; }",`if (gid.x >= topoCount()) { return; }
4794
- if((contacts[gid.x].ids.w&0x80000000u)!=0u){return;}`);this.compile(c,[this.layouts.topo],["degreeContacts","fillContacts"])}this.sensorsEnabled&&Q(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=Hn(Xn(Zn(e)))),e.includes("fn dynamicBody(")&&(e=Yn(e)),e.includes("fn colorCount(")&&(e=Jn(e));let r=this.device,s=r.createShaderModule({code:e}),a=r.createPipelineLayout({bindGroupLayouts:t});for(let n of i)this.pipes[n]=r.createComputePipeline({layout:a,compute:{module:s,entryPoint:n}})}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 $t(this.device,this.bodyBuffer,this.bodyCapacity,e,t,2),i===void 0&&this.contactWatch.setWatched(Array.from({length:this.bodyCount},(r,s)=>s),Array(this.bodyCount).fill(!0))),i!==void 0&&(this.watchedIndices=new Set(i),this.contactWatch.setWatched(Array.from({length:this.bodyCount},(r,s)=>s),Array.from({length:this.bodyCount},(r,s)=>this.watchedIndices.has(s)))),this}async readContactEvents(){this.watchContacts();let e=await this.contactWatch.read();return{...e,events:e.events.map(t=>({...t,type:t.kind===Xt?"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?Qn.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=Ms(e):this.sleeping=new zs(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 s=0,a=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;s=Math.min(t*l,s+Math.min(i,Math.max(0,c)));for(let f=0;s+1e-12>=l&&f<t&&(this.step(),s=Math.max(0,s-l),r?.(this),!(!this.sceneBinding||this.destroyed));f++);}),n=e.onDisposeObservable.addOnce(()=>this.destroy());return this.sceneBinding={scene:e,before:a,dispose:n},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 Ns=o=>{if(!Number.isInteger(o)||o<0||o>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");return o};function we(o,e,t){let i=o&&typeof o.x=="number"?[o.x,o.y,...e>=3?[o.z]:[],...e===4?[o.w]:[]]:Array.isArray(o)||ArrayBuffer.isView(o)&&!(o instanceof DataView)?o:Array.from(o??[]);if(i.length!==e||!i.every(Number.isFinite))throw Error(`${t} requires ${e} finite components`);return i}var sl=["linearVelocity","angularVelocity","impulse","force","","angularImpulse","torque"];function Uc(o,e){if(this.destroyed)throw Error("The solver has been destroyed");let t=this.editInProgress,i=t?new xi:this.editStaging??=new xi;this.editInProgress=!0;try{return Nc.call(this,o,e,i)}finally{this.editInProgress=t}}function Nc(o,e,t){t.count=0;let i,r=(s,a)=>{if(e===3)return we(s,3,a);if(!Number.isFinite(s))throw Error(`${a} must be finite`);return[s,0,0]};for(let s of o){let a=this.bodyIndex(s.body),{isTrigger:n,restitution:l,group:c,collidesWith:f,allowSleep:u}=s;if(n!==void 0||l!==void 0||c!==void 0||f!==void 0||u!==void 0){if(n!==void 0&&typeof n!="boolean")throw Error("isTrigger must be a boolean");if(u!==void 0&&typeof u!="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(f!==void 0&&c===void 0)throw Error("A collision-mask edit requires group as well");c!==void 0&&Ns(c),f!==void 0&&Ns(f),(i??=[]).push({index:a,isTrigger:n,restitution:l,group:c,collidesWith:f??4294967295,allowSleep:u})}let d=s.worldPoint===void 0?void 0:we(s.worldPoint,e,"worldPoint");if(s.position!==void 0){let p=we(s.position,e,"position"),m;if(s.rotation!==void 0){if(m=e===3?we(s.rotation,4,"rotation"):[s.rotation],e===3){let h=Math.hypot(...m);if(!h)throw Error("rotation must be nonzero");m=m.map(b=>b/h)}else if(!Number.isFinite(s.rotation))throw Error("angle must be finite")}t.append(a,4,p,e===3?m:void 0,m!==void 0),e===2&&(t.words[(t.count-1)*12+6]=m?.[0]??0)}else if(s.rotation!==void 0)throw Error("A rotation edit requires position; use teleport for a full pose");for(let p=0;p<sl.length;p++){if(p===4)continue;let m=sl[p];if(s[m]===void 0)continue;let b=p===1||p>=5?r(s[m],m):we(s[m],e,m);t.append(a,p,b,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 s of i??[])s.isTrigger!==void 0&&this.setSensor(s.index,s.isTrigger),s.restitution!==void 0&&this.setRestitution(s.index,s.restitution),s.group!==void 0&&this.setFilters([s.index],[s.group],[s.collidesWith]),s.allowSleep!==void 0&&this.setSleepEnabled(s.index,s.allowSleep);return this}var qs=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],[Ns(e)],[Ns(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 ol(o,{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=o.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 al(o,e,t,i){if(o.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:s,maxFrameTime:a}=ol(o,t);o.timeAccumulator=Math.min(s*r,(o.timeAccumulator??0)+Math.min(a,e));let n=0;for(;o.timeAccumulator+1e-12>=r&&n<s;)o.step(),o.timeAccumulator=Math.max(0,o.timeAccumulator-r),n++,i?.(o);return n}function qc(o,e){return al(this,o,e)}function nl(o,{afterStep:e,...t}={}){if(this.destroyed)throw Error("The solver has been destroyed");if(!o?.onBeforeRenderObservable?.add||!o?.onDisposeObservable?.addOnce||!o?.getEngine)throw Error("A Babylon scene is required");if(e!==void 0&&typeof e!="function")throw Error("afterStep must be a function");if(ol(this,t),this.sceneBinding){if(this.sceneBinding.scene===o)return this;throw Error("The solver is already attached to another scene")}let i=o.onBeforeRenderObservable.add(()=>{al(this,Math.max(0,o.getEngine().getDeltaTime()/1e3),t,e)}),r=o.onDisposeObservable.addOnce(()=>this.destroy());return this.sceneBinding={scene:o,before:i,dispose:r},this}function ll(){let o=this.sceneBinding;return o&&(o.scene.onBeforeRenderObservable.remove(o.before),o.scene.onDisposeObservable.remove(o.dispose),this.sceneBinding=null,this.timeAccumulator=0),this}function Vs(o,e,t){o.advance=qc;let i,r;o.bodyIndex=function(a){if(this.destroyed)throw Error("The solver has been destroyed");let n=a;if(a instanceof qs){if(a.solver!==this)throw Error("Body belongs to another solver");return a.gpuIndex}return typeof n!="number"&&t===3&&(r||(r=new WeakMap,e.bodies.forEach((l,c)=>r.set(l,this.gpuIndex(c)))),n=r.get(a)),this.liveIndex(n),n},o.body=function(a){let n=this.bodyIndex(a);return i??=new Map,i.has(n)||i.set(n,new qs(this,n)),i.get(n)},o.editBodies=function(a){return Uc.call(this,a,t)},o.setLinearVelocities=function(a,n){if(this.destroyed)throw Error("The solver has been destroyed");return this.velocityBatch??=new Lt(this,t),this.velocityBatch.set(a,n),this},o.setVelocities=function(a,n){if(this.destroyed)throw Error("The solver has been destroyed");return n?.angular===void 0&&n?.linear!==void 0?this.setLinearVelocities(a,n.linear):n?.linear===void 0&&n?.angular!==void 0?this.setAngularVelocities(a,n.angular):(this.motionBatch??=new Ht(this,t),this.motionBatch.set(a,n),this)},o.setAngularVelocities=function(a,n){if(this.destroyed)throw Error("The solver has been destroyed");return this.angularVelocityBatch??=new Lt(this,t,"angular"),this.angularVelocityBatch.set(a,n),this};let s=o.destroy;return o.destroy=function(){this.destroyed||(this.velocityBatch?.destroy(),this.angularVelocityBatch?.destroy(),this.motionBatch?.destroy(),this.bodyReadback?.destroy(),this.editStaging=null,s.call(this),i?.clear(),r=null,e=null)},t===2&&(o.readSelectedBodies=function(a,{posesOnly:n=!1}={}){let l=a instanceof Uint32Array?a:Array.from(a);return l.forEach(c=>this.liveIndex(c)),this.flushEdits(),this.bodyReadback??=new Jt(this.device),this.bodyReadback.read(this.bodyBuffer,l,n,6)}),o}var Ws=class extends Us{constructor(e,t,i){super(e,t,i),Vs(this,null,2)}};var na=`struct Body { pos:vec4f, rot:vec4f, initialPos:vec4f, initialRot:vec4f, size:vec4f, moment:vec4f, inertialPos:vec4f, inertialRot:vec4f, velocity:vec4f, angular:vec4f }
4798
+ let bound`);this.compile(l,[this.layouts.solve,this.layouts.pass],["warmStartJoints","warmStartBodies","primal","primalScan","dual","refreshStick","updateVelocities"]);let c=Nr.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=Nl(Vl($l(e)))),e.includes("fn dynamicBody(")&&(e=Wl(e)),e.includes("fn colorCount(")&&(e=Ul(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?Hl.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 Zl=["linearVelocity","angularVelocity","impulse","force","","angularImpulse","torque"];function tf(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 rf.call(this,s,e,i)}finally{this.editInProgress=t}}function rf(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<Zl.length;p++){if(p===4)continue;let g=Zl[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 ec(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 tc(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}=ec(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 sf(s,e){return tc(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(ec(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(()=>{tc(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 Or(s,e,t,i={}){s.advance=sf;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 tf.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),Or(this,null,2)}};var aa=`struct Body { pos:vec4f, rot:vec4f, initialPos:vec4f, initialRot:vec4f, size:vec4f, moment:vec4f, inertialPos:vec4f, inertialRot:vec4f, velocity:vec4f, angular:vec4f }
4795
4800
  struct Command { header:vec4u, value:vec4f, point:vec4f }
4796
4801
  struct Manifold { ids:vec4u, geo:vec4f }
4797
4802
  @group(0) @binding(0) var<storage,read_write> bodies:array<Body>;
@@ -4844,26 +4849,26 @@ fn angularImpulse(b:Body,impulse:vec3f)->vec3f {
4844
4849
  let index=commands[ranges[i].x].header.x;
4845
4850
  if(bodies[index].initialPos.w<0.){bodies[index].initialPos.w=-bodies[index].initialPos.w-1.;}
4846
4851
  }
4847
- `;var la=class extends sr{constructor(e){super(e,na,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;
4848
- ${na}`});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 s=e.beginComputePass();s.setPipeline(this.invalidate),s.setBindGroup(0,this.invalidateGroup);let a=Math.ceil(i.manifoldCapacity/64),n=r.limits.maxComputeWorkgroupsPerDimension;s.dispatchWorkgroups(Math.min(a,n),Math.ceil(a/n)),s.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),s=e.beginComputePass(),s.setPipeline(this.clearMarkers),s.setBindGroup(0,this.markerGroup);let l=Math.ceil(t/64);s.dispatchWorkgroups(Math.min(l,n),Math.ceil(l/n)),s.end()}},Hs=class extends Vt{constructor(e,t,i){super(e,t,i),this.nativeRef=t,Vs(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,s=!1){return this.liveIndex(e),this.prepareBodyCommands(),this.bodyCommands.enqueue(e,t,i,r,s),this}prepareBodyCommands(){return this.wakeAll(),this.bodyCommands??=new la(this)}setLinearVelocity(e,t){return this.queueBodyCommand(e,0,we(t,3,"velocity"))}setAngularVelocity(e,t){return this.queueBodyCommand(e,1,we(t,3,"angular velocity"))}applyImpulse(e,t,i){return this.queueBodyCommand(e,2,we(t,3,"impulse"),i===void 0?void 0:we(i,3,"point"),i!==void 0)}applyForce(e,t,i){return this.queueBodyCommand(e,3,[...we(t,3,"force"),this.params.dt],i===void 0?void 0:we(i,3,"point"),i!==void 0)}applyAngularImpulse(e,t){return this.queueBodyCommand(e,5,we(t,3,"angular impulse"))}applyTorque(e,t){return this.queueBodyCommand(e,6,[...we(t,3,"torque"),this.params.dt])}teleport(e,t,i){let r=we(t,3,"position"),s;if(i!==void 0){s=we(i,4,"rotation");let a=Math.hypot(...s);if(!a)throw Error("rotation must be nonzero");s=s.map(n=>n/a)}return this.queueBodyCommand(e,4,r,s,s!==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 Jt(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 $t(this.device,this.bodyBuffer,this.bodyCapacity,e,t),i===void 0&&(i=Array.from({length:this.bodyCount},(r,s)=>s))),i!==void 0){let r=new Set(i);this.contactWatch.setWatched(Array.from({length:this.bodyCount},(s,a)=>a),Array.from({length:this.bodyCount},(s,a)=>r.has(a)))}return this}async readContactEvents(){this.watchContacts();let e=await this.contactWatch.read();return{...e,events:e.events.map(t=>({...t,type:t.kind===Xt?"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 nl.call(this,e,t)}detachFromScene(){return ll.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 zr(o,e,t){if(o.split(e).length!==2)throw Error("Pinned solver changed; review the cloth kernel integration");return o.replace(e,t)}var Et=zr(be," if (j >= params.jointCount || info[j].x != T_JOINT) { return; }",` if (j >= params.jointCount) { return; }
4852
+ `;var la=class extends Rr{constructor(e){super(e,aa,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
+ ${aa}`});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,Or(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 la(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 cs(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=cs(ze," if (j >= params.jointCount || info[j].x != T_JOINT) { return; }",` if (j >= params.jointCount) { return; }
4849
4854
  if (info[j].x == T_SPRING) {
4850
4855
  // Finite material stiffness: Eq. 16, with no hard-constraint multiplier.
4851
4856
  joints[j].penLin.x = min(joints[j].penLin.w, max(PENALTY_MIN, joints[j].penLin.x * params.gamma));
4852
4857
  return;
4853
4858
  }
4854
- if (info[j].x != T_JOINT) { return; }`);Et=zr(Et," let stiffness = k.penLin.w;"," let stiffness = k.penLin.x;");Et=zr(Et," addRow(acc, n * sg, cross(r, n) * sg, stiffness, stiffness * (len - k.rA.w));",` let force = stiffness * (len - k.rA.w);
4859
+ if (info[j].x != T_JOINT) { return; }`);ti=cs(ti," let stiffness = k.penLin.w;"," let stiffness = k.penLin.x;");ti=cs(ti," addRow(acc, n * sg, cross(r, n) * sg, stiffness, stiffness * (len - k.rA.w));",` let force = stiffness * (len - k.rA.w);
4855
4860
  addRow(acc, n * sg, cross(r, n) * sg, stiffness, force);
4856
4861
  // Eq. 17: positive diagonal lumping of the geometric Hessian's column
4857
4862
  // norms. For C=|xA-xB|-L, G=(force/len)(I-n*n^T).
4858
4863
  let g = abs(force / len) * sqrt(max(vec3f(0.0), vec3f(1.0) - n*n));
4859
- (*acc).lin += mat3x3f(vec3f(g.x,0.0,0.0), vec3f(0.0,g.y,0.0), vec3f(0.0,0.0,g.z));`);Et=zr(Et," if (t != T_JOINT) { return; }",` if (t == T_SPRING) {
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=cs(ti," if (t != T_JOINT) { return; }",` if (t == T_SPRING) {
4860
4865
  let a = info[j].y;
4861
4866
  let b = info[j].z;
4862
4867
  let C = length(anchorA(joints[j], a) - (qrotate(bodies[b].rot, joints[j].rB.xyz) + bodies[b].pos.xyz)) - joints[j].rA.w;
4863
4868
  joints[j].penLin.x = min(joints[j].penLin.w, joints[j].penLin.x + params.betaLin * abs(C));
4864
4869
  return;
4865
4870
  }
4866
- if (t != T_JOINT) { return; }`);Et=zr(Et,"fn finishBody(i: u32, acc: Acc) {",`fn finishBody(i: u32, acc: Acc) {
4871
+ if (t != T_JOINT) { return; }`);ti=cs(ti,"fn finishBody(i: u32, acc: Acc) {",`fn finishBody(i: u32, acc: Acc) {
4867
4872
  if (all(bodies[i].moment.xyz == vec3f(0.0))) {
4868
4873
  // LDL^T of the point's 3x3 SPD system, using the same pivot floor as
4869
4874
  // rigid bodies. Contact friction moves the point; it cannot spin it.
@@ -4881,4 +4886,4 @@ ${na}`});this.invalidate=r.createComputePipeline({layout:"auto",compute:{module:
4881
4886
  let v1 = y1/d1 - l21*v2 - l31*v3;
4882
4887
  bodies[i].pos = vec4f(bodies[i].pos.xyz - vec3f(v1,v2,v3), bodies[i].pos.w);
4883
4888
  return;
4884
- }`);var cl=Et;var J=(o,e,t)=>{let i=Array.from(o);if(i.length!==e||!i.every(Number.isFinite))throw Error(`${t} requires ${e} finite components`);return i},V=(o,e,t=!1)=>{if(!Number.isFinite(o)||(t?o<0:o<=0))throw Error(`${e} must be ${t?"nonnegative":"positive"} and finite`);return o},ul=o=>{if(!Number.isInteger(o)||o<0||o>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");return o};function Js(o){for(let t of["allowSleep","isTrigger"])if(o[t]!==void 0&&typeof o[t]!="boolean")throw Error(`${t} must be a boolean`);let e=o.restitution??0;if(!Number.isFinite(e)||e<0||e>1)throw Error("restitution must be between 0 and 1");if(o.mass!==void 0&&(V(o.mass,"mass",!0),o.mass>0&&o.density===0))throw Error("A positive mass needs positive density");for(let t of["velocity","angularVelocity"])o[t]!==void 0&&J(o[t],3,t);if(o.rotation!==void 0&&!Math.hypot(...J(o.rotation,4,"rotation")))throw Error("rotation must be nonzero");ul(o.group??4294967295),ul(o.collidesWith??4294967295)}function fl(o,e){if(e.timeStep!==void 0&&(o.dt=V(e.timeStep,"timeStep")),e.iterations!==void 0){if(V(e.iterations,"iterations"),!Number.isInteger(e.iterations))throw Error("iterations must be an integer");o.iterations=e.iterations}if(e.gravity!==void 0){if(!Number.isFinite(e.gravity))throw Error("gravity must be finite");o.gravity=e.gravity}}var $s=class{constructor(e={}){if(this.ref=new jt,fl(this.ref,e),this.up=J(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(),Js(t);let i=J(e,3,"size");i.forEach(s=>V(s,"size"));let r=new De(this.ref,i,V(t.density??1,"density",!0),V(t.friction??.6,"friction",!0),J(t.position??[0,0,0],3,"position"));return this.configure(r,t)}addSphere(e,t={}){return this.assertEditable(),Js(t),this.configure(Mi(this.ref,V(e,"radius"),V(t.density??1,"density",!0),V(t.friction??.6,"friction",!0),J(t.position??[0,0,0],3,"position")),t)}addHull(e,t={}){if(this.assertEditable(),Js(t),e.length%3||!Array.from(e).every(Number.isFinite))throw Error("Hull points must contain finite xyz triples");let i=nr(e);if(!i)throw Error("A convex hull requires finite points spanning a volume");return this.hulls=!0,this.configure(qr(this.ref,i,V(t.density??1,"density",!0),V(t.friction??.6,"friction",!0),J(t.position??[0,0,0],3,"position")),t)}addCapsule(e,t,i={}){return this.assertEditable(),Js(i),this.configure(Hi(this.ref,e,t,V(i.density??1,"density",!0),V(i.friction??.6,"friction",!0),J(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=V(t.mass,"mass",!0);if(e.mass===0&&r>0)throw Error("A positive mass needs positive density");let s=e.mass>0?r/e.mass:0;e.mass=r,e.moment.forEach((a,n)=>e.moment[n]=a*s)}if(t.rotation){let r=J(t.rotation,4,"rotation"),s=Math.hypot(...r);if(!s)throw Error("rotation must be nonzero");e.positionAng.set(r.map(a=>a/s))}return t.velocity&&e.velocityLin.set(J(t.velocity,3,"velocity")),t.angularVelocity&&e.velocityAng.set(J(t.angularVelocity,3,"angularVelocity")),this.bodySet.add(e),e}addPoint(e,{mass:t=.02,radius:i=.05,friction:r=.5}={}){let s=this.addSphere(i,{position:e,mass:t,friction:r});return s.moment.fill(0),this.points=!0,s}addFabric({columns:e=16,rows:t=16,spacing:i=.2,origin:r=[0,3,0],mass:s=.02,stiffness:a=1e3,anchorStiffness:n=a,materialAt:l,breakStrain:c=1/0,breakForce:f=1/0,bendingStiffness:u=Number.isFinite(c)||Number.isFinite(f)?0:a/50,pinCorners:d=!1,pinEdges:p=!d}={}){for(let[M,P]of Object.entries({columns:e,rows:t}))if(!Number.isInteger(P)||P<2)throw Error(`${M} must be an integer >= 2`);if(V(i,"spacing"),V(s,"mass"),V(a,"stiffness"),V(n,"anchorStiffness"),l!==void 0&&typeof l!="function")throw Error("materialAt must be a function");if(V(u,"bendingStiffness",!0),typeof d!="boolean"||typeof p!="boolean")throw Error("Fabric pin options must be boolean");let m=Pt({breakStrain:c,breakForce:f}),h=J(r,3,"origin"),b=(M,P)=>`${Math.min(M,P)},${Math.max(M,P)}`;function*y(){for(let M=0;M<t;M++)for(let P=0;P<e;P++){let _=M*e+P;P&&(yield[_,_-1,a]),M&&(yield[_,_-e,a]),P&&M&&(yield[_,_-e-1,a/2],yield[_-1,_-e,a/2]),P>1&&u&&(yield[_,_-2,u]),M>1&&u&&(yield[_,_-2*e,u])}}let v=new Map;if(l)for(let[M,P]of y()){let _=l((M%e+P%e)/(2*(e-1)),(Math.floor(M/e)+Math.floor(P/e))/(2*(t-1)))??{};if(typeof _!="object"||Array.isArray(_))throw Error("materialAt must return a material object");v.set(b(M,P),{scale:V(_.stiffnessScale??1,"materialAt.stiffnessScale"),material:Pt({...m,..._})})}let w=Array.from({length:t},(M,P)=>Array.from({length:e},(_,C)=>this.addPoint([h[0]+(C-(e-1)/2)*i,h[1],h[2]+(P-(t-1)/2)*i],{mass:p&&(C===0||P===0||C===e-1||P===t-1)||d&&(C===0||C===e-1)&&(P===0||P===t-1)?0:s,radius:i/Math.SQRT2}))),g=w.flat(),A=new Map(g.map((M,P)=>[M,P])),x=[],B=new Map,E=(M,P,_)=>{(M.mass===0||P.mass===0)&&(_*=n/a);let C=A.get(M),S=A.get(P),R=v.get(b(C,S)),I=this.addSpring(M,P,[0,0,0],[0,0,0],{stiffness:_*(R?.scale??1),...R?.material??m});return B.set(b(A.get(M),A.get(P)),x.length),x.push(I),I};for(let[M,P,_]of y())E(g[M],g[P],_);let k=[];for(let M=0;M<t;M++)for(let P=0;P<e;P++)if(P&&M){let _=(M-1)*e+P-1,C=_+1,S=M*e+P-1,R=S+1;k.push(_,S,C,C,S,R)}let z=[];for(let M=0;M<k.length;M+=3){let[P,_,C]=k.slice(M,M+3);z.push(B.get(b(P,_)),B.get(b(_,C)),B.get(b(C,P)))}return{points:g,grid:w,indices:Uint32Array.from(k),connections:x,triangleConnections:Uint32Array.from(z)}}addRope({segments:e=12,length:t=12,origin:i=[0,12,0],width:r=.15,endMass:s=20}={}){if(!Number.isInteger(e)||e<1)throw Error("segments must be a positive integer");V(t,"length"),V(r,"width"),V(s,"endMass",!0);let a=J(i,3,"origin"),n=t/e,l=this.addBox([r,r,r],{mass:0,position:a}),c=[];for(let f=0;f<e;f++){let u=this.addBox([r,n,r],{mass:1,position:[a[0],a[1]-(f+.5)*n,a[2]]});this.addJoint(f?c[f-1]:l,u,[0,f?-n/2:0,0],[0,n/2,0]),c.push(u)}if(s){let f=this.addBox([.6,.6,.6],{mass:s,position:[a[0],a[1]-t-.3,a[2]]});this.addJoint(c.at(-1),f,[0,-n/2,0],[0,.3,0]),c.push(f)}return{anchor:l,links:c}}addRagdoll({origin:e=[0,2,0],mass:t=10}={}){let i=J(e,3,"origin");V(t,"mass");let r=(l,c)=>this.addBox(l,{mass:t/10,position:c.map((f,u)=>f+i[u])}),s=r([.7,1.2,.35],[0,2,0]),a=this.addSphere(.25,{mass:t/10,position:[i[0],i[1]+2.9,i[2]]}),n=[s,a];this.addJoint(s,a,[0,.6,0],[0,-.3,0]);for(let l of[-1,1]){let c=r([.3,.8,.3],[l*.5,1.95,0]),f=r([.26,.7,.26],[l*.5,1.2,0]);this.addJoint(s,c,[l*.35,.35,0],[-l*.15,.4,0]),this.addJoint(c,f,[0,-.4,0],[0,.35,0]);let u=r([.28,.8,.3],[l*.2,1,0]),d=r([.26,.75,.28],[l*.2,.225,0]);this.addJoint(s,u,[l*.2,-.6,0],[0,.4,0]),this.addJoint(u,d,[0,-.4,0],[0,.375,0]),n.push(c,f,u,d)}return{torso:s,head:a,bodies:n}}addJoint(e,t,i=[0,0,0],r=[0,0,0],{linearStiffness:s=1/0,angularStiffness:a=0,breakForce:n=1/0,breakOnPull:l=!1}={}){this.assertEditable(),this.checkBodies(e,t);for(let c of[s,a,n])c!==1/0&&V(c,"joint stiffness/breakForce",!0);return this.handle(new Be(this.ref,e,t,J(i,3,"anchorA"),J(r,3,"anchorB"),s,a,l&&n!==1/0?-n:n))}addSpring(e,t,i=[0,0,0],r=[0,0,0],{stiffness:s=1e3,rest:a=-1,breakStrain:n=1/0,breakForce:l=1/0}={}){if(this.assertEditable(),this.checkBodies(e,t),!e)throw Error("A spring requires two bodies");V(s,"stiffness",!0),a!==-1&&V(a,"rest",!0);let c=Pt({breakStrain:n,breakForce:l}),f=new ct(this.ref,e,t,J(i,3,"anchorA"),J(r,3,"anchorB"),s,a);return os(f,c),this.handle(f)}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=gt({...i,type:"motor"}),s=new Be(this.ref,e,t,[0,0,0],[0,0,0],1/0,0);return Wi(s,r),this.handle(s)}addHinge(e,t,i={}){this.assertEditable(),this.checkBodies(e,t);let r=gt({...i,type:"limit"}),s=V(i.span??1,"span"),a=J(i.anchorA??[0,0,0],3,"anchorA"),n=J(i.anchorB??[0,0,0],3,"anchorB"),l=[-1,1].map(u=>this.addJoint(e,t,a.map((d,p)=>d+u*s*.5*r.axisA[p]),n.map((d,p)=>d+u*s*.5*r.axisB[p]))),c,f;if(i.minAngle!==void 0||i.maxAngle!==void 0){let u=new Be(this.ref,e,t,[0,0,0],[0,0,0],1/0,0);Wi(u,r),c=this.handle(u)}return i.motor&&(f=this.addMotor(e,t,{axisA:r.axisA,axisB:r.axisB,...i.motor})),{joints:l,limit:c,motor:f,dispose(){for(let u of[...l,c,f])u?.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(this.assertEditable(),this.hulls&&e.limits.maxStorageBuffersPerShaderStage<9)throw Error("Hull collisions require nine storage buffer bindings");let i=new Hs(e,this.ref,ps(this.ref,{...t,...this.points?{shaders:{...t.shaders,solve:cl}}:{}})),r=[];this.ref.forces.forEach((l,c)=>{this.handles.get(l).slot=c,l instanceof Be&&l.stiffnessAng>0&&r.push({slot:c})}),i.captureConstraintFrames(r),i.params.up=[...this.up];let s=[],a=[],n=[];for(let[l,c]of this.ref.bodies.entries())(c.group!==4294967295||c.collidesWith!==4294967295)&&(s.push(i.gpuIndex(l)),a.push(c.group),n.push(c.collidesWith)),c.isTrigger&&i.setSensor(i.gpuIndex(l),!0),c.restitution>0&&i.setRestitution(i.gpuIndex(l),c.restitution);return s.length&&i.setFilters(s,a,n),(t.sleeping||this.sleepOptIn)&&i.enableSleeping(this.ref,t.sleeping===!0?{}:t.sleeping),this.gpu=i,this.created=!0,i}},Xs=class{constructor(e={}){if(this.topology=new Ps,Object.assign(this.topology.params,Bs()),fl(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 Fs(this.topology,r,e,i.density??1),r}addCircle(e,t={}){return this.addShape(js(e),t)}addHull(e,t={}){return this.addShape(Os(e),t)}addCapsule(e,t,i={}){return this.addShape(Ts(e,t),i)}addSegment(e,t,i={}){return this.addShape(Ds(e,t,i))}addPlane(e=[0,1],t=0,i={}){return this.addShape(Gs(e,t,i))}addBox(e,{density:t=1,friction:i=.6,position:r=[0,0],angle:s=0,velocity:a=[0,0,0],restitution:n=0,isTrigger:l=!1,group:c=4294967295,collidesWith:f=4294967295,allowSleep:u}={}){if(this.assertEditable(),u!==void 0&&typeof u!="boolean")throw Error("allowSleep must be boolean");let d=J(e,2,"size");d.forEach(h=>V(h,"size"));let p=J(r,2,"position");if(!Number.isFinite(s))throw Error("angle must be finite");if(!Number.isFinite(n)||n<0||n>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,f])if(!Number.isInteger(h)||h<0||h>4294967295)throw Error("Collision masks must be unsigned 32-bit integers");let m=this.topology.addBody(d,V(t,"density",!0),V(i,"friction",!0),[...p,s],J(a,3,"velocity"));return this.restitution??=new Map,n>0&&this.restitution.set(m,n),this.sensors??=new Set,l&&this.sensors.add(m),this.filters??=new Map,(c!==4294967295||f!==4294967295)&&this.filters.set(m,[c,f]),this.topology.avbdSleepEligible??=new Map,u!==void 0&&this.topology.avbdSleepEligible.set(m,u),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:s=[1/0,1/0,0],breakForce:a=1/0}={}){if(this.assertEditable(),this.checkBodies(e,t),!s||s.length!==3||Array.from(s).some(l=>l!==1/0&&(!Number.isFinite(l)||l<0))||a!==1/0&&(!Number.isFinite(a)||a<0))throw Error("Joint stiffness and break force must be nonnegative or Infinity");let n=this.topology.addJoint(e,t,J(i,2,"anchorA"),J(r,2,"anchorB"),s,a);return this.constraintHandle(n.slot,n)}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*T+$,e*T+$+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:s=1e3,rest:a=1}={}){if(this.assertEditable(),this.checkBodies(e,t),e<0)throw Error("A spring requires two bodies");let n=this.topology.jointCount;return this.topology.addSpring(e,t,J(i,2,"anchorA"),J(r,2,"anchorB"),V(s,"stiffness",!0),V(a,"rest",!0)),this.constraintHandle(n)}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 s=this.topology.jointCount;return this.topology.addMotor(e,t,i,V(r,"maxTorque",!0)),this.constraintHandle(s)}addAngularLimit(e,t,i={}){this.assertEditable(),this.checkBodies(e,t);let r=ir(i),s=this.topology.addJoint(e,t,[0,0],[0,0],[0,0,0]);oa(this.topology,s.slot,r);let a=this.constraintHandle(s.slot,s);return a.setLimits=n=>{if(a.disposed)throw Error("The angular limit has been disposed");return this.gpu?this.gpu.setAngleLimits(a.slot,n):oa(this.topology,a.slot,ir(n)),a},a}addHinge(e,t,i=[0,0],r=[0,0],s={}){this.assertEditable(),this.checkBodies(e,t);let a=J(i,2,"anchorA"),n=J(r,2,"anchorB"),l=s.minAngle!==void 0||s.maxAngle!==void 0?ir(s):null,c=s.motor;if(c){if(!Number.isFinite(c.speed??1))throw Error("speed must be finite");V(c.maxTorque??100,"maxTorque",!0)}let f=this.addJoint(e,t,a,n),u=l?this.addAngularLimit(e,t,l):null,d=c?this.addMotor(e,t,c):null;return{joint:f,limits:u,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={}){this.assertEditable();let i=new Ws(e,this.topology,t);for(let[r,s]of this.restitution??[])i.setRestitution(r,s);for(let r of this.sensors??[])i.setSensor(r,!0);for(let[r,s]of this.filters??[])i.setFilters([r],[s[0]],[s[1]]);return this.gpu=i,this.created=!0,i}};typeof globalThis.AVBD<"u"?Object.assign(globalThis.AVBD,Ys):globalThis.AVBD=Ys;})();
4889
+ }`);var ic=ti;var ac=8,rc=16,Xi=1e-6,ua=1e-5,nf=1e-6,fa=34028234663852886e22,Mo=0,lc=1,zo=2;function sc(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 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 cc(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 af(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,...cc(s,e)}}function lf(s,e){let t=0,i=-fa;for(let r=0;r<3;r++){let o=$i(s.axis[r],e);o>i&&(i=o,t=r)}return t}function cf(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}=cc(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 uf(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<=ua,c=a<=ua;if(l!==c){let u=0,f=o-a;Math.abs(f)>Xi&&(u=ce(o/f,0,1)),i.length<rc&&i.push(D(C(),r,$(C(),n,r),u))}c&&i.length<rc&&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))<nf)return;if(this.contacts.length>=ac)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 ca(s,e,t,i,r,o,n,a){let l=Ge(i);if(l<Xi)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 oc(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 ff(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<=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),g=a*l-p*p;Math.abs(g)>Xi&&(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 nc(s,e,t,i,r,o,n){let a=r?t:i,l=r?i:t,c=r?n:ee(C(),n),u=af(a,o,c),f=lf(l,u.normal),d=cf(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=uf(d,m,V(m,u.center)+b),!d.length)return[];let g=new Ro(s,e),h=(r?Mo:lc)<<24|(o&255)<<16|(f&255)<<8;for(let m=0;m<d.length&&g.contacts.length<ac;m++){let b=d[m],v=V($(C(),b,u.center),u.normal);if(v>ua)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 df(s,e,t,i,r,o,n){let[a,l]=oc(t,r,n),[c,u]=oc(i,o,ee(C(),n)),[f,d]=ff(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 uc(s,e,t,i=!0){let r=sc(s),o=sc(e),n=$(C(),o.center,r.center),a={type:Mo,indexA:0,indexB:0,separation:-fa,normalAB:C(),valid:!1},l={type:zo,indexA:0,indexB:0,separation:-fa,normalAB:C(),valid:!1};for(let f=0;f<3;f++)if(!ca(r,o,n,r.axis[f],Mo,f,-1,a))return[];for(let f=0;f<3;f++)if(!ca(r,o,n,o.axis[f],lc,-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]),!ca(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),ms(t,ee(C(),u.normalAB)),u.type===zo?df(s,e,r,o,u.indexA,u.indexB,u.normalAB):u.type===Mo?nc(s,e,r,o,!0,u.indexA,u.normalAB):nc(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)),fc=(s,e)=>Te(C(),s.positionAng,T(e,s.positionLin)),Ot=(s,e)=>de(s.positionLin,_e(s.positionAng,e)),hf=[[1,3,7,5],[0,4,6,2],[2,6,7,3],[0,1,5,4],[4,5,7,6],[0,2,3,1]],pf=[[1,0,0],[-1,0,0],[0,1,0],[0,-1,0],[0,0,1],[0,0,-1]];function Tr(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)})):hf.map((n,a)=>({vertices:n.map(l=>t[l]),normal:_e(s.positionAng,pf[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 us(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 mf(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 gf(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 bf(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 yf(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=bf(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 dc(s,e,t,i,r){if(!De(s)&&!De(e)&&!He(s)&&!He(e)&&!wt(s)&&!wt(e))return uc(s,e,t,s.solver.faceBias!==!1);i??=Tr(s),r??=Tr(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(us(i,q(p,-1)),us(r,p)),p),h=G(T(us(r,q(p,-1)),us(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,mf(...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=us(f,p),h=yf(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=gf(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:fc(s,f),rB:fc(e,d)}))}var To=(s,e,t)=>Math.max(e,Math.min(t,s)),vf=(s,e)=>[G(s.slice(0,3),e),G(s.slice(3,6),e),G(s.slice(6,9),e)];function pa(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=Dr(jt(),Zo(jt(),t),s.bodyB.positionAng),s.evaluateAng=i=>{let r=Dr(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 da=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=dc(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(vf(this.basis,T(Ot(e,o.rA),Ot(t,o.rB)))),o.C0[0]+=bs;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)}},ha=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=Xr(e);if(t){e.unlinkFromBodies(),s.forces.splice(s.forces.indexOf(e),1),e.cpuAngular=new ha(s,e,t);continue}if(e instanceof ke&&e.stiffnessAng>0&&pa(e),e instanceof ft){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 hc(s){let e=s.bodies;s.cpuGeometry=new Map;for(let l of e)(De(l)||He(l)||wt(l))&&s.cpuGeometry.set(l,Tr(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 da(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 pc(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=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 Af=()=>({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,Af())}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=ys();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),hc(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=pc(c,this,this.cpuStep);u&&D(c.inertialLin,c.inertialLin,u,e*e),ri(c.inertialAng,c.positionAng,mc(c.velocityAng,e)),_t(this.accel,$(this.accel,c.velocityLin,c.prevVelocityLin),e);let f=V(this.accel,this.up)*hs(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,mc(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,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 g=u.moment.every(h=>h===0);g&&(Ce(r.lhsAng,1,1,1),r.lhsCross.fill(0),r.rhsAng.fill(0)),gs(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,ct(l.velocityAng,l.positionAng,l.initialAng),e));Fo(this,3,n),this.cpuStep++}},xf=C(),mc=(s,e)=>ne(xf,s,e);var ds=(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],fs=(s,e)=>[Math.cos(s)*e[0]-Math.sin(s)*e[1],Math.sin(s)*e[0]+Math.cos(s)*e[1]],bc=s=>Math.max(0,Math.min(1,s)),gc=(s,e,t)=>ds(s,Lt(Re(e,s),bc(st(Re(t,s),Re(e,s))/(st(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=>ds(i,fs(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=ds(s.spine[0],Lt(e,s.radius)),i=ds(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 yc(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=fs(f.angle,[0,1]),g=Yi(d,Lt(p,-1));for(let h of g){let m=st(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=st(Re(Yi(r,Lt(B,-1))[0],Yi(o,B)[0]),B),L=st(Re(Yi(o,Lt(B,-1))[0],Yi(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],gc(...x.spine,A.vertices[B])))}else if(d(fs(A.angle,[0,1])),!x.vertices)for(let B of A.spine)d(Re(B,gc(...x.spine,B)));if(u===-1/0&&d([0,1]),u>0)return 0;let p=Yi(r,Lt(f,-1)),g=Yi(o,f),h=[-f[1],f[0]],m=p.map(A=>st(A,h)),b=g.map(A=>st(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=st(Re(A[1],A[0]),h);return Math.abs(B)<1e-9?A[0]:ds(A[0],Lt(Re(A[1],A[0]),bc((x-st(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=fs(-r.angle,Re(u.a,r.p)),d=fs(-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 vc=(s,e,t)=>[Math.cos(s)*e-Math.sin(s)*t,Math.sin(s)*e+Math.cos(s)*t],Ac=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([is,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=ra*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+Wi]&&(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]=vc(s[a*4+2],m[b+U],m[b+U+1]),[B,E]=vc(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 Mr{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];Ir(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=[],Ac.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=yc(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 jr(s,e){return e&&(!s||e.t<s.t)?e:s}function ma(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 jr(jr(h,qo(s,e,t,r)),qo(s,e,i,r))}function xc(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 wf(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),xc(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&&xc(T(de(e,q(t,u)),q(a.normal,i)),a)&&(n=jr(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=jr(n,ma(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 Bf(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=jr(n,{t:h,n:f}))}i>0&&(n=jr(n,qo(e,t,l,i)))}return r||o<=i*i?{t:0,n:q(t,-1)}:n}function Cf(s,e,t,i){if(s.vertices)return Bf(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 ma(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 wc(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=Cf(No(s.solver,h),c,p,t);else{let A=Tr(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)}:ma(c,p,...A.spine,x)}else w=wf(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,Or(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");ls(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)pa(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");br(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: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,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(),wc(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 Bc=new WeakSet,Jo=s=>s!==null&&typeof s=="object"&&Bc.has(s),Cc=s=>Bc.add(s);async function Sc({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 Ni(e):({device:e,adapter:o}=await wr({...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 Cc(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},kc=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");kc(s.group??4294967295),kc(s.collidesWith??4294967295)}function Pc(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 Xo=class{constructor(e={}){if(this.ref=new ni,Pc(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(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(),$o(t),e.length%3||!Array.from(e).every(Number.isFinite))throw Error("Hull points must contain finite xyz triples");let i=Gr(e);if(!i)throw Error("A convex hull requires finite points spanning a volume");return this.hulls=!0,this.configure(ks(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(xr(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 ft(this.ref,e,t,ie(i,3,"anchorA"),ie(r,3,"anchorB"),o,n);return br(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 Ar(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);Ar(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,$s(this.ref,{...t,...this.points?{shaders:{...t.shaders,solve:ic}}:{}})),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}},Yo=class{constructor(e={}){if(this.topology=new Mr,Object.assign(this.topology.params,io()),Pc(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 Ir(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]);ls(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):ls(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}};typeof globalThis.AVBD<"u"?Object.assign(globalThis.AVBD,Qo):globalThis.AVBD=Qo;})();