@woosh/meep-engine 2.142.0 → 2.144.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/package.json +1 -1
  2. package/src/core/geom/3d/shape/CapsuleShape3D.d.ts +1 -1
  3. package/src/core/geom/3d/shape/CapsuleShape3D.js +1 -1
  4. package/src/core/geom/3d/shape/PointShape3D.d.ts +1 -0
  5. package/src/core/geom/3d/shape/PointShape3D.d.ts.map +1 -1
  6. package/src/core/geom/3d/shape/PointShape3D.js +11 -0
  7. package/src/core/geom/3d/shape/SphereShape3D.d.ts +48 -0
  8. package/src/core/geom/3d/shape/SphereShape3D.d.ts.map +1 -0
  9. package/src/core/geom/3d/shape/SphereShape3D.js +131 -0
  10. package/src/core/geom/3d/shape/UnitSphereShape3D.d.ts +30 -18
  11. package/src/core/geom/3d/shape/UnitSphereShape3D.d.ts.map +1 -1
  12. package/src/core/geom/3d/shape/UnitSphereShape3D.js +44 -92
  13. package/src/core/geom/3d/shape/json/shape_to_type.d.ts.map +1 -1
  14. package/src/core/geom/3d/shape/json/shape_to_type.js +4 -2
  15. package/src/core/geom/3d/shape/json/type_adapters.d.ts +12 -3
  16. package/src/core/geom/3d/shape/json/type_adapters.d.ts.map +1 -1
  17. package/src/core/geom/3d/shape/json/type_adapters.js +16 -4
  18. package/src/core/geom/3d/shape/util/shape_to_visual_entity.js +2 -2
  19. package/src/engine/control/first-person/DESIGN_COLLISION.md +302 -0
  20. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts +91 -58
  21. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
  22. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +1814 -1789
  23. package/src/engine/control/first-person/TODO.md +17 -32
  24. package/src/engine/control/first-person/collision/KinematicMover.d.ts +176 -0
  25. package/src/engine/control/first-person/collision/KinematicMover.d.ts.map +1 -0
  26. package/src/engine/control/first-person/collision/KinematicMover.js +424 -0
  27. package/src/engine/control/first-person/prototype_first_person_controller.js +65 -0
  28. package/src/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.d.ts.map +1 -1
  29. package/src/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js +3 -1
  30. package/src/engine/graphics/render/buffer/simple-fx/ao/SAOShader.js +30 -16
  31. package/src/engine/physics/PLAN.md +94 -32
  32. package/src/engine/physics/contact/ManifoldStore.d.ts +28 -2
  33. package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
  34. package/src/engine/physics/contact/ManifoldStore.js +37 -3
  35. package/src/engine/physics/contact/combine_material.d.ts +30 -0
  36. package/src/engine/physics/contact/combine_material.d.ts.map +1 -0
  37. package/src/engine/physics/contact/combine_material.js +35 -0
  38. package/src/engine/physics/ecs/Collider.d.ts +15 -0
  39. package/src/engine/physics/ecs/Collider.d.ts.map +1 -1
  40. package/src/engine/physics/ecs/Collider.js +34 -0
  41. package/src/engine/physics/ecs/Joint.d.ts +18 -0
  42. package/src/engine/physics/ecs/Joint.d.ts.map +1 -1
  43. package/src/engine/physics/ecs/Joint.js +70 -0
  44. package/src/engine/physics/ecs/JointSerializationAdapter.d.ts +29 -0
  45. package/src/engine/physics/ecs/JointSerializationAdapter.d.ts.map +1 -0
  46. package/src/engine/physics/ecs/JointSerializationAdapter.js +72 -0
  47. package/src/engine/physics/ecs/PhysicsSystem.d.ts +9 -4
  48. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  49. package/src/engine/physics/ecs/PhysicsSystem.js +9 -4
  50. package/src/engine/physics/ecs/RigidBody.d.ts +15 -0
  51. package/src/engine/physics/ecs/RigidBody.d.ts.map +1 -1
  52. package/src/engine/physics/ecs/RigidBody.js +46 -0
  53. package/src/engine/physics/narrowphase/compute_penetration.d.ts +41 -41
  54. package/src/engine/physics/narrowphase/compute_penetration.d.ts.map +1 -1
  55. package/src/engine/physics/narrowphase/compute_penetration.js +96 -169
  56. package/src/engine/physics/narrowphase/narrowphase_step.d.ts +52 -0
  57. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
  58. package/src/engine/physics/narrowphase/narrowphase_step.js +150 -16
  59. package/src/engine/physics/narrowphase/refine_ray_hit.js +2 -2
  60. package/src/engine/physics/narrowphase/sphere_sphere_contact.d.ts +8 -7
  61. package/src/engine/physics/narrowphase/sphere_sphere_contact.d.ts.map +1 -1
  62. package/src/engine/physics/narrowphase/sphere_sphere_contact.js +8 -7
  63. package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
  64. package/src/engine/physics/solver/solve_contacts.js +10 -21
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "description": "Pure JavaScript game engine. Fully featured and production ready.",
7
7
  "type": "module",
8
8
  "author": "Alexander Goldring",
9
- "version": "2.142.0",
9
+ "version": "2.144.0",
10
10
  "main": "build/meep.module.js",
11
11
  "module": "build/meep.module.js",
12
12
  "exports": {
@@ -33,7 +33,7 @@ export class CapsuleShape3D extends AbstractShape3D {
33
33
  */
34
34
  equals(other: CapsuleShape3D): boolean;
35
35
  /**
36
- * Fast type-check marker, mirroring `UnitSphereShape3D.prototype.isUnitSphereShape3D`
36
+ * Fast type-check marker, mirroring `SphereShape3D.prototype.isSphereShape3D`
37
37
  * and `BoxShape3D.prototype.isBoxShape3D`. Lets the physics narrowphase
38
38
  * dispatch capsule-sphere / capsule-capsule / capsule-box pairs to
39
39
  * closed-form helpers (capsule = Minkowski sum of segment + sphere; all
@@ -210,7 +210,7 @@ export class CapsuleShape3D extends AbstractShape3D {
210
210
  }
211
211
 
212
212
  /**
213
- * Fast type-check marker, mirroring `UnitSphereShape3D.prototype.isUnitSphereShape3D`
213
+ * Fast type-check marker, mirroring `SphereShape3D.prototype.isSphereShape3D`
214
214
  * and `BoxShape3D.prototype.isBoxShape3D`. Lets the physics narrowphase
215
215
  * dispatch capsule-sphere / capsule-capsule / capsule-box pairs to
216
216
  * closed-form helpers (capsule = Minkowski sum of segment + sphere; all
@@ -9,6 +9,7 @@ export class PointShape3D extends AbstractShape3D {
9
9
  nearest_point_on_surface(result: any, reference: any): void;
10
10
  sample_random_point_in_volume(result: any, result_offset: any, random: any): void;
11
11
  support(result: any, result_offset: any, direction_x: any, direction_y: any, direction_z: any): void;
12
+ equals(other: any): boolean;
12
13
  }
13
14
  import { AbstractShape3D } from "./AbstractShape3D.js";
14
15
  //# sourceMappingURL=PointShape3D.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PointShape3D.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/shape/PointShape3D.js"],"names":[],"mappings":"AAGA;;GAEG;AACH;IA4CI,8BAAqC;IAnCrC,wCAOC;IAED,6CAEC;IAED,oCAEC;IAED,4DAIC;IAED,kFAIC;IAED,qGAIC;CAGJ;gCAlD+B,sBAAsB"}
1
+ {"version":3,"file":"PointShape3D.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/shape/PointShape3D.js"],"names":[],"mappings":"AAGA;;GAEG;AACH;IAuDI,8BAAqC;IA9CrC,wCAOC;IAED,6CAEC;IAED,oCAEC;IAED,4DAIC;IAED,kFAIC;IAED,qGAIC;IAED,4BAGC;CASJ;gCA7D+B,sBAAsB"}
@@ -48,5 +48,16 @@ export class PointShape3D extends AbstractShape3D {
48
48
  result[result_offset + 2] = 0;
49
49
  }
50
50
 
51
+ equals(other) {
52
+ // Parameterless: identity is the type alone (a point has no fields).
53
+ return super.equals(other);
54
+ }
55
+
56
+ hash() {
57
+ // Constant — every PointShape3D is identical. Distinct from the
58
+ // base-class 0 so it doesn't collide with a hypothetical default shape.
59
+ return 0x504f494e; // "POIN"
60
+ }
61
+
51
62
  static INSTANCE = new PointShape3D();
52
63
  }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Sphere of arbitrary `radius`, centred at the body's local origin.
3
+ *
4
+ * Mirrors the {@link BoxShape3D} (arbitrary half-extents) ↔
5
+ * {@link UnitCubeShape3D} (fixed 0.5) relationship: this is the general
6
+ * parametrised sphere, and {@link UnitSphereShape3D} is the `radius = 1`
7
+ * special case kept for the JSON `'sphere'` tag and the shared `INSTANCE`
8
+ * singleton.
9
+ *
10
+ * The physics narrowphase recognises spheres via the shared `isSphereShape3D`
11
+ * prototype marker and reads `radius`.
12
+ *
13
+ * @author Alex Goldring
14
+ * @copyright Company Named Limited (c) 2026
15
+ */
16
+ export class SphereShape3D extends AbstractShape3D {
17
+ /**
18
+ * Convenience constructor.
19
+ * @param {number} radius
20
+ * @returns {SphereShape3D}
21
+ */
22
+ static from(radius: number): SphereShape3D;
23
+ /**
24
+ * Sphere radius, in the body's local frame.
25
+ * @type {number}
26
+ */
27
+ radius: number;
28
+ support(result: any, result_offset: any, direction_x: any, direction_y: any, direction_z: any): void;
29
+ compute_bounding_box(result: any): void;
30
+ nearest_point_on_surface(result: any, reference: any): void;
31
+ signed_distance_gradient_at_point(result: any, point: any): number;
32
+ signed_distance_at_point(point: any): number;
33
+ contains_point(point: any): boolean;
34
+ sample_random_point_in_volume(result: any, result_offset: any, random: any): void;
35
+ equals(other: any): boolean;
36
+ /**
37
+ * Fast type-check marker. Lets the physics narrowphase short-circuit
38
+ * sphere-involved pairs to closed-form solvers (reading `radius`) rather than
39
+ * running GJK + EPA on a smooth surface (the EPA-degenerate case). `true` for
40
+ * both {@link SphereShape3D} and {@link UnitSphereShape3D} (via the prototype
41
+ * chain).
42
+ * @readonly
43
+ * @type {boolean}
44
+ */
45
+ readonly isSphereShape3D: boolean;
46
+ }
47
+ import { AbstractShape3D } from "./AbstractShape3D.js";
48
+ //# sourceMappingURL=SphereShape3D.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SphereShape3D.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/shape/SphereShape3D.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;GAcG;AACH;IAUI;;;;OAIG;IACH,oBAHW,MAAM,GACJ,aAAa,CAMzB;IAhBG;;;OAGG;IACH,QAFU,MAAM,CAED;IAwBnB,qGAQC;IAED,wCAQC;IAED,4DAaC;IAED,mEAEC;IAED,6CAEC;IAED,oCAOC;IAED,kFAMC;IAED,4BAEC;IAOL;;;;;;;;OAQG;IACH,0BAFU,OAAO,CAEsB;CAXtC;gCApH+B,sBAAsB"}
@@ -0,0 +1,131 @@
1
+ import { computeHashFloat } from "../../../primitives/numbers/computeHashFloat.js";
2
+ import { randomPointInSphere } from "../../random/randomPointInSphere.js";
3
+ import { v3_length } from "../../vec3/v3_length.js";
4
+ import { AbstractShape3D } from "./AbstractShape3D.js";
5
+ import { compute_signed_distance_gradient_by_sampling } from "./util/compute_signed_distance_gradient_by_sampling.js";
6
+
7
+ /**
8
+ * Sphere of arbitrary `radius`, centred at the body's local origin.
9
+ *
10
+ * Mirrors the {@link BoxShape3D} (arbitrary half-extents) ↔
11
+ * {@link UnitCubeShape3D} (fixed 0.5) relationship: this is the general
12
+ * parametrised sphere, and {@link UnitSphereShape3D} is the `radius = 1`
13
+ * special case kept for the JSON `'sphere'` tag and the shared `INSTANCE`
14
+ * singleton.
15
+ *
16
+ * The physics narrowphase recognises spheres via the shared `isSphereShape3D`
17
+ * prototype marker and reads `radius`.
18
+ *
19
+ * @author Alex Goldring
20
+ * @copyright Company Named Limited (c) 2026
21
+ */
22
+ export class SphereShape3D extends AbstractShape3D {
23
+ constructor() {
24
+ super();
25
+ /**
26
+ * Sphere radius, in the body's local frame.
27
+ * @type {number}
28
+ */
29
+ this.radius = 1;
30
+ }
31
+
32
+ /**
33
+ * Convenience constructor.
34
+ * @param {number} radius
35
+ * @returns {SphereShape3D}
36
+ */
37
+ static from(radius) {
38
+ const s = new SphereShape3D();
39
+ s.radius = radius;
40
+ return s;
41
+ }
42
+
43
+ get volume() {
44
+ const r = this.radius;
45
+ return (4 / 3) * Math.PI * r * r * r;
46
+ }
47
+
48
+ get surface_area() {
49
+ const r = this.radius;
50
+ return 4 * Math.PI * r * r;
51
+ }
52
+
53
+ support(result, result_offset, direction_x, direction_y, direction_z) {
54
+ // Farthest point along `direction` on a sphere of this radius. Matches
55
+ // the unit-sphere convention (no normalisation — callers pass a unit
56
+ // direction); for radius r it is simply the direction scaled by r.
57
+ const r = this.radius;
58
+ result[result_offset] = direction_x * r;
59
+ result[result_offset + 1] = direction_y * r;
60
+ result[result_offset + 2] = direction_z * r;
61
+ }
62
+
63
+ compute_bounding_box(result) {
64
+ const r = this.radius;
65
+ result[0] = -r;
66
+ result[1] = -r;
67
+ result[2] = -r;
68
+ result[3] = r;
69
+ result[4] = r;
70
+ result[5] = r;
71
+ }
72
+
73
+ nearest_point_on_surface(result, reference) {
74
+ const r_x = reference[0];
75
+ const r_y = reference[1];
76
+ const r_z = reference[2];
77
+
78
+ const len = v3_length(r_x, r_y, r_z);
79
+ // At the centre the nearest surface point is undefined; return the
80
+ // centre rather than NaN/Inf.
81
+ const d = len > 0 ? this.radius / len : 0;
82
+
83
+ result[0] = r_x * d;
84
+ result[1] = r_y * d;
85
+ result[2] = r_z * d;
86
+ }
87
+
88
+ signed_distance_gradient_at_point(result, point) {
89
+ return compute_signed_distance_gradient_by_sampling(result, this, point);
90
+ }
91
+
92
+ signed_distance_at_point(point) {
93
+ return v3_length(point[0], point[1], point[2]) - this.radius;
94
+ }
95
+
96
+ contains_point(point) {
97
+ const x = point[0];
98
+ const y = point[1];
99
+ const z = point[2];
100
+ const r = this.radius;
101
+
102
+ return (x * x + y * y + z * z) < r * r;
103
+ }
104
+
105
+ sample_random_point_in_volume(result, result_offset, random) {
106
+ randomPointInSphere(random, result, result_offset);
107
+ const r = this.radius;
108
+ result[result_offset] *= r;
109
+ result[result_offset + 1] *= r;
110
+ result[result_offset + 2] *= r;
111
+ }
112
+
113
+ equals(other) {
114
+ return super.equals(other) && this.radius === other.radius;
115
+ }
116
+
117
+ hash() {
118
+ return computeHashFloat(this.radius);
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Fast type-check marker. Lets the physics narrowphase short-circuit
124
+ * sphere-involved pairs to closed-form solvers (reading `radius`) rather than
125
+ * running GJK + EPA on a smooth surface (the EPA-degenerate case). `true` for
126
+ * both {@link SphereShape3D} and {@link UnitSphereShape3D} (via the prototype
127
+ * chain).
128
+ * @readonly
129
+ * @type {boolean}
130
+ */
131
+ SphereShape3D.prototype.isSphereShape3D = true;
@@ -1,27 +1,39 @@
1
1
  /**
2
- * Sphere with diameter of 2 (radius = 1)
2
+ * Sphere with radius 1 (diameter 2), centred at the origin.
3
+ *
4
+ * @deprecated Use {@link SphereShape3D} instead — UnitSphereShape3D is now a
5
+ * thin subclass that just pins `radius` to `1`. All geometry (`support`,
6
+ * `signed_distance_at_point`, `volume`, `surface_area`,
7
+ * `nearest_point_on_surface`, ...) is inherited from {@link SphereShape3D}.
8
+ *
9
+ * Kept only for:
10
+ * - the `UnitSphereShape3D.INSTANCE` shared singleton that scenes, colliders,
11
+ * and tests embed by reference
12
+ * - the JSON `'sphere'` type-tag round-trip in `shape_to_type` /
13
+ * `type_adapters` (an `instanceof` check, which is why we still need a
14
+ * distinct subclass rather than a constant `SphereShape3D` instance)
15
+ *
16
+ * For new code prefer:
17
+ * - `new SphereShape3D()` — also defaults to `radius = 1`
18
+ * - `SphereShape3D.from(radius)` — express by radius
3
19
  */
4
- export class UnitSphereShape3D extends AbstractShape3D {
5
- support(result: any, result_offset: any, direction_x: any, direction_y: any, direction_z: any): void;
6
- compute_bounding_box(result: any): void;
7
- nearest_point_on_surface(result: any, reference: any): void;
8
- signed_distance_gradient_at_point(result: any, point: any): number;
9
- signed_distance_at_point(point: any): number;
10
- contains_point(point: any): boolean;
11
- sample_random_point_in_volume(result: any, result_offset: any, random: any): void;
20
+ export class UnitSphereShape3D extends SphereShape3D {
12
21
  /**
13
- * Fast type-check marker (mirrors {@link Transform.prototype.isTransform}). Lets
14
- * downstream code dispatch on shape kind without instanceof / import coupling.
15
- * Use case: physics narrowphase short-circuits sphere-sphere to a closed-form
16
- * solution rather than running GJK+EPA on a smooth surface (which is the EPA
17
- * degenerate case).
22
+ * Shared singleton. Many call sites JSON deserialisation, the default
23
+ * {@link Collider} shape, tests embed this by reference rather than
24
+ * allocating a fresh sphere.
25
+ * @type {UnitSphereShape3D}
26
+ */
27
+ static INSTANCE: UnitSphereShape3D;
28
+ /**
29
+ * @deprecated Prefer dispatching on `isSphereShape3D`, which is `true` for both
30
+ * UnitSphereShape3D (inherited via prototype chain) and {@link SphereShape3D}.
31
+ * Retained so any older external code that already narrowed via this marker
32
+ * keeps working.
18
33
  * @readonly
19
34
  * @type {boolean}
20
35
  */
21
36
  readonly isUnitSphereShape3D: boolean;
22
37
  }
23
- export namespace UnitSphereShape3D {
24
- let INSTANCE: UnitSphereShape3D;
25
- }
26
- import { AbstractShape3D } from "./AbstractShape3D.js";
38
+ import { SphereShape3D } from "./SphereShape3D.js";
27
39
  //# sourceMappingURL=UnitSphereShape3D.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UnitSphereShape3D.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/shape/UnitSphereShape3D.js"],"names":[],"mappings":"AAKA;;GAEG;AACH;IASI,qGAQC;IAED,wCAQC;IAED,4DAYC;IAED,mEAEC;IAED,6CAMC;IAED,oCAMC;IAED,kFAEC;IASL;;;;;;;;OAQG;IACH,8BAFU,OAAO,CAE8B;CAb9C;;;;gCA5E+B,sBAAsB"}
1
+ {"version":3,"file":"UnitSphereShape3D.d.ts","sourceRoot":"","sources":["../../../../../../src/core/geom/3d/shape/UnitSphereShape3D.js"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AACH;IAKI;;;;;OAKG;IACH,iBAFU,iBAAiB,CAEe;IAG9C;;;;;;;OAOG;IACH,8BAFU,OAAO,CAE8B;CAV9C;8BAjC6B,oBAAoB"}
@@ -1,92 +1,44 @@
1
- import { randomPointInSphere } from "../../random/randomPointInSphere.js";
2
- import { v3_length } from "../../vec3/v3_length.js";
3
- import { AbstractShape3D } from "./AbstractShape3D.js";
4
- import { compute_signed_distance_gradient_by_sampling } from "./util/compute_signed_distance_gradient_by_sampling.js";
5
-
6
- /**
7
- * Sphere with diameter of 2 (radius = 1)
8
- */
9
- export class UnitSphereShape3D extends AbstractShape3D {
10
- get volume() {
11
- return (4 / 3) * Math.PI;
12
- }
13
-
14
- get surface_area() {
15
- return Math.PI * 4;
16
- }
17
-
18
- support(result, result_offset, direction_x, direction_y, direction_z) {
19
-
20
- // since the sphere has a radius of 1, we don't have to multiply by it
21
-
22
- result[result_offset] = direction_x;
23
- result[result_offset + 1] = direction_y;
24
- result[result_offset + 2] = direction_z;
25
-
26
- }
27
-
28
- compute_bounding_box(result) {
29
- result[0] = -1;
30
- result[1] = -1;
31
- result[2] = -1;
32
-
33
- result[3] = 1;
34
- result[4] = 1;
35
- result[5] = 1;
36
- }
37
-
38
- nearest_point_on_surface(result, reference) {
39
-
40
- const r_x = reference[0];
41
- const r_y = reference[1];
42
- const r_z = reference[2];
43
-
44
- // normalize vector to 1 radius
45
- const d = 1 / v3_length(r_x, r_y, r_z);
46
-
47
- result[0] = r_x * d;
48
- result[1] = r_y * d;
49
- result[2] = r_z * d;
50
- }
51
-
52
- signed_distance_gradient_at_point(result, point) {
53
- return compute_signed_distance_gradient_by_sampling(result, this, point);
54
- }
55
-
56
- signed_distance_at_point(point) {
57
- return v3_length(
58
- point[0],
59
- point[1],
60
- point[2]
61
- ) - 1;
62
- }
63
-
64
- contains_point(point) {
65
- const x = point[0];
66
- const y = point[1];
67
- const z = point[2];
68
-
69
- return (x * x + y * y + z * z) < 1;
70
- }
71
-
72
- sample_random_point_in_volume(result, result_offset, random) {
73
- randomPointInSphere(random, result, result_offset);
74
- }
75
-
76
- hash() {
77
- return 13;
78
- }
79
- }
80
-
81
- UnitSphereShape3D.INSTANCE = new UnitSphereShape3D();
82
-
83
- /**
84
- * Fast type-check marker (mirrors {@link Transform.prototype.isTransform}). Lets
85
- * downstream code dispatch on shape kind without instanceof / import coupling.
86
- * Use case: physics narrowphase short-circuits sphere-sphere to a closed-form
87
- * solution rather than running GJK+EPA on a smooth surface (which is the EPA
88
- * degenerate case).
89
- * @readonly
90
- * @type {boolean}
91
- */
92
- UnitSphereShape3D.prototype.isUnitSphereShape3D = true;
1
+ import { SphereShape3D } from "./SphereShape3D.js";
2
+
3
+ /**
4
+ * Sphere with radius 1 (diameter 2), centred at the origin.
5
+ *
6
+ * @deprecated Use {@link SphereShape3D} instead — UnitSphereShape3D is now a
7
+ * thin subclass that just pins `radius` to `1`. All geometry (`support`,
8
+ * `signed_distance_at_point`, `volume`, `surface_area`,
9
+ * `nearest_point_on_surface`, ...) is inherited from {@link SphereShape3D}.
10
+ *
11
+ * Kept only for:
12
+ * - the `UnitSphereShape3D.INSTANCE` shared singleton that scenes, colliders,
13
+ * and tests embed by reference
14
+ * - the JSON `'sphere'` type-tag round-trip in `shape_to_type` /
15
+ * `type_adapters` (an `instanceof` check, which is why we still need a
16
+ * distinct subclass rather than a constant `SphereShape3D` instance)
17
+ *
18
+ * For new code prefer:
19
+ * - `new SphereShape3D()` — also defaults to `radius = 1`
20
+ * - `SphereShape3D.from(radius)` express by radius
21
+ */
22
+ export class UnitSphereShape3D extends SphereShape3D {
23
+ // No constructor / no method overrides on purpose. SphereShape3D's
24
+ // constructor already sets radius to 1, and every geometry method is
25
+ // correct for that case verbatim.
26
+
27
+ /**
28
+ * Shared singleton. Many call sites — JSON deserialisation, the default
29
+ * {@link Collider} shape, tests — embed this by reference rather than
30
+ * allocating a fresh sphere.
31
+ * @type {UnitSphereShape3D}
32
+ */
33
+ static INSTANCE = new UnitSphereShape3D();
34
+ }
35
+
36
+ /**
37
+ * @deprecated Prefer dispatching on `isSphereShape3D`, which is `true` for both
38
+ * UnitSphereShape3D (inherited via prototype chain) and {@link SphereShape3D}.
39
+ * Retained so any older external code that already narrowed via this marker
40
+ * keeps working.
41
+ * @readonly
42
+ * @type {boolean}
43
+ */
44
+ UnitSphereShape3D.prototype.isUnitSphereShape3D = true;
@@ -1 +1 @@
1
- {"version":3,"file":"shape_to_type.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/geom/3d/shape/json/shape_to_type.js"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,uDAFa,MAAM,CAgBlB"}
1
+ {"version":3,"file":"shape_to_type.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/geom/3d/shape/json/shape_to_type.js"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,uDAFa,MAAM,CAkBlB"}
@@ -1,8 +1,8 @@
1
1
  import { CapsuleShape3D } from "../CapsuleShape3D.js";
2
+ import { SphereShape3D } from "../SphereShape3D.js";
2
3
  import { TransformedShape3D } from "../TransformedShape3D.js";
3
4
  import { UnionShape3D } from "../UnionShape3D.js";
4
5
  import { UnitCubeShape3D } from "../UnitCubeShape3D.js";
5
- import { UnitSphereShape3D } from "../UnitSphereShape3D.js";
6
6
 
7
7
  /**
8
8
  *
@@ -14,7 +14,9 @@ export function shape_to_type(shape) {
14
14
  return 'union';
15
15
  } else if (shape instanceof UnitCubeShape3D) {
16
16
  return 'cube';
17
- } else if (shape instanceof UnitSphereShape3D) {
17
+ } else if (shape instanceof SphereShape3D) {
18
+ // Covers UnitSphereShape3D (radius 1) and SphereShape3D (arbitrary);
19
+ // the 'sphere' adapter carries the radius.
18
20
  return 'sphere';
19
21
  } else if (shape instanceof TransformedShape3D) {
20
22
  return 'transform';
@@ -4,8 +4,17 @@ export namespace type_adapters {
4
4
  function write(): {};
5
5
  }
6
6
  namespace sphere {
7
- function read(): UnitSphereShape3D;
8
- function write(): {};
7
+ function read({ radius }?: {
8
+ radius: any;
9
+ }): SphereShape3D;
10
+ /**
11
+ * @param {SphereShape3D} object
12
+ */
13
+ function write(object: SphereShape3D): {
14
+ radius?: undefined;
15
+ } | {
16
+ radius: number;
17
+ };
9
18
  }
10
19
  namespace capsule {
11
20
  function read({ radius, height }: {
@@ -49,7 +58,7 @@ export namespace type_adapters {
49
58
  }
50
59
  }
51
60
  import { UnitCubeShape3D } from "../UnitCubeShape3D.js";
52
- import { UnitSphereShape3D } from "../UnitSphereShape3D.js";
61
+ import { SphereShape3D } from "../SphereShape3D.js";
53
62
  import { CapsuleShape3D } from "../CapsuleShape3D.js";
54
63
  import { TransformedShape3D } from "../TransformedShape3D.js";
55
64
  import { UnionShape3D } from "../UnionShape3D.js";
@@ -1 +1 @@
1
- {"version":3,"file":"type_adapters.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/geom/3d/shape/json/type_adapters.js"],"names":[],"mappings":";;QAUQ,iCAEC;QACD,qBAEC;;;QAGD,mCAEC;QACD,qBAEC;;;QAGD;;;2BAEC;QACD;;;WAGG;QACH;;;UAKC;;;QAGD;;;+BAIC;QACD;;;WAGG;QACH;;;UAKC;;;QAGD;;yBAIC;QACD;;;WAGG;QACH;;UAIC;;;gCApEuB,uBAAuB;kCACrB,yBAAyB;+BAJ5B,sBAAsB;mCAClB,0BAA0B;6BAChC,oBAAoB"}
1
+ {"version":3,"file":"type_adapters.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/geom/3d/shape/json/type_adapters.js"],"names":[],"mappings":";;QAWQ,iCAEC;QACD,qBAEC;;;QAGD;;0BAQC;QACD;;WAEG;QACH;;;;UAIC;;;QAGD;;;2BAEC;QACD;;;WAGG;QACH;;;UAKC;;;QAGD;;;+BAIC;QACD;;;WAGG;QACH;;;UAKC;;;QAGD;;yBAIC;QACD;;;WAGG;QACH;;UAIC;;;gCA/EuB,uBAAuB;8BAHzB,qBAAqB;+BADpB,sBAAsB;mCAElB,0BAA0B;6BAChC,oBAAoB"}
@@ -1,4 +1,5 @@
1
1
  import { CapsuleShape3D } from "../CapsuleShape3D.js";
2
+ import { SphereShape3D } from "../SphereShape3D.js";
2
3
  import { TransformedShape3D } from "../TransformedShape3D.js";
3
4
  import { UnionShape3D } from "../UnionShape3D.js";
4
5
  import { UnitCubeShape3D } from "../UnitCubeShape3D.js";
@@ -16,11 +17,22 @@ export const type_adapters = {
16
17
  }
17
18
  },
18
19
  'sphere': {
19
- read() {
20
- return UnitSphereShape3D.INSTANCE;
20
+ read({ radius } = {}) {
21
+ // Backward-compatible: legacy 'sphere' entries have no radius and
22
+ // map to the unit-sphere singleton. A radius of 1 is also treated
23
+ // as the unit sphere so re-saved unit spheres keep sharing INSTANCE.
24
+ if (radius === undefined || radius === 1) {
25
+ return UnitSphereShape3D.INSTANCE;
26
+ }
27
+ return SphereShape3D.from(radius);
21
28
  },
22
- write() {
23
- return {};
29
+ /**
30
+ * @param {SphereShape3D} object
31
+ */
32
+ write(object) {
33
+ // Omit radius for the unit case to keep the serialized form
34
+ // byte-identical to the pre-SphereShape3D 'sphere' tag.
35
+ return object.radius === 1 ? {} : { radius: object.radius };
24
36
  }
25
37
  },
26
38
  'capsule': {
@@ -8,10 +8,10 @@ import { AttachmentSockets } from "../../../../../engine/ecs/sockets/AttachmentS
8
8
  import { Transform } from "../../../../../engine/ecs/transform/Transform.js";
9
9
  import { DrawMode } from "../../../../../engine/graphics/ecs/mesh-v2/DrawMode.js";
10
10
  import { ShadedGeometry } from "../../../../../engine/graphics/ecs/mesh-v2/ShadedGeometry.js";
11
+ import { SphereShape3D } from "../SphereShape3D.js";
11
12
  import { TransformedShape3D } from "../TransformedShape3D.js";
12
13
  import { UnionShape3D } from "../UnionShape3D.js";
13
14
  import { UnitCubeShape3D } from "../UnitCubeShape3D.js";
14
- import { UnitSphereShape3D } from "../UnitSphereShape3D.js";
15
15
 
16
16
  const g_unit_sphere = makeHelperSphereGeometry(0.5, 32);
17
17
  const g_unit_cube = makeHelperBoxGeometry(1, 1, 1);
@@ -149,7 +149,7 @@ export function shape_to_visual_entity(shape, ecd) {
149
149
  return composite_shape_to_entity(shape, ecd);
150
150
  } else if (shape instanceof UnitCubeShape3D) {
151
151
  return cube_shape_to_entity(shape, ecd);
152
- } else if (shape instanceof UnitSphereShape3D) {
152
+ } else if (shape instanceof SphereShape3D) {
153
153
  return sphere_shape_to_entity(shape, ecd);
154
154
  } else if (shape instanceof TransformedShape3D) {
155
155
  return transformed_shape_to_entity(shape, ecd);