@forgeax/engine-physics 0.1.29 → 0.1.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -0
- package/dist/derived-physics.d.ts +5 -0
- package/dist/derived-physics.d.ts.map +1 -1
- package/dist/index.d.ts +12 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +14 -3
- package/dist/index.mjs.map +1 -1
- package/dist/physics-world.d.ts +22 -1
- package/dist/physics-world.d.ts.map +1 -1
- package/dist/plugin-factory.d.ts +1 -1
- package/dist/plugin-factory.d.ts.map +1 -1
- package/package.json +12 -12
- package/src/derived-physics.ts +19 -5
- package/src/index.ts +12 -12
- package/src/physics-world.ts +26 -1
- package/src/plugin-factory.ts +3 -3
package/README.md
CHANGED
|
@@ -250,6 +250,26 @@ The borrowed `getDerivedAdmission(entity)` proof exists only in that interval;
|
|
|
250
250
|
publications remain unavailable until the normal step/writeback boundary. See the
|
|
251
251
|
[paired Render example](../render/README.md#paired-physics-admission).
|
|
252
252
|
|
|
253
|
+
For splits or replacements across several bodies, use
|
|
254
|
+
`admitDerivedShapeCandidates(candidates, commitGeometry)`. A nonempty group uses
|
|
255
|
+
one existing candidate slot per distinct body (at most 32); constraint identities
|
|
256
|
+
must also be unique. The backend validates the projected endpoint revisions,
|
|
257
|
+
stages every member, then invokes one callback. `getDerivedAdmission(entity)`
|
|
258
|
+
exposes each member only during that callback. A kth-member native failure or a
|
|
259
|
+
returned geometry failure restores every earlier member; an uncertain rollback
|
|
260
|
+
blocks the whole PhysicsWorld for reconstruction. Cancelling or destroying one
|
|
261
|
+
unpublished member cancels/rejects the entire group. Snapshot restoration uses
|
|
262
|
+
the same group path, including constraints referencing multiple restored bodies.
|
|
263
|
+
|
|
264
|
+
An empty `shapes` array clears a body's derived collision set. It neither removes
|
|
265
|
+
an ordinary Collider nor destroys the ECS entity; the consumer retires its
|
|
266
|
+
render/body binding after the matching publication. Optional `motion.rotation`
|
|
267
|
+
is a world-space xyzw quaternion, normalized and copied at preparation. It is
|
|
268
|
+
applied together with COM and velocity before step and restored on rollback.
|
|
269
|
+
Omitting it preserves the body's current orientation. Captured derived motion
|
|
270
|
+
includes the current native orientation so restored or newly split bodies do not
|
|
271
|
+
implicitly inherit the orientation of an unrelated placeholder entity.
|
|
272
|
+
|
|
253
273
|
| Paired result | Observable state |
|
|
254
274
|
|:--|:--|
|
|
255
275
|
| Native staging fails | Geometry commit not called; old state retained or explicit rebuild required |
|
|
@@ -346,3 +366,24 @@ state and exposes `old-state-retained`, or reports `rebuild-required` and blocks
|
|
|
346
366
|
queries; it is never reported as a ready partial commit. Device or World teardown
|
|
347
367
|
invalidates pending work; the 2D `PhysicsWorld2D` contract remains unchanged and
|
|
348
368
|
does not pretend to support 3D voxel shapes.
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
### Bounded interaction impulses
|
|
372
|
+
|
|
373
|
+
`PhysicsWorld.applyDerivedImpulse` applies a world-space impulse at a world-space
|
|
374
|
+
point on a committed dynamic derived body. The caller supplies its exact
|
|
375
|
+
`sourceKey` and `revision`; stale ownership, pending admission, invalid vectors,
|
|
376
|
+
and non-dynamic bodies are refused. Apply it in a FixedUpdate system after
|
|
377
|
+
`physicsSyncBackend` and before `physicsStepSimulation`, bounding magnitude to
|
|
378
|
+
`maxForce * FixedTime.delta`. It changes native velocity, including the lever-arm
|
|
379
|
+
angular response, without teleporting the body. A partial native failure marks
|
|
380
|
+
the PhysicsWorld as requiring recovery. This is an optional backend capability;
|
|
381
|
+
Rapier 3D implements it. Native integration consumes that same fixed delta.
|
|
382
|
+
|
|
383
|
+
Contact observations carry optional world-space surface samples, with the normal
|
|
384
|
+
oriented from entityA toward entityB. Rapier prefers solver contact points; when
|
|
385
|
+
a manifold contains only geometric contacts, the backend can transform a point
|
|
386
|
+
from an ordinary ball, box, or capsule collider. Composite-only contacts without
|
|
387
|
+
solver points remain unsampled because subshape coordinates are not collider
|
|
388
|
+
coordinates. Consumers must handle absent points, including sensor transitions,
|
|
389
|
+
and must not infer impact energy or a solver impulse from a started event.
|
|
@@ -55,6 +55,8 @@ export interface DerivedPhysicsMotion {
|
|
|
55
55
|
readonly centerOfMass: PhysicsVector;
|
|
56
56
|
readonly linearVelocity: PhysicsVector;
|
|
57
57
|
readonly angularVelocity: PhysicsVector;
|
|
58
|
+
/** World-space xyzw orientation; omitted input preserves the native orientation. */
|
|
59
|
+
readonly rotation?: PhysicsQuaternion;
|
|
58
60
|
}
|
|
59
61
|
/** Stable, consumer-owned constraint input. */
|
|
60
62
|
export type PhysicsConstraintInput = {
|
|
@@ -88,6 +90,7 @@ export interface DerivedPhysicsCandidateInput {
|
|
|
88
90
|
readonly entity: number;
|
|
89
91
|
readonly revision: number;
|
|
90
92
|
readonly sourceKey: string;
|
|
93
|
+
/** Empty clears derived shapes; ordinary colliders and ECS body lifetime remain independent. */
|
|
91
94
|
readonly shapes: readonly VoxelShapeInput[];
|
|
92
95
|
readonly seams?: readonly DerivedShapeSeamInput[];
|
|
93
96
|
readonly bodyType?: 'static' | 'dynamic' | 'kinematic';
|
|
@@ -153,7 +156,9 @@ export interface PhysicsContactObservation {
|
|
|
153
156
|
readonly entityB: number;
|
|
154
157
|
readonly shapeA?: string;
|
|
155
158
|
readonly shapeB?: string;
|
|
159
|
+
/** World-space contact sample from either surface, when available. */
|
|
156
160
|
readonly point?: PhysicsVector;
|
|
161
|
+
/** World-space normal oriented from entityA toward entityB, when available. */
|
|
157
162
|
readonly normal?: PhysicsVector;
|
|
158
163
|
}
|
|
159
164
|
/** Portable recovery input produced from a committed derived state. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derived-physics.d.ts","sourceRoot":"","sources":["../src/derived-physics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAE7D,0CAA0C;AAC1C,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAE1D,4DAA4D;AAC5D,MAAM,MAAM,iBAAiB,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAE1E,wEAAwE;AACxE,MAAM,MAAM,aAAa,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAE9D;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,SAAS,EAAE,CAAC;IAClD,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,yEAAyE;AACzE,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,8DAA8D;AAC9D,MAAM,MAAM,qBAAqB,GAC7B;IACE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC;IACrC,QAAQ,CAAC,gBAAgB,EAAE,aAAa,CAAC;IACzC,QAAQ,CAAC,0BAA0B,CAAC,EAAE,iBAAiB,CAAC;CACzD,CAAC;AAEN,sEAAsE;AACtE,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,OAAO,CAAC;AAEzD;;;;;;;;GAQG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC;IACrC,QAAQ,CAAC,cAAc,EAAE,aAAa,CAAC;IACvC,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"derived-physics.d.ts","sourceRoot":"","sources":["../src/derived-physics.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export type { CollisionEventPayload } from './collision-event';
|
|
2
|
-
export { CollisionEvent } from './collision-event';
|
|
3
|
-
export type { ColliderShape, RigidBodyType } from './components';
|
|
4
|
-
export { CharacterController, COLLIDER_SHAPE_CAPSULE, COLLIDER_SHAPE_CUBOID, COLLIDER_SHAPE_SPHERE, Collider, ColliderShapeValue, CollidingEntities, colliderShapeFromF32, RIGID_BODY_TYPE_DYNAMIC, RIGID_BODY_TYPE_KINEMATIC, RIGID_BODY_TYPE_STATIC, RigidBody, RigidBodyTypeValue, registerPhysicsComponents, rigidBodyTypeFromF32, } from './components';
|
|
5
|
-
export type { DerivedPhysicsCandidate, DerivedPhysicsCandidateInput, DerivedPhysicsCandidateState, DerivedPhysicsErrorCode, DerivedPhysicsErrorDetail, DerivedPhysicsFailure, DerivedPhysicsMotion, DerivedPhysicsPublication, DerivedPhysicsSnapshot, DerivedShapeSeamInput, DerivedShapeState, PhysicsConstraintBodyDependency, PhysicsConstraintInput, PhysicsContactObservation, PhysicsMassProperties, PhysicsQuaternion, PhysicsVector, PhysicsVelocityPolicy, VoxelCell, VoxelShapeInput, } from './derived-physics';
|
|
6
|
-
export { cloneDerivedPhysicsInput, DERIVED_PHYSICS_LIMITS, DerivedPhysicsError, estimateDerivedPhysicsInputBytes, normalizeVoxelShapeInput, preserveCenterOfMassVelocity, validateMassProperties, } from './derived-physics';
|
|
7
|
-
export type { PhysicsErrorCode, PhysicsErrorDetail } from './errors';
|
|
8
|
-
export { PHYSICS_ERROR_HINTS, PhysicsError } from './errors';
|
|
9
|
-
export type { PhysicsWorld, PhysicsWorld2D, RaycastHit, RaycastHit2D } from './physics-world';
|
|
10
|
-
export type { PhysicsBackend } from './plugin-factory';
|
|
11
|
-
export { physicsPlugin } from './plugin-factory';
|
|
12
|
-
export { PhysicsSet } from './system-set';
|
|
1
|
+
export type { CollisionEventPayload } from './collision-event.js';
|
|
2
|
+
export { CollisionEvent } from './collision-event.js';
|
|
3
|
+
export type { ColliderShape, RigidBodyType } from './components.js';
|
|
4
|
+
export { CharacterController, COLLIDER_SHAPE_CAPSULE, COLLIDER_SHAPE_CUBOID, COLLIDER_SHAPE_SPHERE, Collider, ColliderShapeValue, CollidingEntities, colliderShapeFromF32, RIGID_BODY_TYPE_DYNAMIC, RIGID_BODY_TYPE_KINEMATIC, RIGID_BODY_TYPE_STATIC, RigidBody, RigidBodyTypeValue, registerPhysicsComponents, rigidBodyTypeFromF32, } from './components.js';
|
|
5
|
+
export type { DerivedPhysicsCandidate, DerivedPhysicsCandidateInput, DerivedPhysicsCandidateState, DerivedPhysicsErrorCode, DerivedPhysicsErrorDetail, DerivedPhysicsFailure, DerivedPhysicsMotion, DerivedPhysicsPublication, DerivedPhysicsSnapshot, DerivedShapeSeamInput, DerivedShapeState, PhysicsConstraintBodyDependency, PhysicsConstraintInput, PhysicsContactObservation, PhysicsMassProperties, PhysicsQuaternion, PhysicsVector, PhysicsVelocityPolicy, VoxelCell, VoxelShapeInput, } from './derived-physics.js';
|
|
6
|
+
export { cloneDerivedPhysicsInput, DERIVED_PHYSICS_LIMITS, DerivedPhysicsError, estimateDerivedPhysicsInputBytes, normalizeVoxelShapeInput, preserveCenterOfMassVelocity, validateMassProperties, } from './derived-physics.js';
|
|
7
|
+
export type { PhysicsErrorCode, PhysicsErrorDetail } from './errors.js';
|
|
8
|
+
export { PHYSICS_ERROR_HINTS, PhysicsError } from './errors.js';
|
|
9
|
+
export type { PhysicsWorld, PhysicsWorld2D, RaycastHit, RaycastHit2D } from './physics-world.js';
|
|
10
|
+
export type { PhysicsBackend } from './plugin-factory.js';
|
|
11
|
+
export { physicsPlugin } from './plugin-factory.js';
|
|
12
|
+
export { PhysicsSet } from './system-set.js';
|
|
13
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,YAAY,EAAE,qBAAqB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,YAAY,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,qBAAqB,EACrB,QAAQ,EACR,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,uBAAuB,EACvB,yBAAyB,EACzB,sBAAsB,EACtB,SAAS,EACT,kBAAkB,EAClB,yBAAyB,EACzB,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,uBAAuB,EACvB,4BAA4B,EAC5B,4BAA4B,EAC5B,uBAAuB,EACvB,yBAAyB,EACzB,qBAAqB,EACrB,oBAAoB,EACpB,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACrB,iBAAiB,EACjB,+BAA+B,EAC/B,sBAAsB,EACtB,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,aAAa,EACb,qBAAqB,EACrB,SAAS,EACT,eAAe,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,mBAAmB,EACnB,gCAAgC,EAChC,wBAAwB,EACxB,4BAA4B,EAC5B,sBAAsB,GACvB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAExE,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACjG,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/index.mjs
CHANGED
|
@@ -333,11 +333,11 @@ function cloneDerivedPhysicsInput(input) {
|
|
|
333
333
|
)
|
|
334
334
|
);
|
|
335
335
|
}
|
|
336
|
-
if (input.shapes.length
|
|
336
|
+
if (input.shapes.length > DERIVED_PHYSICS_LIMITS.maxShapesPerCandidate) {
|
|
337
337
|
return err(
|
|
338
338
|
new DerivedPhysicsError(
|
|
339
339
|
"derived-candidate-budget-exceeded",
|
|
340
|
-
`one candidate contains
|
|
340
|
+
`one candidate contains at most ${DERIVED_PHYSICS_LIMITS.maxShapesPerCandidate} derived shapes`,
|
|
341
341
|
"split the consumer operation at a body boundary and retry",
|
|
342
342
|
{ entity: input.entity, actual: input.shapes.length }
|
|
343
343
|
)
|
|
@@ -361,6 +361,16 @@ function cloneDerivedPhysicsInput(input) {
|
|
|
361
361
|
if (!normalized.ok) return normalized;
|
|
362
362
|
shapes.push(normalized.value);
|
|
363
363
|
}
|
|
364
|
+
const motionRotation = input.motion?.rotation === void 0 ? void 0 : normalizedQuaternion(input.motion.rotation);
|
|
365
|
+
if (input.motion?.rotation !== void 0 && motionRotation === void 0)
|
|
366
|
+
return err(
|
|
367
|
+
new DerivedPhysicsError(
|
|
368
|
+
"derived-candidate-invalid",
|
|
369
|
+
"optional motion rotation is a finite non-degenerate world-space quaternion",
|
|
370
|
+
"supply a valid xyzw body orientation or omit it to preserve the native orientation",
|
|
371
|
+
{ entity: input.entity, actual: input.motion.rotation }
|
|
372
|
+
)
|
|
373
|
+
);
|
|
364
374
|
const mass = validateMassProperties(input.massProperties);
|
|
365
375
|
if (!mass.ok) return mass;
|
|
366
376
|
if (input.motion !== void 0 && (!vectorFinite(input.motion.centerOfMass, 3) || !vectorFinite(input.motion.linearVelocity, 3) || !vectorFinite(input.motion.angularVelocity, 3))) {
|
|
@@ -481,7 +491,8 @@ function cloneDerivedPhysicsInput(input) {
|
|
|
481
491
|
motion: Object.freeze({
|
|
482
492
|
centerOfMass: [...input.motion.centerOfMass],
|
|
483
493
|
linearVelocity: [...input.motion.linearVelocity],
|
|
484
|
-
angularVelocity: [...input.motion.angularVelocity]
|
|
494
|
+
angularVelocity: [...input.motion.angularVelocity],
|
|
495
|
+
...motionRotation === void 0 ? {} : { rotation: motionRotation }
|
|
485
496
|
})
|
|
486
497
|
},
|
|
487
498
|
constraints: Object.freeze([...constraints]),
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/collision-event.ts","../src/components.ts","../src/derived-physics.ts","../src/load-rapier-backend.mjs","../src/plugin-factory.ts","../src/system-set.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["// @forgeax/engine-physics — CollisionEvent ECS Event token placeholder.\n//\n// Emitted by physics tick systems during the Writeback phase.\n// Two states only: 'started' (new contact) and 'stopped' (separated).\n// No 'continued' event — use CollidingEntities component for ongoing contacts\n// (plan-strategy D-3).\n\nimport type { Vec3 } from '@forgeax/engine-math';\n\n/**\n * Collision event payload — per-contact-pair event emitted during Writeback.\n *\n * `type: 'started'` — two colliders just began touching.\n * `type: 'stopped'` — two colliders just separated.\n */\nexport interface CollisionEventPayload {\n type: 'started' | 'stopped';\n entityA: number;\n entityB: number;\n contactPoint: Vec3;\n contactNormal: Vec3;\n}\n\n/**\n * CollisionEvent constant — identifies the collision event type.\n * Backend systems push CollisionEventPayload instances into the event queue\n * during the Writeback phase; user systems drain via query.\n *\n * The backing ECS event infrastructure (Event<T> generic + world.drainEvent)\n * is deferred to a future feat. For M1, this is a type-only contract.\n */\nexport const CollisionEvent = '__CollisionEvent__' as const;\n\n/** Type-level identifier for the CollisionEvent event channel. */\nexport type CollisionEvent = typeof CollisionEvent;\n","// @forgeax/engine-physics — ECS Component schemas.\n//\n// RigidBody and Collider are the two user-facing entry points; AI users\n// spawn entities with these components to opt into physics simulation.\n// CollidingEntities is the runtime set-query component for continuous\n// collision status (started/stopped model, no 'continued' event).\n\nimport { type Component, defineComponent, type World } from '@forgeax/engine-ecs';\n\n/**\n * RigidBody motion type — 3-state discriminant mirroring Rapier's\n * Dynamic / Fixed / KinematicPositionBased triplet.\n *\n * `'static'`: infinite mass, never moves (Rapier Fixed).\n * `'dynamic'`: driven by forces, gravity, collisions (Rapier Dynamic).\n * `'kinematic'`: user-controlled position, velocity derived by engine\n * (Rapier KinematicPositionBased).\n */\nexport type RigidBodyType = 'static' | 'dynamic' | 'kinematic';\n\n/**\n * Collider shape discriminant — 3 AI-friendly shape names.\n *\n * `'cuboid'`: box shape defined by half-extents (x, y, z).\n * `'sphere'`: sphere defined by radius.\n * `'capsule'`: capsule defined by half-height + radius.\n *\n * Named `'sphere'` not `'ball'` per plan-strategy D-5: AI users see\n * the familiar geometric term; backend maps to Rapier `ColliderDesc.ball()`.\n */\nexport type ColliderShape = 'cuboid' | 'sphere' | 'capsule';\n\n// ─── D-3: numeric enum constants + narrowing helpers ─────────────────────\n//\n// Aligned with `packages/runtime/src/components/camera.ts:41-53`\n// `cameraProjectionFromF32` pattern. The ECS `enum` field maps to `number`\n// (Uint32Array column); these constants let AI users write\n// `{ type: RigidBodyTypeValue.dynamic }` instead of bare magic numbers,\n// and the narrowing helpers let backends switch cleanly on the string union.\n//\n// Declared BEFORE the RigidBody / Collider components so each component's enum\n// field descriptor can reference the SAME `*Value` map as its `labels`\n// (Derive, don't Duplicate — one object is both the AI-facing const AND the\n// schema-projected label map that `describeComponent` surfaces).\n\n/** Numeric value for static rigid body (Rapier Fixed). */\nexport const RIGID_BODY_TYPE_STATIC = 0;\n/** Numeric value for dynamic rigid body (Rapier Dynamic). */\nexport const RIGID_BODY_TYPE_DYNAMIC = 1;\n/** Numeric value for kinematic rigid body (Rapier KinematicPositionBased). */\nexport const RIGID_BODY_TYPE_KINEMATIC = 2;\n\nexport const RigidBodyTypeValue = {\n static: RIGID_BODY_TYPE_STATIC,\n dynamic: RIGID_BODY_TYPE_DYNAMIC,\n kinematic: RIGID_BODY_TYPE_KINEMATIC,\n} as const;\n\nexport function rigidBodyTypeFromF32(n: number): RigidBodyType {\n if (n === RIGID_BODY_TYPE_DYNAMIC) return 'dynamic';\n if (n === RIGID_BODY_TYPE_KINEMATIC) return 'kinematic';\n return 'static';\n}\n\n/** Numeric value for cuboid collider shape. */\nexport const COLLIDER_SHAPE_CUBOID = 0;\n/** Numeric value for sphere collider shape. */\nexport const COLLIDER_SHAPE_SPHERE = 1;\n/** Numeric value for capsule collider shape. */\nexport const COLLIDER_SHAPE_CAPSULE = 2;\n\nexport const ColliderShapeValue = {\n cuboid: COLLIDER_SHAPE_CUBOID,\n sphere: COLLIDER_SHAPE_SPHERE,\n capsule: COLLIDER_SHAPE_CAPSULE,\n} as const;\n\nexport function colliderShapeFromF32(n: number): ColliderShape {\n if (n === COLLIDER_SHAPE_SPHERE) return 'sphere';\n if (n === COLLIDER_SHAPE_CAPSULE) return 'capsule';\n return 'cuboid';\n}\n\n/**\n * ECS Component: rigid body physics properties.\n *\n * AI user entry point — spawn with `world.spawn(RigidBody({ type: 'dynamic' }))`\n * to opt an entity into physics simulation.\n *\n * | Field | Type | Default | Purpose |\n * |:--|:--|:--|:--|\n * | `type` | `RigidBodyType` | `'dynamic'` | Motion type discriminant |\n * | `mass` | `number` | `1.0` | Linear mass (> 0 for dynamic) |\n * | `linearDamping` | `number` | `0.0` | Velocity damping factor [0, 1] |\n * | `angularDamping` | `number` | `0.0` | Angular velocity damping [0, 1] |\n * | `gravityScale` | `number` | `1.0` | Per-body gravity multiplier |\n * | `ccdEnabled` | `boolean` | `false` | Continuous collision detection |\n *\n * `type` declares `labels: RigidBodyTypeValue` so `describeComponent` projects\n * the `static=0 / dynamic=1 / kinematic=2` map through the front door — an AI\n * learns the legal variants from the schema, not from engine source.\n */\nexport const RigidBody = defineComponent('RigidBody', {\n type: { type: 'enum', default: RIGID_BODY_TYPE_DYNAMIC, labels: RigidBodyTypeValue },\n mass: { type: 'f32', default: 1 },\n linearDamping: { type: 'f32', default: 0 },\n angularDamping: { type: 'f32', default: 0 },\n gravityScale: { type: 'f32', default: 1 },\n ccdEnabled: { type: 'bool', default: false },\n});\n\n/**\n * ECS Component: collision geometry.\n *\n * Spawn alongside RigidBody to give an entity a collision shape. Entities\n * with Collider but no RigidBody are treated as static colliders (Rapier\n * native behavior — collider without parent body is fixed): `physicsSyncBackend`\n * synthesizes an implicit static body for them, so a bare-Collider floor/wall is\n * simulated as immovable level geometry — the natural way to author static\n * scenery without a redundant `RigidBody{static}`.\n *\n * | Field | Type | Default | Purpose |\n * |:--|:--|:--|:--|\n * | `shape` | `ColliderShape` | — | Shape discriminant |\n * | `halfExtents` | `[number, number, number]` | `[0.5, 0.5, 0.5]` | Cuboid half-width/height/depth |\n * | `radius` | `number` | `0.5` | Sphere / capsule radius |\n * | `halfHeight` | `number` | `0.5` | Capsule half-height |\n * | `friction` | `number` | `0.5` | Coulomb friction coefficient |\n * | `restitution` | `number` | `0.0` | Elasticity (1.0 = perfect bounce) |\n * | `density` | `number` | `1.0` | Mass density (alternative to mass) |\n * | `isSensor` | `bool` | `false` | Sensor mode (detect, no physical response) |\n * | `collisionGroups` | `u32` | `0x0001_FFFF` | 32-bit packed membership/filter |\n * | `solverGroups` | `u32` | `0xFFFF_FFFF` | 32-bit packed constraint groups |\n */\nexport const Collider = defineComponent('Collider', {\n shape: { type: 'enum', default: COLLIDER_SHAPE_CUBOID, labels: ColliderShapeValue },\n // feat-20260709 M4: cuboid half-extents collapsed from 3 per-axis scalar\n // columns into one inline array<f32,3> column. Explicit layer-2 default\n // (the array layer-3 fallback is all-zero, which would give a degenerate\n // zero-size box). radius/halfHeight stay scalar (OOS-1: independent\n // sphere/capsule params, not part of the cuboid vec).\n halfExtents: { type: 'array<f32, 3>', default: new Float32Array([0.5, 0.5, 0.5]) },\n radius: { type: 'f32', default: 0.5 },\n halfHeight: { type: 'f32', default: 0.5 },\n friction: { type: 'f32', default: 0.5 },\n restitution: { type: 'f32', default: 0 },\n density: { type: 'f32', default: 1 },\n isSensor: { type: 'bool', default: false },\n collisionGroups: { type: 'u32', default: 0x0001_ffff },\n solverGroups: { type: 'u32', default: 0xffff_ffff },\n});\n\n/**\n * ECS Component: kinematic character controller tuning + output state.\n *\n * Spawn alongside a `RigidBody({ type: 'kinematic' })` + `Collider` to opt an\n * entity into collision-aware movement via `PhysicsWorld.moveAndSlide`. The\n * tuning fields are stable character properties; `grounded` is written back by\n * the engine after each `moveAndSlide` (game code reads it, never writes it).\n *\n * All fields are flat scalars in engine units (degrees, world-space distance) —\n * no Rapier types leak through. Slope angles use the `Deg` suffix to make the\n * unit explicit; the backend translates degrees to radians. A single field\n * carries both the on/off switch and the value: `autoStepMaxHeight === 0`\n * disables auto-step, `snapToGroundDist === 0` disables snap-to-ground.\n *\n * 2D and 3D reuse this same component (plan-strategy D-9): every field is a\n * dimension-agnostic scalar, so no separate 2D component is needed.\n *\n * | Field | Type | Default | Purpose |\n * |:--|:--|:--|:--|\n * | `offset` | `f32` | `0.01` | Skin thickness, prevents penetration |\n * | `maxSlopeClimbDeg` | `f32` | `45` | Max climbable slope angle (degrees) |\n * | `minSlopeSlideDeg` | `f32` | `30` | Slope angle past which sliding starts (degrees) |\n * | `autoStepMaxHeight` | `f32` | `0.3` | Max auto-step height (0 = off) |\n * | `autoStepMinWidth` | `f32` | `0.2` | Min step width to be steppable |\n * | `snapToGroundDist` | `f32` | `0.2` | Downhill ground-snap distance (0 = off) |\n * | `grounded` | `bool` | `false` | Engine-written: grounded after last move |\n */\nexport const CharacterController = defineComponent('CharacterController', {\n offset: { type: 'f32', default: 0.01 },\n maxSlopeClimbDeg: { type: 'f32', default: 45 },\n minSlopeSlideDeg: { type: 'f32', default: 30 },\n autoStepMaxHeight: { type: 'f32', default: 0.3 },\n autoStepMinWidth: { type: 'f32', default: 0.2 },\n snapToGroundDist: { type: 'f32', default: 0.2 },\n grounded: { type: 'bool', default: false, transient: true },\n});\n\n/**\n * ECS Component: set of entities currently colliding with the holder entity.\n *\n * Maintained by the physics tick systems — entities are added on collision\n * start (`CollisionEvent.started`) and removed on collision stop\n * (`CollisionEvent.stopped`). AI users query this component to know whose\n * colliders overlap right now without consuming per-frame events.\n *\n * This is the `'continued'` equivalent — no repeated per-frame events,\n * one component query per frame exposes the full active contact set\n * (plan-strategy D-3: CollidingEntities set-query mode).\n */\nexport const CollidingEntities = defineComponent(\n 'CollidingEntities',\n {\n entities: { type: 'array<entity>' },\n },\n { transient: true },\n);\n\nconst PHYSICS_COMPONENTS: readonly Component[] = [\n CharacterController,\n Collider,\n CollidingEntities,\n RigidBody,\n];\n\n/** Install the physics component vocabulary in a World and release its leases on teardown. */\nexport function registerPhysicsComponents(world: World): () => void {\n const leases = PHYSICS_COMPONENTS.map((component) =>\n world.components.register(component).unwrap(),\n );\n return () => {\n for (let index = leases.length - 1; index >= 0; index -= 1) leases[index]?.dispose();\n };\n}\n","import { err, ok, type Result } from '@forgeax/engine-types';\n\n/** A portable integer grid coordinate. */\nexport type VoxelCell = readonly [number, number, number];\n\n/** A portable quaternion used by derived-physics inputs. */\nexport type PhysicsQuaternion = readonly [number, number, number, number];\n\n/** A portable three-component vector used by derived-physics inputs. */\nexport type PhysicsVector = readonly [number, number, number];\n\n/**\n * One local voxel shape. `cells` contains contiguous x/y/z triples. The\n * backend copies it while preparing a candidate, so callers may reuse their\n * scratch buffer after the call returns.\n */\nexport interface VoxelShapeInput {\n readonly id: string;\n readonly revision: number;\n readonly cells: Int32Array | readonly VoxelCell[];\n readonly voxelSize: PhysicsVector;\n readonly origin?: PhysicsVector;\n readonly rotation?: PhysicsQuaternion;\n readonly friction?: number;\n readonly restitution?: number;\n readonly density?: number;\n readonly isSensor?: boolean;\n readonly collisionGroups?: number;\n readonly solverGroups?: number;\n}\n\n/** Stable producer identity and revision for one constraint endpoint. */\nexport interface PhysicsConstraintBodyDependency {\n readonly sourceKey: string;\n readonly revision: number;\n}\n\n/** Explicit or density-derived rigid-body mass properties. */\nexport type PhysicsMassProperties =\n | {\n readonly mode: 'automatic';\n readonly density?: number;\n }\n | {\n readonly mode: 'explicit';\n readonly mass: number;\n readonly centerOfMass: PhysicsVector;\n readonly principalInertia: PhysicsVector;\n readonly principalInertiaLocalFrame?: PhysicsQuaternion;\n };\n\n/** How a topology replacement carries the committed body's motion. */\nexport type PhysicsVelocityPolicy = 'preserve' | 'reset';\n\n/**\n * Consumer-visible movement state for one committed derived body.\n *\n * `centerOfMass` is world-space (the same frame as the body's transform),\n * while both velocity vectors are world-space. Keeping this as one POD\n * value makes snapshot/recovery carry the complete motion boundary instead\n * of exposing Rapier objects or asking consumers to infer velocity from\n * successive transforms.\n */\nexport interface DerivedPhysicsMotion {\n readonly centerOfMass: PhysicsVector;\n readonly linearVelocity: PhysicsVector;\n readonly angularVelocity: PhysicsVector;\n}\n\n/** Stable, consumer-owned constraint input. */\nexport type PhysicsConstraintInput =\n | {\n readonly id: string;\n readonly revision: number;\n readonly kind: 'spring';\n readonly bodyA: number;\n readonly bodyB: number;\n readonly bodyASource: PhysicsConstraintBodyDependency;\n readonly bodyBSource: PhysicsConstraintBodyDependency;\n readonly anchorA: PhysicsVector;\n readonly anchorB: PhysicsVector;\n readonly restLength: number;\n readonly stiffness: number;\n readonly damping: number;\n }\n | {\n readonly id: string;\n readonly revision: number;\n readonly kind: 'hinge';\n readonly bodyA: number;\n readonly bodyB: number;\n readonly bodyASource: PhysicsConstraintBodyDependency;\n readonly bodyBSource: PhysicsConstraintBodyDependency;\n readonly anchorA: PhysicsVector;\n readonly anchorB: PhysicsVector;\n readonly axis: PhysicsVector;\n readonly limits?: readonly [number, number];\n };\n\n/** All data needed to prepare one body's derived shape replacement. */\nexport interface DerivedPhysicsCandidateInput {\n readonly entity: number;\n readonly revision: number;\n readonly sourceKey: string;\n readonly shapes: readonly VoxelShapeInput[];\n readonly seams?: readonly DerivedShapeSeamInput[];\n readonly bodyType?: 'static' | 'dynamic' | 'kinematic';\n readonly massProperties?: PhysicsMassProperties;\n readonly velocityPolicy?: PhysicsVelocityPolicy;\n /** Optional committed motion to restore after native mass admission. */\n readonly motion?: DerivedPhysicsMotion;\n readonly constraints?: readonly PhysicsConstraintInput[];\n /** Optional World identity; it is checked when the backend is ECS-bound. */\n readonly worldIdentity?: object;\n}\n\n/** A same-body integer-grid seam maintained by the Rapier voxel backend. */\nexport interface DerivedShapeSeamInput {\n readonly shapeA: string;\n readonly shapeB: string;\n /** Grid-space origin of B relative to A; all components must be integers. */\n readonly offset: PhysicsVector;\n}\n\n/** Candidate lifecycle visible to a consumer. */\nexport type DerivedPhysicsCandidateState =\n | 'ready'\n | 'queued'\n | 'published'\n | 'cancelled'\n | 'invalidated'\n | 'failed';\n\n/** Opaque-enough prepared candidate. Native handles never cross this type. */\nexport interface DerivedPhysicsCandidate {\n readonly candidateId: string;\n readonly generation: number;\n /** Per-PhysicsWorld owner identity; candidate IDs are not global. */\n readonly owner: object;\n readonly input: Readonly<DerivedPhysicsCandidateInput>;\n readonly state: DerivedPhysicsCandidateState;\n}\n\n/** Stable receipt emitted when a candidate becomes the committed shape set. */\nexport interface DerivedPhysicsPublication {\n readonly candidateId: string;\n readonly entity: number;\n readonly revision: number;\n readonly fixedStep: number;\n readonly shapeIds: readonly string[];\n readonly generation: number;\n}\n\n/** Structured admission failure that leaves the prior publication queryable. */\nexport interface DerivedPhysicsFailure {\n readonly candidateId: string;\n readonly entity: number;\n readonly revision: number;\n readonly fixedStep: number;\n readonly error: DerivedPhysicsError;\n readonly recovery: 'old-state-retained' | 'rebuild-required';\n}\n\n/** Public projection of an active local shape. */\nexport interface DerivedShapeState {\n readonly id: string;\n readonly revision: number;\n readonly entity: number;\n readonly voxelSize: PhysicsVector;\n readonly origin: PhysicsVector;\n readonly rotation: PhysicsQuaternion;\n readonly generation: number;\n}\n\n/** Real backend contact observation, including stable shape identity when known. */\nexport interface PhysicsContactObservation {\n readonly phase: 'started' | 'stopped';\n readonly fixedStep: number;\n readonly entityA: number;\n readonly entityB: number;\n readonly shapeA?: string;\n readonly shapeB?: string;\n readonly point?: PhysicsVector;\n readonly normal?: PhysicsVector;\n}\n\n/** Portable recovery input produced from a committed derived state. */\nexport interface DerivedPhysicsSnapshot {\n readonly generation: number;\n readonly fixedStep: number;\n readonly bodies: readonly {\n readonly entity: number;\n readonly revision: number;\n readonly sourceKey: string;\n readonly shapes: readonly VoxelShapeInput[];\n readonly seams?: readonly DerivedShapeSeamInput[];\n readonly bodyType?: 'static' | 'dynamic' | 'kinematic';\n readonly massProperties?: PhysicsMassProperties;\n readonly velocityPolicy?: PhysicsVelocityPolicy;\n /** Committed world-space COM and velocities at capture time. */\n readonly motion?: DerivedPhysicsMotion;\n readonly constraints: readonly PhysicsConstraintInput[];\n }[];\n}\n\nexport type DerivedPhysicsErrorCode =\n | 'derived-physics-disposed'\n | 'derived-body-not-found'\n | 'derived-world-mismatch'\n | 'derived-candidate-not-found'\n | 'derived-candidate-stale'\n | 'derived-candidate-pending'\n | 'derived-candidate-cancelled'\n | 'derived-candidate-invalid'\n | 'derived-candidate-budget-exceeded'\n | 'derived-shape-invalid'\n | 'derived-shape-duplicate'\n | 'derived-seam-invalid'\n | 'derived-mass-invalid'\n | 'derived-constraint-invalid'\n | 'derived-constraint-not-found'\n | 'derived-constraint-stale'\n | 'derived-backend-failed'\n | 'derived-recovery-invalid';\n\n/** Bounded derived-physics preparation envelope. */\nexport const DERIVED_PHYSICS_LIMITS = Object.freeze({\n maxCandidates: 32,\n maxShapesPerCandidate: 64,\n maxConstraintsPerCandidate: 64,\n maxCellsPerCandidate: 262_144,\n maxCandidateBytes: 8 * 1024 * 1024,\n});\n\nexport interface DerivedPhysicsErrorDetail {\n readonly code: DerivedPhysicsErrorCode;\n readonly entity?: number;\n readonly candidateId?: string;\n readonly shapeId?: string;\n readonly constraintId?: string;\n readonly expected?: string;\n readonly actual?: unknown;\n readonly reason?: string;\n}\n\n/** Closed, structured failure for the public derived-physics surface. */\nexport class DerivedPhysicsError extends Error {\n readonly code: DerivedPhysicsErrorCode;\n readonly expected: string;\n readonly hint: string;\n readonly detail: DerivedPhysicsErrorDetail;\n\n constructor(\n code: DerivedPhysicsErrorCode,\n expected: string,\n hint: string,\n detail: Omit<DerivedPhysicsErrorDetail, 'code'> = {},\n ) {\n super(`${code}: ${expected}`);\n this.name = 'DerivedPhysicsError';\n this.code = code;\n this.expected = expected;\n this.hint = hint;\n this.detail = Object.freeze({ code, ...detail });\n }\n}\n\nconst ID_RE = /\\S/;\n\nfunction finite(value: number): boolean {\n return Number.isFinite(value);\n}\n\nfunction vectorFinite(vector: readonly number[], length: number): boolean {\n return vector.length === length && vector.every(finite);\n}\n\n/** Rotate a local origin delta into the shared grid frame used by a seam. */\nfunction rotateVectorByQuaternion(\n vector: readonly [number, number, number],\n rotation: readonly [number, number, number, number],\n): [number, number, number] {\n const [x, y, z] = vector;\n const [qx, qy, qz, qw] = rotation;\n const tx = 2 * (qy * z - qz * y);\n const ty = 2 * (qz * x - qx * z);\n const tz = 2 * (qx * y - qy * x);\n return [\n x + qw * tx + qy * tz - qz * ty,\n y + qw * ty + qz * tx - qx * tz,\n z + qw * tz + qx * ty - qy * tx,\n ];\n}\n\nfunction normalizedQuaternion(rotation: PhysicsQuaternion): PhysicsQuaternion | undefined {\n if (!vectorFinite(rotation, 4)) return undefined;\n const length = Math.hypot(rotation[0], rotation[1], rotation[2], rotation[3]);\n if (!finite(length) || length < 1e-6) return undefined;\n return [rotation[0] / length, rotation[1] / length, rotation[2] / length, rotation[3] / length];\n}\n\nfunction copyCells(cells: Int32Array | readonly VoxelCell[]): Int32Array | undefined {\n if (cells instanceof Int32Array) return new Int32Array(cells);\n const result = new Int32Array(cells.length * 3);\n for (let index = 0; index < cells.length; index += 1) {\n const cell = cells[index];\n if (cell === undefined || cell.length !== 3 || cell.some((value) => !Number.isInteger(value))) {\n return undefined;\n }\n result[index * 3] = cell[0] ?? 0;\n result[index * 3 + 1] = cell[1] ?? 0;\n result[index * 3 + 2] = cell[2] ?? 0;\n }\n return result;\n}\n\n/** Validate and snapshot one voxel input before native resources are created. */\nexport function normalizeVoxelShapeInput(input: VoxelShapeInput): Result<\n VoxelShapeInput & {\n readonly cells: Int32Array;\n readonly origin: PhysicsVector;\n readonly rotation: PhysicsQuaternion;\n },\n DerivedPhysicsError\n> {\n if (typeof input.id !== 'string' || !ID_RE.test(input.id)) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-invalid',\n 'voxel shape id is a non-empty stable string',\n 'provide a stable shape identity from the consumer state',\n { shapeId: input.id },\n ),\n );\n }\n if (!Number.isInteger(input.revision) || input.revision < 0) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-invalid',\n 'voxel shape revision is a non-negative integer',\n 'increment the shape revision when its cells or transform changes',\n { shapeId: input.id, actual: input.revision },\n ),\n );\n }\n const cells = copyCells(input.cells);\n if (cells === undefined || cells.length === 0 || cells.length % 3 !== 0) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-invalid',\n 'voxel cells contain at least one complete integer x/y/z triple',\n 'supply a non-empty Int32Array or cell tuple list',\n { shapeId: input.id, actual: cells?.length },\n ),\n );\n }\n const voxelSize = input.voxelSize;\n if (!vectorFinite(voxelSize, 3) || voxelSize.some((value) => value <= 0)) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-invalid',\n 'voxelSize contains finite positive components',\n 'choose a finite positive voxel size for every axis',\n { shapeId: input.id, actual: voxelSize },\n ),\n );\n }\n for (const value of cells) {\n if (!Number.isInteger(value)) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-invalid',\n 'voxel coordinates are integers',\n 'quantize cells before submitting a physics candidate',\n { shapeId: input.id, actual: value },\n ),\n );\n }\n }\n const origin = input.origin ?? [0, 0, 0];\n if (!vectorFinite(origin, 3)) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-invalid',\n 'voxel origin contains finite coordinates',\n 'supply a finite local origin',\n { shapeId: input.id, actual: origin },\n ),\n );\n }\n const rotation = normalizedQuaternion(input.rotation ?? [0, 0, 0, 1]);\n if (rotation === undefined) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-invalid',\n 'voxel rotation is a finite non-degenerate quaternion',\n 'normalize the local voxel orientation before submitting it',\n { shapeId: input.id, actual: input.rotation },\n ),\n );\n }\n for (const [name, value] of [\n ['friction', input.friction],\n ['restitution', input.restitution],\n ['density', input.density],\n ] as const) {\n if (value !== undefined && (!finite(value) || value < 0)) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-invalid',\n `${name} is finite and non-negative`,\n `repair the ${name} input before native preparation`,\n { shapeId: input.id, actual: value },\n ),\n );\n }\n }\n return ok(\n Object.freeze({\n ...input,\n cells,\n voxelSize: [voxelSize[0], voxelSize[1], voxelSize[2]] as PhysicsVector,\n origin: [origin[0], origin[1], origin[2]] as PhysicsVector,\n rotation,\n }),\n );\n}\n\n/** Validate explicit mass/inertia values before touching the backend. */\nexport function validateMassProperties(\n properties: PhysicsMassProperties | undefined,\n): Result<PhysicsMassProperties | undefined, DerivedPhysicsError> {\n if (properties === undefined || properties.mode === 'automatic') {\n if (\n properties?.density !== undefined &&\n (!finite(properties.density) || properties.density <= 0)\n ) {\n return err(\n new DerivedPhysicsError(\n 'derived-mass-invalid',\n 'automatic density is finite and positive',\n 'omit density to use backend density or provide a positive density',\n { actual: properties.density },\n ),\n );\n }\n return ok(properties);\n }\n if (\n !finite(properties.mass) ||\n properties.mass <= 0 ||\n !vectorFinite(properties.centerOfMass, 3) ||\n !vectorFinite(properties.principalInertia, 3) ||\n properties.principalInertia.some((value) => !finite(value) || value <= 0)\n ) {\n return err(\n new DerivedPhysicsError(\n 'derived-mass-invalid',\n 'explicit mass, center of mass, and principal inertia are finite and non-degenerate',\n 'provide positive mass/inertia and a finite center of mass',\n { actual: properties },\n ),\n );\n }\n const frame = normalizedQuaternion(properties.principalInertiaLocalFrame ?? [0, 0, 0, 1]);\n if (frame === undefined) {\n return err(\n new DerivedPhysicsError(\n 'derived-mass-invalid',\n 'principal inertia local frame is a finite non-degenerate quaternion',\n 'normalize the inertia frame before submitting it',\n { actual: properties.principalInertiaLocalFrame },\n ),\n );\n }\n return ok(\n Object.freeze({\n ...properties,\n centerOfMass: [...properties.centerOfMass] as PhysicsVector,\n principalInertia: [...properties.principalInertia] as PhysicsVector,\n principalInertiaLocalFrame: frame,\n }),\n );\n}\n\n/** The required linear velocity correction for a committed COM change. */\nexport function preserveCenterOfMassVelocity(\n linearVelocity: PhysicsVector,\n angularVelocity: PhysicsVector,\n previousWorldCom: PhysicsVector,\n nextWorldCom: PhysicsVector,\n): PhysicsVector {\n const dx = nextWorldCom[0] - previousWorldCom[0];\n const dy = nextWorldCom[1] - previousWorldCom[1];\n const dz = nextWorldCom[2] - previousWorldCom[2];\n return [\n linearVelocity[0] + angularVelocity[1] * dz - angularVelocity[2] * dy,\n linearVelocity[1] + angularVelocity[2] * dx - angularVelocity[0] * dz,\n linearVelocity[2] + angularVelocity[0] * dy - angularVelocity[1] * dx,\n ];\n}\n\n/** Snapshot an input without retaining caller-owned typed-array references. */\nexport function cloneDerivedPhysicsInput(\n input: DerivedPhysicsCandidateInput,\n): Result<DerivedPhysicsCandidateInput, DerivedPhysicsError> {\n if (!Number.isInteger(input.entity) || input.entity < 0) {\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-invalid',\n 'candidate entity is a non-negative ECS entity value',\n 'submit a live entity from the same World',\n { entity: input.entity },\n ),\n );\n }\n if (!Number.isInteger(input.revision) || input.revision < 0) {\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-invalid',\n 'candidate revision is a non-negative integer',\n 'advance the consumer topology revision monotonically',\n { entity: input.entity, actual: input.revision },\n ),\n );\n }\n if (typeof input.sourceKey !== 'string' || !ID_RE.test(input.sourceKey)) {\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-invalid',\n 'candidate sourceKey is a non-empty stable producer identity',\n 'carry the producer sourceKey with every derived body revision',\n { entity: input.entity, actual: input.sourceKey },\n ),\n );\n }\n if (\n input.shapes.length === 0 ||\n input.shapes.length > DERIVED_PHYSICS_LIMITS.maxShapesPerCandidate\n ) {\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-budget-exceeded',\n `one candidate contains between one and ${DERIVED_PHYSICS_LIMITS.maxShapesPerCandidate} derived shapes`,\n 'split the consumer operation at a body boundary and retry',\n { entity: input.entity, actual: input.shapes.length },\n ),\n );\n }\n const seen = new Set<string>();\n const shapes: VoxelShapeInput[] = [];\n for (const shape of input.shapes) {\n if (seen.has(shape.id)) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-duplicate',\n 'one candidate has one identity per derived shape',\n 'merge or rename duplicate shape inputs before preparation',\n { entity: input.entity, shapeId: shape.id },\n ),\n );\n }\n seen.add(shape.id);\n const normalized = normalizeVoxelShapeInput(shape);\n if (!normalized.ok) return normalized;\n shapes.push(normalized.value);\n }\n const mass = validateMassProperties(input.massProperties);\n if (!mass.ok) return mass;\n if (\n input.motion !== undefined &&\n (!vectorFinite(input.motion.centerOfMass, 3) ||\n !vectorFinite(input.motion.linearVelocity, 3) ||\n !vectorFinite(input.motion.angularVelocity, 3))\n ) {\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-invalid',\n 'optional movement state contains finite world-space COM and velocity vectors',\n 'capture or provide three finite components for centerOfMass, linearVelocity, and angularVelocity',\n { entity: input.entity, actual: input.motion },\n ),\n );\n }\n const constraints = input.constraints ?? [];\n if (constraints.length > DERIVED_PHYSICS_LIMITS.maxConstraintsPerCandidate) {\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-budget-exceeded',\n `one candidate contains at most ${DERIVED_PHYSICS_LIMITS.maxConstraintsPerCandidate} constraint updates`,\n 'submit a bounded constraint set for this body',\n { entity: input.entity, actual: constraints.length },\n ),\n );\n }\n const seams = input.seams ?? [];\n const shapeById = new Map(shapes.map((shape) => [shape.id, shape]));\n for (const seam of seams) {\n const a = shapeById.get(seam.shapeA);\n const b = shapeById.get(seam.shapeB);\n const aRotation = a?.rotation ?? [0, 0, 0, 1];\n const bRotation = b?.rotation ?? [0, 0, 0, 1];\n const aOrigin = a?.origin ?? [0, 0, 0];\n const bOrigin = b?.origin ?? [0, 0, 0];\n const quaternionDot = aRotation.reduce(\n (sum, value, index) => sum + value * (bRotation[index] ?? 0),\n 0,\n );\n const localOriginDelta: [number, number, number] = [\n (bOrigin[0] ?? 0) - (aOrigin[0] ?? 0),\n (bOrigin[1] ?? 0) - (aOrigin[1] ?? 0),\n (bOrigin[2] ?? 0) - (aOrigin[2] ?? 0),\n ];\n // `origin` is expressed in the body's frame while Rapier's seam shift is\n // expressed in shape A's voxel frame. Move the body-local delta through\n // the inverse of A's local-to-body rotation before quantizing it.\n const sharedGridDelta = rotateVectorByQuaternion(localOriginDelta, [\n -aRotation[0],\n -aRotation[1],\n -aRotation[2],\n aRotation[3],\n ]);\n const alignedOrigins =\n a !== undefined &&\n b !== undefined &&\n seam.offset.every(\n (value, index) =>\n Math.abs((sharedGridDelta[index] ?? 0) / (a?.voxelSize[index] ?? 1) - value) <= 1e-5,\n );\n if (\n a === undefined ||\n b === undefined ||\n a.id === b.id ||\n !vectorFinite(seam.offset, 3) ||\n seam.offset.some((value) => !Number.isInteger(value)) ||\n a.voxelSize.some((value, index) => Math.abs(value - (b.voxelSize[index] ?? 0)) > 1e-6) ||\n Math.abs(Math.abs(quaternionDot) - 1) > 1e-5 ||\n !alignedOrigins\n ) {\n return err(\n new DerivedPhysicsError(\n 'derived-seam-invalid',\n 'a voxel seam joins same-grid shapes with integer offset in the shared rotated grid frame',\n 'rotate the local origin delta into the shared grid frame and use an integer grid offset',\n { entity: input.entity, shapeId: seam.shapeA },\n ),\n );\n }\n }\n const seenConstraints = new Set<string>();\n for (const constraint of constraints) {\n if (seenConstraints.has(constraint.id)) {\n return err(\n new DerivedPhysicsError(\n 'derived-constraint-invalid',\n 'one candidate contains one update per constraint identity',\n 'merge duplicate constraint updates before preparation',\n { entity: input.entity, constraintId: constraint.id },\n ),\n );\n }\n seenConstraints.add(constraint.id);\n for (const dependency of [constraint.bodyASource, constraint.bodyBSource]) {\n if (\n typeof dependency.sourceKey !== 'string' ||\n !ID_RE.test(dependency.sourceKey) ||\n !Number.isInteger(dependency.revision) ||\n dependency.revision < 0\n ) {\n return err(\n new DerivedPhysicsError(\n 'derived-constraint-invalid',\n 'constraint endpoint sourceKey and revision are stable and non-negative',\n 'refresh both endpoint dependencies before preparing the constraint',\n { entity: input.entity, constraintId: constraint.id },\n ),\n );\n }\n }\n }\n const cellCount = shapes.reduce((sum, shape) => sum + shape.cells.length / 3, 0);\n if (cellCount > DERIVED_PHYSICS_LIMITS.maxCellsPerCandidate) {\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-budget-exceeded',\n `one candidate contains at most ${DERIVED_PHYSICS_LIMITS.maxCellsPerCandidate} cells`,\n 'reduce the voxel input or split it at a body boundary',\n { entity: input.entity, actual: cellCount },\n ),\n );\n }\n if (\n estimateDerivedPhysicsInputBytes({ ...input, shapes, constraints, seams }) >\n DERIVED_PHYSICS_LIMITS.maxCandidateBytes\n ) {\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-budget-exceeded',\n `one candidate stages at most ${DERIVED_PHYSICS_LIMITS.maxCandidateBytes} bytes`,\n 'reduce cells and constraint metadata before preparing the candidate',\n { entity: input.entity },\n ),\n );\n }\n return ok(\n Object.freeze({\n ...input,\n shapes: Object.freeze(shapes),\n seams: Object.freeze(\n seams.map((seam) => ({ ...seam, offset: [...seam.offset] as PhysicsVector })),\n ),\n ...(mass.value === undefined ? {} : { massProperties: mass.value }),\n ...(input.motion === undefined\n ? {}\n : {\n motion: Object.freeze({\n centerOfMass: [...input.motion.centerOfMass] as PhysicsVector,\n linearVelocity: [...input.motion.linearVelocity] as PhysicsVector,\n angularVelocity: [...input.motion.angularVelocity] as PhysicsVector,\n }),\n }),\n constraints: Object.freeze([...constraints]),\n velocityPolicy: input.velocityPolicy ?? 'preserve',\n }),\n );\n}\n\n/** Estimate staged CPU/native input bytes for the bounded admission budget. */\nexport function estimateDerivedPhysicsInputBytes(input: DerivedPhysicsCandidateInput): number {\n const shapeBytes = input.shapes.reduce(\n (sum, shape) =>\n sum +\n (shape.cells instanceof Int32Array ? shape.cells.length / 3 : shape.cells.length) * 32 +\n 128,\n 0,\n );\n const seamBytes = (input.seams?.length ?? 0) * 64;\n const constraintBytes = (input.constraints?.length ?? 0) * 192;\n return shapeBytes + seamBytes + constraintBytes + 256;\n}\n","// Keep literal specifiers visible to bundlers without pulling backend declarations into the physics TypeScript graph.\nexport function loadRapier3DBackend() {\n return import('@forgeax/engine-physics-rapier3d');\n}\n\nexport function loadRapier2DBackend() {\n return import('@forgeax/engine-physics-rapier2d');\n}\n","// @forgeax/engine-physics -- physicsPlugin(backend) factory (M2 / w10, plan-strategy D-5 / D-7).\n//\n// physicsPlugin lives in @forgeax/engine-physics (the interface package, C-9)\n// and accepts an interface->backend dependency inversion: its async apply\n// dynamic-imports the rapier 2D / 3D backend on demand. The backends are\n// optional peerDependencies in this package's package.json (a regular\n// dependency would form a physics <-> rapier cycle since the backends depend on\n// the interface package); the consuming app declares the selected runtime dep.\n//\n// charter awareness:\n// P3 explicit failure: WASM load failure rejects plugin activation and the\n// App boundary preserves the cause; it is never a silent skip.\n// P4 consistent abstraction: physicsPlugin shares the same Plugin shape as\n// transform / audio -- one mental model covers every wiring.\n\nimport type { Plugin } from '@forgeax/engine-plugin';\nimport { registerPhysicsComponents } from './components';\nimport { PhysicsError } from './errors';\nimport { loadRapier2DBackend, loadRapier3DBackend } from './load-rapier-backend.mjs';\nimport type { PhysicsWorld, PhysicsWorld2D } from './physics-world';\n\ninterface Rapier3DBackendModule {\n loadRapier3D(): Promise<unknown>;\n createRapier3DPhysicsWorld(rapier: unknown): PhysicsWorld;\n registerPhysicsSystems(world: import('@forgeax/engine-ecs').World): () => void;\n}\n\ninterface Rapier2DBackendModule {\n loadRapier2D(): Promise<unknown>;\n createRapier2DPhysicsWorld(rapier: unknown): PhysicsWorld2D;\n registerPhysicsSystems2D(world: import('@forgeax/engine-ecs').World): () => void;\n}\n\n/** Rapier backend selector. */\nexport type PhysicsBackend = 'rapier-2d' | 'rapier-3d';\n\nfunction normalizeWasmLoadFailure(backend: PhysicsBackend, cause: unknown): PhysicsError {\n if (cause instanceof PhysicsError && cause.code === 'wasm-load-failed') return cause;\n const reason = cause instanceof Error ? cause.message : String(cause);\n return new PhysicsError({\n code: 'wasm-load-failed',\n expected: `successful import and WASM initialization for ${backend}`,\n hint: `Rapier backend activation failed: ${reason}`,\n detail: { code: 'wasm-load-failed', reason },\n });\n}\n\ndeclare module '@forgeax/engine-plugin' {\n interface EngineContextServices {\n physics?: PhysicsWorld | PhysicsWorld2D;\n }\n}\n\n/**\n * physicsPlugin(backend) dynamically imports the Rapier backend,\n * loads the WASM module, creates the PhysicsWorld, inserts it as the\n * 'PhysicsWorld' world resource, and registers the three-phase tick systems.\n *\n * The resource is inserted before registering systems so moveAndSlide resolves\n * `PhysicsWorld` on the first tick. Cordis owns rollback if any later effect\n * fails.\n *\n * @param backend 'rapier-2d' or 'rapier-3d'\n */\nexport function physicsPlugin(backend: PhysicsBackend): Plugin {\n return {\n name: 'physics',\n inject: ['world'],\n provide: 'physics',\n async apply(ctx) {\n const world = ctx.world;\n let physics: PhysicsWorld | PhysicsWorld2D;\n let registerSystems: () => () => void;\n if (backend === 'rapier-3d') {\n let module: Rapier3DBackendModule;\n let rapier: unknown;\n try {\n module = (await loadRapier3DBackend()) as Rapier3DBackendModule;\n rapier = await module.loadRapier3D();\n } catch (cause) {\n throw normalizeWasmLoadFailure(backend, cause);\n }\n if (rapier instanceof PhysicsError) throw normalizeWasmLoadFailure(backend, rapier);\n const { createRapier3DPhysicsWorld, registerPhysicsSystems } = module;\n physics = createRapier3DPhysicsWorld(rapier);\n registerSystems = () => registerPhysicsSystems(world);\n } else {\n let module: Rapier2DBackendModule;\n let rapier: unknown;\n try {\n module = (await loadRapier2DBackend()) as Rapier2DBackendModule;\n rapier = await module.loadRapier2D();\n } catch (cause) {\n throw normalizeWasmLoadFailure(backend, cause);\n }\n if (rapier instanceof PhysicsError) throw normalizeWasmLoadFailure(backend, rapier);\n const { createRapier2DPhysicsWorld, registerPhysicsSystems2D } = module;\n physics = createRapier2DPhysicsWorld(rapier);\n registerSystems = () => registerPhysicsSystems2D(world);\n }\n ctx.effect(() => registerPhysicsComponents(world), 'physics/components');\n ctx.effect(() => {\n world.insertResource('PhysicsWorld', physics);\n return () => {\n world.removeResource('PhysicsWorld');\n physics.dispose();\n };\n }, 'physics/resource');\n ctx.effect(() => {\n const unregister = registerSystems();\n return () => unregister();\n }, 'physics/systems');\n ctx.provide('physics', physics);\n },\n };\n}\n","import { defineSystemSet } from '@forgeax/engine-ecs';\n\nexport const PhysicsSet = defineSystemSet({ name: 'physics' });\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/collision-event.ts","../src/components.ts","../src/derived-physics.ts","../src/load-rapier-backend.mjs","../src/plugin-factory.ts","../src/system-set.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["// @forgeax/engine-physics — CollisionEvent ECS Event token placeholder.\n//\n// Emitted by physics tick systems during the Writeback phase.\n// Two states only: 'started' (new contact) and 'stopped' (separated).\n// No 'continued' event — use CollidingEntities component for ongoing contacts\n// (plan-strategy D-3).\n\nimport type { Vec3 } from '@forgeax/engine-math';\n\n/**\n * Collision event payload — per-contact-pair event emitted during Writeback.\n *\n * `type: 'started'` — two colliders just began touching.\n * `type: 'stopped'` — two colliders just separated.\n */\nexport interface CollisionEventPayload {\n type: 'started' | 'stopped';\n entityA: number;\n entityB: number;\n contactPoint: Vec3;\n contactNormal: Vec3;\n}\n\n/**\n * CollisionEvent constant — identifies the collision event type.\n * Backend systems push CollisionEventPayload instances into the event queue\n * during the Writeback phase; user systems drain via query.\n *\n * The backing ECS event infrastructure (Event<T> generic + world.drainEvent)\n * is deferred to a future feat. For M1, this is a type-only contract.\n */\nexport const CollisionEvent = '__CollisionEvent__' as const;\n\n/** Type-level identifier for the CollisionEvent event channel. */\nexport type CollisionEvent = typeof CollisionEvent;\n","// @forgeax/engine-physics — ECS Component schemas.\n//\n// RigidBody and Collider are the two user-facing entry points; AI users\n// spawn entities with these components to opt into physics simulation.\n// CollidingEntities is the runtime set-query component for continuous\n// collision status (started/stopped model, no 'continued' event).\n\nimport { type Component, defineComponent, type World } from '@forgeax/engine-ecs';\n\n/**\n * RigidBody motion type — 3-state discriminant mirroring Rapier's\n * Dynamic / Fixed / KinematicPositionBased triplet.\n *\n * `'static'`: infinite mass, never moves (Rapier Fixed).\n * `'dynamic'`: driven by forces, gravity, collisions (Rapier Dynamic).\n * `'kinematic'`: user-controlled position, velocity derived by engine\n * (Rapier KinematicPositionBased).\n */\nexport type RigidBodyType = 'static' | 'dynamic' | 'kinematic';\n\n/**\n * Collider shape discriminant — 3 AI-friendly shape names.\n *\n * `'cuboid'`: box shape defined by half-extents (x, y, z).\n * `'sphere'`: sphere defined by radius.\n * `'capsule'`: capsule defined by half-height + radius.\n *\n * Named `'sphere'` not `'ball'` per plan-strategy D-5: AI users see\n * the familiar geometric term; backend maps to Rapier `ColliderDesc.ball()`.\n */\nexport type ColliderShape = 'cuboid' | 'sphere' | 'capsule';\n\n// ─── D-3: numeric enum constants + narrowing helpers ─────────────────────\n//\n// Aligned with `packages/runtime/src/components/camera.ts:41-53`\n// `cameraProjectionFromF32` pattern. The ECS `enum` field maps to `number`\n// (Uint32Array column); these constants let AI users write\n// `{ type: RigidBodyTypeValue.dynamic }` instead of bare magic numbers,\n// and the narrowing helpers let backends switch cleanly on the string union.\n//\n// Declared BEFORE the RigidBody / Collider components so each component's enum\n// field descriptor can reference the SAME `*Value` map as its `labels`\n// (Derive, don't Duplicate — one object is both the AI-facing const AND the\n// schema-projected label map that `describeComponent` surfaces).\n\n/** Numeric value for static rigid body (Rapier Fixed). */\nexport const RIGID_BODY_TYPE_STATIC = 0;\n/** Numeric value for dynamic rigid body (Rapier Dynamic). */\nexport const RIGID_BODY_TYPE_DYNAMIC = 1;\n/** Numeric value for kinematic rigid body (Rapier KinematicPositionBased). */\nexport const RIGID_BODY_TYPE_KINEMATIC = 2;\n\nexport const RigidBodyTypeValue = {\n static: RIGID_BODY_TYPE_STATIC,\n dynamic: RIGID_BODY_TYPE_DYNAMIC,\n kinematic: RIGID_BODY_TYPE_KINEMATIC,\n} as const;\n\nexport function rigidBodyTypeFromF32(n: number): RigidBodyType {\n if (n === RIGID_BODY_TYPE_DYNAMIC) return 'dynamic';\n if (n === RIGID_BODY_TYPE_KINEMATIC) return 'kinematic';\n return 'static';\n}\n\n/** Numeric value for cuboid collider shape. */\nexport const COLLIDER_SHAPE_CUBOID = 0;\n/** Numeric value for sphere collider shape. */\nexport const COLLIDER_SHAPE_SPHERE = 1;\n/** Numeric value for capsule collider shape. */\nexport const COLLIDER_SHAPE_CAPSULE = 2;\n\nexport const ColliderShapeValue = {\n cuboid: COLLIDER_SHAPE_CUBOID,\n sphere: COLLIDER_SHAPE_SPHERE,\n capsule: COLLIDER_SHAPE_CAPSULE,\n} as const;\n\nexport function colliderShapeFromF32(n: number): ColliderShape {\n if (n === COLLIDER_SHAPE_SPHERE) return 'sphere';\n if (n === COLLIDER_SHAPE_CAPSULE) return 'capsule';\n return 'cuboid';\n}\n\n/**\n * ECS Component: rigid body physics properties.\n *\n * AI user entry point — spawn with `world.spawn(RigidBody({ type: 'dynamic' }))`\n * to opt an entity into physics simulation.\n *\n * | Field | Type | Default | Purpose |\n * |:--|:--|:--|:--|\n * | `type` | `RigidBodyType` | `'dynamic'` | Motion type discriminant |\n * | `mass` | `number` | `1.0` | Linear mass (> 0 for dynamic) |\n * | `linearDamping` | `number` | `0.0` | Velocity damping factor [0, 1] |\n * | `angularDamping` | `number` | `0.0` | Angular velocity damping [0, 1] |\n * | `gravityScale` | `number` | `1.0` | Per-body gravity multiplier |\n * | `ccdEnabled` | `boolean` | `false` | Continuous collision detection |\n *\n * `type` declares `labels: RigidBodyTypeValue` so `describeComponent` projects\n * the `static=0 / dynamic=1 / kinematic=2` map through the front door — an AI\n * learns the legal variants from the schema, not from engine source.\n */\nexport const RigidBody = defineComponent('RigidBody', {\n type: { type: 'enum', default: RIGID_BODY_TYPE_DYNAMIC, labels: RigidBodyTypeValue },\n mass: { type: 'f32', default: 1 },\n linearDamping: { type: 'f32', default: 0 },\n angularDamping: { type: 'f32', default: 0 },\n gravityScale: { type: 'f32', default: 1 },\n ccdEnabled: { type: 'bool', default: false },\n});\n\n/**\n * ECS Component: collision geometry.\n *\n * Spawn alongside RigidBody to give an entity a collision shape. Entities\n * with Collider but no RigidBody are treated as static colliders (Rapier\n * native behavior — collider without parent body is fixed): `physicsSyncBackend`\n * synthesizes an implicit static body for them, so a bare-Collider floor/wall is\n * simulated as immovable level geometry — the natural way to author static\n * scenery without a redundant `RigidBody{static}`.\n *\n * | Field | Type | Default | Purpose |\n * |:--|:--|:--|:--|\n * | `shape` | `ColliderShape` | — | Shape discriminant |\n * | `halfExtents` | `[number, number, number]` | `[0.5, 0.5, 0.5]` | Cuboid half-width/height/depth |\n * | `radius` | `number` | `0.5` | Sphere / capsule radius |\n * | `halfHeight` | `number` | `0.5` | Capsule half-height |\n * | `friction` | `number` | `0.5` | Coulomb friction coefficient |\n * | `restitution` | `number` | `0.0` | Elasticity (1.0 = perfect bounce) |\n * | `density` | `number` | `1.0` | Mass density (alternative to mass) |\n * | `isSensor` | `bool` | `false` | Sensor mode (detect, no physical response) |\n * | `collisionGroups` | `u32` | `0x0001_FFFF` | 32-bit packed membership/filter |\n * | `solverGroups` | `u32` | `0xFFFF_FFFF` | 32-bit packed constraint groups |\n */\nexport const Collider = defineComponent('Collider', {\n shape: { type: 'enum', default: COLLIDER_SHAPE_CUBOID, labels: ColliderShapeValue },\n // feat-20260709 M4: cuboid half-extents collapsed from 3 per-axis scalar\n // columns into one inline array<f32,3> column. Explicit layer-2 default\n // (the array layer-3 fallback is all-zero, which would give a degenerate\n // zero-size box). radius/halfHeight stay scalar (OOS-1: independent\n // sphere/capsule params, not part of the cuboid vec).\n halfExtents: { type: 'array<f32, 3>', default: new Float32Array([0.5, 0.5, 0.5]) },\n radius: { type: 'f32', default: 0.5 },\n halfHeight: { type: 'f32', default: 0.5 },\n friction: { type: 'f32', default: 0.5 },\n restitution: { type: 'f32', default: 0 },\n density: { type: 'f32', default: 1 },\n isSensor: { type: 'bool', default: false },\n collisionGroups: { type: 'u32', default: 0x0001_ffff },\n solverGroups: { type: 'u32', default: 0xffff_ffff },\n});\n\n/**\n * ECS Component: kinematic character controller tuning + output state.\n *\n * Spawn alongside a `RigidBody({ type: 'kinematic' })` + `Collider` to opt an\n * entity into collision-aware movement via `PhysicsWorld.moveAndSlide`. The\n * tuning fields are stable character properties; `grounded` is written back by\n * the engine after each `moveAndSlide` (game code reads it, never writes it).\n *\n * All fields are flat scalars in engine units (degrees, world-space distance) —\n * no Rapier types leak through. Slope angles use the `Deg` suffix to make the\n * unit explicit; the backend translates degrees to radians. A single field\n * carries both the on/off switch and the value: `autoStepMaxHeight === 0`\n * disables auto-step, `snapToGroundDist === 0` disables snap-to-ground.\n *\n * 2D and 3D reuse this same component (plan-strategy D-9): every field is a\n * dimension-agnostic scalar, so no separate 2D component is needed.\n *\n * | Field | Type | Default | Purpose |\n * |:--|:--|:--|:--|\n * | `offset` | `f32` | `0.01` | Skin thickness, prevents penetration |\n * | `maxSlopeClimbDeg` | `f32` | `45` | Max climbable slope angle (degrees) |\n * | `minSlopeSlideDeg` | `f32` | `30` | Slope angle past which sliding starts (degrees) |\n * | `autoStepMaxHeight` | `f32` | `0.3` | Max auto-step height (0 = off) |\n * | `autoStepMinWidth` | `f32` | `0.2` | Min step width to be steppable |\n * | `snapToGroundDist` | `f32` | `0.2` | Downhill ground-snap distance (0 = off) |\n * | `grounded` | `bool` | `false` | Engine-written: grounded after last move |\n */\nexport const CharacterController = defineComponent('CharacterController', {\n offset: { type: 'f32', default: 0.01 },\n maxSlopeClimbDeg: { type: 'f32', default: 45 },\n minSlopeSlideDeg: { type: 'f32', default: 30 },\n autoStepMaxHeight: { type: 'f32', default: 0.3 },\n autoStepMinWidth: { type: 'f32', default: 0.2 },\n snapToGroundDist: { type: 'f32', default: 0.2 },\n grounded: { type: 'bool', default: false, transient: true },\n});\n\n/**\n * ECS Component: set of entities currently colliding with the holder entity.\n *\n * Maintained by the physics tick systems — entities are added on collision\n * start (`CollisionEvent.started`) and removed on collision stop\n * (`CollisionEvent.stopped`). AI users query this component to know whose\n * colliders overlap right now without consuming per-frame events.\n *\n * This is the `'continued'` equivalent — no repeated per-frame events,\n * one component query per frame exposes the full active contact set\n * (plan-strategy D-3: CollidingEntities set-query mode).\n */\nexport const CollidingEntities = defineComponent(\n 'CollidingEntities',\n {\n entities: { type: 'array<entity>' },\n },\n { transient: true },\n);\n\nconst PHYSICS_COMPONENTS: readonly Component[] = [\n CharacterController,\n Collider,\n CollidingEntities,\n RigidBody,\n];\n\n/** Install the physics component vocabulary in a World and release its leases on teardown. */\nexport function registerPhysicsComponents(world: World): () => void {\n const leases = PHYSICS_COMPONENTS.map((component) =>\n world.components.register(component).unwrap(),\n );\n return () => {\n for (let index = leases.length - 1; index >= 0; index -= 1) leases[index]?.dispose();\n };\n}\n","import { err, ok, type Result } from '@forgeax/engine-types';\n\n/** A portable integer grid coordinate. */\nexport type VoxelCell = readonly [number, number, number];\n\n/** A portable quaternion used by derived-physics inputs. */\nexport type PhysicsQuaternion = readonly [number, number, number, number];\n\n/** A portable three-component vector used by derived-physics inputs. */\nexport type PhysicsVector = readonly [number, number, number];\n\n/**\n * One local voxel shape. `cells` contains contiguous x/y/z triples. The\n * backend copies it while preparing a candidate, so callers may reuse their\n * scratch buffer after the call returns.\n */\nexport interface VoxelShapeInput {\n readonly id: string;\n readonly revision: number;\n readonly cells: Int32Array | readonly VoxelCell[];\n readonly voxelSize: PhysicsVector;\n readonly origin?: PhysicsVector;\n readonly rotation?: PhysicsQuaternion;\n readonly friction?: number;\n readonly restitution?: number;\n readonly density?: number;\n readonly isSensor?: boolean;\n readonly collisionGroups?: number;\n readonly solverGroups?: number;\n}\n\n/** Stable producer identity and revision for one constraint endpoint. */\nexport interface PhysicsConstraintBodyDependency {\n readonly sourceKey: string;\n readonly revision: number;\n}\n\n/** Explicit or density-derived rigid-body mass properties. */\nexport type PhysicsMassProperties =\n | {\n readonly mode: 'automatic';\n readonly density?: number;\n }\n | {\n readonly mode: 'explicit';\n readonly mass: number;\n readonly centerOfMass: PhysicsVector;\n readonly principalInertia: PhysicsVector;\n readonly principalInertiaLocalFrame?: PhysicsQuaternion;\n };\n\n/** How a topology replacement carries the committed body's motion. */\nexport type PhysicsVelocityPolicy = 'preserve' | 'reset';\n\n/**\n * Consumer-visible movement state for one committed derived body.\n *\n * `centerOfMass` is world-space (the same frame as the body's transform),\n * while both velocity vectors are world-space. Keeping this as one POD\n * value makes snapshot/recovery carry the complete motion boundary instead\n * of exposing Rapier objects or asking consumers to infer velocity from\n * successive transforms.\n */\nexport interface DerivedPhysicsMotion {\n readonly centerOfMass: PhysicsVector;\n readonly linearVelocity: PhysicsVector;\n readonly angularVelocity: PhysicsVector;\n /** World-space xyzw orientation; omitted input preserves the native orientation. */\n readonly rotation?: PhysicsQuaternion;\n}\n\n/** Stable, consumer-owned constraint input. */\nexport type PhysicsConstraintInput =\n | {\n readonly id: string;\n readonly revision: number;\n readonly kind: 'spring';\n readonly bodyA: number;\n readonly bodyB: number;\n readonly bodyASource: PhysicsConstraintBodyDependency;\n readonly bodyBSource: PhysicsConstraintBodyDependency;\n readonly anchorA: PhysicsVector;\n readonly anchorB: PhysicsVector;\n readonly restLength: number;\n readonly stiffness: number;\n readonly damping: number;\n }\n | {\n readonly id: string;\n readonly revision: number;\n readonly kind: 'hinge';\n readonly bodyA: number;\n readonly bodyB: number;\n readonly bodyASource: PhysicsConstraintBodyDependency;\n readonly bodyBSource: PhysicsConstraintBodyDependency;\n readonly anchorA: PhysicsVector;\n readonly anchorB: PhysicsVector;\n readonly axis: PhysicsVector;\n readonly limits?: readonly [number, number];\n };\n\n/** All data needed to prepare one body's derived shape replacement. */\nexport interface DerivedPhysicsCandidateInput {\n readonly entity: number;\n readonly revision: number;\n readonly sourceKey: string;\n /** Empty clears derived shapes; ordinary colliders and ECS body lifetime remain independent. */\n readonly shapes: readonly VoxelShapeInput[];\n readonly seams?: readonly DerivedShapeSeamInput[];\n readonly bodyType?: 'static' | 'dynamic' | 'kinematic';\n readonly massProperties?: PhysicsMassProperties;\n readonly velocityPolicy?: PhysicsVelocityPolicy;\n /** Optional committed motion to restore after native mass admission. */\n readonly motion?: DerivedPhysicsMotion;\n readonly constraints?: readonly PhysicsConstraintInput[];\n /** Optional World identity; it is checked when the backend is ECS-bound. */\n readonly worldIdentity?: object;\n}\n\n/** A same-body integer-grid seam maintained by the Rapier voxel backend. */\nexport interface DerivedShapeSeamInput {\n readonly shapeA: string;\n readonly shapeB: string;\n /** Grid-space origin of B relative to A; all components must be integers. */\n readonly offset: PhysicsVector;\n}\n\n/** Candidate lifecycle visible to a consumer. */\nexport type DerivedPhysicsCandidateState =\n | 'ready'\n | 'queued'\n | 'published'\n | 'cancelled'\n | 'invalidated'\n | 'failed';\n\n/** Opaque-enough prepared candidate. Native handles never cross this type. */\nexport interface DerivedPhysicsCandidate {\n readonly candidateId: string;\n readonly generation: number;\n /** Per-PhysicsWorld owner identity; candidate IDs are not global. */\n readonly owner: object;\n readonly input: Readonly<DerivedPhysicsCandidateInput>;\n readonly state: DerivedPhysicsCandidateState;\n}\n\n/** Stable receipt emitted when a candidate becomes the committed shape set. */\nexport interface DerivedPhysicsPublication {\n readonly candidateId: string;\n readonly entity: number;\n readonly revision: number;\n readonly fixedStep: number;\n readonly shapeIds: readonly string[];\n readonly generation: number;\n}\n\n/** Structured admission failure that leaves the prior publication queryable. */\nexport interface DerivedPhysicsFailure {\n readonly candidateId: string;\n readonly entity: number;\n readonly revision: number;\n readonly fixedStep: number;\n readonly error: DerivedPhysicsError;\n readonly recovery: 'old-state-retained' | 'rebuild-required';\n}\n\n/** Public projection of an active local shape. */\nexport interface DerivedShapeState {\n readonly id: string;\n readonly revision: number;\n readonly entity: number;\n readonly voxelSize: PhysicsVector;\n readonly origin: PhysicsVector;\n readonly rotation: PhysicsQuaternion;\n readonly generation: number;\n}\n\n/** Real backend contact observation, including stable shape identity when known. */\nexport interface PhysicsContactObservation {\n readonly phase: 'started' | 'stopped';\n readonly fixedStep: number;\n readonly entityA: number;\n readonly entityB: number;\n readonly shapeA?: string;\n readonly shapeB?: string;\n /** World-space contact sample from either surface, when available. */\n readonly point?: PhysicsVector;\n /** World-space normal oriented from entityA toward entityB, when available. */\n readonly normal?: PhysicsVector;\n}\n\n/** Portable recovery input produced from a committed derived state. */\nexport interface DerivedPhysicsSnapshot {\n readonly generation: number;\n readonly fixedStep: number;\n readonly bodies: readonly {\n readonly entity: number;\n readonly revision: number;\n readonly sourceKey: string;\n readonly shapes: readonly VoxelShapeInput[];\n readonly seams?: readonly DerivedShapeSeamInput[];\n readonly bodyType?: 'static' | 'dynamic' | 'kinematic';\n readonly massProperties?: PhysicsMassProperties;\n readonly velocityPolicy?: PhysicsVelocityPolicy;\n /** Committed world-space COM and velocities at capture time. */\n readonly motion?: DerivedPhysicsMotion;\n readonly constraints: readonly PhysicsConstraintInput[];\n }[];\n}\n\nexport type DerivedPhysicsErrorCode =\n | 'derived-physics-disposed'\n | 'derived-body-not-found'\n | 'derived-world-mismatch'\n | 'derived-candidate-not-found'\n | 'derived-candidate-stale'\n | 'derived-candidate-pending'\n | 'derived-candidate-cancelled'\n | 'derived-candidate-invalid'\n | 'derived-candidate-budget-exceeded'\n | 'derived-shape-invalid'\n | 'derived-shape-duplicate'\n | 'derived-seam-invalid'\n | 'derived-mass-invalid'\n | 'derived-constraint-invalid'\n | 'derived-constraint-not-found'\n | 'derived-constraint-stale'\n | 'derived-backend-failed'\n | 'derived-recovery-invalid';\n\n/** Bounded derived-physics preparation envelope. */\nexport const DERIVED_PHYSICS_LIMITS = Object.freeze({\n maxCandidates: 32,\n maxShapesPerCandidate: 64,\n maxConstraintsPerCandidate: 64,\n maxCellsPerCandidate: 262_144,\n maxCandidateBytes: 8 * 1024 * 1024,\n});\n\nexport interface DerivedPhysicsErrorDetail {\n readonly code: DerivedPhysicsErrorCode;\n readonly entity?: number;\n readonly candidateId?: string;\n readonly shapeId?: string;\n readonly constraintId?: string;\n readonly expected?: string;\n readonly actual?: unknown;\n readonly reason?: string;\n}\n\n/** Closed, structured failure for the public derived-physics surface. */\nexport class DerivedPhysicsError extends Error {\n readonly code: DerivedPhysicsErrorCode;\n readonly expected: string;\n readonly hint: string;\n readonly detail: DerivedPhysicsErrorDetail;\n\n constructor(\n code: DerivedPhysicsErrorCode,\n expected: string,\n hint: string,\n detail: Omit<DerivedPhysicsErrorDetail, 'code'> = {},\n ) {\n super(`${code}: ${expected}`);\n this.name = 'DerivedPhysicsError';\n this.code = code;\n this.expected = expected;\n this.hint = hint;\n this.detail = Object.freeze({ code, ...detail });\n }\n}\n\nconst ID_RE = /\\S/;\n\nfunction finite(value: number): boolean {\n return Number.isFinite(value);\n}\n\nfunction vectorFinite(vector: readonly number[], length: number): boolean {\n return vector.length === length && vector.every(finite);\n}\n\n/** Rotate a local origin delta into the shared grid frame used by a seam. */\nfunction rotateVectorByQuaternion(\n vector: readonly [number, number, number],\n rotation: readonly [number, number, number, number],\n): [number, number, number] {\n const [x, y, z] = vector;\n const [qx, qy, qz, qw] = rotation;\n const tx = 2 * (qy * z - qz * y);\n const ty = 2 * (qz * x - qx * z);\n const tz = 2 * (qx * y - qy * x);\n return [\n x + qw * tx + qy * tz - qz * ty,\n y + qw * ty + qz * tx - qx * tz,\n z + qw * tz + qx * ty - qy * tx,\n ];\n}\n\nfunction normalizedQuaternion(rotation: PhysicsQuaternion): PhysicsQuaternion | undefined {\n if (!vectorFinite(rotation, 4)) return undefined;\n const length = Math.hypot(rotation[0], rotation[1], rotation[2], rotation[3]);\n if (!finite(length) || length < 1e-6) return undefined;\n return [rotation[0] / length, rotation[1] / length, rotation[2] / length, rotation[3] / length];\n}\n\nfunction copyCells(cells: Int32Array | readonly VoxelCell[]): Int32Array | undefined {\n if (cells instanceof Int32Array) return new Int32Array(cells);\n const result = new Int32Array(cells.length * 3);\n for (let index = 0; index < cells.length; index += 1) {\n const cell = cells[index];\n if (cell === undefined || cell.length !== 3 || cell.some((value) => !Number.isInteger(value))) {\n return undefined;\n }\n result[index * 3] = cell[0] ?? 0;\n result[index * 3 + 1] = cell[1] ?? 0;\n result[index * 3 + 2] = cell[2] ?? 0;\n }\n return result;\n}\n\n/** Validate and snapshot one voxel input before native resources are created. */\nexport function normalizeVoxelShapeInput(input: VoxelShapeInput): Result<\n VoxelShapeInput & {\n readonly cells: Int32Array;\n readonly origin: PhysicsVector;\n readonly rotation: PhysicsQuaternion;\n },\n DerivedPhysicsError\n> {\n if (typeof input.id !== 'string' || !ID_RE.test(input.id)) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-invalid',\n 'voxel shape id is a non-empty stable string',\n 'provide a stable shape identity from the consumer state',\n { shapeId: input.id },\n ),\n );\n }\n if (!Number.isInteger(input.revision) || input.revision < 0) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-invalid',\n 'voxel shape revision is a non-negative integer',\n 'increment the shape revision when its cells or transform changes',\n { shapeId: input.id, actual: input.revision },\n ),\n );\n }\n const cells = copyCells(input.cells);\n if (cells === undefined || cells.length === 0 || cells.length % 3 !== 0) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-invalid',\n 'voxel cells contain at least one complete integer x/y/z triple',\n 'supply a non-empty Int32Array or cell tuple list',\n { shapeId: input.id, actual: cells?.length },\n ),\n );\n }\n const voxelSize = input.voxelSize;\n if (!vectorFinite(voxelSize, 3) || voxelSize.some((value) => value <= 0)) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-invalid',\n 'voxelSize contains finite positive components',\n 'choose a finite positive voxel size for every axis',\n { shapeId: input.id, actual: voxelSize },\n ),\n );\n }\n for (const value of cells) {\n if (!Number.isInteger(value)) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-invalid',\n 'voxel coordinates are integers',\n 'quantize cells before submitting a physics candidate',\n { shapeId: input.id, actual: value },\n ),\n );\n }\n }\n const origin = input.origin ?? [0, 0, 0];\n if (!vectorFinite(origin, 3)) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-invalid',\n 'voxel origin contains finite coordinates',\n 'supply a finite local origin',\n { shapeId: input.id, actual: origin },\n ),\n );\n }\n const rotation = normalizedQuaternion(input.rotation ?? [0, 0, 0, 1]);\n if (rotation === undefined) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-invalid',\n 'voxel rotation is a finite non-degenerate quaternion',\n 'normalize the local voxel orientation before submitting it',\n { shapeId: input.id, actual: input.rotation },\n ),\n );\n }\n for (const [name, value] of [\n ['friction', input.friction],\n ['restitution', input.restitution],\n ['density', input.density],\n ] as const) {\n if (value !== undefined && (!finite(value) || value < 0)) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-invalid',\n `${name} is finite and non-negative`,\n `repair the ${name} input before native preparation`,\n { shapeId: input.id, actual: value },\n ),\n );\n }\n }\n return ok(\n Object.freeze({\n ...input,\n cells,\n voxelSize: [voxelSize[0], voxelSize[1], voxelSize[2]] as PhysicsVector,\n origin: [origin[0], origin[1], origin[2]] as PhysicsVector,\n rotation,\n }),\n );\n}\n\n/** Validate explicit mass/inertia values before touching the backend. */\nexport function validateMassProperties(\n properties: PhysicsMassProperties | undefined,\n): Result<PhysicsMassProperties | undefined, DerivedPhysicsError> {\n if (properties === undefined || properties.mode === 'automatic') {\n if (\n properties?.density !== undefined &&\n (!finite(properties.density) || properties.density <= 0)\n ) {\n return err(\n new DerivedPhysicsError(\n 'derived-mass-invalid',\n 'automatic density is finite and positive',\n 'omit density to use backend density or provide a positive density',\n { actual: properties.density },\n ),\n );\n }\n return ok(properties);\n }\n if (\n !finite(properties.mass) ||\n properties.mass <= 0 ||\n !vectorFinite(properties.centerOfMass, 3) ||\n !vectorFinite(properties.principalInertia, 3) ||\n properties.principalInertia.some((value) => !finite(value) || value <= 0)\n ) {\n return err(\n new DerivedPhysicsError(\n 'derived-mass-invalid',\n 'explicit mass, center of mass, and principal inertia are finite and non-degenerate',\n 'provide positive mass/inertia and a finite center of mass',\n { actual: properties },\n ),\n );\n }\n const frame = normalizedQuaternion(properties.principalInertiaLocalFrame ?? [0, 0, 0, 1]);\n if (frame === undefined) {\n return err(\n new DerivedPhysicsError(\n 'derived-mass-invalid',\n 'principal inertia local frame is a finite non-degenerate quaternion',\n 'normalize the inertia frame before submitting it',\n { actual: properties.principalInertiaLocalFrame },\n ),\n );\n }\n return ok(\n Object.freeze({\n ...properties,\n centerOfMass: [...properties.centerOfMass] as PhysicsVector,\n principalInertia: [...properties.principalInertia] as PhysicsVector,\n principalInertiaLocalFrame: frame,\n }),\n );\n}\n\n/** The required linear velocity correction for a committed COM change. */\nexport function preserveCenterOfMassVelocity(\n linearVelocity: PhysicsVector,\n angularVelocity: PhysicsVector,\n previousWorldCom: PhysicsVector,\n nextWorldCom: PhysicsVector,\n): PhysicsVector {\n const dx = nextWorldCom[0] - previousWorldCom[0];\n const dy = nextWorldCom[1] - previousWorldCom[1];\n const dz = nextWorldCom[2] - previousWorldCom[2];\n return [\n linearVelocity[0] + angularVelocity[1] * dz - angularVelocity[2] * dy,\n linearVelocity[1] + angularVelocity[2] * dx - angularVelocity[0] * dz,\n linearVelocity[2] + angularVelocity[0] * dy - angularVelocity[1] * dx,\n ];\n}\n\n/** Snapshot an input without retaining caller-owned typed-array references. */\nexport function cloneDerivedPhysicsInput(\n input: DerivedPhysicsCandidateInput,\n): Result<DerivedPhysicsCandidateInput, DerivedPhysicsError> {\n if (!Number.isInteger(input.entity) || input.entity < 0) {\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-invalid',\n 'candidate entity is a non-negative ECS entity value',\n 'submit a live entity from the same World',\n { entity: input.entity },\n ),\n );\n }\n if (!Number.isInteger(input.revision) || input.revision < 0) {\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-invalid',\n 'candidate revision is a non-negative integer',\n 'advance the consumer topology revision monotonically',\n { entity: input.entity, actual: input.revision },\n ),\n );\n }\n if (typeof input.sourceKey !== 'string' || !ID_RE.test(input.sourceKey)) {\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-invalid',\n 'candidate sourceKey is a non-empty stable producer identity',\n 'carry the producer sourceKey with every derived body revision',\n { entity: input.entity, actual: input.sourceKey },\n ),\n );\n }\n if (input.shapes.length > DERIVED_PHYSICS_LIMITS.maxShapesPerCandidate) {\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-budget-exceeded',\n `one candidate contains at most ${DERIVED_PHYSICS_LIMITS.maxShapesPerCandidate} derived shapes`,\n 'split the consumer operation at a body boundary and retry',\n { entity: input.entity, actual: input.shapes.length },\n ),\n );\n }\n const seen = new Set<string>();\n const shapes: VoxelShapeInput[] = [];\n for (const shape of input.shapes) {\n if (seen.has(shape.id)) {\n return err(\n new DerivedPhysicsError(\n 'derived-shape-duplicate',\n 'one candidate has one identity per derived shape',\n 'merge or rename duplicate shape inputs before preparation',\n { entity: input.entity, shapeId: shape.id },\n ),\n );\n }\n seen.add(shape.id);\n const normalized = normalizeVoxelShapeInput(shape);\n if (!normalized.ok) return normalized;\n shapes.push(normalized.value);\n }\n const motionRotation =\n input.motion?.rotation === undefined ? undefined : normalizedQuaternion(input.motion.rotation);\n if (input.motion?.rotation !== undefined && motionRotation === undefined)\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-invalid',\n 'optional motion rotation is a finite non-degenerate world-space quaternion',\n 'supply a valid xyzw body orientation or omit it to preserve the native orientation',\n { entity: input.entity, actual: input.motion.rotation },\n ),\n );\n const mass = validateMassProperties(input.massProperties);\n if (!mass.ok) return mass;\n if (\n input.motion !== undefined &&\n (!vectorFinite(input.motion.centerOfMass, 3) ||\n !vectorFinite(input.motion.linearVelocity, 3) ||\n !vectorFinite(input.motion.angularVelocity, 3))\n ) {\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-invalid',\n 'optional movement state contains finite world-space COM and velocity vectors',\n 'capture or provide three finite components for centerOfMass, linearVelocity, and angularVelocity',\n { entity: input.entity, actual: input.motion },\n ),\n );\n }\n const constraints = input.constraints ?? [];\n if (constraints.length > DERIVED_PHYSICS_LIMITS.maxConstraintsPerCandidate) {\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-budget-exceeded',\n `one candidate contains at most ${DERIVED_PHYSICS_LIMITS.maxConstraintsPerCandidate} constraint updates`,\n 'submit a bounded constraint set for this body',\n { entity: input.entity, actual: constraints.length },\n ),\n );\n }\n const seams = input.seams ?? [];\n const shapeById = new Map(shapes.map((shape) => [shape.id, shape]));\n for (const seam of seams) {\n const a = shapeById.get(seam.shapeA);\n const b = shapeById.get(seam.shapeB);\n const aRotation = a?.rotation ?? [0, 0, 0, 1];\n const bRotation = b?.rotation ?? [0, 0, 0, 1];\n const aOrigin = a?.origin ?? [0, 0, 0];\n const bOrigin = b?.origin ?? [0, 0, 0];\n const quaternionDot = aRotation.reduce(\n (sum, value, index) => sum + value * (bRotation[index] ?? 0),\n 0,\n );\n const localOriginDelta: [number, number, number] = [\n (bOrigin[0] ?? 0) - (aOrigin[0] ?? 0),\n (bOrigin[1] ?? 0) - (aOrigin[1] ?? 0),\n (bOrigin[2] ?? 0) - (aOrigin[2] ?? 0),\n ];\n // `origin` is expressed in the body's frame while Rapier's seam shift is\n // expressed in shape A's voxel frame. Move the body-local delta through\n // the inverse of A's local-to-body rotation before quantizing it.\n const sharedGridDelta = rotateVectorByQuaternion(localOriginDelta, [\n -aRotation[0],\n -aRotation[1],\n -aRotation[2],\n aRotation[3],\n ]);\n const alignedOrigins =\n a !== undefined &&\n b !== undefined &&\n seam.offset.every(\n (value, index) =>\n Math.abs((sharedGridDelta[index] ?? 0) / (a?.voxelSize[index] ?? 1) - value) <= 1e-5,\n );\n if (\n a === undefined ||\n b === undefined ||\n a.id === b.id ||\n !vectorFinite(seam.offset, 3) ||\n seam.offset.some((value) => !Number.isInteger(value)) ||\n a.voxelSize.some((value, index) => Math.abs(value - (b.voxelSize[index] ?? 0)) > 1e-6) ||\n Math.abs(Math.abs(quaternionDot) - 1) > 1e-5 ||\n !alignedOrigins\n ) {\n return err(\n new DerivedPhysicsError(\n 'derived-seam-invalid',\n 'a voxel seam joins same-grid shapes with integer offset in the shared rotated grid frame',\n 'rotate the local origin delta into the shared grid frame and use an integer grid offset',\n { entity: input.entity, shapeId: seam.shapeA },\n ),\n );\n }\n }\n const seenConstraints = new Set<string>();\n for (const constraint of constraints) {\n if (seenConstraints.has(constraint.id)) {\n return err(\n new DerivedPhysicsError(\n 'derived-constraint-invalid',\n 'one candidate contains one update per constraint identity',\n 'merge duplicate constraint updates before preparation',\n { entity: input.entity, constraintId: constraint.id },\n ),\n );\n }\n seenConstraints.add(constraint.id);\n for (const dependency of [constraint.bodyASource, constraint.bodyBSource]) {\n if (\n typeof dependency.sourceKey !== 'string' ||\n !ID_RE.test(dependency.sourceKey) ||\n !Number.isInteger(dependency.revision) ||\n dependency.revision < 0\n ) {\n return err(\n new DerivedPhysicsError(\n 'derived-constraint-invalid',\n 'constraint endpoint sourceKey and revision are stable and non-negative',\n 'refresh both endpoint dependencies before preparing the constraint',\n { entity: input.entity, constraintId: constraint.id },\n ),\n );\n }\n }\n }\n const cellCount = shapes.reduce((sum, shape) => sum + shape.cells.length / 3, 0);\n if (cellCount > DERIVED_PHYSICS_LIMITS.maxCellsPerCandidate) {\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-budget-exceeded',\n `one candidate contains at most ${DERIVED_PHYSICS_LIMITS.maxCellsPerCandidate} cells`,\n 'reduce the voxel input or split it at a body boundary',\n { entity: input.entity, actual: cellCount },\n ),\n );\n }\n if (\n estimateDerivedPhysicsInputBytes({ ...input, shapes, constraints, seams }) >\n DERIVED_PHYSICS_LIMITS.maxCandidateBytes\n ) {\n return err(\n new DerivedPhysicsError(\n 'derived-candidate-budget-exceeded',\n `one candidate stages at most ${DERIVED_PHYSICS_LIMITS.maxCandidateBytes} bytes`,\n 'reduce cells and constraint metadata before preparing the candidate',\n { entity: input.entity },\n ),\n );\n }\n return ok(\n Object.freeze({\n ...input,\n shapes: Object.freeze(shapes),\n seams: Object.freeze(\n seams.map((seam) => ({ ...seam, offset: [...seam.offset] as PhysicsVector })),\n ),\n ...(mass.value === undefined ? {} : { massProperties: mass.value }),\n ...(input.motion === undefined\n ? {}\n : {\n motion: Object.freeze({\n centerOfMass: [...input.motion.centerOfMass] as PhysicsVector,\n linearVelocity: [...input.motion.linearVelocity] as PhysicsVector,\n angularVelocity: [...input.motion.angularVelocity] as PhysicsVector,\n ...(motionRotation === undefined ? {} : { rotation: motionRotation }),\n }),\n }),\n constraints: Object.freeze([...constraints]),\n velocityPolicy: input.velocityPolicy ?? 'preserve',\n }),\n );\n}\n\n/** Estimate staged CPU/native input bytes for the bounded admission budget. */\nexport function estimateDerivedPhysicsInputBytes(input: DerivedPhysicsCandidateInput): number {\n const shapeBytes = input.shapes.reduce(\n (sum, shape) =>\n sum +\n (shape.cells instanceof Int32Array ? shape.cells.length / 3 : shape.cells.length) * 32 +\n 128,\n 0,\n );\n const seamBytes = (input.seams?.length ?? 0) * 64;\n const constraintBytes = (input.constraints?.length ?? 0) * 192;\n return shapeBytes + seamBytes + constraintBytes + 256;\n}\n","// Keep literal specifiers visible to bundlers without pulling backend declarations into the physics TypeScript graph.\nexport function loadRapier3DBackend() {\n return import('@forgeax/engine-physics-rapier3d');\n}\n\nexport function loadRapier2DBackend() {\n return import('@forgeax/engine-physics-rapier2d');\n}\n","// @forgeax/engine-physics -- physicsPlugin(backend) factory (M2 / w10, plan-strategy D-5 / D-7).\n//\n// physicsPlugin lives in @forgeax/engine-physics (the interface package, C-9)\n// and accepts an interface->backend dependency inversion: its async apply\n// dynamic-imports the rapier 2D / 3D backend on demand. The backends are\n// optional peerDependencies in this package's package.json (a regular\n// dependency would form a physics <-> rapier cycle since the backends depend on\n// the interface package); the consuming app declares the selected runtime dep.\n//\n// charter awareness:\n// P3 explicit failure: WASM load failure rejects plugin activation and the\n// App boundary preserves the cause; it is never a silent skip.\n// P4 consistent abstraction: physicsPlugin shares the same Plugin shape as\n// transform / audio -- one mental model covers every wiring.\n\nimport type { Plugin } from '@forgeax/engine-plugin';\nimport { registerPhysicsComponents } from './components.js';\nimport { PhysicsError } from './errors.js';\nimport { loadRapier2DBackend, loadRapier3DBackend } from './load-rapier-backend.mjs';\nimport type { PhysicsWorld, PhysicsWorld2D } from './physics-world.js';\n\ninterface Rapier3DBackendModule {\n loadRapier3D(): Promise<unknown>;\n createRapier3DPhysicsWorld(rapier: unknown): PhysicsWorld;\n registerPhysicsSystems(world: import('@forgeax/engine-ecs').World): () => void;\n}\n\ninterface Rapier2DBackendModule {\n loadRapier2D(): Promise<unknown>;\n createRapier2DPhysicsWorld(rapier: unknown): PhysicsWorld2D;\n registerPhysicsSystems2D(world: import('@forgeax/engine-ecs').World): () => void;\n}\n\n/** Rapier backend selector. */\nexport type PhysicsBackend = 'rapier-2d' | 'rapier-3d';\n\nfunction normalizeWasmLoadFailure(backend: PhysicsBackend, cause: unknown): PhysicsError {\n if (cause instanceof PhysicsError && cause.code === 'wasm-load-failed') return cause;\n const reason = cause instanceof Error ? cause.message : String(cause);\n return new PhysicsError({\n code: 'wasm-load-failed',\n expected: `successful import and WASM initialization for ${backend}`,\n hint: `Rapier backend activation failed: ${reason}`,\n detail: { code: 'wasm-load-failed', reason },\n });\n}\n\ndeclare module '@forgeax/engine-plugin' {\n interface EngineContextServices {\n physics?: PhysicsWorld | PhysicsWorld2D;\n }\n}\n\n/**\n * physicsPlugin(backend) dynamically imports the Rapier backend,\n * loads the WASM module, creates the PhysicsWorld, inserts it as the\n * 'PhysicsWorld' world resource, and registers the three-phase tick systems.\n *\n * The resource is inserted before registering systems so moveAndSlide resolves\n * `PhysicsWorld` on the first tick. Cordis owns rollback if any later effect\n * fails.\n *\n * @param backend 'rapier-2d' or 'rapier-3d'\n */\nexport function physicsPlugin(backend: PhysicsBackend): Plugin {\n return {\n name: 'physics',\n inject: ['world'],\n provide: 'physics',\n async apply(ctx) {\n const world = ctx.world;\n let physics: PhysicsWorld | PhysicsWorld2D;\n let registerSystems: () => () => void;\n if (backend === 'rapier-3d') {\n let module: Rapier3DBackendModule;\n let rapier: unknown;\n try {\n module = (await loadRapier3DBackend()) as Rapier3DBackendModule;\n rapier = await module.loadRapier3D();\n } catch (cause) {\n throw normalizeWasmLoadFailure(backend, cause);\n }\n if (rapier instanceof PhysicsError) throw normalizeWasmLoadFailure(backend, rapier);\n const { createRapier3DPhysicsWorld, registerPhysicsSystems } = module;\n physics = createRapier3DPhysicsWorld(rapier);\n registerSystems = () => registerPhysicsSystems(world);\n } else {\n let module: Rapier2DBackendModule;\n let rapier: unknown;\n try {\n module = (await loadRapier2DBackend()) as Rapier2DBackendModule;\n rapier = await module.loadRapier2D();\n } catch (cause) {\n throw normalizeWasmLoadFailure(backend, cause);\n }\n if (rapier instanceof PhysicsError) throw normalizeWasmLoadFailure(backend, rapier);\n const { createRapier2DPhysicsWorld, registerPhysicsSystems2D } = module;\n physics = createRapier2DPhysicsWorld(rapier);\n registerSystems = () => registerPhysicsSystems2D(world);\n }\n ctx.effect(() => registerPhysicsComponents(world), 'physics/components');\n ctx.effect(() => {\n world.insertResource('PhysicsWorld', physics);\n return () => {\n world.removeResource('PhysicsWorld');\n physics.dispose();\n };\n }, 'physics/resource');\n ctx.effect(() => {\n const unregister = registerSystems();\n return () => unregister();\n }, 'physics/systems');\n ctx.provide('physics', physics);\n },\n };\n}\n","import { defineSystemSet } from '@forgeax/engine-ecs';\n\nexport const PhysicsSet = defineSystemSet({ name: 'physics' });\n"]}
|
package/dist/physics-world.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Vec2, Vec3 } from '@forgeax/engine-math';
|
|
2
2
|
import type { Result } from '@forgeax/engine-types';
|
|
3
|
-
import type { DerivedPhysicsCandidate, DerivedPhysicsCandidateInput, DerivedPhysicsError, DerivedPhysicsFailure, DerivedPhysicsMotion, DerivedPhysicsPublication, DerivedPhysicsSnapshot, DerivedShapeState, PhysicsConstraintInput, PhysicsContactObservation } from './derived-physics';
|
|
3
|
+
import type { DerivedPhysicsCandidate, DerivedPhysicsCandidateInput, DerivedPhysicsError, DerivedPhysicsFailure, DerivedPhysicsMotion, DerivedPhysicsPublication, DerivedPhysicsSnapshot, DerivedShapeState, PhysicsConstraintInput, PhysicsContactObservation, PhysicsVector } from './derived-physics.js';
|
|
4
4
|
/**
|
|
5
5
|
* Raycast hit result — returned by `PhysicsWorld.raycast()`.
|
|
6
6
|
*
|
|
@@ -109,6 +109,13 @@ export interface PhysicsWorld {
|
|
|
109
109
|
* writes and requires rebuild. Reentrant physics access is refused.
|
|
110
110
|
*/
|
|
111
111
|
admitDerivedShapeCandidate?: (candidate: DerivedPhysicsCandidate, commitGeometry?: () => Result<void, Error>) => Result<DerivedPhysicsCandidate, DerivedPhysicsError>;
|
|
112
|
+
/**
|
|
113
|
+
* Queue one bounded replacement across distinct bodies. Native preparation
|
|
114
|
+
* completes for every member before the single geometry callback; any member
|
|
115
|
+
* failure rolls the group back. A thrown callback or failed rollback requires
|
|
116
|
+
* rebuilding the PhysicsWorld. Preparation/candidate budgets remain shared.
|
|
117
|
+
*/
|
|
118
|
+
admitDerivedShapeCandidates?: (candidates: readonly DerivedPhysicsCandidate[], commitGeometry?: () => Result<void, Error>) => Result<readonly DerivedPhysicsCandidate[], DerivedPhysicsError>;
|
|
112
119
|
/** Borrowed ordering proof, present only inside the paired geometry commit. */
|
|
113
120
|
getDerivedAdmission?: (entity?: number) => {
|
|
114
121
|
readonly entity: number;
|
|
@@ -131,6 +138,20 @@ export interface PhysicsWorld {
|
|
|
131
138
|
getDerivedBodyMass?: (entity: number) => number | undefined;
|
|
132
139
|
/** Read the committed world-space COM and velocities for one derived body. */
|
|
133
140
|
getDerivedMotion?: (entity: number) => DerivedPhysicsMotion | undefined;
|
|
141
|
+
/**
|
|
142
|
+
* Apply a world-space impulse at a world-space point on the exact committed
|
|
143
|
+
* dynamic body revision. Call after syncBackend and before stepSimulation.
|
|
144
|
+
* Rejects queued admission, stale identity and invalid vectors; never moves
|
|
145
|
+
* the pose directly. A partially failed native write requires World recovery.
|
|
146
|
+
* The caller bounds impulse magnitude, normally maxForce * FixedTime.delta.
|
|
147
|
+
*/
|
|
148
|
+
applyDerivedImpulse?: (input: {
|
|
149
|
+
readonly entity: number;
|
|
150
|
+
readonly sourceKey: string;
|
|
151
|
+
readonly revision: number;
|
|
152
|
+
readonly impulse: PhysicsVector;
|
|
153
|
+
readonly point: PhysicsVector;
|
|
154
|
+
}) => Result<void, DerivedPhysicsError>;
|
|
134
155
|
/** Read the currently committed local shape identities for one body. */
|
|
135
156
|
getDerivedShapes?: (entity: number) => readonly DerivedShapeState[];
|
|
136
157
|
/** Read detached contact observations from the latest fixed-step drain. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"physics-world.d.ts","sourceRoot":"","sources":["../src/physics-world.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,EACV,uBAAuB,EACvB,4BAA4B,EAC5B,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,yBAAyB,EACzB,sBAAsB,EACtB,iBAAiB,EACjB,sBAAsB,EACtB,yBAAyB,
|
|
1
|
+
{"version":3,"file":"physics-world.d.ts","sourceRoot":"","sources":["../src/physics-world.ts"],"names":[],"mappings":"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"}
|
package/dist/plugin-factory.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Plugin } from '@forgeax/engine-plugin';
|
|
2
|
-
import type { PhysicsWorld, PhysicsWorld2D } from './physics-world';
|
|
2
|
+
import type { PhysicsWorld, PhysicsWorld2D } from './physics-world.js';
|
|
3
3
|
/** Rapier backend selector. */
|
|
4
4
|
export type PhysicsBackend = 'rapier-2d' | 'rapier-3d';
|
|
5
5
|
declare module '@forgeax/engine-plugin' {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-factory.d.ts","sourceRoot":"","sources":["../src/plugin-factory.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAIrD,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"plugin-factory.d.ts","sourceRoot":"","sources":["../src/plugin-factory.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAIrD,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAcvE,+BAA+B;AAC/B,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,WAAW,CAAC;AAavD,OAAO,QAAQ,wBAAwB,CAAC;IACtC,UAAU,qBAAqB;QAC7B,OAAO,CAAC,EAAE,YAAY,GAAG,cAAc,CAAC;KACzC;CACF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAmD7D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgeax/engine-physics",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.30",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -26,21 +26,21 @@
|
|
|
26
26
|
"LICENSE"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@forgeax/engine-ecs": "0.1.
|
|
30
|
-
"@forgeax/engine-math": "0.1.
|
|
31
|
-
"@forgeax/engine-plugin": "0.1.
|
|
32
|
-
"@forgeax/engine-types": "0.1.
|
|
29
|
+
"@forgeax/engine-ecs": "0.1.30",
|
|
30
|
+
"@forgeax/engine-math": "0.1.30",
|
|
31
|
+
"@forgeax/engine-plugin": "0.1.30",
|
|
32
|
+
"@forgeax/engine-types": "0.1.30"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@forgeax/engine-assets-runtime": "0.1.
|
|
36
|
-
"@forgeax/engine-physics-rapier2d": "0.1.
|
|
37
|
-
"@forgeax/engine-physics-rapier3d": "0.1.
|
|
38
|
-
"@forgeax/engine-runtime": "0.1.
|
|
39
|
-
"@forgeax/engine-shader": "0.1.
|
|
35
|
+
"@forgeax/engine-assets-runtime": "0.1.30",
|
|
36
|
+
"@forgeax/engine-physics-rapier2d": "0.1.30",
|
|
37
|
+
"@forgeax/engine-physics-rapier3d": "0.1.30",
|
|
38
|
+
"@forgeax/engine-runtime": "0.1.30",
|
|
39
|
+
"@forgeax/engine-shader": "0.1.30"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@forgeax/engine-physics-rapier2d": "0.1.
|
|
43
|
-
"@forgeax/engine-physics-rapier3d": "0.1.
|
|
42
|
+
"@forgeax/engine-physics-rapier2d": "0.1.30",
|
|
43
|
+
"@forgeax/engine-physics-rapier3d": "0.1.30"
|
|
44
44
|
},
|
|
45
45
|
"peerDependenciesMeta": {
|
|
46
46
|
"@forgeax/engine-physics-rapier2d": {
|
package/src/derived-physics.ts
CHANGED
|
@@ -65,6 +65,8 @@ export interface DerivedPhysicsMotion {
|
|
|
65
65
|
readonly centerOfMass: PhysicsVector;
|
|
66
66
|
readonly linearVelocity: PhysicsVector;
|
|
67
67
|
readonly angularVelocity: PhysicsVector;
|
|
68
|
+
/** World-space xyzw orientation; omitted input preserves the native orientation. */
|
|
69
|
+
readonly rotation?: PhysicsQuaternion;
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
/** Stable, consumer-owned constraint input. */
|
|
@@ -102,6 +104,7 @@ export interface DerivedPhysicsCandidateInput {
|
|
|
102
104
|
readonly entity: number;
|
|
103
105
|
readonly revision: number;
|
|
104
106
|
readonly sourceKey: string;
|
|
107
|
+
/** Empty clears derived shapes; ordinary colliders and ECS body lifetime remain independent. */
|
|
105
108
|
readonly shapes: readonly VoxelShapeInput[];
|
|
106
109
|
readonly seams?: readonly DerivedShapeSeamInput[];
|
|
107
110
|
readonly bodyType?: 'static' | 'dynamic' | 'kinematic';
|
|
@@ -180,7 +183,9 @@ export interface PhysicsContactObservation {
|
|
|
180
183
|
readonly entityB: number;
|
|
181
184
|
readonly shapeA?: string;
|
|
182
185
|
readonly shapeB?: string;
|
|
186
|
+
/** World-space contact sample from either surface, when available. */
|
|
183
187
|
readonly point?: PhysicsVector;
|
|
188
|
+
/** World-space normal oriented from entityA toward entityB, when available. */
|
|
184
189
|
readonly normal?: PhysicsVector;
|
|
185
190
|
}
|
|
186
191
|
|
|
@@ -534,14 +539,11 @@ export function cloneDerivedPhysicsInput(
|
|
|
534
539
|
),
|
|
535
540
|
);
|
|
536
541
|
}
|
|
537
|
-
if (
|
|
538
|
-
input.shapes.length === 0 ||
|
|
539
|
-
input.shapes.length > DERIVED_PHYSICS_LIMITS.maxShapesPerCandidate
|
|
540
|
-
) {
|
|
542
|
+
if (input.shapes.length > DERIVED_PHYSICS_LIMITS.maxShapesPerCandidate) {
|
|
541
543
|
return err(
|
|
542
544
|
new DerivedPhysicsError(
|
|
543
545
|
'derived-candidate-budget-exceeded',
|
|
544
|
-
`one candidate contains
|
|
546
|
+
`one candidate contains at most ${DERIVED_PHYSICS_LIMITS.maxShapesPerCandidate} derived shapes`,
|
|
545
547
|
'split the consumer operation at a body boundary and retry',
|
|
546
548
|
{ entity: input.entity, actual: input.shapes.length },
|
|
547
549
|
),
|
|
@@ -565,6 +567,17 @@ export function cloneDerivedPhysicsInput(
|
|
|
565
567
|
if (!normalized.ok) return normalized;
|
|
566
568
|
shapes.push(normalized.value);
|
|
567
569
|
}
|
|
570
|
+
const motionRotation =
|
|
571
|
+
input.motion?.rotation === undefined ? undefined : normalizedQuaternion(input.motion.rotation);
|
|
572
|
+
if (input.motion?.rotation !== undefined && motionRotation === undefined)
|
|
573
|
+
return err(
|
|
574
|
+
new DerivedPhysicsError(
|
|
575
|
+
'derived-candidate-invalid',
|
|
576
|
+
'optional motion rotation is a finite non-degenerate world-space quaternion',
|
|
577
|
+
'supply a valid xyzw body orientation or omit it to preserve the native orientation',
|
|
578
|
+
{ entity: input.entity, actual: input.motion.rotation },
|
|
579
|
+
),
|
|
580
|
+
);
|
|
568
581
|
const mass = validateMassProperties(input.massProperties);
|
|
569
582
|
if (!mass.ok) return mass;
|
|
570
583
|
if (
|
|
@@ -717,6 +730,7 @@ export function cloneDerivedPhysicsInput(
|
|
|
717
730
|
centerOfMass: [...input.motion.centerOfMass] as PhysicsVector,
|
|
718
731
|
linearVelocity: [...input.motion.linearVelocity] as PhysicsVector,
|
|
719
732
|
angularVelocity: [...input.motion.angularVelocity] as PhysicsVector,
|
|
733
|
+
...(motionRotation === undefined ? {} : { rotation: motionRotation }),
|
|
720
734
|
}),
|
|
721
735
|
}),
|
|
722
736
|
constraints: Object.freeze([...constraints]),
|
package/src/index.ts
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
// @forgeax/engine-math (Vec2 / Vec3 / Quat),
|
|
8
8
|
// @forgeax/engine-types (type utilities).
|
|
9
9
|
|
|
10
|
-
export type { CollisionEventPayload } from './collision-event';
|
|
11
|
-
export { CollisionEvent } from './collision-event';
|
|
12
|
-
export type { ColliderShape, RigidBodyType } from './components';
|
|
10
|
+
export type { CollisionEventPayload } from './collision-event.js';
|
|
11
|
+
export { CollisionEvent } from './collision-event.js';
|
|
12
|
+
export type { ColliderShape, RigidBodyType } from './components.js';
|
|
13
13
|
export {
|
|
14
14
|
CharacterController,
|
|
15
15
|
COLLIDER_SHAPE_CAPSULE,
|
|
@@ -26,7 +26,7 @@ export {
|
|
|
26
26
|
RigidBodyTypeValue,
|
|
27
27
|
registerPhysicsComponents,
|
|
28
28
|
rigidBodyTypeFromF32,
|
|
29
|
-
} from './components';
|
|
29
|
+
} from './components.js';
|
|
30
30
|
export type {
|
|
31
31
|
DerivedPhysicsCandidate,
|
|
32
32
|
DerivedPhysicsCandidateInput,
|
|
@@ -48,7 +48,7 @@ export type {
|
|
|
48
48
|
PhysicsVelocityPolicy,
|
|
49
49
|
VoxelCell,
|
|
50
50
|
VoxelShapeInput,
|
|
51
|
-
} from './derived-physics';
|
|
51
|
+
} from './derived-physics.js';
|
|
52
52
|
export {
|
|
53
53
|
cloneDerivedPhysicsInput,
|
|
54
54
|
DERIVED_PHYSICS_LIMITS,
|
|
@@ -57,11 +57,11 @@ export {
|
|
|
57
57
|
normalizeVoxelShapeInput,
|
|
58
58
|
preserveCenterOfMassVelocity,
|
|
59
59
|
validateMassProperties,
|
|
60
|
-
} from './derived-physics';
|
|
61
|
-
export type { PhysicsErrorCode, PhysicsErrorDetail } from './errors';
|
|
60
|
+
} from './derived-physics.js';
|
|
61
|
+
export type { PhysicsErrorCode, PhysicsErrorDetail } from './errors.js';
|
|
62
62
|
|
|
63
|
-
export { PHYSICS_ERROR_HINTS, PhysicsError } from './errors';
|
|
64
|
-
export type { PhysicsWorld, PhysicsWorld2D, RaycastHit, RaycastHit2D } from './physics-world';
|
|
65
|
-
export type { PhysicsBackend } from './plugin-factory';
|
|
66
|
-
export { physicsPlugin } from './plugin-factory';
|
|
67
|
-
export { PhysicsSet } from './system-set';
|
|
63
|
+
export { PHYSICS_ERROR_HINTS, PhysicsError } from './errors.js';
|
|
64
|
+
export type { PhysicsWorld, PhysicsWorld2D, RaycastHit, RaycastHit2D } from './physics-world.js';
|
|
65
|
+
export type { PhysicsBackend } from './plugin-factory.js';
|
|
66
|
+
export { physicsPlugin } from './plugin-factory.js';
|
|
67
|
+
export { PhysicsSet } from './system-set.js';
|
package/src/physics-world.ts
CHANGED
|
@@ -17,7 +17,8 @@ import type {
|
|
|
17
17
|
DerivedShapeState,
|
|
18
18
|
PhysicsConstraintInput,
|
|
19
19
|
PhysicsContactObservation,
|
|
20
|
-
|
|
20
|
+
PhysicsVector,
|
|
21
|
+
} from './derived-physics.js';
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Raycast hit result — returned by `PhysicsWorld.raycast()`.
|
|
@@ -146,6 +147,16 @@ export interface PhysicsWorld {
|
|
|
146
147
|
candidate: DerivedPhysicsCandidate,
|
|
147
148
|
commitGeometry?: () => Result<void, Error>,
|
|
148
149
|
) => Result<DerivedPhysicsCandidate, DerivedPhysicsError>;
|
|
150
|
+
/**
|
|
151
|
+
* Queue one bounded replacement across distinct bodies. Native preparation
|
|
152
|
+
* completes for every member before the single geometry callback; any member
|
|
153
|
+
* failure rolls the group back. A thrown callback or failed rollback requires
|
|
154
|
+
* rebuilding the PhysicsWorld. Preparation/candidate budgets remain shared.
|
|
155
|
+
*/
|
|
156
|
+
admitDerivedShapeCandidates?: (
|
|
157
|
+
candidates: readonly DerivedPhysicsCandidate[],
|
|
158
|
+
commitGeometry?: () => Result<void, Error>,
|
|
159
|
+
) => Result<readonly DerivedPhysicsCandidate[], DerivedPhysicsError>;
|
|
149
160
|
/** Borrowed ordering proof, present only inside the paired geometry commit. */
|
|
150
161
|
getDerivedAdmission?: (
|
|
151
162
|
entity?: number,
|
|
@@ -170,6 +181,20 @@ export interface PhysicsWorld {
|
|
|
170
181
|
getDerivedBodyMass?: (entity: number) => number | undefined;
|
|
171
182
|
/** Read the committed world-space COM and velocities for one derived body. */
|
|
172
183
|
getDerivedMotion?: (entity: number) => DerivedPhysicsMotion | undefined;
|
|
184
|
+
/**
|
|
185
|
+
* Apply a world-space impulse at a world-space point on the exact committed
|
|
186
|
+
* dynamic body revision. Call after syncBackend and before stepSimulation.
|
|
187
|
+
* Rejects queued admission, stale identity and invalid vectors; never moves
|
|
188
|
+
* the pose directly. A partially failed native write requires World recovery.
|
|
189
|
+
* The caller bounds impulse magnitude, normally maxForce * FixedTime.delta.
|
|
190
|
+
*/
|
|
191
|
+
applyDerivedImpulse?: (input: {
|
|
192
|
+
readonly entity: number;
|
|
193
|
+
readonly sourceKey: string;
|
|
194
|
+
readonly revision: number;
|
|
195
|
+
readonly impulse: PhysicsVector;
|
|
196
|
+
readonly point: PhysicsVector;
|
|
197
|
+
}) => Result<void, DerivedPhysicsError>;
|
|
173
198
|
/** Read the currently committed local shape identities for one body. */
|
|
174
199
|
getDerivedShapes?: (entity: number) => readonly DerivedShapeState[];
|
|
175
200
|
/** Read detached contact observations from the latest fixed-step drain. */
|
package/src/plugin-factory.ts
CHANGED
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
// transform / audio -- one mental model covers every wiring.
|
|
15
15
|
|
|
16
16
|
import type { Plugin } from '@forgeax/engine-plugin';
|
|
17
|
-
import { registerPhysicsComponents } from './components';
|
|
18
|
-
import { PhysicsError } from './errors';
|
|
17
|
+
import { registerPhysicsComponents } from './components.js';
|
|
18
|
+
import { PhysicsError } from './errors.js';
|
|
19
19
|
import { loadRapier2DBackend, loadRapier3DBackend } from './load-rapier-backend.mjs';
|
|
20
|
-
import type { PhysicsWorld, PhysicsWorld2D } from './physics-world';
|
|
20
|
+
import type { PhysicsWorld, PhysicsWorld2D } from './physics-world.js';
|
|
21
21
|
|
|
22
22
|
interface Rapier3DBackendModule {
|
|
23
23
|
loadRapier3D(): Promise<unknown>;
|