@vworlds/vecs-physics 1.0.26 → 1.0.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/adapter/{state.d.ts → engine.d.ts} +12 -5
  2. package/adapter/{state.js → engine.js} +19 -21
  3. package/adapter/engine.js.map +1 -0
  4. package/adapter/queries.d.ts +68 -0
  5. package/adapter/queries.js +145 -0
  6. package/adapter/queries.js.map +1 -0
  7. package/adapter/runtime.d.ts +4 -0
  8. package/adapter/runtime.js +20 -0
  9. package/adapter/runtime.js.map +1 -1
  10. package/components/body.js +1 -1
  11. package/components/body.js.map +1 -1
  12. package/components/geometry.d.ts +15 -8
  13. package/components/geometry.js +26 -14
  14. package/components/geometry.js.map +1 -1
  15. package/components/material.d.ts +5 -0
  16. package/components/material.js +5 -0
  17. package/components/material.js.map +1 -1
  18. package/index.d.ts +3 -1
  19. package/index.js +4 -2
  20. package/index.js.map +1 -1
  21. package/module.js +25 -22
  22. package/module.js.map +1 -1
  23. package/package.json +2 -2
  24. package/systems/chain_lifecycle.d.ts +6 -0
  25. package/systems/chain_lifecycle.js +102 -0
  26. package/systems/chain_lifecycle.js.map +1 -0
  27. package/systems/debug.d.ts +2 -2
  28. package/systems/debug.js +17 -17
  29. package/systems/debug.js.map +1 -1
  30. package/systems/event_opt_in_sync.d.ts +2 -2
  31. package/systems/event_opt_in_sync.js +53 -28
  32. package/systems/event_opt_in_sync.js.map +1 -1
  33. package/systems/events.d.ts +2 -2
  34. package/systems/events.js +34 -34
  35. package/systems/events.js.map +1 -1
  36. package/systems/forces.d.ts +2 -2
  37. package/systems/forces.js +9 -9
  38. package/systems/forces.js.map +1 -1
  39. package/systems/impulse_accumulate.d.ts +3 -3
  40. package/systems/impulse_accumulate.js +28 -26
  41. package/systems/impulse_accumulate.js.map +1 -1
  42. package/systems/impulse_zero.d.ts +2 -2
  43. package/systems/impulse_zero.js +4 -4
  44. package/systems/impulse_zero.js.map +1 -1
  45. package/systems/index.d.ts +3 -3
  46. package/systems/index.js +31 -28
  47. package/systems/index.js.map +1 -1
  48. package/systems/kinematic.d.ts +2 -2
  49. package/systems/kinematic.js +26 -25
  50. package/systems/kinematic.js.map +1 -1
  51. package/systems/lifecycle.d.ts +2 -2
  52. package/systems/lifecycle.js +21 -21
  53. package/systems/lifecycle.js.map +1 -1
  54. package/systems/mass_recompute.d.ts +2 -2
  55. package/systems/mass_recompute.js +12 -12
  56. package/systems/mass_recompute.js.map +1 -1
  57. package/systems/material_filter_sync.d.ts +2 -2
  58. package/systems/material_filter_sync.js +48 -34
  59. package/systems/material_filter_sync.js.map +1 -1
  60. package/systems/pose_sync_in.d.ts +2 -2
  61. package/systems/pose_sync_in.js +14 -11
  62. package/systems/pose_sync_in.js.map +1 -1
  63. package/systems/pose_sync_out.d.ts +2 -2
  64. package/systems/pose_sync_out.js +6 -6
  65. package/systems/pose_sync_out.js.map +1 -1
  66. package/systems/shape_lifecycle.d.ts +29 -4
  67. package/systems/shape_lifecycle.js +46 -86
  68. package/systems/shape_lifecycle.js.map +1 -1
  69. package/systems/shape_pose_sync.d.ts +2 -2
  70. package/systems/shape_pose_sync.js +28 -13
  71. package/systems/shape_pose_sync.js.map +1 -1
  72. package/systems/shape_predicates.d.ts +8 -3
  73. package/systems/shape_predicates.js +3 -2
  74. package/systems/shape_predicates.js.map +1 -1
  75. package/systems/step.d.ts +2 -2
  76. package/systems/step.js +5 -5
  77. package/systems/step.js.map +1 -1
  78. package/util/resolve_body.d.ts +1 -1
  79. package/util/resolve_body.js +1 -3
  80. package/util/resolve_body.js.map +1 -1
  81. package/adapter/state.js.map +0 -1
@@ -1,5 +1,6 @@
1
1
  import { ArrayMap, type EID, type World } from "@vworlds/vecs";
2
2
  import { type WarnSink, WarnDedupe } from "../util/warn.js";
3
+ import { type PhysicsQueries } from "./queries.js";
3
4
  import { type Box2DModule } from "./runtime.js";
4
5
  export type EntityId = EID;
5
6
  export type b2WorldId = ReturnType<Box2DModule["b2CreateWorld"]>;
@@ -7,6 +8,11 @@ export type b2BodyId = ReturnType<Box2DModule["b2CreateBody"]>;
7
8
  export type b2ShapeId = ReturnType<Box2DModule["b2CreateCircleShape"]>;
8
9
  export type b2ChainId = ReturnType<Box2DModule["b2CreateChain"]>;
9
10
  export type b2Vec2 = ReturnType<Box2DModule["b2Body_GetPosition"]>;
11
+ export type b2QueryFilter = Parameters<Box2DModule["b2World_OverlapAABB"]>[2];
12
+ export type b2AABB = Parameters<Box2DModule["b2World_OverlapAABB"]>[1];
13
+ /** The transient result object passed to a `b2World_CastRay` collector callback
14
+ * (the binding types the callback parameter as `any`). */
15
+ export type b2RayCallbackResult = InstanceType<Box2DModule["b2RayCallbackResult"]>;
10
16
  /** Fully-resolved engine configuration: every `PhysicsOptions` field with its
11
17
  * default applied. Built by `PhysicsModule`; the source of truth for tunables
12
18
  * the engine reads at runtime. */
@@ -33,10 +39,10 @@ export interface ResolvedPhysicsOptions {
33
39
  export declare class PhysicsSystemTag {
34
40
  }
35
41
  export declare function registerInternalComponents(world: World): void;
36
- export declare function attachPhysics(world: World, state: PhysicsState): void;
37
- export declare function getPhysics(world: World): PhysicsState;
38
- export declare function hasPhysics(world: World): boolean;
39
- export declare class PhysicsState {
42
+ export declare function attachPhysicsEngine(world: World, engine: PhysicsEngine): void;
43
+ export declare function getPhysicsEngine(world: World): PhysicsEngine;
44
+ export declare function hasPhysicsEngine(world: World): boolean;
45
+ export declare class PhysicsEngine {
40
46
  worldId: b2WorldId;
41
47
  readonly box2d: Box2DModule;
42
48
  readonly gravityX: number;
@@ -69,6 +75,7 @@ export declare class PhysicsState {
69
75
  value: number;
70
76
  wake: boolean;
71
77
  }>;
72
- readonly scratchVec2: b2Vec2;
78
+ queries?: PhysicsQueries;
79
+ constructor();
73
80
  constructor(box2d: Box2DModule, options: ResolvedPhysicsOptions, warnSink?: WarnSink);
74
81
  }
@@ -8,30 +8,29 @@ import { WarnDedupe } from "../util/warn.js";
8
8
  export class PhysicsSystemTag {
9
9
  }
10
10
  export function registerInternalComponents(world) {
11
- world.component(PhysicsRoot);
11
+ world.component(PhysicsEngine);
12
12
  world.component(PhysicsSystemTag);
13
13
  }
14
- export function attachPhysics(world, state) {
15
- world.component(PhysicsRoot).add(Singleton);
16
- world.set(PhysicsRoot, { state });
14
+ export function attachPhysicsEngine(world, engine) {
15
+ world.component(PhysicsEngine).add(Singleton);
16
+ world.component(PhysicsEngine).attach(PhysicsEngine, engine);
17
17
  }
18
- export function getPhysics(world) {
19
- const root = world.get(PhysicsRoot);
20
- if (!root) {
21
- throw new Error("world.module(PhysicsModule) must be called before reading physics state");
18
+ export function getPhysicsEngine(world) {
19
+ const engine = world.get(PhysicsEngine);
20
+ if (!engine) {
21
+ throw new Error("world.module(PhysicsModule) must be called before reading physics engine");
22
22
  }
23
- return root.state;
23
+ return engine;
24
24
  }
25
- export function hasPhysics(world) {
26
- if (!world._classRegistry.has(PhysicsRoot)) {
25
+ export function hasPhysicsEngine(world) {
26
+ if (!world._classRegistry.has(PhysicsEngine)) {
27
27
  return false;
28
28
  }
29
- const root = world.get(PhysicsRoot);
30
- return root?.state !== undefined;
29
+ return world.get(PhysicsEngine) !== undefined;
31
30
  }
32
- export class PhysicsState {
31
+ export class PhysicsEngine {
33
32
  constructor(box2d, options, warnSink) {
34
- // Forward handles live on components: Body._bodyId and Shape._shapeId.
33
+ // Forward handles live on components: Body._bodyId, SingleShape._shapeId, and Chain._chainId.
35
34
  // Index-keyed reverse ArrayMaps resolve Box2D event IDs back to entities.
36
35
  // Emscripten returns fresh wrapper objects for b2*Id fields on events, so
37
36
  // Map<b2*Id, EntityId> misses by object identity. Public index1 slot 0 is
@@ -43,7 +42,7 @@ export class PhysicsState {
43
42
  // Bodies whose mass needs recomputing this step (populated by shape lifecycle).
44
43
  this.dirtyMassBodies = new Set();
45
44
  // Per-step event tracking sets for PhysicsEvents (M7-8 should-fix: moved from
46
- // closure-local to state so they survive future pause/resume cycles).
45
+ // closure-local to engine so they survive future pause/resume cycles).
47
46
  // Populated by PhysicsEvents at the end of each step; persist into the next
48
47
  // step to detect which entities stopped receiving events.
49
48
  this.prevTouchedContact = new Set();
@@ -59,6 +58,9 @@ export class PhysicsState {
59
58
  // looking up event wrappers.
60
59
  this.pendingLinearImpulse = new Map();
61
60
  this.pendingAngularImpulse = new Map();
61
+ if (box2d === undefined || options === undefined) {
62
+ return;
63
+ }
62
64
  this.box2d = box2d;
63
65
  this.gravityX = options.gravityX;
64
66
  this.gravityY = options.gravityY;
@@ -74,10 +76,6 @@ export class PhysicsState {
74
76
  this.maximumLinearSpeed = options.maximumLinearSpeed;
75
77
  this.enableSleep = options.enableSleep;
76
78
  this.enableContinuous = options.enableContinuous;
77
- this.scratchVec2 = new box2d.b2Vec2();
78
79
  }
79
80
  }
80
- // Internal singleton state holder. Never exported from the package public API.
81
- class PhysicsRoot {
82
- }
83
- //# sourceMappingURL=state.js.map
81
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../../src/adapter/engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { type Entity, type World } from "@vworlds/vecs";
2
+ import { type Vec2 } from "../components/geometry.js";
3
+ /** Category/mask filter applied to a query. Unlike a shape's own filter
4
+ * (default `categoryBits = 1`), a query's default `categoryBits` is
5
+ * `0xffffffff` so the query is not itself filtered out. */
6
+ export interface QueryFilter {
7
+ /** Bits this query "is". Default `0xffffffff` (matches every category). */
8
+ categoryBits?: number;
9
+ /** Bits this query "sees". Default `0xffffffff` (sees every category). */
10
+ maskBits?: number;
11
+ }
12
+ /** A single ray-cast hit, resolved to a Vecs shape entity with plain-data
13
+ * geometry — never a Box2D handle. */
14
+ export interface RayHit {
15
+ /** The shape entity that was hit. */
16
+ entity: Entity;
17
+ /** World-space hit point. */
18
+ point: Vec2;
19
+ /** World-space unit surface normal at the hit point. */
20
+ normal: Vec2;
21
+ /** Fraction along `from` → `to`, in `[0, 1]`. */
22
+ fraction: number;
23
+ }
24
+ /**
25
+ * Stable, world-scoped facade for synchronous read-only physics queries: ray
26
+ * casts and spatial overlaps. Obtained via {@link physics}. Never mutates the
27
+ * world, never creates or destroys entities, and never wakes bodies.
28
+ */
29
+ export interface PhysicsQueries {
30
+ /** Casts a ray from `from` to `to` and returns the closest hit, or `undefined`
31
+ * if the ray hits nothing (or only hits shapes whose entity has since been
32
+ * destroyed / removed). */
33
+ rayCastClosest(query: {
34
+ from: Vec2;
35
+ to: Vec2;
36
+ filter?: QueryFilter;
37
+ }): RayHit | undefined;
38
+ /** Casts a ray from `from` to `to` and returns every hit along the way. */
39
+ rayCastAll(query: {
40
+ from: Vec2;
41
+ to: Vec2;
42
+ filter?: QueryFilter;
43
+ }): RayHit[];
44
+ /** Returns every shape entity whose fat AABB overlaps `[min, max]`. This is
45
+ * a broad-phase query: it can over-report relative to exact shape
46
+ * overlap. */
47
+ overlapAABB(query: {
48
+ min: Vec2;
49
+ max: Vec2;
50
+ filter?: QueryFilter;
51
+ }): Entity[];
52
+ /** Returns every shape entity that precisely overlaps a circle centered at
53
+ * `center` with the given `radius`. */
54
+ overlapCircle(query: {
55
+ center: Vec2;
56
+ radius: number;
57
+ filter?: QueryFilter;
58
+ }): Entity[];
59
+ }
60
+ /**
61
+ * Returns the {@link PhysicsQueries} facade for `world`.
62
+ *
63
+ * Throws if `world.module(PhysicsModule)` has not been called (the error
64
+ * message comes from `getPhysicsEngine`). The returned facade is stable: repeated
65
+ * calls for the same world return the same instance, so it never
66
+ * re-allocates.
67
+ */
68
+ export declare function physics(world: World): PhysicsQueries;
@@ -0,0 +1,145 @@
1
+ // M8-3 — Query foundation: `physics(world)` accessor + `PhysicsQueries` facade.
2
+ //
3
+ // The ONE narrow imperative entry point vecs-physics exposes: world-scoped,
4
+ // read-only queries against the live Box2D world. Results are always Vecs
5
+ // entities (shape entities) and plain data — never Box2D handles.
6
+ //
7
+ // box2d3-wasm imports are confined to `src/adapter/`; this file is part of
8
+ // that boundary. Scratch allocations (b2Vec2, b2QueryFilter, b2AABB) reuse
9
+ // global pools allocated at module load. Transient allocations like b2RayResult
10
+ // are freed via explicit `finally { .delete() }`.
11
+ import { scr_b2AABB, scr_b2QueryFilter, scr_b2Vec2 } from "./runtime.js";
12
+ import { getPhysicsEngine, } from "./engine.js";
13
+ /**
14
+ * Returns the {@link PhysicsQueries} facade for `world`.
15
+ *
16
+ * Throws if `world.module(PhysicsModule)` has not been called (the error
17
+ * message comes from `getPhysicsEngine`). The returned facade is stable: repeated
18
+ * calls for the same world return the same instance, so it never
19
+ * re-allocates.
20
+ */
21
+ export function physics(world) {
22
+ const engine = getPhysicsEngine(world);
23
+ return (engine.queries ?? (engine.queries = new PhysicsQueriesImpl(world, engine)));
24
+ }
25
+ class PhysicsQueriesImpl {
26
+ constructor(world, engine) {
27
+ this.world = world;
28
+ this.engine = engine;
29
+ }
30
+ rayCastClosest(query) {
31
+ const { box2d, worldId } = this.engine;
32
+ const origin = scr_b2Vec2[0];
33
+ origin.Set(query.from.x, query.from.y);
34
+ const translation = scr_b2Vec2[1];
35
+ translation.Set(query.to.x - query.from.x, query.to.y - query.from.y);
36
+ const result = box2d.b2World_CastRayClosest(worldId, origin, translation, to_b2QueryFilter(query.filter));
37
+ try {
38
+ if (!result.hit) {
39
+ return undefined;
40
+ }
41
+ const entity = resolveShapeEntity(this.engine, this.world, result.shapeId);
42
+ if (entity === undefined) {
43
+ return undefined;
44
+ }
45
+ return {
46
+ entity,
47
+ point: { x: result.point.x, y: result.point.y },
48
+ normal: { x: result.normal.x, y: result.normal.y },
49
+ fraction: result.fraction,
50
+ };
51
+ }
52
+ finally {
53
+ result.delete();
54
+ }
55
+ }
56
+ rayCastAll(query) {
57
+ const { box2d, worldId } = this.engine;
58
+ const origin = scr_b2Vec2[0];
59
+ origin.Set(query.from.x, query.from.y);
60
+ const translation = scr_b2Vec2[1];
61
+ translation.Set(query.to.x - query.from.x, query.to.y - query.from.y);
62
+ const hits = [];
63
+ box2d.b2World_CastRay(worldId, origin, translation, to_b2QueryFilter(query.filter), (result) => {
64
+ const entity = resolveShapeEntity(this.engine, this.world, result.shapeId);
65
+ if (entity !== undefined) {
66
+ hits.push({
67
+ entity,
68
+ point: { x: result.point.x, y: result.point.y },
69
+ normal: { x: result.normal.x, y: result.normal.y },
70
+ fraction: result.fraction,
71
+ });
72
+ }
73
+ return 1;
74
+ });
75
+ return hits;
76
+ }
77
+ overlapAABB(query) {
78
+ const { box2d, worldId } = this.engine;
79
+ const aabb = scr_b2AABB;
80
+ aabb.lowerBound.Set(query.min.x, query.min.y);
81
+ aabb.upperBound.Set(query.max.x, query.max.y);
82
+ const entities = [];
83
+ const seen = new Set();
84
+ box2d.b2World_OverlapAABB(worldId, aabb, to_b2QueryFilter(query.filter), (result) => {
85
+ const entity = resolveShapeEntity(this.engine, this.world, result.shapeId);
86
+ if (entity !== undefined && !seen.has(entity.eid)) {
87
+ seen.add(entity.eid);
88
+ entities.push(entity);
89
+ }
90
+ return true;
91
+ });
92
+ return entities;
93
+ }
94
+ overlapCircle(query) {
95
+ const { box2d, worldId } = this.engine;
96
+ const centerVec = scr_b2Vec2[0];
97
+ centerVec.Set(query.center.x, query.center.y);
98
+ const proxy = box2d.b2MakeProxy(centerVec, 1, query.radius);
99
+ try {
100
+ const entities = [];
101
+ const seen = new Set();
102
+ box2d.b2World_OverlapShape(worldId, proxy, to_b2QueryFilter(query.filter), (result) => {
103
+ const entity = resolveShapeEntity(this.engine, this.world, result.shapeId);
104
+ if (entity !== undefined && !seen.has(entity.eid)) {
105
+ seen.add(entity.eid);
106
+ entities.push(entity);
107
+ }
108
+ return true;
109
+ });
110
+ return entities;
111
+ }
112
+ finally {
113
+ proxy.delete();
114
+ }
115
+ }
116
+ }
117
+ /** Maps a {@link QueryFilter} (default `0xffffffff`/`0xffffffff` — "sees and
118
+ * is seen by everything") and returns a scratch `b2QueryFilter`. `b2QueryFilter` is not
119
+ * `b2DefaultQueryFilter` here: the default-constructed filter is all zeros,
120
+ * which would match nothing.
121
+ * to_b2QueryFilter cannot be called again until the returned b2QueryFilter is no longer in use
122
+ * */
123
+ function to_b2QueryFilter(filter) {
124
+ const target = scr_b2QueryFilter[0];
125
+ target.categoryBits = filter?.categoryBits ?? 0xffffffff;
126
+ target.maskBits = filter?.maskBits ?? 0xffffffff;
127
+ return target;
128
+ }
129
+ /** Resolves a Box2D shape hit back to its Vecs shape entity, mirroring the
130
+ * `PhysicsEvents` shape→entity resolution (`src/systems/events.ts`):
131
+ * `entityByShapeIndex.get(shapeId.index1)` → `EID` → live `Entity`. Returns
132
+ * `undefined` (drop silently) if the slot is empty or the entity has been
133
+ * destroyed — the same rule as `PhysicsEvents`. */
134
+ function resolveShapeEntity(engine, world, shapeId) {
135
+ const eid = engine.entityByShapeIndex.get(shapeId.index1);
136
+ if (eid === undefined) {
137
+ return undefined;
138
+ }
139
+ const entity = world.getEntity(eid);
140
+ if (entity === undefined || entity.destroyed) {
141
+ return undefined;
142
+ }
143
+ return entity;
144
+ }
145
+ //# sourceMappingURL=queries.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.js","sourceRoot":"","sources":["../../../../src/adapter/queries.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,8 @@
1
1
  import Box2DFactory from "box2d3-wasm";
2
+ import type { b2AABB, b2QueryFilter, b2Vec2 } from "./engine.js";
2
3
  export type Box2DModule = Awaited<ReturnType<typeof Box2DFactory>>;
4
+ export declare const scr_b2Vec2: b2Vec2[];
5
+ export declare const scr_b2QueryFilter: b2QueryFilter[];
6
+ export declare let scr_b2AABB: b2AABB | null;
3
7
  export declare function preloadPhysics(): Promise<void>;
4
8
  export declare function getBox2D(): Box2DModule;
@@ -2,6 +2,11 @@ import { cpus } from "node:os";
2
2
  import Box2DFactory from "box2d3-wasm";
3
3
  let modulePromise = null;
4
4
  let module = null;
5
+ // Global scratch pools for common Box2D structs. Allocated once at module load,
6
+ // reused across queries and other non-reentrant operations.
7
+ export const scr_b2Vec2 = [];
8
+ export const scr_b2QueryFilter = [];
9
+ export let scr_b2AABB = null;
5
10
  export async function preloadPhysics() {
6
11
  var _a;
7
12
  if (modulePromise) {
@@ -14,10 +19,25 @@ export async function preloadPhysics() {
14
19
  (_a = global.navigator).hardwareConcurrency ?? (_a.hardwareConcurrency = cpus().length);
15
20
  modulePromise = Box2DFactory().then((loadedModule) => {
16
21
  module = loadedModule;
22
+ initializeScratchPools(loadedModule);
17
23
  return loadedModule;
18
24
  });
19
25
  await modulePromise;
20
26
  }
27
+ function initializeScratchPools(box2d) {
28
+ // b2Vec2: ray casts need 2 simultaneous (origin + translation), polygon/chain creation
29
+ // can reuse serially. Allocate 3 for safety margin.
30
+ for (let i = 0; i < 3; i++) {
31
+ scr_b2Vec2.push(new box2d.b2Vec2());
32
+ }
33
+ // b2QueryFilter: queries and material_filter_sync each need at most 1 simultaneously.
34
+ // Allocate 2 for safety.
35
+ for (let i = 0; i < 2; i++) {
36
+ scr_b2QueryFilter.push(new box2d.b2QueryFilter());
37
+ }
38
+ // b2AABB: overlapAABB needs exactly 1.
39
+ scr_b2AABB = new box2d.b2AABB();
40
+ }
21
41
  export function getBox2D() {
22
42
  if (!module) {
23
43
  throw new Error("Box2D module not loaded. Call `await preloadPhysics()` before `world.module(PhysicsModule)`.");
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../../src/adapter/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,OAAO,YAAY,MAAM,aAAa,CAAC;AAIvC,IAAI,aAAa,GAAgC,IAAI,CAAC;AACtD,IAAI,MAAM,GAAuB,IAAI,CAAC;AAEtC,MAAM,CAAC,KAAK,UAAU,cAAc;;IAClC,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,aAAa,CAAC;QACpB,OAAO;IACT,CAAC;IAED,8EAA8E;IAC9E,MAAM,MAAM,GAAG,UAA2D,CAAC;IAC3E,MAAM,CAAC,SAAS,KAAhB,MAAM,CAAC,SAAS,GAAK,EAAE,EAAC;IACxB,MAAC,MAAM,CAAC,SAA8C,EAAC,mBAAmB,QAAnB,mBAAmB,GAAK,IAAI,EAAE,CAAC,MAAM,EAAC;IAE7F,aAAa,GAAG,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE;QACnD,MAAM,GAAG,YAAY,CAAC;QACtB,OAAO,YAAY,CAAC;IACtB,CAAC,CAAC,CAAC;IACH,MAAM,aAAa,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,8FAA8F,CAC/F,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../../src/adapter/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,OAAO,YAAY,MAAM,aAAa,CAAC;AAMvC,IAAI,aAAa,GAAgC,IAAI,CAAC;AACtD,IAAI,MAAM,GAAuB,IAAI,CAAC;AAEtC,gFAAgF;AAChF,4DAA4D;AAC5D,MAAM,CAAC,MAAM,UAAU,GAAa,EAAE,CAAC;AACvC,MAAM,CAAC,MAAM,iBAAiB,GAAoB,EAAE,CAAC;AACrD,MAAM,CAAC,IAAI,UAAU,GAAkB,IAAI,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,cAAc;;IAClC,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,aAAa,CAAC;QACpB,OAAO;IACT,CAAC;IAED,8EAA8E;IAC9E,MAAM,MAAM,GAAG,UAA2D,CAAC;IAC3E,MAAM,CAAC,SAAS,KAAhB,MAAM,CAAC,SAAS,GAAK,EAAE,EAAC;IACxB,MAAC,MAAM,CAAC,SAA8C,EAAC,mBAAmB,QAAnB,mBAAmB,GAAK,IAAI,EAAE,CAAC,MAAM,EAAC;IAE7F,aAAa,GAAG,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,EAAE;QACnD,MAAM,GAAG,YAAY,CAAC;QACtB,sBAAsB,CAAC,YAAY,CAAC,CAAC;QACrC,OAAO,YAAY,CAAC;IACtB,CAAC,CAAC,CAAC;IACH,MAAM,aAAa,CAAC;AACtB,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAkB;IAChD,uFAAuF;IACvF,oDAAoD;IACpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,UAAU,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,sFAAsF;IACtF,yBAAyB;IACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,iBAAiB,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,uCAAuC;IACvC,UAAU,GAAG,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,8FAA8F,CAC/F,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1,5 +1,5 @@
1
1
  // Body-level components: the entity-marking `Body` plus the canonical pose and
2
- // velocity state. Defaults match Box2D's `b2DefaultBodyDef()` (see
2
+ // velocity data. Defaults match Box2D's `b2DefaultBodyDef()` (see
3
3
  // `box2d/src/types.c`). Public API — see `docs/components.md`.
4
4
  //
5
5
  // These are plain data classes: every field is initialised on the class body so
@@ -1 +1 @@
1
- {"version":3,"file":"body.js","sourceRoot":"","sources":["../../../../src/components/body.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,+DAA+D;AAC/D,EAAE;AACF,gFAAgF;AAChF,uEAAuE;AACvE,2EAA2E;AAC3E,2CAA2C;AAI3C,8CAA8C;AAC9C,MAAM,CAAN,IAAY,QAOX;AAPD,WAAY,QAAQ;IAClB,gCAAgC;IAChC,6BAAiB,CAAA;IACjB,2EAA2E;IAC3E,mCAAuB,CAAA;IACvB,2DAA2D;IAC3D,+BAAmB,CAAA;AACrB,CAAC,EAPW,QAAQ,KAAR,QAAQ,QAOnB;AAED,kFAAkF;AAClF,MAAM,OAAO,IAAI;IAAjB;QACE,SAAI,GAAG,QAAQ,CAAC,MAAM,CAAC;QACvB,WAAM,GAAG,KAAK,CAAC;QACf,YAAO,GAAG,IAAI,CAAC;QACf,sBAAiB,GAAG,KAAK,CAAC;QAC1B,8FAA8F;QAC9F,YAAO,GAAyB,SAAS,CAAC;IAC5C,CAAC;CAAA;AAED,gFAAgF;AAChF,MAAM,OAAO,QAAQ;IAArB;QACE,MAAC,GAAG,CAAC,CAAC;QACN,MAAC,GAAG,CAAC,CAAC;IACR,CAAC;CAAA;AAED,8EAA8E;AAC9E,MAAM,OAAO,QAAQ;IAArB;QACE,UAAK,GAAG,CAAC,CAAC;IACZ,CAAC;CAAA;AAED,gFAAgF;AAChF,MAAM,OAAO,cAAc;IAA3B;QACE,MAAC,GAAG,CAAC,CAAC;QACN,MAAC,GAAG,CAAC,CAAC;IACR,CAAC;CAAA;AAED,mDAAmD;AACnD,MAAM,OAAO,eAAe;IAA5B;QACE,UAAK,GAAG,CAAC,CAAC;IACZ,CAAC;CAAA"}
1
+ {"version":3,"file":"body.js","sourceRoot":"","sources":["../../../../src/components/body.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,kEAAkE;AAClE,+DAA+D;AAC/D,EAAE;AACF,gFAAgF;AAChF,uEAAuE;AACvE,2EAA2E;AAC3E,2CAA2C;AAI3C,8CAA8C;AAC9C,MAAM,CAAN,IAAY,QAOX;AAPD,WAAY,QAAQ;IAClB,gCAAgC;IAChC,6BAAiB,CAAA;IACjB,2EAA2E;IAC3E,mCAAuB,CAAA;IACvB,2DAA2D;IAC3D,+BAAmB,CAAA;AACrB,CAAC,EAPW,QAAQ,KAAR,QAAQ,QAOnB;AAED,kFAAkF;AAClF,MAAM,OAAO,IAAI;IAAjB;QACE,SAAI,GAAG,QAAQ,CAAC,MAAM,CAAC;QACvB,WAAM,GAAG,KAAK,CAAC;QACf,YAAO,GAAG,IAAI,CAAC;QACf,sBAAiB,GAAG,KAAK,CAAC;QAC1B,8FAA8F;QAC9F,YAAO,GAAyB,SAAS,CAAC;IAC5C,CAAC;CAAA;AAED,gFAAgF;AAChF,MAAM,OAAO,QAAQ;IAArB;QACE,MAAC,GAAG,CAAC,CAAC;QACN,MAAC,GAAG,CAAC,CAAC;IACR,CAAC;CAAA;AAED,8EAA8E;AAC9E,MAAM,OAAO,QAAQ;IAArB;QACE,UAAK,GAAG,CAAC,CAAC;IACZ,CAAC;CAAA;AAED,gFAAgF;AAChF,MAAM,OAAO,cAAc;IAA3B;QACE,MAAC,GAAG,CAAC,CAAC;QACN,MAAC,GAAG,CAAC,CAAC;IACR,CAAC;CAAA;AAED,mDAAmD;AACnD,MAAM,OAAO,eAAe;IAA5B;QACE,UAAK,GAAG,CAAC,CAAC;IACZ,CAAC;CAAA"}
@@ -4,13 +4,20 @@ export type Vec2 = {
4
4
  y: number;
5
5
  };
6
6
  /**
7
- * Abstract base for the six geometry components. Every shape entity carries
7
+ * Empty umbrella marker for the six geometry components. Every shape entity carries
8
8
  * exactly one concrete geometry (`Box`, `Circle`, `Capsule`, `Segment`,
9
- * `Polygon`, or `Chain`); each declares `Implements: [Shape]` so queries and
10
- * systems can match `Shape` without enumerating every concrete type.
9
+ * `Polygon`, or `Chain`); each implements `Shape` so queries and systems can
10
+ * match any geometry without enumerating every concrete type.
11
11
  */
12
12
  export declare abstract class Shape {
13
13
  }
14
+ /**
15
+ * Internal marker for geometries backed by one Box2D `b2ShapeId`. Chains are
16
+ * intentionally excluded because Box2D creates them through `b2ChainId` and
17
+ * exposes their collision segments separately.
18
+ */
19
+ export declare abstract class SingleShape extends Shape {
20
+ }
14
21
  /**
15
22
  * Axis-aligned box in local shape space, stored as half extents (`hx`/`hy`) to
16
23
  * match Box2D's internal representation. The `width`/`height` accessors are
@@ -20,7 +27,7 @@ export declare abstract class Shape {
20
27
  * still go through `entity.set(Box, …)` or `entity.modified(Box)` for physics
21
28
  * to notice. See PLAN → Box accessors.
22
29
  */
23
- export declare class Box extends Shape {
30
+ export declare class Box extends SingleShape {
24
31
  hx: number;
25
32
  hy: number;
26
33
  get width(): number;
@@ -29,11 +36,11 @@ export declare class Box extends Shape {
29
36
  set height(value: number);
30
37
  }
31
38
  /** Circle geometry. */
32
- export declare class Circle extends Shape {
39
+ export declare class Circle extends SingleShape {
33
40
  radius: number;
34
41
  }
35
42
  /** Capsule geometry: two local endpoints joined by a radius. */
36
- export declare class Capsule extends Shape {
43
+ export declare class Capsule extends SingleShape {
37
44
  x1: number;
38
45
  y1: number;
39
46
  x2: number;
@@ -41,7 +48,7 @@ export declare class Capsule extends Shape {
41
48
  radius: number;
42
49
  }
43
50
  /** Line-segment geometry. */
44
- export declare class Segment extends Shape {
51
+ export declare class Segment extends SingleShape {
45
52
  x1: number;
46
53
  y1: number;
47
54
  x2: number;
@@ -52,7 +59,7 @@ export declare class Segment extends Shape {
52
59
  * Convexity and vertex count are validated on shape creation, not on every
53
60
  * update. See PLAN → Vec2 in Polygon / Chain.
54
61
  */
55
- export declare class Polygon extends Shape {
62
+ export declare class Polygon extends SingleShape {
56
63
  vertices: Vec2[];
57
64
  radius: number;
58
65
  }
@@ -1,6 +1,8 @@
1
- // Geometry components. Exactly one per shape entity; each declares
2
- // `Implements: [Shape]` so `PhysicsModule` enforces mutual exclusivity (setting
3
- // one evicts any previous geometry). Defaults match the documented shapes.
1
+ // Geometry components. Exactly one per shape entity; every concrete geometry
2
+ // implements the `Shape` umbrella so `PhysicsModule` enforces mutual exclusivity
3
+ // (setting one evicts any previous geometry). Single Box2D shapes also implement
4
+ // the internal `SingleShape` tier; `Chain` is separate because Box2D exposes it
5
+ // through `b2ChainId` plus underlying segment shapes.
4
6
  // Public API — see `docs/components.md`.
5
7
  //
6
8
  // These are plain data classes: every field is initialised on the class body so
@@ -8,16 +10,22 @@
8
10
  // contract). No imports from systems/ or adapter/ beyond type-only `b2*Id`
9
11
  // handle types — components are pure data.
10
12
  /**
11
- * Abstract base for the six geometry components. Every shape entity carries
13
+ * Empty umbrella marker for the six geometry components. Every shape entity carries
12
14
  * exactly one concrete geometry (`Box`, `Circle`, `Capsule`, `Segment`,
13
- * `Polygon`, or `Chain`); each declares `Implements: [Shape]` so queries and
14
- * systems can match `Shape` without enumerating every concrete type.
15
+ * `Polygon`, or `Chain`); each implements `Shape` so queries and systems can
16
+ * match any geometry without enumerating every concrete type.
15
17
  */
16
18
  export class Shape {
19
+ }
20
+ /**
21
+ * Internal marker for geometries backed by one Box2D `b2ShapeId`. Chains are
22
+ * intentionally excluded because Box2D creates them through `b2ChainId` and
23
+ * exposes their collision segments separately.
24
+ */
25
+ export class SingleShape extends Shape {
17
26
  constructor() {
18
- /** @internal Engine-owned box2d handle: a `b2ShapeId` for real shapes, a
19
- * `b2ChainId` for `Chain`. Set by the shape lifecycle system; undefined
20
- * until then. */
27
+ super(...arguments);
28
+ /** @internal Engine-owned Box2D shape handle. Set by the single-shape lifecycle system. */
21
29
  this._shapeId = undefined;
22
30
  }
23
31
  }
@@ -30,7 +38,7 @@ export class Shape {
30
38
  * still go through `entity.set(Box, …)` or `entity.modified(Box)` for physics
31
39
  * to notice. See PLAN → Box accessors.
32
40
  */
33
- export class Box extends Shape {
41
+ export class Box extends SingleShape {
34
42
  constructor() {
35
43
  super(...arguments);
36
44
  this.hx = 0.5;
@@ -50,14 +58,14 @@ export class Box extends Shape {
50
58
  }
51
59
  }
52
60
  /** Circle geometry. */
53
- export class Circle extends Shape {
61
+ export class Circle extends SingleShape {
54
62
  constructor() {
55
63
  super(...arguments);
56
64
  this.radius = 0.5;
57
65
  }
58
66
  }
59
67
  /** Capsule geometry: two local endpoints joined by a radius. */
60
- export class Capsule extends Shape {
68
+ export class Capsule extends SingleShape {
61
69
  constructor() {
62
70
  super(...arguments);
63
71
  this.x1 = -0.5;
@@ -68,7 +76,7 @@ export class Capsule extends Shape {
68
76
  }
69
77
  }
70
78
  /** Line-segment geometry. */
71
- export class Segment extends Shape {
79
+ export class Segment extends SingleShape {
72
80
  constructor() {
73
81
  super(...arguments);
74
82
  this.x1 = -0.5;
@@ -82,7 +90,7 @@ export class Segment extends Shape {
82
90
  * Convexity and vertex count are validated on shape creation, not on every
83
91
  * update. See PLAN → Vec2 in Polygon / Chain.
84
92
  */
85
- export class Polygon extends Shape {
93
+ export class Polygon extends SingleShape {
86
94
  constructor() {
87
95
  super(...arguments);
88
96
  this.vertices = [];
@@ -93,6 +101,10 @@ export class Polygon extends Shape {
93
101
  export class Chain extends Shape {
94
102
  constructor() {
95
103
  super(...arguments);
104
+ /** @internal Engine-owned Box2D chain handle. Set by the chain lifecycle system. */
105
+ this._chainId = undefined;
106
+ /** @internal Public shape indices of the chain's generated segment shapes. */
107
+ this._segmentIndices = [];
96
108
  this.points = [];
97
109
  this.loop = false;
98
110
  }
@@ -1 +1 @@
1
- {"version":3,"file":"geometry.js","sourceRoot":"","sources":["../../../../src/components/geometry.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,gFAAgF;AAChF,2EAA2E;AAC3E,yCAAyC;AACzC,EAAE;AACF,gFAAgF;AAChF,uEAAuE;AACvE,2EAA2E;AAC3E,2CAA2C;AAO3C;;;;;GAKG;AACH,MAAM,OAAgB,KAAK;IAA3B;QACE;;0BAEkB;QAClB,aAAQ,GAAsC,SAAS,CAAC;IAC1D,CAAC;CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,GAAI,SAAQ,KAAK;IAA9B;;QACE,OAAE,GAAG,GAAG,CAAC;QACT,OAAE,GAAG,GAAG,CAAC;IAiBX,CAAC;IAfC,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IACrB,CAAC;IAED,IAAI,KAAK,CAAC,KAAa;QACrB,IAAI,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;IACtB,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IACrB,CAAC;IAED,IAAI,MAAM,CAAC,KAAa;QACtB,IAAI,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;IACtB,CAAC;CACF;AAED,uBAAuB;AACvB,MAAM,OAAO,MAAO,SAAQ,KAAK;IAAjC;;QACE,WAAM,GAAG,GAAG,CAAC;IACf,CAAC;CAAA;AAED,gEAAgE;AAChE,MAAM,OAAO,OAAQ,SAAQ,KAAK;IAAlC;;QACE,OAAE,GAAG,CAAC,GAAG,CAAC;QACV,OAAE,GAAG,CAAC,CAAC;QACP,OAAE,GAAG,GAAG,CAAC;QACT,OAAE,GAAG,CAAC,CAAC;QACP,WAAM,GAAG,IAAI,CAAC;IAChB,CAAC;CAAA;AAED,6BAA6B;AAC7B,MAAM,OAAO,OAAQ,SAAQ,KAAK;IAAlC;;QACE,OAAE,GAAG,CAAC,GAAG,CAAC;QACV,OAAE,GAAG,CAAC,CAAC;QACP,OAAE,GAAG,GAAG,CAAC;QACT,OAAE,GAAG,CAAC,CAAC;IACT,CAAC;CAAA;AAED;;;;GAIG;AACH,MAAM,OAAO,OAAQ,SAAQ,KAAK;IAAlC;;QACE,aAAQ,GAAW,EAAE,CAAC;QACtB,WAAM,GAAG,CAAC,CAAC;IACb,CAAC;CAAA;AAED,qEAAqE;AACrE,MAAM,OAAO,KAAM,SAAQ,KAAK;IAAhC;;QACE,WAAM,GAAW,EAAE,CAAC;QACpB,SAAI,GAAG,KAAK,CAAC;IACf,CAAC;CAAA"}
1
+ {"version":3,"file":"geometry.js","sourceRoot":"","sources":["../../../../src/components/geometry.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,iFAAiF;AACjF,iFAAiF;AACjF,gFAAgF;AAChF,sDAAsD;AACtD,yCAAyC;AACzC,EAAE;AACF,gFAAgF;AAChF,uEAAuE;AACvE,2EAA2E;AAC3E,2CAA2C;AAO3C;;;;;GAKG;AACH,MAAM,OAAgB,KAAK;CAAG;AAE9B;;;;GAIG;AACH,MAAM,OAAgB,WAAY,SAAQ,KAAK;IAA/C;;QACE,2FAA2F;QAC3F,aAAQ,GAA0B,SAAS,CAAC;IAC9C,CAAC;CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,GAAI,SAAQ,WAAW;IAApC;;QACE,OAAE,GAAG,GAAG,CAAC;QACT,OAAE,GAAG,GAAG,CAAC;IAiBX,CAAC;IAfC,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IACrB,CAAC;IAED,IAAI,KAAK,CAAC,KAAa;QACrB,IAAI,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;IACtB,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;IACrB,CAAC;IAED,IAAI,MAAM,CAAC,KAAa;QACtB,IAAI,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;IACtB,CAAC;CACF;AAED,uBAAuB;AACvB,MAAM,OAAO,MAAO,SAAQ,WAAW;IAAvC;;QACE,WAAM,GAAG,GAAG,CAAC;IACf,CAAC;CAAA;AAED,gEAAgE;AAChE,MAAM,OAAO,OAAQ,SAAQ,WAAW;IAAxC;;QACE,OAAE,GAAG,CAAC,GAAG,CAAC;QACV,OAAE,GAAG,CAAC,CAAC;QACP,OAAE,GAAG,GAAG,CAAC;QACT,OAAE,GAAG,CAAC,CAAC;QACP,WAAM,GAAG,IAAI,CAAC;IAChB,CAAC;CAAA;AAED,6BAA6B;AAC7B,MAAM,OAAO,OAAQ,SAAQ,WAAW;IAAxC;;QACE,OAAE,GAAG,CAAC,GAAG,CAAC;QACV,OAAE,GAAG,CAAC,CAAC;QACP,OAAE,GAAG,GAAG,CAAC;QACT,OAAE,GAAG,CAAC,CAAC;IACT,CAAC;CAAA;AAED;;;;GAIG;AACH,MAAM,OAAO,OAAQ,SAAQ,WAAW;IAAxC;;QACE,aAAQ,GAAW,EAAE,CAAC;QACtB,WAAM,GAAG,CAAC,CAAC;IACb,CAAC;CAAA;AAED,qEAAqE;AACrE,MAAM,OAAO,KAAM,SAAQ,KAAK;IAAhC;;QACE,oFAAoF;QACpF,aAAQ,GAA0B,SAAS,CAAC;QAC5C,8EAA8E;QAC9E,oBAAe,GAAa,EAAE,CAAC;QAC/B,WAAM,GAAW,EAAE,CAAC;QACpB,SAAI,GAAG,KAAK,CAAC;IACf,CAAC;CAAA"}
@@ -16,3 +16,8 @@ export declare class CollisionFilter {
16
16
  /** Marks a shape as an overlap-only sensor (no collision response). */
17
17
  export declare class Sensor {
18
18
  }
19
+ /** Marks a (typically solid) shape as detectable by sensor overlaps. Without it,
20
+ * Box2D v3 will not report this shape to overlapping sensors. It does NOT make
21
+ * the shape a sensor, and the shape does not itself receive sensor events. */
22
+ export declare class Detectable {
23
+ }
@@ -29,4 +29,9 @@ export class CollisionFilter {
29
29
  /** Marks a shape as an overlap-only sensor (no collision response). */
30
30
  export class Sensor {
31
31
  }
32
+ /** Marks a (typically solid) shape as detectable by sensor overlaps. Without it,
33
+ * Box2D v3 will not report this shape to overlapping sensors. It does NOT make
34
+ * the shape a sensor, and the shape does not itself receive sensor events. */
35
+ export class Detectable {
36
+ }
32
37
  //# sourceMappingURL=material.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"material.js","sourceRoot":"","sources":["../../../../src/components/material.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,6EAA6E;AAC7E,oEAAoE;AACpE,EAAE;AACF,4EAA4E;AAC5E,0EAA0E;AAC1E,+EAA+E;AAC/E,2EAA2E;AAC3E,4DAA4D;AAE5D,+EAA+E;AAC/E,MAAM,OAAO,QAAQ;IAArB;QACE,YAAO,GAAG,CAAC,CAAC;QACZ,aAAQ,GAAG,GAAG,CAAC;QACf,gBAAW,GAAG,CAAC,CAAC;QAChB,sBAAiB,GAAG,CAAC,CAAC;QACtB,iBAAY,GAAG,CAAC,CAAC;QACjB,mBAAc,GAAG,CAAC,CAAC;IACrB,CAAC;CAAA;AAED,kFAAkF;AAClF,MAAM,OAAO,eAAe;IAA5B;QACE,iBAAY,GAAG,CAAC,CAAC;QACjB,aAAQ,GAAG,UAAU,CAAC;QACtB,eAAU,GAAG,CAAC,CAAC;IACjB,CAAC;CAAA;AAED,uEAAuE;AACvE,MAAM,OAAO,MAAM;CAAG"}
1
+ {"version":3,"file":"material.js","sourceRoot":"","sources":["../../../../src/components/material.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,6EAA6E;AAC7E,oEAAoE;AACpE,EAAE;AACF,4EAA4E;AAC5E,0EAA0E;AAC1E,+EAA+E;AAC/E,2EAA2E;AAC3E,4DAA4D;AAE5D,+EAA+E;AAC/E,MAAM,OAAO,QAAQ;IAArB;QACE,YAAO,GAAG,CAAC,CAAC;QACZ,aAAQ,GAAG,GAAG,CAAC;QACf,gBAAW,GAAG,CAAC,CAAC;QAChB,sBAAiB,GAAG,CAAC,CAAC;QACtB,iBAAY,GAAG,CAAC,CAAC;QACjB,mBAAc,GAAG,CAAC,CAAC;IACrB,CAAC;CAAA;AAED,kFAAkF;AAClF,MAAM,OAAO,eAAe;IAA5B;QACE,iBAAY,GAAG,CAAC,CAAC;QACjB,aAAQ,GAAG,UAAU,CAAC;QACtB,eAAU,GAAG,CAAC,CAAC;IACjB,CAAC;CAAA;AAED,uEAAuE;AACvE,MAAM,OAAO,MAAM;CAAG;AAEtB;;8EAE8E;AAC9E,MAAM,OAAO,UAAU;CAAG"}
package/index.d.ts CHANGED
@@ -4,7 +4,9 @@ export { Body, BodyType, Position, Rotation, LinearVelocity, AngularVelocity, }
4
4
  export { Damping, GravityScale, MotionLocks, Sleep } from "./components/body_tuning.js";
5
5
  export { ShapePosition, ShapeRotation } from "./components/shape_pose.js";
6
6
  export { Shape, Box, Circle, Capsule, Segment, Polygon, Chain, type Vec2, } from "./components/geometry.js";
7
- export { Material, CollisionFilter, Sensor } from "./components/material.js";
7
+ export { Material, CollisionFilter, Sensor, Detectable } from "./components/material.js";
8
8
  export { Force, Torque, Impulse, AngularImpulse } from "./components/force.js";
9
9
  export { KinematicTargetPosition, KinematicTargetRotation } from "./components/target.js";
10
10
  export { ContactEvents, type ContactEvent, SensorEvents, type SensorEvent, HitEvents, type HitEvent, } from "./components/events.js";
11
+ export { physics } from "./adapter/queries.js";
12
+ export type { PhysicsQueries, QueryFilter, RayHit } from "./adapter/queries.js";