@newkrok/nape-js 3.32.0 → 3.33.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,2 +1,2 @@
1
- import {aa,ka,Y,ba,I,$,fa,ea,da,sa,ra,oa,pa,ma,na,qa,ga,ja,ia,ca,ha,U as U$1}from'../chunk-263GQ5UK.js';var at=1;function b(t){return {x:t.x,y:t.y}}function ut(t){if(t==null)return null;try{let o=JSON.stringify(t);return o==="{}"?null:JSON.parse(o)}catch{return null}}function mt(t){return {elasticity:t.elasticity,dynamicFriction:t.dynamicFriction,staticFriction:t.staticFriction,density:t.density,rollingFriction:t.rollingFriction}}function yt(t){return {collisionGroup:t.collisionGroup,collisionMask:t.collisionMask,sensorGroup:t.sensorGroup,sensorMask:t.sensorMask,fluidGroup:t.fluidGroup,fluidMask:t.fluidMask}}function ft(t){if(t==null)return null;let o=t.gravity;return {density:t.density,viscosity:t.viscosity,gravity:o!=null?b(o):null}}function bt(t){let o=mt(t.material),n=yt(t.filter),e=t.fluidEnabled,r=e?ft(t.fluidProperties):null,a=t.sensorEnabled;if(t.isCircle()){let i=t,s=t.localCOM;return {type:"circle",radius:i.radius,localCOM:b(s),material:o,filter:n,sensorEnabled:a,fluidEnabled:e,fluidProperties:r}}else if(t.isCapsule()){let i=t,s=t.localCOM;return {type:"capsule",width:i.width,height:i.height,localCOM:b(s),material:o,filter:n,sensorEnabled:a,fluidEnabled:e,fluidProperties:r}}else {let s=t.localVerts,l=[],u=s.length;for(let m=0;m<u;m++)l.push(b(s.at(m)));return {type:"polygon",localVerts:l,material:o,filter:n,sensorEnabled:a,fluidEnabled:e,fluidProperties:r}}}var Ft={1:"STATIC",2:"DYNAMIC",3:"KINEMATIC"},Dt={0:"DEFAULT",1:"FIXED",2:"FIXED_GROUP"},ht={0:"DEFAULT",1:"FIXED",2:"FIXED_GROUP"},Mt={0:"DEFAULT",1:"FIXED",2:"SCALED"};function gt(t,o){let n=t.zpp_inner,e=Dt[n.massMode]??"DEFAULT",r=ht[n.inertiaMode]??"DEFAULT",a=Mt[n.gravMassMode]??"DEFAULT",i=[],s=t.shapes,l=s.length;for(let u=0;u<l;u++)i.push(bt(s.at(u)));return {id:o,type:Ft[n.type]??"DYNAMIC",position:b(t.position),rotation:t.rotation,velocity:b(t.velocity),angularVel:t.angularVel,kinematicVel:b(t.kinematicVel),kinAngVel:t.kinAngVel,surfaceVel:b(t.surfaceVel),force:b(t.force),torque:n.type===2?t.torque:0,massMode:e,mass:e==="FIXED"?n.cmass:null,inertiaMode:r,inertia:r==="FIXED"?n.cinertia:null,gravMassMode:a,gravMassScale:n.gravMassScale,allowMovement:t.allowMovement,allowRotation:t.allowRotation,bullet:t.isBullet,shapes:i,userData:ut(n.userData)}}function B(t,o,n,e){let r=t.zpp_inner,a=n!=null?o.get(n.zpp_inner.id)??null:null,i=e!=null?o.get(e.zpp_inner.id)??null:null;return {body1Id:a,body2Id:i,active:r.active,ignore:r.ignore,stiff:r.stiff,frequency:r.frequency,damping:r.damping,maxForce:r.maxForce,maxError:r.maxError,breakUnderForce:r.breakUnderForce,breakUnderError:r.breakUnderError,removeOnBreak:r.removeOnBreak,userData:ut(r.userData)}}function Ct(t,o){switch(t.constructor?.name??""){case "PivotJoint":{let e=t;return {...B(t,o,e.body1,e.body2),type:"PivotJoint",anchor1:b(e.anchor1),anchor2:b(e.anchor2)}}case "DistanceJoint":{let e=t;return {...B(t,o,e.body1,e.body2),type:"DistanceJoint",anchor1:b(e.anchor1),anchor2:b(e.anchor2),jointMin:e.jointMin,jointMax:e.jointMax}}case "AngleJoint":{let e=t;return {...B(t,o,e.body1,e.body2),type:"AngleJoint",jointMin:e.jointMin,jointMax:e.jointMax,ratio:e.ratio}}case "MotorJoint":{let e=t;return {...B(t,o,e.body1,e.body2),type:"MotorJoint",rate:e.rate,ratio:e.ratio}}case "LineJoint":{let e=t;return {...B(t,o,e.body1,e.body2),type:"LineJoint",anchor1:b(e.anchor1),anchor2:b(e.anchor2),direction:b(e.direction),jointMin:e.jointMin,jointMax:e.jointMax}}case "PulleyJoint":{let e=t;return {...B(t,o,e.body1,e.body2),type:"PulleyJoint",anchor1:b(e.anchor1),anchor2:b(e.anchor2),anchor3:b(e.anchor3),anchor4:b(e.anchor4),jointMin:e.jointMin,jointMax:e.jointMax,ratio:e.ratio}}case "WeldJoint":{let e=t;return {...B(t,o,e.body1,e.body2),type:"WeldJoint",anchor1:b(e.anchor1),anchor2:b(e.anchor2),phase:e.phase}}default:return null}}function wt(t){let o=[],n=new Map,e=new Map;function r(d){let f=d.zpp_inner.id;if(e.has(f))return;let p=o.length;n.set(d,p),e.set(f,p),o.push(gt(d,p));}let a=t.bodies,i=a.length;for(let d=0;d<i;d++)r(a.at(d));let s=t.compounds,l=s.length;for(let d=0;d<l;d++){let p=s.at(d).bodies,g=p.length;for(let I=0;I<g;I++)r(p.at(I));}let u=[],m=new Map;function D(d){if(m.has(d))return;let f=Ct(d,e);f!=null&&(m.set(d,u.length),u.push(f));}let M=t.constraints,S=M.length;for(let d=0;d<S;d++)D(M.at(d));for(let d=0;d<l;d++){let p=s.at(d).constraints,g=p.length;for(let I=0;I<g;I++)D(p.at(I));}let A=[];for(let d=0;d<l;d++){let f=s.at(d),p=[],g=f.bodies,I=g.length;for(let J=0;J<I;J++){let st=g.at(J),O=n.get(st);O!=null&&p.push(O);}let C=[],x=f.constraints,w=x.length;for(let J=0;J<w;J++){let st=x.at(J),O=m.get(st);O!=null&&C.push(O);}A.push({bodyIds:p,constraintIndices:C,childIndices:[]});}let c=t.zpp_inner.bphase.is_sweep?"SWEEP_AND_PRUNE":"DYNAMIC_AABB_TREE",F=t.gravity;return {version:1,gravity:b(F),worldLinearDrag:t.worldLinearDrag,worldAngularDrag:t.worldAngularDrag,sortContacts:t.sortContacts,deterministic:t.deterministic,broadphase:c,bodies:o,constraints:u,compounds:A}}function P(t){return I.get(t.x,t.y)}function v(t){return I.weak(t.x,t.y)}function vt(t){return new ca(t.elasticity,t.dynamicFriction,t.staticFriction,t.density,t.rollingFriction)}function At(t){let o=new ha;return o.collisionGroup=t.collisionGroup,o.collisionMask=t.collisionMask,o.sensorGroup=t.sensorGroup,o.sensorMask=t.sensorMask,o.fluidGroup=t.fluidGroup,o.fluidMask=t.fluidMask,o}function It(t){let o=new U$1(t.density,t.viscosity);return t.gravity!=null&&(o.gravity=P(t.gravity)),o}function Jt(t){let o=vt(t.material),n=At(t.filter),e;if(t.type==="circle"){let r=P(t.localCOM);e=new ga(t.radius,r,o,n);}else if(t.type==="capsule"){let r=P(t.localCOM);e=new ja(t.width,t.height,r,o,n);}else {let r=t.localVerts.map(a=>P(a));e=new ia(r,o,n);}return e.sensorEnabled=t.sensorEnabled,e.fluidEnabled=t.fluidEnabled,t.fluidEnabled&&t.fluidProperties!=null&&(e.fluidProperties=It(t.fluidProperties)),e}function St(t){let o=t.type==="STATIC"?aa.STATIC:t.type==="KINEMATIC"?aa.KINEMATIC:aa.DYNAMIC,n=new $(o,v(t.position));n.rotation=t.rotation,t.type!=="STATIC"&&(n.velocity=P(t.velocity),n.angularVel=t.angularVel),n.kinematicVel=P(t.kinematicVel),n.kinAngVel=t.kinAngVel,n.surfaceVel=P(t.surfaceVel),t.type==="DYNAMIC"&&(n.force=P(t.force),n.torque=t.torque),t.massMode==="FIXED"&&t.mass!=null?n.mass=t.mass:t.massMode==="DEFAULT"&&(n.massMode=fa.DEFAULT),t.inertiaMode==="FIXED"&&t.inertia!=null?n.inertia=t.inertia:t.inertiaMode==="DEFAULT"&&(n.inertiaMode=ea.DEFAULT),t.gravMassMode==="SCALED"?(n.gravMassMode=da.SCALED,n.gravMassScale=t.gravMassScale):t.gravMassMode==="FIXED"&&(n.gravMassMode=da.FIXED),n.allowMovement=t.allowMovement,n.allowRotation=t.allowRotation,n.isBullet=t.bullet;for(let e of t.shapes)Jt(e).body=n;return t.userData!=null&&Object.assign(n.userData,t.userData),n}function U(t,o){t.active=o.active,t.ignore=o.ignore,t.stiff=o.stiff,t.frequency=o.frequency,t.damping=o.damping,t.maxForce=o.maxForce,t.maxError=o.maxError,t.breakUnderForce=o.breakUnderForce,t.breakUnderError=o.breakUnderError,t.removeOnBreak=o.removeOnBreak,o.userData!=null&&Object.assign(t.userData,o.userData);}function xt(t,o){let n=t.body1Id!=null?o[t.body1Id]??null:null,e=t.body2Id!=null?o[t.body2Id]??null:null;switch(t.type){case "PivotJoint":{let r=new qa(n,e,v(t.anchor1),v(t.anchor2));return U(r,t),r}case "DistanceJoint":{let r=new na(n,e,v(t.anchor1),v(t.anchor2),t.jointMin,t.jointMax);return U(r,t),r}case "AngleJoint":{let r=new ma(n,e,t.jointMin,t.jointMax,t.ratio);return U(r,t),r}case "MotorJoint":{let r=new pa(n,e,t.rate,t.ratio);return U(r,t),r}case "LineJoint":{let r=new oa(n,e,v(t.anchor1),v(t.anchor2),v(t.direction),t.jointMin,t.jointMax);return U(r,t),r}case "PulleyJoint":{let r=new ra(n,e,null,null,v(t.anchor1),v(t.anchor2),v(t.anchor3),v(t.anchor4),t.jointMin,t.jointMax,t.ratio);return U(r,t),r}case "WeldJoint":{let r=new sa(n,e,v(t.anchor1),v(t.anchor2),t.phase);return U(r,t),r}}}function Et(t){if(t.version!==1)throw new Error(`nape-js serialization: unsupported snapshot version ${t.version} (expected ${1})`);let o=t.broadphase==="SWEEP_AND_PRUNE"?ka.SWEEP_AND_PRUNE:ka.DYNAMIC_AABB_TREE,n=new Y(v(t.gravity),o);n.worldLinearDrag=t.worldLinearDrag,n.worldAngularDrag=t.worldAngularDrag,n.sortContacts=t.sortContacts,n.deterministic=t.deterministic??false;let e=t.bodies.map(St),r=t.constraints.map(s=>xt(s,e)),a=new Set,i=new Set;for(let s of t.compounds){let l=new ba;for(let u of s.bodyIds)e[u].compound=l,a.add(u);for(let u of s.constraintIndices)r[u].compound=l,i.add(u);l.space=n;}for(let s=0;s<e.length;s++)a.has(s)||(e[s].space=n);for(let s=0;s<r.length;s++)i.has(s)||(r[s].space=n);return n}var rt=class{constructor(o=4096){this.pos=0;this.buf=new ArrayBuffer(o),this.view=new DataView(this.buf);}ensure(o){let n=this.pos+o;if(n<=this.buf.byteLength)return;let e=this.buf.byteLength;for(;e<n;)e*=2;let r=new ArrayBuffer(e);new Uint8Array(r).set(new Uint8Array(this.buf)),this.buf=r,this.view=new DataView(this.buf);}writeUint8(o){this.ensure(1),this.view.setUint8(this.pos,o),this.pos+=1;}writeUint16(o){this.ensure(2),this.view.setUint16(this.pos,o,true),this.pos+=2;}writeUint32(o){this.ensure(4),this.view.setUint32(this.pos,o,true),this.pos+=4;}writeInt32(o){this.ensure(4),this.view.setInt32(this.pos,o,true),this.pos+=4;}writeFloat64(o){this.ensure(8),this.view.setFloat64(this.pos,o,true),this.pos+=8;}writeBool(o){this.writeUint8(o?1:0);}finish(){return new Uint8Array(this.buf,0,this.pos)}};var Pt=1312903237,_=2,Bt=0,Ut=1,kt=2,Tt=3,Nt=4,Vt=5,Ot=6;function _t(t,o){t.writeFloat64(o.elasticity),t.writeFloat64(o.dynamicFriction),t.writeFloat64(o.staticFriction),t.writeFloat64(o.density),t.writeFloat64(o.rollingFriction);}function Lt(t,o){t.writeInt32(o.collisionGroup),t.writeInt32(o.collisionMask),t.writeInt32(o.sensorGroup),t.writeInt32(o.sensorMask),t.writeInt32(o.fluidGroup),t.writeInt32(o.fluidMask);}function Rt(t,o){if(o==null)return;t.writeFloat64(o.density),t.writeFloat64(o.viscosity);let n=o.gravity;t.writeBool(n!=null),n!=null&&(t.writeFloat64(n.x),t.writeFloat64(n.y));}function jt(t,o){if(o.isCircle()){t.writeUint8(0);let a=o;t.writeFloat64(a.radius);let i=o.localCOM;t.writeFloat64(i.x),t.writeFloat64(i.y);}else if(o.isCapsule()){t.writeUint8(2);let a=o;t.writeFloat64(a.width),t.writeFloat64(a.height);let i=o.localCOM;t.writeFloat64(i.x),t.writeFloat64(i.y);}else {t.writeUint8(1);let i=o.localVerts,s=i.length;t.writeUint16(s);for(let l=0;l<s;l++){let u=i.at(l);t.writeFloat64(u.x),t.writeFloat64(u.y);}}_t(t,o.material),Lt(t,o.filter);let n=o.fluidEnabled,e=n&&o.fluidProperties!=null,r=(o.sensorEnabled?1:0)|(n?2:0)|(e?4:0);t.writeUint8(r),e&&Rt(t,o.fluidProperties);}function Gt(t,o){let n=o.zpp_inner;t.writeUint8(n.type),t.writeFloat64(o.position.x),t.writeFloat64(o.position.y),t.writeFloat64(o.rotation),t.writeFloat64(o.velocity.x),t.writeFloat64(o.velocity.y),t.writeFloat64(o.angularVel),t.writeFloat64(o.kinematicVel.x),t.writeFloat64(o.kinematicVel.y),t.writeFloat64(o.kinAngVel),t.writeFloat64(o.surfaceVel.x),t.writeFloat64(o.surfaceVel.y),t.writeFloat64(o.force.x),t.writeFloat64(o.force.y),t.writeFloat64(n.type===2?o.torque:0),t.writeUint8(n.massMode),t.writeFloat64(n.massMode===1?n.cmass:0),t.writeUint8(n.inertiaMode),t.writeFloat64(n.inertiaMode===1?n.cinertia:0),t.writeUint8(n.gravMassMode),t.writeFloat64(n.gravMassScale);let e=(o.allowMovement?1:0)|(o.allowRotation?2:0)|(o.isBullet?4:0);t.writeUint8(e);let r=o.shapes,a=r.length;t.writeUint16(a);for(let i=0;i<a;i++)jt(t,r.at(i));}var pt={PivotJoint:Bt,DistanceJoint:Ut,AngleJoint:kt,MotorJoint:Tt,LineJoint:Nt,PulleyJoint:Vt,WeldJoint:Ot};function k(t,o,n,e,r){let a=e!=null?n.get(e.zpp_inner.id)??-1:-1,i=r!=null?n.get(r.zpp_inner.id)??-1:-1;t.writeInt32(a),t.writeInt32(i);let s=o.zpp_inner,l=(s.active?1:0)|(s.ignore?2:0)|(s.stiff?4:0)|(s.breakUnderForce?8:0)|(s.breakUnderError?16:0)|(s.removeOnBreak?32:0);t.writeUint8(l),t.writeFloat64(s.frequency),t.writeFloat64(s.damping),t.writeFloat64(s.maxForce),t.writeFloat64(s.maxError);}function Wt(t,o,n){let e=o.constructor?.name??"",r=pt[e];if(r===void 0)return false;switch(t.writeUint8(r),e){case "PivotJoint":{let a=o;k(t,o,n,a.body1,a.body2),t.writeFloat64(a.anchor1.x),t.writeFloat64(a.anchor1.y),t.writeFloat64(a.anchor2.x),t.writeFloat64(a.anchor2.y);break}case "DistanceJoint":{let a=o;k(t,o,n,a.body1,a.body2),t.writeFloat64(a.anchor1.x),t.writeFloat64(a.anchor1.y),t.writeFloat64(a.anchor2.x),t.writeFloat64(a.anchor2.y),t.writeFloat64(a.jointMin),t.writeFloat64(a.jointMax);break}case "AngleJoint":{let a=o;k(t,o,n,a.body1,a.body2),t.writeFloat64(a.jointMin),t.writeFloat64(a.jointMax),t.writeFloat64(a.ratio);break}case "MotorJoint":{let a=o;k(t,o,n,a.body1,a.body2),t.writeFloat64(a.rate),t.writeFloat64(a.ratio);break}case "LineJoint":{let a=o;k(t,o,n,a.body1,a.body2),t.writeFloat64(a.anchor1.x),t.writeFloat64(a.anchor1.y),t.writeFloat64(a.anchor2.x),t.writeFloat64(a.anchor2.y),t.writeFloat64(a.direction.x),t.writeFloat64(a.direction.y),t.writeFloat64(a.jointMin),t.writeFloat64(a.jointMax);break}case "PulleyJoint":{let a=o;k(t,o,n,a.body1,a.body2),t.writeFloat64(a.anchor1.x),t.writeFloat64(a.anchor1.y),t.writeFloat64(a.anchor2.x),t.writeFloat64(a.anchor2.y),t.writeFloat64(a.anchor3.x),t.writeFloat64(a.anchor3.y),t.writeFloat64(a.anchor4.x),t.writeFloat64(a.anchor4.y),t.writeFloat64(a.jointMin),t.writeFloat64(a.jointMax),t.writeFloat64(a.ratio);break}case "WeldJoint":{let a=o;k(t,o,n,a.body1,a.body2),t.writeFloat64(a.anchor1.x),t.writeFloat64(a.anchor1.y),t.writeFloat64(a.anchor2.x),t.writeFloat64(a.anchor2.y),t.writeFloat64(a.phase);break}}return true}function Yt(t){let o=new rt,n=[],e=new Map,r=new Map;function a(c){let F=c.zpp_inner.id;if(e.has(F))return;let d=n.length;r.set(c,d),e.set(F,d),n.push(c);}let i=t.bodies,s=i.length;for(let c=0;c<s;c++)a(i.at(c));let l=t.compounds,u=l.length;for(let c=0;c<u;c++){let d=l.at(c).bodies,f=d.length;for(let p=0;p<f;p++)a(d.at(p));}let m=[],D=new Map;function M(c){if(D.has(c))return;let F=c.constructor?.name??"";pt[F]!==void 0&&(D.set(c,m.length),m.push(c));}let S=t.constraints,A=S.length;for(let c=0;c<A;c++)M(S.at(c));for(let c=0;c<u;c++){let d=l.at(c).constraints,f=d.length;for(let p=0;p<f;p++)M(d.at(p));}o.writeUint32(Pt),o.writeUint16(_),o.writeUint32(n.length),o.writeUint32(m.length),o.writeUint32(u);let h=t.gravity;o.writeFloat64(h.x),o.writeFloat64(h.y),o.writeFloat64(t.worldLinearDrag),o.writeFloat64(t.worldAngularDrag),o.writeBool(t.sortContacts),o.writeBool(t.deterministic),o.writeUint8(t.zpp_inner.bphase.is_sweep?0:1);for(let c=0;c<n.length;c++)Gt(o,n[c]);for(let c=0;c<m.length;c++)Wt(o,m[c],e);for(let c=0;c<u;c++){let F=l.at(c),d=F.bodies,f=d.length;o.writeUint16(f);for(let C=0;C<f;C++){let x=d.at(C),w=r.get(x)??0;o.writeUint32(w);}let p=F.constraints,g=p.length,I=0;for(let C=0;C<g;C++){let x=p.at(C);D.has(x)&&I++;}o.writeUint16(I);for(let C=0;C<g;C++){let x=p.at(C),w=D.get(x);w!=null&&o.writeUint32(w);}o.writeUint16(0);}return o.finish()}var it=class{constructor(o){this.pos=0;this.view=new DataView(o.buffer,o.byteOffset,o.byteLength);}readUint8(){let o=this.view.getUint8(this.pos);return this.pos+=1,o}readUint16(){let o=this.view.getUint16(this.pos,true);return this.pos+=2,o}readUint32(){let o=this.view.getUint32(this.pos,true);return this.pos+=4,o}readInt32(){let o=this.view.getInt32(this.pos,true);return this.pos+=4,o}readFloat64(){let o=this.view.getFloat64(this.pos,true);return this.pos+=8,o}readBool(){return this.readUint8()!==0}};var dt=1312903237,Xt=0,qt=1,zt=2,Ht=3,$t=4,Kt=5,Qt=6,Zt={1:aa.STATIC,2:aa.DYNAMIC,3:aa.KINEMATIC};function lt(t){let o=t.readFloat64(),n=t.readFloat64(),e=t.readFloat64(),r=t.readFloat64(),a=t.readFloat64();return new ca(o,n,e,r,a)}function ct(t){let o=new ha;return o.collisionGroup=t.readInt32(),o.collisionMask=t.readInt32(),o.sensorGroup=t.readInt32(),o.sensorMask=t.readInt32(),o.fluidGroup=t.readInt32(),o.fluidMask=t.readInt32(),o}function to(t){let o=t.readFloat64(),n=t.readFloat64(),e=new U$1(o,n);return t.readBool()&&(e.gravity=I.get(t.readFloat64(),t.readFloat64())),e}function oo(t){let o=t.readUint8(),n;if(o===0){let a=t.readFloat64(),i=t.readFloat64(),s=t.readFloat64(),l=lt(t),u=ct(t);n=new ga(a,I.weak(i,s),l,u);}else if(o===2){let a=t.readFloat64(),i=t.readFloat64(),s=t.readFloat64(),l=t.readFloat64(),u=lt(t),m=ct(t);n=new ja(a,i,I.weak(s,l),u,m);}else {let a=t.readUint16(),i=[];for(let u=0;u<a;u++)i.push(I.get(t.readFloat64(),t.readFloat64()));let s=lt(t),l=ct(t);n=new ia(i,s,l);}let e=t.readUint8();return n.sensorEnabled=(e&1)!==0,n.fluidEnabled=(e&2)!==0,(e&4)!==0&&(n.fluidProperties=to(t)),n}function eo(t){let o=t.readUint8(),n=Zt[o]??aa.DYNAMIC,e=t.readFloat64(),r=t.readFloat64(),a=t.readFloat64(),i=new $(n,I.weak(e,r));i.rotation=a;let s=t.readFloat64(),l=t.readFloat64(),u=t.readFloat64();o!==1&&(i.velocity=I.get(s,l),i.angularVel=u),i.kinematicVel=I.get(t.readFloat64(),t.readFloat64()),i.kinAngVel=t.readFloat64(),i.surfaceVel=I.get(t.readFloat64(),t.readFloat64());let m=t.readFloat64(),D=t.readFloat64(),M=t.readFloat64();o===2&&(i.force=I.get(m,D),i.torque=M);let S=t.readUint8(),A=t.readFloat64();S===1&&A!==0?i.mass=A:S===0&&(i.massMode=fa.DEFAULT);let h=t.readUint8(),c=t.readFloat64();h===1&&c!==0?i.inertia=c:h===0&&(i.inertiaMode=ea.DEFAULT);let F=t.readUint8(),d=t.readFloat64();F===2?(i.gravMassMode=da.SCALED,i.gravMassScale=d):F===1&&(i.gravMassMode=da.FIXED);let f=t.readUint8();i.allowMovement=(f&1)!==0,i.allowRotation=(f&2)!==0,i.isBullet=(f&4)!==0;let p=t.readUint16();for(let g=0;g<p;g++)oo(t).body=i;return i}function no(t){let o=t.readInt32(),n=t.readInt32(),e=t.readUint8(),r=t.readFloat64(),a=t.readFloat64(),i=t.readFloat64(),s=t.readFloat64();return {body1Id:o,body2Id:n,active:(e&1)!==0,ignore:(e&2)!==0,stiff:(e&4)!==0,breakUnderForce:(e&8)!==0,breakUnderError:(e&16)!==0,removeOnBreak:(e&32)!==0,frequency:r,damping:a,maxForce:i,maxError:s}}function T(t,o){t.active=o.active,t.ignore=o.ignore,t.stiff=o.stiff,t.frequency=o.frequency,t.damping=o.damping,t.maxForce=o.maxForce,t.maxError=o.maxError,t.breakUnderForce=o.breakUnderForce,t.breakUnderError=o.breakUnderError,t.removeOnBreak=o.removeOnBreak;}function ao(t,o){let n=t.readUint8(),e=no(t),r=e.body1Id>=0?o[e.body1Id]??null:null,a=e.body2Id>=0?o[e.body2Id]??null:null;switch(n){case Xt:{let i=t.readFloat64(),s=t.readFloat64(),l=t.readFloat64(),u=t.readFloat64(),m=new qa(r,a,I.weak(i,s),I.weak(l,u));return T(m,e),m}case qt:{let i=t.readFloat64(),s=t.readFloat64(),l=t.readFloat64(),u=t.readFloat64(),m=t.readFloat64(),D=t.readFloat64(),M=new na(r,a,I.weak(i,s),I.weak(l,u),m,D);return T(M,e),M}case zt:{let i=t.readFloat64(),s=t.readFloat64(),l=t.readFloat64(),u=new ma(r,a,i,s,l);return T(u,e),u}case Ht:{let i=t.readFloat64(),s=t.readFloat64(),l=new pa(r,a,i,s);return T(l,e),l}case $t:{let i=t.readFloat64(),s=t.readFloat64(),l=t.readFloat64(),u=t.readFloat64(),m=t.readFloat64(),D=t.readFloat64(),M=t.readFloat64(),S=t.readFloat64(),A=new oa(r,a,I.weak(i,s),I.weak(l,u),I.weak(m,D),M,S);return T(A,e),A}case Kt:{let i=t.readFloat64(),s=t.readFloat64(),l=t.readFloat64(),u=t.readFloat64(),m=t.readFloat64(),D=t.readFloat64(),M=t.readFloat64(),S=t.readFloat64(),A=t.readFloat64(),h=t.readFloat64(),c=t.readFloat64(),F=new ra(r,a,null,null,I.weak(i,s),I.weak(l,u),I.weak(m,D),I.weak(M,S),A,h,c);return T(F,e),F}case Qt:{let i=t.readFloat64(),s=t.readFloat64(),l=t.readFloat64(),u=t.readFloat64(),m=t.readFloat64(),D=new sa(r,a,I.weak(i,s),I.weak(l,u),m);return T(D,e),D}default:throw new Error(`nape-js binary: unknown constraint type tag ${n}`)}}function ro(t){let o=new it(t),n=o.readUint32();if(n!==dt)throw new Error(`nape-js binary: invalid magic bytes 0x${n.toString(16)} (expected 0x${dt.toString(16)})`);let e=o.readUint16();if(e!==_)throw new Error(`nape-js binary: unsupported version ${e} (expected ${_})`);let r=o.readUint32(),a=o.readUint32(),i=o.readUint32(),s=o.readFloat64(),l=o.readFloat64(),u=o.readFloat64(),m=o.readFloat64(),D=o.readBool(),M=o.readBool(),A=o.readUint8()===0?ka.SWEEP_AND_PRUNE:ka.DYNAMIC_AABB_TREE,h=new Y(I.weak(s,l),A);h.worldLinearDrag=u,h.worldAngularDrag=m,h.sortContacts=D,h.deterministic=M;let c=new Array(r);for(let p=0;p<r;p++)c[p]=eo(o);let F=new Array(a);for(let p=0;p<a;p++)F[p]=ao(o,c);let d=new Set,f=new Set;for(let p=0;p<i;p++){let g=new ba,I=o.readUint16();for(let w=0;w<I;w++){let J=o.readUint32();c[J].compound=g,d.add(J);}let C=o.readUint16();for(let w=0;w<C;w++){let J=o.readUint32();F[J].compound=g,f.add(J);}let x=o.readUint16();for(let w=0;w<x;w++)o.readUint32();g.space=h;}for(let p=0;p<r;p++)d.has(p)||(c[p].space=h);for(let p=0;p<a;p++)f.has(p)||(F[p].space=h);return h}export{_ as BINARY_SNAPSHOT_VERSION,at as SNAPSHOT_VERSION,ro as spaceFromBinary,Et as spaceFromJSON,Yt as spaceToBinary,wt as spaceToJSON};//# sourceMappingURL=index.js.map
1
+ export{a as BINARY_SNAPSHOT_VERSION,c as spaceFromBinary,b as spaceToBinary}from'../chunk-GPGT7DYQ.js';import {ka,Y,ba,I,aa,$,fa,ea,da,sa,ra,oa,pa,ma,na,qa,ga,ja,ia,ca,ha,U}from'../chunk-263GQ5UK.js';var J=1;function s(t){return {x:t.x,y:t.y}}function Q(t){if(t==null)return null;try{let a=JSON.stringify(t);return a==="{}"?null:JSON.parse(a)}catch{return null}}function it(t){return {elasticity:t.elasticity,dynamicFriction:t.dynamicFriction,staticFriction:t.staticFriction,density:t.density,rollingFriction:t.rollingFriction}}function st(t){return {collisionGroup:t.collisionGroup,collisionMask:t.collisionMask,sensorGroup:t.sensorGroup,sensorMask:t.sensorMask,fluidGroup:t.fluidGroup,fluidMask:t.fluidMask}}function lt(t){if(t==null)return null;let a=t.gravity;return {density:t.density,viscosity:t.viscosity,gravity:a!=null?s(a):null}}function ct(t){let a=it(t.material),n=st(t.filter),e=t.fluidEnabled,o=e?lt(t.fluidProperties):null,l=t.sensorEnabled;if(t.isCircle()){let c=t,r=t.localCOM;return {type:"circle",radius:c.radius,localCOM:s(r),material:a,filter:n,sensorEnabled:l,fluidEnabled:e,fluidProperties:o}}else if(t.isCapsule()){let c=t,r=t.localCOM;return {type:"capsule",width:c.width,height:c.height,localCOM:s(r),material:a,filter:n,sensorEnabled:l,fluidEnabled:e,fluidProperties:o}}else {let r=t.localVerts,m=[],u=r.length;for(let b=0;b<u;b++)m.push(s(r.at(b)));return {type:"polygon",localVerts:m,material:a,filter:n,sensorEnabled:l,fluidEnabled:e,fluidProperties:o}}}var ut={1:"STATIC",2:"DYNAMIC",3:"KINEMATIC"},pt={0:"DEFAULT",1:"FIXED",2:"FIXED_GROUP"},mt={0:"DEFAULT",1:"FIXED",2:"FIXED_GROUP"},Dt={0:"DEFAULT",1:"FIXED",2:"SCALED"};function yt(t,a){let n=t.zpp_inner,e=pt[n.massMode]??"DEFAULT",o=mt[n.inertiaMode]??"DEFAULT",l=Dt[n.gravMassMode]??"DEFAULT",c=[],r=t.shapes,m=r.length;for(let u=0;u<m;u++)c.push(ct(r.at(u)));return {id:a,type:ut[n.type]??"DYNAMIC",position:s(t.position),rotation:t.rotation,velocity:s(t.velocity),angularVel:t.angularVel,kinematicVel:s(t.kinematicVel),kinAngVel:t.kinAngVel,surfaceVel:s(t.surfaceVel),force:s(t.force),torque:n.type===2?t.torque:0,massMode:e,mass:e==="FIXED"?n.cmass:null,inertiaMode:o,inertia:o==="FIXED"?n.cinertia:null,gravMassMode:l,gravMassScale:n.gravMassScale,allowMovement:t.allowMovement,allowRotation:t.allowRotation,bullet:t.isBullet,shapes:c,userData:Q(n.userData)}}function h(t,a,n,e){let o=t.zpp_inner,l=n!=null?a.get(n.zpp_inner.id)??null:null,c=e!=null?a.get(e.zpp_inner.id)??null:null;return {body1Id:l,body2Id:c,active:o.active,ignore:o.ignore,stiff:o.stiff,frequency:o.frequency,damping:o.damping,maxForce:o.maxForce,maxError:o.maxError,breakUnderForce:o.breakUnderForce,breakUnderError:o.breakUnderError,removeOnBreak:o.removeOnBreak,userData:Q(o.userData)}}function ft(t,a){switch(t.constructor?.name??""){case "PivotJoint":{let e=t;return {...h(t,a,e.body1,e.body2),type:"PivotJoint",anchor1:s(e.anchor1),anchor2:s(e.anchor2)}}case "DistanceJoint":{let e=t;return {...h(t,a,e.body1,e.body2),type:"DistanceJoint",anchor1:s(e.anchor1),anchor2:s(e.anchor2),jointMin:e.jointMin,jointMax:e.jointMax}}case "AngleJoint":{let e=t;return {...h(t,a,e.body1,e.body2),type:"AngleJoint",jointMin:e.jointMin,jointMax:e.jointMax,ratio:e.ratio}}case "MotorJoint":{let e=t;return {...h(t,a,e.body1,e.body2),type:"MotorJoint",rate:e.rate,ratio:e.ratio}}case "LineJoint":{let e=t;return {...h(t,a,e.body1,e.body2),type:"LineJoint",anchor1:s(e.anchor1),anchor2:s(e.anchor2),direction:s(e.direction),jointMin:e.jointMin,jointMax:e.jointMax}}case "PulleyJoint":{let e=t;return {...h(t,a,e.body1,e.body2),type:"PulleyJoint",anchor1:s(e.anchor1),anchor2:s(e.anchor2),anchor3:s(e.anchor3),anchor4:s(e.anchor4),jointMin:e.jointMin,jointMax:e.jointMax,ratio:e.ratio}}case "WeldJoint":{let e=t;return {...h(t,a,e.body1,e.body2),type:"WeldJoint",anchor1:s(e.anchor1),anchor2:s(e.anchor2),phase:e.phase}}default:return null}}function dt(t){let a=[],n=new Map,e=new Map;function o(i){let y=i.zpp_inner.id;if(e.has(y))return;let D=a.length;n.set(i,D),e.set(y,D),a.push(yt(i,D));}let l=t.bodies,c=l.length;for(let i=0;i<c;i++)o(l.at(i));let r=t.compounds,m=r.length;for(let i=0;i<m;i++){let D=r.at(i).bodies,C=D.length;for(let f=0;f<C;f++)o(D.at(f));}let u=[],b=new Map;function I(i){if(b.has(i))return;let y=ft(i,e);y!=null&&(b.set(i,u.length),u.push(y));}let x=t.constraints,Z=x.length;for(let i=0;i<Z;i++)I(x.at(i));for(let i=0;i<m;i++){let D=r.at(i).constraints,C=D.length;for(let f=0;f<C;f++)I(D.at(f));}let V=[];for(let i=0;i<m;i++){let y=r.at(i),D=[],C=y.bodies,f=C.length;for(let M=0;M<f;M++){let F=C.at(M),S=n.get(F);S!=null&&D.push(S);}let B=[],w=y.constraints,nt=w.length;for(let M=0;M<nt;M++){let F=w.at(M),S=b.get(F);S!=null&&B.push(S);}V.push({bodyIds:D,constraintIndices:B,childIndices:[]});}let tt=t.zpp_inner.bphase.is_sweep?"SWEEP_AND_PRUNE":"DYNAMIC_AABB_TREE",et=t.gravity;return {version:1,gravity:s(et),worldLinearDrag:t.worldLinearDrag,worldAngularDrag:t.worldAngularDrag,sortContacts:t.sortContacts,deterministic:t.deterministic,broadphase:tt,bodies:a,constraints:u,compounds:V}}function d(t){return I.get(t.x,t.y)}function p(t){return I.weak(t.x,t.y)}function bt(t){return new ca(t.elasticity,t.dynamicFriction,t.staticFriction,t.density,t.rollingFriction)}function Mt(t){let a=new ha;return a.collisionGroup=t.collisionGroup,a.collisionMask=t.collisionMask,a.sensorGroup=t.sensorGroup,a.sensorMask=t.sensorMask,a.fluidGroup=t.fluidGroup,a.fluidMask=t.fluidMask,a}function ht(t){let a=new U(t.density,t.viscosity);return t.gravity!=null&&(a.gravity=d(t.gravity)),a}function gt(t){let a=bt(t.material),n=Mt(t.filter),e;if(t.type==="circle"){let o=d(t.localCOM);e=new ga(t.radius,o,a,n);}else if(t.type==="capsule"){let o=d(t.localCOM);e=new ja(t.width,t.height,o,a,n);}else {let o=t.localVerts.map(l=>d(l));e=new ia(o,a,n);}return e.sensorEnabled=t.sensorEnabled,e.fluidEnabled=t.fluidEnabled,t.fluidEnabled&&t.fluidProperties!=null&&(e.fluidProperties=ht(t.fluidProperties)),e}function Ct(t){let a=t.type==="STATIC"?aa.STATIC:t.type==="KINEMATIC"?aa.KINEMATIC:aa.DYNAMIC,n=new $(a,p(t.position));n.rotation=t.rotation,t.type!=="STATIC"&&(n.velocity=d(t.velocity),n.angularVel=t.angularVel),n.kinematicVel=d(t.kinematicVel),n.kinAngVel=t.kinAngVel,n.surfaceVel=d(t.surfaceVel),t.type==="DYNAMIC"&&(n.force=d(t.force),n.torque=t.torque),t.massMode==="FIXED"&&t.mass!=null?n.mass=t.mass:t.massMode==="DEFAULT"&&(n.massMode=fa.DEFAULT),t.inertiaMode==="FIXED"&&t.inertia!=null?n.inertia=t.inertia:t.inertiaMode==="DEFAULT"&&(n.inertiaMode=ea.DEFAULT),t.gravMassMode==="SCALED"?(n.gravMassMode=da.SCALED,n.gravMassScale=t.gravMassScale):t.gravMassMode==="FIXED"&&(n.gravMassMode=da.FIXED),n.allowMovement=t.allowMovement,n.allowRotation=t.allowRotation,n.isBullet=t.bullet;for(let e of t.shapes)gt(e).body=n;return t.userData!=null&&Object.assign(n.userData,t.userData),n}function g(t,a){t.active=a.active,t.ignore=a.ignore,t.stiff=a.stiff,t.frequency=a.frequency,t.damping=a.damping,t.maxForce=a.maxForce,t.maxError=a.maxError,t.breakUnderForce=a.breakUnderForce,t.breakUnderError=a.breakUnderError,t.removeOnBreak=a.removeOnBreak,a.userData!=null&&Object.assign(t.userData,a.userData);}function St(t,a){let n=t.body1Id!=null?a[t.body1Id]??null:null,e=t.body2Id!=null?a[t.body2Id]??null:null;switch(t.type){case "PivotJoint":{let o=new qa(n,e,p(t.anchor1),p(t.anchor2));return g(o,t),o}case "DistanceJoint":{let o=new na(n,e,p(t.anchor1),p(t.anchor2),t.jointMin,t.jointMax);return g(o,t),o}case "AngleJoint":{let o=new ma(n,e,t.jointMin,t.jointMax,t.ratio);return g(o,t),o}case "MotorJoint":{let o=new pa(n,e,t.rate,t.ratio);return g(o,t),o}case "LineJoint":{let o=new oa(n,e,p(t.anchor1),p(t.anchor2),p(t.direction),t.jointMin,t.jointMax);return g(o,t),o}case "PulleyJoint":{let o=new ra(n,e,null,null,p(t.anchor1),p(t.anchor2),p(t.anchor3),p(t.anchor4),t.jointMin,t.jointMax,t.ratio);return g(o,t),o}case "WeldJoint":{let o=new sa(n,e,p(t.anchor1),p(t.anchor2),t.phase);return g(o,t),o}}}function Et(t){if(t.version!==1)throw new Error(`nape-js serialization: unsupported snapshot version ${t.version} (expected ${1})`);let a=t.broadphase==="SWEEP_AND_PRUNE"?ka.SWEEP_AND_PRUNE:ka.DYNAMIC_AABB_TREE,n=new Y(p(t.gravity),a);n.worldLinearDrag=t.worldLinearDrag,n.worldAngularDrag=t.worldAngularDrag,n.sortContacts=t.sortContacts,n.deterministic=t.deterministic??false;let e=t.bodies.map(Ct),o=t.constraints.map(r=>St(r,e)),l=new Set,c=new Set;for(let r of t.compounds){let m=new ba;for(let u of r.bodyIds)e[u].compound=m,l.add(u);for(let u of r.constraintIndices)o[u].compound=m,c.add(u);m.space=n;}for(let r=0;r<e.length;r++)l.has(r)||(e[r].space=n);for(let r=0;r<o.length;r++)c.has(r)||(o[r].space=n);return n}export{J as SNAPSHOT_VERSION,Et as spaceFromJSON,dt as spaceToJSON};//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map
package/llms-full.txt CHANGED
@@ -4,8 +4,8 @@
4
4
 
5
5
  - **npm**: `npm install @newkrok/nape-js`
6
6
  - **GitHub**: https://github.com/NewKrok/nape-js
7
- - **API docs**: https://newkrok.github.io/nape-js/api/index.html
8
- - **Demos**: https://newkrok.github.io/nape-js/examples.html
7
+ - **API docs**: https://napejs.org/api/index.html
8
+ - **Demos**: https://napejs.org/examples.html
9
9
  - **License**: MIT
10
10
  - **Version**: 3.30.0
11
11
  - **Cookbook**: https://github.com/NewKrok/nape-js/blob/master/docs/guides/cookbook.md
@@ -2073,3 +2073,133 @@ function render() {
2073
2073
  }
2074
2074
  render();
2075
2075
  ```
2076
+
2077
+ ---
2078
+
2079
+ ## Replay Sub-Package (`@newkrok/nape-js/replay`)
2080
+
2081
+ Record a deterministic simulation as `(initial snapshot, per-frame input log)`
2082
+ and replay it deterministically — same machine, another machine, days later.
2083
+ Built on `/serialization` plus `space.deterministic = true`. Tree-shakeable.
2084
+
2085
+ ```typescript
2086
+ import "@newkrok/nape-js"; // engine bootstrap
2087
+ import { Recorder, Player, encodeReplay, decodeReplay } from "@newkrok/nape-js/replay";
2088
+ ```
2089
+
2090
+ ### Recorder
2091
+
2092
+ ```typescript
2093
+ new Recorder<T>(space: Space, options?: { keyframeEvery?: number })
2094
+ ```
2095
+
2096
+ Captures the initial snapshot at construction and stores user-supplied input
2097
+ payloads via `recordFrame`. With `keyframeEvery > 0` (default `60`), also
2098
+ captures intermediate snapshots for fast scrub.
2099
+
2100
+ **Methods:**
2101
+ - `recordFrame(input?: T | null): void` — Log a payload at the current frame
2102
+ and advance. Pass `null` (or omit) for input-less frames; only non-null
2103
+ payloads are stored. Payloads are deep-cloned via JSON (primitives
2104
+ fast-pathed). Throws after `finish()`.
2105
+ - `finish(): Replay<T>` — Seal the recording and return an immutable result.
2106
+
2107
+ **Properties:**
2108
+ - `frame: number` — Frames recorded so far.
2109
+ - `finished: boolean` — True after `finish()`.
2110
+
2111
+ ### Player
2112
+
2113
+ ```typescript
2114
+ new Player<T>(replay: Replay<T>, applyInput?: ((input: T, space: Space, frame: number) => void) | null, options?: { dt?: number; velocityIterations?: number; positionIterations?: number })
2115
+ ```
2116
+
2117
+ Plays a recorded `Replay`. Owns its own `Space` deserialised from the initial
2118
+ snapshot.
2119
+
2120
+ **Lifecycle:**
2121
+ - `restore(): Space` — Restore initial snapshot. Idempotent (rewinds to frame 0).
2122
+ - `step(): void` — Apply the next recorded input via `applyInput`, then step
2123
+ physics by `dt`. Throws past end or before `restore()`.
2124
+ - `stepTo(frame: number): void` — Random-access seek. Forward jumps walk the
2125
+ log; backward jumps restore the latest keyframe ≤ target then step forward.
2126
+
2127
+ **Properties:**
2128
+ - `space: Space` — Active space (throws before `restore()`).
2129
+ - `frame: number` — Current frame index (0 = pre-step).
2130
+ - `frameCount: number` — Total frames in the replay.
2131
+ - `finished: boolean` — `frame >= frameCount`.
2132
+ - `applyInput` — Mutable; swap callback mid-playback.
2133
+
2134
+ ### encodeReplay / decodeReplay
2135
+
2136
+ ```typescript
2137
+ function encodeReplay<T>(replay: Replay<T>): Uint8Array
2138
+ function decodeReplay<T = unknown>(bytes: Uint8Array): Replay<T>
2139
+ ```
2140
+
2141
+ Compact binary format: magic `RPLY`, versioned, length-prefixed snapshots,
2142
+ UTF-8 JSON for input payloads. Round-trip preserves frame count, inputs, and
2143
+ keyframes byte-for-byte. Throws on bad magic or unsupported version.
2144
+
2145
+ ### validateDeterministicConfig
2146
+
2147
+ ```typescript
2148
+ function validateDeterministicConfig(space: Space): { ok: boolean; warnings: string[] }
2149
+ ```
2150
+
2151
+ Sanity-checks `space.deterministic = true` and friends. Pure inspection.
2152
+
2153
+ ### Replay type
2154
+
2155
+ ```typescript
2156
+ interface Replay<T> {
2157
+ readonly version: number;
2158
+ readonly initialSnapshot: Uint8Array;
2159
+ readonly inputs: ReadonlyArray<{ frame: number; payload: T }>;
2160
+ readonly keyframes: ReadonlyArray<{ frame: number; snapshot: Uint8Array }>;
2161
+ readonly frameCount: number;
2162
+ }
2163
+ ```
2164
+
2165
+ ### Determinism contract
2166
+
2167
+ Replay matches recording bit-close on the **same platform** when:
2168
+
2169
+ 1. `space.deterministic = true` is set on the recording space (and survives in
2170
+ the snapshot).
2171
+ 2. Both sides use a fixed `dt` and matching velocity/position iteration counts.
2172
+ 3. The user's `applyInput` is a pure function of `(input, space, frame)` — no
2173
+ `Math.random()`, no wall-clock reads, no closure mutations.
2174
+
2175
+ Cross-platform bit-exact replay is not currently supported (floating-point
2176
+ rounding differs across CPUs). `body.userData` is NOT preserved through binary
2177
+ snapshots — encode it into your input payload if needed.
2178
+
2179
+ ### Usage example
2180
+
2181
+ ```typescript
2182
+ import "@newkrok/nape-js";
2183
+ import { Recorder, Player, encodeReplay, decodeReplay } from "@newkrok/nape-js/replay";
2184
+
2185
+ type Input = { fire?: boolean };
2186
+
2187
+ // Record
2188
+ space.deterministic = true;
2189
+ const recorder = new Recorder<Input>(space, { keyframeEvery: 60 });
2190
+ for (let f = 0; f < 600; f++) {
2191
+ const input = readInput();
2192
+ recorder.recordFrame(input);
2193
+ if (input?.fire) ball.applyImpulse(new Vec2(0, -200));
2194
+ space.step(1 / 60);
2195
+ }
2196
+ const blob = encodeReplay(recorder.finish());
2197
+
2198
+ // Replay
2199
+ const replay = decodeReplay<Input>(blob);
2200
+ const player = new Player(replay, (input, sp) => {
2201
+ if (input.fire) sp.bodies.at(1).applyImpulse(new Vec2(0, -200));
2202
+ });
2203
+ player.restore();
2204
+ while (!player.finished) player.step();
2205
+ ```
package/llms.txt CHANGED
@@ -6,10 +6,11 @@ Install: `npm install @newkrok/nape-js`
6
6
 
7
7
  - [GitHub Repository](https://github.com/NewKrok/nape-js): Source code, issues, contributing guide
8
8
  - [npm Package](https://www.npmjs.com/package/@newkrok/nape-js): Published package with TypeScript declarations
9
- - [API Reference](https://newkrok.github.io/nape-js/api/index.html): Full TypeDoc-generated API docs
10
- - [Interactive Demos](https://newkrok.github.io/nape-js/examples.html): Live physics demos with source code
9
+ - [API Reference](https://napejs.org/api/index.html): Full TypeDoc-generated API docs
10
+ - [Interactive Demos](https://napejs.org/examples.html): Live physics demos with source code
11
11
  - [Full LLM Documentation](https://raw.githubusercontent.com/NewKrok/nape-js/master/packages/nape-js/llms-full.txt): Complete API reference in a single file
12
- - [Cookbook](https://github.com/NewKrok/nape-js/blob/master/docs/guides/cookbook.md): Task-oriented recipes (platformer, ragdoll, fluid, serialization, etc.)
12
+ - [Cookbook](https://github.com/NewKrok/nape-js/blob/master/docs/guides/cookbook.md): Task-oriented recipes (platformer, ragdoll, fluid, serialization, replay, etc.)
13
+ - [Replay Guide](https://github.com/NewKrok/nape-js/blob/master/docs/guides/replay-guide.md): Recorder + Player + binary encode/decode + determinism contract
13
14
  - [Troubleshooting](https://github.com/NewKrok/nape-js/blob/master/docs/guides/troubleshooting.md): Common problems and solutions
14
15
  - [Anti-Patterns](https://github.com/NewKrok/nape-js/blob/master/docs/guides/anti-patterns.md): Common mistakes to avoid
15
16
  - [PixiJS Integration](https://www.npmjs.com/package/@newkrok/nape-pixi) (`@newkrok/nape-pixi`): Sibling package — body/sprite sync, fixed-step render interpolation, debug draw, and off-thread physics bridge. PIXI v8.
@@ -36,92 +37,92 @@ function update() {
36
37
 
37
38
  ## Core Classes
38
39
 
39
- - [Space](https://newkrok.github.io/nape-js/api/classes/Space.html): Physics world — create with gravity, add bodies, call `step(dt)` to simulate. `space.deterministic = true` for same-platform reproducibility (multiplayer rollback/prediction)
40
- - [Body](https://newkrok.github.io/nape-js/api/classes/Body.html): Rigid body with position, velocity, rotation, mass, shapes list
41
- - [Vec2](https://newkrok.github.io/nape-js/api/classes/Vec2.html): 2D vector with pooling (`Vec2.get()`, `Vec2.weak()`) and arithmetic methods
42
- - [AABB](https://newkrok.github.io/nape-js/api/classes/AABB.html): Axis-aligned bounding box for spatial queries
40
+ - [Space](https://napejs.org/api/classes/Space.html): Physics world — create with gravity, add bodies, call `step(dt)` to simulate. `space.deterministic = true` for same-platform reproducibility (multiplayer rollback/prediction)
41
+ - [Body](https://napejs.org/api/classes/Body.html): Rigid body with position, velocity, rotation, mass, shapes list
42
+ - [Vec2](https://napejs.org/api/classes/Vec2.html): 2D vector with pooling (`Vec2.get()`, `Vec2.weak()`) and arithmetic methods
43
+ - [AABB](https://napejs.org/api/classes/AABB.html): Axis-aligned bounding box for spatial queries
43
44
 
44
45
  ## Shapes
45
46
 
46
- - [Circle](https://newkrok.github.io/nape-js/api/classes/Circle.html): Circular collision shape with radius
47
- - [Polygon](https://newkrok.github.io/nape-js/api/classes/Polygon.html): Convex polygon with factories: `Polygon.box()`, `Polygon.rect()`, `Polygon.regular()`
48
- - [Shape](https://newkrok.github.io/nape-js/api/classes/Shape.html): Base class — material, filter, sensor support, cbTypes
49
- - [Edge](https://newkrok.github.io/nape-js/api/classes/Edge.html): Read-only polygon edge with normal and projection data
47
+ - [Circle](https://napejs.org/api/classes/Circle.html): Circular collision shape with radius
48
+ - [Polygon](https://napejs.org/api/classes/Polygon.html): Convex polygon with factories: `Polygon.box()`, `Polygon.rect()`, `Polygon.regular()`
49
+ - [Shape](https://napejs.org/api/classes/Shape.html): Base class — material, filter, sensor support, cbTypes
50
+ - [Edge](https://napejs.org/api/classes/Edge.html): Read-only polygon edge with normal and projection data
50
51
 
51
52
  ## Physics Properties
52
53
 
53
- - [Material](https://newkrok.github.io/nape-js/api/classes/Material.html): Elasticity, friction, density — presets: `wood()`, `steel()`, `ice()`, `rubber()`, `glass()`, `sand()`
54
- - [FluidProperties](https://newkrok.github.io/nape-js/api/classes/FluidProperties.html): Density, viscosity for fluid interaction shapes
55
- - [InteractionFilter](https://newkrok.github.io/nape-js/api/classes/InteractionFilter.html): Bit-mask collision/sensor/fluid filtering
56
- - [InteractionGroup](https://newkrok.github.io/nape-js/api/classes/InteractionGroup.html): Group-based interaction management
54
+ - [Material](https://napejs.org/api/classes/Material.html): Elasticity, friction, density — presets: `wood()`, `steel()`, `ice()`, `rubber()`, `glass()`, `sand()`
55
+ - [FluidProperties](https://napejs.org/api/classes/FluidProperties.html): Density, viscosity for fluid interaction shapes
56
+ - [InteractionFilter](https://napejs.org/api/classes/InteractionFilter.html): Bit-mask collision/sensor/fluid filtering
57
+ - [InteractionGroup](https://napejs.org/api/classes/InteractionGroup.html): Group-based interaction management
57
58
 
58
59
  ## Constraints (Joints)
59
60
 
60
- - [PivotJoint](https://newkrok.github.io/nape-js/api/classes/PivotJoint.html): Pin two bodies at a shared anchor point
61
- - [DistanceJoint](https://newkrok.github.io/nape-js/api/classes/DistanceJoint.html): Constrain distance between two anchors to [min, max]
62
- - [WeldJoint](https://newkrok.github.io/nape-js/api/classes/WeldJoint.html): Fix relative position and rotation angle
63
- - [AngleJoint](https://newkrok.github.io/nape-js/api/classes/AngleJoint.html): Constrain relative angle to [min, max] with optional ratio
64
- - [MotorJoint](https://newkrok.github.io/nape-js/api/classes/MotorJoint.html): Drive relative angular velocity to a target rate
65
- - [LineJoint](https://newkrok.github.io/nape-js/api/classes/LineJoint.html): Constrain anchor to slide along a line direction
66
- - [PulleyJoint](https://newkrok.github.io/nape-js/api/classes/PulleyJoint.html): Constrain weighted sum of two distances (pulley/rope)
67
- - [Constraint](https://newkrok.github.io/nape-js/api/classes/Constraint.html): Base class — stiff/soft, frequency, damping, breaking, maxForce
61
+ - [PivotJoint](https://napejs.org/api/classes/PivotJoint.html): Pin two bodies at a shared anchor point
62
+ - [DistanceJoint](https://napejs.org/api/classes/DistanceJoint.html): Constrain distance between two anchors to [min, max]
63
+ - [WeldJoint](https://napejs.org/api/classes/WeldJoint.html): Fix relative position and rotation angle
64
+ - [AngleJoint](https://napejs.org/api/classes/AngleJoint.html): Constrain relative angle to [min, max] with optional ratio
65
+ - [MotorJoint](https://napejs.org/api/classes/MotorJoint.html): Drive relative angular velocity to a target rate
66
+ - [LineJoint](https://napejs.org/api/classes/LineJoint.html): Constrain anchor to slide along a line direction
67
+ - [PulleyJoint](https://napejs.org/api/classes/PulleyJoint.html): Constrain weighted sum of two distances (pulley/rope)
68
+ - [Constraint](https://napejs.org/api/classes/Constraint.html): Base class — stiff/soft, frequency, damping, breaking, maxForce
68
69
 
69
70
  ## Callbacks & Events
70
71
 
71
- - [InteractionListener](https://newkrok.github.io/nape-js/api/classes/InteractionListener.html): Listen for BEGIN/ONGOING/END collision, sensor, or fluid events
72
- - [BodyListener](https://newkrok.github.io/nape-js/api/classes/BodyListener.html): Listen for WAKE/SLEEP body state changes
73
- - [ConstraintListener](https://newkrok.github.io/nape-js/api/classes/ConstraintListener.html): Listen for BREAK constraint events
74
- - [PreListener](https://newkrok.github.io/nape-js/api/classes/PreListener.html): Pre-collision handler — filter or modify collisions before solving
75
- - [CbType](https://newkrok.github.io/nape-js/api/classes/CbType.html): Tag bodies/shapes/constraints for selective callback filtering
76
- - [CbEvent](https://newkrok.github.io/nape-js/api/classes/CbEvent.html): Event types — BEGIN, ONGOING, END, WAKE, SLEEP, BREAK, PRE
72
+ - [InteractionListener](https://napejs.org/api/classes/InteractionListener.html): Listen for BEGIN/ONGOING/END collision, sensor, or fluid events
73
+ - [BodyListener](https://napejs.org/api/classes/BodyListener.html): Listen for WAKE/SLEEP body state changes
74
+ - [ConstraintListener](https://napejs.org/api/classes/ConstraintListener.html): Listen for BREAK constraint events
75
+ - [PreListener](https://napejs.org/api/classes/PreListener.html): Pre-collision handler — filter or modify collisions before solving
76
+ - [CbType](https://napejs.org/api/classes/CbType.html): Tag bodies/shapes/constraints for selective callback filtering
77
+ - [CbEvent](https://napejs.org/api/classes/CbEvent.html): Event types — BEGIN, ONGOING, END, WAKE, SLEEP, BREAK, PRE
77
78
 
78
79
  ## Collision & Dynamics
79
80
 
80
- - [Arbiter](https://newkrok.github.io/nape-js/api/classes/Arbiter.html): Interaction data between two shapes (base class)
81
- - [CollisionArbiter](https://newkrok.github.io/nape-js/api/classes/CollisionArbiter.html): Collision contacts, normal, impulses, kinetic energy
82
- - [FluidArbiter](https://newkrok.github.io/nape-js/api/classes/FluidArbiter.html): Fluid overlap, buoyancy/drag impulses
83
- - [Contact](https://newkrok.github.io/nape-js/api/classes/Contact.html): Single contact point — position, penetration, friction
81
+ - [Arbiter](https://napejs.org/api/classes/Arbiter.html): Interaction data between two shapes (base class)
82
+ - [CollisionArbiter](https://napejs.org/api/classes/CollisionArbiter.html): Collision contacts, normal, impulses, kinetic energy
83
+ - [FluidArbiter](https://napejs.org/api/classes/FluidArbiter.html): Fluid overlap, buoyancy/drag impulses
84
+ - [Contact](https://napejs.org/api/classes/Contact.html): Single contact point — position, penetration, friction
84
85
 
85
86
  ## Geometry Utilities
86
87
 
87
- - [Ray](https://newkrok.github.io/nape-js/api/classes/Ray.html): Ray for raycasting queries with origin, direction, maxDistance
88
- - [Mat23](https://newkrok.github.io/nape-js/api/classes/Mat23.html): 2x3 affine transform matrix — rotation, translation, scale
89
- - [Geom](https://newkrok.github.io/nape-js/api/classes/Geom.html): Static utilities — distance queries, ray tests, polygon operations
90
- - [MarchingSquares](https://newkrok.github.io/nape-js/api/classes/MarchingSquares.html): Contour extraction from scalar fields
88
+ - [Ray](https://napejs.org/api/classes/Ray.html): Ray for raycasting queries with origin, direction, maxDistance
89
+ - [Mat23](https://napejs.org/api/classes/Mat23.html): 2x3 affine transform matrix — rotation, translation, scale
90
+ - [Geom](https://napejs.org/api/classes/Geom.html): Static utilities — distance queries, ray tests, polygon operations
91
+ - [MarchingSquares](https://napejs.org/api/classes/MarchingSquares.html): Contour extraction from scalar fields
91
92
 
92
93
  ## Destruction / Fracture
93
94
 
94
- - [fractureBody](https://newkrok.github.io/nape-js/api/functions/fractureBody.html): Shatter a polygon body into Voronoi fragments — `fractureBody(body, impactPoint, { fragmentCount?, explosionImpulse?, random? })`
95
- - [computeVoronoi](https://newkrok.github.io/nape-js/api/functions/computeVoronoi.html): Raw Voronoi diagram computation from point set
96
- - [generateFractureSites](https://newkrok.github.io/nape-js/api/functions/generateFractureSites.html): Generate random fracture site points within a polygon
95
+ - [fractureBody](https://napejs.org/api/functions/fractureBody.html): Shatter a polygon body into Voronoi fragments — `fractureBody(body, impactPoint, { fragmentCount?, explosionImpulse?, random? })`
96
+ - [computeVoronoi](https://napejs.org/api/functions/computeVoronoi.html): Raw Voronoi diagram computation from point set
97
+ - [generateFractureSites](https://napejs.org/api/functions/generateFractureSites.html): Generate random fracture site points within a polygon
97
98
 
98
99
  ## Helpers
99
100
 
100
101
  Higher-level building blocks layered on top of the engine — opt-in modules.
101
102
 
102
- - [CharacterController](https://newkrok.github.io/nape-js/api/classes/CharacterController.html): Velocity-based 2D platformer controller with ground/slope/wall raycasts, coyote-time, one-way platforms, moving-platform inheritance, and an overridable `down` direction (radial-gravity worlds)
103
- - [RadialGravityField](https://newkrok.github.io/nape-js/api/classes/RadialGravityField.html) / [RadialGravityFieldGroup](https://newkrok.github.io/nape-js/api/classes/RadialGravityFieldGroup.html): Point-source gravity field with `inverse-square` / `inverse` / `constant` / custom falloff, `maxRadius` / `softening` / `minRadius`, body filter, mass scaling — replaces hand-rolled `body.force = ...` loops for orbital, planet, and multi-body scenarios
104
- - [ParticleEmitter](https://newkrok.github.io/nape-js/api/classes/ParticleEmitter.html) / [ParticleEmitterGroup](https://newkrok.github.io/nape-js/api/classes/ParticleEmitterGroup.html): Physics-aware particle emitter — pooled `Body` swarm with continuous (`rate`) / periodic (`burstCount` + `burstInterval`) / manual (`emit(n)`) spawning, configurable spawn (`point` / `rect` / `circle` / `arc` / custom) and velocity (`fixed` / `cone` / `radial` / custom) patterns, deterministic RNG, world-space `bounds`, `selfCollision` toggle, lifecycle hooks (`onSpawn` / `onUpdate` / `onDeath` / `onCollide` with `requestKill`)
103
+ - [CharacterController](https://napejs.org/api/classes/CharacterController.html): Velocity-based 2D platformer controller with ground/slope/wall raycasts, coyote-time, one-way platforms, moving-platform inheritance, and an overridable `down` direction (radial-gravity worlds)
104
+ - [RadialGravityField](https://napejs.org/api/classes/RadialGravityField.html) / [RadialGravityFieldGroup](https://napejs.org/api/classes/RadialGravityFieldGroup.html): Point-source gravity field with `inverse-square` / `inverse` / `constant` / custom falloff, `maxRadius` / `softening` / `minRadius`, body filter, mass scaling — replaces hand-rolled `body.force = ...` loops for orbital, planet, and multi-body scenarios
105
+ - [ParticleEmitter](https://napejs.org/api/classes/ParticleEmitter.html) / [ParticleEmitterGroup](https://napejs.org/api/classes/ParticleEmitterGroup.html): Physics-aware particle emitter — pooled `Body` swarm with continuous (`rate`) / periodic (`burstCount` + `burstInterval`) / manual (`emit(n)`) spawning, configurable spawn (`point` / `rect` / `circle` / `arc` / custom) and velocity (`fixed` / `cone` / `radial` / custom) patterns, deterministic RNG, world-space `bounds`, `selfCollision` toggle, lifecycle hooks (`onSpawn` / `onUpdate` / `onDeath` / `onCollide` with `requestKill`)
105
106
  - `buildTilemapBody` / `meshTilemap` / `tiledLayerToGrid` / `ldtkLayerToGrid`: Greedy-meshed collision body from a 2D tile grid (5–50× fewer shapes vs one-polygon-per-cell), with built-in parsers for Tiled JSON tile layers and LDtk IntGrid layers
106
- - [TriggerZone](https://newkrok.github.io/nape-js/api/classes/TriggerZone.html): Sensor zone with `onEnter` / `onExit` callbacks — wraps the BEGIN/END `InteractionListener` plumbing
107
- - [createConcaveBody](https://newkrok.github.io/nape-js/api/functions/createConcaveBody.html): Decomposes a concave outline into convex polygons and packs them into a single body
107
+ - [TriggerZone](https://napejs.org/api/classes/TriggerZone.html): Sensor zone with `onEnter` / `onExit` callbacks — wraps the BEGIN/END `InteractionListener` plumbing
108
+ - [createConcaveBody](https://napejs.org/api/functions/createConcaveBody.html): Decomposes a concave outline into convex polygons and packs them into a single body
108
109
 
109
110
  ## Enums
110
111
 
111
- - [BodyType](https://newkrok.github.io/nape-js/api/classes/BodyType.html): STATIC, DYNAMIC, KINEMATIC
112
- - [ShapeType](https://newkrok.github.io/nape-js/api/classes/ShapeType.html): CIRCLE, POLYGON
113
- - [Broadphase](https://newkrok.github.io/nape-js/api/classes/Broadphase.html): DYNAMIC_AABB_TREE (default), SWEEP_AND_PRUNE, SPATIAL_HASH
114
- - [InteractionType](https://newkrok.github.io/nape-js/api/classes/InteractionType.html): COLLISION, SENSOR, FLUID, ANY
115
- - [ArbiterType](https://newkrok.github.io/nape-js/api/classes/ArbiterType.html): COLLISION, SENSOR, FLUID
112
+ - [BodyType](https://napejs.org/api/classes/BodyType.html): STATIC, DYNAMIC, KINEMATIC
113
+ - [ShapeType](https://napejs.org/api/classes/ShapeType.html): CIRCLE, POLYGON
114
+ - [Broadphase](https://napejs.org/api/classes/Broadphase.html): DYNAMIC_AABB_TREE (default), SWEEP_AND_PRUNE, SPATIAL_HASH
115
+ - [InteractionType](https://napejs.org/api/classes/InteractionType.html): COLLISION, SENSOR, FLUID, ANY
116
+ - [ArbiterType](https://napejs.org/api/classes/ArbiterType.html): COLLISION, SENSOR, FLUID
116
117
 
117
118
  ## Grouping & Hierarchy
118
119
 
119
- - [Compound](https://newkrok.github.io/nape-js/api/classes/Compound.html): Hierarchical grouping of bodies, constraints, and sub-compounds
120
- - [Interactor](https://newkrok.github.io/nape-js/api/classes/Interactor.html): Base class for Body, Shape, Compound — type casting, cbTypes
120
+ - [Compound](https://napejs.org/api/classes/Compound.html): Hierarchical grouping of bodies, constraints, and sub-compounds
121
+ - [Interactor](https://napejs.org/api/classes/Interactor.html): Base class for Body, Shape, Compound — type casting, cbTypes
121
122
 
122
123
  ## Collections
123
124
 
124
- - [NapeList](https://newkrok.github.io/nape-js/api/classes/NapeList.html): Generic iterable list with `for...of` support, add/remove/push/pop
125
+ - [NapeList](https://napejs.org/api/classes/NapeList.html): Generic iterable list with `for...of` support, add/remove/push/pop
125
126
 
126
127
  ## Web Worker (`@newkrok/nape-js/worker`)
127
128
 
@@ -129,3 +130,14 @@ Higher-level building blocks layered on top of the engine — opt-in modules.
129
130
  - `buildWorkerScript(napeUrl)`: Generate self-contained worker script for inline Blob or hosted file
130
131
  - `BodyTransform`: `{ x, y, rotation }` per-body transform read from shared buffer
131
132
  - `FLOATS_PER_BODY`, `HEADER_FLOATS`: Buffer layout constants
133
+
134
+ ## Replay (`@newkrok/nape-js/replay`)
135
+
136
+ Record a deterministic simulation and play it back. Built on `/serialization` + `space.deterministic = true`. Tree-shakeable; only loads when imported.
137
+
138
+ - [Recorder](https://napejs.org/api/classes/Recorder.html)`<T>`: Captures the initial snapshot at construction, then `recordFrame(input)` logs an input payload per frame. Optional `keyframeEvery` (default 60) records intermediate snapshots for fast scrub. `finish()` returns an immutable `Replay<T>`.
139
+ - [Player](https://napejs.org/api/classes/Player.html)`<T>`: Owns its own deserialised `Space`. `restore()` rewinds to frame 0; `step()` applies the next recorded input (via the user's `applyInput` callback) and steps physics; `stepTo(frame)` does random-access scrub (uses keyframes for backward jumps).
140
+ - [encodeReplay](https://napejs.org/api/functions/encodeReplay.html) / [decodeReplay](https://napejs.org/api/functions/decodeReplay.html): Compact binary format (magic `RPLY`, versioned, length-prefixed snapshots, UTF-8 JSON payloads). Round-trips byte-for-byte.
141
+ - [validateDeterministicConfig](https://napejs.org/api/functions/validateDeterministicConfig.html): Sanity-checks `space.deterministic = true` etc.; returns `{ ok, warnings }`.
142
+
143
+ **Determinism contract** — replay matches recording when (a) `space.deterministic = true`, (b) fixed `dt` and matching iteration counts on both sides, (c) the user's `applyInput` is a pure function of `(input, space, frame)`. Same-platform soft determinism only (floating-point rounding differs across CPUs).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newkrok/nape-js",
3
- "version": "3.32.0",
3
+ "version": "3.33.0",
4
4
  "description": "High-performance 2D physics engine for TypeScript & JavaScript — rigid bodies, constraints, fluid simulation, raycasting, and deterministic multiplayer. Tree-shakeable, zero dependencies.",
5
5
  "type": "module",
6
6
  "sideEffects": [
@@ -49,6 +49,16 @@
49
49
  "default": "./dist/serialization/index.cjs"
50
50
  }
51
51
  },
52
+ "./replay": {
53
+ "import": {
54
+ "types": "./dist/replay/index.d.ts",
55
+ "default": "./dist/replay/index.js"
56
+ },
57
+ "require": {
58
+ "types": "./dist/replay/index.d.cts",
59
+ "default": "./dist/replay/index.cjs"
60
+ }
61
+ },
52
62
  "./worker": {
53
63
  "import": {
54
64
  "types": "./dist/worker/index.d.ts",
@@ -70,8 +80,8 @@
70
80
  }
71
81
  }
72
82
  },
73
- "llms": "https://newkrok.github.io/nape-js/llms.txt",
74
- "llmsFull": "https://newkrok.github.io/nape-js/llms-full.txt",
83
+ "llms": "https://napejs.org/llms.txt",
84
+ "llmsFull": "https://napejs.org/llms-full.txt",
75
85
  "files": [
76
86
  "dist",
77
87
  "!dist/**/*.map",
@@ -119,5 +129,5 @@
119
129
  "bugs": {
120
130
  "url": "https://github.com/NewKrok/nape-js/issues"
121
131
  },
122
- "homepage": "https://newkrok.github.io/nape-js/"
132
+ "homepage": "https://napejs.org/"
123
133
  }