@newkrok/nape-js 3.31.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.
- package/dist/chunk-263GQ5UK.js +2 -0
- package/dist/chunk-CA2F5ISB.cjs +2 -0
- package/dist/chunk-GPGT7DYQ.js +2 -0
- package/dist/chunk-HQH77APJ.cjs +2 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +352 -1
- package/dist/index.d.ts +352 -1
- package/dist/index.js +1 -1
- package/dist/replay/index.cjs +2 -0
- package/dist/replay/index.d.cts +266 -0
- package/dist/replay/index.d.ts +266 -0
- package/dist/replay/index.js +2 -0
- package/dist/serialization/index.cjs +1 -1
- package/dist/serialization/index.js +1 -1
- package/llms-full.txt +225 -3
- package/llms.txt +65 -52
- package/package.json +14 -4
- package/dist/chunk-OFVSWS4I.cjs +0 -2
- package/dist/chunk-ZNBQE3PX.js +0 -2
|
@@ -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-ZNBQE3PX.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://
|
|
8
|
-
- **Demos**: https://
|
|
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
|
|
@@ -1424,8 +1424,9 @@ interactionType(shape1: Shape, shape2: Shape): InteractionType | null
|
|
|
1424
1424
|
|
|
1425
1425
|
| Value | Description |
|
|
1426
1426
|
|-------|-------------|
|
|
1427
|
+
| `Broadphase.DYNAMIC_AABB_TREE` | Default. Good for dynamic scenes with varied object sizes |
|
|
1427
1428
|
| `Broadphase.SWEEP_AND_PRUNE` | Good for many objects with little movement |
|
|
1428
|
-
| `Broadphase.
|
|
1429
|
+
| `Broadphase.SPATIAL_HASH` | Best for dense, uniform-size scenes |
|
|
1429
1430
|
|
|
1430
1431
|
---
|
|
1431
1432
|
|
|
@@ -1653,6 +1654,97 @@ const grid2 = ldtkLayerToGrid(ldtkJson.levels[0].layerInstances[0]); // LDtk Int
|
|
|
1653
1654
|
- `tiledLayerToGrid` / `ldtkLayerToGrid` only consume the data + dimension fields — they don't depend on the full Tiled/LDtk JSON shape, so you can pass a hand-shaped subset.
|
|
1654
1655
|
- For destructible terrain, rebuild the body when the grid changes (`body.shapes.clear()` then call `buildTilemapBody(grid, { ..., body })`).
|
|
1655
1656
|
|
|
1657
|
+
### ParticleEmitter
|
|
1658
|
+
|
|
1659
|
+
Physics-aware particle emitter — a pooled, lifecycle-managed swarm of dynamic bodies. Each particle is a real `Body` with a `Circle` or `Polygon` shape, so it collides with the world, reacts to forces / gravity / fluids, and triggers callbacks like any other body. Body pool is reused across spawns — zero allocation in the steady state.
|
|
1660
|
+
|
|
1661
|
+
```typescript
|
|
1662
|
+
import { ParticleEmitter, ParticleEmitterGroup, Body, Vec2 } from "@newkrok/nape-js";
|
|
1663
|
+
|
|
1664
|
+
// Volcano: continuous lava cone.
|
|
1665
|
+
const volcano = new ParticleEmitter({
|
|
1666
|
+
space,
|
|
1667
|
+
origin: new Vec2(400, 100), // Vec2 OR Body (auto-tracking)
|
|
1668
|
+
spawn: { kind: "arc", radius: 6, angleStart: -Math.PI, angleEnd: 0 },
|
|
1669
|
+
velocity: {
|
|
1670
|
+
kind: "cone", // "fixed" | "cone" | "radial" | custom
|
|
1671
|
+
direction: -Math.PI / 2,
|
|
1672
|
+
spread: Math.PI / 5,
|
|
1673
|
+
speedMin: 320,
|
|
1674
|
+
speedMax: 520,
|
|
1675
|
+
},
|
|
1676
|
+
rate: 90, // particles/sec — fractional rates work
|
|
1677
|
+
maxParticles: 600,
|
|
1678
|
+
lifetimeMin: 4,
|
|
1679
|
+
lifetimeMax: 7,
|
|
1680
|
+
particleRadius: 2.5,
|
|
1681
|
+
selfCollision: false, // particles don't collide with each other
|
|
1682
|
+
});
|
|
1683
|
+
|
|
1684
|
+
// Each frame, BEFORE space.step():
|
|
1685
|
+
volcano.update(1 / 60);
|
|
1686
|
+
space.step(1 / 60);
|
|
1687
|
+
|
|
1688
|
+
// Manual burst:
|
|
1689
|
+
volcano.emit(40); // returns Body[]
|
|
1690
|
+
|
|
1691
|
+
// Periodic burst (5 particles every 0.5s):
|
|
1692
|
+
const fireworks = new ParticleEmitter({
|
|
1693
|
+
space, origin: pad,
|
|
1694
|
+
velocity: { kind: "radial", speedMin: 200, speedMax: 480 },
|
|
1695
|
+
burstCount: 30,
|
|
1696
|
+
burstInterval: 0.5,
|
|
1697
|
+
});
|
|
1698
|
+
|
|
1699
|
+
// Bullet emitter with collision callback (for shooter / damage logic):
|
|
1700
|
+
const bulletCb = new CbType();
|
|
1701
|
+
const bullets = new ParticleEmitter({
|
|
1702
|
+
space,
|
|
1703
|
+
origin: playerBody,
|
|
1704
|
+
velocity: { kind: "fixed", value: new Vec2(700, 0) }, // mutated per-shot
|
|
1705
|
+
particleRadius: 2,
|
|
1706
|
+
particleCbType: bulletCb,
|
|
1707
|
+
onCollide: (bullet, other) => {
|
|
1708
|
+
// Damage `other`, then defer the bullet's death (we're inside a
|
|
1709
|
+
// collision callback — never mutate the space synchronously).
|
|
1710
|
+
bullets.requestKill(bullet);
|
|
1711
|
+
},
|
|
1712
|
+
});
|
|
1713
|
+
|
|
1714
|
+
// Compose multiple emitters:
|
|
1715
|
+
const group = new ParticleEmitterGroup();
|
|
1716
|
+
group.add(volcano);
|
|
1717
|
+
group.add(fireworks);
|
|
1718
|
+
group.update(1 / 60); // runs every member
|
|
1719
|
+
```
|
|
1720
|
+
|
|
1721
|
+
**Spawn patterns** (positions are sampled in emitter-local space, then translated by `origin`):
|
|
1722
|
+
- `{ kind: "point" }` — always at origin
|
|
1723
|
+
- `{ kind: "rect", width, height }` — uniform inside an axis-aligned box
|
|
1724
|
+
- `{ kind: "circle", radius, hollow? }` — uniform inside a disk; `hollow: true` samples the rim only
|
|
1725
|
+
- `{ kind: "arc", radius, angleStart, angleEnd }` — points on a circular arc
|
|
1726
|
+
- `{ kind: "custom", sample: (rng) => Vec2 }` — user-supplied sampler
|
|
1727
|
+
|
|
1728
|
+
**Velocity patterns:**
|
|
1729
|
+
- `{ kind: "fixed", value }` — every particle gets the same vector (mutate `value` for aimed shooting)
|
|
1730
|
+
- `{ kind: "cone", direction, spread, speedMin, speedMax }` — uniformly random direction inside a cone of half-width `spread` rad
|
|
1731
|
+
- `{ kind: "radial", speedMin, speedMax }` — outward from the spawn point relative to `origin`
|
|
1732
|
+
- `{ kind: "custom", sample: (rng, localPos) => Vec2 }` — user-supplied sampler
|
|
1733
|
+
|
|
1734
|
+
**Lifecycle hooks:**
|
|
1735
|
+
- `onSpawn(state, body)` — fired after the body is in the space
|
|
1736
|
+
- `onUpdate(body, age, dt)` — every `update()` for each live particle
|
|
1737
|
+
- `onDeath(body, reason)` — `reason` is `"lifetime" | "manual" | "bounds"`
|
|
1738
|
+
- `onCollide(body, other)` — requires `particleCbType`. Use `requestKill(body)` to defer death until the next `update()`
|
|
1739
|
+
|
|
1740
|
+
**Gotchas:**
|
|
1741
|
+
- Call `update(dt)` **before** `space.step(dt)`, with the same `dt`. The pattern matches `RadialGravityField.apply()`.
|
|
1742
|
+
- `space.gravity` and `body.force` still apply — particles are normal dynamic bodies. Clear `body.force` per-frame if you stack a custom field on top.
|
|
1743
|
+
- `overflowPolicy: "drop-oldest"` (default) kills the oldest live particle to make room for a new spawn — bullets always come out. Set to `"drop-new"` to protect already-visible particles instead.
|
|
1744
|
+
- `selfCollision: false` (default) generates a self-excluding `InteractionFilter` so particles don't waste cycles colliding with each other. Override by passing your own `particleFilter`.
|
|
1745
|
+
- `requestKill(body)` is the only safe way to kill a particle from inside a collision callback. Direct `body.space = null` mid-step is undefined behaviour.
|
|
1746
|
+
- `destroy()` removes every body (live + pooled) from the space and unregisters the collision listener; subsequent `update()` / `emit()` calls throw.
|
|
1747
|
+
|
|
1656
1748
|
### TriggerZone
|
|
1657
1749
|
|
|
1658
1750
|
Sensor-based zone with `onEnter` / `onExit` callbacks — wraps the BEGIN/END `InteractionListener` plumbing so you don't have to wire it up by hand.
|
|
@@ -1981,3 +2073,133 @@ function render() {
|
|
|
1981
2073
|
}
|
|
1982
2074
|
render();
|
|
1983
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://
|
|
10
|
-
- [Interactive Demos](https://
|
|
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,91 +37,92 @@ function update() {
|
|
|
36
37
|
|
|
37
38
|
## Core Classes
|
|
38
39
|
|
|
39
|
-
- [Space](https://
|
|
40
|
-
- [Body](https://
|
|
41
|
-
- [Vec2](https://
|
|
42
|
-
- [AABB](https://
|
|
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://
|
|
47
|
-
- [Polygon](https://
|
|
48
|
-
- [Shape](https://
|
|
49
|
-
- [Edge](https://
|
|
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://
|
|
54
|
-
- [FluidProperties](https://
|
|
55
|
-
- [InteractionFilter](https://
|
|
56
|
-
- [InteractionGroup](https://
|
|
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://
|
|
61
|
-
- [DistanceJoint](https://
|
|
62
|
-
- [WeldJoint](https://
|
|
63
|
-
- [AngleJoint](https://
|
|
64
|
-
- [MotorJoint](https://
|
|
65
|
-
- [LineJoint](https://
|
|
66
|
-
- [PulleyJoint](https://
|
|
67
|
-
- [Constraint](https://
|
|
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://
|
|
72
|
-
- [BodyListener](https://
|
|
73
|
-
- [ConstraintListener](https://
|
|
74
|
-
- [PreListener](https://
|
|
75
|
-
- [CbType](https://
|
|
76
|
-
- [CbEvent](https://
|
|
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://
|
|
81
|
-
- [CollisionArbiter](https://
|
|
82
|
-
- [FluidArbiter](https://
|
|
83
|
-
- [Contact](https://
|
|
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://
|
|
88
|
-
- [Mat23](https://
|
|
89
|
-
- [Geom](https://
|
|
90
|
-
- [MarchingSquares](https://
|
|
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://
|
|
95
|
-
- [computeVoronoi](https://
|
|
96
|
-
- [generateFractureSites](https://
|
|
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://
|
|
103
|
-
- [RadialGravityField](https://
|
|
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`)
|
|
104
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
|
|
105
|
-
- [TriggerZone](https://
|
|
106
|
-
- [createConcaveBody](https://
|
|
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
|
|
107
109
|
|
|
108
110
|
## Enums
|
|
109
111
|
|
|
110
|
-
- [BodyType](https://
|
|
111
|
-
- [ShapeType](https://
|
|
112
|
-
- [Broadphase](https://
|
|
113
|
-
- [InteractionType](https://
|
|
114
|
-
- [ArbiterType](https://
|
|
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
|
|
115
117
|
|
|
116
118
|
## Grouping & Hierarchy
|
|
117
119
|
|
|
118
|
-
- [Compound](https://
|
|
119
|
-
- [Interactor](https://
|
|
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
|
|
120
122
|
|
|
121
123
|
## Collections
|
|
122
124
|
|
|
123
|
-
- [NapeList](https://
|
|
125
|
+
- [NapeList](https://napejs.org/api/classes/NapeList.html): Generic iterable list with `for...of` support, add/remove/push/pop
|
|
124
126
|
|
|
125
127
|
## Web Worker (`@newkrok/nape-js/worker`)
|
|
126
128
|
|
|
@@ -128,3 +130,14 @@ Higher-level building blocks layered on top of the engine — opt-in modules.
|
|
|
128
130
|
- `buildWorkerScript(napeUrl)`: Generate self-contained worker script for inline Blob or hosted file
|
|
129
131
|
- `BodyTransform`: `{ x, y, rotation }` per-body transform read from shared buffer
|
|
130
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.
|
|
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://
|
|
74
|
-
"llmsFull": "https://
|
|
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://
|
|
132
|
+
"homepage": "https://napejs.org/"
|
|
123
133
|
}
|