@ignifx/physics-2d 0.0.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1 +1,1686 @@
1
- export {}
1
+ import { AssetHandle, AssetLoader, Component, ComponentHooks, DiagnosticsGroup, Disconnect, Entity, ErrorContext, Extension, ExtensionContext, IgnifxError, JsonValue, LayerMask, MutableVec2, Schema, SchemaDescription, Signal, Vec2, Vec2Like } from "@ignifx/core";
2
+ import { Collider, EventQueue, RigidBody, World } from "@dimforge/rapier2d-compat";
3
+ import { TilemapCollisionData } from "@ignifx/2d";
4
+ //#region src/settings.d.ts
5
+ /**
6
+ * The `physics2d` project settings section (`docs/architecture/11-2d-toolkit.md` §8,
7
+ * `09-physics.md` §6). It mirrors the 3D `physics` section with a 2D gravity vector and Rapier's
8
+ * solver knob in place of Havok's world velocity clamps, which Rapier has no equivalent of.
9
+ *
10
+ * `fixedDeltaTime` is **not** here: the fixed step is shared with the core `time` section and the
11
+ * extension reads it from `app.time.fixedDeltaTime` on every step.
12
+ */
13
+ /**
14
+ * The section name as it appears in `ignifx.config.ts`.
15
+ *
16
+ * @public
17
+ */
18
+ export declare const PHYSICS_2D_SETTINGS_SECTION = "physics2d";
19
+ /**
20
+ * A surface, either as the `physics2d.defaultMaterial` setting or inline on a collider.
21
+ *
22
+ * @public
23
+ */
24
+ interface Physics2DMaterialValues {
25
+ /** The friction coefficient. */
26
+ readonly friction: number;
27
+ /** How much of the approach speed is returned, `0` to `1`. */
28
+ readonly restitution: number;
29
+ }
30
+ /**
31
+ * The resolved `physics2d` settings section.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * // ignifx.config.ts
36
+ * export default {
37
+ * layers: { layers: ["Default", "Player", "Enemy"] },
38
+ * physics2d: {
39
+ * gravity: { x: 0, y: -9.81 },
40
+ * collisionMatrix: { Player: ["Default", "Enemy"], Enemy: ["Default"] },
41
+ * },
42
+ * };
43
+ * ```
44
+ *
45
+ * @public
46
+ */
47
+ interface Physics2DSettings {
48
+ /** World gravity in metres per second squared; +Y is up (`11-2d-toolkit.md` §3). */
49
+ readonly gravity: Vec2Like;
50
+ /**
51
+ * Which layers each layer collides with. A layer the map does not mention collides with
52
+ * everything, which is what makes the default project need no matrix at all.
53
+ */
54
+ readonly collisionMatrix: Readonly<Record<string, readonly string[]>>;
55
+ /** The surface a collider with no material of its own uses. */
56
+ readonly defaultMaterial: Physics2DMaterialValues;
57
+ /** How many iterations Rapier's constraint solver runs; `0` leaves Rapier's own default (4). */
58
+ readonly velocityIterations: number;
59
+ /** Whether dynamic bodies and character controllers interpolate between fixed steps. */
60
+ readonly interpolation: boolean;
61
+ }
62
+ /**
63
+ * Builds the schema the `physics2d` section is validated against.
64
+ *
65
+ * @remarks
66
+ * It is a function, not a module-level constant: every field kind is a function call, and module
67
+ * scope holds declarations and immutable constants only (`CONSTITUTION.md` §3.5).
68
+ *
69
+ * @returns The schema.
70
+ *
71
+ * @public
72
+ */
73
+ export declare function physics2DSettingsSchema(): Schema;
74
+ /**
75
+ * The values used when a project omits the `physics2d` section.
76
+ *
77
+ * @returns A fresh defaults object.
78
+ *
79
+ * @public
80
+ */
81
+ export declare function defaultPhysics2DSettings(): Physics2DSettings;
82
+ //#endregion
83
+ //#region src/material.d.ts
84
+ /**
85
+ * The `ignifx.physicsmaterial` asset, read by the 2D extension.
86
+ *
87
+ * ## Why the format is the 3D one
88
+ *
89
+ * `11-2d-toolkit.md` §8 lists a `PhysicsMaterial2D`, and `09-physics.md` §2.4 already defines
90
+ * `{ "format": "ignifx.physicsmaterial", "friction": …, "staticFriction": …, "restitution": … }`.
91
+ * Inventing a second document for the same two numbers would give artists two files to keep in
92
+ * step, so this package reads **the same format and the same `.physicsmaterial.json` extension**,
93
+ * ignoring `staticFriction` (Rapier 2D has one friction coefficient, `geometry/collider.d.ts`).
94
+ * `@ignifx/physics` and `@ignifx/physics-2d` never run in one world — `IGX-1101` — so the two
95
+ * loaders never collide.
96
+ *
97
+ * The 2D-only knobs, how two surfaces' friction and restitution are **combined**, are fields on the
98
+ * collider rather than on the asset, so the document stays byte-identical to the 3D one.
99
+ */
100
+ /**
101
+ * The asset type name `.physicsmaterial.json` addresses resolve to.
102
+ *
103
+ * @public
104
+ */
105
+ export declare const PHYSICS_MATERIAL_2D_ASSET_TYPE = "physicsmaterial";
106
+ /**
107
+ * The address suffix that selects the loader.
108
+ *
109
+ * @public
110
+ */
111
+ export declare const PHYSICS_MATERIAL_2D_FILE_EXTENSION = ".physicsmaterial.json";
112
+ /**
113
+ * The `format` string every physics-material document declares.
114
+ *
115
+ * @public
116
+ */
117
+ export declare const PHYSICS_MATERIAL_2D_FILE_FORMAT = "ignifx.physicsmaterial";
118
+ /**
119
+ * The file format version; `1` before ignifx 1.0.
120
+ *
121
+ * @public
122
+ */
123
+ export declare const PHYSICS_MATERIAL_2D_FORMAT_VERSION = 1;
124
+ /**
125
+ * A loaded 2D surface.
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * const ice = await app.assets.load<PhysicsMaterial2D>("materials/ice.physicsmaterial.json");
130
+ * floor.addComponent(BoxCollider2D, { size: { x: 10, y: 1 }, material: ice });
131
+ * ```
132
+ *
133
+ * @public
134
+ */
135
+ export declare class PhysicsMaterial2D implements Physics2DMaterialValues {
136
+ /** The asset type token, so `asset(PhysicsMaterial2D)` fields resolve. */
137
+ static assetType: string;
138
+ /** A human-readable name, used in diagnostics. */
139
+ readonly name: string;
140
+ /** The friction coefficient. */
141
+ readonly friction: number;
142
+ /** How much of the approach speed is returned, `0` to `1`. */
143
+ readonly restitution: number;
144
+ /**
145
+ * Wraps parsed values.
146
+ *
147
+ * @param name - A human-readable name.
148
+ * @param values - Friction and restitution.
149
+ */
150
+ constructor(name: string, values: Physics2DMaterialValues);
151
+ /**
152
+ * Builds a material in code, filling in the fields the caller omitted.
153
+ *
154
+ * @param name - A human-readable name.
155
+ * @param values - Any subset of the two coefficients.
156
+ * @returns The material.
157
+ *
158
+ * @example
159
+ * ```ts
160
+ * const bouncy = PhysicsMaterial2D.fromValues("bouncy", { restitution: 0.9 });
161
+ * ```
162
+ */
163
+ static fromValues(name: string, values: Partial<Physics2DMaterialValues>): PhysicsMaterial2D;
164
+ }
165
+ /**
166
+ * Builds the loader for `.physicsmaterial.json` files.
167
+ *
168
+ * @returns The loader, ready for `ctx.registerAssetLoader`.
169
+ *
170
+ * @public
171
+ */
172
+ export declare function createPhysicsMaterial2DLoader(): AssetLoader<PhysicsMaterial2D>;
173
+ /**
174
+ * Parses one `ignifx.physicsmaterial` document into a 2D surface.
175
+ *
176
+ * @param address - The address it came from, for the diagnostic.
177
+ * @param document - The parsed JSON.
178
+ * @returns The material.
179
+ * @throws IgnifxError with code `IGX-1154` when the document is not one this build can read.
180
+ *
181
+ * @public
182
+ */
183
+ export declare function parsePhysicsMaterial2D(address: string, document: JsonValue): PhysicsMaterial2D;
184
+ //#endregion
185
+ //#region src/lite/rapier/world.d.ts
186
+ /**
187
+ * The Rapier 2D adapter (`docs/architecture/11-2d-toolkit.md` §8, ADR-0006). Everything the runtime
188
+ * needs from `@dimforge/rapier2d-compat` is a function here, so the rest of `src/` never imports the
189
+ * backend (`ignifx/no-lite-outside-adapter`, coding standards §4).
190
+ *
191
+ * ## Facts measured against `@dimforge/rapier2d-compat@0.20.0` (spike S6.2)
192
+ *
193
+ * - **The broadphase is only built by `World.step`.** Before the first step, `castRay` returns
194
+ * `null` and `KinematicCharacterController.computeColliderMovement` reports the full requested
195
+ * motion with no obstacles; a collider created after the last step is invisible until the next
196
+ * one. {@link primeWorld} runs a zero-length step, which builds the broadphase without
197
+ * integrating — but it is *not* free of side effects on a running simulation (a settled pile
198
+ * hashes differently), so the runtime primes only when the collider set changed.
199
+ * - **`InteractionGroups` is one 32-bit number**: membership in the high 16 bits, filter in the low
200
+ * 16 (`geometry/interaction_groups.d.ts`). Sixteen layers, not thirty-two.
201
+ * - **`ActiveCollisionTypes.DEFAULT` excludes non-dynamic pairs**, so a kinematic character never
202
+ * reports entering a static sensor. Colliders that want events are given
203
+ * `ActiveCollisionTypes.ALL`.
204
+ */
205
+ /**
206
+ * Rapier's physics world.
207
+ *
208
+ * @internal
209
+ */
210
+ type RapierWorld = World;
211
+ /**
212
+ * One Rapier rigid body.
213
+ *
214
+ * @internal
215
+ */
216
+ type RapierBody = RigidBody;
217
+ /**
218
+ * One Rapier collider.
219
+ *
220
+ * @internal
221
+ */
222
+ type RapierCollider = Collider;
223
+ /**
224
+ * How a body moves, in the three flavours ignifx exposes.
225
+ *
226
+ * @internal
227
+ */
228
+ declare const BodyMotion2D: {
229
+ /** Simulated by the solver. */
230
+ readonly dynamic: "dynamic";
231
+ /** Moved by the game, pushes dynamic bodies, ignores forces. */
232
+ readonly kinematic: "kinematic";
233
+ /** Never moves. */
234
+ readonly static: "static";
235
+ };
236
+ /**
237
+ * The union of {@link BodyMotion2D}.
238
+ *
239
+ * @internal
240
+ */
241
+ type BodyMotion2D = (typeof BodyMotion2D)[keyof typeof BodyMotion2D];
242
+ /**
243
+ * A collision shape, described in metres in the body's local frame.
244
+ *
245
+ * @internal
246
+ */
247
+ type RapierShape2D = {
248
+ readonly kind: "box";
249
+ readonly halfWidth: number;
250
+ readonly halfHeight: number;
251
+ } | {
252
+ readonly kind: "circle";
253
+ readonly radius: number;
254
+ } | {
255
+ readonly kind: "capsule";
256
+ readonly halfHeight: number;
257
+ readonly radius: number;
258
+ } | {
259
+ readonly kind: "polygon";
260
+ readonly points: Float32Array;
261
+ } | {
262
+ readonly kind: "polyline";
263
+ readonly points: Float32Array;
264
+ };
265
+ //#endregion
266
+ //#region src/components/collider.d.ts
267
+ /**
268
+ * The 2D collider contract (`docs/architecture/11-2d-toolkit.md` §8). Every collider shares an
269
+ * offset, the trigger flag, a surface, a layer override, and the one-way platform flag, and answers
270
+ * one question the body builder asks: which Rapier shapes it stands for.
271
+ *
272
+ * ## Corrections to §8
273
+ *
274
+ * - **The material is two fields, not a union.** A schema field has exactly one kind (ADR-0004), so
275
+ * {@link Collider2D.material} (an asset reference) and {@link Collider2D.inlineMaterial} (a
276
+ * record) are separate; the asset wins, the inline record is the fallback, and
277
+ * `physics2d.defaultMaterial` is the last resort. This is the same split `@ignifx/physics` makes.
278
+ * - **Combine rules are collider fields.** Rapier combines two surfaces' friction and restitution
279
+ * with a per-collider rule (`dynamics/coefficient_combine_rule.d.ts`); the 3D
280
+ * `ignifx.physicsmaterial` document has no such field, so the knob lives here rather than
281
+ * forking the asset format.
282
+ * - **A collider may stand for several Rapier colliders.** `TilemapCollider2D` produces one polygon
283
+ * per merged tile run, so {@link Collider2D.collectShapes} fills a list rather than returning one
284
+ * shape.
285
+ *
286
+ * ## Sizes and scale
287
+ *
288
+ * Sizes are authored in local metres and multiplied by the entity's lossy scale when the shapes are
289
+ * built. Rapier cannot rescale a built shape, so a later scale change needs
290
+ * {@link Collider2D.rebuild}.
291
+ */
292
+ /**
293
+ * How two surfaces' coefficients are combined when they touch, mirroring Rapier's
294
+ * `CoefficientCombineRule`.
295
+ *
296
+ * @public
297
+ */
298
+ export declare const COMBINE_RULES: readonly ["average", "min", "multiply", "max"];
299
+ /**
300
+ * The union of {@link COMBINE_RULES}.
301
+ *
302
+ * @public
303
+ */
304
+ type CombineRule = (typeof COMBINE_RULES)[number];
305
+ /**
306
+ * One Rapier shape a collider stands for, positioned in the body's local frame.
307
+ *
308
+ * @internal
309
+ */
310
+ interface CollectedShape2D {
311
+ /** The geometry. */
312
+ readonly shape: RapierShape2D;
313
+ /** Where it sits relative to the entity origin, in metres. */
314
+ readonly offset: Vec2Like;
315
+ /** How it is turned about that point, in radians counter-clockwise. */
316
+ readonly rotation: number;
317
+ /** Whether it is solid only when a character controller comes down onto it. */
318
+ readonly oneWay: boolean;
319
+ }
320
+ /**
321
+ * The fields every 2D collider declares.
322
+ *
323
+ * @returns The shared field declarations, ready to spread into a collider's own schema.
324
+ *
325
+ * @public
326
+ */
327
+ export declare function collider2DFields(): Schema;
328
+ /**
329
+ * The base class of every 2D collider.
330
+ *
331
+ * @public
332
+ */
333
+ export declare abstract class Collider2D extends Component implements ComponentHooks {
334
+ /** Several colliders on one entity make one compound body. */
335
+ static allowMultiple: boolean;
336
+ /** The shape's offset from the entity origin, in local metres. */
337
+ offset: Vec2Like;
338
+ /** When `true` the shape reports overlaps and resolves no contacts. */
339
+ isTrigger: boolean;
340
+ /** A `.physicsmaterial.json` reference; wins over {@link Collider2D.inlineMaterial}. */
341
+ material: AssetHandle<PhysicsMaterial2D> | null;
342
+ /** An inline surface, used when {@link Collider2D.material} is `null`. */
343
+ inlineMaterial: Physics2DMaterialValues | null;
344
+ /** How this surface's friction combines with the one it touches. */
345
+ frictionCombine: CombineRule;
346
+ /** How this surface's restitution combines with the one it touches. */
347
+ restitutionCombine: CombineRule;
348
+ /**
349
+ * Whether this is a one-way platform: a `CharacterController2D` with
350
+ * `onOneWayPlatforms` passes up through it and lands on it coming down. Rigid bodies are
351
+ * unaffected — one-way support is a character-controller feature in the MVP.
352
+ */
353
+ oneWay: boolean;
354
+ /** The name of the layer this collider filters as, or `""` to use `entity.layer`. */
355
+ layerOverride: string;
356
+ /** Applies the shared defaults. A concrete collider calls `super()` and then applies its own. */
357
+ constructor();
358
+ /** Marks the entity's body for a rebuild at the start of the next fixed step. */
359
+ onAttach(): void;
360
+ /** Marks the entity's body for a rebuild, which removes this collider from it. */
361
+ onDetach(): void;
362
+ /**
363
+ * Rebuilds the entity's body and shapes at the start of the next fixed step. Call it after
364
+ * changing a size, an offset, `isTrigger`, or the entity's scale.
365
+ *
366
+ * @example
367
+ * ```ts
368
+ * box.size = { x: 2, y: 2 };
369
+ * box.rebuild();
370
+ * ```
371
+ */
372
+ rebuild(): void;
373
+ /**
374
+ * Resolves the surface this collider presents to Rapier.
375
+ *
376
+ * @param fallback - The world's `physics2d.defaultMaterial`.
377
+ * @returns The asset's values, the inline values, or the fallback.
378
+ */
379
+ resolveMaterial(fallback: Physics2DMaterialValues): Physics2DMaterialValues;
380
+ /**
381
+ * Appends the Rapier shapes this collider stands for.
382
+ *
383
+ * @param scale - The entity's lossy scale in the 2D plane.
384
+ * @param out - The list to append to.
385
+ *
386
+ * @internal
387
+ */
388
+ abstract collectShapes(scale: Vec2Like, out: CollectedShape2D[]): void;
389
+ }
390
+ //#endregion
391
+ //#region src/events.d.ts
392
+ /**
393
+ * The payloads the five physics callbacks receive in 2D (`docs/architecture/11-2d-toolkit.md` §8,
394
+ * `09-physics.md` §4).
395
+ *
396
+ * ## The callbacks are the 3D names
397
+ *
398
+ * `11-2d-toolkit.md` §8 writes them as `onCollisionEnter2D`/`onTriggerEnter2D`. The kernel's
399
+ * `PhysicsCallbackName` union has five members and no `2D` variants
400
+ * (`packages/core/src/lifecycle/callbacks.ts`), and a world uses either `physics()` or
401
+ * `physics2d()` — never both, which is what `IGX-1101` enforces. So a 2D game implements
402
+ * `onCollisionEnter`, `onCollisionStay`, `onCollisionExit`, `onTriggerEnter`, and `onTriggerExit`,
403
+ * and receives the 2D payloads below. §8 is corrected accordingly.
404
+ *
405
+ * ## Identities are native
406
+ *
407
+ * Rapier reports **both** colliders of every event (`pipeline/event_queue.d.ts`,
408
+ * `drainCollisionEvents`), so `other` is never `null` for a live body and the ADR-0013 waiver that
409
+ * 3D physics needs has no counterpart here.
410
+ *
411
+ * Every payload is **pooled**: the same instances are reused for every event of a step, so a script
412
+ * that needs a value after its callback returns must copy it out (coding standards §7).
413
+ */
414
+ /**
415
+ * One contact point of a 2D collision. Pooled with its owning {@link Collision2D}.
416
+ *
417
+ * @public
418
+ */
419
+ interface ContactPoint2D {
420
+ /** The world-space contact point, in metres. */
421
+ readonly point: Vec2Like;
422
+ /** The world-space contact normal, pointing away from the other collider. */
423
+ readonly normal: Vec2Like;
424
+ /** The magnitude of the impulse Rapier's solver applied; `0` for a contact that just ended. */
425
+ readonly impulse: number;
426
+ }
427
+ /**
428
+ * What a script's `onTriggerEnter`/`onTriggerExit` is handed in a 2D world.
429
+ *
430
+ * @example
431
+ * ```ts
432
+ * class Coin extends Script implements ScriptCallbacks {
433
+ * static typeId = "mygame/Coin";
434
+ * onTriggerEnter(trigger: TriggerEvent2D): void {
435
+ * if (trigger.other?.tags.has("player") === true) {
436
+ * this.entity.destroy();
437
+ * }
438
+ * }
439
+ * }
440
+ * ```
441
+ *
442
+ * @public
443
+ */
444
+ interface TriggerEvent2D {
445
+ /** The entity that entered or left, or `null` when its body is already gone. */
446
+ readonly other: Entity | null;
447
+ /** The exact collider on the other entity — Rapier reports shape identity, unlike Havok. */
448
+ readonly otherCollider: Collider2D | null;
449
+ /** The entity whose script is being called. */
450
+ readonly self: Entity;
451
+ /** The collider on this entity that took part. */
452
+ readonly selfCollider: Collider2D | null;
453
+ }
454
+ /**
455
+ * What a script's `onCollisionEnter`/`onCollisionStay`/`onCollisionExit` is handed in a 2D world.
456
+ *
457
+ * @public
458
+ */
459
+ interface Collision2D {
460
+ /** The entity that was hit, or `null` when its body is already gone. */
461
+ readonly other: Entity | null;
462
+ /** The exact collider on the other entity. */
463
+ readonly otherCollider: Collider2D | null;
464
+ /** The entity whose script is being called. */
465
+ readonly self: Entity;
466
+ /** The collider on this entity that took part. */
467
+ readonly selfCollider: Collider2D | null;
468
+ /** The contacts of this event. Pooled; valid only during the callback. */
469
+ readonly contacts: readonly ContactPoint2D[];
470
+ /** The relative velocity of the two bodies at the contact, in metres per second. */
471
+ readonly relativeVelocity: Vec2Like;
472
+ }
473
+ /**
474
+ * What `CharacterController2D.onCollided` reports: one obstacle the character hit this step.
475
+ *
476
+ * @public
477
+ */
478
+ interface CharacterCollision2D {
479
+ /** The entity that was hit, or `null` when it is not an ignifx body. */
480
+ readonly other: Entity | null;
481
+ /** The collider that was hit, or `null`. */
482
+ readonly otherCollider: Collider2D | null;
483
+ /** The world-space contact point. */
484
+ readonly point: Vec2Like;
485
+ /** The world-space outward normal on the obstacle. */
486
+ readonly normal: Vec2Like;
487
+ }
488
+ //#endregion
489
+ //#region src/components/rigidbody.d.ts
490
+ /**
491
+ * The `Rigidbody2D` component (`docs/architecture/11-2d-toolkit.md` §8): what makes an entity's 2D
492
+ * colliders a simulated, kinematic, or explicitly static Rapier body.
493
+ *
494
+ * ## Decisions §8 leaves open
495
+ *
496
+ * - **`mass` is exact, and `0` means "weigh the colliders".** Rapier derives a body's mass and
497
+ * angular inertia from each collider's *density* and area (`geometry/collider.d.ts`,
498
+ * `setDensity`), and `setAdditionalMass` adds mass without inertia. So a non-zero `mass` is
499
+ * applied by scaling every collider's density until the body weighs exactly that, which keeps the
500
+ * inertia distribution the shapes imply; `mass: 0` leaves Rapier's own density of 1 kg/m² alone.
501
+ * - **`freezeRotation` is one boolean, not three.** A 2D body has one rotational degree of freedom
502
+ * (`dynamics/rigid_body.d.ts`, `lockRotations`).
503
+ * - **Damping is per body here, unlike 3D.** Havok has no per-body damping; Rapier does
504
+ * (`setLinearDamping`, `setAngularDamping`), so `linearDamping` and `angularDamping` are real
505
+ * fields rather than upstream requests.
506
+ * - **`collisionEvents` is a three-valued enum**, exactly as in `@ignifx/physics`: a schema field
507
+ * has one kind (ADR-0004), and `"auto"` recomputes from `ctx.entityImplements` whenever a
508
+ * component joins or leaves the entity.
509
+ */
510
+ /**
511
+ * How a 2D body moves.
512
+ *
513
+ * @public
514
+ */
515
+ export declare const BODY_TYPES_2D: readonly ["dynamic", "kinematic", "static"];
516
+ /**
517
+ * The union of {@link BODY_TYPES_2D}.
518
+ *
519
+ * @public
520
+ */
521
+ type BodyType2D = (typeof BODY_TYPES_2D)[number];
522
+ /**
523
+ * Whether a body's display pose is interpolated between fixed steps.
524
+ *
525
+ * @public
526
+ */
527
+ export declare const INTERPOLATION_MODES_2D: readonly ["none", "interpolate"];
528
+ /**
529
+ * The union of {@link INTERPOLATION_MODES_2D}.
530
+ *
531
+ * @public
532
+ */
533
+ type InterpolationMode2D = (typeof INTERPOLATION_MODES_2D)[number];
534
+ /**
535
+ * Whether collision callbacks are delivered for this body.
536
+ *
537
+ * @public
538
+ */
539
+ export declare const COLLISION_EVENT_MODES_2D: readonly ["auto", "on", "off"];
540
+ /**
541
+ * The union of {@link COLLISION_EVENT_MODES_2D}.
542
+ *
543
+ * @public
544
+ */
545
+ type CollisionEventMode2D = (typeof COLLISION_EVENT_MODES_2D)[number];
546
+ /**
547
+ * The Rapier objects a `Rigidbody2D` owns. Unstable escape hatch
548
+ * (`docs/architecture/00-overview.md` §3).
549
+ *
550
+ * @public
551
+ */
552
+ interface Rigidbody2DRapierHandles {
553
+ /** The Rapier body, or `null` before the first fixed step has built it. */
554
+ readonly body: RapierBody | null;
555
+ }
556
+ /**
557
+ * Makes an entity's 2D colliders a Rapier body.
558
+ *
559
+ * @example
560
+ * ```ts
561
+ * const crate = world.createEntity("Crate");
562
+ * crate.transform.position2D = new Vec2(0, 5);
563
+ * crate.addComponent(BoxCollider2D, { size: { x: 1, y: 1 } });
564
+ * crate.addComponent(Rigidbody2D, { mass: 2 });
565
+ * ```
566
+ *
567
+ * @public
568
+ */
569
+ export declare class Rigidbody2D extends Component implements ComponentHooks {
570
+ #private;
571
+ /** The namespaced registration id. */
572
+ static typeId: string;
573
+ /** One body per entity. */
574
+ static allowMultiple: boolean;
575
+ /** The serialized field declarations (ADR-0004). */
576
+ static schema: Schema;
577
+ bodyType: BodyType2D;
578
+ mass: number;
579
+ gravityScale: number;
580
+ linearDamping: number;
581
+ angularDamping: number;
582
+ freezeRotation: boolean;
583
+ interpolation: InterpolationMode2D;
584
+ collisionEvents: CollisionEventMode2D;
585
+ /** Applies the schema defaults, exactly as `Component.define` would. */
586
+ constructor();
587
+ /** Marks the entity's body for a rebuild at the start of the next fixed step. */
588
+ onAttach(): void;
589
+ /** Marks the entity's body for a rebuild, which turns it back into an implicit static body. */
590
+ onDetach(): void;
591
+ /**
592
+ * Rebuilds the body at the start of the next fixed step. Call it after changing `bodyType`,
593
+ * `mass`, `freezeRotation`, damping, or the entity's scale.
594
+ */
595
+ rebuild(): void;
596
+ /**
597
+ * The Rapier handles this component owns.
598
+ *
599
+ * @returns The body, or `null` before the first fixed step built it.
600
+ */
601
+ get rapier(): Rigidbody2DRapierHandles;
602
+ /**
603
+ * The body's linear velocity in metres per second.
604
+ *
605
+ * @returns A freshly allocated vector; use {@link Rigidbody2D.linearVelocityToRef} in hot code.
606
+ */
607
+ get linearVelocity(): Vec2;
608
+ /**
609
+ * Replaces the body's linear velocity.
610
+ *
611
+ * @param value - Metres per second, world space.
612
+ */
613
+ set linearVelocity(value: Vec2Like);
614
+ /**
615
+ * Reads the linear velocity without allocating.
616
+ *
617
+ * @param out - The vector to write.
618
+ * @returns `out`.
619
+ */
620
+ linearVelocityToRef(out: MutableVec2): MutableVec2;
621
+ /**
622
+ * The body's angular velocity.
623
+ *
624
+ * @returns Degrees per second, counter-clockwise — the same unit as `Transform.rotation2D`.
625
+ */
626
+ get angularVelocity(): number;
627
+ /**
628
+ * Replaces the body's angular velocity.
629
+ *
630
+ * @param value - Degrees per second, counter-clockwise.
631
+ */
632
+ set angularVelocity(value: number);
633
+ /**
634
+ * The mass Rapier computed for the body, in kilograms.
635
+ *
636
+ * @returns The mass, or `0` before the body exists.
637
+ */
638
+ get computedMass(): number;
639
+ /**
640
+ * Applies a force for one fixed step. Call it from `fixedUpdate`.
641
+ *
642
+ * @param force - Newtons, world space.
643
+ * @param point - Where to apply it; defaults to the centre of mass.
644
+ *
645
+ * @example
646
+ * ```ts
647
+ * fixedUpdate(): void {
648
+ * this.body.addForce({ x: 0, y: 20 });
649
+ * }
650
+ * ```
651
+ */
652
+ addForce(force: Vec2Like, point?: Vec2Like): void;
653
+ /**
654
+ * Applies an instantaneous impulse.
655
+ *
656
+ * @param impulse - Newton-seconds, world space.
657
+ * @param point - Where to apply it; defaults to the centre of mass.
658
+ */
659
+ addImpulse(impulse: Vec2Like, point?: Vec2Like): void;
660
+ /**
661
+ * Applies a torque for one fixed step.
662
+ *
663
+ * @param torque - Newton-metres, positive counter-clockwise.
664
+ */
665
+ addTorque(torque: number): void;
666
+ /**
667
+ * Moves the body without integrating a velocity, and resets the interpolation history so the
668
+ * display pose does not slide across the gap.
669
+ *
670
+ * @param position - The new world position, in metres.
671
+ * @param rotation - The new rotation in degrees counter-clockwise; defaults to the current one.
672
+ */
673
+ teleport(position: Vec2Like, rotation?: number): void;
674
+ }
675
+ //#endregion
676
+ //#region src/components/character-controller.d.ts
677
+ /**
678
+ * The `CharacterController2D` component (`docs/architecture/11-2d-toolkit.md` §8): Rapier's
679
+ * `KinematicCharacterController` (`control/character_controller.d.ts`) driven from `fixedUpdate`.
680
+ *
681
+ * ## How it is driven
682
+ *
683
+ * Call {@link CharacterController2D.move} from `fixedUpdate`. The requested displacements of one
684
+ * step are summed and handed to Rapier's `computeColliderMovement` by the step system, so two
685
+ * scripts moving the same character compose instead of fighting. Gravity is **not** applied by this
686
+ * component: a bare controller is purely kinematic, exactly as the 3D one is, and the toolkit
687
+ * controller scripts integrate gravity themselves.
688
+ *
689
+ * After the step the controller owns the entity's world X and Y. Z and `rotation2D` stay
690
+ * user-controlled.
691
+ *
692
+ * ## The one addition to §8: `shape`
693
+ *
694
+ * §8 describes the controller as a capsule. Measured against `@dimforge/rapier2d-compat@0.20.0`
695
+ * (spike S6.2), Rapier's autostep clears a 0.3 m step with a **box** character and refuses anything
696
+ * above about 0.15 m with a capsule of radius 0.2 — so `stepOffset` is only usable with a box.
697
+ * {@link CharacterController2D.shape} therefore chooses between the two, defaulting to `"capsule"`
698
+ * as §8 says, and the limitation is documented in the skill and in ADR-0006's validation section.
699
+ */
700
+ /**
701
+ * The collision shape a 2D character controller uses.
702
+ *
703
+ * @public
704
+ */
705
+ export declare const CHARACTER_SHAPES_2D: readonly ["capsule", "box"];
706
+ /**
707
+ * The union of {@link CHARACTER_SHAPES_2D}.
708
+ *
709
+ * @public
710
+ */
711
+ type CharacterShape2D = (typeof CHARACTER_SHAPES_2D)[number];
712
+ /**
713
+ * A kinematic character that walks, slides, climbs slopes, and steps up.
714
+ *
715
+ * @example
716
+ * ```ts
717
+ * class Walk extends Script implements ScriptCallbacks {
718
+ * static typeId = "mygame/Walk";
719
+ * fixedUpdate(dt: number): void {
720
+ * const controller = this.entity.requireComponent(CharacterController2D);
721
+ * controller.move({ x: 4 * dt, y: -9.81 * dt });
722
+ * }
723
+ * }
724
+ * ```
725
+ *
726
+ * @public
727
+ */
728
+ export declare class CharacterController2D extends Component implements ComponentHooks {
729
+ #private;
730
+ /** The namespaced registration id. */
731
+ static typeId: string;
732
+ /** One controller per entity. */
733
+ static allowMultiple: boolean;
734
+ /** The serialized field declarations (ADR-0004). */
735
+ static schema: Schema;
736
+ shape: CharacterShape2D;
737
+ radius: number;
738
+ height: number;
739
+ offset: Vec2Like;
740
+ slopeLimit: number;
741
+ stepOffset: number;
742
+ snapToGround: number;
743
+ skinWidth: number;
744
+ onOneWayPlatforms: boolean;
745
+ pushBodies: boolean;
746
+ interpolation: InterpolationMode2D;
747
+ /** Applies the schema defaults. */
748
+ constructor();
749
+ /** Creates the Rapier controller at the start of the next fixed step. */
750
+ onAttach(): void;
751
+ /** Releases the Rapier controller and its collider. */
752
+ onDetach(): void;
753
+ /** Rebuilds the capsule or box at the start of the next fixed step. */
754
+ rebuild(): void;
755
+ /**
756
+ * Requests a displacement for this fixed step. Displacements accumulate until the step runs.
757
+ *
758
+ * @param displacement - The world-space displacement to attempt, in metres.
759
+ */
760
+ move(displacement: Vec2Like): void;
761
+ /**
762
+ * How fast the character actually moved over the last fixed step, after sliding and blocking.
763
+ *
764
+ * @returns A freshly allocated vector in metres per second.
765
+ */
766
+ get velocity(): Vec2;
767
+ /**
768
+ * Whether the character ended the last step on walkable ground.
769
+ *
770
+ * @returns Rapier's `computedGrounded` from the last move.
771
+ */
772
+ get isGrounded(): boolean;
773
+ /**
774
+ * The most upward-facing normal of the obstacles the last move touched.
775
+ *
776
+ * @returns A live view; copy it if you keep it.
777
+ */
778
+ get groundNormal(): Vec2;
779
+ /**
780
+ * Emitted once per obstacle the character hit during a step.
781
+ *
782
+ * @returns The signal, created on first access.
783
+ */
784
+ get onCollided(): Signal<CharacterCollision2D>;
785
+ /**
786
+ * Teleports the character, clearing any pending motion and the interpolation history.
787
+ *
788
+ * @param position - The new world position of the entity, in metres.
789
+ */
790
+ teleport(position: Vec2Like): void;
791
+ /**
792
+ * The displacement requested so far this step, consumed by the step system.
793
+ *
794
+ * @returns A live view of the accumulator.
795
+ *
796
+ * @internal
797
+ */
798
+ takePendingMove(): Vec2;
799
+ /**
800
+ * Records the outcome of a step.
801
+ *
802
+ * @param movement - What Rapier resolved.
803
+ * @param grounded - Whether the character ended on walkable ground.
804
+ * @param normal - The most upward-facing contact normal, or `null` when there was none.
805
+ * @param deltaSeconds - The fixed step the move covered.
806
+ *
807
+ * @internal
808
+ */
809
+ applyStepResult(movement: Vec2Like, grounded: boolean, normal: Vec2Like | null, deltaSeconds: number): void;
810
+ /**
811
+ * Emits `onCollided` if anything is listening.
812
+ *
813
+ * @param collision - The obstacle to report.
814
+ *
815
+ * @internal
816
+ */
817
+ reportHit(collision: CharacterCollision2D): void;
818
+ }
819
+ //#endregion
820
+ //#region src/components/colliders.d.ts
821
+ /**
822
+ * The axis a 2D capsule stands along.
823
+ *
824
+ * @public
825
+ */
826
+ export declare const CAPSULE_DIRECTIONS_2D: readonly ["x", "y"];
827
+ /**
828
+ * The union of {@link CAPSULE_DIRECTIONS_2D}.
829
+ *
830
+ * @public
831
+ */
832
+ type CapsuleDirection2D = (typeof CAPSULE_DIRECTIONS_2D)[number];
833
+ /**
834
+ * An axis-aligned box collider, sized in local metres.
835
+ *
836
+ * @example
837
+ * ```ts
838
+ * const floor = world.createEntity("Floor");
839
+ * floor.addComponent(BoxCollider2D, { size: { x: 20, y: 1 } });
840
+ * ```
841
+ *
842
+ * @public
843
+ */
844
+ export declare class BoxCollider2D extends Collider2D {
845
+ /** The namespaced registration id. */
846
+ static typeId: string;
847
+ /** The serialized field declarations (ADR-0004). */
848
+ static schema: Schema;
849
+ size: Vec2Like;
850
+ /** Applies this collider's defaults on top of the shared ones. */
851
+ constructor();
852
+ /**
853
+ * Appends this collider's Rapier shape.
854
+ *
855
+ * @param scale - The entity's lossy 2D scale.
856
+ * @param out - The list to append to.
857
+ *
858
+ * @internal
859
+ */
860
+ collectShapes(scale: Vec2Like, out: CollectedShape2D[]): void;
861
+ }
862
+ /**
863
+ * A circle collider. Non-uniform scale is not representable as a circle, so the larger scale axis
864
+ * wins — the same rule Unity applies.
865
+ *
866
+ * @public
867
+ */
868
+ export declare class CircleCollider2D extends Collider2D {
869
+ /** The namespaced registration id. */
870
+ static typeId: string;
871
+ /** The serialized field declarations. */
872
+ static schema: Schema;
873
+ radius: number;
874
+ /** Applies this collider's defaults on top of the shared ones. */
875
+ constructor();
876
+ /**
877
+ * Appends this collider's Rapier shape.
878
+ *
879
+ * @param scale - The entity's lossy 2D scale.
880
+ * @param out - The list to append to.
881
+ *
882
+ * @internal
883
+ */
884
+ collectShapes(scale: Vec2Like, out: CollectedShape2D[]): void;
885
+ }
886
+ /**
887
+ * A capsule collider: a rectangle with semicircular caps, standing along X or Y.
888
+ *
889
+ * @remarks
890
+ * `height` is the **total** tip-to-tip height, so a capsule shorter than `2 * radius` degenerates to
891
+ * a circle of that radius rather than inverting. Rapier's capsule always stands along Y, so an
892
+ * `x` capsule is expressed by swapping the axes of the half-extents — which means an `x` capsule
893
+ * and a rotated `y` capsule are the same shape.
894
+ *
895
+ * @public
896
+ */
897
+ export declare class CapsuleCollider2D extends Collider2D {
898
+ /** The namespaced registration id. */
899
+ static typeId: string;
900
+ /** The serialized field declarations. */
901
+ static schema: Schema;
902
+ radius: number;
903
+ height: number;
904
+ direction: CapsuleDirection2D;
905
+ /** Applies this collider's defaults on top of the shared ones. */
906
+ constructor();
907
+ /**
908
+ * Appends this collider's Rapier shape.
909
+ *
910
+ * @param scale - The entity's lossy 2D scale.
911
+ * @param out - The list to append to.
912
+ *
913
+ * @internal
914
+ */
915
+ collectShapes(scale: Vec2Like, out: CollectedShape2D[]): void;
916
+ }
917
+ /**
918
+ * A convex polygon collider, wound in either direction, in local metres.
919
+ *
920
+ * @remarks
921
+ * Rapier builds the **convex hull** of the points, so a concave outline is silently rounded out.
922
+ * Model a concave shape as several `PolygonCollider2D`s on one entity, or as an
923
+ * {@link EdgeCollider2D} when it is an open contour.
924
+ *
925
+ * @public
926
+ */
927
+ export declare class PolygonCollider2D extends Collider2D {
928
+ /** The namespaced registration id. */
929
+ static typeId: string;
930
+ /** The serialized field declarations. */
931
+ static schema: Schema;
932
+ points: Vec2Like[];
933
+ /** Applies this collider's defaults on top of the shared ones. */
934
+ constructor();
935
+ /**
936
+ * Appends this collider's Rapier shape.
937
+ *
938
+ * @param scale - The entity's lossy 2D scale.
939
+ * @param out - The list to append to.
940
+ * @throws IgnifxError with code `IGX-1156` when fewer than three points are given.
941
+ *
942
+ * @internal
943
+ */
944
+ collectShapes(scale: Vec2Like, out: CollectedShape2D[]): void;
945
+ }
946
+ /**
947
+ * An open chain of line segments — a platformer's ground contour.
948
+ *
949
+ * @public
950
+ */
951
+ export declare class EdgeCollider2D extends Collider2D {
952
+ /** The namespaced registration id. */
953
+ static typeId: string;
954
+ /** The serialized field declarations. */
955
+ static schema: Schema;
956
+ points: Vec2Like[];
957
+ /** Applies this collider's defaults on top of the shared ones. */
958
+ constructor();
959
+ /**
960
+ * Appends this collider's Rapier shape.
961
+ *
962
+ * @param scale - The entity's lossy 2D scale.
963
+ * @param out - The list to append to.
964
+ * @throws IgnifxError with code `IGX-1156` when fewer than two points are given.
965
+ *
966
+ * @internal
967
+ */
968
+ collectShapes(scale: Vec2Like, out: CollectedShape2D[]): void;
969
+ }
970
+ //#endregion
971
+ //#region src/components/tilemap-collider.d.ts
972
+ /**
973
+ * `TilemapCollider2D` (`docs/architecture/11-2d-toolkit.md` §2.5, §8): the merged collision surface
974
+ * of a `Tilemap`, turned into Rapier geometry.
975
+ *
976
+ * ## How it reaches the data
977
+ *
978
+ * `@ignifx/2d` is an **optional** peer of `@ignifx/physics-2d` (a physics-only 2D game needs no
979
+ * sprite toolkit), so this component never imports the toolkit as a value — only the
980
+ * `TilemapCollisionData` type. A game, or `@ignifx/2d`'s own tilemap loader, assigns
981
+ * {@link TilemapCollider2D.collisionData}; the runtime compares the data's `version` at the start of
982
+ * every fixed step and rebuilds the shapes when it changes, which is the same moment
983
+ * `Tilemap.onCollisionChanged` fires and needs no signal subscription across the package boundary.
984
+ *
985
+ * ## Why closed polylines rather than polygons
986
+ *
987
+ * A merged run of solid tiles is not convex in general — an L of tiles merges into an L — and
988
+ * Rapier's polygon shape is a **convex hull** (`geometry/shape.d.ts`, `ConvexPolygon`), which would
989
+ * silently fill the notch. A closed `polyline` reproduces the outline exactly and is the shape
990
+ * static level geometry wants; the trade-off is that a polyline is infinitely thin, so a body that
991
+ * starts inside the tilemap is not pushed out.
992
+ */
993
+ /**
994
+ * The collision surface of a tilemap, as one static body's worth of Rapier shapes.
995
+ *
996
+ * @example
997
+ * ```ts
998
+ * const map = world.createEntity("Map");
999
+ * const collider = map.addComponent(TilemapCollider2D);
1000
+ * collider.collisionData = tilemap.collisionData;
1001
+ * ```
1002
+ *
1003
+ * @public
1004
+ */
1005
+ export declare class TilemapCollider2D extends Collider2D {
1006
+ #private;
1007
+ /** The namespaced registration id. */
1008
+ static typeId: string;
1009
+ /** The serialized field declarations; the geometry itself comes from the tilemap asset. */
1010
+ static schema: Schema;
1011
+ /** Applies the shared defaults. */
1012
+ constructor();
1013
+ /**
1014
+ * The merged chunk geometry this collider builds shapes from.
1015
+ *
1016
+ * @returns The data, or `null` when none has been supplied.
1017
+ */
1018
+ get collisionData(): TilemapCollisionData | null;
1019
+ /**
1020
+ * Replaces the tilemap geometry and schedules a rebuild.
1021
+ *
1022
+ * @param value - The merged chunk geometry, or `null` to drop the shapes.
1023
+ */
1024
+ set collisionData(value: TilemapCollisionData | null);
1025
+ /**
1026
+ * Whether the supplied data has changed since the shapes were built. The runtime polls this once
1027
+ * per fixed step, which is how a tile edit reaches physics without a cross-package subscription.
1028
+ *
1029
+ * @returns `true` when a rebuild is due.
1030
+ *
1031
+ * @internal
1032
+ */
1033
+ needsRebuild(): boolean;
1034
+ /**
1035
+ * Appends one shape per merged outline and one per one-way edge.
1036
+ *
1037
+ * @param scale - The entity's lossy 2D scale.
1038
+ * @param out - The list to append to.
1039
+ *
1040
+ * @internal
1041
+ */
1042
+ collectShapes(scale: Vec2Like, out: CollectedShape2D[]): void;
1043
+ }
1044
+ //#endregion
1045
+ //#region src/errors.d.ts
1046
+ /**
1047
+ * The diagnostic codes `@ignifx/physics-2d` owns. 2D physics shares the `11` subsystem range with
1048
+ * the 2D toolkit (`docs/architecture/15-devtools-and-diagnostics.md` §1,
1049
+ * `docs/architecture/11-2d-toolkit.md` §8), so the range is split: `@ignifx/2d` owns
1050
+ * `IGX-1101`–`IGX-1149` and this package owns `IGX-1150` upwards.
1051
+ *
1052
+ * `IGX-1101` is the one exception. `11-2d-toolkit.md` §8 names it by number — "registering both
1053
+ * throws `IGX-1101`" — and only this package can detect the condition, so this package registers
1054
+ * it. An app's error-code registry refuses a duplicate registration
1055
+ * (`packages/core/src/errors/error-code-registry.ts`), so `@ignifx/2d` must not declare it.
1056
+ */
1057
+ /**
1058
+ * Every diagnostic code `@ignifx/physics-2d` can throw or report.
1059
+ *
1060
+ * @example
1061
+ * ```ts
1062
+ * throw physics2DError(Physics2DErrorCode.queryBeforeStep, "raycast() ran before the first step.", {
1063
+ * context: { query: "raycast" },
1064
+ * });
1065
+ * ```
1066
+ *
1067
+ * @public
1068
+ */
1069
+ export declare const Physics2DErrorCode: {
1070
+ /** Both `physics()` and `physics2d()` are registered on one world (`11-2d-toolkit.md` §8). */
1071
+ readonly bothPhysicsExtensions: "IGX-1101";
1072
+ /** The Rapier WebAssembly module could not be instantiated. */
1073
+ readonly rapierUnavailable: "IGX-1150";
1074
+ /** An entity with 2D colliders but no `Rigidbody2D` moved after its static body was placed. */
1075
+ readonly movedStaticBody: "IGX-1151";
1076
+ /** A collider's layer index is outside the sixteen Rapier's interaction groups can express. */
1077
+ readonly layerOutOfRange: "IGX-1152";
1078
+ /** A query ran before the first completed fixed step, so Rapier has no broadphase yet. */
1079
+ readonly queryBeforeStep: "IGX-1153";
1080
+ /** A `.physicsmaterial.json` file is not an `ignifx.physicsmaterial` document this build reads. */
1081
+ readonly invalidMaterialFile: "IGX-1154";
1082
+ /** The `physics2d.collisionMatrix` setting names a layer the project does not declare. */
1083
+ readonly unknownLayer: "IGX-1155";
1084
+ /** A collider's geometry is degenerate: too few points, or a hull Rapier refused to build. */
1085
+ readonly colliderGeometryInvalid: "IGX-1156";
1086
+ /** A 2D body was built for an entity that has a parent, whose pose is not world space. */
1087
+ readonly bodyOnChildEntity: "IGX-1157";
1088
+ };
1089
+ /**
1090
+ * The union of the codes the `Physics2DErrorCode` table declares.
1091
+ *
1092
+ * @public
1093
+ */
1094
+ export type Physics2DErrorCode = (typeof Physics2DErrorCode)[keyof typeof Physics2DErrorCode];
1095
+ /**
1096
+ * The one-line message template of every code, as `ExtensionContext.registerErrorCodes` wants it.
1097
+ *
1098
+ * @public
1099
+ */
1100
+ export declare const PHYSICS_2D_ERROR_MESSAGES: Readonly<Record<string, string>>;
1101
+ /**
1102
+ * Options accepted by {@link physics2DError}.
1103
+ *
1104
+ * @public
1105
+ */
1106
+ interface Physics2DErrorOptions {
1107
+ /** Identifiers that locate the failure. */
1108
+ readonly context?: ErrorContext;
1109
+ /** One sentence telling the developer what to do about it. */
1110
+ readonly hint?: string;
1111
+ /** The failure being wrapped, when there is one. */
1112
+ readonly cause?: unknown;
1113
+ }
1114
+ /**
1115
+ * Builds an `IgnifxError` carrying one of this package's codes.
1116
+ *
1117
+ * @param code - The code from the `Physics2DErrorCode` table.
1118
+ * @param message - The actionable development sentence.
1119
+ * @param options - Context identifiers, a remedy hint, and the wrapped cause.
1120
+ * @returns The error to throw or to reject with.
1121
+ *
1122
+ * @example
1123
+ * ```ts
1124
+ * throw physics2DError(Physics2DErrorCode.unknownLayer, "physics2d.collisionMatrix names Enemy.", {
1125
+ * context: { layer: "Enemy" },
1126
+ * });
1127
+ * ```
1128
+ *
1129
+ * @public
1130
+ */
1131
+ export declare function physics2DError(code: Physics2DErrorCode, message: string, options?: Physics2DErrorOptions): IgnifxError;
1132
+ //#endregion
1133
+ //#region src/queries.d.ts
1134
+ /**
1135
+ * The query vocabulary of `app.physics2d` (`docs/architecture/11-2d-toolkit.md` §8,
1136
+ * `09-physics.md` §5).
1137
+ *
1138
+ * Unlike the 3D service, every 2D query is **shape-accurate and identity-carrying**: Rapier's
1139
+ * `castRayAndGetNormal`, `intersectionsWithShape`, and `castShape` all return the `Collider` that
1140
+ * was hit (`pipeline/world.d.ts`), so no bounds index is needed and the corrections `09-physics.md`
1141
+ * §5 records for 3D do not apply here.
1142
+ */
1143
+ /**
1144
+ * Options every 2D query accepts.
1145
+ *
1146
+ * @public
1147
+ */
1148
+ interface QueryOptions2D {
1149
+ /** Which layers the query may hit. Defaults to everything. */
1150
+ readonly layerMask?: LayerMask;
1151
+ /** Whether trigger volumes count as hits. Defaults to `false`. */
1152
+ readonly hitTriggers?: boolean;
1153
+ }
1154
+ /**
1155
+ * What a 2D ray or shape query hit.
1156
+ *
1157
+ * @remarks
1158
+ * The object is freshly allocated per hit, so it is safe to keep. `raycastAll` returns a **reused**
1159
+ * array of freshly allocated hits.
1160
+ *
1161
+ * @public
1162
+ */
1163
+ interface RaycastHit2D {
1164
+ /** The entity that was hit. */
1165
+ readonly entity: Entity;
1166
+ /** The collider that was hit. */
1167
+ readonly collider: Collider2D | null;
1168
+ /** The world-space contact point, in metres. */
1169
+ readonly point: Vec2Like;
1170
+ /** The world-space surface normal. */
1171
+ readonly normal: Vec2Like;
1172
+ /** The distance from the ray origin, in metres. */
1173
+ readonly distance: number;
1174
+ }
1175
+ /**
1176
+ * What a 2D shape sweep hit.
1177
+ *
1178
+ * @public
1179
+ */
1180
+ interface ShapeCastHit2D {
1181
+ /** The entity the swept shape hit. */
1182
+ readonly entity: Entity;
1183
+ /** The collider it hit. */
1184
+ readonly collider: Collider2D | null;
1185
+ /** The world-space contact point on the hit collider. */
1186
+ readonly point: Vec2Like;
1187
+ /** The world-space contact normal. */
1188
+ readonly normal: Vec2Like;
1189
+ /** The distance travelled before contact, in metres. */
1190
+ readonly distance: number;
1191
+ /** How far along the sweep the contact occurs, in `[0, 1]`. */
1192
+ readonly fraction: number;
1193
+ }
1194
+ //#endregion
1195
+ //#region src/runtime/body-record.d.ts
1196
+ /**
1197
+ * One entity's 2D physics representation. The runtime keeps these in creation order, which is the
1198
+ * iteration order every per-step loop uses — body creation order is what decides Rapier's internal
1199
+ * ordering, so keeping it stable is part of determinism (`docs/architecture/09-physics.md` §8).
1200
+ *
1201
+ * @internal
1202
+ */
1203
+ interface BodyRecord2D {
1204
+ /** The entity the body belongs to. */
1205
+ readonly entity: Entity;
1206
+ /** The `Rigidbody2D`, or `null` for an implicit static body or a bare controller. */
1207
+ rigidbody: Rigidbody2D | null;
1208
+ /** The `CharacterController2D`, or `null`. */
1209
+ controller: CharacterController2D | null;
1210
+ /** The Rapier body. */
1211
+ body: RapierBody;
1212
+ /** Every Rapier collider the record owns, in creation order. */
1213
+ colliders: RapierCollider[];
1214
+ /** The ignifx collider each Rapier collider came from; `null` for the controller's own shape. */
1215
+ owners: (Collider2D | null)[];
1216
+ /** The controller's own collider, which is what `computeColliderMovement` moves. */
1217
+ controllerCollider: RapierCollider | null;
1218
+ /** How the body moves. */
1219
+ motion: BodyMotion2D;
1220
+ /** Whether the display pose is interpolated between fixed steps. */
1221
+ interpolate: boolean;
1222
+ /** The layer the filter word was built from, so a runtime change is noticed. */
1223
+ layer: number;
1224
+ /** Whether the record's colliders currently raise events. */
1225
+ collisionEvents: boolean;
1226
+ /** The position at the end of the previous fixed step. */
1227
+ readonly previousPosition: Vec2;
1228
+ /** The rotation in radians at the end of the previous fixed step. */
1229
+ previousRotation: number;
1230
+ /** The authoritative position at the end of the last fixed step. */
1231
+ readonly currentPosition: Vec2;
1232
+ /** The authoritative rotation in radians at the end of the last fixed step. */
1233
+ currentRotation: number;
1234
+ /**
1235
+ * The linear velocity as it was *before* the last step's solver ran, which is the impact speed a
1236
+ * collision callback wants — reading it afterwards reports the resolved velocity, which for a
1237
+ * landing body is zero.
1238
+ */
1239
+ readonly preStepVelocity: Vec2;
1240
+ /** `Transform.worldMatrixVersion` when an implicit static body was placed (`IGX-1151`). */
1241
+ staticVersion: number;
1242
+ /** Whether the `IGX-1151` diagnostic has already been reported for this body. */
1243
+ reportedMove: boolean;
1244
+ /** Signal connections the record owns, dropped when it is torn down. */
1245
+ disconnects: Disconnect[];
1246
+ }
1247
+ //#endregion
1248
+ //#region src/runtime/runtime.d.ts
1249
+ /**
1250
+ * The per-app 2D physics runtime: the Rapier world, the bodies, the character controllers, the
1251
+ * event drain, and the three things the systems ask it to do each frame — restore, step,
1252
+ * interpolate (`docs/architecture/11-2d-toolkit.md` §8, `09-physics.md` §1).
1253
+ *
1254
+ * Everything here is `@internal`; the public surface is `Physics2DService`, `Rigidbody2D`, the 2D
1255
+ * colliders, and `CharacterController2D`.
1256
+ */
1257
+ /** What the extension hands the runtime. */
1258
+ interface Physics2DRuntimeOptions {
1259
+ /** The extension registration surface; the physics kernel hooks live on it. */
1260
+ readonly ctx: ExtensionContext;
1261
+ /** The resolved `physics2d` settings section. */
1262
+ readonly settings: Physics2DSettings;
1263
+ /** The Rapier world. */
1264
+ readonly world: RapierWorld;
1265
+ /** The `physics2d` diagnostics group. */
1266
+ readonly counters: DiagnosticsGroup;
1267
+ }
1268
+ /**
1269
+ * The counters `09-physics.md` §9 and `11-2d-toolkit.md` §8 name for 2D.
1270
+ *
1271
+ * @public
1272
+ */
1273
+ export declare const PHYSICS_2D_DIAGNOSTICS_COUNTERS: readonly string[];
1274
+ /**
1275
+ * The diagnostics group name.
1276
+ *
1277
+ * @public
1278
+ */
1279
+ export declare const PHYSICS_2D_DIAGNOSTICS_GROUP = "physics2d";
1280
+ /** Which ignifx collider a Rapier collider belongs to. */
1281
+ interface ColliderBinding {
1282
+ /** The record that owns it. */
1283
+ readonly record: BodyRecord2D;
1284
+ /** The authored collider, or `null` for a character controller's own shape. */
1285
+ readonly owner: Collider2D | null;
1286
+ /** The Rapier collider itself, which the event and contact paths need. */
1287
+ readonly collider: RapierCollider;
1288
+ }
1289
+ /**
1290
+ * The per-app 2D physics runtime.
1291
+ *
1292
+ * @internal
1293
+ */
1294
+ declare class Physics2DRuntime {
1295
+ #private;
1296
+ /**
1297
+ * Builds the runtime and applies the world settings.
1298
+ *
1299
+ * @param options - The context, settings, world, and counters.
1300
+ * @throws IgnifxError with code `IGX-1155` when the collision matrix names an unknown layer.
1301
+ */
1302
+ constructor(options: Physics2DRuntimeOptions);
1303
+ /**
1304
+ * The Rapier world, for the query and escape-hatch paths.
1305
+ *
1306
+ * @returns The world handle.
1307
+ */
1308
+ get world(): RapierWorld;
1309
+ /**
1310
+ * Whether at least one fixed step has run, which is what Rapier's broadphase needs before a query
1311
+ * can answer (`09-physics.md` §5, spike S6.2).
1312
+ *
1313
+ * @returns `true` once a step has completed.
1314
+ */
1315
+ get hasStepped(): boolean;
1316
+ /**
1317
+ * Every body, in creation order.
1318
+ *
1319
+ * @returns The records.
1320
+ */
1321
+ get records(): readonly BodyRecord2D[];
1322
+ /**
1323
+ * The resolved settings.
1324
+ *
1325
+ * @returns The `physics2d` section.
1326
+ */
1327
+ get settings(): Physics2DSettings;
1328
+ /**
1329
+ * Replaces world gravity.
1330
+ *
1331
+ * @param gravity - The new acceleration vector.
1332
+ */
1333
+ setGravity(gravity: Vec2Like): void;
1334
+ /**
1335
+ * Marks an entity's body for a rebuild at the start of the next fixed step.
1336
+ *
1337
+ * @param entity - The entity whose colliders, `Rigidbody2D`, or controller changed.
1338
+ */
1339
+ markDirty(entity: Entity): void;
1340
+ /**
1341
+ * Marks a character controller's entity for a rebuild.
1342
+ *
1343
+ * @param component - The controller component.
1344
+ */
1345
+ markControllerDirty(component: CharacterController2D): void;
1346
+ /**
1347
+ * Drops a character controller's body, which is what detaching the component does.
1348
+ *
1349
+ * @param component - The controller component.
1350
+ */
1351
+ releaseController(component: CharacterController2D): void;
1352
+ /**
1353
+ * The Rapier body of an entity, for the escape hatch.
1354
+ *
1355
+ * @param entity - The entity.
1356
+ * @returns The body handle, or `null`.
1357
+ */
1358
+ bodyHandleOf(entity: Entity): BodyRecord2D["body"] | null;
1359
+ /**
1360
+ * The record an entity owns.
1361
+ *
1362
+ * @param entity - The entity.
1363
+ * @returns The record, or `null`.
1364
+ */
1365
+ recordOf(entity: Entity): BodyRecord2D | null;
1366
+ /**
1367
+ * The entity and collider a Rapier collider belongs to, which is how a query result or an event
1368
+ * becomes an ignifx object.
1369
+ *
1370
+ * @param collider - The Rapier collider, or `null`.
1371
+ * @returns The binding, or `null`.
1372
+ */
1373
+ bindingOf(collider: RapierCollider | null): ColliderBinding | null;
1374
+ /**
1375
+ * The mass Rapier computed for an entity's body.
1376
+ *
1377
+ * @param entity - The entity.
1378
+ * @returns Kilograms, or `0` when there is no body.
1379
+ */
1380
+ massOf(entity: Entity): number;
1381
+ /**
1382
+ * Reads a body's linear velocity.
1383
+ *
1384
+ * @param entity - The entity.
1385
+ * @param out - The vector to write; left untouched when there is no body.
1386
+ */
1387
+ readLinear(entity: Entity, out: MutableVec2): void;
1388
+ /**
1389
+ * Reads a body's angular velocity.
1390
+ *
1391
+ * @param entity - The entity.
1392
+ * @returns Degrees per second, counter-clockwise.
1393
+ */
1394
+ readAngular(entity: Entity): number;
1395
+ /**
1396
+ * Sets a body's linear velocity.
1397
+ *
1398
+ * @param entity - The entity.
1399
+ * @param velocity - Metres per second.
1400
+ */
1401
+ setLinearVelocity(entity: Entity, velocity: Vec2Like): void;
1402
+ /**
1403
+ * Sets a body's angular velocity.
1404
+ *
1405
+ * @param entity - The entity.
1406
+ * @param velocity - Degrees per second.
1407
+ */
1408
+ setAngularVelocity(entity: Entity, velocity: number): void;
1409
+ /**
1410
+ * Applies a force for one fixed step.
1411
+ *
1412
+ * @param entity - The entity.
1413
+ * @param force - Newtons.
1414
+ * @param point - The application point, or `null` for the centre of mass.
1415
+ */
1416
+ addForce(entity: Entity, force: Vec2Like, point: Vec2Like | null): void;
1417
+ /**
1418
+ * Applies an impulse.
1419
+ *
1420
+ * @param entity - The entity.
1421
+ * @param impulse - Newton-seconds.
1422
+ * @param point - The application point, or `null` for the centre of mass.
1423
+ */
1424
+ addImpulse(entity: Entity, impulse: Vec2Like, point: Vec2Like | null): void;
1425
+ /**
1426
+ * Applies a torque for one fixed step.
1427
+ *
1428
+ * @param entity - The entity.
1429
+ * @param torque - Newton-metres, positive counter-clockwise.
1430
+ */
1431
+ addTorque(entity: Entity, torque: number): void;
1432
+ /**
1433
+ * Teleports a body and resets its interpolation history.
1434
+ *
1435
+ * @param entity - The entity.
1436
+ * @param position - The new world position.
1437
+ * @param rotationDegrees - The new rotation in degrees counter-clockwise.
1438
+ */
1439
+ teleport(entity: Entity, position: Vec2Like, rotationDegrees: number): void;
1440
+ /**
1441
+ * Teleports a character controller.
1442
+ *
1443
+ * @param component - The controller component.
1444
+ * @param position - The new world position.
1445
+ */
1446
+ teleportController(component: CharacterController2D, position: Vec2Like): void;
1447
+ /**
1448
+ * Restores the authoritative pose of every interpolated body, undoing the display pose the
1449
+ * `PreRender` system wrote (`09-physics.md` §1).
1450
+ */
1451
+ restorePoses(): void;
1452
+ /**
1453
+ * Runs one fixed step: reconcile, push kinematic poses, move controllers, step Rapier, snapshot,
1454
+ * dispatch events.
1455
+ *
1456
+ * @param fixedDeltaSeconds - The fixed step in seconds.
1457
+ */
1458
+ step(fixedDeltaSeconds: number): void;
1459
+ /**
1460
+ * Writes the interpolated display pose of every interpolated body.
1461
+ *
1462
+ * @param alpha - `time.fixedStepAlpha`, in `[0, 1)`.
1463
+ */
1464
+ interpolate(alpha: number): void;
1465
+ /** Tears every body down and releases the Rapier world. */
1466
+ dispose(): void;
1467
+ }
1468
+ //#endregion
1469
+ //#region src/runtime/host.d.ts
1470
+ /**
1471
+ * The one mutable cell between `register` and `onStart`.
1472
+ *
1473
+ * `Extension.register` runs **before** `createApp` builds the world
1474
+ * (`packages/core/src/app/app.ts`, `initialize`), and the Rapier world needs the world's layer
1475
+ * table and Rapier's WebAssembly module, which is loaded asynchronously. So the extension declares
1476
+ * its systems and its service in `register` — which is where `docs/architecture/04-extensions.md`
1477
+ * §1 says everything is declared — and they all read the runtime through this holder, which
1478
+ * `onStart` fills in.
1479
+ *
1480
+ * @internal
1481
+ */
1482
+ declare class Physics2DHost {
1483
+ /** The runtime, or `null` until `onStart` has built it. */
1484
+ runtime: Physics2DRuntime | null;
1485
+ }
1486
+ //#endregion
1487
+ //#region src/service.d.ts
1488
+ /**
1489
+ * The Rapier objects the 2D physics extension owns. Unstable escape hatch
1490
+ * (`docs/architecture/00-overview.md` §3).
1491
+ *
1492
+ * @public
1493
+ */
1494
+ interface Physics2DRapierHandles {
1495
+ /** Rapier's `World`. */
1496
+ readonly world: RapierWorld;
1497
+ }
1498
+ /**
1499
+ * The service behind `app.physics2d`.
1500
+ *
1501
+ * @example
1502
+ * ```ts
1503
+ * const hit = app.physics2d.raycast({ x: 0, y: 5 }, { x: 0, y: -1 }, 20);
1504
+ * if (hit !== null) {
1505
+ * app.log.info(`ray hit ${hit.entity.name} at ${String(hit.point.y)}`);
1506
+ * }
1507
+ * ```
1508
+ *
1509
+ * @public
1510
+ */
1511
+ export declare class Physics2DService {
1512
+ #private;
1513
+ /**
1514
+ * Wraps the holder the extension fills in from `onStart`.
1515
+ *
1516
+ * @param host - The holder the runtime lands in.
1517
+ * @param settings - The resolved `physics2d` settings section.
1518
+ *
1519
+ * @internal
1520
+ */
1521
+ constructor(host: Physics2DHost, settings: Physics2DSettings);
1522
+ /**
1523
+ * World gravity in metres per second squared.
1524
+ *
1525
+ * @returns A live view; writing to it does nothing, assign the property instead.
1526
+ */
1527
+ get gravity(): Vec2;
1528
+ /**
1529
+ * Replaces world gravity, which every body feels from the next fixed step.
1530
+ *
1531
+ * @param value - The new acceleration vector.
1532
+ */
1533
+ set gravity(value: Vec2Like);
1534
+ /**
1535
+ * The Rapier handles.
1536
+ *
1537
+ * @returns The world.
1538
+ */
1539
+ get rapier(): Physics2DRapierHandles;
1540
+ /**
1541
+ * Casts a ray and returns the first entity it hits.
1542
+ *
1543
+ * @param origin - The world-space origin, in metres.
1544
+ * @param direction - The direction; it is normalised for you.
1545
+ * @param maxDistance - How far to travel; defaults to 10 km.
1546
+ * @param options - Layer mask and trigger behaviour.
1547
+ * @returns The hit, or `null` when the ray clears everything.
1548
+ * @throws IgnifxError with code `IGX-1153` when no fixed step has run yet.
1549
+ */
1550
+ raycast(origin: Vec2Like, direction: Vec2Like, maxDistance?: number, options?: QueryOptions2D): RaycastHit2D | null;
1551
+ /**
1552
+ * Casts a ray and returns every entity along it, nearest first.
1553
+ *
1554
+ * @param origin - The world-space origin.
1555
+ * @param direction - The direction; it is normalised for you.
1556
+ * @param maxDistance - How far to travel; defaults to 10 km.
1557
+ * @param options - Layer mask and trigger behaviour.
1558
+ * @returns The hits, in increasing distance. The array is reused between calls.
1559
+ * @throws IgnifxError with code `IGX-1153` when no fixed step has run yet.
1560
+ */
1561
+ raycastAll(origin: Vec2Like, direction: Vec2Like, maxDistance?: number, options?: QueryOptions2D): readonly RaycastHit2D[];
1562
+ /**
1563
+ * Lists the entities a circle overlaps.
1564
+ *
1565
+ * @param centre - The circle's world position.
1566
+ * @param radius - Its radius in metres.
1567
+ * @param options - Layer mask and trigger behaviour.
1568
+ * @returns The overlapping entities, in Rapier's order. The array is reused between calls.
1569
+ * @throws IgnifxError with code `IGX-1153` when no fixed step has run yet.
1570
+ */
1571
+ overlapCircle(centre: Vec2Like, radius: number, options?: QueryOptions2D): readonly Entity[];
1572
+ /**
1573
+ * Lists the entities a box overlaps.
1574
+ *
1575
+ * @param centre - The box's world position.
1576
+ * @param size - Its full width and height in metres.
1577
+ * @param rotation - Its rotation in degrees counter-clockwise; defaults to `0`.
1578
+ * @param options - Layer mask and trigger behaviour.
1579
+ * @returns The overlapping entities. The array is reused between calls.
1580
+ * @throws IgnifxError with code `IGX-1153` when no fixed step has run yet.
1581
+ */
1582
+ overlapBox(centre: Vec2Like, size: Vec2Like, rotation?: number, options?: QueryOptions2D): readonly Entity[];
1583
+ /**
1584
+ * Sweeps a circle and returns the first contact.
1585
+ *
1586
+ * @param centre - Where the sweep starts.
1587
+ * @param radius - The circle's radius in metres.
1588
+ * @param direction - The sweep direction; it is normalised for you.
1589
+ * @param maxDistance - How far to sweep.
1590
+ * @param options - Layer mask and trigger behaviour.
1591
+ * @returns The hit, or `null`.
1592
+ * @throws IgnifxError with code `IGX-1153` when no fixed step has run yet.
1593
+ */
1594
+ shapeCast(centre: Vec2Like, radius: number, direction: Vec2Like, maxDistance: number, options?: QueryOptions2D): ShapeCastHit2D | null;
1595
+ }
1596
+ //#endregion
1597
+ //#region src/extension.d.ts
1598
+ /**
1599
+ * The `@ignifx/physics-2d` extension (`docs/architecture/11-2d-toolkit.md` §8,
1600
+ * `04-extensions.md` §1).
1601
+ *
1602
+ * ## Why `@ignifx/2d` is optional rather than required
1603
+ *
1604
+ * `00-overview.md` §2 draws `@ignifx/physics-2d` above `@ignifx/2d`, and the layering rule allows
1605
+ * the dependency. At runtime the only thing this package needs from the toolkit is the
1606
+ * `TilemapCollisionData` **type**, which is erased at build time, so a platformer that draws its own
1607
+ * graphics can register `physics2d()` on its own. The manifest therefore declares
1608
+ * `requires: []` and `optional: ["@ignifx/2d"]`, and `package.json` makes `@ignifx/2d` an optional
1609
+ * peer dependency.
1610
+ *
1611
+ * ## Why the world is built in `onStart`
1612
+ *
1613
+ * `register` runs before `createApp` builds the `World` (`packages/core/src/app/app.ts`,
1614
+ * `initialize`), and the Rapier world needs the world's layer table; Rapier's WebAssembly module
1615
+ * also has to be instantiated, which is asynchronous. So `register` declares everything against a
1616
+ * {@link Physics2DHost} holder and `onStart` fills the holder in.
1617
+ *
1618
+ * ## One physics extension per world
1619
+ *
1620
+ * `11-2d-toolkit.md` §8: "A world uses either `physics()` or `physics2d()`; registering both throws
1621
+ * `IGX-1101`". `@ignifx/physics` publishes its Havok simulation scene through
1622
+ * `ExtensionContext.setSimulationScene`, so `app.world.lite.simulationScene !== null` at `onStart`
1623
+ * is the test — and it needs no dependency on `@ignifx/physics`, which this package must not have.
1624
+ */
1625
+ /**
1626
+ * What `physics2d()` accepts.
1627
+ *
1628
+ * @public
1629
+ */
1630
+ interface Physics2DOptions {
1631
+ /**
1632
+ * Replaces the step that instantiates Rapier's WebAssembly module. The default awaits
1633
+ * `RAPIER.init()`, which decodes the base64 payload the `-compat` build inlines; a host that has
1634
+ * already preloaded the module, or a test that wants to observe the failure path, supplies its
1635
+ * own.
1636
+ */
1637
+ readonly initialize?: () => Promise<void>;
1638
+ }
1639
+ declare module "@ignifx/core" {
1640
+ interface App {
1641
+ /** 2D physics: gravity, queries, and the Rapier escape hatch. */
1642
+ readonly physics2d: Physics2DService;
1643
+ }
1644
+ }
1645
+ /**
1646
+ * Builds the 2D physics extension.
1647
+ *
1648
+ * @param options - Optionally, an already-instantiated Rapier module.
1649
+ * @returns The extension descriptor.
1650
+ *
1651
+ * @example
1652
+ * ```ts
1653
+ * const app = await createApp({ headless: true, extensions: [physics2d()] });
1654
+ * ```
1655
+ *
1656
+ * @public
1657
+ */
1658
+ export declare const physics2d: (options?: Physics2DOptions) => Extension;
1659
+ //#endregion
1660
+ //#region src/schemas.d.ts
1661
+ /**
1662
+ * The documentation harness's view of everything `@ignifx/physics-2d` declares
1663
+ * (`docs/architecture/16-docs-harness-and-skill.md` §3, `scripts/README.md`).
1664
+ *
1665
+ * The `ignifx.physicsmaterial` **file format** is deliberately absent: `@ignifx/physics` already
1666
+ * documents it and this package reads the very same document (`material.ts`), so describing it
1667
+ * twice would render the same table on the formats page twice — the harness keeps the first
1668
+ * declaration and drops the rest (`scripts/lib/schema-source.ts`).
1669
+ */
1670
+ /**
1671
+ * Describes every component this package declares.
1672
+ *
1673
+ * @returns The records, keyed by namespaced type id.
1674
+ *
1675
+ * @example
1676
+ * ```ts
1677
+ * const schemas = describeSchemas();
1678
+ * schemas["ignifx/Rigidbody2D"].fields["mass"].default; // 1
1679
+ * ```
1680
+ *
1681
+ * @public
1682
+ */
1683
+ export declare function describeSchemas(): Readonly<Record<string, SchemaDescription>>;
1684
+ //#endregion
1685
+ export type { BodyType2D, CapsuleDirection2D, CharacterCollision2D, CharacterShape2D, Collision2D, CollisionEventMode2D, CombineRule, ContactPoint2D, InterpolationMode2D, Physics2DErrorOptions, Physics2DMaterialValues, Physics2DOptions, Physics2DRapierHandles, Physics2DSettings, QueryOptions2D, RaycastHit2D, Rigidbody2DRapierHandles, ShapeCastHit2D, TriggerEvent2D };
1686
+ //# sourceMappingURL=index.d.ts.map