@datamoc/mw_games 0.36.1 → 0.38.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 (132) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +32 -2
  3. package/api-surface.json +384 -0
  4. package/dist/assets/paths.d.ts.map +1 -1
  5. package/dist/assets/paths.js +3 -0
  6. package/dist/assets/paths.js.map +1 -1
  7. package/dist/audio/Playable.d.ts.map +1 -1
  8. package/dist/audio/Playable.js +14 -1
  9. package/dist/audio/Playable.js.map +1 -1
  10. package/dist/audio/Synth.d.ts +14 -0
  11. package/dist/audio/Synth.d.ts.map +1 -1
  12. package/dist/audio/Synth.js +16 -0
  13. package/dist/audio/Synth.js.map +1 -1
  14. package/dist/audio/index.d.ts +1 -1
  15. package/dist/audio/index.d.ts.map +1 -1
  16. package/dist/audio/index.js +1 -1
  17. package/dist/audio/index.js.map +1 -1
  18. package/dist/core/FixedStepper.d.ts +38 -0
  19. package/dist/core/FixedStepper.d.ts.map +1 -0
  20. package/dist/core/FixedStepper.js +56 -0
  21. package/dist/core/FixedStepper.js.map +1 -0
  22. package/dist/core/Input.d.ts +61 -0
  23. package/dist/core/Input.d.ts.map +1 -1
  24. package/dist/core/Input.js +101 -0
  25. package/dist/core/Input.js.map +1 -1
  26. package/dist/core/StoredValue.d.ts +11 -2
  27. package/dist/core/StoredValue.d.ts.map +1 -1
  28. package/dist/core/StoredValue.js +11 -2
  29. package/dist/core/StoredValue.js.map +1 -1
  30. package/dist/core/index.d.ts +3 -1
  31. package/dist/core/index.d.ts.map +1 -1
  32. package/dist/core/index.js +3 -1
  33. package/dist/core/index.js.map +1 -1
  34. package/dist/mw_games.global.js +121 -121
  35. package/dist/mwl/presentation.d.ts +70 -0
  36. package/dist/mwl/presentation.d.ts.map +1 -0
  37. package/dist/mwl/presentation.js +412 -0
  38. package/dist/mwl/presentation.js.map +1 -0
  39. package/dist/physics/PhysicsWorld.d.ts +123 -0
  40. package/dist/physics/PhysicsWorld.d.ts.map +1 -0
  41. package/dist/physics/PhysicsWorld.js +137 -0
  42. package/dist/physics/PhysicsWorld.js.map +1 -0
  43. package/dist/physics/XpbdWorld.d.ts +139 -0
  44. package/dist/physics/XpbdWorld.d.ts.map +1 -0
  45. package/dist/physics/XpbdWorld.js +207 -0
  46. package/dist/physics/XpbdWorld.js.map +1 -0
  47. package/dist/physics/index.d.ts +3 -0
  48. package/dist/physics/index.d.ts.map +1 -0
  49. package/dist/physics/index.js +2 -0
  50. package/dist/physics/index.js.map +1 -0
  51. package/dist/physics/xpbd.d.ts +3 -0
  52. package/dist/physics/xpbd.d.ts.map +1 -0
  53. package/dist/physics/xpbd.js +2 -0
  54. package/dist/physics/xpbd.js.map +1 -0
  55. package/dist/two-d/presentation/MwlPresentation.d.ts +98 -0
  56. package/dist/two-d/presentation/MwlPresentation.d.ts.map +1 -0
  57. package/dist/two-d/presentation/MwlPresentation.js +704 -0
  58. package/dist/two-d/presentation/MwlPresentation.js.map +1 -0
  59. package/dist/two-d/presentation/index.d.ts +3 -0
  60. package/dist/two-d/presentation/index.d.ts.map +1 -0
  61. package/dist/two-d/presentation/index.js +2 -0
  62. package/dist/two-d/presentation/index.js.map +1 -0
  63. package/dist/two-d/render/Camera.d.ts +6 -0
  64. package/dist/two-d/render/Camera.d.ts.map +1 -1
  65. package/dist/two-d/render/Camera.js +9 -0
  66. package/dist/two-d/render/Camera.js.map +1 -1
  67. package/dist/two-d/render/Particles.d.ts +10 -1
  68. package/dist/two-d/render/Particles.d.ts.map +1 -1
  69. package/dist/two-d/render/Particles.js +14 -7
  70. package/dist/two-d/render/Particles.js.map +1 -1
  71. package/dist/two-d/render/Shape2D.d.ts +7 -0
  72. package/dist/two-d/render/Shape2D.d.ts.map +1 -1
  73. package/dist/two-d/render/Shape2D.js +18 -0
  74. package/dist/two-d/render/Shape2D.js.map +1 -1
  75. package/dist/two-d/render/SpriteSheet.d.ts +5 -0
  76. package/dist/two-d/render/SpriteSheet.d.ts.map +1 -1
  77. package/dist/two-d/render/SpriteSheet.js +15 -0
  78. package/dist/two-d/render/SpriteSheet.js.map +1 -1
  79. package/dist/two-d/ui/Bar.d.ts +3 -1
  80. package/dist/two-d/ui/Bar.d.ts.map +1 -1
  81. package/dist/two-d/ui/Bar.js +5 -0
  82. package/dist/two-d/ui/Bar.js.map +1 -1
  83. package/dist/two-d/ui/Button.d.ts +19 -0
  84. package/dist/two-d/ui/Button.d.ts.map +1 -1
  85. package/dist/two-d/ui/Button.js +30 -4
  86. package/dist/two-d/ui/Button.js.map +1 -1
  87. package/dist/two-d/ui/Dropdown.d.ts +3 -0
  88. package/dist/two-d/ui/Dropdown.d.ts.map +1 -1
  89. package/dist/two-d/ui/Dropdown.js +3 -0
  90. package/dist/two-d/ui/Dropdown.js.map +1 -1
  91. package/dist/two-d/ui/DropdownView.d.ts +40 -0
  92. package/dist/two-d/ui/DropdownView.d.ts.map +1 -0
  93. package/dist/two-d/ui/DropdownView.js +75 -0
  94. package/dist/two-d/ui/DropdownView.js.map +1 -0
  95. package/dist/two-d/ui/Label.d.ts +2 -0
  96. package/dist/two-d/ui/Label.d.ts.map +1 -1
  97. package/dist/two-d/ui/Label.js +7 -0
  98. package/dist/two-d/ui/Label.js.map +1 -1
  99. package/dist/two-d/ui/Layout.d.ts +34 -0
  100. package/dist/two-d/ui/Layout.d.ts.map +1 -1
  101. package/dist/two-d/ui/Layout.js +47 -0
  102. package/dist/two-d/ui/Layout.js.map +1 -1
  103. package/dist/two-d/ui/Window.d.ts +17 -0
  104. package/dist/two-d/ui/Window.d.ts.map +1 -1
  105. package/dist/two-d/ui/Window.js +28 -4
  106. package/dist/two-d/ui/Window.js.map +1 -1
  107. package/dist/two-d/ui/index.d.ts +6 -2
  108. package/dist/two-d/ui/index.d.ts.map +1 -1
  109. package/dist/two-d/ui/index.js +2 -1
  110. package/dist/two-d/ui/index.js.map +1 -1
  111. package/dist/version.d.ts +1 -1
  112. package/dist/version.js +1 -1
  113. package/package.json +36 -2
  114. package/sbom.cdx.json +58 -6
  115. package/tools/browser-driver.d.mts +14 -0
  116. package/tools/browser-driver.mjs +62 -0
  117. package/tools/build-tablebases.mjs +6 -2
  118. package/tools/classic-html.mjs +9 -1
  119. package/tools/compile-openings.mjs +6 -2
  120. package/tools/compile-resources.d.mts +5 -0
  121. package/tools/compile-resources.mjs +45 -4
  122. package/tools/compress-dist.mjs +15 -3
  123. package/tools/emit-page.mjs +5 -1
  124. package/tools/init.d.mts +5 -0
  125. package/tools/init.mjs +145 -0
  126. package/tools/play-uci.mjs +6 -3
  127. package/tools/sbom.mjs +5 -1
  128. package/tools/single-file.mjs +9 -1
  129. package/tools/verify-scenarios.d.mts +15 -0
  130. package/tools/verify-scenarios.mjs +129 -0
  131. package/tools/vite.mjs +5 -0
  132. package/tools/webp-convert.mjs +9 -1
@@ -0,0 +1,137 @@
1
+ import Matter from 'matter-js';
2
+ import { FixedStepper } from '../core/FixedStepper.js';
3
+ import { Signal } from '../core/Signal.js';
4
+ /**
5
+ * Rigid bodies and constraints through matter-js, stepped on a fixed clock.
6
+ *
7
+ * The adapter is the framework side of using matter-js in a mwg game: it owns the `Engine`,
8
+ * steps it with a `FixedStepper` so the simulation is the same at any display refresh rate,
9
+ * and reports contacts through a `Signal`, while leaving the bodies themselves as plain
10
+ * matter-js objects a game reads `position` and `angle` from to place its sprites. It is
11
+ * renderer-free, so a game's headless tests can run the same world.
12
+ *
13
+ * `matter-js` is an optional peer dependency (`npm install matter-js`), imported only by this
14
+ * module (`@datamoc/mw_games/physics`), so a game that never simulates physics never bundles it.
15
+ * Constraints are springs and rods. Give one a `maxStretch` and it breaks when pulled that far
16
+ * past its rest length (`onBreak`); a game with a different stress rule reads `stretchOf` itself
17
+ * and calls `remove`.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import { PhysicsWorld } from '@datamoc/mw_games/physics';
22
+ *
23
+ * const world = new PhysicsWorld();
24
+ * world.addBox(0, 300, 800, 20, { isStatic: true });
25
+ * const crate = world.addBox(100, 0, 40, 40, { restitution: 0.3 });
26
+ * world.update(1 / 30); // two fixed steps
27
+ * console.log(crate.position.y > 0); // true: it has started to fall
28
+ * ```
29
+ */
30
+ export class PhysicsWorld {
31
+ constructor(options = {}) {
32
+ /** fires once per new contact between two bodies, with the matter-js bodies of the pair */
33
+ this.onContact = new Signal();
34
+ /** fires when a breakable constraint passes its `maxStretch`; it is already removed from the world */
35
+ this.onBreak = new Signal();
36
+ this.breakable = new Map();
37
+ this.engine = Matter.Engine.create();
38
+ const gravity = options.gravity ?? { x: 0, y: 9.8 };
39
+ //matter's gravity is a direction times `scale`; 9.8 maps to its own default scale of 0.001
40
+ this.engine.gravity.x = Math.sign(gravity.x);
41
+ this.engine.gravity.y = Math.sign(gravity.y);
42
+ this.engine.gravity.scale = Math.max(Math.abs(gravity.x), Math.abs(gravity.y)) * 0.0001;
43
+ this.stepper = new FixedStepper(options.step ?? 1 / 60, options.maxSubsteps ?? 5);
44
+ Matter.Events.on(this.engine, 'collisionStart', (event) => {
45
+ for (const pair of event.pairs)
46
+ this.onContact.dispatch({ a: pair.bodyA, b: pair.bodyB });
47
+ });
48
+ }
49
+ get bodies() {
50
+ return Matter.Composite.allBodies(this.engine.world);
51
+ }
52
+ get constraints() {
53
+ return Matter.Composite.allConstraints(this.engine.world);
54
+ }
55
+ /** how far into the next fixed step the clock is, 0 to 1, for interpolated drawing */
56
+ get alpha() {
57
+ return this.stepper.alpha;
58
+ }
59
+ /** a box centred on (x, y) */
60
+ addBox(x, y, width, height, options = {}) {
61
+ return this.add(Matter.Bodies.rectangle(x, y, width, height, options));
62
+ }
63
+ addCircle(x, y, radius, options = {}) {
64
+ return this.add(Matter.Bodies.circle(x, y, radius, options));
65
+ }
66
+ /** joins two bodies, or a body to a fixed point in the world when `b` is a point */
67
+ addConstraint(a, b, options = {}) {
68
+ const isBody = (value) => 'position' in value;
69
+ const constraint = Matter.Constraint.create({
70
+ bodyA: a,
71
+ ...(isBody(b) ? { bodyB: b } : { pointB: b }),
72
+ ...(options.pointA ? { pointA: options.pointA } : {}),
73
+ ...(isBody(b) && options.pointB ? { pointB: options.pointB } : {}),
74
+ stiffness: options.stiffness ?? 1,
75
+ damping: options.damping ?? 0,
76
+ ...(options.length !== undefined ? { length: options.length } : {}),
77
+ });
78
+ Matter.Composite.add(this.engine.world, constraint);
79
+ if (options.maxStretch !== undefined)
80
+ this.breakable.set(constraint, options.maxStretch);
81
+ return constraint;
82
+ }
83
+ /** removes a body, or a constraint, from the simulation */
84
+ remove(item) {
85
+ Matter.Composite.remove(this.engine.world, item);
86
+ this.breakable.delete(item);
87
+ }
88
+ /**
89
+ * How far a constraint is stretched past its rest length, as a fraction of it (0.1 is 10%
90
+ * longer); for a zero-length joint, the distance between its ends. Negative when compressed.
91
+ */
92
+ stretchOf(constraint) {
93
+ const a = endPoint(constraint.bodyA, constraint.pointA);
94
+ const b = endPoint(constraint.bodyB, constraint.pointB);
95
+ const distance = Math.hypot(a.x - b.x, a.y - b.y);
96
+ return constraint.length > 0 ? distance / constraint.length - 1 : distance;
97
+ }
98
+ /**
99
+ * Advances the simulation by `dt` seconds of real time, running as many fixed steps as that
100
+ * covers; call it from `Scene.update(dt)`.
101
+ *
102
+ * @returns how many fixed steps ran
103
+ */
104
+ update(dt) {
105
+ return this.stepper.advance(dt, (step) => {
106
+ Matter.Engine.update(this.engine, step * 1000);
107
+ this.breakOverstretched();
108
+ });
109
+ }
110
+ breakOverstretched() {
111
+ //collected first: removing while iterating the map would skip entries
112
+ const snapped = [];
113
+ for (const [constraint, limit] of this.breakable) {
114
+ const stretch = this.stretchOf(constraint);
115
+ if (stretch > limit)
116
+ snapped.push([constraint, stretch]);
117
+ }
118
+ for (const [constraint, stretch] of snapped) {
119
+ this.remove(constraint);
120
+ this.onBreak.dispatch({ constraint, stretch });
121
+ }
122
+ }
123
+ add(body) {
124
+ Matter.Composite.add(this.engine.world, body);
125
+ return body;
126
+ }
127
+ }
128
+ /** a constraint end in world space: the body's attachment point turned and moved with it, or the fixed point itself */
129
+ function endPoint(body, point) {
130
+ const local = point ?? { x: 0, y: 0 };
131
+ if (!body)
132
+ return local;
133
+ const cos = Math.cos(body.angle);
134
+ const sin = Math.sin(body.angle);
135
+ return { x: body.position.x + local.x * cos - local.y * sin, y: body.position.y + local.x * sin + local.y * cos };
136
+ }
137
+ //# sourceMappingURL=PhysicsWorld.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PhysicsWorld.js","sourceRoot":"","sources":["../../src/physics/PhysicsWorld.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,139 @@
1
+ import { Signal } from '../core/Signal.ts';
2
+ export interface XpbdOptions {
3
+ /** downward acceleration in units per second squared; 520 when omitted (a 1-unit-per-pixel scale) */
4
+ gravity?: number;
5
+ /** substeps per `step`; 16 when omitted. More is stiffer and steadier, and costs linearly */
6
+ substeps?: number;
7
+ /** constraint iterations per substep; 2 when omitted */
8
+ iterations?: number;
9
+ /** the frame time one `step` advances, in seconds; 1/60 when omitted */
10
+ step?: number;
11
+ /** velocity damping per second (exponential); 2.5 when omitted. Raise it while a structure settles */
12
+ damping?: number;
13
+ /** time constant of the load smoothing used for breaking, in seconds; 0.06 when omitted */
14
+ smoothing?: number;
15
+ /** how much of a node's sideways motion the ground removes while it touches, 0 to 1; 0.5 when omitted */
16
+ groundFriction?: number;
17
+ }
18
+ /** the ground a node cannot sink below: a height (y grows downward), or a height at each x */
19
+ export type XpbdGround = number | ((x: number) => number);
20
+ export interface XpbdNodeSpec {
21
+ x: number;
22
+ y: number;
23
+ /** an anchor that never moves */
24
+ fixed?: boolean;
25
+ /** point mass; 1 when omitted. Link `mass` is added on top */
26
+ mass?: number;
27
+ }
28
+ export interface XpbdLinkSpec {
29
+ a: number;
30
+ b: number;
31
+ /** spring stiffness: force per unit of stretch ratio. Higher is more rigid */
32
+ stiffness: number;
33
+ /** rest length; the current distance between the nodes when omitted */
34
+ rest?: number;
35
+ /** mass of the link itself, shared evenly between its two nodes */
36
+ mass?: number;
37
+ /** a cable: pulls when stretched and goes slack, without pushing, when compressed */
38
+ tensionOnly?: boolean;
39
+ /** the load it carries in compression before breaking; also in tension unless `tensionStrength` is set. Unbreakable when omitted */
40
+ strength?: number;
41
+ /** the load it carries in tension before breaking, when that differs from `strength` */
42
+ tensionStrength?: number;
43
+ }
44
+ export interface XpbdNode {
45
+ x: number;
46
+ y: number;
47
+ fixed: boolean;
48
+ vx: number;
49
+ vy: number;
50
+ /** inverse mass, 0 for a fixed node */
51
+ w: number;
52
+ }
53
+ export interface XpbdLink {
54
+ a: number;
55
+ b: number;
56
+ stiffness: number;
57
+ rest: number;
58
+ tensionOnly: boolean;
59
+ strength: number | undefined;
60
+ tensionStrength: number | undefined;
61
+ broken: boolean;
62
+ /** the force it carried over the last step, positive in tension, negative in compression */
63
+ force: number;
64
+ /** smoothed load as a fraction of what it can carry; it breaks above 1 */
65
+ ratio: number;
66
+ }
67
+ /**
68
+ * A deterministic structure solver: point masses joined by springs, solved with extended
69
+ * position-based dynamics (XPBD), with the force in every link read back so a link can break
70
+ * at a real load rather than at a stretch.
71
+ *
72
+ * The method (Macklin, Muller and Chentanaput's XPBD) moves each node freely for a substep,
73
+ * then corrects positions so every link returns to its rest length, with a compliance of
74
+ * `rest / stiffness / dt^2`: a link behaves as a spring of the stated stiffness whatever the
75
+ * step or iteration count, and the correction's Lagrange multiplier divided by `dt^2` is the
76
+ * force it carried. Steps are fixed and nothing is random, so the same structure and the same
77
+ * calls give the same result on every machine, which is what replaying or validating a
78
+ * player's bridge needs.
79
+ *
80
+ * It is the engine of Pontifex (a bridge-building game), generalised: the vehicle, the water
81
+ * and the levels stay in the game, and what is here is only nodes, links, forces and breaking.
82
+ * Unlike `PhysicsWorld` it has no rigid bodies or collisions and no `matter-js` dependency.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * import { XpbdWorld } from '@datamoc/mw_games/physics/xpbd';
87
+ *
88
+ * const world = new XpbdWorld({ gravity: 520 });
89
+ * const wall = world.addNode({ x: 0, y: 0, fixed: true });
90
+ * const weight = world.addNode({ x: 40, y: 0, mass: 1 });
91
+ * const rope = world.addLink({ a: wall, b: weight, stiffness: 2e4, strength: 900 });
92
+ * world.breaking = true;
93
+ * for (let i = 0; i < 120; i++) world.step();
94
+ * console.log(world.links[rope].broken, world.nodes[weight].y > 0);
95
+ * ```
96
+ */
97
+ export declare class XpbdWorld {
98
+ readonly nodes: XpbdNode[];
99
+ readonly links: XpbdLink[];
100
+ /** fires once for a link that passed its strength, which has already stopped carrying load */
101
+ readonly onBreak: Signal<{
102
+ link: number;
103
+ x: number;
104
+ y: number;
105
+ }>;
106
+ /** links break only while this is true, so a structure can settle under its own weight first */
107
+ breaking: boolean;
108
+ /** the highest smoothed load ratio across the links at the last step, for a strain gauge */
109
+ peakRatio: number;
110
+ gravity: number;
111
+ damping: number;
112
+ /** nodes are held on or above this; null for none. Water, a gorge or a cliff face is the game's own business */
113
+ ground: XpbdGround | null;
114
+ groundFriction: number;
115
+ private readonly frame;
116
+ private readonly substeps;
117
+ private readonly iterations;
118
+ private readonly smoothing;
119
+ private readonly forces;
120
+ private readonly masses;
121
+ private readonly lambda;
122
+ private readonly accumulated;
123
+ constructor(options?: XpbdOptions);
124
+ /** adds a node and returns its index */
125
+ addNode(spec: XpbdNodeSpec): number;
126
+ /** adds a link between two existing nodes and returns its index */
127
+ addLink(spec: XpbdLinkSpec): number;
128
+ /** an external force on a node for the next `step` only (a wheel's weight, wind) */
129
+ applyForce(node: number, fx: number, fy: number): void;
130
+ /** advances one frame: the substeps, then the link loads and any breaking */
131
+ step(): void;
132
+ private refreshInverseMass;
133
+ private substep;
134
+ /** lifts any node that sank below the ground back onto it, and takes some of its sideways motion with it */
135
+ private collideWithGround;
136
+ /** averages each link's force over the substeps, smooths the load ratio and breaks what passed its strength */
137
+ private settleLoads;
138
+ }
139
+ //# sourceMappingURL=XpbdWorld.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"XpbdWorld.d.ts","sourceRoot":"","sources":["../../src/physics/XpbdWorld.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,207 @@
1
+ import { Signal } from '../core/Signal.js';
2
+ /**
3
+ * A deterministic structure solver: point masses joined by springs, solved with extended
4
+ * position-based dynamics (XPBD), with the force in every link read back so a link can break
5
+ * at a real load rather than at a stretch.
6
+ *
7
+ * The method (Macklin, Muller and Chentanaput's XPBD) moves each node freely for a substep,
8
+ * then corrects positions so every link returns to its rest length, with a compliance of
9
+ * `rest / stiffness / dt^2`: a link behaves as a spring of the stated stiffness whatever the
10
+ * step or iteration count, and the correction's Lagrange multiplier divided by `dt^2` is the
11
+ * force it carried. Steps are fixed and nothing is random, so the same structure and the same
12
+ * calls give the same result on every machine, which is what replaying or validating a
13
+ * player's bridge needs.
14
+ *
15
+ * It is the engine of Pontifex (a bridge-building game), generalised: the vehicle, the water
16
+ * and the levels stay in the game, and what is here is only nodes, links, forces and breaking.
17
+ * Unlike `PhysicsWorld` it has no rigid bodies or collisions and no `matter-js` dependency.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import { XpbdWorld } from '@datamoc/mw_games/physics/xpbd';
22
+ *
23
+ * const world = new XpbdWorld({ gravity: 520 });
24
+ * const wall = world.addNode({ x: 0, y: 0, fixed: true });
25
+ * const weight = world.addNode({ x: 40, y: 0, mass: 1 });
26
+ * const rope = world.addLink({ a: wall, b: weight, stiffness: 2e4, strength: 900 });
27
+ * world.breaking = true;
28
+ * for (let i = 0; i < 120; i++) world.step();
29
+ * console.log(world.links[rope].broken, world.nodes[weight].y > 0);
30
+ * ```
31
+ */
32
+ export class XpbdWorld {
33
+ constructor(options = {}) {
34
+ this.nodes = [];
35
+ this.links = [];
36
+ /** fires once for a link that passed its strength, which has already stopped carrying load */
37
+ this.onBreak = new Signal();
38
+ /** links break only while this is true, so a structure can settle under its own weight first */
39
+ this.breaking = false;
40
+ /** the highest smoothed load ratio across the links at the last step, for a strain gauge */
41
+ this.peakRatio = 0;
42
+ /** nodes are held on or above this; null for none. Water, a gorge or a cliff face is the game's own business */
43
+ this.ground = null;
44
+ this.forces = [];
45
+ this.masses = [];
46
+ this.lambda = [];
47
+ this.accumulated = [];
48
+ this.gravity = options.gravity ?? 520;
49
+ this.damping = options.damping ?? 2.5;
50
+ this.groundFriction = options.groundFriction ?? 0.5;
51
+ this.frame = options.step ?? 1 / 60;
52
+ this.substeps = Math.max(1, Math.floor(options.substeps ?? 16));
53
+ this.iterations = Math.max(1, Math.floor(options.iterations ?? 2));
54
+ this.smoothing = options.smoothing ?? 0.06;
55
+ }
56
+ /** adds a node and returns its index */
57
+ addNode(spec) {
58
+ const mass = spec.mass ?? 1;
59
+ if (!(mass > 0) && !spec.fixed)
60
+ throw new Error('a moving node needs a positive mass');
61
+ this.nodes.push({ x: spec.x, y: spec.y, fixed: spec.fixed ?? false, vx: 0, vy: 0, w: 0 });
62
+ this.masses.push(mass);
63
+ this.forces.push({ x: 0, y: 0 });
64
+ this.refreshInverseMass();
65
+ return this.nodes.length - 1;
66
+ }
67
+ /** adds a link between two existing nodes and returns its index */
68
+ addLink(spec) {
69
+ const a = this.nodes[spec.a];
70
+ const b = this.nodes[spec.b];
71
+ if (!a || !b)
72
+ throw new Error('a link needs two existing nodes');
73
+ const rest = spec.rest ?? Math.hypot(a.x - b.x, a.y - b.y);
74
+ if (!(rest > 0))
75
+ throw new Error('a link needs a positive rest length');
76
+ if (!(spec.stiffness > 0))
77
+ throw new Error('a link needs a positive stiffness');
78
+ const share = (spec.mass ?? 0) / 2;
79
+ this.masses[spec.a] += share;
80
+ this.masses[spec.b] += share;
81
+ this.links.push({
82
+ a: spec.a,
83
+ b: spec.b,
84
+ stiffness: spec.stiffness,
85
+ rest,
86
+ tensionOnly: spec.tensionOnly ?? false,
87
+ strength: spec.strength,
88
+ tensionStrength: spec.tensionStrength,
89
+ broken: false,
90
+ force: 0,
91
+ ratio: 0,
92
+ });
93
+ this.lambda.push(0);
94
+ this.accumulated.push(0);
95
+ this.refreshInverseMass();
96
+ return this.links.length - 1;
97
+ }
98
+ /** an external force on a node for the next `step` only (a wheel's weight, wind) */
99
+ applyForce(node, fx, fy) {
100
+ this.forces[node].x += fx;
101
+ this.forces[node].y += fy;
102
+ }
103
+ /** advances one frame: the substeps, then the link loads and any breaking */
104
+ step() {
105
+ const dt = this.frame / this.substeps;
106
+ this.accumulated.fill(0);
107
+ for (let s = 0; s < this.substeps; s++)
108
+ this.substep(dt);
109
+ for (const force of this.forces) {
110
+ force.x = 0;
111
+ force.y = 0;
112
+ }
113
+ this.settleLoads();
114
+ }
115
+ refreshInverseMass() {
116
+ this.nodes.forEach((node, i) => {
117
+ node.w = node.fixed ? 0 : 1 / this.masses[i];
118
+ });
119
+ }
120
+ substep(dt) {
121
+ const damp = Math.exp(-this.damping * dt);
122
+ const previous = this.nodes.map((node) => ({ x: node.x, y: node.y }));
123
+ this.nodes.forEach((node, i) => {
124
+ if (node.fixed)
125
+ return;
126
+ const force = this.forces[i];
127
+ node.vx = (node.vx + force.x * node.w * dt) * damp;
128
+ node.vy = (node.vy + (force.y * node.w + this.gravity) * dt) * damp;
129
+ node.x += node.vx * dt;
130
+ node.y += node.vy * dt;
131
+ });
132
+ this.lambda.fill(0);
133
+ for (let iteration = 0; iteration < this.iterations; iteration++) {
134
+ this.links.forEach((link, i) => {
135
+ if (link.broken)
136
+ return;
137
+ const p = this.nodes[link.a];
138
+ const q = this.nodes[link.b];
139
+ const w = p.w + q.w;
140
+ if (w === 0)
141
+ return;
142
+ const dx = q.x - p.x;
143
+ const dy = q.y - p.y;
144
+ const length = Math.hypot(dx, dy) || 1e-9;
145
+ const c = length - link.rest;
146
+ if (link.tensionOnly && c < 0 && this.lambda[i] >= 0)
147
+ return;
148
+ const alpha = link.rest / link.stiffness / (dt * dt);
149
+ const delta = (-c - alpha * this.lambda[i]) / (w + alpha);
150
+ this.lambda[i] += delta;
151
+ const nx = dx / length;
152
+ const ny = dy / length;
153
+ p.x -= p.w * delta * nx;
154
+ p.y -= p.w * delta * ny;
155
+ q.x += q.w * delta * nx;
156
+ q.y += q.w * delta * ny;
157
+ });
158
+ }
159
+ this.collideWithGround(previous);
160
+ this.nodes.forEach((node, i) => {
161
+ if (node.fixed)
162
+ return;
163
+ node.vx = (node.x - previous[i].x) / dt;
164
+ node.vy = (node.y - previous[i].y) / dt;
165
+ });
166
+ this.links.forEach((_, i) => {
167
+ this.accumulated[i] += -this.lambda[i] / (dt * dt);
168
+ });
169
+ }
170
+ /** lifts any node that sank below the ground back onto it, and takes some of its sideways motion with it */
171
+ collideWithGround(previous) {
172
+ const ground = this.ground;
173
+ if (ground === null)
174
+ return;
175
+ this.nodes.forEach((node, i) => {
176
+ if (node.fixed)
177
+ return;
178
+ const surface = typeof ground === 'number' ? ground : ground(node.x);
179
+ if (node.y <= surface)
180
+ return;
181
+ node.y = surface;
182
+ node.x -= (node.x - previous[i].x) * this.groundFriction;
183
+ });
184
+ }
185
+ /** averages each link's force over the substeps, smooths the load ratio and breaks what passed its strength */
186
+ settleLoads() {
187
+ const blend = 1 - Math.exp(-this.frame / this.smoothing);
188
+ let peak = 0;
189
+ this.links.forEach((link, i) => {
190
+ if (link.broken)
191
+ return;
192
+ link.force = this.accumulated[i] / this.substeps;
193
+ const limit = link.force > 0 ? (link.tensionStrength ?? link.strength) : link.strength;
194
+ const instant = limit === undefined ? 0 : Math.abs(link.force) / limit;
195
+ link.ratio += (instant - link.ratio) * blend;
196
+ peak = Math.max(peak, link.ratio);
197
+ if (this.breaking && link.ratio > 1) {
198
+ link.broken = true;
199
+ const p = this.nodes[link.a];
200
+ const q = this.nodes[link.b];
201
+ this.onBreak.dispatch({ link: i, x: (p.x + q.x) / 2, y: (p.y + q.y) / 2 });
202
+ }
203
+ });
204
+ this.peakRatio = peak;
205
+ }
206
+ }
207
+ //# sourceMappingURL=XpbdWorld.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"XpbdWorld.js","sourceRoot":"","sources":["../../src/physics/XpbdWorld.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { PhysicsWorld } from './PhysicsWorld.ts';
2
+ export type { BodyOptions, ConstraintOptions, PhysicsBody, PhysicsConstraint, PhysicsOptions } from './PhysicsWorld.ts';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/physics/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,WAAW,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { PhysicsWorld } from './PhysicsWorld.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/physics/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { XpbdWorld } from './XpbdWorld.ts';
2
+ export type { XpbdGround, XpbdLink, XpbdLinkSpec, XpbdNode, XpbdNodeSpec, XpbdOptions } from './XpbdWorld.ts';
3
+ //# sourceMappingURL=xpbd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xpbd.d.ts","sourceRoot":"","sources":["../../src/physics/xpbd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { XpbdWorld } from './XpbdWorld.js';
2
+ //# sourceMappingURL=xpbd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xpbd.js","sourceRoot":"","sources":["../../src/physics/xpbd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,98 @@
1
+ import { Container } from 'pixi.js';
2
+ import { Camera } from '../render/Camera.ts';
3
+ import { WindowStack } from '../ui/WindowStack.ts';
4
+ import type { CompiledPresentation, PresentationItem, PresentationProperties, PresentationValue } from '../../mwl/presentation.ts';
5
+ export type PresentationState = Readonly<Record<string, PresentationValue | readonly PresentationItem[]>>;
6
+ export interface PresentationAdapterContext {
7
+ readonly tokens: Readonly<Record<string, number>>;
8
+ readonly properties: PresentationProperties;
9
+ }
10
+ /** Runtime owns and destroys `view`; destroy detaches adapter-owned subscriptions/resources. */
11
+ export interface PresentationAdapter {
12
+ readonly view: Container;
13
+ update?(dt: number, state: PresentationState): void;
14
+ resize?(width: number, height: number): void;
15
+ restyle?(context: PresentationAdapterContext): void;
16
+ destroy?(): void;
17
+ }
18
+ export interface PresentationRuntimeOptions {
19
+ readonly parent: Container;
20
+ readonly state: () => PresentationState;
21
+ readonly actions: Readonly<Record<string, (item?: PresentationItem) => void>>;
22
+ readonly adapters?: Readonly<Record<string, (context: PresentationAdapterContext) => PresentationAdapter>>;
23
+ readonly translate?: (message: string) => string;
24
+ /** Optional external notification; returned disposer is called at destruction. */
25
+ readonly subscribe?: (refresh: () => void) => () => void;
26
+ }
27
+ /**
28
+ * Instantiates compiled MWL presentation using existing Pixi widgets. The controller owns state
29
+ * and actions; context switches restyle the same views without rebuilding procedural adapters.
30
+ * Kept off the root barrel so a game pays for this runtime only when it imports the subpath.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * import { MwlPresentation } from '@datamoc/mw_games/two-d/presentation';
35
+ * import type { CompiledPresentation } from '@datamoc/mw_games/mwl/presentation';
36
+ * import { Node2D } from '@datamoc/mw_games/two-d/render';
37
+ * declare const data: CompiledPresentation;
38
+ * const ui = new MwlPresentation(data, 'game', { parent: new Node2D(), state: () => ({}), actions: {} });
39
+ * ui.resize(800, 600);
40
+ * ui.update(1 / 60);
41
+ * ui.destroy();
42
+ * ```
43
+ */
44
+ export declare class MwlPresentation<Id extends string = string> {
45
+ private readonly data;
46
+ private readonly options;
47
+ readonly root: Container<import("pixi.js").ContainerChild>;
48
+ readonly windows: WindowStack;
49
+ readonly camera: Camera;
50
+ private readonly nodes;
51
+ private readonly roots;
52
+ private readonly baseTheme;
53
+ private readonly cameraProperties;
54
+ private readonly cameraPath;
55
+ private readonly previousTheme;
56
+ private appliedTheme;
57
+ private context;
58
+ private tokens;
59
+ private viewport;
60
+ private focused;
61
+ private destroyed;
62
+ private unsubscribe?;
63
+ private state;
64
+ private readonly inputListener;
65
+ constructor(data: CompiledPresentation, sceneId: string, options: PresentationRuntimeOptions);
66
+ /** Looks up an instance by its compiled path; repeats add their stable key to the path. */
67
+ get(id: Id): Container | null;
68
+ get focusId(): string | null;
69
+ get activeContext(): string;
70
+ get palette(): Readonly<Record<string, number>>;
71
+ setContext(context?: string): void;
72
+ private applyTheme;
73
+ update(dt?: number): void;
74
+ resize(width: number, height: number): void;
75
+ private createRecord;
76
+ private read;
77
+ private coerce;
78
+ private resolveProperties;
79
+ private refresh;
80
+ private mount;
81
+ private reconcile;
82
+ private token;
83
+ private applyProperties;
84
+ private layout;
85
+ private layoutNode;
86
+ private invoke;
87
+ private isFocusable;
88
+ private focusable;
89
+ private setFocus;
90
+ private navigate;
91
+ /** Offers modal windows input first, then the screen-space buttons. */
92
+ handleAction(action: string): boolean;
93
+ private unmount;
94
+ private dispose;
95
+ private assertAlive;
96
+ destroy(): void;
97
+ }
98
+ //# sourceMappingURL=MwlPresentation.d.ts.map