@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
@@ -1 +1 @@
1
- {"version":3,"file":"PhysicsBody.js","sources":["../../../src/PhysicsBody.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PhysicsBody.js","names":[],"sources":["../../src/PhysicsBody.ts"],"sourcesContent":["import type { PointLike } from '@codexo/exojs';\nimport { Vector } from '@codexo/exojs';\n\nimport { Collider, type ColliderOptions } from './Collider';\nimport type { Transform } from './math';\nimport { applyTransform, createTransform, setTransform } from './math';\nimport type { ShapeMassProperties } from './shapes/Shape';\nimport type { BodyType } from './types';\n\n/** Construction options for a body. */\nexport interface BodyOptions {\n /** Simulation role. Default `'dynamic'`. */\n type?: BodyType;\n /** Initial world position. Default `(0, 0)`. */\n position?: Readonly<PointLike>;\n /** Initial rotation in radians. Default `0`. */\n angle?: number;\n /** Linear damping applied to the velocity each sub-step. Default `0`. */\n linearDamping?: number;\n /** Angular damping applied to the angular velocity each sub-step. Default `0`. */\n angularDamping?: number;\n /** Per-body multiplier on world gravity (e.g. `0` to ignore gravity). Default `1`. */\n gravityScale?: number;\n /** When `true`, the body never rotates under contacts (infinite rotational inertia). Default `false`. */\n fixedRotation?: boolean;\n /** When `true`, the body's colliders are shape-cast along each step's motion (CCD) so it cannot tunnel through thin geometry. Default `false`. */\n isBullet?: boolean;\n /** Colliders to attach up-front. Each may be a {@link Collider} instance or its {@link ColliderOptions}. */\n colliders?: Array<Collider | ColliderOptions>;\n}\n\n/**\n * Internal hook the world hands to each body so colliders can be id-allocated\n * and registered without the body importing the concrete world class.\n */\nexport interface BodyOwner {\n _allocateColliderId(): number;\n _registerCollider(collider: Collider): void;\n}\n\n/**\n * A rigid body: a world transform plus mass properties aggregated from its\n * colliders. Dynamic bodies integrate under gravity, accumulated forces/torque\n * and contact impulses each fixed sub-step; static bodies never move; kinematic\n * bodies move by their velocity only and stay immovable under contacts. Drive a\n * body with {@link applyForce}, {@link applyTorque} and {@link applyImpulse}, or\n * set {@link linearVelocityX}/{@link linearVelocityY}/{@link angularVelocity}\n * directly; reposition it (teleport, no velocity) with {@link setTransform}.\n */\nexport class PhysicsBody {\n public readonly type: BodyType;\n\n /** Linear damping applied to the velocity each sub-step. */\n public linearDamping: number;\n /** Angular damping applied to the angular velocity each sub-step. */\n public angularDamping: number;\n /** Per-body multiplier on world gravity (e.g. `0` to ignore gravity). */\n public gravityScale: number;\n /** When `true`, rotational inertia is treated as infinite. */\n public fixedRotation: boolean;\n /** When `true`, the body's colliders are shape-cast along each step's motion (CCD) so it cannot tunnel through thin geometry. */\n public isBullet: boolean;\n\n /** Total mass (0 for static/kinematic). */\n public mass = 0;\n /** Inverse mass (`0` = immovable). */\n public invMass = 0;\n /** Rotational inertia about the centre of mass (0 for static/kinematic or fixed rotation). */\n public inertia = 0;\n /** Inverse rotational inertia (`0` = no angular response). */\n public invInertia = 0;\n\n /** Linear velocity X in px/s. */\n public linearVelocityX = 0;\n /** Linear velocity Y in px/s. */\n public linearVelocityY = 0;\n /** Angular velocity in rad/s. */\n public angularVelocity = 0;\n\n /** When `false`, this body is never put to sleep. Default `true`. */\n public allowSleep = true;\n\n /** @internal - Delta position X accumulated across the frame's sub-steps by the TGS integrator; written into the transform once per frame by {@link _finalizePosition}. */\n public _deltaPosX = 0;\n /** @internal - Delta position Y accumulated across the frame's sub-steps by the TGS integrator. */\n public _deltaPosY = 0;\n /** @internal - Delta rotation (radians) accumulated across the frame's sub-steps by the TGS integrator. */\n public _deltaAngle = 0;\n /** @internal - `cos(_deltaAngle)`, cached so the solver can rotate the contact anchors by the live sub-step rotation without a per-contact trig call. */\n public _deltaCos = 1;\n /** @internal - `sin(_deltaAngle)`, cached alongside {@link _deltaCos}. */\n public _deltaSin = 0;\n\n private _forceX = 0;\n private _forceY = 0;\n private _torque = 0;\n\n /** @internal - seconds the body has stayed below the sleep thresholds (frozen while asleep). Read by the world's island pass. */\n public _sleepTime = 0;\n /** @internal - dense union-find index assigned by the world's island pass each step. */\n public _islandIndex = 0;\n /**\n * @internal - raised by {@link setTransform}, cleared once the fixed step that\n * saw it completes. A static/kinematic body driven by teleporting carries no\n * velocity, so this is the world's only signal that such a body moved and its\n * sleeping contact partners must be woken.\n */\n public _teleported = false;\n /** @internal - world-space centre of mass at the start of the current fixed step (CCD swept-test origin). */\n public _ccdPrevX = 0;\n /** @internal - see {@link _ccdPrevX}. */\n public _ccdPrevY = 0;\n\n private _sleeping = false;\n\n private _id = -1;\n private _owner: BodyOwner | null = null;\n private _attached = false;\n\n private readonly _transform: Transform;\n // Transform at the START of the most recent fixed step. Presentation only:\n // the solver never reads it, and it is captured before the step writes its\n // delta so a teleport can collapse it onto the current state.\n private _previousX: number;\n private _previousY: number;\n private _previousAngle: number;\n private readonly _colliders: Collider[] = [];\n private _comX = 0;\n private _comY = 0;\n private _massReady = false;\n private _destroyed = false;\n\n public constructor(options: BodyOptions = {}) {\n this.type = options.type ?? 'dynamic';\n this._transform = createTransform(options.position?.x ?? 0, options.position?.y ?? 0, options.angle ?? 0);\n this._previousX = this._transform.x;\n this._previousY = this._transform.y;\n this._previousAngle = this._transform.angle;\n this.linearDamping = options.linearDamping ?? 0;\n this.angularDamping = options.angularDamping ?? 0;\n this.gravityScale = options.gravityScale ?? 1;\n this.fixedRotation = options.fixedRotation ?? false;\n this.isBullet = options.isBullet ?? false;\n\n // Build up-front colliders now (no id/world registration until the body\n // joins a world via `world.add()`). They sit in `_colliders` unsynchronised;\n // `_attachToWorld` assigns ids, registers them and computes the mass model.\n if (options.colliders) {\n for (const entry of options.colliders) {\n this._colliders.push(entry instanceof Collider ? entry : new Collider(entry));\n }\n }\n }\n\n /** Stable id, assigned when the body joins a world via `world.add()`; `-1` until then. */\n public get id(): number {\n return this._id;\n }\n\n /** `true` once the body has been added to a world (guards against double-add). */\n public get attached(): boolean {\n return this._attached;\n }\n\n /** World X. */\n public get x(): number {\n return this._transform.x;\n }\n\n /** World Y. */\n public get y(): number {\n return this._transform.y;\n }\n\n /** Rotation in radians. */\n public get angle(): number {\n return this._transform.angle;\n }\n\n /**\n * World X at the start of the most recent fixed step. With {@link x} it\n * brackets the last step, which is what an interpolating presentation blends\n * between; a teleport collapses it onto {@link x}. Never read by the solver.\n */\n public get previousX(): number {\n return this._previousX;\n }\n\n /** World Y at the start of the most recent fixed step; see {@link previousX}. */\n public get previousY(): number {\n return this._previousY;\n }\n\n /**\n * Rotation in radians at the start of the most recent fixed step; see\n * {@link previousX}. Body angles are continuous and unbounded, never wrapped\n * to a range, so this and {@link angle} can be blended with a plain lerp.\n */\n public get previousAngle(): number {\n return this._previousAngle;\n }\n\n /** A fresh `Vector` copy of the body's world position. */\n public get position(): Vector {\n return new Vector(this._transform.x, this._transform.y);\n }\n\n /** The body's world transform (read-only; mutate via {@link setTransform}). */\n public get transform(): Readonly<Transform> {\n return this._transform;\n }\n\n /** The body's colliders (read-only view). */\n public get colliders(): readonly Collider[] {\n return this._colliders;\n }\n\n /** Centre of mass in body-local space (relative to the body origin). */\n public get centerOfMassX(): number {\n return this._comX;\n }\n\n /** Centre of mass in body-local space (relative to the body origin). */\n public get centerOfMassY(): number {\n return this._comY;\n }\n\n /**\n * `true` when the body is ready to simulate. Static/kinematic bodies are\n * always ready (infinite-mass semantics); a dynamic body is ready only once\n * it has at least one positive-density collider.\n */\n public get isMassReady(): boolean {\n return this.type !== 'dynamic' || this._massReady;\n }\n\n /** `true` after the owning world has destroyed this body. */\n public get destroyed(): boolean {\n return this._destroyed;\n }\n\n /** `true` when the body is asleep - skipped by the integrator and solver until woken. */\n public get isSleeping(): boolean {\n return this._sleeping;\n }\n\n /**\n * Attach a collider to this body. Accepts a {@link Collider} instance or its\n * {@link ColliderOptions} (a convenience that constructs the collider for you).\n * When the body is already in a world, the collider is id-allocated, registered,\n * the mass model is recomputed and the world geometry synchronised immediately;\n * on a free-standing body the collider is simply held until `world.add()`.\n * Returns the collider.\n */\n public addCollider(collider: Collider | ColliderOptions): Collider {\n if (this._destroyed) {\n throw new Error('PhysicsBody: cannot add a collider to a destroyed body.');\n }\n\n // Collider imports PhysicsBody type-only (erased), so this value import is\n // one-directional - no runtime cycle.\n const instance = collider instanceof Collider ? collider : new Collider(collider);\n\n this._colliders.push(instance);\n\n // Before the body joins a world there is no owner to allocate ids / register\n // with; `_attachToWorld` does that (and the mass/sync pass) for every held\n // collider. Once attached, mirror the world's create order exactly.\n if (this._attached && this._owner) {\n attachWithChainEdges(instance, this, this._owner);\n this._recomputeMass();\n this._assertDynamicCarriesMass();\n instance.synchronize(this._transform);\n this._owner._registerCollider(instance);\n }\n\n return instance;\n }\n\n /**\n * Set the body's world transform. Resets the body's cached collider geometry\n * immediately so subsequent queries see the new placement. Returns `this`.\n */\n public setTransform(position: Readonly<PointLike>, angle: number = this._transform.angle): this {\n if (this._destroyed) {\n throw new Error('PhysicsBody: cannot move a destroyed body.');\n }\n\n this.wake();\n\n this._teleported = true;\n\n setTransform(this._transform, position.x, position.y, angle);\n\n // A teleport is a discontinuity, not motion - collapsing the pair keeps an\n // interpolating presentation from sweeping the node across the jump.\n this._previousX = this._transform.x;\n this._previousY = this._transform.y;\n this._previousAngle = this._transform.angle;\n\n for (const collider of this._colliders) {\n collider.synchronize(this._transform);\n }\n\n return this;\n }\n\n /** Refresh every collider's world geometry from the current transform. */\n public synchronizeColliders(): void {\n for (const collider of this._colliders) {\n collider.synchronize(this._transform);\n }\n }\n\n /** World-space centre of mass X (body origin + rotated local centre of mass). */\n public get worldCenterOfMassX(): number {\n return this._transform.x + this._transform.cos * this._comX - this._transform.sin * this._comY;\n }\n\n /** World-space centre of mass Y. */\n public get worldCenterOfMassY(): number {\n return this._transform.y + this._transform.sin * this._comX + this._transform.cos * this._comY;\n }\n\n /**\n * Accumulate a world-space force at the centre of mass; integrated on the next\n * sub-step and then cleared. No-op on static/kinematic bodies. Returns `this`.\n */\n public applyForce(forceX: number, forceY: number): this {\n this.wake();\n this._forceX += forceX;\n this._forceY += forceY;\n\n return this;\n }\n\n /**\n * Accumulate a torque; integrated on the next sub-step and then cleared. No-op\n * on static/kinematic bodies (and fixed-rotation bodies). Returns `this`.\n */\n public applyTorque(torque: number): this {\n this.wake();\n this._torque += torque;\n\n return this;\n }\n\n /**\n * Apply an instantaneous world-space impulse at `(pointX, pointY)` (world space;\n * defaults to the centre of mass), changing velocity immediately. No-op on\n * static/kinematic bodies (infinite mass). Returns `this`.\n */\n public applyImpulse(impulseX: number, impulseY: number, pointX?: number, pointY?: number): this {\n if (this.invMass === 0) {\n return this;\n }\n\n this.wake();\n this.linearVelocityX += impulseX * this.invMass;\n this.linearVelocityY += impulseY * this.invMass;\n\n if (pointX !== undefined && pointY !== undefined && this.invInertia !== 0) {\n const rx = pointX - this.worldCenterOfMassX;\n const ry = pointY - this.worldCenterOfMassY;\n\n this.angularVelocity += (rx * impulseY - ry * impulseX) * this.invInertia;\n }\n\n return this;\n }\n\n /**\n * @internal - integrate velocity from gravity, accumulated forces/torque and\n * damping over the sub-step `h`. No-op for static/kinematic (infinite mass\n * keeps their velocity solver-driven only). Called once per TGS sub-step, so\n * gravity/forces are applied with `h` each sub-step (`N·h = dt`, same total\n * impulse, but the small-step position error scales with `h²`). The\n * force/torque accumulators are **not** cleared here - they are consumed by\n * every sub-step and cleared once per frame by {@link _finalizePosition}.\n */\n public _integrateVelocity(h: number, gravityX: number, gravityY: number): void {\n if (this.invMass === 0 || this._sleeping) {\n return;\n }\n\n this.linearVelocityX += (gravityX * this.gravityScale + this._forceX * this.invMass) * h;\n this.linearVelocityY += (gravityY * this.gravityScale + this._forceY * this.invMass) * h;\n this.angularVelocity += this._torque * this.invInertia * h;\n\n // Exponential damping (no-op when damping is 0).\n this.linearVelocityX /= 1 + h * this.linearDamping;\n this.linearVelocityY /= 1 + h * this.linearDamping;\n this.angularVelocity /= 1 + h * this.angularDamping;\n }\n\n /**\n * @internal - accumulate this sub-step's velocity into the per-frame delta\n * position/rotation (TGS sub-stepping). The transform itself is **not** moved\n * here; {@link _finalizePosition} writes the accumulated delta once per frame.\n * Tracking the delta (rather than moving the transform each sub-step) lets the\n * solver recompute contact separation from it without re-running detection or\n * re-syncing collider geometry per sub-step. Static bodies never move.\n */\n public _integratePosition(h: number): void {\n if (this.type === 'static' || this._sleeping) {\n return;\n }\n\n this._deltaPosX += this.linearVelocityX * h;\n this._deltaPosY += this.linearVelocityY * h;\n this._deltaAngle += this.angularVelocity * h;\n\n // Cache the rotation so the solver can rotate the contact anchors by the\n // live sub-step rotation (TGS): without it the anchors stay frozen at frame\n // start and a tilting tower's restoring torque is mis-computed, so the tilt\n // grows instead of being corrected. Only non-zero rotation pays the trig.\n if (this._deltaAngle !== 0) {\n this._deltaCos = Math.cos(this._deltaAngle);\n this._deltaSin = Math.sin(this._deltaAngle);\n }\n }\n\n /**\n * @internal - advance the sleep timer over one fixed step `dt`. A body below\n * both velocity thresholds accumulates time; a too-fast body, or one that opts\n * out via {@link allowSleep}, resets it. The sleep/wake decision is made per\n * island by the world (so a stack sleeps as a unit) from {@link _sleepTime}.\n */\n public _accumulateSleepTime(dt: number, linearThreshold: number, angularThreshold: number): void {\n const tooFast =\n this.linearVelocityX * this.linearVelocityX + this.linearVelocityY * this.linearVelocityY > linearThreshold * linearThreshold ||\n Math.abs(this.angularVelocity) > angularThreshold;\n\n this._sleepTime = !this.allowSleep || tooFast ? 0 : this._sleepTime + dt;\n }\n\n /** @internal - set the sleep state. Sleeping zeroes the velocity; waking resets the sleep timer. */\n public _setSleeping(sleeping: boolean): void {\n if (this._sleeping === sleeping) {\n return;\n }\n\n this._sleeping = sleeping;\n\n if (sleeping) {\n this.linearVelocityX = 0;\n this.linearVelocityY = 0;\n this.angularVelocity = 0;\n } else {\n this._sleepTime = 0;\n }\n }\n\n /**\n * Wake the body if it is asleep, resetting its sleep timer. The rest of its\n * island wakes with it on the next step (a contact to an awake body keeps the\n * whole island awake). Returns `this`.\n */\n public wake(): this {\n this._setSleeping(false);\n this._sleepTime = 0;\n\n return this;\n }\n\n /**\n * @internal - apply the frame's accumulated delta position/rotation to the\n * transform (rotating about the centre of mass), re-sync collider geometry and\n * clear the force/torque accumulators. Called once per frame after the\n * sub-step loop. Static bodies never move; the force clear still runs (forces\n * are a no-op on infinite mass but the accumulator is reset for consistency).\n */\n public _finalizePosition(): void {\n this._forceX = 0;\n this._forceY = 0;\n this._torque = 0;\n this._teleported = false;\n\n // Captured before the step's delta is applied, and before the no-motion\n // early return below - a body that did not move must report previous ===\n // current rather than a stale pair from the last step it did move in.\n this._previousX = this._transform.x;\n this._previousY = this._transform.y;\n this._previousAngle = this._transform.angle;\n\n if (this.type === 'static' || (this._deltaPosX === 0 && this._deltaPosY === 0 && this._deltaAngle === 0)) {\n this._resetDelta();\n\n return;\n }\n\n const newComX = this.worldCenterOfMassX + this._deltaPosX;\n const newComY = this.worldCenterOfMassY + this._deltaPosY;\n const newAngle = this._transform.angle + this._deltaAngle;\n const cos = Math.cos(newAngle);\n const sin = Math.sin(newAngle);\n\n // origin = newCoM − R(newAngle)·comLocal (so rotation pivots about the CoM).\n setTransform(this._transform, newComX - (cos * this._comX - sin * this._comY), newComY - (sin * this._comX + cos * this._comY), newAngle);\n\n this._resetDelta();\n\n for (const collider of this._colliders) {\n collider.synchronize(this._transform);\n }\n }\n\n /** Clear the per-frame TGS delta accumulators (position, rotation and its cached cos/sin). */\n private _resetDelta(): void {\n this._deltaPosX = 0;\n this._deltaPosY = 0;\n this._deltaAngle = 0;\n this._deltaCos = 1;\n this._deltaSin = 0;\n }\n\n /** Internal: detach a collider (called by the world during destruction). */\n public _removeCollider(collider: Collider): void {\n const index = this._colliders.indexOf(collider);\n\n if (index !== -1) {\n this._colliders.splice(index, 1);\n this._recomputeMass();\n }\n }\n\n /**\n * @internal - join `owner`'s world with the allocated `id`. Allocates ids for\n * and registers every held collider, then aggregates the mass model and\n * synchronises world geometry. Called once by {@link PhysicsWorld.add}.\n *\n * Ordering matters and mirrors the per-collider create path exactly: ids and\n * the body link go on first, then a single mass recompute over the full\n * collider set (so the centre of mass / inertia aggregate is correct), then\n * `synchronize` over every collider (the cached world geometry the broad/narrow\n * phase reads), then world registration last. Recomputing mass before all\n * colliders are linked, or syncing before the mass model exists, would feed the\n * solver a stale CoM and produce subtle integration bugs.\n */\n public _attachToWorld(owner: BodyOwner, id: number): void {\n if (this._destroyed) {\n throw new Error('PhysicsBody: cannot add a destroyed body to a world.');\n }\n\n this._owner = owner;\n this._id = id;\n this._attached = true;\n\n for (const collider of this._colliders) {\n attachWithChainEdges(collider, this, owner);\n }\n\n this._recomputeMass();\n this._assertDynamicCarriesMass();\n\n for (const collider of this._colliders) {\n collider.synchronize(this._transform);\n }\n\n for (const collider of this._colliders) {\n owner._registerCollider(collider);\n }\n }\n\n /** Internal: mark destroyed (called by the world). */\n public _markDestroyed(): void {\n this._destroyed = true;\n }\n\n /**\n * A dynamic body has to carry mass. Boundary geometry (a segment, a chain)\n * reports no mass properties, and a collider may also be given zero density,\n * so a dynamic body can end up with none at all - which the solver cannot tell\n * apart from a static body, since both have `invMass === 0`. Rejecting it is\n * the difference between a clear error and a body that silently stops moving.\n */\n private _assertDynamicCarriesMass(): void {\n if (this.type !== 'dynamic' || this._massReady || this._colliders.length === 0) {\n return;\n }\n\n throw new Error(\n 'PhysicsBody: a dynamic body must carry at least one collider with mass — every collider it holds is either boundary geometry (a segment or chain, which has no interior) or has zero density. Add a solid collider, or make the body static or kinematic.',\n );\n }\n\n /** Recompute mass, centre of mass and rotational inertia from the colliders. */\n private _recomputeMass(): void {\n if (this.type !== 'dynamic') {\n this.mass = 0;\n this.invMass = 0;\n this.inertia = 0;\n this.invInertia = 0;\n this._comX = 0;\n this._comY = 0;\n this._massReady = false;\n\n return;\n }\n\n let mass = 0;\n let cx = 0;\n let cy = 0;\n let inertiaOrigin = 0;\n const point = { x: 0, y: 0 };\n\n for (const collider of this._colliders) {\n // Boundary geometry (a segment, later a chain) has no interior and reports\n // no mass properties; it contributes collision only.\n const massProperties: ShapeMassProperties | null = collider.shape.massProperties;\n\n if (massProperties === null) {\n continue;\n }\n\n const m = collider.density * massProperties.area;\n\n if (m <= 0) {\n continue;\n }\n\n // Shape centroid expressed in body-local space (offset + local rotation).\n applyTransform(collider.localTransform, massProperties.centroidX, massProperties.centroidY, point);\n mass += m;\n cx += m * point.x;\n cy += m * point.y;\n // Parallel-axis to the body origin: I_origin += I_centroid + m·d².\n inertiaOrigin += collider.density * massProperties.unitInertia + m * (point.x * point.x + point.y * point.y);\n }\n\n if (mass > 0) {\n cx /= mass;\n cy /= mass;\n }\n\n this.mass = mass;\n this.invMass = mass > 0 ? 1 / mass : 0;\n this._comX = cx;\n this._comY = cy;\n // Shift inertia from the body origin to the centre of mass.\n const inertiaCom = inertiaOrigin - mass * (cx * cx + cy * cy);\n\n this.inertia = this.fixedRotation ? 0 : inertiaCom;\n this.invInertia = this.fixedRotation || inertiaCom <= 0 ? 0 : 1 / inertiaCom;\n this._massReady = mass > 0;\n }\n}\n\n/**\n * Give a collider its id, and a chain collider's edge proxies theirs. The\n * proxies are ids in the same space as authored colliders - the contact graph\n * keys pairs on them - but they never appear in `body.colliders`.\n */\nconst attachWithChainEdges = (collider: Collider, body: PhysicsBody, owner: BodyOwner): void => {\n collider._attach(body, owner._allocateColliderId());\n\n const edges = collider.chainEdges;\n\n if (edges === null) {\n return;\n }\n\n for (const edge of edges) {\n edge._attach(body, owner._allocateColliderId());\n }\n};\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
- import type { SceneNode } from '@codexo/exojs';
1
+ import type { AabbLike, PointLike, SceneNode, Seconds } from '@codexo/exojs';
2
2
  import { Signal, Vector } from '@codexo/exojs';
3
- import type { Aabb } from './Aabb';
4
3
  import type { PhysicsBackend } from './backend/PhysicsBackend';
5
4
  import type { PhysicsBinding } from './binding/PhysicsBinding';
6
5
  import { Collider } from './Collider';
6
+ import type { ContactModifier } from './ContactModifier';
7
7
  import type { CollisionEvent, SensorEvent } from './events';
8
8
  import type { Joint } from './joints/Joint';
9
9
  import type { BodyOwner } from './PhysicsBody';
@@ -11,11 +11,11 @@ import { PhysicsBody } from './PhysicsBody';
11
11
  import type { QueryFilter, RayHit } from './query/QueryEngine';
12
12
  import type { AnyShape } from './shapes/AnyShape';
13
13
  import { TimeStepper } from './TimeStepper';
14
- import type { BodyType, CollisionFilter, VectorLike } from './types';
14
+ import type { BodyType, CollisionFilter } from './types';
15
15
  /** Construction options for a {@link PhysicsWorld}. */
16
16
  export interface PhysicsWorldOptions {
17
17
  /** Gravity in px/s² (+Y down). Integrated each sub-step. Default `(0, 0)`. */
18
- gravity?: VectorLike;
18
+ gravity?: Readonly<PointLike>;
19
19
  /** Fixed timestep in seconds. Default `1 / 60`. */
20
20
  fixedDelta?: number;
21
21
  /** Maximum fixed steps per `step` call (spiral-of-death guard). Default `8`. */
@@ -24,7 +24,7 @@ export interface PhysicsWorldOptions {
24
24
  * TGS-Soft sub-steps per fixed step (the solver's stiffness scales with this,
25
25
  * not iteration count). Default `4`. Must be ≥ 1. Values below `2` visibly
26
26
  * degrade tall-stack stability (a 10-box tower jitters at `1`), so the default
27
- * is load-bearing do not lower it for performance.
27
+ * is load-bearing - do not lower it for performance.
28
28
  */
29
29
  subStepCount?: number;
30
30
  /** Soft-contact stiffness in Hz (the contact behaves as a damped spring at this frequency). Default `30`. */
@@ -33,6 +33,31 @@ export interface PhysicsWorldOptions {
33
33
  dampingRatio?: number;
34
34
  /** Put resting bodies to sleep so they skip integration and solving. Default `true`. */
35
35
  enableSleeping?: boolean;
36
+ /**
37
+ * Adjust each solid contact for the coming step (one-way platforms,
38
+ * conditional friction, per-pair material overrides). At most one per world;
39
+ * see {@link PhysicsWorld.contactModifier}. Default none.
40
+ */
41
+ contactModifier?: ContactModifier | null;
42
+ /**
43
+ * Place bound nodes between the last two fixed states instead of snapping them
44
+ * to the latest one, which smooths motion when the fixed rate is below the
45
+ * frame rate. Default `false`.
46
+ *
47
+ * The blend factor comes from {@link frameAlphaSource}; a world driven as a
48
+ * `System` has to supply one.
49
+ */
50
+ interpolation?: boolean;
51
+ /**
52
+ * Where interpolated bindings read their blend factor, in `[0, 1)`.
53
+ *
54
+ * Defaults to this world's own accumulator - correct when the world is driven
55
+ * with {@link PhysicsWorld.step}, which is what advances it. A world driven as
56
+ * a `System` goes through {@link PhysicsWorld.fixedUpdate} and bypasses that
57
+ * accumulator entirely, so the host owns the fraction: pass
58
+ * `() => app.frameAlpha`.
59
+ */
60
+ frameAlphaSource?: () => number;
36
61
  /** Linear speed at or below which a body is a sleep candidate, px/s. Default `5`. */
37
62
  sleepLinearVelocity?: number;
38
63
  /** Angular speed at or below which a body is a sleep candidate, rad/s. Default `0.06`. */
@@ -47,9 +72,9 @@ export interface PhysicsWorldOptions {
47
72
  export interface AttachOptions {
48
73
  /** Simulation role of the created body. Default `'dynamic'`. */
49
74
  type?: BodyType;
50
- /** Initial world position of the body. Default the node's position is left untouched and `(0, 0)` is used. */
51
- position?: VectorLike;
52
- /** Initial rotation (radians) of the body. Default `0`. */
75
+ /** Initial world position of the body. Default the node's current WORLD position ({@link SceneNode.getWorldTransform}) at attach time. */
76
+ position?: Readonly<PointLike>;
77
+ /** Initial rotation (radians) of the body. Default the node's current WORLD rotation at attach time. */
53
78
  angle?: number;
54
79
  /** Per-body multiplier on world gravity. Default `1`. */
55
80
  gravityScale?: number;
@@ -58,7 +83,7 @@ export interface AttachOptions {
58
83
  /** The collider geometry. */
59
84
  shape: AnyShape;
60
85
  /** Body-local offset of the collider. Default `(0, 0)`. */
61
- offset?: VectorLike;
86
+ offset?: Readonly<PointLike>;
62
87
  /** Body-local rotation of the collider (radians). Default `0`. */
63
88
  rotation?: number;
64
89
  /** Collider density (mass per px²). Default `1`. */
@@ -79,7 +104,7 @@ export interface AttachOptions {
79
104
  * body velocities, runs broad- and narrow-phase detection, solves contacts and
80
105
  * integrates positions, then fires immutable contact/sensor events and writes
81
106
  * bound node transforms. It holds **no module-level state**, so any number of
82
- * worlds run in isolation (gate I-1).
107
+ * worlds run in isolation.
83
108
  *
84
109
  * The dynamics are a native, warm-started **TGS-Soft** solver (Box2D-v3 "soft
85
110
  * step"): each fixed step runs detection once, then several sub-steps, each
@@ -91,19 +116,49 @@ export interface AttachOptions {
91
116
  * touching this public surface.
92
117
  *
93
118
  * **Operating envelope.** The soft solver trades a little accuracy for
94
- * robustness, so it has a few documented limits each stays finite/stable and
95
- * each is pinned by a gate in `dynamics.test.ts`:
96
- * - **Mass ratio** — resting stacks are slop-accurate up to ~100:1. Beyond that
97
- * the velocity-capped soft push-out (`maxBiasVelocity`) lets the lighter body
98
- * settle progressively deeper (≈6px at 500:1, fully through a thin floor by
99
- * ~5000:1) always finite, never exploding (SG-MR3).
100
- * - **No CCD** detection runs once per fixed step with no swept test, so a
101
- * body that travels farther than an obstacle's thickness in one step tunnels
102
- * straight through it (it stays finite). Reliably stopping fast projectiles is
103
- * a future bullet-mode feature (SG-X5).
104
- * - **{@link PhysicsWorldOptions.subStepCount}** the default `4` is
119
+ * robustness, so it has a few documented limits - each stays finite and stable,
120
+ * and each is pinned by a gate in `dynamics.test.ts` or
121
+ * `contact-push-out.test.ts`:
122
+ * - **Resting contacts** settle within a small, fixed tolerance. A face contact
123
+ * settles at exactly that tolerance; a single-point contact settles slightly
124
+ * deeper, and that gap grows with acceleration. Very high accelerations
125
+ * eventually exceed what the push-out can resolve within a step, at which
126
+ * point the contact holds a slightly deeper resting depth instead of the
127
+ * tolerance - keep gravity in the range ordinary 2D games use.
128
+ * - **Mass ratio** - contacts between bodies of very different mass degrade
129
+ * gradually rather than at a fixed ratio. What sets the practical limit is how
130
+ * thick the supporting geometry is relative to the lighter body, not the ratio
131
+ * alone: a light body squeezed against a boundary thinner than itself is the
132
+ * case that fails first, and it fails by sinking through.
133
+ * - **Scale-relative behaviour** - the solver's tolerances are absolute lengths,
134
+ * so a very small shape sees them as a large fraction of itself, and a very
135
+ * large one as a negligible one. Keep the shapes of one world within a couple
136
+ * of orders of magnitude of each other.
137
+ * - **CCD is opt-in and translation-only** - detection runs once per fixed
138
+ * step, so an ordinary body that crosses more than roughly half a barrier's
139
+ * total thickness within one step may end up on the wrong side of it, either
140
+ * passing through or being resolved out of the far face. Flag fast
141
+ * projectiles with {@link PhysicsBody.isBullet}: each of the body's colliders
142
+ * is then shape-cast along the step's motion (an exact translation-only sweep
143
+ * of the full shape, not just the centre) and clamped at the first impact.
144
+ * Rotation over the step is not swept - a long body spinning fast enough to
145
+ * sweep past an obstacle within one step can still miss it.
146
+ * - **{@link PhysicsWorldOptions.subStepCount}** - the default `4` is
105
147
  * load-bearing for tall-stack stability; lowering it below `2` visibly
106
148
  * degrades stacking, so do not reduce it for performance.
149
+ * - **Broad phase is a dynamic AABB tree** (`AabbTreeBroadPhase`), stateful
150
+ * across fixed steps: a collider whose tight AABB stays inside its stored
151
+ * fat AABB costs nothing to re-sync, and only colliders that actually move
152
+ * outside their margin trigger a tree update and a local re-query for new
153
+ * neighbours. Detection still walks every live collider once per step (a
154
+ * cheap containment check for each), so there is a small linear floor, but
155
+ * the dominant cost - reinsertion and neighbour discovery - is driven by
156
+ * how much actually moved, not by the total live collider count; sleeping
157
+ * bodies skip that dominant cost entirely. Scales to tens of thousands of
158
+ * simultaneously-live colliders, including dense clusters that would
159
+ * degrade a sort-and-sweep broad phase; very large or highly dynamic
160
+ * worlds may still benefit from splitting into several smaller
161
+ * `PhysicsWorld` instances (e.g. per room/chunk).
107
162
  */
108
163
  export declare class PhysicsWorld implements BodyOwner {
109
164
  /** Fires when two solid colliders begin touching. Argument is an immutable snapshot. */
@@ -132,9 +187,42 @@ export declare class PhysicsWorld implements BodyOwner {
132
187
  readonly sleepAngularVelocity: number;
133
188
  /** Seconds below the thresholds before a body sleeps. */
134
189
  readonly timeToSleep: number;
190
+ /**
191
+ * Runs once per solid contact per fixed step, after contact generation and
192
+ * before island building and the solver, so a contact it disables applies no
193
+ * impulse and does not couple its two bodies into one sleeping island.
194
+ *
195
+ * At most one modifier per world - it mutates simulation state, so a
196
+ * multi-listener signal would make the outcome depend on registration order.
197
+ * Set to `null` to remove it; the per-contact values then stay at the
198
+ * defaults derived from the two colliders.
199
+ */
200
+ contactModifier: ContactModifier | null;
201
+ /**
202
+ * Whether bound nodes are placed between the last two fixed states rather than
203
+ * snapped to the latest one. Toggleable at runtime; switching it off snaps
204
+ * every bound node back to the current fixed state on the next sync.
205
+ */
206
+ interpolation: boolean;
207
+ /**
208
+ * Supplies the `[0, 1)` blend factor for interpolated bindings. Defaults to
209
+ * this world's own accumulator; point it at the host's own fraction
210
+ * (`() => app.frameAlpha`) when the world runs as a `System`, because
211
+ * {@link fixedUpdate} never advances the local accumulator.
212
+ */
213
+ frameAlphaSource: () => number;
135
214
  private readonly _backend;
136
215
  private readonly _bodies;
137
216
  private readonly _colliders;
217
+ /**
218
+ * What detection actually runs over: the authored colliders, with a chain
219
+ * replaced by the edge proxies it fans out into. The broad phase, the narrow
220
+ * phase and the queries all read this list; `_colliders` stays the authored
221
+ * set every public surface reports.
222
+ */
223
+ private readonly _detectionColliders;
224
+ /** Pooled scratch for re-syncing a single body's broad-phase leaves. */
225
+ private readonly _leafScratch;
138
226
  private readonly _joints;
139
227
  private readonly _bindings;
140
228
  private readonly _query;
@@ -143,10 +231,32 @@ export declare class PhysicsWorld implements BodyOwner {
143
231
  private readonly _islandParent;
144
232
  /** Pooled per-island minimum sleep time, indexed by union-find root. */
145
233
  private readonly _islandMinSleep;
146
- /** Pooled ray-hit buffer + origin/direction for the CCD swept test. */
147
- private readonly _ccdHits;
148
- private readonly _ccdOrigin;
149
- private readonly _ccdDir;
234
+ /** Pooled scratch for the CCD pass (clamp target, per-pair sweep hit, best hit, swept AABB) - keeps the sweep allocation-free. */
235
+ private readonly _ccdClampPosition;
236
+ private readonly _ccdSweepHit;
237
+ private readonly _ccdBestHit;
238
+ private readonly _ccdSweptAabb;
239
+ /** Pooled result buffer for the CCD pass's broad-phase query (refilled per bullet collider). */
240
+ private readonly _ccdCandidates;
241
+ /**
242
+ * Narrow-phase sweep tests run by the CCD pass since world creation. Pairs
243
+ * rejected by the swept-AABB prune never count, so slow bullets far from any
244
+ * geometry keep this at zero (the cheap path).
245
+ *
246
+ * @internal - test/diagnostic hook.
247
+ */
248
+ _ccdSweepTests: number;
249
+ /**
250
+ * Colliders the CCD pass pulled out of the broad phase since world creation -
251
+ * the size of the candidate set the swept-AABB prune and the narrow-phase
252
+ * sweep then work on. Counted separately from {@link _ccdSweepTests} because
253
+ * the two measure different halves: this is what the pass looks at, that is
254
+ * what it actually sweeps. Stays proportional to the geometry near the
255
+ * bullets, not to the world's collider count.
256
+ *
257
+ * @internal - test/diagnostic hook.
258
+ */
259
+ _ccdBroadPhaseCandidates: number;
150
260
  private _nextBodyId;
151
261
  private _nextColliderId;
152
262
  private _dispatching;
@@ -156,11 +266,18 @@ export declare class PhysicsWorld implements BodyOwner {
156
266
  get bodies(): readonly PhysicsBody[];
157
267
  /** Live colliders (read-only view). */
158
268
  get colliders(): readonly Collider[];
269
+ /**
270
+ * @internal - the geometry the broad phase and the narrow phase actually hold:
271
+ * every authored collider, with a chain replaced by its per-edge proxies.
272
+ * Consumed by the debug draw layer, which visualises what the solver sees;
273
+ * public identity stays {@link colliders}.
274
+ */
275
+ get detectionGeometry(): readonly Collider[];
159
276
  /**
160
277
  * Add a body to the world: allocates the body and its collider ids, registers
161
278
  * the colliders, computes the mass model and tracks the body for stepping.
162
- * Construct the body freely first (`new PhysicsBody({ })`), then add it.
163
- * Safe to call inside an event callback the body push is deferred to the end
279
+ * Construct the body freely first (`new PhysicsBody({ ... })`), then add it.
280
+ * Safe to call inside an event callback - the body push is deferred to the end
164
281
  * of the step, exactly like collider registration. Returns the body.
165
282
  *
166
283
  * @throws if the body has already been added to a world.
@@ -170,16 +287,30 @@ export declare class PhysicsWorld implements BodyOwner {
170
287
  * Convenience: create a body carrying a single collider, add it to the world
171
288
  * and bind it to `node` in one call. The node tracks `body.position` after each
172
289
  * step. Returns the body. Equivalent to `new PhysicsBody(...)` + `add` + `bind`.
290
+ *
291
+ * When `options.position`/`options.angle` are omitted, the body starts at
292
+ * `node`'s current WORLD position/rotation (via `getWorldTransform()`,
293
+ * composed through any transform-group boundary) rather than `(0, 0)` -
294
+ * otherwise a body attached to an already-placed node would visibly "teleport"
295
+ * to the origin on the next step. Pass `position`/`angle` explicitly to override.
173
296
  */
174
297
  attach(node: SceneNode, options: AttachOptions): PhysicsBody;
175
- /** Destroy a body and its colliders. Deferred when called inside a callback. */
298
+ /**
299
+ * Destroy a body and its colliders. Every dynamic body touching it is woken,
300
+ * so anything that was resting on the destroyed body falls once its support is
301
+ * gone. Deferred when called inside a callback.
302
+ */
176
303
  destroyBody(body: PhysicsBody): void;
177
- /** Destroy a single collider, recomputing its body's mass. Deferred when called inside a callback. */
304
+ /**
305
+ * Destroy a single collider, recomputing its body's mass. Wakes every dynamic
306
+ * body touching it, the same way {@link destroyBody} does. Deferred when
307
+ * called inside a callback.
308
+ */
178
309
  destroyCollider(collider: Collider): void;
179
310
  /** Live joints (read-only view). */
180
311
  get joints(): readonly Joint[];
181
312
  /**
182
- * Add a constraint joint. Construct it first (`new DistanceJoint({ })`),
313
+ * Add a constraint joint. Construct it first (`new DistanceJoint({ ... })`),
183
314
  * then add it. Wakes both bodies; safe inside a callback (registration is
184
315
  * deferred). Returns the joint.
185
316
  */
@@ -192,24 +323,73 @@ export declare class PhysicsWorld implements BodyOwner {
192
323
  * gravity, solve contacts with a soft bias, integrate positions, relax) and a
193
324
  * restitution pass, then writes the accumulated motion into each body. Finally
194
325
  * dispatches events and writes bound node transforms.
326
+ *
327
+ * **Prefer registering the world as a system instead**
328
+ * (`app.systems.add(world, { order: SystemOrder.Physics })` or the scene
329
+ * equivalent) so {@link fixedUpdate} drives stepping directly from the
330
+ * engine's own fixed-timestep scheduler - one call per fixed step, no
331
+ * accumulator duplication. `step` remains available here for manual/advanced
332
+ * driving (e.g. a fixed-but-non-standard rate, or stepping outside the
333
+ * normal frame loop entirely): pass any delta and this accumulator converts
334
+ * it into the right number of fixed sub-steps (0, 1, or several, clamped by
335
+ * {@link PhysicsWorldOptions.maxSubSteps}).
336
+ *
337
+ * Either way the simulation is frame-rate independent and deterministic -
338
+ * the same sequence of deltas replays identically. `timeStepper.alpha`
339
+ * (`[0, 1)`) is the leftover sub-step fraction after this call, for callers
340
+ * that want to interpolate a bound node's rendered position between the last
341
+ * two fixed states instead of snapping to the latest one (bindings do not do
342
+ * this automatically - {@link bind} always writes the latest fixed-step
343
+ * transform verbatim).
195
344
  */
196
345
  step(frameDeltaSeconds: number): void;
197
- /** Link a body to a scene node; the node tracks the body after each step. */
346
+ /**
347
+ * Advance by exactly one fixed step, driven directly by the engine's own
348
+ * fixed-timestep scheduler when this world is registered as a `System`
349
+ * (`app.systems.add(world, { order: SystemOrder.Physics })` or the scene
350
+ * equivalent) - bypasses {@link timeStepper}'s variable-delta accumulator
351
+ * entirely, since the caller has already decided exactly when a fixed step
352
+ * occurs. Prefer this over manual {@link step} once the world is
353
+ * system-registered; `step` remains available for advanced manual driving.
354
+ * Always advances by exactly {@link timeStepper}'s configured `fixedDelta`,
355
+ * regardless of the caller's actual fixed-step interval - if the engine's
356
+ * `Application.fixedTimeStep` doesn't match this world's `fixedDelta`, the
357
+ * simulation stays deterministic but runs at the wrong wall-clock speed
358
+ * relative to real time.
359
+ */
360
+ fixedUpdate(_step: Seconds): void;
361
+ /**
362
+ * Variable-rate `System` phase: places bound nodes for the frame that is about
363
+ * to be drawn. Only does work while {@link interpolation} is on - otherwise
364
+ * {@link fixedUpdate} has already snapped them to the latest fixed state.
365
+ */
366
+ update(_delta: Seconds): void;
367
+ /** Present bound nodes, snapping or interpolating according to {@link interpolation}. */
368
+ private _syncBindings;
369
+ private _stepOnce;
370
+ /**
371
+ * Link a body to a scene node; the node tracks the body after each step.
372
+ * Destroying the node is enough to end the link - the next step drops it
373
+ * rather than writing into the node's released transform, so an explicit
374
+ * {@link unbind} is only needed to stop tracking a node that stays alive.
375
+ *
376
+ * @throws if `node` is already destroyed.
377
+ */
198
378
  bind(body: PhysicsBody, node: SceneNode): PhysicsBinding;
199
379
  /** Remove a body↔node link. */
200
380
  unbind(body: PhysicsBody): void;
201
381
  /** Colliders containing `point`. Fresh array. */
202
- queryPoint(point: VectorLike, filter?: QueryFilter): Collider[];
382
+ queryPoint(point: Readonly<PointLike>, filter?: QueryFilter): Collider[];
203
383
  /** Colliders whose AABB overlaps `bounds`. Writes into `out` (cleared) if given. */
204
- queryAabb(bounds: Aabb, filter?: QueryFilter, out?: Collider[]): Collider[];
384
+ queryAabb(bounds: AabbLike, filter?: QueryFilter, out?: Collider[]): Collider[];
205
385
  /** Invoke `callback` for each collider whose AABB overlaps `bounds`. Allocation-free. */
206
- forEachAabbHit(bounds: Aabb, filter: QueryFilter | undefined, callback: (collider: Collider) => void): void;
386
+ forEachAabbHit(bounds: AabbLike, filter: QueryFilter | undefined, callback: (collider: Collider) => void): void;
207
387
  /** Nearest collider hit by the ray, or `null`. */
208
- rayCast(origin: VectorLike, direction: VectorLike, filter?: QueryFilter, maxDistance?: number): RayHit | null;
388
+ rayCast(origin: Readonly<PointLike>, direction: Readonly<PointLike>, filter?: QueryFilter, maxDistance?: number): RayHit | null;
209
389
  /** All collider hits along the ray, sorted by distance. Writes into `out` (cleared) if given. */
210
- rayCastAll(origin: VectorLike, direction: VectorLike, filter?: QueryFilter, out?: RayHit[], maxDistance?: number): RayHit[];
390
+ rayCastAll(origin: Readonly<PointLike>, direction: Readonly<PointLike>, filter?: QueryFilter, out?: RayHit[], maxDistance?: number): RayHit[];
211
391
  /** Colliders overlapping `shape` placed at `position`/`angle`. Fresh array. */
212
- overlapShape(shape: AnyShape, position: VectorLike, filter?: QueryFilter, angle?: number): Collider[];
392
+ overlapShape(shape: AnyShape, position: Readonly<PointLike>, filter?: QueryFilter, angle?: number): Collider[];
213
393
  /** Release every body, collider, binding and backend resource. */
214
394
  destroy(): void;
215
395
  _allocateColliderId(): number;
@@ -224,10 +404,28 @@ export declare class PhysicsWorld implements BodyOwner {
224
404
  * kinematic bodies are boundaries, not nodes); it sleeps once every member has
225
405
  * stayed below the sleep thresholds for `timeToSleep`, and wakes the instant
226
406
  * any member does (e.g. an awake body merges into it via a new contact).
407
+ * A boundary that is itself moving resets the sleep timer of every dynamic
408
+ * body it touches, so a platform keeps its passengers awake however slowly it
409
+ * travels; so does a contact still carrying more penetration than the solver
410
+ * leaves at rest, because the push-out that resolves it is slower than the
411
+ * sleep velocity threshold and a body would otherwise be frozen embedded.
227
412
  * Deterministic: union-find roots break ties by lower index and the contact
228
413
  * set is id-sorted.
229
414
  */
230
415
  private _updateSleeping;
416
+ /**
417
+ * Union dynamic↔dynamic solid contacts into islands. A dynamic body touching a
418
+ * MOVING static/kinematic body has its sleep timer reset instead: those types
419
+ * are island boundaries, not members, so nothing else would keep the passenger
420
+ * of a slow-moving platform awake - and the solver skips a contact whose
421
+ * dynamic side is asleep, letting the platform drive straight through it.
422
+ *
423
+ * The same traversal resets the sleep timer of both sides of a contact whose
424
+ * penetration the solver has not worked off yet, so the island it belongs to
425
+ * stays awake until the overlap is within the tolerance the solver itself
426
+ * converges to.
427
+ */
428
+ private _unionContactIslands;
231
429
  /** Union-find union by lower index (deterministic roots). */
232
430
  private _union;
233
431
  /** Union-find find with path halving. */
@@ -243,14 +441,27 @@ export declare class PhysicsWorld implements BodyOwner {
243
441
  /** Snapshot each bullet's centre of mass at the start of the fixed step (the swept-test origin). */
244
442
  private _recordBulletPositions;
245
443
  /**
246
- * Sweep each bullet's centre of mass along this fixed step's motion against every
247
- * other body's colliders; if it would cross one, clamp the body just short of the
248
- * surface and resolve the impact about the surface normal (a slide for a non-bouncy
249
- * body, an elastic reflection as restitution → 1) so it cannot tunnel. Sweeps the
250
- * centre point good for small/point-like projectiles; a full swept-shape TOI for
251
- * large fast bodies is backlog (raise sub-steps or thicken geometry meanwhile).
444
+ * Shape-cast each bullet's colliders along this fixed step's motion against
445
+ * every other body's colliders; if any would cross one, clamp the body at the
446
+ * earliest impact and resolve it about the surface normal (a slide for a
447
+ * non-bouncy body, an elastic reflection as restitution → 1) so it cannot
448
+ * tunnel. The sweep is an exact translation-only cast of the full shapes
449
+ * (Minkowski ray for circles, swept SAT for polygon pairs) - the step's
450
+ * rotation is applied before the sweep, not swept through. Pairs already
451
+ * overlapping at the start of the step are skipped: the discrete solver owns
452
+ * them (that hand-off is what lets a landed bullet rest on real contacts).
453
+ * Filters and sensors behave exactly as in the discrete narrow phase.
252
454
  */
253
455
  private _advanceBullets;
456
+ /**
457
+ * Find the earliest impact for a bullet whose colliders translated by
458
+ * `(dx, dy)` this step. Each of the bullet's colliders queries the broad
459
+ * phase with its swept AABB, so the pass costs what the geometry around the
460
+ * bullet's path costs - not one iteration per collider in the world. Returns
461
+ * the blocking collider (with the impact written into {@link _ccdBestHit}),
462
+ * or `null` when nothing blocks the motion.
463
+ */
464
+ private _sweepBulletColliders;
254
465
  /** The highest restitution among a body's colliders (its CCD bounce factor). */
255
466
  private _bulletRestitution;
256
467
  /** Run `command` now, or queue it when inside an event dispatch (deferred to end of step). */
@@ -260,5 +471,27 @@ export declare class PhysicsWorld implements BodyOwner {
260
471
  private _teardownBody;
261
472
  private _removeCollider;
262
473
  private _detachCollider;
474
+ /** Drop one broad-phase leaf: an authored collider, or one chain edge proxy. */
475
+ private _removeDetectionCollider;
476
+ /**
477
+ * The broad-phase leaves of one body - its colliders, with a chain replaced by
478
+ * its edge proxies. Returns pooled scratch, valid until the next call.
479
+ */
480
+ private _detectionLeavesOf;
481
+ /**
482
+ * Wake every dynamic body still touching `collider` at the moment it leaves
483
+ * the world. A sleeping body's sleep timer is frozen, so the island pass alone
484
+ * can never re-open its sleep decision: losing the support it rested on just
485
+ * removes a contact, and the island (now smaller, or a lone body) still reports
486
+ * a long-expired timer and is put straight back to sleep - a stack whose floor,
487
+ * platform or bottom box is destroyed would hang in mid-air forever. Kinematic
488
+ * and static supports are the sharp edge, since they are island boundaries
489
+ * rather than nodes and so are invisible to wake propagation, but the same hole
490
+ * exists for a dynamic support. Waking the far side of each contact is enough:
491
+ * the woken body's reset timer propagates through the rest of its sleeping
492
+ * island on the next step, exactly like any other wake event.
493
+ */
494
+ private _wakeTouchingBodies;
263
495
  private _assertAlive;
264
496
  }
497
+ //# sourceMappingURL=PhysicsWorld.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PhysicsWorld.d.ts","sourceRoot":"","sources":["../../src/PhysicsWorld.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAU,MAAM,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAIvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAoB,QAAQ,EAAE,MAAM,YAAY,CAAC;AAIxD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAE/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AA8JzD,uDAAuD;AACvD,MAAM,WAAW,mBAAmB;IAClC,8EAA8E;IAC9E,OAAO,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC9B,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,6GAA6G;IAC7G,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sFAAsF;IACtF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wFAAwF;IACxF,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,eAAe,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IACzC;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,MAAM,MAAM,CAAC;IAChC,qFAAqF;IACrF,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,0FAA0F;IAC1F,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,2FAA2F;IAC3F,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,0IAA0I;IAC1I,QAAQ,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC/B,wGAAwG;IACxG,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,6BAA6B;IAC7B,KAAK,EAAE,QAAQ,CAAC;IAChB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC7B,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mGAAmG;IACnG,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AACH,qBAAa,YAAa,YAAW,SAAS;IAC5C,wFAAwF;IACxF,SAAgB,gBAAgB,2BAAkC;IAClE,0EAA0E;IAC1E,SAAgB,cAAc,2BAAkC;IAChE,6CAA6C;IAC7C,SAAgB,aAAa,wBAA+B;IAC5D,6CAA6C;IAC7C,SAAgB,YAAY,wBAA+B;IAE3D,gEAAgE;IAChE,SAAgB,OAAO,EAAE,MAAM,CAAC;IAChC,kCAAkC;IAClC,SAAgB,WAAW,EAAE,WAAW,CAAC;IACzC,yCAAyC;IACzC,SAAgB,YAAY,EAAE,MAAM,CAAC;IACrC,oCAAoC;IACpC,SAAgB,YAAY,EAAE,MAAM,CAAC;IACrC,kCAAkC;IAClC,SAAgB,YAAY,EAAE,MAAM,CAAC;IACrC,+CAA+C;IAC/C,SAAgB,cAAc,EAAE,OAAO,CAAC;IACxC,qCAAqC;IACrC,SAAgB,mBAAmB,EAAE,MAAM,CAAC;IAC5C,uCAAuC;IACvC,SAAgB,oBAAoB,EAAE,MAAM,CAAC;IAC7C,yDAAyD;IACzD,SAAgB,WAAW,EAAE,MAAM,CAAC;IAEpC;;;;;;;;;OASG;IACI,eAAe,EAAE,eAAe,GAAG,IAAI,CAAC;IAE/C;;;;OAIG;IACI,aAAa,EAAE,OAAO,CAAC;IAE9B;;;;;OAKG;IACI,gBAAgB,EAAE,MAAM,MAAM,CAAC;IAEtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8C;IACvE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkB;IAC7C;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAkB;IACtD,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkB;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;IACnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;IACnD,qGAAqG;IACrG,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAgB;IAChD,kIAAkI;IAClI,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAkB;IACpD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA8C;IAC3E,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA8C;IAC1E,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA0B;IACxD,gGAAgG;IAChG,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAkB;IAEjD;;;;;;OAMG;IACI,cAAc,SAAK;IAE1B;;;;;;;;;OASG;IACI,wBAAwB,SAAK;IAEpC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,UAAU,CAAS;gBAER,OAAO,GAAE,mBAAwB;IA0BpD,oCAAoC;IACpC,IAAW,MAAM,IAAI,SAAS,WAAW,EAAE,CAE1C;IAED,uCAAuC;IACvC,IAAW,SAAS,IAAI,SAAS,QAAQ,EAAE,CAE1C;IAED;;;;;OAKG;IACH,IAAW,iBAAiB,IAAI,SAAS,QAAQ,EAAE,CAElD;IAID;;;;;;;;OAQG;IACI,GAAG,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW;IAqB1C;;;;;;;;;;OAUG;IACI,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,GAAG,WAAW;IA2BnE;;;;OAIG;IACI,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IAI3C;;;;OAIG;IACI,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAQhD,oCAAoC;IACpC,IAAW,MAAM,IAAI,SAAS,KAAK,EAAE,CAEpC;IAED;;;;OAIG;IACI,QAAQ,CAAC,CAAC,SAAS,KAAK,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC;IAc7C,yHAAyH;IAClH,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAetC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACI,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI;IA4B5C;;;;;;;;;;;;;OAaG;IACI,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAoBxC;;;;OAIG;IACI,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAQpC,yFAAyF;IACzF,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,SAAS;IA4FjB;;;;;;;OAOG;IACI,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,GAAG,cAAc;IAI/D,+BAA+B;IACxB,MAAM,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IAMtC,iDAAiD;IAC1C,UAAU,CAAC,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,QAAQ,EAAE;IAI/E,oFAAoF;IAC7E,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE;IAItF,yFAAyF;IAClF,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,GAAG,SAAS,EAAE,QAAQ,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI;IAItH,kDAAkD;IAC3C,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAItI,iGAAiG;IAC1F,UAAU,CAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE;IAIpJ,+EAA+E;IACxE,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,EAAE;IAIrH,kEAAkE;IAC3D,OAAO,IAAI,IAAI;IAoCf,mBAAmB,IAAI,MAAM;IAI7B,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAwBlD,0EAA0E;IAC1E,IAAW,OAAO,IAAI,cAAc,CAEnC;IAED,OAAO,CAAC,eAAe;IAwBvB;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,eAAe;IA6DvB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,oBAAoB;IAqC5B,6DAA6D;IAC7D,OAAO,CAAC,MAAM;IAWd,yCAAyC;IACzC,OAAO,CAAC,KAAK;IAYb,0EAA0E;IAC1E,OAAO,CAAC,cAAc;IAMtB,iEAAiE;IACjE,OAAO,CAAC,gBAAgB;IAMxB,mEAAmE;IACnE,OAAO,CAAC,YAAY;IAMpB,kFAAkF;IAClF,OAAO,CAAC,WAAW;IAUnB,oGAAoG;IACpG,OAAO,CAAC,sBAAsB;IAS9B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,eAAe;IA6DvB;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB;IAgE7B,gFAAgF;IAChF,OAAO,CAAC,kBAAkB;IAY1B,8FAA8F;IAC9F,OAAO,CAAC,MAAM;IAQd,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,WAAW;IAenB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,eAAe;IAsBvB,gFAAgF;IAChF,OAAO,CAAC,wBAAwB;IAUhC;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAsB1B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,mBAAmB;IAqB3B,OAAO,CAAC,YAAY;CAKrB"}