@codexo/exojs-physics 0.15.3 → 0.16.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.
Files changed (201) hide show
  1. package/README.md +51 -23
  2. package/dist/esm/Aabb.d.ts +6 -10
  3. package/dist/esm/Aabb.d.ts.map +1 -0
  4. package/dist/esm/Aabb.js +9 -5
  5. package/dist/esm/Aabb.js.map +1 -1
  6. package/dist/esm/Collider.d.ts +62 -10
  7. package/dist/esm/Collider.d.ts.map +1 -0
  8. package/dist/esm/Collider.js +263 -157
  9. package/dist/esm/Collider.js.map +1 -1
  10. package/dist/esm/ContactGraph.d.ts +51 -5
  11. package/dist/esm/ContactGraph.d.ts.map +1 -0
  12. package/dist/esm/ContactGraph.js +282 -223
  13. package/dist/esm/ContactGraph.js.map +1 -1
  14. package/dist/esm/ContactModifier.d.ts +85 -0
  15. package/dist/esm/ContactModifier.d.ts.map +1 -0
  16. package/dist/esm/ContactModifier.js +49 -0
  17. package/dist/esm/ContactModifier.js.map +1 -0
  18. package/dist/esm/PhysicsBody.d.ts +56 -22
  19. package/dist/esm/PhysicsBody.d.ts.map +1 -0
  20. package/dist/esm/PhysicsBody.js +461 -443
  21. package/dist/esm/PhysicsBody.js.map +1 -1
  22. package/dist/esm/PhysicsWorld.d.ts +276 -43
  23. package/dist/esm/PhysicsWorld.d.ts.map +1 -0
  24. package/dist/esm/PhysicsWorld.js +890 -626
  25. package/dist/esm/PhysicsWorld.js.map +1 -1
  26. package/dist/esm/TimeStepper.d.ts +3 -2
  27. package/dist/esm/TimeStepper.d.ts.map +1 -0
  28. package/dist/esm/TimeStepper.js +56 -67
  29. package/dist/esm/TimeStepper.js.map +1 -1
  30. package/dist/esm/backend/NativePhysicsBackend.d.ts +8 -4
  31. package/dist/esm/backend/NativePhysicsBackend.d.ts.map +1 -0
  32. package/dist/esm/backend/NativePhysicsBackend.js +48 -41
  33. package/dist/esm/backend/NativePhysicsBackend.js.map +1 -1
  34. package/dist/esm/backend/PhysicsBackend.d.ts +9 -2
  35. package/dist/esm/backend/PhysicsBackend.d.ts.map +1 -0
  36. package/dist/esm/binding/BindingRegistry.d.ts +25 -4
  37. package/dist/esm/binding/BindingRegistry.d.ts.map +1 -0
  38. package/dist/esm/binding/BindingRegistry.js +70 -36
  39. package/dist/esm/binding/BindingRegistry.js.map +1 -1
  40. package/dist/esm/binding/PhysicsBinding.d.ts +22 -5
  41. package/dist/esm/binding/PhysicsBinding.d.ts.map +1 -0
  42. package/dist/esm/binding/PhysicsBinding.js +46 -21
  43. package/dist/esm/binding/PhysicsBinding.js.map +1 -1
  44. package/dist/esm/broadphase/AabbTreeBroadPhase.d.ts +68 -0
  45. package/dist/esm/broadphase/AabbTreeBroadPhase.d.ts.map +1 -0
  46. package/dist/esm/broadphase/AabbTreeBroadPhase.js +149 -0
  47. package/dist/esm/broadphase/AabbTreeBroadPhase.js.map +1 -0
  48. package/dist/esm/broadphase/BroadPhase.d.ts +7 -4
  49. package/dist/esm/broadphase/BroadPhase.d.ts.map +1 -0
  50. package/dist/esm/broadphase/index.d.ts +2 -1
  51. package/dist/esm/broadphase/index.d.ts.map +1 -0
  52. package/dist/esm/collision/CollisionProxy.d.ts +3 -2
  53. package/dist/esm/collision/CollisionProxy.d.ts.map +1 -0
  54. package/dist/esm/collision/Manifold.d.ts +5 -4
  55. package/dist/esm/collision/Manifold.d.ts.map +1 -0
  56. package/dist/esm/collision/Manifold.js +34 -25
  57. package/dist/esm/collision/Manifold.js.map +1 -1
  58. package/dist/esm/collision/chainAdjacency.d.ts +29 -0
  59. package/dist/esm/collision/chainAdjacency.d.ts.map +1 -0
  60. package/dist/esm/collision/chainAdjacency.js +44 -0
  61. package/dist/esm/collision/chainAdjacency.js.map +1 -0
  62. package/dist/esm/collision/dispatch.d.ts +35 -0
  63. package/dist/esm/collision/dispatch.d.ts.map +1 -0
  64. package/dist/esm/collision/dispatch.js +58 -0
  65. package/dist/esm/collision/dispatch.js.map +1 -0
  66. package/dist/esm/collision/index.d.ts +2 -0
  67. package/dist/esm/collision/index.d.ts.map +1 -0
  68. package/dist/esm/collision/narrowphase.d.ts +5 -2
  69. package/dist/esm/collision/narrowphase.d.ts.map +1 -0
  70. package/dist/esm/collision/narrowphase.js +524 -399
  71. package/dist/esm/collision/narrowphase.js.map +1 -1
  72. package/dist/esm/collision/segments.d.ts +19 -0
  73. package/dist/esm/collision/segments.d.ts.map +1 -0
  74. package/dist/esm/collision/segments.js +36 -0
  75. package/dist/esm/collision/segments.js.map +1 -0
  76. package/dist/esm/collision/sweep.d.ts +35 -0
  77. package/dist/esm/collision/sweep.d.ts.map +1 -0
  78. package/dist/esm/collision/sweep.js +437 -0
  79. package/dist/esm/collision/sweep.js.map +1 -0
  80. package/dist/esm/debug/PhysicsDebugDraw.d.ts +23 -4
  81. package/dist/esm/debug/PhysicsDebugDraw.d.ts.map +1 -0
  82. package/dist/esm/debug/PhysicsDebugDraw.js +230 -188
  83. package/dist/esm/debug/PhysicsDebugDraw.js.map +1 -1
  84. package/dist/esm/debug/index.d.ts +1 -0
  85. package/dist/esm/debug/index.d.ts.map +1 -0
  86. package/dist/esm/debug/index.js +3 -2
  87. package/dist/esm/events.d.ts +1 -0
  88. package/dist/esm/events.d.ts.map +1 -0
  89. package/dist/esm/index.d.ts +1 -0
  90. package/dist/esm/index.d.ts.map +1 -0
  91. package/dist/esm/index.js +24 -19
  92. package/dist/esm/joints/DistanceJoint.d.ts +4 -3
  93. package/dist/esm/joints/DistanceJoint.d.ts.map +1 -0
  94. package/dist/esm/joints/DistanceJoint.js +160 -172
  95. package/dist/esm/joints/DistanceJoint.js.map +1 -1
  96. package/dist/esm/joints/Joint.d.ts +5 -4
  97. package/dist/esm/joints/Joint.d.ts.map +1 -0
  98. package/dist/esm/joints/Joint.js +23 -21
  99. package/dist/esm/joints/Joint.js.map +1 -1
  100. package/dist/esm/joints/MouseJoint.d.ts +8 -7
  101. package/dist/esm/joints/MouseJoint.d.ts.map +1 -0
  102. package/dist/esm/joints/MouseJoint.js +132 -133
  103. package/dist/esm/joints/MouseJoint.js.map +1 -1
  104. package/dist/esm/joints/PrismaticJoint.d.ts +5 -4
  105. package/dist/esm/joints/PrismaticJoint.d.ts.map +1 -0
  106. package/dist/esm/joints/PrismaticJoint.js +211 -240
  107. package/dist/esm/joints/PrismaticJoint.js.map +1 -1
  108. package/dist/esm/joints/RevoluteJoint.d.ts +4 -3
  109. package/dist/esm/joints/RevoluteJoint.d.ts.map +1 -0
  110. package/dist/esm/joints/RevoluteJoint.js +191 -213
  111. package/dist/esm/joints/RevoluteJoint.js.map +1 -1
  112. package/dist/esm/joints/WeldJoint.d.ts +3 -2
  113. package/dist/esm/joints/WeldJoint.d.ts.map +1 -0
  114. package/dist/esm/joints/WeldJoint.js +156 -152
  115. package/dist/esm/joints/WeldJoint.js.map +1 -1
  116. package/dist/esm/joints/WheelJoint.d.ts +4 -3
  117. package/dist/esm/joints/WheelJoint.d.ts.map +1 -0
  118. package/dist/esm/joints/WheelJoint.js +228 -255
  119. package/dist/esm/joints/WheelJoint.js.map +1 -1
  120. package/dist/esm/math.d.ts +6 -9
  121. package/dist/esm/math.d.ts.map +1 -0
  122. package/dist/esm/math.js +37 -39
  123. package/dist/esm/math.js.map +1 -1
  124. package/dist/esm/physicsBuildInfo.d.ts +1 -0
  125. package/dist/esm/physicsBuildInfo.d.ts.map +1 -0
  126. package/dist/esm/physicsBuildInfo.js +6 -4
  127. package/dist/esm/physicsBuildInfo.js.map +1 -1
  128. package/dist/esm/public.d.ts +8 -3
  129. package/dist/esm/public.d.ts.map +1 -0
  130. package/dist/esm/query/QueryEngine.d.ts +56 -12
  131. package/dist/esm/query/QueryEngine.d.ts.map +1 -0
  132. package/dist/esm/query/QueryEngine.js +494 -237
  133. package/dist/esm/query/QueryEngine.js.map +1 -1
  134. package/dist/esm/query/SpatialIndex.d.ts +34 -0
  135. package/dist/esm/query/SpatialIndex.d.ts.map +1 -0
  136. package/dist/esm/shapes/AnyShape.d.ts +9 -4
  137. package/dist/esm/shapes/AnyShape.d.ts.map +1 -0
  138. package/dist/esm/shapes/BoxShape.d.ts +2 -1
  139. package/dist/esm/shapes/BoxShape.d.ts.map +1 -0
  140. package/dist/esm/shapes/BoxShape.js +37 -25
  141. package/dist/esm/shapes/BoxShape.js.map +1 -1
  142. package/dist/esm/shapes/CapsuleShape.d.ts +30 -0
  143. package/dist/esm/shapes/CapsuleShape.d.ts.map +1 -0
  144. package/dist/esm/shapes/CapsuleShape.js +88 -0
  145. package/dist/esm/shapes/CapsuleShape.js.map +1 -0
  146. package/dist/esm/shapes/ChainEdgeShape.d.ts +30 -0
  147. package/dist/esm/shapes/ChainEdgeShape.d.ts.map +1 -0
  148. package/dist/esm/shapes/ChainEdgeShape.js +66 -0
  149. package/dist/esm/shapes/ChainEdgeShape.js.map +1 -0
  150. package/dist/esm/shapes/ChainShape.d.ts +52 -0
  151. package/dist/esm/shapes/ChainShape.d.ts.map +1 -0
  152. package/dist/esm/shapes/ChainShape.js +85 -0
  153. package/dist/esm/shapes/ChainShape.js.map +1 -0
  154. package/dist/esm/shapes/CircleShape.d.ts +3 -4
  155. package/dist/esm/shapes/CircleShape.d.ts.map +1 -0
  156. package/dist/esm/shapes/CircleShape.js +27 -26
  157. package/dist/esm/shapes/CircleShape.js.map +1 -1
  158. package/dist/esm/shapes/PolygonShape.d.ts +7 -8
  159. package/dist/esm/shapes/PolygonShape.d.ts.map +1 -0
  160. package/dist/esm/shapes/PolygonShape.js +131 -162
  161. package/dist/esm/shapes/PolygonShape.js.map +1 -1
  162. package/dist/esm/shapes/SegmentShape.d.ts +31 -0
  163. package/dist/esm/shapes/SegmentShape.d.ts.map +1 -0
  164. package/dist/esm/shapes/SegmentShape.js +62 -0
  165. package/dist/esm/shapes/SegmentShape.js.map +1 -0
  166. package/dist/esm/shapes/Shape.d.ts +28 -17
  167. package/dist/esm/shapes/Shape.d.ts.map +1 -0
  168. package/dist/esm/shapes/Shape.js +12 -13
  169. package/dist/esm/shapes/Shape.js.map +1 -1
  170. package/dist/esm/shapes/convexParts.d.ts +21 -0
  171. package/dist/esm/shapes/convexParts.d.ts.map +1 -0
  172. package/dist/esm/shapes/convexParts.js +26 -0
  173. package/dist/esm/shapes/convexParts.js.map +1 -0
  174. package/dist/esm/shapes/decompose.d.ts +24 -0
  175. package/dist/esm/shapes/decompose.d.ts.map +1 -0
  176. package/dist/esm/shapes/decompose.js +272 -0
  177. package/dist/esm/shapes/decompose.js.map +1 -0
  178. package/dist/esm/shapes/index.d.ts +4 -0
  179. package/dist/esm/shapes/index.d.ts.map +1 -0
  180. package/dist/esm/solver/ContactSolver.d.ts +12 -5
  181. package/dist/esm/solver/ContactSolver.d.ts.map +1 -0
  182. package/dist/esm/solver/ContactSolver.js +425 -471
  183. package/dist/esm/solver/ContactSolver.js.map +1 -1
  184. package/dist/esm/solver/tolerances.d.ts +34 -0
  185. package/dist/esm/solver/tolerances.d.ts.map +1 -0
  186. package/dist/esm/solver/tolerances.js +38 -0
  187. package/dist/esm/solver/tolerances.js.map +1 -0
  188. package/dist/esm/sort.d.ts +5 -4
  189. package/dist/esm/sort.d.ts.map +1 -0
  190. package/dist/esm/sort.js +41 -51
  191. package/dist/esm/sort.js.map +1 -1
  192. package/dist/esm/types.d.ts +4 -8
  193. package/dist/esm/types.d.ts.map +1 -0
  194. package/dist/esm/types.js +15 -17
  195. package/dist/esm/types.js.map +1 -1
  196. package/package.json +6 -6
  197. package/dist/esm/broadphase/SweepAndPrune.d.ts +0 -15
  198. package/dist/esm/broadphase/SweepAndPrune.js +0 -77
  199. package/dist/esm/broadphase/SweepAndPrune.js.map +0 -1
  200. package/dist/esm/debug/index.js.map +0 -1
  201. package/dist/esm/index.js.map +0 -1
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # @codexo/exojs-physics
2
2
 
3
- Native 2D **collision, query and sensor** runtime for [ExoJS](https://github.com/Exoridus/ExoJS).
3
+ Native 2D **rigid-body** runtime for [ExoJS](https://github.com/Exoridus/ExoJS).
4
4
 
5
- Zero production dependencies, ESM-only, version-locked with the core engine. This
6
- first release ships a complete **collision/query world without dynamics**:
7
- shapes, colliders, bodies, a broad phase, a manifold-generating narrow phase,
8
- collision filters, sensors, events, spatial queries, scene-node binding and a
9
- debug overlay. Forces, impulses and gravity integration (the rigid-body solver)
10
- arrive in a follow-up the public surface here is forward-compatible with it.
5
+ Zero production dependencies, ESM-only, version-locked with the core engine.
6
+ It ships a fixed-step world with a warm-started **TGS-Soft** solver: shapes,
7
+ colliders, bodies, a dynamic-AABB broad phase, a manifold-generating narrow
8
+ phase, joints, sleeping islands, continuous collision for fast bodies, a
9
+ per-contact modifier, collision filters, sensors, events, spatial queries,
10
+ scene-node binding with interpolation, and a debug overlay.
11
11
 
12
12
  > **Library, not an extension.** Physics contributes no renderer or asset
13
13
  > bindings, so there is no `/register` entry. Construct a `PhysicsWorld`
@@ -57,18 +57,27 @@ class GameScene extends Scene {
57
57
 
58
58
  ## What it does
59
59
 
60
- | Area | API |
61
- |---|---|
62
- | World | `PhysicsWorld`, `step`, `gravity`, `timeStepper`, `destroy` |
63
- | Bodies | `new PhysicsBody` + `world.add` (`dynamic`/`static`/`kinematic`), `setTransform`, mass/inertia from colliders |
64
- | Colliders | `new Collider` + `body.addCollider` / `colliders: [...]`, density/friction/restitution, `isSensor`, filter, offset |
65
- | Attach | `world.attach(node, def)` — body + collider + `bind` in one call |
66
- | Shapes | `CircleShape`, `PolygonShape` (convex-validated), `BoxShape` |
67
- | Filtering | `CollisionFilter` (category/mask/group), `shouldCollide` |
68
- | Events | `onCollisionStart` / `onCollisionEnd` / `onSensorEnter` / `onSensorExit` — immutable snapshots |
69
- | Queries | `queryPoint`, `queryAabb` (+ `out` / `forEachAabbHit`), `rayCast`, `rayCastAll`, `overlapShape` |
70
- | Binding | `bind(body, node)` — node tracks the body's position each step |
71
- | Debug | `@codexo/exojs-physics/debug` `PhysicsDebugDraw` (shapes/AABBs/contacts/normals/centres/broad-phase) |
60
+ | Area | API |
61
+ | -------------------- | --------------------------------------------------------------------------------------------------------------------------- |
62
+ | World | `PhysicsWorld`, `step`, `gravity`, `timeStepper`, `destroy` |
63
+ | Bodies | `new PhysicsBody` + `world.add` (`dynamic`/`static`/`kinematic`), `setTransform`, mass/inertia from colliders |
64
+ | Colliders | `new Collider` + `body.addCollider` / `colliders: [...]`, density/friction/restitution, `isSensor`, filter, offset |
65
+ | Attach | `world.attach(node, def)` — body + collider + `bind` in one call |
66
+ | Shapes | solid: `CircleShape`, `CapsuleShape`, `PolygonShape` (convex-validated), `BoxShape`; boundary: `SegmentShape`, `ChainShape` |
67
+ | Concave outlines | `toConvexPolygonShapes(vertices)` — one possibly-concave outline into the convex `PolygonShape`s for a single body |
68
+ | Dynamics | fixed-step TGS-Soft solver, gravity, forces/impulses, friction/restitution, sleeping islands |
69
+ | Joints | `DistanceJoint`, `RevoluteJoint`, `PrismaticJoint`, `WheelJoint`, `WeldJoint`, `MouseJoint` |
70
+ | Continuous collision | `body.isBullet` — exact translational shape cast of the whole shape, not just its centre |
71
+ | Contact policy | `world.contactModifier` — per-contact material/enable decisions (one-way platforms, conditional friction) |
72
+ | Filtering | `CollisionFilter` (category/mask/group), `shouldCollide` |
73
+ | Events | `onCollisionStart` / `onCollisionEnd` / `onSensorEnter` / `onSensorExit` — immutable snapshots |
74
+ | Queries | `queryPoint`, `queryAabb` (+ `out` / `forEachAabbHit`), `rayCast`, `rayCastAll`, `overlapShape` |
75
+ | Binding | `bind(body, node)` — node tracks the body's position each step |
76
+ | Debug | `@codexo/exojs-physics/debug` → `PhysicsDebugDraw` (shapes/AABBs/contacts/normals/centres/broad-phase/joints) |
77
+
78
+ Building a level out of a tilemap? `@codexo/exojs-tilemap-physics` turns
79
+ `@codexo/exojs-tilemap` collision geometry into static bodies and keeps them in
80
+ sync with streamed chunks.
72
81
 
73
82
  ## Determinism & non-goals
74
83
 
@@ -79,10 +88,29 @@ guarantees across builds or machines** (floating-point reality). The package is
79
88
  single-threaded and 2D only — no workers, GPU, 3D, soft bodies, fluids or
80
89
  vehicles.
81
90
 
82
- This release contains **no dynamics solver**: bodies move only via
83
- `setTransform`. The narrow phase already produces full contact manifolds (normal,
84
- 1–2 points, stable feature ids) so the solver can be added without changing the
85
- public API.
91
+ `step()` owns its own fixed-timestep accumulator, so you can drive it from
92
+ either the engine's `Scene.fixedUpdate` (already a constant-rate hook the
93
+ idiomatic choice) or straight from `Scene.update`'s raw, variable per-frame
94
+ delta; either way `step` converts whatever it's given into the right number of
95
+ fixed sub-steps. See the "Stepping the world" section of the
96
+ [physics guide](https://exoridus.github.io/ExoJS/en/guide/physics/physics-basics/)
97
+ for the details and an interpolation note (`world.timeStepper.alpha`).
98
+
99
+ **Broad-phase scale.** Collision detection uses a dynamic AABB tree
100
+ (Box2D-style), incrementally updated across steps: a collider whose AABB
101
+ stays within its stored margin is never reinserted, so the dominant cost
102
+ tracks how much actually moved rather than the total live collider count
103
+ (there's still a cheap linear pass over all live colliders each step). Scales
104
+ to tens of thousands of simultaneously-live colliders.
105
+
106
+ **Solid and boundary geometry.** `CircleShape`, `CapsuleShape`, `PolygonShape`
107
+ and `BoxShape` enclose an area and carry mass; `SegmentShape` and `ChainShape`
108
+ are boundaries with no interior, so they contribute collision only and a
109
+ `dynamic` body needs at least one solid collider alongside them. A chain is one
110
+ authored collider that the engine solves edge by edge with shared-vertex
111
+ adjacency, so a body slides across a seam without snagging. Two boundaries never
112
+ collide with each other, and a boundary is never the _moving_ operand of a
113
+ continuous shape cast — level structure is swept against, not swept.
86
114
 
87
115
  ## License
88
116
 
@@ -1,14 +1,10 @@
1
- export interface Aabb {
2
- minX: number;
3
- minY: number;
4
- maxX: number;
5
- maxY: number;
6
- }
1
+ import type { AabbLike } from '@codexo/exojs';
7
2
  /** Create a zero-extent AABB at the origin. */
8
- export declare const createAabb: () => Aabb;
3
+ export declare const createAabb: () => AabbLike;
9
4
  /** `true` when two AABBs overlap (touching edges count as overlapping). */
10
- export declare const aabbOverlap: (a: Aabb, b: Aabb) => boolean;
5
+ export declare const aabbOverlap: (a: AabbLike, b: AabbLike) => boolean;
11
6
  /** `true` when `(x, y)` lies inside (or on the edge of) `aabb`. */
12
- export declare const aabbContainsPoint: (aabb: Aabb, x: number, y: number) => boolean;
7
+ export declare const aabbContainsPoint: (aabb: AabbLike, x: number, y: number) => boolean;
13
8
  /** Grow `aabb` outward by `margin` on every side, in place. */
14
- export declare const expandAabb: (aabb: Aabb, margin: number) => Aabb;
9
+ export declare const expandAabb: (aabb: AabbLike, margin: number) => AabbLike;
10
+ //# sourceMappingURL=Aabb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Aabb.d.ts","sourceRoot":"","sources":["../../src/Aabb.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,+CAA+C;AAC/C,eAAO,MAAM,UAAU,QAAO,QAAoD,CAAC;AAEnF,2EAA2E;AAC3E,eAAO,MAAM,WAAW,GAAI,GAAG,QAAQ,EAAE,GAAG,QAAQ,KAAG,OAAuF,CAAC;AAE/I,mEAAmE;AACnE,eAAO,MAAM,iBAAiB,GAAI,MAAM,QAAQ,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,OAA+E,CAAC;AAEzJ,+DAA+D;AAC/D,eAAO,MAAM,UAAU,GAAI,MAAM,QAAQ,EAAE,QAAQ,MAAM,KAAG,QAO3D,CAAC"}
package/dist/esm/Aabb.js CHANGED
@@ -1,12 +1,16 @@
1
- // Axis-aligned bounding box used by the broad phase and AABB queries. Stored as
2
- // min/max extents (not centre + half-extent) because the sweep-and-prune broad
3
- // phase and overlap tests read the edges directly.
1
+ //#region src/Aabb.ts
4
2
  /** Create a zero-extent AABB at the origin. */
5
- const createAabb = () => ({ minX: 0, minY: 0, maxX: 0, maxY: 0 });
3
+ const createAabb = () => ({
4
+ minX: 0,
5
+ minY: 0,
6
+ maxX: 0,
7
+ maxY: 0
8
+ });
6
9
  /** `true` when two AABBs overlap (touching edges count as overlapping). */
7
10
  const aabbOverlap = (a, b) => a.minX <= b.maxX && a.maxX >= b.minX && a.minY <= b.maxY && a.maxY >= b.minY;
8
11
  /** `true` when `(x, y)` lies inside (or on the edge of) `aabb`. */
9
12
  const aabbContainsPoint = (aabb, x, y) => x >= aabb.minX && x <= aabb.maxX && y >= aabb.minY && y <= aabb.maxY;
10
13
 
14
+ //#endregion
11
15
  export { aabbContainsPoint, aabbOverlap, createAabb };
12
- //# sourceMappingURL=Aabb.js.map
16
+ //# sourceMappingURL=Aabb.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Aabb.js","sources":["../../../src/Aabb.ts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;AACA;AACA;AASA;AACO,MAAM,UAAU,GAAG,OAAa,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE;AAE7E;AACO,MAAM,WAAW,GAAG,CAAC,CAAO,EAAE,CAAO,KAC1C,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;AAE1E;AACO,MAAM,iBAAiB,GAAG,CAAC,IAAU,EAAE,CAAS,EAAE,CAAS,KAChE,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC;;;;"}
1
+ {"version":3,"file":"Aabb.js","names":[],"sources":["../../src/Aabb.ts"],"sourcesContent":["// Axis-aligned bounding box helpers for the broad phase and AABB queries. The\n// box itself is core's structural `AabbLike` (min/max extents, not centre +\n// half-extent) - the broad-phase tree and the overlap tests read the edges\n// directly, and sharing one contract keeps colliders, spatial trees and query\n// bounds interchangeable across package boundaries.\n\nimport type { AabbLike } from '@codexo/exojs';\n\n/** Create a zero-extent AABB at the origin. */\nexport const createAabb = (): AabbLike => ({ minX: 0, minY: 0, maxX: 0, maxY: 0 });\n\n/** `true` when two AABBs overlap (touching edges count as overlapping). */\nexport const aabbOverlap = (a: AabbLike, b: AabbLike): boolean => a.minX <= b.maxX && a.maxX >= b.minX && a.minY <= b.maxY && a.maxY >= b.minY;\n\n/** `true` when `(x, y)` lies inside (or on the edge of) `aabb`. */\nexport const aabbContainsPoint = (aabb: AabbLike, x: number, y: number): boolean => x >= aabb.minX && x <= aabb.maxX && y >= aabb.minY && y <= aabb.maxY;\n\n/** Grow `aabb` outward by `margin` on every side, in place. */\nexport const expandAabb = (aabb: AabbLike, margin: number): AabbLike => {\n aabb.minX -= margin;\n aabb.minY -= margin;\n aabb.maxX += margin;\n aabb.maxY += margin;\n\n return aabb;\n};\n"],"mappings":";;AASA,MAAa,oBAA8B;CAAE,MAAM;CAAG,MAAM;CAAG,MAAM;CAAG,MAAM;AAAE;;AAGhF,MAAa,eAAe,GAAa,MAAyB,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE;;AAG1I,MAAa,qBAAqB,MAAgB,GAAW,MAAuB,KAAK,KAAK,QAAQ,KAAK,KAAK,QAAQ,KAAK,KAAK,QAAQ,KAAK,KAAK"}
@@ -1,8 +1,8 @@
1
- import type { Aabb } from './Aabb';
2
- import type { Mutable2D, Transform } from './math';
1
+ import type { AabbLike, PointLike } from '@codexo/exojs';
2
+ import type { Transform } from './math';
3
3
  import type { PhysicsBody } from './PhysicsBody';
4
4
  import type { AnyShape } from './shapes/AnyShape';
5
- import type { CollisionFilter, VectorLike } from './types';
5
+ import type { CollisionFilter } from './types';
6
6
  /** Construction options for a collider. */
7
7
  export interface ColliderOptions {
8
8
  /** The collision geometry. */
@@ -18,7 +18,7 @@ export interface ColliderOptions {
18
18
  /** Category/mask/group filter; partials merge over the defaults. */
19
19
  filter?: Partial<CollisionFilter>;
20
20
  /** Body-local offset of the shape origin. Default `(0, 0)`. */
21
- offset?: VectorLike;
21
+ offset?: Readonly<PointLike>;
22
22
  /** Body-local rotation of the shape in radians (compound colliders). Default `0`. */
23
23
  rotation?: number;
24
24
  }
@@ -26,7 +26,7 @@ export interface ColliderOptions {
26
26
  * Geometry attached to a {@link PhysicsBody}: a {@link Shape} plus a body-local
27
27
  * offset/rotation, material (friction/restitution/density) and a collision
28
28
  * filter. A body may own several colliders (compound). The collider also caches
29
- * its world-space geometry refreshed by {@link synchronize} which the broad
29
+ * its world-space geometry - refreshed by {@link synchronize} - which the broad
30
30
  * phase, narrow phase and queries read directly.
31
31
  *
32
32
  * Material fields and the filter are mutable; the shape and local placement are
@@ -45,6 +45,8 @@ export declare class Collider {
45
45
  readonly filter: CollisionFilter;
46
46
  private _id;
47
47
  private _body;
48
+ private readonly _chainEdges;
49
+ private _chainParent;
48
50
  private readonly _localTransform;
49
51
  private readonly _worldTransform;
50
52
  private readonly _aabb;
@@ -53,6 +55,15 @@ export declare class Collider {
53
55
  private readonly _worldVertices;
54
56
  private readonly _worldNormals;
55
57
  private _destroyed;
58
+ /**
59
+ * @internal - proxy id in the physics world's broad-phase spatial tree; `-1`
60
+ * when not inserted. Like `PhysicsBody._islandIndex`/`_sleepTime`, this is a
61
+ * single-owner slot: exactly ONE `AabbTreeBroadPhase` may track this collider
62
+ * at a time (in production, the world's own broad phase for the collider's
63
+ * whole lifetime). A second broad phase over the same collider would clobber
64
+ * this value and corrupt the first's tree - never do that.
65
+ */
66
+ _treeProxy: number;
56
67
  constructor(options: ColliderOptions);
57
68
  /** Stable id, assigned when the owning body joins a world via `world.add()`; `-1` until then. */
58
69
  get id(): number;
@@ -62,17 +73,28 @@ export declare class Collider {
62
73
  */
63
74
  get body(): PhysicsBody;
64
75
  /** The collider's world AABB (valid after the latest {@link synchronize}). */
65
- get aabb(): Readonly<Aabb>;
76
+ get aabb(): Readonly<AabbLike>;
66
77
  /** The collider's world transform (offset/rotation composed with the body's). */
67
78
  get worldTransform(): Readonly<Transform>;
68
79
  /** The collider's body-local transform (offset + local rotation). */
69
80
  get localTransform(): Readonly<Transform>;
70
81
  /** World-space circle centre (only meaningful for circle shapes). */
71
- get worldCenter(): Readonly<Mutable2D>;
72
- /** World-space polygon vertices `[x0, y0, ]` (only meaningful for polygon shapes). */
82
+ get worldCenter(): Readonly<PointLike>;
83
+ /** World-space polygon vertices `[x0, y0, ...]` (only meaningful for polygon shapes). */
73
84
  get worldVertices(): readonly number[];
74
- /** World-space polygon outward normals `[x0, y0, ]` (only meaningful for polygon shapes). */
85
+ /** World-space polygon outward normals `[x0, y0, ...]` (only meaningful for polygon shapes). */
75
86
  get worldNormals(): readonly number[];
87
+ /**
88
+ * @internal - the engine-owned edge proxies a chain collider fans out into,
89
+ * one per chain edge; `null` for every other shape. They are what the broad
90
+ * phase, the narrow phase and the solver see, so a chain contact reuses the
91
+ * one-manifold-per-pair model unchanged. They are never part of
92
+ * `body.colliders`, `world.colliders` or any query result - the authored
93
+ * collider is the public identity of every contact they produce.
94
+ */
95
+ get chainEdges(): readonly Collider[] | null;
96
+ /** @internal - the authored chain collider this edge proxy belongs to; `null` for an authored collider. */
97
+ get chainParent(): Collider | null;
76
98
  /** `true` after the owning world has destroyed this collider. */
77
99
  get destroyed(): boolean;
78
100
  /**
@@ -81,8 +103,38 @@ export declare class Collider {
81
103
  * detection pass.
82
104
  */
83
105
  synchronize(bodyTransform: Transform): void;
84
- /** @internal — bind this collider to its body and id (called when the body joins a world). */
106
+ /**
107
+ * A chain's world geometry is its edge proxies': each of them shares the
108
+ * chain's local placement and syncs its own two endpoints, and the chain's own
109
+ * AABB is their union. Nothing is transformed twice, and no proxy is rebuilt.
110
+ */
111
+ private _synchronizeChain;
112
+ /** A circle is its transformed centre; the local vertex buffers stay unused. */
113
+ private _synchronizeCircle;
114
+ /**
115
+ * Transform a local vertex/normal ring into the world buffers and take the
116
+ * AABB while doing it. `radius` inflates the box for a rounded outline (a
117
+ * capsule's spine); it is `0` for a plain polygon.
118
+ */
119
+ private _synchronizePolygon;
120
+ /** @internal - bind this collider to its body and id (called when the body joins a world). */
85
121
  _attach(body: PhysicsBody, id: number): void;
122
+ /**
123
+ * Fan a chain out into one proxy per edge. Each proxy carries the chain's own
124
+ * local placement, so it needs no transform of its own, and its shape carries
125
+ * the adjacency that keeps a body from snagging at a shared vertex.
126
+ */
127
+ private _buildChainEdges;
86
128
  /** Internal: mark destroyed (called by the world). */
87
129
  _markDestroyed(): void;
88
130
  }
131
+ /**
132
+ * The authored collider a contact, query hit or sweep target belongs to: the
133
+ * collider itself, or the chain it is an engine-owned edge proxy of. Every
134
+ * public identity - events, query results, the contact modifier - goes through
135
+ * this, so a solver-side partition never reaches a caller.
136
+ *
137
+ * @internal
138
+ */
139
+ export declare const authoredCollider: (collider: Collider) => Collider;
140
+ //# sourceMappingURL=Collider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Collider.d.ts","sourceRoot":"","sources":["../../src/Collider.ts"],"names":[],"mappings":"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"}