@zylem/behaviors 0.4.1 → 0.5.1

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 (145) hide show
  1. package/README.md +13 -1
  2. package/dist/{behavior-system-y8SGrGWy.d.ts → behavior-system-CeJXzNvr.d.ts} +305 -17
  3. package/dist/{chunk-GFARAJV2.js → chunk-2PAHQZZD.js} +44 -73
  4. package/dist/chunk-2PAHQZZD.js.map +1 -0
  5. package/dist/chunk-52FJIDGL.js +30 -0
  6. package/dist/chunk-52FJIDGL.js.map +1 -0
  7. package/dist/{chunk-UYFOLI2X.js → chunk-5A5AYP2C.js} +1 -1
  8. package/dist/{chunk-UYFOLI2X.js.map → chunk-5A5AYP2C.js.map} +1 -1
  9. package/dist/{chunk-A4CA35DQ.js → chunk-5EBIIYZD.js} +25 -45
  10. package/dist/chunk-5EBIIYZD.js.map +1 -0
  11. package/dist/{chunk-4L36OPY2.js → chunk-5NJGASUJ.js} +81 -135
  12. package/dist/chunk-5NJGASUJ.js.map +1 -0
  13. package/dist/{chunk-27UPCP5B.js → chunk-5UMCWV5A.js} +22 -13
  14. package/dist/chunk-5UMCWV5A.js.map +1 -0
  15. package/dist/chunk-5WRI5ZAA.js +31 -0
  16. package/dist/chunk-5WRI5ZAA.js.map +1 -0
  17. package/dist/{chunk-5SM5SH5O.js → chunk-7JLWZXPA.js} +2 -2
  18. package/dist/{chunk-Z72F2ENM.js → chunk-AEBDZWCP.js} +17 -26
  19. package/dist/chunk-AEBDZWCP.js.map +1 -0
  20. package/dist/chunk-AS3HR7AS.js +188 -0
  21. package/dist/chunk-AS3HR7AS.js.map +1 -0
  22. package/dist/chunk-E4X4YJZB.js +841 -0
  23. package/dist/chunk-E4X4YJZB.js.map +1 -0
  24. package/dist/{chunk-VMQHNJJI.js → chunk-F6ESSHQK.js} +17 -23
  25. package/dist/chunk-F6ESSHQK.js.map +1 -0
  26. package/dist/chunk-GQAPBNGT.js +210 -0
  27. package/dist/chunk-GQAPBNGT.js.map +1 -0
  28. package/dist/chunk-JGXRQUTC.js +191 -0
  29. package/dist/chunk-JGXRQUTC.js.map +1 -0
  30. package/dist/{chunk-BXP4K7RF.js → chunk-JVADRLWX.js} +57 -186
  31. package/dist/chunk-JVADRLWX.js.map +1 -0
  32. package/dist/{chunk-ZA43LPRM.js → chunk-KIYUUSPK.js} +2 -2
  33. package/dist/{chunk-QDCJLJUV.js → chunk-KOWGILCN.js} +22 -13
  34. package/dist/chunk-KOWGILCN.js.map +1 -0
  35. package/dist/{chunk-WWVD5DR5.js → chunk-M3QDKKDF.js} +2 -8
  36. package/dist/chunk-M3QDKKDF.js.map +1 -0
  37. package/dist/{chunk-FTDZAKZW.js → chunk-NQPYMUDF.js} +7 -5
  38. package/dist/{chunk-FTDZAKZW.js.map → chunk-NQPYMUDF.js.map} +1 -1
  39. package/dist/{chunk-XP3ASVGJ.js → chunk-NW4SE5XW.js} +2 -2
  40. package/dist/{chunk-KDY5N6J4.js → chunk-OPZ2LVS2.js} +1 -22
  41. package/dist/{chunk-KDY5N6J4.js.map → chunk-OPZ2LVS2.js.map} +1 -1
  42. package/dist/{chunk-5XZWTFGF.js → chunk-PLIXVF7B.js} +3 -3
  43. package/dist/chunk-PLIXVF7B.js.map +1 -0
  44. package/dist/{chunk-Y7YIAWPW.js → chunk-SGHIGTVZ.js} +1 -11
  45. package/dist/{chunk-Y7YIAWPW.js.map → chunk-SGHIGTVZ.js.map} +1 -1
  46. package/dist/{chunk-UL6Q5HDP.js → chunk-TBUKJKY6.js} +3 -25
  47. package/dist/chunk-TBUKJKY6.js.map +1 -0
  48. package/dist/chunk-VFDUKGRZ.js +155 -0
  49. package/dist/chunk-VFDUKGRZ.js.map +1 -0
  50. package/dist/chunk-VT3H43QA.js +288 -0
  51. package/dist/chunk-VT3H43QA.js.map +1 -0
  52. package/dist/chunk-W26PHBME.js +309 -0
  53. package/dist/chunk-W26PHBME.js.map +1 -0
  54. package/dist/components-BANNjAZP.d.ts +30 -0
  55. package/dist/cooldown.d.ts +2 -2
  56. package/dist/cooldown.js +1 -0
  57. package/dist/coordinators/boundary-ricochet-3d.d.ts +4 -4
  58. package/dist/coordinators/boundary-ricochet-3d.js +1 -0
  59. package/dist/coordinators/boundary-ricochet.d.ts +4 -4
  60. package/dist/coordinators/boundary-ricochet.js +3 -2
  61. package/dist/coordinators/first-person-shooter.js +1 -0
  62. package/dist/coordinators/multidirectional-space-shooter.d.ts +3 -3
  63. package/dist/coordinators/multidirectional-space-shooter.js +5 -3
  64. package/dist/coordinators/top-down-shooter.d.ts +3 -3
  65. package/dist/coordinators/top-down-shooter.js +5 -3
  66. package/dist/core.d.ts +288 -8
  67. package/dist/core.js +480 -13
  68. package/dist/core.js.map +1 -1
  69. package/dist/destructible-3d.d.ts +32 -4
  70. package/dist/destructible-3d.js +2 -1
  71. package/dist/destructible-prebake.js +1 -0
  72. package/dist/{entity-types-CmtQ-IBp.d.ts → entity-types-DhfsZbSK.d.ts} +5 -3
  73. package/dist/first-person.d.ts +27 -38
  74. package/dist/first-person.js +8 -8
  75. package/dist/index.d.ts +14 -15
  76. package/dist/index.js +37 -52
  77. package/dist/jumper-2d.d.ts +3 -17
  78. package/dist/jumper-2d.js +4 -9
  79. package/dist/jumper-3d.d.ts +5 -39
  80. package/dist/jumper-3d.js +5 -10
  81. package/dist/{moveable-Cl9h-_w7.d.ts → moveable-XhzWPAw5.d.ts} +21 -4
  82. package/dist/particle-emitter/presets.js +1 -0
  83. package/dist/particle-emitter.d.ts +3 -3
  84. package/dist/particle-emitter.js +3 -2
  85. package/dist/platformer-2d.d.ts +13 -82
  86. package/dist/platformer-2d.js +4 -5
  87. package/dist/platformer-3d.d.ts +13 -78
  88. package/dist/platformer-3d.js +4 -5
  89. package/dist/ricochet-2d.d.ts +3 -3
  90. package/dist/ricochet-2d.js +4 -3
  91. package/dist/ricochet-3d.d.ts +3 -3
  92. package/dist/ricochet-3d.js +4 -3
  93. package/dist/runtime-2d.d.ts +2 -2
  94. package/dist/runtime-2d.js +1 -0
  95. package/dist/runtime-2d.js.map +1 -1
  96. package/dist/screen-visibility.d.ts +2 -2
  97. package/dist/screen-visibility.js +1 -0
  98. package/dist/screen-wrap.d.ts +2 -2
  99. package/dist/screen-wrap.js +4 -3
  100. package/dist/shooter-2d.d.ts +3 -3
  101. package/dist/shooter-2d.js +4 -3
  102. package/dist/thruster.d.ts +5 -34
  103. package/dist/thruster.js +4 -6
  104. package/dist/top-down-movement.d.ts +9 -27
  105. package/dist/top-down-movement.js +6 -6
  106. package/dist/{vector-Bm65-FOG.d.ts → vector-DjhLUrak.d.ts} +2 -4
  107. package/dist/world-boundary-2d.d.ts +2 -2
  108. package/dist/world-boundary-2d.js +5 -4
  109. package/dist/world-boundary-3d.d.ts +2 -2
  110. package/dist/world-boundary-3d.js +4 -3
  111. package/package.json +2 -3
  112. package/dist/chunk-27UPCP5B.js.map +0 -1
  113. package/dist/chunk-4L36OPY2.js.map +0 -1
  114. package/dist/chunk-4URF65BR.js +0 -44
  115. package/dist/chunk-4URF65BR.js.map +0 -1
  116. package/dist/chunk-5XZWTFGF.js.map +0 -1
  117. package/dist/chunk-67XLJ26X.js +0 -536
  118. package/dist/chunk-67XLJ26X.js.map +0 -1
  119. package/dist/chunk-75FJIUIG.js +0 -240
  120. package/dist/chunk-75FJIUIG.js.map +0 -1
  121. package/dist/chunk-A4CA35DQ.js.map +0 -1
  122. package/dist/chunk-BXP4K7RF.js.map +0 -1
  123. package/dist/chunk-F72WX4MH.js +0 -422
  124. package/dist/chunk-F72WX4MH.js.map +0 -1
  125. package/dist/chunk-GFARAJV2.js.map +0 -1
  126. package/dist/chunk-JXMF4NUI.js +0 -309
  127. package/dist/chunk-JXMF4NUI.js.map +0 -1
  128. package/dist/chunk-OTLSUYQQ.js +0 -29
  129. package/dist/chunk-OTLSUYQQ.js.map +0 -1
  130. package/dist/chunk-Q75LKHDF.js +0 -56
  131. package/dist/chunk-Q75LKHDF.js.map +0 -1
  132. package/dist/chunk-QDCJLJUV.js.map +0 -1
  133. package/dist/chunk-RDHSHEZM.js +0 -479
  134. package/dist/chunk-RDHSHEZM.js.map +0 -1
  135. package/dist/chunk-UIG7MWS2.js +0 -518
  136. package/dist/chunk-UIG7MWS2.js.map +0 -1
  137. package/dist/chunk-UL6Q5HDP.js.map +0 -1
  138. package/dist/chunk-VMQHNJJI.js.map +0 -1
  139. package/dist/chunk-WWVD5DR5.js.map +0 -1
  140. package/dist/chunk-Z72F2ENM.js.map +0 -1
  141. package/dist/components-BWG1GkZA.d.ts +0 -20
  142. package/dist/use-behavior-B85d5u7-.d.ts +0 -13
  143. /package/dist/{chunk-5SM5SH5O.js.map → chunk-7JLWZXPA.js.map} +0 -0
  144. /package/dist/{chunk-ZA43LPRM.js.map → chunk-KIYUUSPK.js.map} +0 -0
  145. /package/dist/{chunk-XP3ASVGJ.js.map → chunk-NW4SE5XW.js.map} +0 -0
@@ -1,240 +0,0 @@
1
- import {
2
- createThrusterInputComponent,
3
- createThrusterMovementComponent
4
- } from "./chunk-IZJFUAXB.js";
5
- import {
6
- getRotationAngle2D,
7
- normalizeDirection2DInto
8
- } from "./chunk-Y7YIAWPW.js";
9
- import {
10
- SyncStateMachine,
11
- t
12
- } from "./chunk-4URF65BR.js";
13
- import {
14
- defineBehavior
15
- } from "./chunk-EZNCCO4L.js";
16
-
17
- // src/lib/behaviors/thruster/thruster-fsm.ts
18
- var ThrusterState = /* @__PURE__ */ ((ThrusterState2) => {
19
- ThrusterState2["Idle"] = "idle";
20
- ThrusterState2["Active"] = "active";
21
- ThrusterState2["Boosting"] = "boosting";
22
- ThrusterState2["Disabled"] = "disabled";
23
- ThrusterState2["Docked"] = "docked";
24
- return ThrusterState2;
25
- })(ThrusterState || {});
26
- var ThrusterEvent = /* @__PURE__ */ ((ThrusterEvent2) => {
27
- ThrusterEvent2["Activate"] = "activate";
28
- ThrusterEvent2["Deactivate"] = "deactivate";
29
- ThrusterEvent2["Boost"] = "boost";
30
- ThrusterEvent2["EndBoost"] = "endBoost";
31
- ThrusterEvent2["Disable"] = "disable";
32
- ThrusterEvent2["Enable"] = "enable";
33
- ThrusterEvent2["Dock"] = "dock";
34
- ThrusterEvent2["Undock"] = "undock";
35
- return ThrusterEvent2;
36
- })(ThrusterEvent || {});
37
- var ThrusterFSM = class {
38
- constructor(ctx) {
39
- this.ctx = ctx;
40
- this.machine = new SyncStateMachine(
41
- "idle" /* Idle */,
42
- [
43
- // Core transitions
44
- t("idle" /* Idle */, "activate" /* Activate */, "active" /* Active */),
45
- t("active" /* Active */, "deactivate" /* Deactivate */, "idle" /* Idle */),
46
- t("active" /* Active */, "boost" /* Boost */, "boosting" /* Boosting */),
47
- t("active" /* Active */, "disable" /* Disable */, "disabled" /* Disabled */),
48
- t("active" /* Active */, "dock" /* Dock */, "docked" /* Docked */),
49
- t("boosting" /* Boosting */, "endBoost" /* EndBoost */, "active" /* Active */),
50
- t("boosting" /* Boosting */, "disable" /* Disable */, "disabled" /* Disabled */),
51
- t("disabled" /* Disabled */, "enable" /* Enable */, "idle" /* Idle */),
52
- t("docked" /* Docked */, "undock" /* Undock */, "idle" /* Idle */),
53
- // Self-transitions (no-ops for redundant events)
54
- t("idle" /* Idle */, "deactivate" /* Deactivate */, "idle" /* Idle */),
55
- t("active" /* Active */, "activate" /* Activate */, "active" /* Active */)
56
- ]
57
- );
58
- }
59
- ctx;
60
- machine;
61
- /**
62
- * Get current state
63
- */
64
- getState() {
65
- return this.machine.getState();
66
- }
67
- /**
68
- * Dispatch an event to transition state
69
- */
70
- dispatch(event) {
71
- if (this.machine.can(event)) {
72
- this.machine.syncDispatch(event);
73
- }
74
- }
75
- /**
76
- * Update FSM state based on player input.
77
- * Auto-transitions between Idle/Active to report current state.
78
- * Does NOT modify input - just observes and reports.
79
- */
80
- update(playerInput) {
81
- const state = this.machine.getState();
82
- const hasInput = Math.abs(playerInput.thrust) > 0.01 || Math.abs(playerInput.rotate) > 0.01 || Math.abs(playerInput.thrustX ?? 0) > 0.01 || Math.abs(playerInput.thrustY ?? 0) > 0.01;
83
- if (hasInput && state === "idle" /* Idle */) {
84
- this.dispatch("activate" /* Activate */);
85
- } else if (!hasInput && state === "active" /* Active */) {
86
- this.dispatch("deactivate" /* Deactivate */);
87
- }
88
- }
89
- };
90
-
91
- // src/lib/behaviors/thruster/thruster.system.ts
92
- var _thrustDirection = { x: 0, y: 0 };
93
- var ThrusterSystem = class {
94
- constructor(world) {
95
- this.world = world;
96
- }
97
- world;
98
- /**
99
- * Update a single thruster-enabled entity.
100
- */
101
- updateEntity(gameEntity, _dt) {
102
- if (!gameEntity.physics?.body || !gameEntity.thruster || !gameEntity.$thruster) {
103
- return;
104
- }
105
- const e = {
106
- physics: gameEntity.physics,
107
- thruster: gameEntity.thruster,
108
- $thruster: gameEntity.$thruster
109
- };
110
- const body = e.physics.body;
111
- const thruster = e.thruster;
112
- const input = e.$thruster;
113
- if (thruster.linearDamping != null && typeof body.setLinearDamping === "function") {
114
- body.setLinearDamping(thruster.linearDamping);
115
- }
116
- const rotationZ = getRotationAngle2D(body.rotation());
117
- const currentVel = body.linvel();
118
- const hasVectorThrust = normalizeDirection2DInto(input.thrustX, input.thrustY, _thrustDirection);
119
- if (hasVectorThrust) {
120
- const thrustScale = Math.min(1, Math.hypot(input.thrustX, input.thrustY));
121
- const thrustAmount = thruster.linearThrust * thrustScale * 0.1;
122
- body.setLinvel({
123
- x: currentVel.x + _thrustDirection.x * thrustAmount,
124
- y: currentVel.y + _thrustDirection.y * thrustAmount,
125
- z: currentVel.z
126
- }, true);
127
- } else if (input.thrust !== 0) {
128
- const forwardX = Math.sin(-rotationZ);
129
- const forwardY = Math.cos(-rotationZ);
130
- const thrustAmount = thruster.linearThrust * input.thrust * 0.1;
131
- body.setLinvel({
132
- x: currentVel.x + forwardX * thrustAmount,
133
- y: currentVel.y + forwardY * thrustAmount,
134
- z: currentVel.z
135
- }, true);
136
- }
137
- if (input.rotate !== 0) {
138
- body.setAngvel({ x: 0, y: 0, z: -thruster.angularThrust * input.rotate }, true);
139
- } else {
140
- const angVel = body.angvel();
141
- body.setAngvel({ x: angVel.x, y: angVel.y, z: 0 }, true);
142
- }
143
- }
144
- update(dt) {
145
- if (!this.world?.collisionMap) return;
146
- for (const [, entity] of this.world.collisionMap) {
147
- this.updateEntity(entity, dt);
148
- }
149
- }
150
- };
151
-
152
- // src/lib/behaviors/thruster/thruster.descriptor.ts
153
- var defaultOptions = {
154
- linearThrust: 10,
155
- angularThrust: 5,
156
- linearDamping: void 0
157
- };
158
- var THRUSTER_BEHAVIOR_KEY = /* @__PURE__ */ Symbol.for("zylem:behavior:thruster");
159
- var ThrusterBehaviorSystem = class {
160
- constructor(world, wasmStage, getBehaviorLinks) {
161
- this.wasmStage = wasmStage;
162
- this.getBehaviorLinks = getBehaviorLinks;
163
- this.movementBehavior = new ThrusterSystem(world);
164
- }
165
- wasmStage;
166
- getBehaviorLinks;
167
- movementBehavior;
168
- attachedRuntimeSlots = /* @__PURE__ */ new Set();
169
- update(_ecs, delta) {
170
- const links = this.getBehaviorLinks?.(THRUSTER_BEHAVIOR_KEY);
171
- if (!links) return;
172
- for (const link of links) {
173
- const gameEntity = link.entity;
174
- const thrusterRef = link.ref;
175
- const options = thrusterRef.options;
176
- if (!gameEntity.thruster) {
177
- gameEntity.thruster = createThrusterMovementComponent(
178
- options.linearThrust,
179
- options.angularThrust,
180
- { linearDamping: options.linearDamping }
181
- );
182
- }
183
- if (!gameEntity.$thruster) {
184
- gameEntity.$thruster = createThrusterInputComponent();
185
- }
186
- const handle = gameEntity.runtimeHandle ?? -1;
187
- if (this.wasmStage && handle >= 0) {
188
- this.ensureWasmAttached(handle, options);
189
- const input = gameEntity.$thruster;
190
- if (input) {
191
- this.wasmStage.writeInputAxes(handle, input.thrust, input.rotate);
192
- }
193
- continue;
194
- }
195
- if (!thrusterRef.fsm && gameEntity.$thruster) {
196
- thrusterRef.fsm = new ThrusterFSM({ input: gameEntity.$thruster });
197
- }
198
- if (thrusterRef.fsm && gameEntity.$thruster) {
199
- thrusterRef.fsm.update({
200
- thrust: gameEntity.$thruster.thrust,
201
- rotate: gameEntity.$thruster.rotate,
202
- thrustX: gameEntity.$thruster.thrustX,
203
- thrustY: gameEntity.$thruster.thrustY
204
- });
205
- }
206
- if (!gameEntity.body) continue;
207
- if (!gameEntity.physics) {
208
- gameEntity.physics = { body: gameEntity.body };
209
- }
210
- this.movementBehavior.updateEntity(gameEntity, delta);
211
- }
212
- }
213
- ensureWasmAttached(handle, options) {
214
- if (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;
215
- this.wasmStage.attachThruster(handle, {
216
- maxSpeed: 50,
217
- acceleration: options.linearThrust,
218
- turnRateRadPerSec: options.angularThrust,
219
- linearDamping: options.linearDamping ?? 0
220
- });
221
- this.attachedRuntimeSlots.add(handle);
222
- }
223
- destroy(_ecs) {
224
- this.attachedRuntimeSlots.clear();
225
- }
226
- };
227
- var ThrusterBehavior = defineBehavior({
228
- name: "thruster",
229
- defaultOptions,
230
- systemFactory: (ctx) => new ThrusterBehaviorSystem(ctx.world, ctx.wasmStage ?? null, ctx.getBehaviorLinks)
231
- });
232
-
233
- export {
234
- ThrusterState,
235
- ThrusterEvent,
236
- ThrusterFSM,
237
- ThrusterSystem,
238
- ThrusterBehavior
239
- };
240
- //# sourceMappingURL=chunk-75FJIUIG.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/behaviors/thruster/thruster-fsm.ts","../src/lib/behaviors/thruster/thruster.system.ts","../src/lib/behaviors/thruster/thruster.descriptor.ts"],"sourcesContent":["/**\n * ThrusterFSM\n * \n * State machine controller for thruster behavior.\n * FSM does NOT touch physics or ThrusterSystem - it only writes ThrusterInputComponent.\n */\n\nimport { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\nimport type { ThrusterInputComponent } from './components';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FSM State Model\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport enum ThrusterState {\n\tIdle = 'idle',\n\tActive = 'active',\n\tBoosting = 'boosting',\n\tDisabled = 'disabled',\n\tDocked = 'docked',\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FSM Events\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport enum ThrusterEvent {\n\tActivate = 'activate',\n\tDeactivate = 'deactivate',\n\tBoost = 'boost',\n\tEndBoost = 'endBoost',\n\tDisable = 'disable',\n\tEnable = 'enable',\n\tDock = 'dock',\n\tUndock = 'undock',\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FSM Context Object\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ThrusterFSMContext {\n\tinput: ThrusterInputComponent;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Player Input (raw input from controller/keyboard)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface PlayerInput {\n\tthrust: number;\n\trotate: number;\n\tthrustX?: number;\n\tthrustY?: number;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ThrusterFSM Controller\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport class ThrusterFSM {\n\tmachine: SyncStateMachine<ThrusterState, ThrusterEvent, never>;\n\n\tconstructor(private ctx: ThrusterFSMContext) {\n\t\tthis.machine = new SyncStateMachine<ThrusterState, ThrusterEvent, never>(\n\t\t\tThrusterState.Idle,\n\t\t\t[\n\t\t\t\t// Core transitions\n\t\t\t\tt(ThrusterState.Idle, ThrusterEvent.Activate, ThrusterState.Active),\n\t\t\t\tt(ThrusterState.Active, ThrusterEvent.Deactivate, ThrusterState.Idle),\n\t\t\t\tt(ThrusterState.Active, ThrusterEvent.Boost, ThrusterState.Boosting),\n\t\t\t\tt(ThrusterState.Active, ThrusterEvent.Disable, ThrusterState.Disabled),\n\t\t\t\tt(ThrusterState.Active, ThrusterEvent.Dock, ThrusterState.Docked),\n\t\t\t\tt(ThrusterState.Boosting, ThrusterEvent.EndBoost, ThrusterState.Active),\n\t\t\t\tt(ThrusterState.Boosting, ThrusterEvent.Disable, ThrusterState.Disabled),\n\t\t\t\tt(ThrusterState.Disabled, ThrusterEvent.Enable, ThrusterState.Idle),\n\t\t\t\tt(ThrusterState.Docked, ThrusterEvent.Undock, ThrusterState.Idle),\n\t\t\t\t// Self-transitions (no-ops for redundant events)\n\t\t\t\tt(ThrusterState.Idle, ThrusterEvent.Deactivate, ThrusterState.Idle),\n\t\t\t\tt(ThrusterState.Active, ThrusterEvent.Activate, ThrusterState.Active),\n\t\t\t]\n\t\t);\n\t}\n\n\t/**\n\t * Get current state\n\t */\n\tgetState(): ThrusterState {\n\t\treturn this.machine.getState();\n\t}\n\n\t/**\n\t * Dispatch an event to transition state\n\t */\n\tdispatch(event: ThrusterEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n\n\t/**\n\t * Update FSM state based on player input.\n\t * Auto-transitions between Idle/Active to report current state.\n\t * Does NOT modify input - just observes and reports.\n\t */\n\tupdate(playerInput: PlayerInput): void {\n\t\tconst state = this.machine.getState();\n\t\tconst hasInput =\n\t\t\tMath.abs(playerInput.thrust) > 0.01\n\t\t\t|| Math.abs(playerInput.rotate) > 0.01\n\t\t\t|| Math.abs(playerInput.thrustX ?? 0) > 0.01\n\t\t\t|| Math.abs(playerInput.thrustY ?? 0) > 0.01;\n\n\t\t// Auto-transition to report state based on input\n\t\tif (hasInput && state === ThrusterState.Idle) {\n\t\t\tthis.dispatch(ThrusterEvent.Activate);\n\t\t} else if (!hasInput && state === ThrusterState.Active) {\n\t\t\tthis.dispatch(ThrusterEvent.Deactivate);\n\t\t}\n\t}\n}\n","/**\n * ThrusterSystem\n * \n * This is the heart of the thruster movement system - a pure, stateless force generator.\n * Works identically for player, AI, and replay.\n */\n\nimport type { ZylemWorld } from '../../collision/world';\nimport type { PhysicsBodyComponent } from '../components';\nimport type { ThrusterMovementComponent, ThrusterInputComponent } from './components';\nimport {\n\tgetRotationAngle2D,\n\tnormalizeDirection2DInto,\n\ttype Direction2D,\n} from '../shared/direction-2d';\n\n// Per-frame scratch; normalizeDirection2DInto writes here instead of\n// allocating a fresh direction object per entity per frame.\nconst _thrustDirection: Direction2D = { x: 0, y: 0 };\n\n/**\n * Entity with thruster components\n */\nexport interface ThrusterEntity {\n\tphysics: PhysicsBodyComponent;\n\tthruster: ThrusterMovementComponent;\n\t$thruster: ThrusterInputComponent;\n}\n\n/**\n * ThrusterSystem - Force generator for thruster-equipped entities\n * \n * Responsibilities:\n * - Query entities with PhysicsBody, ThrusterMovement, and ThrusterInput components\n * - Apply velocities based on thrust input (2D mode)\n * - Apply angular velocity based on rotation input\n */\nexport class ThrusterSystem {\n\tconstructor(private world: ZylemWorld | null) {}\n\n\t/**\n\t * Update a single thruster-enabled entity.\n\t */\n\tupdateEntity(gameEntity: any, _dt: number): void {\n\t\tif (!gameEntity.physics?.body || !gameEntity.thruster || !gameEntity.$thruster) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst e: ThrusterEntity = {\n\t\t\tphysics: gameEntity.physics,\n\t\t\tthruster: gameEntity.thruster,\n\t\t\t$thruster: gameEntity.$thruster,\n\t\t};\n\n\t\tconst body = e.physics.body;\n\t\tconst thruster = e.thruster;\n\t\tconst input = e.$thruster;\n\n\t\tif (thruster.linearDamping != null && typeof body.setLinearDamping === 'function') {\n\t\t\tbody.setLinearDamping(thruster.linearDamping);\n\t\t}\n\n\t\t// Get Z rotation from quaternion (for 2D sprites)\n\t\tconst rotationZ = getRotationAngle2D(body.rotation());\n\t\tconst currentVel = body.linvel();\n\t\tconst hasVectorThrust = normalizeDirection2DInto(input.thrustX, input.thrustY, _thrustDirection);\n\n\t\t// --- Linear thrust ---\n\t\tif (hasVectorThrust) {\n\t\t\tconst thrustScale = Math.min(1, Math.hypot(input.thrustX, input.thrustY));\n\t\t\tconst thrustAmount = thruster.linearThrust * thrustScale * 0.1;\n\t\t\tbody.setLinvel({\n\t\t\t\tx: currentVel.x + _thrustDirection.x * thrustAmount,\n\t\t\t\ty: currentVel.y + _thrustDirection.y * thrustAmount,\n\t\t\t\tz: currentVel.z,\n\t\t\t}, true);\n\t\t} else if (input.thrust !== 0) {\n\t\t\tconst forwardX = Math.sin(-rotationZ);\n\t\t\tconst forwardY = Math.cos(-rotationZ);\n\t\t\tconst thrustAmount = thruster.linearThrust * input.thrust * 0.1;\n\t\t\tbody.setLinvel({\n\t\t\t\tx: currentVel.x + forwardX * thrustAmount,\n\t\t\t\ty: currentVel.y + forwardY * thrustAmount,\n\t\t\t\tz: currentVel.z\n\t\t\t}, true);\n\t\t}\n\n\t\t// --- Angular thrust (Z-axis for 2D) ---\n\t\tif (input.rotate !== 0) {\n\t\t\tbody.setAngvel({ x: 0, y: 0, z: -thruster.angularThrust * input.rotate }, true);\n\t\t} else {\n\t\t\t// Stop rotation when no input\n\t\t\tconst angVel = body.angvel();\n\t\t\tbody.setAngvel({ x: angVel.x, y: angVel.y, z: 0 }, true);\n\t\t}\n\t}\n\n\tupdate(dt: number): void {\n\t\tif (!this.world?.collisionMap) return;\n\t\tfor (const [, entity] of this.world.collisionMap) {\n\t\t\tthis.updateEntity(entity, dt);\n\t\t}\n\t}\n}\n","/**\n * Thruster Behavior Descriptor\n * \n * Type-safe descriptor for the thruster behavior system using the new entity.use() API.\n * This wraps the existing ThrusterSystem and components.\n */\n\nimport { defineBehavior } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport { ThrusterSystem, ThrusterEntity } from './thruster.system';\nimport { ThrusterFSM } from './thruster-fsm';\nimport {\n\tcreateThrusterInputComponent,\n\tcreateThrusterMovementComponent,\n\ttype ThrusterMovementComponent,\n\ttype ThrusterInputComponent,\n} from './components';\nimport type { WasmStageRuntime } from '../../runtime/wasm-stage-runtime';\n\n/**\n * Thruster behavior options (typed for entity.use() autocomplete)\n */\nexport interface ThrusterBehaviorOptions {\n\t/** Forward thrust force (default: 10) */\n\tlinearThrust: number;\n\t/** Rotation torque (default: 5) */\n\tangularThrust: number;\n\t/** Optional linear damping override */\n\tlinearDamping?: number;\n}\n\nconst defaultOptions: ThrusterBehaviorOptions = {\n\tlinearThrust: 10,\n\tangularThrust: 5,\n\tlinearDamping: undefined,\n};\n\nconst THRUSTER_BEHAVIOR_KEY = Symbol.for('zylem:behavior:thruster');\n\n/**\n * Adapter that wraps ThrusterSystem as a BehaviorSystem.\n * \n * This bridges the entity.use() pattern with the ECS component-based approach:\n * - Reads options from entity behaviorRefs\n * - Initializes ThrusterMovementComponent and ThrusterInputComponent on entities\n * - Creates FSM lazily and attaches to BehaviorRef for access via handle.getFSM()\n * - Delegates physics to ThrusterSystem\n * \n * NOTE: Input is controlled by the user via entity.onUpdate() - set entity.input.thrust/rotate\n */\nclass ThrusterBehaviorSystem implements BehaviorSystem {\n\tprivate movementBehavior: ThrusterSystem;\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tworld: import('../../collision/world').ZylemWorld | null,\n\t\tprivate wasmStage: WasmStageRuntime | null,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) {\n\t\tthis.movementBehavior = new ThrusterSystem(world);\n\t}\n\n\tupdate(_ecs: unknown, delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(THRUSTER_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst gameEntity = link.entity as any;\n\t\t\tconst thrusterRef = link.ref as any;\n\n\t\t\tconst options = thrusterRef.options as ThrusterBehaviorOptions;\n\n\t\t\tif (!gameEntity.thruster) {\n\t\t\t\tgameEntity.thruster = createThrusterMovementComponent(\n\t\t\t\t\toptions.linearThrust,\n\t\t\t\t\toptions.angularThrust,\n\t\t\t\t\t{ linearDamping: options.linearDamping },\n\t\t\t\t) as ThrusterMovementComponent;\n\t\t\t}\n\n\t\t\tif (!gameEntity.$thruster) {\n\t\t\t\tgameEntity.$thruster = createThrusterInputComponent() as ThrusterInputComponent;\n\t\t\t}\n\n\t\t\t// Wasm fast path: the Rust runtime owns the thruster simulation;\n\t\t\t// skip the (input-mirroring) TS FSM entirely.\n\t\t\tconst handle = (gameEntity.runtimeHandle ?? -1) as number;\n\t\t\tif (this.wasmStage && handle >= 0) {\n\t\t\t\tthis.ensureWasmAttached(handle, options);\n\t\t\t\tconst input = gameEntity.$thruster as ThrusterInputComponent | undefined;\n\t\t\t\tif (input) {\n\t\t\t\t\tthis.wasmStage.writeInputAxes(handle, input.thrust, input.rotate);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!thrusterRef.fsm && gameEntity.$thruster) {\n\t\t\t\tthrusterRef.fsm = new ThrusterFSM({ input: gameEntity.$thruster });\n\t\t\t}\n\n\t\t\tif (thrusterRef.fsm && gameEntity.$thruster) {\n\t\t\t\tthrusterRef.fsm.update({\n\t\t\t\t\tthrust: gameEntity.$thruster.thrust,\n\t\t\t\t\trotate: gameEntity.$thruster.rotate,\n\t\t\t\t\tthrustX: gameEntity.$thruster.thrustX,\n\t\t\t\t\tthrustY: gameEntity.$thruster.thrustY,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (!gameEntity.body) continue;\n\t\t\tif (!gameEntity.physics) {\n\t\t\t\tgameEntity.physics = { body: gameEntity.body };\n\t\t\t}\n\t\t\tthis.movementBehavior.updateEntity(gameEntity, delta);\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: ThrusterBehaviorOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tthis.wasmStage.attachThruster(handle, {\n\t\t\tmaxSpeed: 50,\n\t\t\tacceleration: options.linearThrust,\n\t\t\tturnRateRadPerSec: options.angularThrust,\n\t\t\tlinearDamping: options.linearDamping ?? 0,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\n/**\n * ThrusterBehavior - typed descriptor for thruster movement.\n * \n * Uses the existing ThrusterSystem under the hood.\n * \n * @example\n * ```typescript\n * import { ThrusterBehavior } from \"@zylem/game-lib/behavior\";\n * \n * const ship = createSprite({ ... });\n * ship.use(ThrusterBehavior, { linearThrust: 15, angularThrust: 8 });\n * ```\n */\nexport const ThrusterBehavior = defineBehavior<ThrusterBehaviorOptions, Record<string, never>, ThrusterEntity>({\n\tname: 'thruster',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew ThrusterBehaviorSystem(ctx.world, ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n});\n"],"mappings":"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","names":["ThrusterState","ThrusterEvent"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/behaviors/top-down-movement/top-down-movement.system.ts","../src/lib/behaviors/top-down-movement/top-down-movement.descriptor.ts"],"sourcesContent":["import {\n\tangleFromDirection2D,\n\tnormalizeDirection2DInto,\n\ttype Direction2D,\n} from '../shared/direction-2d';\nimport type {\n\tTopDownMovementComponent,\n\tTopDownMovementInputComponent,\n\tTopDownMovementStateComponent,\n} from './components';\n\n// Per-frame scratch objects; normalizeDirection2DInto writes here instead of\n// allocating fresh direction objects per entity per frame.\nconst _moveDirection: Direction2D = { x: 0, y: 0 };\nconst _facingDirection: Direction2D = { x: 0, y: 0 };\n\nexport interface TopDownMovementEntity {\n\tbody: {\n\t\tlinvel(): { x: number; y: number; z: number };\n\t};\n\ttransformStore?: {\n\t\tvelocity: { x: number; y: number; z: number };\n\t\tdirty: { velocityX: boolean; velocityY: boolean; velocityZ: boolean };\n\t};\n\tsetRotationZ?: (angle: number) => void;\n\ttopDownMovement: TopDownMovementComponent;\n\t$topDownMovement: TopDownMovementInputComponent;\n\ttopDownMovementState: TopDownMovementStateComponent;\n}\n\nexport class TopDownMovementSystem {\n\tupdateEntity(entity: TopDownMovementEntity, _delta: number): void {\n\t\tif (\n\t\t\t!entity.body\n\t\t\t|| !entity.transformStore\n\t\t\t|| !entity.topDownMovement\n\t\t\t|| !entity.$topDownMovement\n\t\t\t|| !entity.topDownMovementState\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst movement = entity.topDownMovement;\n\t\tconst input = entity.$topDownMovement;\n\t\tconst state = entity.topDownMovementState;\n\t\tconst isMoving = normalizeDirection2DInto(input.moveX, input.moveY, _moveDirection);\n\t\tconst velocity = entity.body.linvel();\n\n\t\tstate.moving = isMoving;\n\t\tentity.transformStore.velocity.x = isMoving ? _moveDirection.x * movement.moveSpeed : 0;\n\t\tentity.transformStore.velocity.y = isMoving ? _moveDirection.y * movement.moveSpeed : 0;\n\t\tentity.transformStore.velocity.z = velocity.z;\n\t\tentity.transformStore.dirty.velocityX = true;\n\t\tentity.transformStore.dirty.velocityY = true;\n\t\tentity.transformStore.dirty.velocityZ = true;\n\n\t\tif (normalizeDirection2DInto(input.faceX, input.faceY, _facingDirection)) {\n\t\t\tstate.facingAngle = angleFromDirection2D(_facingDirection);\n\t\t}\n\n\t\tentity.setRotationZ?.(state.facingAngle);\n\t}\n}\n","import { defineBehavior, type BehaviorRef } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport {\n\tcreateTopDownMovementComponent,\n\tcreateTopDownMovementInputComponent,\n\tcreateTopDownMovementStateComponent,\n} from './components';\nimport {\n\tTopDownMovementSystem,\n\ttype TopDownMovementEntity,\n} from './top-down-movement.system';\nimport {\n\tStageTopDownPlane,\n\ttype WasmStageRuntime,\n} from '../../runtime/wasm-stage-runtime';\n\nexport interface TopDownMovementBehaviorOptions {\n\tmoveSpeed?: number;\n}\n\nexport interface TopDownMovementHandle {\n\tgetFacingAngle(): number;\n}\n\nconst defaultOptions: TopDownMovementBehaviorOptions = {\n\tmoveSpeed: 8,\n};\n\nconst TOP_DOWN_MOVEMENT_BEHAVIOR_KEY = Symbol.for(\n\t'zylem:behavior:top-down-movement',\n);\n\nfunction createTopDownMovementHandle(\n\tref: BehaviorRef<TopDownMovementBehaviorOptions>,\n): TopDownMovementHandle {\n\treturn {\n\t\tgetFacingAngle: () =>\n\t\t\t(ref as any).__entity?.topDownMovementState?.facingAngle ?? 0,\n\t};\n}\n\nclass TopDownMovementBehaviorSystem implements BehaviorSystem {\n\tprivate behavior = new TopDownMovementSystem();\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate wasmStage: WasmStageRuntime | null,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t) {}\n\n\tupdate(_ecs: unknown, delta: number): void {\n\t\tconst links = this.getBehaviorLinks?.(TOP_DOWN_MOVEMENT_BEHAVIOR_KEY);\n\t\tif (!links) return;\n\n\t\tfor (const link of links) {\n\t\t\tconst entity = link.entity as any;\n\t\t\tconst ref = link.ref as any;\n\n\t\t\tif (!entity.topDownMovement) {\n\t\t\t\tentity.topDownMovement = createTopDownMovementComponent(ref.options);\n\t\t\t}\n\t\t\tif (!entity.$topDownMovement) {\n\t\t\t\tentity.$topDownMovement = createTopDownMovementInputComponent();\n\t\t\t}\n\t\t\tif (!entity.topDownMovementState) {\n\t\t\t\tentity.topDownMovementState = createTopDownMovementStateComponent();\n\t\t\t}\n\n\t\t\tref.__entity = entity;\n\n\t\t\tconst handle = (entity.runtimeHandle ?? -1) as number;\n\t\t\tif (this.wasmStage && handle >= 0) {\n\t\t\t\tthis.ensureWasmAttached(handle, ref.options as TopDownMovementBehaviorOptions);\n\t\t\t\tconst input = entity.$topDownMovement;\n\t\t\t\tif (input) {\n\t\t\t\t\tthis.wasmStage.writeInputAxes(handle, input.moveX ?? 0, input.moveY ?? input.moveZ ?? 0);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!entity.body || !entity.transformStore) continue;\n\t\t\tthis.behavior.updateEntity(entity, delta);\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: TopDownMovementBehaviorOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tthis.wasmStage.attachTopDown(handle, {\n\t\t\tplane: StageTopDownPlane.Xy,\n\t\t\tspeed: options.moveSpeed ?? defaultOptions.moveSpeed!,\n\t\t\tfaceMovement: true,\n\t\t});\n\t\tthis.attachedRuntimeSlots.add(handle);\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tthis.attachedRuntimeSlots.clear();\n\t}\n}\n\nexport const TopDownMovementBehavior = defineBehavior<\n\tTopDownMovementBehaviorOptions,\n\tTopDownMovementHandle,\n\tTopDownMovementEntity\n>({\n\tname: 'top-down-movement',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew TopDownMovementBehaviorSystem(ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n\tcreateHandle: createTopDownMovementHandle,\n});\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/behaviors/destructible-3d/destructible-3d.descriptor.ts","../src/lib/physics/physics-pose.ts","../src/lib/behaviors/destructible-3d/index.ts"],"sourcesContent":["import {\n\tActiveCollisionTypes,\n\tColliderDesc,\n\tRigidBodyDesc,\n} from '@dimforge/rapier3d-compat';\nimport {\n\tDestructibleMesh,\n\tFractureOptions as PinataFractureOptions,\n} from '@dgreenheck/three-pinata';\nimport {\n\tBox3,\n\tBufferAttribute,\n\tBufferGeometry,\n\tGroup,\n\tMatrix4,\n\tQuaternion,\n\tVector2,\n\tVector3,\n\ttype Material,\n\ttype Mesh,\n\ttype Object3D,\n} from 'three';\n\nimport * as Comlink from 'comlink';\n\nimport { defineBehavior, type BehaviorRef } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport type { CreateEntityFn, GameEntity } from '../../entities/entity';\nimport { getBodyRenderPose } from '../../physics/physics-pose';\n\nimport {\n\tbuildFractureGeometryCacheKey,\n\tbuildNormalizedFractureSourceGeometry,\n\tbufferGeometryToPlain,\n\ttype DestructiblePrebakeWorkerAPI,\n\tpinataFractureOptionsToPlain,\n\tplainWorkerResultToTemplateParts,\n} from '../../destructible-prebake';\n\nexport type FractureOptionsInput =\n\tNonNullable<ConstructorParameters<typeof PinataFractureOptions>[0]>;\n\nexport type Destructible3DFragmentColliderShape =\n\t| 'convexHull'\n\t| 'cuboid'\n\t| 'trimesh';\n\nexport interface Destructible3DColliderOptions {\n\tshape?: Destructible3DFragmentColliderShape;\n\tsensor?: boolean;\n\tcollisionGroups?: number;\n\tactiveCollisionTypes?: number;\n}\n\nexport interface Destructible3DFragmentPhysicsOptions {\n\tmode?: 'compound' | 'independent';\n\tinheritSourceVelocity?: boolean;\n\toutwardVelocity?: number;\n\tangularVelocity?: number;\n}\n\nexport interface Destructible3DBehaviorOptions {\n\tfractureOptions?: FractureOptionsInput | PinataFractureOptions;\n\tinnerMaterial?: Material | null;\n\tcollider?: Destructible3DColliderOptions;\n\tfragmentPhysics?: Destructible3DFragmentPhysicsOptions;\n\t/**\n\t * When set, {@link Destructible3DHandle.prebakeAsync} runs Voronoi fracture\n\t * in a Web Worker (see `destructible-prebake-worker` bundle).\n\t */\n\tprebakeWorkerUrl?: URL | string;\n}\n\nexport interface Destructible3DHandle {\n\tfracture(\n\t\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n\t): readonly DestructibleMesh[];\n\tprebake(\n\t\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n\t): void;\n\tprebakeAsync(\n\t\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n\t): Promise<void>;\n\trepair(): void;\n\tisFractured(): boolean;\n\tgetFragments(): readonly DestructibleMesh[];\n}\n\ninterface PrebakedFragmentTemplate {\n\tgeometry: BufferGeometry;\n\tposition: Vector3;\n\tquaternion: Quaternion;\n\tscale: Vector3;\n}\n\ninterface RuntimeState {\n\tfragmentContainer: Group | null;\n\tfragmentEntities: GameEntity<any>[];\n\tfragments: DestructibleMesh[];\n\tprebakedFragments: PrebakedFragmentTemplate[];\n\tprebakedFractureKey: string | null;\n\tcreatedRootGroup: boolean;\n\tfractureMode: 'compound' | 'independent' | null;\n\tisFractured: boolean;\n\toriginalMeshParent: Object3D | null;\n\toriginalColliderDesc: ColliderDesc | undefined;\n\toriginalColliderDescs: ColliderDesc[];\n\toriginalMeshVisible: boolean;\n\toriginalGroupVisible: boolean;\n\tsourceBodySnapshot: PhysicsSnapshot | null;\n\tsourcePhysicsAttached: boolean;\n}\n\ninterface PhysicsSnapshot {\n\ttranslation: { x: number; y: number; z: number };\n\trotation: { x: number; y: number; z: number; w: number };\n\tlinearVelocity: { x: number; y: number; z: number };\n\tangularVelocity: { x: number; y: number; z: number };\n}\n\ntype BehaviorWorld = {\n\tinterpolationAlpha?: number;\n\tdestroyEntity(entity: GameEntity<any>): void;\n\taddEntity(entity: GameEntity<any>): void;\n};\n\ntype BehaviorScene = {\n\tscene: {\n\t\tadd(object: Object3D): void;\n\t\tremove(object: Object3D): void;\n\t};\n};\n\nconst DESTRUCTIBLE_3D_BEHAVIOR_KEY = Symbol.for(\n\t'zylem:behavior:destructible-3d',\n);\n\nconst DEFAULT_FRACTURE_OPTIONS: FractureOptionsInput = {\n\tfractureMethod: 'voronoi',\n\tfragmentCount: 12,\n\tvoronoiOptions: {\n\t\tmode: '3D',\n\t},\n\tfracturePlanes: {\n\t\tx: true,\n\t\ty: true,\n\t\tz: true,\n\t},\n\ttextureScale: new Vector2(1, 1),\n\ttextureOffset: new Vector2(0, 0),\n};\n\nconst DEFAULT_FRAGMENT_PHYSICS: Required<Destructible3DFragmentPhysicsOptions> = {\n\tmode: 'compound',\n\tinheritSourceVelocity: true,\n\toutwardVelocity: 3,\n\tangularVelocity: 1.5,\n};\n\nconst defaultOptions: Destructible3DBehaviorOptions = {\n\tfractureOptions: DEFAULT_FRACTURE_OPTIONS,\n\tinnerMaterial: null,\n\tcollider: {\n\t\tshape: 'convexHull',\n\t\tsensor: false,\n\t\tactiveCollisionTypes: ActiveCollisionTypes.DEFAULT,\n\t},\n\tfragmentPhysics: DEFAULT_FRAGMENT_PHYSICS,\n};\n\nconst runtimeStates = new WeakMap<\n\tBehaviorRef<Destructible3DBehaviorOptions>,\n\tRuntimeState\n>();\n\nfunction getRuntimeState(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): RuntimeState {\n\tconst existing = runtimeStates.get(ref);\n\tif (existing) {\n\t\treturn existing;\n\t}\n\n\tconst state: RuntimeState = {\n\t\tfragmentContainer: null,\n\t\tfragmentEntities: [],\n\t\tfragments: [],\n\t\tprebakedFragments: [],\n\t\tprebakedFractureKey: null,\n\t\tcreatedRootGroup: false,\n\t\tfractureMode: null,\n\t\tisFractured: false,\n\t\toriginalMeshParent: null,\n\t\toriginalColliderDesc: undefined,\n\t\toriginalColliderDescs: [],\n\t\toriginalMeshVisible: true,\n\t\toriginalGroupVisible: true,\n\t\tsourceBodySnapshot: null,\n\t\tsourcePhysicsAttached: false,\n\t};\n\truntimeStates.set(ref, state);\n\treturn state;\n}\n\nconst prebakeWorkerApis = new Map<\n\tstring,\n\tComlink.Remote<DestructiblePrebakeWorkerAPI>\n>();\n\n/** One in-flight worker prebake per behavior ref (dedupes duplicate bind calls). */\nconst prebakeAsyncInFlight = new WeakMap<\n\tBehaviorRef<Destructible3DBehaviorOptions>,\n\tPromise<void>\n>();\n\nfunction resolvePrebakeWorkerHref(url: URL | string): string {\n\treturn typeof url === 'string' ? url : url.href;\n}\n\nfunction getPrebakeWorkerApi(\n\turl: URL | string,\n): Comlink.Remote<DestructiblePrebakeWorkerAPI> {\n\tif (typeof Worker === 'undefined') {\n\t\tthrow new Error(\n\t\t\t'Destructible3D prebakeAsync requires a Web Worker-capable environment.',\n\t\t);\n\t}\n\tconst key = resolvePrebakeWorkerHref(url);\n\tlet api = prebakeWorkerApis.get(key);\n\tif (api) {\n\t\treturn api;\n\t}\n\tconst worker = new Worker(key, { type: 'module' });\n\tapi = Comlink.wrap(worker);\n\tprebakeWorkerApis.set(key, api);\n\treturn api;\n}\n\nfunction requireEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): GameEntity<any> {\n\tconst entity = (ref as any).__entity as GameEntity<any> | undefined;\n\tif (!entity) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior requires the entity to be registered on a stage before calling fracture() or repair().',\n\t\t);\n\t}\n\n\treturn entity;\n}\n\nfunction getBehaviorWorld(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): BehaviorWorld | null {\n\treturn ((ref as any).__world ?? null) as BehaviorWorld | null;\n}\n\nfunction getBehaviorScene(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): BehaviorScene | null {\n\treturn ((ref as any).__scene ?? null) as BehaviorScene | null;\n}\n\nfunction getBehaviorCreateEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): CreateEntityFn | null {\n\treturn ((ref as any).__createEntity ?? null) as CreateEntityFn | null;\n}\n\nfunction getBehaviorGlobals(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): (() => any) | null {\n\treturn ((ref as any).__getGlobals ?? null) as (() => any) | null;\n}\n\nfunction cloneFractureOptionsInput(\n\tvalue?: FractureOptionsInput | PinataFractureOptions,\n): FractureOptionsInput {\n\tif (!value) {\n\t\treturn {};\n\t}\n\n\tif (value instanceof PinataFractureOptions) {\n\t\treturn {\n\t\t\tfractureMethod: value.fractureMethod,\n\t\t\tfragmentCount: value.fragmentCount,\n\t\t\tvoronoiOptions: value.voronoiOptions\n\t\t\t\t? {\n\t\t\t\t\tmode: value.voronoiOptions.mode,\n\t\t\t\t\tseedPoints: value.voronoiOptions.seedPoints?.map((point) =>\n\t\t\t\t\t\tpoint.clone()),\n\t\t\t\t\timpactPoint: value.voronoiOptions.impactPoint?.clone(),\n\t\t\t\t\timpactRadius: value.voronoiOptions.impactRadius,\n\t\t\t\t\tprojectionAxis: value.voronoiOptions.projectionAxis,\n\t\t\t\t\tprojectionNormal: value.voronoiOptions.projectionNormal?.clone(),\n\t\t\t\t\tuseApproximation: value.voronoiOptions.useApproximation,\n\t\t\t\t\tapproximationNeighborCount:\n\t\t\t\t\t\tvalue.voronoiOptions.approximationNeighborCount,\n\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t\tfracturePlanes: value.fracturePlanes\n\t\t\t\t? { ...value.fracturePlanes }\n\t\t\t\t: undefined,\n\t\t\ttextureScale: value.textureScale?.clone(),\n\t\t\ttextureOffset: value.textureOffset?.clone(),\n\t\t\tseed: value.seed,\n\t\t};\n\t}\n\n\treturn {\n\t\t...value,\n\t\tvoronoiOptions: value.voronoiOptions\n\t\t\t? {\n\t\t\t\t...value.voronoiOptions,\n\t\t\t\tseedPoints: value.voronoiOptions.seedPoints?.map((point) =>\n\t\t\t\t\tpoint.clone()),\n\t\t\t\timpactPoint: value.voronoiOptions.impactPoint?.clone(),\n\t\t\t\tprojectionNormal: value.voronoiOptions.projectionNormal?.clone(),\n\t\t\t}\n\t\t\t: undefined,\n\t\tfracturePlanes: value.fracturePlanes\n\t\t\t? { ...value.fracturePlanes }\n\t\t\t: undefined,\n\t\ttextureScale: value.textureScale?.clone(),\n\t\ttextureOffset: value.textureOffset?.clone(),\n\t};\n}\n\nfunction resolveFractureOptions(\n\tbaseValue?: FractureOptionsInput | PinataFractureOptions,\n\toverrideValue?: FractureOptionsInput | PinataFractureOptions,\n): PinataFractureOptions {\n\tconst base = cloneFractureOptionsInput(baseValue);\n\tconst override = cloneFractureOptionsInput(overrideValue);\n\n\tconst fractureMethod =\n\t\toverride.fractureMethod\n\t\t?? base.fractureMethod\n\t\t?? DEFAULT_FRACTURE_OPTIONS.fractureMethod\n\t\t?? 'voronoi';\n\n\tconst voronoiOptions = fractureMethod === 'voronoi'\n\t\t? {\n\t\t\tmode:\n\t\t\t\toverride.voronoiOptions?.mode\n\t\t\t\t?? base.voronoiOptions?.mode\n\t\t\t\t?? DEFAULT_FRACTURE_OPTIONS.voronoiOptions?.mode\n\t\t\t\t?? '3D',\n\t\t\tseedPoints:\n\t\t\t\toverride.voronoiOptions?.seedPoints\n\t\t\t\t?? base.voronoiOptions?.seedPoints,\n\t\t\timpactPoint:\n\t\t\t\toverride.voronoiOptions?.impactPoint\n\t\t\t\t?? base.voronoiOptions?.impactPoint,\n\t\t\timpactRadius:\n\t\t\t\toverride.voronoiOptions?.impactRadius\n\t\t\t\t?? base.voronoiOptions?.impactRadius,\n\t\t\tprojectionAxis:\n\t\t\t\toverride.voronoiOptions?.projectionAxis\n\t\t\t\t?? base.voronoiOptions?.projectionAxis,\n\t\t\tprojectionNormal:\n\t\t\t\toverride.voronoiOptions?.projectionNormal\n\t\t\t\t?? base.voronoiOptions?.projectionNormal,\n\t\t\tuseApproximation:\n\t\t\t\toverride.voronoiOptions?.useApproximation\n\t\t\t\t?? base.voronoiOptions?.useApproximation,\n\t\t\tapproximationNeighborCount:\n\t\t\t\toverride.voronoiOptions?.approximationNeighborCount\n\t\t\t\t?? base.voronoiOptions?.approximationNeighborCount,\n\t\t}\n\t\t: undefined;\n\n\treturn new PinataFractureOptions({\n\t\tfractureMethod,\n\t\tfragmentCount:\n\t\t\toverride.fragmentCount\n\t\t\t?? base.fragmentCount\n\t\t\t?? DEFAULT_FRACTURE_OPTIONS.fragmentCount\n\t\t\t?? 12,\n\t\tvoronoiOptions,\n\t\tfracturePlanes: {\n\t\t\tx:\n\t\t\t\toverride.fracturePlanes?.x\n\t\t\t\t?? base.fracturePlanes?.x\n\t\t\t\t?? DEFAULT_FRACTURE_OPTIONS.fracturePlanes?.x\n\t\t\t\t?? true,\n\t\t\ty:\n\t\t\t\toverride.fracturePlanes?.y\n\t\t\t\t?? base.fracturePlanes?.y\n\t\t\t\t?? DEFAULT_FRACTURE_OPTIONS.fracturePlanes?.y\n\t\t\t\t?? true,\n\t\t\tz:\n\t\t\t\toverride.fracturePlanes?.z\n\t\t\t\t?? base.fracturePlanes?.z\n\t\t\t\t?? DEFAULT_FRACTURE_OPTIONS.fracturePlanes?.z\n\t\t\t\t?? true,\n\t\t},\n\t\ttextureScale:\n\t\t\toverride.textureScale?.clone()\n\t\t\t?? base.textureScale?.clone()\n\t\t\t?? DEFAULT_FRACTURE_OPTIONS.textureScale?.clone()\n\t\t\t?? new Vector2(1, 1),\n\t\ttextureOffset:\n\t\t\toverride.textureOffset?.clone()\n\t\t\t?? base.textureOffset?.clone()\n\t\t\t?? DEFAULT_FRACTURE_OPTIONS.textureOffset?.clone()\n\t\t\t?? new Vector2(0, 0),\n\t\tseed: override.seed ?? base.seed,\n\t});\n}\n\nfunction resolveColliderOptions(\n\tinput?: Destructible3DColliderOptions,\n): Required<\n\tPick<Destructible3DColliderOptions, 'shape' | 'sensor' | 'activeCollisionTypes'>\n> & Omit<Destructible3DColliderOptions, 'shape' | 'sensor' | 'activeCollisionTypes'> {\n\treturn {\n\t\tshape: input?.shape ?? defaultOptions.collider?.shape ?? 'convexHull',\n\t\tsensor: input?.sensor ?? defaultOptions.collider?.sensor ?? false,\n\t\tcollisionGroups: input?.collisionGroups,\n\t\tactiveCollisionTypes:\n\t\t\tinput?.activeCollisionTypes\n\t\t\t?? defaultOptions.collider?.activeCollisionTypes\n\t\t\t?? ActiveCollisionTypes.DEFAULT,\n\t};\n}\n\nfunction resolveFragmentPhysicsOptions(\n\tinput?: Destructible3DFragmentPhysicsOptions,\n): Required<Destructible3DFragmentPhysicsOptions> {\n\treturn {\n\t\tmode: input?.mode ?? DEFAULT_FRAGMENT_PHYSICS.mode,\n\t\tinheritSourceVelocity:\n\t\t\tinput?.inheritSourceVelocity\n\t\t\t?? DEFAULT_FRAGMENT_PHYSICS.inheritSourceVelocity,\n\t\toutwardVelocity:\n\t\t\tinput?.outwardVelocity\n\t\t\t?? DEFAULT_FRAGMENT_PHYSICS.outwardVelocity,\n\t\tangularVelocity:\n\t\t\tinput?.angularVelocity\n\t\t\t?? DEFAULT_FRAGMENT_PHYSICS.angularVelocity,\n\t};\n}\n\nfunction findFirstMesh(root: Object3D | null | undefined): Mesh | null {\n\tlet resolved: Mesh | null = null;\n\troot?.traverse((child) => {\n\t\tif (resolved) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ((child as { isMesh?: boolean }).isMesh) {\n\t\t\tresolved = child as Mesh;\n\t\t}\n\t});\n\treturn resolved;\n}\n\nfunction requireEntityMesh(entity: GameEntity<any>): Mesh {\n\tif (entity.mesh?.geometry) {\n\t\treturn entity.mesh;\n\t}\n\n\tconst mesh = findFirstMesh(entity.group);\n\tif (!mesh?.geometry) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior requires the entity to have a primary mesh geometry.',\n\t\t);\n\t}\n\n\tentity.mesh = mesh;\n\tif (!entity.materials?.length) {\n\t\tif (Array.isArray(mesh.material)) {\n\t\t\tentity.materials = [...mesh.material];\n\t\t} else if (mesh.material) {\n\t\t\tentity.materials = [mesh.material];\n\t\t}\n\t}\n\n\treturn mesh;\n}\n\nfunction getPrimaryMaterial(mesh: Mesh): Material {\n\tif (Array.isArray(mesh.material)) {\n\t\tconst material = mesh.material[0];\n\t\tif (material) {\n\t\t\treturn material;\n\t\t}\n\t} else if (mesh.material) {\n\t\treturn mesh.material;\n\t}\n\n\tthrow new Error(\n\t\t'Destructible3DBehavior requires the entity mesh to have a material.',\n\t);\n}\n\nfunction ensureRootGroup(\n\tentity: GameEntity<any>,\n\tstate: RuntimeState,\n): Group {\n\tif (entity.group) {\n\t\tstate.createdRootGroup = false;\n\t\treturn entity.group;\n\t}\n\n\tconst originalMesh = requireEntityMesh(entity);\n\tconst parent = originalMesh.parent;\n\tconst root = new Group();\n\troot.name = `${entity.name ?? entity.uuid}-destructible-root`;\n\troot.position.copy(originalMesh.position);\n\troot.quaternion.copy(originalMesh.quaternion);\n\troot.scale.copy(originalMesh.scale);\n\n\toriginalMesh.position.set(0, 0, 0);\n\toriginalMesh.quaternion.identity();\n\toriginalMesh.scale.set(1, 1, 1);\n\n\tif (parent) {\n\t\tparent.remove(originalMesh);\n\t\tparent.add(root);\n\t}\n\n\troot.add(originalMesh);\n\tentity.group = root;\n\tstate.createdRootGroup = true;\n\treturn root;\n}\n\nfunction createFractureSourceMesh(\n\tmesh: Mesh,\n\troot: Group,\n\tinnerMaterial: Material | null | undefined,\n): DestructibleMesh {\n\tconst geometry = buildNormalizedFractureSourceGeometry(mesh, root);\n\tconst outerMaterial = getPrimaryMaterial(mesh);\n\treturn new DestructibleMesh(\n\t\tgeometry,\n\t\touterMaterial,\n\t\tinnerMaterial ?? outerMaterial,\n\t);\n}\n\nfunction createPrebakedFragmentTemplates(\n\tfragments: readonly DestructibleMesh[],\n): PrebakedFragmentTemplate[] {\n\treturn fragments.map((fragment) => {\n\t\tconst geometry = fragment.geometry.clone();\n\t\tgeometry.computeBoundingBox();\n\t\tgeometry.computeBoundingSphere();\n\t\treturn {\n\t\t\tgeometry,\n\t\t\tposition: fragment.position.clone(),\n\t\t\tquaternion: fragment.quaternion.clone(),\n\t\t\tscale: fragment.scale.clone(),\n\t\t};\n\t});\n}\n\nfunction disposePrebakedFragmentTemplates(\n\ttemplates: readonly PrebakedFragmentTemplate[],\n): void {\n\tfor (const template of templates) {\n\t\ttemplate.geometry.dispose();\n\t}\n}\n\nfunction cachePrebakedFragments(\n\tstate: RuntimeState,\n\tcacheKey: string,\n\tfragments: readonly DestructibleMesh[],\n): void {\n\tif (\n\t\tstate.prebakedFractureKey === cacheKey\n\t\t&& state.prebakedFragments.length > 0\n\t) {\n\t\treturn;\n\t}\n\n\tdisposePrebakedFragmentTemplates(state.prebakedFragments);\n\tstate.prebakedFragments = createPrebakedFragmentTemplates(fragments);\n\tstate.prebakedFractureKey = cacheKey;\n}\n\nfunction installPrebakedTemplateParts(\n\tstate: RuntimeState,\n\tcacheKey: string,\n\tparts: Array<{\n\t\tgeometry: BufferGeometry;\n\t\tposition: Vector3;\n\t\tquaternion: Quaternion;\n\t\tscale: Vector3;\n\t}>,\n): void {\n\tif (\n\t\tstate.prebakedFractureKey === cacheKey\n\t\t&& state.prebakedFragments.length > 0\n\t) {\n\t\tfor (const part of parts) {\n\t\t\tpart.geometry.dispose();\n\t\t}\n\t\treturn;\n\t}\n\n\tdisposePrebakedFragmentTemplates(state.prebakedFragments);\n\tstate.prebakedFragments = parts.map((part) => ({\n\t\tgeometry: part.geometry,\n\t\tposition: part.position.clone(),\n\t\tquaternion: part.quaternion.clone(),\n\t\tscale: part.scale.clone(),\n\t}));\n\tstate.prebakedFractureKey = cacheKey;\n}\n\nfunction instantiatePrebakedFragments(\n\tmesh: Mesh,\n\tinnerMaterial: Material | null | undefined,\n\ttemplates: readonly PrebakedFragmentTemplate[],\n): readonly DestructibleMesh[] {\n\tconst outerMaterial = getPrimaryMaterial(mesh);\n\treturn templates.map((template) => {\n\t\tconst fragment = new DestructibleMesh(\n\t\t\ttemplate.geometry.clone(),\n\t\t\touterMaterial,\n\t\t\tinnerMaterial ?? outerMaterial,\n\t\t);\n\t\tfragment.position.copy(template.position);\n\t\tfragment.quaternion.copy(template.quaternion);\n\t\tfragment.scale.copy(template.scale);\n\t\treturn fragment;\n\t});\n}\n\nfunction tagConvexHullCollider(\n\tcolliderDesc: ColliderDesc,\n\tvertices: Float32Array,\n): ColliderDesc {\n\t(colliderDesc as any).__zylemShapeData = {\n\t\tshape: 'convexHull',\n\t\tvertices: Array.from(vertices),\n\t};\n\treturn colliderDesc;\n}\n\nfunction tagTrimeshCollider(\n\tcolliderDesc: ColliderDesc,\n\tvertices: Float32Array,\n\tindices: Uint32Array,\n): ColliderDesc {\n\t(colliderDesc as any).__zylemShapeData = {\n\t\tshape: 'trimesh',\n\t\tvertices: Array.from(vertices),\n\t\tindices: Array.from(indices),\n\t};\n\treturn colliderDesc;\n}\n\nfunction getFragmentVertices(fragment: DestructibleMesh): Float32Array {\n\tconst position = fragment.geometry.getAttribute('position');\n\tif (!(position instanceof BufferAttribute)) {\n\t\tthrow new Error('Fragment geometry is missing a position attribute.');\n\t}\n\n\treturn new Float32Array(position.array as ArrayLike<number>);\n}\n\nfunction getFragmentIndices(fragment: DestructibleMesh): Uint32Array {\n\tconst geometryIndex = fragment.geometry.getIndex();\n\tif (geometryIndex) {\n\t\treturn new Uint32Array(geometryIndex.array as ArrayLike<number>);\n\t}\n\n\tconst position = fragment.geometry.getAttribute('position');\n\tif (!(position instanceof BufferAttribute)) {\n\t\treturn new Uint32Array();\n\t}\n\n\treturn Uint32Array.from({ length: position.count }, (_value, index) => index);\n}\n\nfunction createCuboidCollider(fragment: DestructibleMesh): ColliderDesc {\n\tconst bounds = fragment.geometry.boundingBox ?? new Box3();\n\tif (!fragment.geometry.boundingBox) {\n\t\tfragment.geometry.computeBoundingBox();\n\t}\n\tbounds.copy(fragment.geometry.boundingBox ?? bounds);\n\tconst size = bounds.getSize(new Vector3());\n\treturn ColliderDesc.cuboid(\n\t\tMath.max(size.x / 2, 0.001),\n\t\tMath.max(size.y / 2, 0.001),\n\t\tMath.max(size.z / 2, 0.001),\n\t);\n}\n\nfunction createFragmentColliderDesc(\n\tfragment: DestructibleMesh,\n\toptions: Destructible3DColliderOptions | undefined,\n\ttranslation?: Vector3 | null,\n): ColliderDesc {\n\tconst resolved = resolveColliderOptions(options);\n\tconst vertices = getFragmentVertices(fragment);\n\n\tlet colliderDesc: ColliderDesc | null = null;\n\n\tif (resolved.shape === 'convexHull') {\n\t\tcolliderDesc = ColliderDesc.convexHull(vertices);\n\t\tif (colliderDesc) {\n\t\t\tcolliderDesc = tagConvexHullCollider(colliderDesc, vertices);\n\t\t}\n\t}\n\n\tif (!colliderDesc && resolved.shape === 'trimesh') {\n\t\tconst indices = getFragmentIndices(fragment);\n\t\tcolliderDesc = tagTrimeshCollider(\n\t\t\tColliderDesc.trimesh(vertices, indices),\n\t\t\tvertices,\n\t\t\tindices,\n\t\t);\n\t}\n\n\tif (!colliderDesc) {\n\t\tcolliderDesc = createCuboidCollider(fragment);\n\t}\n\n\tif (translation) {\n\t\tcolliderDesc.setTranslation(\n\t\t\ttranslation.x,\n\t\t\ttranslation.y,\n\t\t\ttranslation.z,\n\t\t);\n\t}\n\tcolliderDesc.setSensor(resolved.sensor);\n\tif (resolved.collisionGroups !== undefined) {\n\t\tcolliderDesc.setCollisionGroups(resolved.collisionGroups);\n\t}\n\tcolliderDesc.activeCollisionTypes = resolved.activeCollisionTypes;\n\treturn colliderDesc;\n}\n\nfunction snapshotBody(entity: GameEntity<any>): PhysicsSnapshot | null {\n\tif (!entity.body) {\n\t\treturn null;\n\t}\n\n\tconst translation = entity.body.translation();\n\tconst rotation = entity.body.rotation();\n\tconst linearVelocity = entity.body.linvel();\n\tconst angularVelocity = entity.body.angvel();\n\n\treturn {\n\t\ttranslation: { ...translation },\n\t\trotation: { ...rotation },\n\t\tlinearVelocity: { ...linearVelocity },\n\t\tangularVelocity: { ...angularVelocity },\n\t};\n}\n\nfunction restoreBodySnapshot(\n\tentity: GameEntity<any>,\n\tsnapshot: PhysicsSnapshot | null,\n): void {\n\tif (!snapshot || !entity.body) {\n\t\treturn;\n\t}\n\n\tentity.body.setTranslation(snapshot.translation, true);\n\tentity.body.setRotation(snapshot.rotation, true);\n\tentity.body.setLinvel(snapshot.linearVelocity, true);\n\tentity.body.setAngvel(snapshot.angularVelocity, true);\n}\n\nfunction attachEntityPhysics(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tentity: GameEntity<any>,\n\tsnapshot: PhysicsSnapshot | null,\n): void {\n\tconst world = getBehaviorWorld(ref);\n\tif (!world || !entity.colliderDesc) {\n\t\treturn;\n\t}\n\n\tif (entity.physicsAttached) {\n\t\tworld.destroyEntity(entity);\n\t}\n\n\tworld.addEntity(entity);\n\trestoreBodySnapshot(entity, snapshot);\n}\n\nfunction detachEntityPhysics(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tentity: GameEntity<any>,\n): void {\n\tconst world = getBehaviorWorld(ref);\n\tif (!world || !entity.physicsAttached) {\n\t\treturn;\n\t}\n\n\tworld.destroyEntity(entity);\n}\n\nfunction disposeFragments(fragments: readonly DestructibleMesh[]): void {\n\tfor (const fragment of fragments) {\n\t\tfragment.removeFromParent();\n\t\tfragment.geometry.dispose();\n\t}\n}\n\nfunction syncRuntimeFragmentEntityTransform(\n\tentity: GameEntity<any>,\n\tinterpolationAlpha: number,\n): void {\n\tconst target = entity.group ?? entity.mesh;\n\tif (!target) {\n\t\treturn;\n\t}\n\n\tconst wasmPose = (entity as any).getPose?.();\n\tif (wasmPose && (entity as any).runtimeHandle >= 0) {\n\t\ttarget.position.set(wasmPose.position.x, wasmPose.position.y, wasmPose.position.z);\n\t\ttarget.quaternion.set(wasmPose.rotation.x, wasmPose.rotation.y, wasmPose.rotation.z, wasmPose.rotation.w);\n\t\treturn;\n\t}\n\n\tif (!entity.body) {\n\t\treturn;\n\t}\n\tconst pose = getBodyRenderPose(entity.body as any, interpolationAlpha);\n\ttarget.position.set(pose.position.x, pose.position.y, pose.position.z);\n\ttarget.quaternion.set(pose.rotation.x, pose.rotation.y, pose.rotation.z, pose.rotation.w);\n}\n\nfunction bakeScaleIntoFragmentGeometry(\n\tfragment: DestructibleMesh,\n\tscale: Vector3,\n): void {\n\tif (\n\t\tMath.abs(scale.x - 1) < 1e-6\n\t\t&& Math.abs(scale.y - 1) < 1e-6\n\t\t&& Math.abs(scale.z - 1) < 1e-6\n\t) {\n\t\treturn;\n\t}\n\n\tfragment.geometry.applyMatrix4(\n\t\tnew Matrix4().makeScale(scale.x, scale.y, scale.z),\n\t);\n\tfragment.geometry.computeBoundingBox();\n\tfragment.geometry.computeBoundingSphere();\n}\n\nfunction getRootWorldPosition(root: Group): Vector3 {\n\troot.updateMatrixWorld(true);\n\treturn root.getWorldPosition(new Vector3());\n}\n\nfunction getImpactPointWorld(\n\troot: Group,\n\tfractureOptions: PinataFractureOptions,\n): Vector3 | null {\n\tconst localImpactPoint = fractureOptions.voronoiOptions?.impactPoint;\n\tif (!localImpactPoint) {\n\t\treturn null;\n\t}\n\n\troot.updateMatrixWorld(true);\n\treturn localImpactPoint.clone().applyMatrix4(root.matrixWorld);\n}\n\nfunction computeFragmentWorldPose(\n\troot: Group,\n\tfragment: DestructibleMesh,\n): {\n\tposition: Vector3;\n\trotation: Quaternion;\n\tscale: Vector3;\n} {\n\troot.updateMatrixWorld(true);\n\tfragment.updateMatrix();\n\n\tconst worldMatrix = new Matrix4()\n\t\t.copy(root.matrixWorld)\n\t\t.multiply(fragment.matrix);\n\tconst position = new Vector3();\n\tconst rotation = new Quaternion();\n\tconst scale = new Vector3();\n\n\tworldMatrix.decompose(position, rotation, scale);\n\treturn {\n\t\tposition,\n\t\trotation,\n\t\tscale,\n\t};\n}\n\nfunction pseudoRandomSigned(index: number, salt: number): number {\n\tconst value = Math.sin((index + 1) * 12.9898 + salt * 78.233) * 43758.5453;\n\treturn (value - Math.floor(value)) * 2 - 1;\n}\n\nfunction computeFragmentAngularVelocity(\n\tindex: number,\n\tmagnitude: number,\n): { x: number; y: number; z: number } {\n\tif (magnitude <= 0) {\n\t\treturn { x: 0, y: 0, z: 0 };\n\t}\n\n\tconst axis = new Vector3(\n\t\tpseudoRandomSigned(index, 0.13),\n\t\tpseudoRandomSigned(index, 0.47),\n\t\tpseudoRandomSigned(index, 0.91),\n\t);\n\tif (axis.lengthSq() <= 1e-6) {\n\t\taxis.set(0.35, 1, 0.2);\n\t}\n\taxis.normalize().multiplyScalar(magnitude);\n\treturn {\n\t\tx: axis.x,\n\t\ty: axis.y,\n\t\tz: axis.z,\n\t};\n}\n\nfunction computeFragmentLinearVelocity(\n\tfragmentWorldPosition: Vector3,\n\trootWorldPosition: Vector3,\n\timpactPointWorld: Vector3 | null,\n\tphysicsOptions: Required<Destructible3DFragmentPhysicsOptions>,\n\tsourceVelocity: { x: number; y: number; z: number } | null,\n): { x: number; y: number; z: number } {\n\tconst velocity = new Vector3();\n\n\tif (physicsOptions.inheritSourceVelocity && sourceVelocity) {\n\t\tvelocity.set(\n\t\t\tsourceVelocity.x,\n\t\t\tsourceVelocity.y,\n\t\t\tsourceVelocity.z,\n\t\t);\n\t}\n\n\tif (physicsOptions.outwardVelocity <= 0) {\n\t\treturn {\n\t\t\tx: velocity.x,\n\t\t\ty: velocity.y,\n\t\t\tz: velocity.z,\n\t\t};\n\t}\n\n\tconst direction = fragmentWorldPosition.clone().sub(\n\t\timpactPointWorld ?? rootWorldPosition,\n\t);\n\tif (direction.lengthSq() <= 1e-6) {\n\t\tdirection.copy(fragmentWorldPosition).sub(rootWorldPosition);\n\t}\n\tif (direction.lengthSq() <= 1e-6) {\n\t\tdirection.set(0, 1, 0);\n\t}\n\tdirection.normalize().multiplyScalar(physicsOptions.outwardVelocity);\n\tvelocity.add(direction);\n\n\treturn {\n\t\tx: velocity.x,\n\t\ty: velocity.y,\n\t\tz: velocity.z,\n\t};\n}\n\nfunction createRuntimeFragmentEntity(\n\tcreateEntity: CreateEntityFn,\n\tparentEntity: GameEntity<any>,\n\tfragment: DestructibleMesh,\n\tindex: number,\n\tcolliderOptions: Destructible3DColliderOptions | undefined,\n\tposition: Vector3,\n\trotation: Quaternion,\n): GameEntity<any> {\n\tconst entity = createEntity({\n\t\tname: `${parentEntity.name ?? parentEntity.uuid}-fragment-${index}`,\n\t});\n\n\tentity.onCleanup(() => {\n\t\tfragment.removeFromParent();\n\t\tfragment.geometry.dispose();\n\t});\n\tentity.create();\n\n\tentity.mesh = fragment;\n\tif (Array.isArray(fragment.material)) {\n\t\tentity.materials = [...fragment.material];\n\t} else if (fragment.material) {\n\t\tentity.materials = [fragment.material];\n\t}\n\n\tentity.colliderDesc = createFragmentColliderDesc(fragment, colliderOptions);\n\tentity.colliderDescs = [entity.colliderDesc];\n\tentity.bodyDesc = RigidBodyDesc.dynamic()\n\t\t.setTranslation(position.x, position.y, position.z)\n\t\t.setCanSleep(false)\n\t\t.setCcdEnabled(true);\n\n\tfragment.position.set(0, 0, 0);\n\tfragment.quaternion.identity();\n\tfragment.scale.set(1, 1, 1);\n\tentity.bodyDesc.setRotation({\n\t\tx: rotation.x,\n\t\ty: rotation.y,\n\t\tz: rotation.z,\n\t\tw: rotation.w,\n\t});\n\n\treturn entity;\n}\n\n/**\n * {@link ZylemWorld} locks translations and rotations on every new rigid body\n * when world gravity is `(0,0,0)`, so entities do not drift in zero‑G scenes.\n * Independent destructible fragments are still meant to move via\n * `setLinvel` / `setAngvel`, so they must opt out of that lock after spawn.\n */\nfunction unlockIndependentFragmentPhysicsBody(entity: GameEntity<any>): void {\n\tconst body = entity.body as\n\t\t| {\n\t\t\tlockTranslations?(locked: boolean, wakeUp?: boolean): void;\n\t\t\tlockRotations?(locked: boolean, wakeUp?: boolean): void;\n\t\t}\n\t\t| null\n\t\t| undefined;\n\tif (!body?.lockTranslations || !body.lockRotations) {\n\t\treturn;\n\t}\n\tbody.lockTranslations(false, true);\n\tbody.lockRotations(false, true);\n}\n\nfunction destroyRuntimeFragmentEntities(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tstate: RuntimeState,\n): void {\n\tconst world = getBehaviorWorld(ref);\n\tconst scene = getBehaviorScene(ref);\n\tconst handledFragments = new Set<DestructibleMesh>();\n\n\tfor (const fragmentEntity of state.fragmentEntities) {\n\t\tconst fragmentMesh = fragmentEntity.mesh as DestructibleMesh | undefined;\n\t\tif (fragmentMesh) {\n\t\t\thandledFragments.add(fragmentMesh);\n\t\t}\n\n\t\ttry {\n\t\t\tfragmentEntity.nodeDestroy({\n\t\t\t\tme: fragmentEntity,\n\t\t\t\tglobals: getBehaviorGlobals(ref)?.() ?? {},\n\t\t\t} as any);\n\t\t} catch {\n\t\t\t// Cleanup is best-effort for behavior-managed runtime fragments.\n\t\t}\n\n\t\tif (world && fragmentEntity.physicsAttached) {\n\t\t\tworld.destroyEntity(fragmentEntity);\n\t\t}\n\n\t\tconst target = fragmentEntity.group ?? fragmentEntity.mesh;\n\t\tif (target) {\n\t\t\ttarget.removeFromParent();\n\t\t\tscene?.scene.remove(target);\n\t\t}\n\t}\n\n\tfor (const fragment of state.fragments) {\n\t\tif (handledFragments.has(fragment)) {\n\t\t\tcontinue;\n\t\t}\n\t\tfragment.removeFromParent();\n\t\tfragment.geometry.dispose();\n\t}\n\n\tstate.fragmentEntities = [];\n}\n\nfunction restoreOriginalMesh(\n\tentity: GameEntity<any>,\n\tstate: RuntimeState,\n): void {\n\tif (!entity.mesh) {\n\t\treturn;\n\t}\n\n\tif (state.createdRootGroup && entity.group) {\n\t\tconst root = entity.group;\n\t\tconst parent = root.parent;\n\t\tentity.mesh.position.copy(root.position);\n\t\tentity.mesh.quaternion.copy(root.quaternion);\n\t\tentity.mesh.scale.copy(root.scale);\n\t\tentity.mesh.removeFromParent();\n\n\t\tif (parent) {\n\t\t\tparent.remove(root);\n\t\t\tparent.add(entity.mesh);\n\t\t}\n\n\t\tentity.group = undefined;\n\t\treturn;\n\t}\n\n\tconst parent = state.originalMeshParent ?? entity.group;\n\tif (parent && entity.mesh.parent !== parent) {\n\t\tparent.add(entity.mesh);\n\t}\n}\n\nfunction restoreRuntimeState(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\trefreshPhysics: boolean,\n): void {\n\tconst state = getRuntimeState(ref);\n\tif (!state.isFractured) {\n\t\treturn;\n\t}\n\n\tconst entity = requireEntity(ref);\n\n\tif (state.fractureMode === 'independent') {\n\t\tdestroyRuntimeFragmentEntities(ref, state);\n\t} else {\n\t\tstate.fragmentContainer?.removeFromParent();\n\t\tstate.fragmentContainer?.clear();\n\t\tdisposeFragments(state.fragments);\n\t}\n\n\tstate.fragmentContainer = null;\n\tstate.fragments = [];\n\n\trestoreOriginalMesh(entity, state);\n\tif (entity.mesh) {\n\t\tentity.mesh.visible = state.originalMeshVisible;\n\t}\n\tif (entity.group) {\n\t\tentity.group.visible = state.originalGroupVisible;\n\t}\n\n\tentity.colliderDesc = state.originalColliderDesc;\n\tentity.colliderDescs = [...state.originalColliderDescs];\n\tif (!entity.colliderDesc && entity.colliderDescs.length > 0) {\n\t\tentity.colliderDesc = entity.colliderDescs[0];\n\t}\n\n\tif (refreshPhysics && state.sourcePhysicsAttached) {\n\t\tattachEntityPhysics(ref, entity, state.sourceBodySnapshot);\n\t}\n\n\tstate.createdRootGroup = false;\n\tstate.fractureMode = null;\n\tstate.originalMeshParent = null;\n\tstate.originalColliderDesc = undefined;\n\tstate.originalColliderDescs = [];\n\tstate.originalMeshVisible = true;\n\tstate.originalGroupVisible = true;\n\tstate.sourceBodySnapshot = null;\n\tstate.sourcePhysicsAttached = false;\n\tstate.isFractured = false;\n}\n\nfunction disposeRuntimeState(state: RuntimeState): void {\n\tdisposePrebakedFragmentTemplates(state.prebakedFragments);\n\tstate.prebakedFragments = [];\n\tstate.prebakedFractureKey = null;\n}\n\nfunction fractureCompoundEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tentity: GameEntity<any>,\n\troot: Group,\n\tfragments: readonly DestructibleMesh[],\n\tstate: RuntimeState,\n): void {\n\tconst fragmentContainer = new Group();\n\tfragmentContainer.name = `${entity.name ?? entity.uuid}-fracture-fragments`;\n\tfor (const fragment of fragments) {\n\t\tfragmentContainer.add(fragment);\n\t}\n\n\tentity.mesh?.removeFromParent();\n\troot.add(fragmentContainer);\n\n\tstate.fragmentContainer = fragmentContainer;\n\tstate.fractureMode = 'compound';\n\n\tconst colliderDescs = fragments.map((fragment) =>\n\t\tcreateFragmentColliderDesc(\n\t\t\tfragment,\n\t\t\tref.options.collider,\n\t\t\tfragment.position,\n\t\t));\n\tif (colliderDescs.length > 0) {\n\t\tentity.colliderDescs = colliderDescs;\n\t\tentity.colliderDesc = colliderDescs[0];\n\t\tif (state.sourcePhysicsAttached) {\n\t\t\tattachEntityPhysics(ref, entity, state.sourceBodySnapshot);\n\t\t}\n\t}\n}\n\nfunction fractureIndependentEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\tentity: GameEntity<any>,\n\troot: Group,\n\tfractureOptions: PinataFractureOptions,\n\tfragments: readonly DestructibleMesh[],\n\tstate: RuntimeState,\n): void {\n\tconst world = getBehaviorWorld(ref);\n\tconst scene = getBehaviorScene(ref);\n\tif (!world || !scene) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior independent fragments require an active scene and physics world.',\n\t\t);\n\t}\n\n\tconst createEntity = getBehaviorCreateEntity(ref);\n\tif (!createEntity) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior independent fragments require a host entity factory (BehaviorSystemContext.createEntity).',\n\t\t);\n\t}\n\n\tconst physicsOptions = resolveFragmentPhysicsOptions(ref.options.fragmentPhysics);\n\tconst rootWorldPosition = getRootWorldPosition(root);\n\tconst impactPointWorld = getImpactPointWorld(root, fractureOptions);\n\tconst sourceVelocity = state.sourceBodySnapshot?.linearVelocity ?? null;\n\n\tif (entity.mesh) {\n\t\tentity.mesh.visible = false;\n\t}\n\tif (state.sourcePhysicsAttached) {\n\t\tdetachEntityPhysics(ref, entity);\n\t}\n\n\tconst fragmentEntities: GameEntity<any>[] = [];\n\n\tfor (const [index, fragment] of fragments.entries()) {\n\t\tconst fragmentWorldPose = computeFragmentWorldPose(root, fragment);\n\t\tbakeScaleIntoFragmentGeometry(fragment, fragmentWorldPose.scale);\n\n\t\tconst fragmentEntity = createRuntimeFragmentEntity(\n\t\t\tcreateEntity,\n\t\t\tentity,\n\t\t\tfragment,\n\t\t\tindex,\n\t\t\tref.options.collider,\n\t\t\tfragmentWorldPose.position,\n\t\t\tfragmentWorldPose.rotation,\n\t\t);\n\n\t\tworld.addEntity(fragmentEntity);\n\t\tunlockIndependentFragmentPhysicsBody(fragmentEntity);\n\t\tconst linearVelocity = computeFragmentLinearVelocity(\n\t\t\tfragmentWorldPose.position,\n\t\t\trootWorldPosition,\n\t\t\timpactPointWorld,\n\t\t\tphysicsOptions,\n\t\t\tsourceVelocity,\n\t\t);\n\t\tfragmentEntity.body?.setLinvel(linearVelocity, true);\n\t\tfragmentEntity.body?.setAngvel(\n\t\t\tcomputeFragmentAngularVelocity(\n\t\t\t\tindex,\n\t\t\t\tphysicsOptions.angularVelocity,\n\t\t\t),\n\t\t\ttrue,\n\t\t);\n\n\t\tsyncRuntimeFragmentEntityTransform(\n\t\t\tfragmentEntity,\n\t\t\tworld.interpolationAlpha ?? 0,\n\t\t);\n\n\t\tconst target = fragmentEntity.group ?? fragmentEntity.mesh;\n\t\tif (target) {\n\t\t\ttarget.removeFromParent();\n\t\t\tscene.scene.add(target);\n\t\t}\n\n\t\tfragmentEntities.push(fragmentEntity);\n\t}\n\n\tstate.fragmentEntities = fragmentEntities;\n\tstate.fractureMode = 'independent';\n}\n\nfunction fractureEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n): readonly DestructibleMesh[] {\n\tconst entity = requireEntity(ref);\n\tif (entity.isInstanced) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior does not support entities using instanced rendering.',\n\t\t);\n\t}\n\n\tconst state = getRuntimeState(ref);\n\tif (state.isFractured) {\n\t\trestoreRuntimeState(ref, true);\n\t}\n\n\tconst sourceMesh = requireEntityMesh(entity);\n\tconst fractureOptions = resolveFractureOptions(\n\t\tref.options.fractureOptions,\n\t\toverrideOptions,\n\t);\n\tconst cacheKey = buildFractureGeometryCacheKey(fractureOptions);\n\n\tconst root = ensureRootGroup(entity, state);\n\tstate.originalMeshParent = sourceMesh.parent;\n\tstate.originalColliderDesc = entity.colliderDesc;\n\tstate.originalColliderDescs = entity.colliderDescs.length > 0\n\t\t? [...entity.colliderDescs]\n\t\t: entity.colliderDesc\n\t\t\t? [entity.colliderDesc]\n\t\t\t: [];\n\tstate.originalMeshVisible = sourceMesh.visible;\n\tstate.originalGroupVisible = entity.group?.visible ?? true;\n\tstate.sourceBodySnapshot = snapshotBody(entity);\n\tstate.sourcePhysicsAttached = entity.physicsAttached;\n\n\tconst usePrebakedFragments =\n\t\tstate.prebakedFractureKey === cacheKey\n\t\t&& state.prebakedFragments.length > 0;\n\tconst source = usePrebakedFragments\n\t\t? null\n\t\t: createFractureSourceMesh(\n\t\t\tsourceMesh,\n\t\t\troot,\n\t\t\tref.options.innerMaterial,\n\t\t);\n\n\ttry {\n\t\tconst fragmentPhysics = resolveFragmentPhysicsOptions(\n\t\t\tref.options.fragmentPhysics,\n\t\t);\n\t\tconst fragments = usePrebakedFragments\n\t\t\t? instantiatePrebakedFragments(\n\t\t\t\tsourceMesh,\n\t\t\t\tref.options.innerMaterial,\n\t\t\t\tstate.prebakedFragments,\n\t\t\t)\n\t\t\t: source!.fracture(fractureOptions);\n\t\tcachePrebakedFragments(state, cacheKey, fragments);\n\n\t\tstate.fragments = [...fragments];\n\t\tstate.isFractured = true;\n\n\t\tif (fragmentPhysics.mode === 'independent') {\n\t\t\tfractureIndependentEntity(\n\t\t\t\tref,\n\t\t\t\tentity,\n\t\t\t\troot,\n\t\t\t\tfractureOptions,\n\t\t\t\tfragments,\n\t\t\t\tstate,\n\t\t\t);\n\t\t} else {\n\t\t\tfractureCompoundEntity(\n\t\t\t\tref,\n\t\t\t\tentity,\n\t\t\t\troot,\n\t\t\t\tfragments,\n\t\t\t\tstate,\n\t\t\t);\n\t\t}\n\n\t\treturn fragments;\n\t} catch (error) {\n\t\trestoreRuntimeState(ref, true);\n\t\tthrow error;\n\t} finally {\n\t\tsource?.geometry.dispose();\n\t}\n}\n\nfunction prebakeEntityGeometryOnly(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n): void {\n\tconst entity = requireEntity(ref);\n\tif (entity.isInstanced) {\n\t\tthrow new Error(\n\t\t\t'Destructible3DBehavior does not support entities using instanced rendering.',\n\t\t);\n\t}\n\n\tconst state = getRuntimeState(ref);\n\tif (state.isFractured) {\n\t\treturn;\n\t}\n\n\tconst fractureOptions = resolveFractureOptions(\n\t\tref.options.fractureOptions,\n\t\toverrideOptions,\n\t);\n\tconst cacheKey = buildFractureGeometryCacheKey(fractureOptions);\n\tif (\n\t\tstate.prebakedFractureKey === cacheKey\n\t\t&& state.prebakedFragments.length > 0\n\t) {\n\t\treturn;\n\t}\n\n\tconst sourceMesh = requireEntityMesh(entity);\n\tconst root = ensureRootGroup(entity, state);\n\tconst createdRootGroup = state.createdRootGroup;\n\n\tconst source = createFractureSourceMesh(\n\t\tsourceMesh,\n\t\troot,\n\t\tref.options.innerMaterial,\n\t);\n\ttry {\n\t\tconst fragments = source.fracture(fractureOptions) as DestructibleMesh[];\n\t\tcachePrebakedFragments(state, cacheKey, fragments);\n\t\tfor (const fragment of fragments) {\n\t\t\tfragment.geometry.dispose();\n\t\t}\n\t} finally {\n\t\tsource.geometry.dispose();\n\t}\n\n\tif (createdRootGroup) {\n\t\trestoreOriginalMesh(entity, state);\n\t\tstate.createdRootGroup = false;\n\t}\n}\n\nasync function prebakeEntityAsync(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n): Promise<void> {\n\tconst workerUrl = ref.options.prebakeWorkerUrl;\n\tif (!workerUrl) {\n\t\tprebakeEntityGeometryOnly(ref, overrideOptions);\n\t\treturn;\n\t}\n\n\tconst existing = prebakeAsyncInFlight.get(ref);\n\tif (existing) {\n\t\tawait existing;\n\t\treturn;\n\t}\n\n\tconst job = (async () => {\n\t\tconst entity = requireEntity(ref);\n\t\tif (entity.isInstanced) {\n\t\t\tthrow new Error(\n\t\t\t\t'Destructible3DBehavior does not support entities using instanced rendering.',\n\t\t\t);\n\t\t}\n\n\t\tconst state = getRuntimeState(ref);\n\t\tif (state.isFractured) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst fractureOptions = resolveFractureOptions(\n\t\t\tref.options.fractureOptions,\n\t\t\toverrideOptions,\n\t\t);\n\t\tconst cacheKey = buildFractureGeometryCacheKey(fractureOptions);\n\t\tif (\n\t\t\tstate.prebakedFractureKey === cacheKey\n\t\t\t&& state.prebakedFragments.length > 0\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst sourceMesh = requireEntityMesh(entity);\n\t\tconst root = ensureRootGroup(entity, state);\n\t\tconst createdRootGroup = state.createdRootGroup;\n\n\t\tconst normalizedGeometry = buildNormalizedFractureSourceGeometry(\n\t\t\tsourceMesh,\n\t\t\troot,\n\t\t);\n\n\t\tif (createdRootGroup) {\n\t\t\trestoreOriginalMesh(entity, state);\n\t\t\tstate.createdRootGroup = false;\n\t\t}\n\n\t\tconst { payload, transferables } = bufferGeometryToPlain(normalizedGeometry);\n\t\tnormalizedGeometry.dispose();\n\n\t\tconst plainOptions = pinataFractureOptionsToPlain(fractureOptions);\n\t\tconst api = getPrebakeWorkerApi(workerUrl);\n\t\tconst request = Comlink.transfer(\n\t\t\t{ geometry: payload, options: plainOptions },\n\t\t\ttransferables,\n\t\t);\n\n\t\tconst response = await api.prebake(request);\n\t\tconst parts = plainWorkerResultToTemplateParts(response);\n\t\tinstallPrebakedTemplateParts(state, cacheKey, parts);\n\t})();\n\n\tprebakeAsyncInFlight.set(ref, job);\n\ttry {\n\t\tawait job;\n\t} finally {\n\t\tif (prebakeAsyncInFlight.get(ref) === job) {\n\t\t\tprebakeAsyncInFlight.delete(ref);\n\t\t}\n\t}\n}\n\nfunction prebakeEntity(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n\toverrideOptions?: FractureOptionsInput | PinataFractureOptions,\n): void {\n\tprebakeEntityGeometryOnly(ref, overrideOptions);\n}\n\nfunction createDestructible3DHandle(\n\tref: BehaviorRef<Destructible3DBehaviorOptions>,\n): Destructible3DHandle {\n\treturn {\n\t\tfracture: (overrideOptions) => fractureEntity(ref, overrideOptions),\n\t\tprebake: (overrideOptions) => {\n\t\t\tprebakeEntity(ref, overrideOptions);\n\t\t},\n\t\tprebakeAsync: (overrideOptions) => prebakeEntityAsync(ref, overrideOptions),\n\t\trepair: () => restoreRuntimeState(ref, true),\n\t\tisFractured: () => getRuntimeState(ref).isFractured,\n\t\tgetFragments: () => getRuntimeState(ref).fragments,\n\t};\n}\n\nclass Destructible3DSystem implements BehaviorSystem {\n\tconstructor(\n\t\tprivate world: unknown,\n\t\tprivate scene: unknown,\n\t\tprivate getBehaviorLinks?: (key: symbol) => Iterable<BehaviorEntityLink>,\n\t\tprivate createEntity?: CreateEntityFn,\n\t\tprivate getGlobals?: () => any,\n\t) {\n\t\tthis.primeLinks();\n\t}\n\n\tattach(link: BehaviorEntityLink): void {\n\t\tif (link.ref?.descriptor?.key !== DESTRUCTIBLE_3D_BEHAVIOR_KEY) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.primeLink(link);\n\t}\n\n\tupdate(_ecs: unknown, _delta: number): void {\n\t\tthis.primeLinks();\n\t\tconst links = this.getBehaviorLinks?.(DESTRUCTIBLE_3D_BEHAVIOR_KEY);\n\t\tif (!links) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst interpolationAlpha =\n\t\t\t(this.world as { interpolationAlpha?: number } | null)?.interpolationAlpha\n\t\t\t?? 0;\n\t\tfor (const link of links) {\n\t\t\tconst state = getRuntimeState(\n\t\t\t\tlink.ref as BehaviorRef<Destructible3DBehaviorOptions>,\n\t\t\t);\n\t\t\tfor (const fragmentEntity of state.fragmentEntities) {\n\t\t\t\tsyncRuntimeFragmentEntityTransform(\n\t\t\t\t\tfragmentEntity,\n\t\t\t\t\tinterpolationAlpha,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tdestroy(_ecs: unknown): void {\n\t\tconst links = this.getBehaviorLinks?.(DESTRUCTIBLE_3D_BEHAVIOR_KEY);\n\t\tif (!links) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const link of links) {\n\t\t\tconst ref = link.ref as BehaviorRef<Destructible3DBehaviorOptions>;\n\t\t\trestoreRuntimeState(ref, false);\n\t\t\tdisposeRuntimeState(getRuntimeState(ref));\n\t\t}\n\t}\n\n\tprivate primeLinks(): void {\n\t\tconst links = this.getBehaviorLinks?.(DESTRUCTIBLE_3D_BEHAVIOR_KEY);\n\t\tif (!links) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const link of links) {\n\t\t\tthis.primeLink(link);\n\t\t}\n\t}\n\n\tprivate primeLink(link: BehaviorEntityLink): void {\n\t\tconst ref = link.ref as BehaviorRef<Destructible3DBehaviorOptions> & {\n\t\t\t__cleanupRegistered?: boolean;\n\t\t};\n\t\tconst entity = link.entity as GameEntity<any>;\n\t\t(ref as any).__entity = entity;\n\t\t(ref as any).__world = this.world;\n\t\t(ref as any).__scene = this.scene;\n\t\t(ref as any).__createEntity = this.createEntity;\n\t\t(ref as any).__getGlobals = this.getGlobals;\n\n\t\tif (!ref.__cleanupRegistered) {\n\t\t\tentity.onCleanup(() => {\n\t\t\t\trestoreRuntimeState(ref, false);\n\t\t\t\tdisposeRuntimeState(getRuntimeState(ref));\n\t\t\t});\n\t\t\tref.__cleanupRegistered = true;\n\t\t}\n\t}\n}\n\nexport const Destructible3DBehavior = defineBehavior<\n\tDestructible3DBehaviorOptions,\n\tDestructible3DHandle\n>({\n\tname: 'destructible-3d',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew Destructible3DSystem(\n\t\t\tctx.world,\n\t\t\tctx.scene,\n\t\t\tctx.getBehaviorLinks,\n\t\t\tctx.createEntity,\n\t\t\tctx.getGlobals,\n\t\t),\n\tcreateHandle: createDestructible3DHandle,\n});\n","import { Quaternion } from 'three';\n\nexport interface PhysicsVector3 {\n\tx: number;\n\ty: number;\n\tz: number;\n}\n\nexport interface PhysicsQuaternion {\n\tx: number;\n\ty: number;\n\tz: number;\n\tw: number;\n}\n\nexport interface PhysicsPose {\n\tposition: PhysicsVector3;\n\trotation: PhysicsQuaternion;\n}\n\nexport interface PhysicsPoseHistory {\n\tprevious: PhysicsPose;\n\tcurrent: PhysicsPose;\n}\n\nexport interface PhysicsPoseReadable {\n\ttranslation(): PhysicsVector3;\n\trotation(): PhysicsQuaternion;\n}\n\nexport interface PhysicsRenderPoseProvider {\n\tgetPoseHistory(): PhysicsPoseHistory;\n\tgetRenderPose(alpha: number): PhysicsPose;\n}\n\nconst directBodyPoseHistory = new WeakMap<object, PhysicsPoseHistory>();\nconst _previousQuaternion = new Quaternion();\nconst _currentQuaternion = new Quaternion();\nconst _renderQuaternion = new Quaternion();\n\nexport function createPhysicsPose(\n\tposition: Partial<PhysicsVector3> = {},\n\trotation: Partial<PhysicsQuaternion> = {},\n): PhysicsPose {\n\treturn {\n\t\tposition: {\n\t\t\tx: position.x ?? 0,\n\t\t\ty: position.y ?? 0,\n\t\t\tz: position.z ?? 0,\n\t\t},\n\t\trotation: {\n\t\t\tx: rotation.x ?? 0,\n\t\t\ty: rotation.y ?? 0,\n\t\t\tz: rotation.z ?? 0,\n\t\t\tw: rotation.w ?? 1,\n\t\t},\n\t};\n}\n\nexport function clonePhysicsVector3(vector: PhysicsVector3): PhysicsVector3 {\n\treturn { x: vector.x, y: vector.y, z: vector.z };\n}\n\nexport function clonePhysicsQuaternion(\n\trotation: PhysicsQuaternion,\n): PhysicsQuaternion {\n\treturn { x: rotation.x, y: rotation.y, z: rotation.z, w: rotation.w };\n}\n\nexport function clonePhysicsPose(pose: PhysicsPose): PhysicsPose {\n\treturn {\n\t\tposition: clonePhysicsVector3(pose.position),\n\t\trotation: clonePhysicsQuaternion(pose.rotation),\n\t};\n}\n\nexport function clampInterpolationAlpha(alpha: number): number {\n\tif (!Number.isFinite(alpha)) return 0;\n\treturn Math.max(0, Math.min(1, alpha));\n}\n\nexport function capturePhysicsPose(body: PhysicsPoseReadable): PhysicsPose {\n\treturn {\n\t\tposition: clonePhysicsVector3(body.translation()),\n\t\trotation: clonePhysicsQuaternion(body.rotation()),\n\t};\n}\n\nexport function createCollapsedPhysicsPoseHistory(\n\tpose: PhysicsPose,\n): PhysicsPoseHistory {\n\tconst current = clonePhysicsPose(pose);\n\treturn {\n\t\tprevious: clonePhysicsPose(current),\n\t\tcurrent,\n\t};\n}\n\nexport function registerDirectBodyPoseHistory(\n\tbody: object & PhysicsPoseReadable,\n): PhysicsPoseHistory {\n\tconst history = createCollapsedPhysicsPoseHistory(capturePhysicsPose(body));\n\tdirectBodyPoseHistory.set(body, history);\n\treturn history;\n}\n\nexport function getDirectBodyPoseHistory(\n\tbody: object,\n): PhysicsPoseHistory | null {\n\treturn directBodyPoseHistory.get(body) ?? null;\n}\n\nexport function collapseDirectBodyPoseHistory(\n\tbody: object & PhysicsPoseReadable,\n): PhysicsPoseHistory {\n\tconst pose = capturePhysicsPose(body);\n\tconst history =\n\t\tdirectBodyPoseHistory.get(body) ?? createCollapsedPhysicsPoseHistory(pose);\n\n\thistory.previous = clonePhysicsPose(pose);\n\thistory.current = clonePhysicsPose(pose);\n\tdirectBodyPoseHistory.set(body, history);\n\n\treturn history;\n}\n\nexport function prepareDirectBodyPoseHistoryStep(\n\tbody: object & PhysicsPoseReadable,\n): PhysicsPoseHistory {\n\treturn collapseDirectBodyPoseHistory(body);\n}\n\nexport function commitDirectBodyPoseHistoryStep(\n\tbody: object & PhysicsPoseReadable,\n): PhysicsPoseHistory {\n\tconst pose = capturePhysicsPose(body);\n\tconst history =\n\t\tdirectBodyPoseHistory.get(body) ?? createCollapsedPhysicsPoseHistory(pose);\n\n\thistory.current = clonePhysicsPose(pose);\n\tdirectBodyPoseHistory.set(body, history);\n\n\treturn history;\n}\n\nexport function interpolatePhysicsPose(\n\tprevious: PhysicsPose,\n\tcurrent: PhysicsPose,\n\talpha: number,\n): PhysicsPose {\n\tconst t = clampInterpolationAlpha(alpha);\n\n\t_previousQuaternion.set(\n\t\tprevious.rotation.x,\n\t\tprevious.rotation.y,\n\t\tprevious.rotation.z,\n\t\tprevious.rotation.w,\n\t);\n\t_currentQuaternion.set(\n\t\tcurrent.rotation.x,\n\t\tcurrent.rotation.y,\n\t\tcurrent.rotation.z,\n\t\tcurrent.rotation.w,\n\t);\n\t_renderQuaternion.slerpQuaternions(\n\t\t_previousQuaternion,\n\t\t_currentQuaternion,\n\t\tt,\n\t);\n\n\treturn {\n\t\tposition: {\n\t\t\tx: previous.position.x + (current.position.x - previous.position.x) * t,\n\t\t\ty: previous.position.y + (current.position.y - previous.position.y) * t,\n\t\t\tz: previous.position.z + (current.position.z - previous.position.z) * t,\n\t\t},\n\t\trotation: {\n\t\t\tx: _renderQuaternion.x,\n\t\t\ty: _renderQuaternion.y,\n\t\t\tz: _renderQuaternion.z,\n\t\t\tw: _renderQuaternion.w,\n\t\t},\n\t};\n}\n\nexport function getBodyPoseHistory(body: unknown): PhysicsPoseHistory | null {\n\tif (isRenderPoseProvider(body)) {\n\t\treturn body.getPoseHistory();\n\t}\n\tif (isPhysicsPoseReadable(body)) {\n\t\treturn directBodyPoseHistory.get(body as object) ?? null;\n\t}\n\treturn null;\n}\n\nexport function getBodyRenderPose(\n\tbody: PhysicsPoseReadable | PhysicsRenderPoseProvider,\n\talpha: number,\n): PhysicsPose {\n\tif (isRenderPoseProvider(body)) {\n\t\treturn body.getRenderPose(alpha);\n\t}\n\n\tconst history = directBodyPoseHistory.get(body as object);\n\tif (!history) {\n\t\treturn capturePhysicsPose(body);\n\t}\n\n\tconst latestPose = capturePhysicsPose(body);\n\tif (!posesEqual(latestPose, history.current)) {\n\t\tconst collapsed = collapseDirectBodyPoseHistory(body as object & PhysicsPoseReadable);\n\t\treturn clonePhysicsPose(collapsed.current);\n\t}\n\n\treturn interpolatePhysicsPose(history.previous, history.current, alpha);\n}\n\nfunction isPhysicsPoseReadable(value: unknown): value is PhysicsPoseReadable {\n\treturn (\n\t\tvalue != null &&\n\t\ttypeof value === 'object' &&\n\t\ttypeof (value as PhysicsPoseReadable).translation === 'function' &&\n\t\ttypeof (value as PhysicsPoseReadable).rotation === 'function'\n\t);\n}\n\nfunction isRenderPoseProvider(value: unknown): value is PhysicsRenderPoseProvider {\n\treturn (\n\t\tvalue != null &&\n\t\ttypeof value === 'object' &&\n\t\ttypeof (value as PhysicsRenderPoseProvider).getPoseHistory === 'function' &&\n\t\ttypeof (value as PhysicsRenderPoseProvider).getRenderPose === 'function'\n\t);\n}\n\nfunction posesEqual(a: PhysicsPose, b: PhysicsPose): boolean {\n\treturn (\n\t\ta.position.x === b.position.x &&\n\t\ta.position.y === b.position.y &&\n\t\ta.position.z === b.position.z &&\n\t\ta.rotation.x === b.rotation.x &&\n\t\ta.rotation.y === b.rotation.y &&\n\t\ta.rotation.z === b.rotation.z &&\n\t\ta.rotation.w === b.rotation.w\n\t);\n}\n","export * from './destructible-3d.descriptor';\nexport type {\n\tDestructiblePrebakeWorkerAPI,\n\tPlainBufferGeometryPayload,\n\tPlainFractureOptions,\n\tPrebakeWorkerRequest,\n\tPrebakeWorkerResponse,\n} from '../../destructible-prebake';\nexport {\n\tDestructibleMesh,\n\tFractureOptions,\n\ttype VoronoiOptions,\n} from '@dgreenheck/three-pinata';\n"],"mappings":"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","names":["Quaternion","Quaternion","parent","DestructibleMesh"]}