@zylem/behaviors 0.5.2 → 0.5.7

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 (165) hide show
  1. package/dist/{behavior-system-CldqNUgr.d.ts → behavior-system-HEt67el5.d.ts} +14 -1
  2. package/dist/{chunk-EIWQM6U3.js → chunk-2HKY6WF7.js} +0 -1
  3. package/dist/{chunk-IZJFUAXB.js → chunk-2HLZBWGD.js} +0 -1
  4. package/dist/{chunk-LL4FLHIY.js → chunk-2YF7J3H4.js} +0 -1
  5. package/dist/{chunk-SGHIGTVZ.js → chunk-3X3CL24Z.js} +0 -1
  6. package/dist/{chunk-HZMY3TT4.js → chunk-4DVDFCVY.js} +0 -1
  7. package/dist/{chunk-QVCMJ4Q2.js → chunk-4EWASZHB.js} +0 -1
  8. package/dist/{chunk-4LLK2FJI.js → chunk-55CFXXZH.js} +3 -4
  9. package/dist/{chunk-4MZ57HPD.js → chunk-57GLKGEX.js} +3 -4
  10. package/dist/{chunk-QS3VXWVO.js → chunk-7GGR26YA.js} +3 -4
  11. package/dist/{chunk-Y4PHT2HG.js → chunk-7LHXAEOZ.js} +4 -5
  12. package/dist/{chunk-PLIXVF7B.js → chunk-7TIIRJKF.js} +3 -4
  13. package/dist/{chunk-LZIHSJZR.js → chunk-CB3C7CRD.js} +4 -5
  14. package/dist/{chunk-G2KUXVU6.js → chunk-CTSYM56P.js} +30 -12
  15. package/dist/{chunk-2PAHQZZD.js → chunk-CVRN7YAI.js} +3 -4
  16. package/dist/{chunk-NW4SE5XW.js → chunk-DD4U42FG.js} +2 -3
  17. package/dist/{chunk-BAXJ7XHJ.js → chunk-E2MOFIDH.js} +3 -4
  18. package/dist/{chunk-WOMHL23C.js → chunk-ERS6SNA5.js} +1 -2
  19. package/dist/{chunk-4WH2ZN7P.js → chunk-F7E23E26.js} +0 -1
  20. package/dist/{chunk-DZ4LLQON.js → chunk-GZ3DQIIZ.js} +23 -2
  21. package/dist/{chunk-5WRI5ZAA.js → chunk-JSBRDJBE.js} +0 -1
  22. package/dist/{chunk-5A5AYP2C.js → chunk-K6CWKFHL.js} +0 -1
  23. package/dist/{chunk-52FJIDGL.js → chunk-LAN7U3AK.js} +1 -2
  24. package/dist/{chunk-WU6XXL3D.js → chunk-LLDLVVG4.js} +4 -5
  25. package/dist/{chunk-M3QDKKDF.js → chunk-LWM346FW.js} +0 -1
  26. package/dist/{chunk-7DGXUAPV.js → chunk-M25QJBDN.js} +4 -5
  27. package/dist/{chunk-7JLWZXPA.js → chunk-NDJO56BB.js} +3 -4
  28. package/dist/{chunk-AS3HR7AS.js → chunk-OBF6BIA2.js} +1 -2
  29. package/dist/{chunk-KIYUUSPK.js → chunk-OSPQFWQF.js} +2 -3
  30. package/dist/{chunk-4CEW64HO.js → chunk-OU2SW4U5.js} +3 -4
  31. package/dist/{chunk-H4TJ7X4O.js → chunk-QU6GQ657.js} +2 -3
  32. package/dist/{chunk-KFFETUAL.js → chunk-RR3XNDKG.js} +2 -3
  33. package/dist/{chunk-JVADRLWX.js → chunk-SHZZ2QRV.js} +2 -3
  34. package/dist/{chunk-7W3KY55G.js → chunk-TK3AXXXI.js} +3 -4
  35. package/dist/{chunk-OPZ2LVS2.js → chunk-TZQQYJYK.js} +0 -1
  36. package/dist/{chunk-7JJEIADR.js → chunk-UF7QPYUX.js} +299 -157
  37. package/dist/{chunk-NQPYMUDF.js → chunk-UKGBQTHL.js} +3 -4
  38. package/dist/{chunk-5XPPLTC7.js → chunk-UUMH3DC3.js} +1 -2
  39. package/dist/{chunk-TBUKJKY6.js → chunk-VJ3UA6OD.js} +1 -2
  40. package/dist/{chunk-OHCPV2NT.js → chunk-WHKPWIQO.js} +0 -1
  41. package/dist/{chunk-EZNCCO4L.js → chunk-YDLO5M7S.js} +0 -1
  42. package/dist/{components-BmievOxF.d.ts → components-JZQoO2sU.d.ts} +1 -1
  43. package/dist/cooldown.d.ts +1 -1
  44. package/dist/cooldown.js +3 -4
  45. package/dist/coordinators/boundary-ricochet-3d.d.ts +2 -2
  46. package/dist/coordinators/boundary-ricochet-3d.js +4 -5
  47. package/dist/coordinators/boundary-ricochet.d.ts +2 -2
  48. package/dist/coordinators/boundary-ricochet.js +4 -5
  49. package/dist/coordinators/first-person-shooter.js +4 -5
  50. package/dist/coordinators/multidirectional-space-shooter.d.ts +1 -1
  51. package/dist/coordinators/multidirectional-space-shooter.js +6 -7
  52. package/dist/coordinators/top-down-shooter.d.ts +1 -1
  53. package/dist/coordinators/top-down-shooter.js +6 -7
  54. package/dist/core.d.ts +21 -6
  55. package/dist/core.js +29 -7
  56. package/dist/destructible-3d.d.ts +1 -1
  57. package/dist/destructible-3d.js +4 -5
  58. package/dist/destructible-prebake.js +2 -3
  59. package/dist/{first-person-perspective-C9Mptl0-.d.ts → first-person-perspective-BxFHgFln.d.ts} +2 -0
  60. package/dist/first-person.d.ts +12 -3
  61. package/dist/first-person.js +7 -8
  62. package/dist/index.d.ts +5 -5
  63. package/dist/index.js +40 -41
  64. package/dist/jumper-2d.d.ts +1 -1
  65. package/dist/jumper-2d.js +5 -6
  66. package/dist/jumper-3d.d.ts +1 -1
  67. package/dist/jumper-3d.js +6 -7
  68. package/dist/{moveable-rdIvWiak.d.ts → moveable-BdFmI3s1.d.ts} +1 -1
  69. package/dist/particle-emitter/presets.d.ts +1 -1
  70. package/dist/particle-emitter/presets.js +2 -3
  71. package/dist/particle-emitter.d.ts +3 -3
  72. package/dist/particle-emitter.js +5 -6
  73. package/dist/platformer-2d.d.ts +1 -1
  74. package/dist/platformer-2d.js +5 -6
  75. package/dist/platformer-3d.d.ts +1 -1
  76. package/dist/platformer-3d.js +5 -6
  77. package/dist/ricochet-2d.d.ts +1 -1
  78. package/dist/ricochet-2d.js +5 -6
  79. package/dist/ricochet-3d.d.ts +1 -1
  80. package/dist/ricochet-3d.js +5 -6
  81. package/dist/runtime-2d.d.ts +1 -1
  82. package/dist/runtime-2d.js +2 -3
  83. package/dist/screen-visibility.d.ts +1 -1
  84. package/dist/screen-visibility.js +3 -4
  85. package/dist/screen-wrap.d.ts +1 -1
  86. package/dist/screen-wrap.js +5 -6
  87. package/dist/shooter-2d.d.ts +1 -1
  88. package/dist/shooter-2d.js +5 -6
  89. package/dist/{spark-Dx3cJbTW.d.ts → spark-C4Tp-52_.d.ts} +4 -2
  90. package/dist/thruster.d.ts +1 -1
  91. package/dist/thruster.js +5 -6
  92. package/dist/top-down-movement.d.ts +1 -1
  93. package/dist/top-down-movement.js +7 -8
  94. package/dist/world-boundary-2d.d.ts +1 -1
  95. package/dist/world-boundary-2d.js +6 -7
  96. package/dist/world-boundary-3d.d.ts +1 -1
  97. package/dist/world-boundary-3d.js +6 -7
  98. package/package.json +159 -161
  99. package/dist/chunk-2PAHQZZD.js.map +0 -1
  100. package/dist/chunk-4CEW64HO.js.map +0 -1
  101. package/dist/chunk-4LLK2FJI.js.map +0 -1
  102. package/dist/chunk-4MZ57HPD.js.map +0 -1
  103. package/dist/chunk-4WH2ZN7P.js.map +0 -1
  104. package/dist/chunk-52FJIDGL.js.map +0 -1
  105. package/dist/chunk-5A5AYP2C.js.map +0 -1
  106. package/dist/chunk-5WRI5ZAA.js.map +0 -1
  107. package/dist/chunk-5XPPLTC7.js.map +0 -1
  108. package/dist/chunk-7DGXUAPV.js.map +0 -1
  109. package/dist/chunk-7JJEIADR.js.map +0 -1
  110. package/dist/chunk-7JLWZXPA.js.map +0 -1
  111. package/dist/chunk-7W3KY55G.js.map +0 -1
  112. package/dist/chunk-AS3HR7AS.js.map +0 -1
  113. package/dist/chunk-BAXJ7XHJ.js.map +0 -1
  114. package/dist/chunk-DZ4LLQON.js.map +0 -1
  115. package/dist/chunk-EIWQM6U3.js.map +0 -1
  116. package/dist/chunk-EZNCCO4L.js.map +0 -1
  117. package/dist/chunk-G2KUXVU6.js.map +0 -1
  118. package/dist/chunk-H4TJ7X4O.js.map +0 -1
  119. package/dist/chunk-HZMY3TT4.js.map +0 -1
  120. package/dist/chunk-IZJFUAXB.js.map +0 -1
  121. package/dist/chunk-JVADRLWX.js.map +0 -1
  122. package/dist/chunk-KFFETUAL.js.map +0 -1
  123. package/dist/chunk-KIYUUSPK.js.map +0 -1
  124. package/dist/chunk-LL4FLHIY.js.map +0 -1
  125. package/dist/chunk-LZIHSJZR.js.map +0 -1
  126. package/dist/chunk-M3QDKKDF.js.map +0 -1
  127. package/dist/chunk-NQPYMUDF.js.map +0 -1
  128. package/dist/chunk-NW4SE5XW.js.map +0 -1
  129. package/dist/chunk-OHCPV2NT.js.map +0 -1
  130. package/dist/chunk-OPZ2LVS2.js.map +0 -1
  131. package/dist/chunk-PLIXVF7B.js.map +0 -1
  132. package/dist/chunk-QS3VXWVO.js.map +0 -1
  133. package/dist/chunk-QVCMJ4Q2.js.map +0 -1
  134. package/dist/chunk-SGHIGTVZ.js.map +0 -1
  135. package/dist/chunk-TBUKJKY6.js.map +0 -1
  136. package/dist/chunk-WOMHL23C.js.map +0 -1
  137. package/dist/chunk-WU6XXL3D.js.map +0 -1
  138. package/dist/chunk-Y4PHT2HG.js.map +0 -1
  139. package/dist/cooldown.js.map +0 -1
  140. package/dist/coordinators/boundary-ricochet-3d.js.map +0 -1
  141. package/dist/coordinators/boundary-ricochet.js.map +0 -1
  142. package/dist/coordinators/first-person-shooter.js.map +0 -1
  143. package/dist/coordinators/multidirectional-space-shooter.js.map +0 -1
  144. package/dist/coordinators/top-down-shooter.js.map +0 -1
  145. package/dist/core.js.map +0 -1
  146. package/dist/destructible-3d.js.map +0 -1
  147. package/dist/destructible-prebake.js.map +0 -1
  148. package/dist/first-person.js.map +0 -1
  149. package/dist/index.js.map +0 -1
  150. package/dist/jumper-2d.js.map +0 -1
  151. package/dist/jumper-3d.js.map +0 -1
  152. package/dist/particle-emitter/presets.js.map +0 -1
  153. package/dist/particle-emitter.js.map +0 -1
  154. package/dist/platformer-2d.js.map +0 -1
  155. package/dist/platformer-3d.js.map +0 -1
  156. package/dist/ricochet-2d.js.map +0 -1
  157. package/dist/ricochet-3d.js.map +0 -1
  158. package/dist/runtime-2d.js.map +0 -1
  159. package/dist/screen-visibility.js.map +0 -1
  160. package/dist/screen-wrap.js.map +0 -1
  161. package/dist/shooter-2d.js.map +0 -1
  162. package/dist/thruster.js.map +0 -1
  163. package/dist/top-down-movement.js.map +0 -1
  164. package/dist/world-boundary-2d.js.map +0 -1
  165. package/dist/world-boundary-3d.js.map +0 -1
@@ -1,20 +1,19 @@
1
1
  import {
2
2
  TopDownMovementBehavior
3
- } from "./chunk-Y4PHT2HG.js";
3
+ } from "./chunk-7LHXAEOZ.js";
4
4
  import {
5
5
  createTopDownMovementComponent,
6
6
  createTopDownMovementInputComponent,
7
7
  createTopDownMovementStateComponent
8
- } from "./chunk-EIWQM6U3.js";
9
- import "./chunk-TBUKJKY6.js";
10
- import "./chunk-SGHIGTVZ.js";
11
- import "./chunk-DZ4LLQON.js";
12
- import "./chunk-EZNCCO4L.js";
13
- import "./chunk-5WRI5ZAA.js";
8
+ } from "./chunk-2HKY6WF7.js";
9
+ import "./chunk-VJ3UA6OD.js";
10
+ import "./chunk-3X3CL24Z.js";
11
+ import "./chunk-GZ3DQIIZ.js";
12
+ import "./chunk-YDLO5M7S.js";
13
+ import "./chunk-JSBRDJBE.js";
14
14
  export {
15
15
  TopDownMovementBehavior,
16
16
  createTopDownMovementComponent,
17
17
  createTopDownMovementInputComponent,
18
18
  createTopDownMovementStateComponent
19
19
  };
20
- //# sourceMappingURL=top-down-movement.js.map
@@ -1,4 +1,4 @@
1
- import { a as BehaviorDescriptor } from './behavior-system-CldqNUgr.js';
1
+ import { a as BehaviorDescriptor } from './behavior-system-HEt67el5.js';
2
2
  import { S as SyncStateMachine } from './sync-state-machine-CZyspBpj.js';
3
3
  import '@zylem/runtime';
4
4
  import 'typescript-fsm';
@@ -5,12 +5,12 @@ import {
5
5
  WorldBoundary2DState,
6
6
  computeWorldBoundary2DHits,
7
7
  hasAnyWorldBoundary2DHit
8
- } from "./chunk-7DGXUAPV.js";
9
- import "./chunk-OPZ2LVS2.js";
10
- import "./chunk-AS3HR7AS.js";
11
- import "./chunk-DZ4LLQON.js";
12
- import "./chunk-EZNCCO4L.js";
13
- import "./chunk-5WRI5ZAA.js";
8
+ } from "./chunk-M25QJBDN.js";
9
+ import "./chunk-TZQQYJYK.js";
10
+ import "./chunk-OBF6BIA2.js";
11
+ import "./chunk-GZ3DQIIZ.js";
12
+ import "./chunk-YDLO5M7S.js";
13
+ import "./chunk-JSBRDJBE.js";
14
14
  export {
15
15
  WorldBoundary2DBehavior,
16
16
  WorldBoundary2DEvent,
@@ -19,4 +19,3 @@ export {
19
19
  computeWorldBoundary2DHits,
20
20
  hasAnyWorldBoundary2DHit
21
21
  };
22
- //# sourceMappingURL=world-boundary-2d.js.map
@@ -1,4 +1,4 @@
1
- import { a as BehaviorDescriptor } from './behavior-system-CldqNUgr.js';
1
+ import { a as BehaviorDescriptor } from './behavior-system-HEt67el5.js';
2
2
  import { S as SyncStateMachine } from './sync-state-machine-CZyspBpj.js';
3
3
  import '@zylem/runtime';
4
4
  import 'typescript-fsm';
@@ -5,12 +5,12 @@ import {
5
5
  WorldBoundary3DState,
6
6
  computeWorldBoundary3DHits,
7
7
  hasAnyWorldBoundary3DHit
8
- } from "./chunk-WU6XXL3D.js";
9
- import "./chunk-OHCPV2NT.js";
10
- import "./chunk-AS3HR7AS.js";
11
- import "./chunk-DZ4LLQON.js";
12
- import "./chunk-EZNCCO4L.js";
13
- import "./chunk-5WRI5ZAA.js";
8
+ } from "./chunk-LLDLVVG4.js";
9
+ import "./chunk-WHKPWIQO.js";
10
+ import "./chunk-OBF6BIA2.js";
11
+ import "./chunk-GZ3DQIIZ.js";
12
+ import "./chunk-YDLO5M7S.js";
13
+ import "./chunk-JSBRDJBE.js";
14
14
  export {
15
15
  WorldBoundary3DBehavior,
16
16
  WorldBoundary3DEvent,
@@ -19,4 +19,3 @@ export {
19
19
  computeWorldBoundary3DHits,
20
20
  hasAnyWorldBoundary3DHit
21
21
  };
22
- //# sourceMappingURL=world-boundary-3d.js.map
package/package.json CHANGED
@@ -1,162 +1,160 @@
1
1
  {
2
- "name": "@zylem/behaviors",
3
- "version": "0.5.2",
4
- "type": "module",
5
- "description": "Tree-shakable Zylem behavior descriptors, systems, coordinators, and runtime-agnostic behavior helpers.",
6
- "license": "MIT",
7
- "repository": {
8
- "type": "git",
9
- "url": "git+ssh://git@github.com/zylem-game-lib/behaviors.git"
10
- },
11
- "engines": {
12
- "node": ">=22.12.0",
13
- "pnpm": ">=10.32.1"
14
- },
15
- "sideEffects": false,
16
- "files": [
17
- "dist"
18
- ],
19
- "exports": {
20
- ".": {
21
- "types": "./dist/index.d.ts",
22
- "import": "./dist/index.js"
23
- },
24
- "./core": {
25
- "types": "./dist/core.d.ts",
26
- "import": "./dist/core.js"
27
- },
28
- "./destructible-prebake": {
29
- "types": "./dist/destructible-prebake.d.ts",
30
- "import": "./dist/destructible-prebake.js"
31
- },
32
- "./cooldown": {
33
- "types": "./dist/cooldown.d.ts",
34
- "import": "./dist/cooldown.js"
35
- },
36
- "./destructible-3d": {
37
- "types": "./dist/destructible-3d.d.ts",
38
- "import": "./dist/destructible-3d.js"
39
- },
40
- "./first-person": {
41
- "types": "./dist/first-person.d.ts",
42
- "import": "./dist/first-person.js"
43
- },
44
- "./jumper-2d": {
45
- "types": "./dist/jumper-2d.d.ts",
46
- "import": "./dist/jumper-2d.js"
47
- },
48
- "./jumper-3d": {
49
- "types": "./dist/jumper-3d.d.ts",
50
- "import": "./dist/jumper-3d.js"
51
- },
52
- "./particle-emitter": {
53
- "types": "./dist/particle-emitter.d.ts",
54
- "import": "./dist/particle-emitter.js"
55
- },
56
- "./particle-emitter/presets": {
57
- "types": "./dist/particle-emitter/presets.d.ts",
58
- "import": "./dist/particle-emitter/presets.js"
59
- },
60
- "./platformer-2d": {
61
- "types": "./dist/platformer-2d.d.ts",
62
- "import": "./dist/platformer-2d.js"
63
- },
64
- "./platformer-3d": {
65
- "types": "./dist/platformer-3d.d.ts",
66
- "import": "./dist/platformer-3d.js"
67
- },
68
- "./ricochet-2d": {
69
- "types": "./dist/ricochet-2d.d.ts",
70
- "import": "./dist/ricochet-2d.js"
71
- },
72
- "./ricochet-3d": {
73
- "types": "./dist/ricochet-3d.d.ts",
74
- "import": "./dist/ricochet-3d.js"
75
- },
76
- "./runtime-2d": {
77
- "types": "./dist/runtime-2d.d.ts",
78
- "import": "./dist/runtime-2d.js"
79
- },
80
- "./screen-visibility": {
81
- "types": "./dist/screen-visibility.d.ts",
82
- "import": "./dist/screen-visibility.js"
83
- },
84
- "./screen-wrap": {
85
- "types": "./dist/screen-wrap.d.ts",
86
- "import": "./dist/screen-wrap.js"
87
- },
88
- "./shooter-2d": {
89
- "types": "./dist/shooter-2d.d.ts",
90
- "import": "./dist/shooter-2d.js"
91
- },
92
- "./thruster": {
93
- "types": "./dist/thruster.d.ts",
94
- "import": "./dist/thruster.js"
95
- },
96
- "./top-down-movement": {
97
- "types": "./dist/top-down-movement.d.ts",
98
- "import": "./dist/top-down-movement.js"
99
- },
100
- "./world-boundary-2d": {
101
- "types": "./dist/world-boundary-2d.d.ts",
102
- "import": "./dist/world-boundary-2d.js"
103
- },
104
- "./world-boundary-3d": {
105
- "types": "./dist/world-boundary-3d.d.ts",
106
- "import": "./dist/world-boundary-3d.js"
107
- },
108
- "./coordinators/boundary-ricochet": {
109
- "types": "./dist/coordinators/boundary-ricochet.d.ts",
110
- "import": "./dist/coordinators/boundary-ricochet.js"
111
- },
112
- "./coordinators/boundary-ricochet-3d": {
113
- "types": "./dist/coordinators/boundary-ricochet-3d.d.ts",
114
- "import": "./dist/coordinators/boundary-ricochet-3d.js"
115
- },
116
- "./coordinators/first-person-shooter": {
117
- "types": "./dist/coordinators/first-person-shooter.d.ts",
118
- "import": "./dist/coordinators/first-person-shooter.js"
119
- },
120
- "./coordinators/multidirectional-space-shooter": {
121
- "types": "./dist/coordinators/multidirectional-space-shooter.d.ts",
122
- "import": "./dist/coordinators/multidirectional-space-shooter.js"
123
- },
124
- "./coordinators/top-down-shooter": {
125
- "types": "./dist/coordinators/top-down-shooter.d.ts",
126
- "import": "./dist/coordinators/top-down-shooter.js"
127
- },
128
- "./package.json": "./package.json"
129
- },
130
- "scripts": {
131
- "zylem": "node --experimental-strip-types ./scripts/zylem-runner.ts",
132
- "build": "tsup",
133
- "dev": "tsup --watch",
134
- "typecheck": "tsc --noEmit",
135
- "test": "vitest --reporter=verbose",
136
- "prepublishOnly": "pnpm run build && vitest run"
137
- },
138
- "dependencies": {
139
- "@dgreenheck/three-pinata": "^2.0.1",
140
- "@zylem/runtime": "^0.2.2",
141
- "comlink": "^4.4.2",
142
- "typescript-fsm": "^1.6.0",
143
- "valtio": "^2.1.7"
144
- },
145
- "peerDependencies": {
146
- "three": "^0.185.0"
147
- },
148
- "devDependencies": {
149
- "@clack/prompts": "^1.6.0",
150
- "@types/node": "^20.19.13",
151
- "@types/three": "^0.185.0",
152
- "happy-dom": "^18.0.1",
153
- "tsup": "^8.5.1",
154
- "typescript": "5.8.2",
155
- "vitest": "^4.0.9"
156
- },
157
- "packageManager": "pnpm@10.33.0",
158
- "publishConfig": {
159
- "access": "public",
160
- "registry": "https://registry.npmjs.org/"
161
- }
162
- }
2
+ "name": "@zylem/behaviors",
3
+ "version": "0.5.7",
4
+ "type": "module",
5
+ "description": "Tree-shakable Zylem behavior descriptors, systems, coordinators, and runtime-agnostic behavior helpers.",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+ssh://git@github.com/zylem-game-lib/behaviors.git"
10
+ },
11
+ "engines": {
12
+ "node": ">=22.12.0",
13
+ "pnpm": ">=10.32.1"
14
+ },
15
+ "sideEffects": false,
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.js"
23
+ },
24
+ "./core": {
25
+ "types": "./dist/core.d.ts",
26
+ "import": "./dist/core.js"
27
+ },
28
+ "./destructible-prebake": {
29
+ "types": "./dist/destructible-prebake.d.ts",
30
+ "import": "./dist/destructible-prebake.js"
31
+ },
32
+ "./cooldown": {
33
+ "types": "./dist/cooldown.d.ts",
34
+ "import": "./dist/cooldown.js"
35
+ },
36
+ "./destructible-3d": {
37
+ "types": "./dist/destructible-3d.d.ts",
38
+ "import": "./dist/destructible-3d.js"
39
+ },
40
+ "./first-person": {
41
+ "types": "./dist/first-person.d.ts",
42
+ "import": "./dist/first-person.js"
43
+ },
44
+ "./jumper-2d": {
45
+ "types": "./dist/jumper-2d.d.ts",
46
+ "import": "./dist/jumper-2d.js"
47
+ },
48
+ "./jumper-3d": {
49
+ "types": "./dist/jumper-3d.d.ts",
50
+ "import": "./dist/jumper-3d.js"
51
+ },
52
+ "./particle-emitter": {
53
+ "types": "./dist/particle-emitter.d.ts",
54
+ "import": "./dist/particle-emitter.js"
55
+ },
56
+ "./particle-emitter/presets": {
57
+ "types": "./dist/particle-emitter/presets.d.ts",
58
+ "import": "./dist/particle-emitter/presets.js"
59
+ },
60
+ "./platformer-2d": {
61
+ "types": "./dist/platformer-2d.d.ts",
62
+ "import": "./dist/platformer-2d.js"
63
+ },
64
+ "./platformer-3d": {
65
+ "types": "./dist/platformer-3d.d.ts",
66
+ "import": "./dist/platformer-3d.js"
67
+ },
68
+ "./ricochet-2d": {
69
+ "types": "./dist/ricochet-2d.d.ts",
70
+ "import": "./dist/ricochet-2d.js"
71
+ },
72
+ "./ricochet-3d": {
73
+ "types": "./dist/ricochet-3d.d.ts",
74
+ "import": "./dist/ricochet-3d.js"
75
+ },
76
+ "./runtime-2d": {
77
+ "types": "./dist/runtime-2d.d.ts",
78
+ "import": "./dist/runtime-2d.js"
79
+ },
80
+ "./screen-visibility": {
81
+ "types": "./dist/screen-visibility.d.ts",
82
+ "import": "./dist/screen-visibility.js"
83
+ },
84
+ "./screen-wrap": {
85
+ "types": "./dist/screen-wrap.d.ts",
86
+ "import": "./dist/screen-wrap.js"
87
+ },
88
+ "./shooter-2d": {
89
+ "types": "./dist/shooter-2d.d.ts",
90
+ "import": "./dist/shooter-2d.js"
91
+ },
92
+ "./thruster": {
93
+ "types": "./dist/thruster.d.ts",
94
+ "import": "./dist/thruster.js"
95
+ },
96
+ "./top-down-movement": {
97
+ "types": "./dist/top-down-movement.d.ts",
98
+ "import": "./dist/top-down-movement.js"
99
+ },
100
+ "./world-boundary-2d": {
101
+ "types": "./dist/world-boundary-2d.d.ts",
102
+ "import": "./dist/world-boundary-2d.js"
103
+ },
104
+ "./world-boundary-3d": {
105
+ "types": "./dist/world-boundary-3d.d.ts",
106
+ "import": "./dist/world-boundary-3d.js"
107
+ },
108
+ "./coordinators/boundary-ricochet": {
109
+ "types": "./dist/coordinators/boundary-ricochet.d.ts",
110
+ "import": "./dist/coordinators/boundary-ricochet.js"
111
+ },
112
+ "./coordinators/boundary-ricochet-3d": {
113
+ "types": "./dist/coordinators/boundary-ricochet-3d.d.ts",
114
+ "import": "./dist/coordinators/boundary-ricochet-3d.js"
115
+ },
116
+ "./coordinators/first-person-shooter": {
117
+ "types": "./dist/coordinators/first-person-shooter.d.ts",
118
+ "import": "./dist/coordinators/first-person-shooter.js"
119
+ },
120
+ "./coordinators/multidirectional-space-shooter": {
121
+ "types": "./dist/coordinators/multidirectional-space-shooter.d.ts",
122
+ "import": "./dist/coordinators/multidirectional-space-shooter.js"
123
+ },
124
+ "./coordinators/top-down-shooter": {
125
+ "types": "./dist/coordinators/top-down-shooter.d.ts",
126
+ "import": "./dist/coordinators/top-down-shooter.js"
127
+ },
128
+ "./package.json": "./package.json"
129
+ },
130
+ "dependencies": {
131
+ "@dgreenheck/three-pinata": "^2.0.1",
132
+ "@zylem/runtime": "link:../runtime",
133
+ "comlink": "^4.4.2",
134
+ "typescript-fsm": "^1.6.0",
135
+ "valtio": "^2.1.7"
136
+ },
137
+ "peerDependencies": {
138
+ "three": "^0.185.0"
139
+ },
140
+ "devDependencies": {
141
+ "@clack/prompts": "^1.6.0",
142
+ "@types/node": "^20.19.13",
143
+ "@types/three": "^0.185.0",
144
+ "happy-dom": "^18.0.1",
145
+ "tsup": "^8.5.1",
146
+ "typescript": "5.8.2",
147
+ "vitest": "^4.0.9"
148
+ },
149
+ "publishConfig": {
150
+ "access": "public",
151
+ "registry": "https://registry.npmjs.org/"
152
+ },
153
+ "scripts": {
154
+ "zylem": "node --experimental-strip-types ./scripts/zylem-runner.ts",
155
+ "build": "tsup",
156
+ "dev": "tsup --watch",
157
+ "typecheck": "tsc --noEmit",
158
+ "test": "vitest --reporter=verbose"
159
+ }
160
+ }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/behaviors/screen-wrap/screen-wrap-fsm.ts","../src/lib/behaviors/screen-wrap/screen-wrap.descriptor.ts"],"sourcesContent":["/**\n * ScreenWrapFSM\n * \n * State machine for screen wrap behavior.\n * Reports position relative to bounds edges.\n */\n\nimport { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FSM State Model\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport enum ScreenWrapState {\n\tCenter = 'center',\n\tNearEdgeLeft = 'near-edge-left',\n\tNearEdgeRight = 'near-edge-right',\n\tNearEdgeTop = 'near-edge-top',\n\tNearEdgeBottom = 'near-edge-bottom',\n\tWrapped = 'wrapped',\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// FSM Events\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport enum ScreenWrapEvent {\n\tEnterCenter = 'enter-center',\n\tApproachLeft = 'approach-left',\n\tApproachRight = 'approach-right',\n\tApproachTop = 'approach-top',\n\tApproachBottom = 'approach-bottom',\n\tWrap = 'wrap',\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// ScreenWrapFSM\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport class ScreenWrapFSM {\n\tmachine: SyncStateMachine<ScreenWrapState, ScreenWrapEvent, never>;\n\n\tconstructor() {\n\t\tthis.machine = new SyncStateMachine<ScreenWrapState, ScreenWrapEvent, never>(\n\t\t\tScreenWrapState.Center,\n\t\t\t[\n\t\t\t\t// From Center\n\t\t\t\tt(ScreenWrapState.Center, ScreenWrapEvent.ApproachLeft, ScreenWrapState.NearEdgeLeft),\n\t\t\t\tt(ScreenWrapState.Center, ScreenWrapEvent.ApproachRight, ScreenWrapState.NearEdgeRight),\n\t\t\t\tt(ScreenWrapState.Center, ScreenWrapEvent.ApproachTop, ScreenWrapState.NearEdgeTop),\n\t\t\t\tt(ScreenWrapState.Center, ScreenWrapEvent.ApproachBottom, ScreenWrapState.NearEdgeBottom),\n\t\t\t\t\n\t\t\t\t// From NearEdge to Wrapped\n\t\t\t\tt(ScreenWrapState.NearEdgeLeft, ScreenWrapEvent.Wrap, ScreenWrapState.Wrapped),\n\t\t\t\tt(ScreenWrapState.NearEdgeRight, ScreenWrapEvent.Wrap, ScreenWrapState.Wrapped),\n\t\t\t\tt(ScreenWrapState.NearEdgeTop, ScreenWrapEvent.Wrap, ScreenWrapState.Wrapped),\n\t\t\t\tt(ScreenWrapState.NearEdgeBottom, ScreenWrapEvent.Wrap, ScreenWrapState.Wrapped),\n\n\t\t\t\t// From NearEdge back to Center\n\t\t\t\tt(ScreenWrapState.NearEdgeLeft, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\t\t\t\tt(ScreenWrapState.NearEdgeRight, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\t\t\t\tt(ScreenWrapState.NearEdgeTop, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\t\t\t\tt(ScreenWrapState.NearEdgeBottom, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\n\t\t\t\t// From Wrapped back to Center\n\t\t\t\tt(ScreenWrapState.Wrapped, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\n\t\t\t\t// From Wrapped to NearEdge (landed near opposite edge)\n\t\t\t\tt(ScreenWrapState.Wrapped, ScreenWrapEvent.ApproachLeft, ScreenWrapState.NearEdgeLeft),\n\t\t\t\tt(ScreenWrapState.Wrapped, ScreenWrapEvent.ApproachRight, ScreenWrapState.NearEdgeRight),\n\t\t\t\tt(ScreenWrapState.Wrapped, ScreenWrapEvent.ApproachTop, ScreenWrapState.NearEdgeTop),\n\t\t\t\tt(ScreenWrapState.Wrapped, ScreenWrapEvent.ApproachBottom, ScreenWrapState.NearEdgeBottom),\n\n\t\t\t\t// Self-transitions (no-ops for redundant events)\n\t\t\t\tt(ScreenWrapState.Center, ScreenWrapEvent.EnterCenter, ScreenWrapState.Center),\n\t\t\t\tt(ScreenWrapState.NearEdgeLeft, ScreenWrapEvent.ApproachLeft, ScreenWrapState.NearEdgeLeft),\n\t\t\t\tt(ScreenWrapState.NearEdgeRight, ScreenWrapEvent.ApproachRight, ScreenWrapState.NearEdgeRight),\n\t\t\t\tt(ScreenWrapState.NearEdgeTop, ScreenWrapEvent.ApproachTop, ScreenWrapState.NearEdgeTop),\n\t\t\t\tt(ScreenWrapState.NearEdgeBottom, ScreenWrapEvent.ApproachBottom, ScreenWrapState.NearEdgeBottom),\n\t\t\t]\n\t\t);\n\t}\n\n\tgetState(): ScreenWrapState {\n\t\treturn this.machine.getState();\n\t}\n\n\tdispatch(event: ScreenWrapEvent): 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 based on entity position relative to bounds\n\t */\n\tupdate(position: { x: number; y: number }, bounds: {\n\t\tminX: number; maxX: number; minY: number; maxY: number;\n\t\tedgeThreshold: number;\n\t}, wrapped: boolean): void {\n\t\tconst { x, y } = position;\n\t\tconst { minX, maxX, minY, maxY, edgeThreshold } = bounds;\n\n\t\tif (wrapped) {\n\t\t\tthis.dispatch(ScreenWrapEvent.Wrap);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if near edges\n\t\tconst nearLeft = x < minX + edgeThreshold;\n\t\tconst nearRight = x > maxX - edgeThreshold;\n\t\tconst nearBottom = y < minY + edgeThreshold;\n\t\tconst nearTop = y > maxY - edgeThreshold;\n\n\t\tif (nearLeft) {\n\t\t\tthis.dispatch(ScreenWrapEvent.ApproachLeft);\n\t\t} else if (nearRight) {\n\t\t\tthis.dispatch(ScreenWrapEvent.ApproachRight);\n\t\t} else if (nearTop) {\n\t\t\tthis.dispatch(ScreenWrapEvent.ApproachTop);\n\t\t} else if (nearBottom) {\n\t\t\tthis.dispatch(ScreenWrapEvent.ApproachBottom);\n\t\t} else {\n\t\t\tthis.dispatch(ScreenWrapEvent.EnterCenter);\n\t\t}\n\t}\n}\n","/**\n * ScreenWrapBehavior\n * \n * When an entity exits the defined 2D bounds, it wraps around to the opposite edge.\n * Asteroids-style screen wrapping with FSM for edge detection.\n */\n\nimport { defineBehavior } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport { ScreenWrapFSM } from './screen-wrap-fsm';\nimport { createBounds2DRect } from '../shared/bounds-2d';\nimport type { BehaviorRuntime } from '../../runtime/wasm-stage-runtime';\n\n/**\n * Screen wrap options (typed for entity.use() autocomplete)\n */\nexport interface ScreenWrapOptions {\n\t/** Width of the wrapping area (default: 20) */\n\twidth: number;\n\t/** Height of the wrapping area (default: 15) */\n\theight: number;\n\t/** Center X position (default: 0) */\n\tcenterX: number;\n\t/** Center Y position (default: 0) */\n\tcenterY: number;\n\t/** Distance from edge to trigger NearEdge state (default: 2) */\n\tedgeThreshold: number;\n}\n\nconst defaultOptions: ScreenWrapOptions = {\n\twidth: 20,\n\theight: 15,\n\tcenterX: 0,\n\tcenterY: 0,\n\tedgeThreshold: 2,\n};\n\nconst SCREEN_WRAP_BEHAVIOR_KEY = Symbol.for('zylem:behavior:screen-wrap');\n\n/**\n * ScreenWrapSystem - Wraps entities around 2D bounds\n *\n * The Rust `screen_wrap` Stage behavior owns the wrap; this system attaches\n * it and mirrors the queried state into the local FSM so handles can observe\n * edge/wrap states.\n */\nclass ScreenWrapSystem implements BehaviorSystem {\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate wasmStage: BehaviorRuntime | 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?.(SCREEN_WRAP_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 wrapRef = link.ref as any;\n\t\t\tconst options = wrapRef.options as ScreenWrapOptions;\n\n\t\t\tif (!wrapRef.fsm) {\n\t\t\t\twrapRef.fsm = new ScreenWrapFSM();\n\t\t\t}\n\n\t\t\tconst handle = (gameEntity.runtimeHandle ?? -1) as number;\n\t\t\tif (!this.wasmStage || handle < 0) continue;\n\n\t\t\tthis.ensureWasmAttached(handle, options);\n\t\t\tconst pose = this.wasmStage.getPose(handle);\n\t\t\tconst query = this.wasmStage.queryScreenWrap(handle);\n\t\t\tif (pose && query) {\n\t\t\t\tconst bounds = createBounds2DRect(options);\n\t\t\t\twrapRef.fsm.update(\n\t\t\t\t\t{ x: pose.position[0], y: pose.position[1] },\n\t\t\t\t\t{\n\t\t\t\t\t\tminX: bounds.minX,\n\t\t\t\t\t\tmaxX: bounds.maxX,\n\t\t\t\t\t\tminY: bounds.minY,\n\t\t\t\t\t\tmaxY: bounds.maxY,\n\t\t\t\t\t\tedgeThreshold: options.edgeThreshold,\n\t\t\t\t\t},\n\t\t\t\t\tquery.lastWrappedAxes !== 0,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: ScreenWrapOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tthis.wasmStage.attachScreenWrap(handle, {\n\t\t\twidth: options.width,\n\t\t\theight: options.height,\n\t\t\tcenterX: options.centerX,\n\t\t\tcenterY: options.centerY,\n\t\t\tedgeThreshold: options.edgeThreshold,\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 * ScreenWrapBehavior - Wraps entities around 2D bounds\n * \n * @example\n * ```typescript\n * import { ScreenWrapBehavior } from \"@zylem/game-lib/behavior\";\n * \n * const ship = createSprite({ ... });\n * const wrapRef = ship.use(ScreenWrapBehavior, { width: 20, height: 15 });\n * \n * // Access FSM to observe edge state\n * const fsm = wrapRef.getFSM();\n * console.log(fsm?.getState()); // 'center', 'near-edge-left', 'wrapped', etc.\n * ```\n */\nexport const ScreenWrapBehavior = defineBehavior({\n\tname: 'screen-wrap',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew ScreenWrapSystem(ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n});\n"],"mappings":";;;;;;;;;;;;AAaO,IAAK,kBAAL,kBAAKA,qBAAL;AACN,EAAAA,iBAAA,YAAS;AACT,EAAAA,iBAAA,kBAAe;AACf,EAAAA,iBAAA,mBAAgB;AAChB,EAAAA,iBAAA,iBAAc;AACd,EAAAA,iBAAA,oBAAiB;AACjB,EAAAA,iBAAA,aAAU;AANC,SAAAA;AAAA,GAAA;AAaL,IAAK,kBAAL,kBAAKC,qBAAL;AACN,EAAAA,iBAAA,iBAAc;AACd,EAAAA,iBAAA,kBAAe;AACf,EAAAA,iBAAA,mBAAgB;AAChB,EAAAA,iBAAA,iBAAc;AACd,EAAAA,iBAAA,oBAAiB;AACjB,EAAAA,iBAAA,UAAO;AANI,SAAAA;AAAA,GAAA;AAaL,IAAM,gBAAN,MAAoB;AAAA,EAC1B;AAAA,EAEA,cAAc;AACb,SAAK,UAAU,IAAI;AAAA,MAClB;AAAA,MACA;AAAA;AAAA,YAEC,yBAAE,uBAAwB,oCAA8B,mCAA4B;AAAA,YACpF,yBAAE,uBAAwB,sCAA+B,qCAA6B;AAAA,YACtF,yBAAE,uBAAwB,kCAA6B,iCAA2B;AAAA,YAClF,yBAAE,uBAAwB,wCAAgC,uCAA8B;AAAA;AAAA,YAGxF,yBAAE,qCAA8B,mBAAsB,uBAAuB;AAAA,YAC7E,yBAAE,uCAA+B,mBAAsB,uBAAuB;AAAA,YAC9E,yBAAE,mCAA6B,mBAAsB,uBAAuB;AAAA,YAC5E,yBAAE,yCAAgC,mBAAsB,uBAAuB;AAAA;AAAA,YAG/E,yBAAE,qCAA8B,kCAA6B,qBAAsB;AAAA,YACnF,yBAAE,uCAA+B,kCAA6B,qBAAsB;AAAA,YACpF,yBAAE,mCAA6B,kCAA6B,qBAAsB;AAAA,YAClF,yBAAE,yCAAgC,kCAA6B,qBAAsB;AAAA;AAAA,YAGrF,yBAAE,yBAAyB,kCAA6B,qBAAsB;AAAA;AAAA,YAG9E,yBAAE,yBAAyB,oCAA8B,mCAA4B;AAAA,YACrF,yBAAE,yBAAyB,sCAA+B,qCAA6B;AAAA,YACvF,yBAAE,yBAAyB,kCAA6B,iCAA2B;AAAA,YACnF,yBAAE,yBAAyB,wCAAgC,uCAA8B;AAAA;AAAA,YAGzF,yBAAE,uBAAwB,kCAA6B,qBAAsB;AAAA,YAC7E,yBAAE,qCAA8B,oCAA8B,mCAA4B;AAAA,YAC1F,yBAAE,uCAA+B,sCAA+B,qCAA6B;AAAA,YAC7F,yBAAE,mCAA6B,kCAA6B,iCAA2B;AAAA,YACvF,yBAAE,yCAAgC,wCAAgC,uCAA8B;AAAA,MACjG;AAAA,IACD;AAAA,EACD;AAAA,EAEA,WAA4B;AAC3B,WAAO,KAAK,QAAQ,SAAS;AAAA,EAC9B;AAAA,EAEA,SAAS,OAA8B;AACtC,QAAI,KAAK,QAAQ,IAAI,KAAK,GAAG;AAC5B,WAAK,QAAQ,aAAa,KAAK;AAAA,IAChC;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,UAAoC,QAGxC,SAAwB;AAC1B,UAAM,EAAE,GAAG,EAAE,IAAI;AACjB,UAAM,EAAE,MAAM,MAAM,MAAM,MAAM,cAAc,IAAI;AAElD,QAAI,SAAS;AACZ,WAAK,SAAS,iBAAoB;AAClC;AAAA,IACD;AAGA,UAAM,WAAW,IAAI,OAAO;AAC5B,UAAM,YAAY,IAAI,OAAO;AAC7B,UAAM,aAAa,IAAI,OAAO;AAC9B,UAAM,UAAU,IAAI,OAAO;AAE3B,QAAI,UAAU;AACb,WAAK,SAAS,kCAA4B;AAAA,IAC3C,WAAW,WAAW;AACrB,WAAK,SAAS,oCAA6B;AAAA,IAC5C,WAAW,SAAS;AACnB,WAAK,SAAS,gCAA2B;AAAA,IAC1C,WAAW,YAAY;AACtB,WAAK,SAAS,sCAA8B;AAAA,IAC7C,OAAO;AACN,WAAK,SAAS,gCAA2B;AAAA,IAC1C;AAAA,EACD;AACD;;;ACjGA,IAAM,iBAAoC;AAAA,EACzC,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,eAAe;AAChB;AAEA,IAAM,2BAA2B,uBAAO,IAAI,4BAA4B;AASxE,IAAM,mBAAN,MAAiD;AAAA,EAGhD,YACS,WACA,kBACP;AAFO;AACA;AAAA,EACN;AAAA,EAFM;AAAA,EACA;AAAA,EAJD,uBAAuB,oBAAI,IAAY;AAAA,EAO/C,OAAO,MAAe,QAAsB;AAC3C,UAAM,QAAQ,KAAK,mBAAmB,wBAAwB;AAC9D,QAAI,CAAC,MAAO;AAEZ,eAAW,QAAQ,OAAO;AACzB,YAAM,aAAa,KAAK;AACxB,YAAM,UAAU,KAAK;AACrB,YAAM,UAAU,QAAQ;AAExB,UAAI,CAAC,QAAQ,KAAK;AACjB,gBAAQ,MAAM,IAAI,cAAc;AAAA,MACjC;AAEA,YAAM,SAAU,WAAW,iBAAiB;AAC5C,UAAI,CAAC,KAAK,aAAa,SAAS,EAAG;AAEnC,WAAK,mBAAmB,QAAQ,OAAO;AACvC,YAAM,OAAO,KAAK,UAAU,QAAQ,MAAM;AAC1C,YAAM,QAAQ,KAAK,UAAU,gBAAgB,MAAM;AACnD,UAAI,QAAQ,OAAO;AAClB,cAAM,SAAS,mBAAmB,OAAO;AACzC,gBAAQ,IAAI;AAAA,UACX,EAAE,GAAG,KAAK,SAAS,CAAC,GAAG,GAAG,KAAK,SAAS,CAAC,EAAE;AAAA,UAC3C;AAAA,YACC,MAAM,OAAO;AAAA,YACb,MAAM,OAAO;AAAA,YACb,MAAM,OAAO;AAAA,YACb,MAAM,OAAO;AAAA,YACb,eAAe,QAAQ;AAAA,UACxB;AAAA,UACA,MAAM,oBAAoB;AAAA,QAC3B;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAEQ,mBAAmB,QAAgB,SAAkC;AAC5E,QAAI,CAAC,KAAK,aAAa,KAAK,qBAAqB,IAAI,MAAM,EAAG;AAC9D,SAAK,UAAU,iBAAiB,QAAQ;AAAA,MACvC,OAAO,QAAQ;AAAA,MACf,QAAQ,QAAQ;AAAA,MAChB,SAAS,QAAQ;AAAA,MACjB,SAAS,QAAQ;AAAA,MACjB,eAAe,QAAQ;AAAA,IACxB,CAAC;AACD,SAAK,qBAAqB,IAAI,MAAM;AAAA,EACrC;AAAA,EAEA,QAAQ,MAAqB;AAC5B,SAAK,qBAAqB,MAAM;AAAA,EACjC;AACD;AAiBO,IAAM,qBAAqB,eAAe;AAAA,EAChD,MAAM;AAAA,EACN;AAAA,EACA,eAAe,CAAC,QACf,IAAI,iBAAiB,IAAI,aAAa,MAAM,IAAI,gBAAgB;AAClE,CAAC;","names":["ScreenWrapState","ScreenWrapEvent"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/behaviors/jumper-2d/components.ts","../src/lib/behaviors/jumper-2d/jumper-2d-fsm.ts","../src/lib/behaviors/jumper-2d/jumper-2d.descriptor.ts"],"sourcesContent":["export interface JumpConfig2D {\n\tjumpHeight: number;\n\tgravity: number;\n\tmaxFallSpeed?: number;\n\tmaxJumps: number;\n\tresetJumpsOnGround: boolean;\n\tcoyoteTimeMs: number;\n\tjumpBufferMs: number;\n\tminTimeBetweenJumpsMs?: number;\n\tvariableJump?: {\n\t\tenabled: boolean;\n\t\tcutGravityMultiplier: number;\n\t\tmaxHoldMs?: number;\n\t};\n}\n\nexport function createJumpConfig2D(\n\toptions: Partial<JumpConfig2D> = {},\n): JumpConfig2D {\n\treturn {\n\t\tjumpHeight: options.jumpHeight ?? 2.5,\n\t\tgravity: options.gravity ?? 20,\n\t\tmaxFallSpeed: options.maxFallSpeed,\n\t\tmaxJumps: options.maxJumps ?? 1,\n\t\tresetJumpsOnGround: options.resetJumpsOnGround ?? true,\n\t\tcoyoteTimeMs: options.coyoteTimeMs ?? 100,\n\t\tjumpBufferMs: options.jumpBufferMs ?? 80,\n\t\tminTimeBetweenJumpsMs: options.minTimeBetweenJumpsMs,\n\t\tvariableJump: options.variableJump,\n\t};\n}\n\nexport interface JumpInput2D {\n\tjumpPressed: boolean;\n\tjumpHeld: boolean;\n\tjumpReleased: boolean;\n\tfastFall?: boolean;\n}\n\nexport function createJumpInput2D(): JumpInput2D {\n\treturn {\n\t\tjumpPressed: false,\n\t\tjumpHeld: false,\n\t\tjumpReleased: false,\n\t\tfastFall: false,\n\t};\n}\n\nexport interface JumpContext2D {\n\tdt: number;\n\tvelocityY: number;\n\tisGrounded: boolean;\n\ttimeSinceGroundedMs: number;\n\tsetVerticalVelocity(y: number): void;\n}\n\nexport interface JumpState2D {\n\tjumpsUsed: number;\n\tlastJumpTimeMs: number;\n\tbufferedJumpMs: number;\n\tcoyoteMs: number;\n\tisJumping: boolean;\n\tjumpHoldMs: number;\n\tjumpCutApplied: boolean;\n}\n\nexport function createJumpState2D(): JumpState2D {\n\treturn {\n\t\tjumpsUsed: 0,\n\t\tlastJumpTimeMs: 0,\n\t\tbufferedJumpMs: 0,\n\t\tcoyoteMs: 0,\n\t\tisJumping: false,\n\t\tjumpHoldMs: 0,\n\t\tjumpCutApplied: false,\n\t};\n}\n","import { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\nimport type { JumpState2D } from './components';\n\nexport enum Jumper2DState {\n\tGrounded = 'grounded',\n\tJumping = 'jumping',\n\tFalling = 'falling',\n}\n\nexport enum Jumper2DEvent {\n\tJump = 'jump',\n\tFall = 'fall',\n\tLand = 'land',\n}\n\nexport interface Jumper2DFSMContext {\n\tstate: JumpState2D;\n}\n\nexport class Jumper2DFSM {\n\tmachine: SyncStateMachine<Jumper2DState, Jumper2DEvent, never>;\n\n\tconstructor(private ctx: Jumper2DFSMContext) {\n\t\tthis.machine = new SyncStateMachine<Jumper2DState, Jumper2DEvent, never>(\n\t\t\tJumper2DState.Grounded,\n\t\t\t[\n\t\t\t\tt(Jumper2DState.Grounded, Jumper2DEvent.Jump, Jumper2DState.Jumping),\n\t\t\t\tt(Jumper2DState.Grounded, Jumper2DEvent.Fall, Jumper2DState.Falling),\n\t\t\t\tt(Jumper2DState.Grounded, Jumper2DEvent.Land, Jumper2DState.Grounded),\n\t\t\t\tt(Jumper2DState.Jumping, Jumper2DEvent.Fall, Jumper2DState.Falling),\n\t\t\t\tt(Jumper2DState.Jumping, Jumper2DEvent.Land, Jumper2DState.Grounded),\n\t\t\t\tt(Jumper2DState.Jumping, Jumper2DEvent.Jump, Jumper2DState.Jumping),\n\t\t\t\tt(Jumper2DState.Falling, Jumper2DEvent.Land, Jumper2DState.Grounded),\n\t\t\t\tt(Jumper2DState.Falling, Jumper2DEvent.Jump, Jumper2DState.Jumping),\n\t\t\t\tt(Jumper2DState.Falling, Jumper2DEvent.Fall, Jumper2DState.Falling),\n\t\t\t],\n\t\t);\n\t}\n\n\tgetState(): Jumper2DState {\n\t\treturn this.machine.getState();\n\t}\n\n\tdispatch(event: Jumper2DEvent): void {\n\t\tif (this.machine.can(event)) {\n\t\t\tthis.machine.syncDispatch(event);\n\t\t}\n\t}\n\n\tisJumping(): boolean {\n\t\treturn this.getState() === Jumper2DState.Jumping;\n\t}\n\n\tisGrounded(): boolean {\n\t\treturn this.getState() === Jumper2DState.Grounded;\n\t}\n\n\tgetJumpsUsed(): number {\n\t\treturn this.ctx.state.jumpsUsed;\n\t}\n\n\tapplyTickEvent(tickEvent: string, isGrounded: boolean): void {\n\t\tswitch (tickEvent) {\n\t\t\tcase 'jump':\n\t\t\t\tthis.dispatch(Jumper2DEvent.Jump);\n\t\t\t\tbreak;\n\t\t\tcase 'fall':\n\t\t\t\tthis.dispatch(Jumper2DEvent.Fall);\n\t\t\t\tbreak;\n\t\t\tcase 'land':\n\t\t\t\tthis.dispatch(Jumper2DEvent.Land);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tif (!isGrounded && this.getState() === Jumper2DState.Grounded) {\n\t\t\t\t\tthis.dispatch(Jumper2DEvent.Fall);\n\t\t\t\t}\n\t\t\t\tif (isGrounded && this.getState() !== Jumper2DState.Grounded) {\n\t\t\t\t\tthis.dispatch(Jumper2DEvent.Land);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n","import { defineBehavior } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport {\n\tcreateJumpInput2D,\n\ttype JumpConfig2D,\n\ttype JumpInput2D,\n\ttype JumpState2D,\n} from './components';\nimport { Jumper2DState } from './jumper-2d-fsm';\nimport {\n\tSTAGE_INPUT_BUTTON_JUMP,\n\treadBehaviorSnapshot,\n\ttype BehaviorRuntime,\n} from '../../runtime/wasm-stage-runtime';\n\nexport interface Jumper2DBehaviorOptions {\n\tjumpHeight?: number;\n\tgravity?: number;\n\tmaxFallSpeed?: number;\n\tmaxJumps?: number;\n\tresetJumpsOnGround?: boolean;\n\tcoyoteTimeMs?: number;\n\tjumpBufferMs?: number;\n\tminTimeBetweenJumpsMs?: number;\n\tvariableJump?: JumpConfig2D['variableJump'];\n\tgroundRayLength?: number;\n\tsnapToGroundDistance?: number;\n\tdebugGroundProbe?: boolean;\n}\n\nconst defaultOptions: Jumper2DBehaviorOptions = {\n\tjumpHeight: 2.5,\n\tgravity: 20,\n\tmaxJumps: 1,\n\tresetJumpsOnGround: true,\n\tcoyoteTimeMs: 100,\n\tjumpBufferMs: 80,\n\tgroundRayLength: 1,\n\tdebugGroundProbe: false,\n};\n\nconst JUMPER_2D_BEHAVIOR_KEY = Symbol.for('zylem:behavior:jumper-2d');\n\nexport function isJumper2DGrounded(params: {\n\tnearGround?: boolean;\n\tvelocityY: number;\n\tsupportToi?: number | null;\n\tsnapToGroundDistance?: number;\n}): boolean {\n\tif (params.velocityY > 0) {\n\t\treturn false;\n\t}\n\n\tif (params.snapToGroundDistance != null) {\n\t\treturn (\n\t\t\tparams.supportToi != null &&\n\t\t\tparams.supportToi <= params.snapToGroundDistance\n\t\t);\n\t}\n\n\treturn params.nearGround === true;\n}\n\nexport interface Jumper2DEntity {\n\tuuid: string;\n\ttransformStore: import('../../capabilities/transform-store').TransformState;\n\tjumper2d: JumpConfig2D;\n\t$jumper2d: JumpInput2D;\n\tjumper2dState: JumpState2D;\n}\n\n/**\n * Forwards jump input into the wasm runtime. The Rust `jumper_2d` Stage\n * behavior (ground probe + jump core) is the single simulation path; handles\n * read its state back via the snapshot buffer.\n */\nclass Jumper2DBehaviorSystem implements BehaviorSystem {\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate wasmStage: BehaviorRuntime | 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?.(JUMPER_2D_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 jumperRef = link.ref as any;\n\n\t\t\tconst options = jumperRef.options as Jumper2DBehaviorOptions;\n\t\t\tconst handle = (gameEntity.runtimeHandle ?? -1) as number;\n\t\t\tif (!this.wasmStage || handle < 0) continue;\n\n\t\t\tif (!gameEntity.$jumper2d) {\n\t\t\t\tgameEntity.$jumper2d = createJumpInput2D();\n\t\t\t}\n\n\t\t\tthis.ensureWasmAttached(handle, options);\n\t\t\tjumperRef.__wasmStage = this.wasmStage;\n\t\t\tjumperRef.__entity = gameEntity;\n\t\t\tconst input = gameEntity.$jumper2d as JumpInput2D;\n\t\t\tconst jumpPressed = !!(input.jumpPressed || input.jumpHeld);\n\t\t\tthis.wasmStage.writeInputButton(handle, STAGE_INPUT_BUTTON_JUMP, jumpPressed);\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(handle: number, options: Jumper2DBehaviorOptions): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tconst jumpForce = Math.sqrt(2 * (options.gravity ?? 20) * (options.jumpHeight ?? 2.5));\n\t\tthis.wasmStage.attachJumper2D(handle, {\n\t\t\tjumpForce,\n\t\t\tmaxJumps: options.maxJumps ?? 1,\n\t\t\tjumpBufferTime: (options.jumpBufferMs ?? 80) / 1000,\n\t\t\tcoyoteTime: (options.coyoteTimeMs ?? 100) / 1000,\n\t\t\tgravity: options.gravity ?? 20,\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 Jumper2DBehavior = defineBehavior<\n\tJumper2DBehaviorOptions,\n\t{\n\t\tgetState: () => Jumper2DState;\n\t\tisJumping: () => boolean;\n\t\tgetJumpsUsed: () => number;\n\t\tgetJumpsRemaining: () => number;\n\t},\n\tJumper2DEntity\n>({\n\tname: 'jumper-2d',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew Jumper2DBehaviorSystem(ctx.wasmStage ?? null, ctx.getBehaviorLinks),\n\t// Handles read the runtime snapshot buffer (previous-step values). The\n\t// Rust behavior is the single source of truth.\n\tcreateHandle: (ref) => {\n\t\tconst jumpsUsed = () => readBehaviorSnapshot(ref)?.jumpCount ?? 0;\n\t\treturn {\n\t\t\tgetState: () => {\n\t\t\t\tconst snapshot = readBehaviorSnapshot(ref);\n\t\t\t\tif (!snapshot) return Jumper2DState.Grounded;\n\t\t\t\tif (snapshot.grounded) return Jumper2DState.Grounded;\n\t\t\t\treturn snapshot.verticalVelocity > 0\n\t\t\t\t\t? Jumper2DState.Jumping\n\t\t\t\t\t: Jumper2DState.Falling;\n\t\t\t},\n\t\t\tisJumping: () => {\n\t\t\t\tconst snapshot = readBehaviorSnapshot(ref);\n\t\t\t\treturn snapshot ? !snapshot.grounded && snapshot.verticalVelocity > 0 : false;\n\t\t\t},\n\t\t\tgetJumpsUsed: jumpsUsed,\n\t\t\tgetJumpsRemaining: () => (ref.options.maxJumps ?? 1) - jumpsUsed(),\n\t\t};\n\t},\n});\n"],"mappings":"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","names":["Jumper2DState","Jumper2DEvent"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/behaviors/platformer-3d/components.ts","../src/lib/behaviors/platformer-3d/platformer-3d-fsm.ts","../src/lib/behaviors/platformer-3d/platformer-3d.descriptor.ts"],"sourcesContent":["/**\n * Platformer 3D ECS Components\n * \n * Components for 3D platformer movement system including walking, running,\n * jumping with multi-jump support, and falling/landing states.\n */\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Platformer3DMovementComponent (capability / configuration)\n// Defines the movement capabilities and physics parameters\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface Platformer3DMovementComponent {\n\t/** Base walking speed */\n\twalkSpeed: number;\n\t/** Sprint/run speed */\n\trunSpeed: number;\n\t/** Initial jump force/velocity */\n\tjumpForce: number;\n\t/** Maximum number of jumps (1 = single jump, 2 = double jump, etc.) */\n\tmaxJumps: number;\n\t/** Gravity force (optional override) */\n\tgravity: number;\n\t/** Coyote time in seconds (grace period after leaving ground) */\n\tcoyoteTime: number;\n\t/** Jump buffer time in seconds (queue jump input before landing) */\n\tjumpBufferTime: number;\n\t/** Velocity multiplier when releasing jump button early (0-1) */\n\tjumpCutMultiplier: number;\n\t/** Time in seconds before multi-jump becomes available (0 = after button release) */\n\tmultiJumpWindowTime: number;\n\t/** Maximum slope angle (degrees) the character can walk up */\n\tslopeClimbAngle: number;\n\t/** Slope angle (degrees) past which the character slides down */\n\tslopeSlideAngle: number;\n\t/** Autostep configuration for small ledges, or false to disable */\n\tautostep: { maxHeight: number; minWidth: number } | false;\n\t/** Snap-to-ground distance (keeps the character glued going downhill) */\n\tsnapToGroundDistance: number;\n\t/** Character controller offset (small gap kept between collider and environment) */\n\tcharacterOffset: number;\n}\n\nexport function createPlatformer3DMovementComponent(\n\toptions: Partial<Platformer3DMovementComponent> = {}\n): Platformer3DMovementComponent {\n\treturn {\n\t\twalkSpeed: options.walkSpeed ?? 12,\n\t\trunSpeed: options.runSpeed ?? 24,\n\t\tjumpForce: options.jumpForce ?? 12,\n\t\tmaxJumps: options.maxJumps ?? 1,\n\t\tgravity: options.gravity ?? 9.82,\n\t\tcoyoteTime: options.coyoteTime ?? 0.1,\n\t\tjumpBufferTime: options.jumpBufferTime ?? 0.1,\n\t\tjumpCutMultiplier: options.jumpCutMultiplier ?? 0.5,\n\t\tmultiJumpWindowTime: options.multiJumpWindowTime ?? 0.15, // 150ms default\n\t\tslopeClimbAngle: options.slopeClimbAngle ?? 50,\n\t\tslopeSlideAngle: options.slopeSlideAngle ?? 40,\n\t\tautostep: options.autostep ?? { maxHeight: 0.3, minWidth: 0.1 },\n\t\tsnapToGroundDistance: options.snapToGroundDistance ?? 0.3,\n\t\tcharacterOffset: options.characterOffset ?? 0.05,\n\t};\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Platformer3DInputComponent (intent)\n// Written by: Player controller, AI controller\n// Read by: Platformer3DBehavior\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface Platformer3DInputComponent {\n\t/** Horizontal movement input (-1 to 1) */\n\tmoveX: number;\n\t/** Forward/backward movement input (-1 to 1) */\n\tmoveZ: number;\n\t/** Jump button pressed */\n\tjump: boolean;\n\t/** Run/sprint button held */\n\trun: boolean;\n}\n\nexport function createPlatformer3DInputComponent(): Platformer3DInputComponent {\n\treturn {\n\t\tmoveX: 0,\n\t\tmoveZ: 0,\n\t\tjump: false,\n\t\trun: false,\n\t};\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Platformer3DStateComponent (runtime state)\n// Tracks the current state of the platformer entity\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface Platformer3DStateComponent {\n\t/** Is the entity on the ground */\n\tgrounded: boolean;\n\t/** Is currently in a jump arc */\n\tjumping: boolean;\n\t/** Is falling (not jumping) */\n\tfalling: boolean;\n\t/** Current jump count (for multi-jump) */\n\tjumpCount: number;\n\t/** Y position when jump started */\n\tjumpStartHeight: number;\n\t/** Current movement speed being applied */\n\tcurrentSpeed: number;\n\t/** Last known ground Y position */\n\tlastGroundedY: number;\n\t/** Was jump button pressed last frame (for edge detection) */\n\tjumpPressedLastFrame: boolean;\n\t\n\t// -- New fields --\n\t/** Is currently colliding with ground (from physics collision callback) */\n\tcollisionGrounded: boolean;\n\t/** Timestamp of last ground collision */\n\tgroundedCollisionTime: number;\n\t/** Time in seconds since last grounded */\n\ttimeSinceGrounded: number;\n\t/** Is a jump allowed due to buffer? */\n\tjumpBuffered: boolean;\n\t/** Time remaining in jump buffer */\n\tjumpBufferTimer: number;\n\t/** Is jump button currently held */\n\tjumpHeld: boolean;\n\t/** Has the jump cut been applied for this jump? */\n\tjumpCutApplied: boolean;\n\t/** Has jump button been released since last jump (required for multi-jump) */\n\tjumpReleasedSinceLastJump: boolean;\n\t/** Time since current jump started (for multi-jump window) */\n\ttimeSinceJump: number;\n\t/** True for the single frame on which a jump impulse was applied; prevents gravity from clobbering jump velocity. */\n\tjumpedThisFrame: boolean;\n\t/** Remaining seconds of jump-cut velocity ramp; while > 0, verticalVelocity lerps toward verticalVelocity * jumpCutMultiplier. */\n\tjumpCutRampTimer: number;\n\t/**\n\t * Controller-owned vertical velocity (units/second).\n\t * The body is kinematic, so `linvel()` is meaningless — this field is the\n\t * single source of truth for jump/gravity motion on the Y axis.\n\t */\n\tverticalVelocity: number;\n}\n\nexport function createPlatformer3DStateComponent(): Platformer3DStateComponent {\n\treturn {\n\t\tgrounded: false,\n\t\tjumping: false,\n\t\tfalling: false,\n\t\tjumpCount: 0,\n\t\tjumpStartHeight: 0,\n\t\tcurrentSpeed: 0,\n\t\tlastGroundedY: 0,\n\t\tjumpPressedLastFrame: false,\n\t\tcollisionGrounded: false,\n\t\tgroundedCollisionTime: 0,\n\t\ttimeSinceGrounded: 0,\n\t\tjumpBuffered: false,\n\t\tjumpBufferTimer: 0,\n\t\tjumpHeld: false,\n\t\tjumpCutApplied: false,\n\t\tjumpReleasedSinceLastJump: true,\n\t\ttimeSinceJump: 0,\n\t\tjumpedThisFrame: false,\n\t\tjumpCutRampTimer: 0,\n\t\tverticalVelocity: 0,\n\t};\n}\n","/**\n * Platformer 3D Finite State Machine\n * \n * Manages state transitions for 3D platformer movement:\n * - Idle: Standing still on ground\n * - Walking: Moving on ground (slow)\n * - Running: Moving on ground (fast)\n * - Jumping: Ascending from jump\n * - Falling: Descending (gravity)\n * - Landing: Just touched ground\n */\n\nimport { SyncStateMachine, t } from '../../core/utility/sync-state-machine';\nimport type { Platformer3DInputComponent, Platformer3DStateComponent } from './components';\n\n/**\n * Simplified Collision Context interface\n */\nexport interface PlatformerCollisionContext {\n\tcontact: {\n\t\tnormal: { x: number; y: number; z?: number };\n\t};\n}\n\n/**\n * Platformer states\n */\nexport enum Platformer3DState {\n\tIdle = 'idle',\n\tWalking = 'walking',\n\tRunning = 'running',\n\tJumping = 'jumping',\n\tFalling = 'falling',\n\tLanding = 'landing',\n}\n\n/**\n * Events that trigger state transitions\n */\nexport enum Platformer3DEvent {\n\tWalk = 'walk',\n\tRun = 'run',\n\tJump = 'jump',\n\tFall = 'fall',\n\tLand = 'land',\n\tStop = 'stop',\n}\n\n/**\n * Context for the FSM\n */\nexport interface Platformer3DContext {\n\tinput: Platformer3DInputComponent;\n\tstate: Platformer3DStateComponent;\n}\n\n/**\n * Platformer 3D FSM\n */\nexport class Platformer3DFSM {\n\tmachine: SyncStateMachine<Platformer3DState, Platformer3DEvent, never>;\n\n\tconstructor(private ctx: Platformer3DContext) {\n\t\tthis.machine = new SyncStateMachine<Platformer3DState, Platformer3DEvent, never>(\n\t\t\tPlatformer3DState.Idle,\n\t\t\t[\n\t\t\t\t// Idle transitions\n\t\t\t\tt(Platformer3DState.Idle, Platformer3DEvent.Walk, Platformer3DState.Walking),\n\t\t\t\tt(Platformer3DState.Idle, Platformer3DEvent.Run, Platformer3DState.Running),\n\t\t\t\tt(Platformer3DState.Idle, Platformer3DEvent.Jump, Platformer3DState.Jumping),\n\t\t\t\tt(Platformer3DState.Idle, Platformer3DEvent.Fall, Platformer3DState.Falling),\n\t\t\t\t\n\t\t\t\t// Walking transitions\n\t\t\t\tt(Platformer3DState.Walking, Platformer3DEvent.Run, Platformer3DState.Running),\n\t\t\t\tt(Platformer3DState.Walking, Platformer3DEvent.Jump, Platformer3DState.Jumping),\n\t\t\t\tt(Platformer3DState.Walking, Platformer3DEvent.Stop, Platformer3DState.Idle),\n\t\t\t\tt(Platformer3DState.Walking, Platformer3DEvent.Fall, Platformer3DState.Falling),\n\t\t\t\t\n\t\t\t\t// Running transitions\n\t\t\t\tt(Platformer3DState.Running, Platformer3DEvent.Walk, Platformer3DState.Walking),\n\t\t\t\tt(Platformer3DState.Running, Platformer3DEvent.Jump, Platformer3DState.Jumping),\n\t\t\t\tt(Platformer3DState.Running, Platformer3DEvent.Stop, Platformer3DState.Idle),\n\t\t\t\tt(Platformer3DState.Running, Platformer3DEvent.Fall, Platformer3DState.Falling),\n\t\t\t\t\n\t\t\t\t// Jumping transitions\n\t\t\t\tt(Platformer3DState.Jumping, Platformer3DEvent.Fall, Platformer3DState.Falling),\n\t\t\t\tt(Platformer3DState.Jumping, Platformer3DEvent.Land, Platformer3DState.Landing),\n\t\t\t\tt(Platformer3DState.Jumping, Platformer3DEvent.Jump, Platformer3DState.Jumping), // Multi-jump\n\t\t\t\t\n\t\t\t\t// Falling transitions\n\t\t\t\tt(Platformer3DState.Falling, Platformer3DEvent.Land, Platformer3DState.Landing),\n\t\t\t\t\n\t\t\t\t// Landing transitions\n\t\t\t\tt(Platformer3DState.Landing, Platformer3DEvent.Walk, Platformer3DState.Walking),\n\t\t\t\tt(Platformer3DState.Landing, Platformer3DEvent.Run, Platformer3DState.Running),\n\t\t\t\tt(Platformer3DState.Landing, Platformer3DEvent.Stop, Platformer3DState.Idle),\n\t\t\t\t\n\t\t\t\t// Self-transitions (no-ops)\n\t\t\t\tt(Platformer3DState.Idle, Platformer3DEvent.Stop, Platformer3DState.Idle),\n\t\t\t]\n\t\t);\n\t}\n\n\t/**\n\t * Get the current state\n\t */\n\tgetState(): Platformer3DState {\n\t\treturn this.machine.getState();\n\t}\n\n\t/**\n\t * Dispatch an event to the FSM\n\t */\n\tdispatch(event: Platformer3DEvent): 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 * Check if grounded\n\t */\n\tisGrounded(): boolean {\n\t\tconst state = this.getState();\n\t\treturn state === Platformer3DState.Idle || \n\t\t state === Platformer3DState.Walking || \n\t\t state === Platformer3DState.Running || \n\t\t state === Platformer3DState.Landing;\n\t}\n\n\t/**\n\t * Get current jump count from context\n\t */\n\tgetJumpCount(): number {\n\t\treturn this.ctx.state.jumpCount;\n\t}\n\n\t/**\n\t * Handle collision event to update ground state\n\t */\n\thandleCollision(ctx: PlatformerCollisionContext): void {\n\t\t// Check if collision is ground (normal pointing up)\n\t\t// Y normal > 0.5 means roughly within 60 degrees of up\n\t\tif (ctx.contact.normal.y > 0.5) {\n\t\t\tthis.ctx.state.collisionGrounded = true;\n\t\t\tthis.ctx.state.groundedCollisionTime = performance.now();\n\t\t}\n\t}\n\n\t/**\n\t * Update FSM based on current state\n\t */\n\tupdate(input: Platformer3DInputComponent, state: Platformer3DStateComponent): void {\n\t\t// Update context\n\t\tthis.ctx.input = input;\n\t\tthis.ctx.state = state;\n\n\t\t// Get current FSM state\n\t\tconst currentState = this.getState();\n\n\t\t// Determine movement state\n\t\tconst hasInput = Math.abs(input.moveX) > 0.1 || Math.abs(input.moveZ) > 0.1;\n\t\tconst isRunning = input.run;\n\n\t\t// Handle landing: if we're in falling state and now grounded, land\n\t\tif (currentState === Platformer3DState.Falling && state.grounded) {\n\t\t\tthis.dispatch(Platformer3DEvent.Land);\n\t\t\t// Don't return - allow immediate transition to movement state\n\t\t}\n\n\t\t// Send appropriate events based on state\n\t\tif (state.grounded) {\n\t\t\tif (hasInput) {\n\t\t\t\tif (isRunning) {\n\t\t\t\t\tthis.dispatch(Platformer3DEvent.Run);\n\t\t\t\t} else {\n\t\t\t\t\tthis.dispatch(Platformer3DEvent.Walk);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.dispatch(Platformer3DEvent.Stop);\n\t\t\t}\n\t\t} else {\n\t\t\t// Not grounded - check if we should be falling\n\t\t\t// Transition to falling if: We're in jumping state and now falling, \n\t\t\t// OR we walked off a ledge (idle/walking/running and now falling)\n\t\t\tif (state.falling) {\n\t\t\t\tthis.dispatch(Platformer3DEvent.Fall);\n\t\t\t}\n\t\t}\n\n\t\t// Handle jump input (edge detection handled in behavior)\n\t\tif (input.jump && !state.jumpPressedLastFrame) {\n\t\t\tthis.dispatch(Platformer3DEvent.Jump);\n\t\t}\n\t}\n}\n","/**\n * Platformer 3D Behavior Descriptor\n * \n * Type-safe descriptor for the platformer 3D behavior system.\n * Provides entity.use() API for 3D platformer movement.\n */\n\nimport { defineBehavior } from '../behavior-descriptor';\nimport type { BehaviorEntityLink, BehaviorSystem } from '../behavior-system';\nimport { Platformer3DState, PlatformerCollisionContext } from './platformer-3d-fsm';\nimport {\n\tcreatePlatformer3DMovementComponent,\n\tcreatePlatformer3DInputComponent,\n\tcreatePlatformer3DStateComponent,\n\ttype Platformer3DMovementComponent,\n\ttype Platformer3DInputComponent,\n\ttype Platformer3DStateComponent,\n} from './components';\nimport {\n\tSTAGE_INPUT_BUTTON_JUMP,\n\tSTAGE_INPUT_BUTTON_RUN,\n\treadBehaviorSnapshot,\n\tStagePlatformerShapeSource,\n\ttype BehaviorRuntime,\n\ttype StagePlatformer3DOptions,\n} from '../../runtime/wasm-stage-runtime';\n\n/** Rust `Platformer3DFsmState` index → TS state (see `platformer_3d/fsm.rs`). */\nconst FSM_STATE_BY_INDEX: readonly Platformer3DState[] = [\n\tPlatformer3DState.Idle,\n\tPlatformer3DState.Walking,\n\tPlatformer3DState.Running,\n\tPlatformer3DState.Jumping,\n\tPlatformer3DState.Falling,\n\tPlatformer3DState.Landing,\n];\n\n/**\n * Platformer behavior options (typed for entity.use() autocomplete)\n */\nexport interface Platformer3DBehaviorOptions {\n\t/** Base walking speed (default: 12) */\n\twalkSpeed?: number;\n\t/** Sprint/run speed (default: 24) */\n\trunSpeed?: number;\n\t/** Initial jump force (default: 12) */\n\tjumpForce?: number;\n\t/** Maximum number of jumps (default: 1) */\n\tmaxJumps?: number;\n\t/** Gravity force (default: 9.82) */\n\tgravity?: number;\n\t/** Maximum slope angle in degrees the character can walk up (default: 50) */\n\tslopeClimbAngle?: number;\n\t/** Slope angle in degrees past which the character slides (default: 40) */\n\tslopeSlideAngle?: number;\n\t/** Autostep over small ledges, or false to disable (default: { maxHeight: 0.3, minWidth: 0.1 }) */\n\tautostep?: { maxHeight: number; minWidth: number } | false;\n\t/** Snap-to-ground distance for downhill/step-down stability (default: 0.3) */\n\tsnapToGroundDistance?: number;\n\t/** Character controller collision offset (default: 0.05) */\n\tcharacterOffset?: number;\n\t/** Explicit KCC capsule override (requires `useAttachedCollider: false`). */\n\tshape?: {\n\t\thalfHeight: number;\n\t\tradius: number;\n\t\toffset?: [number, number, number];\n\t};\n\t/** When true (default), KCC reads shape + offset from the attached Rapier collider. */\n\tuseAttachedCollider?: boolean;\n}\n\nconst defaultOptions: Platformer3DBehaviorOptions = {\n\twalkSpeed: 12,\n\trunSpeed: 24,\n\tjumpForce: 12,\n\tmaxJumps: 1,\n\tgravity: 9.82,\n\tslopeClimbAngle: 50,\n\tslopeSlideAngle: 40,\n\tautostep: { maxHeight: 0.3, minWidth: 0.1 },\n\tsnapToGroundDistance: 0.3,\n\tcharacterOffset: 0.05,\n};\n\nconst PLATFORMER_BEHAVIOR_KEY = Symbol.for('zylem:behavior:platformer-3d');\n\nfunction resolvePlatformerAttachShape(\n\toptions: Platformer3DBehaviorOptions,\n\tgameEntity?: {\n\t\tcolliderDesc?: {\n\t\t\tshape?: { type?: string; halfHeight?: number; radius?: number };\n\t\t\toffset?: [number, number, number];\n\t\t};\n\t},\n): Pick<StagePlatformer3DOptions, 'halfHeight' | 'radius' | 'offsetX' | 'offsetY' | 'offsetZ' | 'shapeSource'> {\n\tconst fallback = {\n\t\thalfHeight: 0.9,\n\t\tradius: 0.4,\n\t\toffsetX: 0,\n\t\toffsetY: 0,\n\t\toffsetZ: 0,\n\t\tshapeSource: StagePlatformerShapeSource.Auto,\n\t};\n\n\tif (options.useAttachedCollider === false && options.shape) {\n\t\tconst offset = options.shape.offset ?? [0, 0, 0];\n\t\treturn {\n\t\t\thalfHeight: options.shape.halfHeight,\n\t\t\tradius: options.shape.radius,\n\t\t\toffsetX: offset[0],\n\t\t\toffsetY: offset[1],\n\t\t\toffsetZ: offset[2],\n\t\t\tshapeSource: StagePlatformerShapeSource.Override,\n\t\t};\n\t}\n\n\tconst collider = gameEntity?.colliderDesc;\n\tif (collider?.shape?.type === 'capsule') {\n\t\tconst offset = collider.offset ?? [0, 0, 0];\n\t\treturn {\n\t\t\thalfHeight: collider.shape.halfHeight ?? fallback.halfHeight,\n\t\t\tradius: collider.shape.radius ?? fallback.radius,\n\t\t\toffsetX: offset[0],\n\t\t\toffsetY: offset[1],\n\t\t\toffsetZ: offset[2],\n\t\t\tshapeSource: StagePlatformerShapeSource.Auto,\n\t\t};\n\t}\n\n\treturn fallback;\n}\n\n/**\n * Entity with platformer components (input written by the game; the wasm\n * runtime owns the kinematic character controller and FSM).\n */\nexport interface Platformer3DEntity {\n\tuuid: string;\n\tplatformer: Platformer3DMovementComponent;\n\t$platformer: Platformer3DInputComponent;\n\tplatformerState: Platformer3DStateComponent;\n}\n\n/**\n * Forwards platformer input into the wasm runtime. The Rust `platformer_3d`\n * Stage behavior (KCC + jump FSM) is the single simulation path; handles\n * read its state back via the snapshot buffer.\n */\nclass Platformer3DBehaviorSystem implements BehaviorSystem {\n\tprivate attachedRuntimeSlots = new Set<number>();\n\n\tconstructor(\n\t\tprivate wasmStage: BehaviorRuntime | 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?.(PLATFORMER_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 platformerRef = link.ref as any;\n\n\t\t\tconst options = platformerRef.options as Platformer3DBehaviorOptions;\n\n\t\t\tif (!gameEntity.platformer) {\n\t\t\t\tgameEntity.platformer = createPlatformer3DMovementComponent(options);\n\t\t\t}\n\t\t\tif (!gameEntity.$platformer) {\n\t\t\t\tgameEntity.$platformer = createPlatformer3DInputComponent();\n\t\t\t}\n\t\t\tif (!gameEntity.platformerState) {\n\t\t\t\tgameEntity.platformerState = createPlatformer3DStateComponent();\n\t\t\t}\n\n\t\t\tconst handle = (gameEntity.runtimeHandle ?? -1) as number;\n\t\t\tif (!this.wasmStage || handle < 0) continue;\n\n\t\t\tthis.ensureWasmAttached(handle, options, gameEntity);\n\t\t\tplatformerRef.__wasmStage = this.wasmStage;\n\t\t\tplatformerRef.__entity = gameEntity;\n\t\t\tconst input = gameEntity.$platformer;\n\t\t\tif (input) {\n\t\t\t\tthis.wasmStage.writeInputAxes(handle, input.moveX ?? 0, input.moveZ ?? 0);\n\t\t\t\tthis.wasmStage.writeInputButton(handle, STAGE_INPUT_BUTTON_JUMP, !!input.jump);\n\t\t\t\tthis.wasmStage.writeInputButton(handle, STAGE_INPUT_BUTTON_RUN, !!input.run);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate ensureWasmAttached(\n\t\thandle: number,\n\t\toptions: Platformer3DBehaviorOptions,\n\t\tgameEntity?: { colliderDesc?: { shape?: { type?: string; halfHeight?: number; radius?: number }; offset?: [number, number, number] } },\n\t): void {\n\t\tif (!this.wasmStage || this.attachedRuntimeSlots.has(handle)) return;\n\t\tconst autostep = options.autostep ?? defaultOptions.autostep!;\n\t\tconst shape = resolvePlatformerAttachShape(options, gameEntity);\n\t\tthis.wasmStage.attachPlatformer3D(handle, {\n\t\t\t...shape,\n\t\t\twalkSpeed: options.walkSpeed ?? defaultOptions.walkSpeed!,\n\t\t\trunSpeed: options.runSpeed ?? defaultOptions.runSpeed!,\n\t\t\tjumpForce: options.jumpForce ?? defaultOptions.jumpForce!,\n\t\t\tmaxJumps: options.maxJumps ?? defaultOptions.maxJumps!,\n\t\t\tgravity: options.gravity ?? defaultOptions.gravity!,\n\t\t\tslopeClimbAngle: options.slopeClimbAngle ?? defaultOptions.slopeClimbAngle!,\n\t\t\tslopeSlideAngle: options.slopeSlideAngle ?? defaultOptions.slopeSlideAngle!,\n\t\t\tautostepHeight: autostep ? autostep.maxHeight : 0,\n\t\t\tautostepMinWidth: autostep ? autostep.minWidth : 0.1,\n\t\t\tsnapToGroundDistance: options.snapToGroundDistance ?? defaultOptions.snapToGroundDistance!,\n\t\t\tcharacterOffset: options.characterOffset ?? defaultOptions.characterOffset!,\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 * Platformer3DBehavior - typed descriptor for 3D platformer movement\n * \n * Provides complete 3D platformer physics including:\n * - Walking and running\n * - Jumping with multi-jump support\n * - Gravity and falling\n * - Ground detection\n * \n * @example\n * ```typescript\n * import { Platformer3DBehavior } from \"@zylem/game-lib/behavior\";\n * \n * const player = await playgroundActor('player');\n * const platformer = player.use(Platformer3DBehavior, {\n * walkSpeed: 12,\n * runSpeed: 24,\n * jumpForce: 12,\n * maxJumps: 2, // Double jump!\n * });\n * \n * // In update loop\n * player.onUpdate(({ inputs }) => {\n * player.$platformer.moveX = inputs.p1.axes.Horizontal.value;\n * player.$platformer.moveZ = inputs.p1.axes.Vertical.value;\n * player.$platformer.jump = inputs.p1.buttons.A.held > 0;\n * player.$platformer.run = inputs.p1.shoulders.LTrigger.held > 0;\n * \n * const state = platformer.getState();\n * const grounded = platformer.isGrounded();\n * });\n * ```\n */\nexport const Platformer3DBehavior = defineBehavior<\n\tPlatformer3DBehaviorOptions,\n\t{\n\t\tgetState: () => Platformer3DState;\n\t\tisGrounded: () => boolean;\n\t\tgetJumpCount: () => number;\n\t\tonPlatformCollision: (ctx: PlatformerCollisionContext) => void;\n\t},\n\tPlatformer3DEntity\n>({\n\tname: 'platformer-3d',\n\tdefaultOptions,\n\tsystemFactory: (ctx) =>\n\t\tnew Platformer3DBehaviorSystem(\n\t\t\tctx.wasmStage ?? null,\n\t\t\tctx.getBehaviorLinks,\n\t\t),\n\t// Handles read the runtime snapshot buffer (values are from the end of\n\t// the previous step — one-frame lag). The Rust FSM is the single source\n\t// of truth.\n\tcreateHandle: (ref) => ({\n\t\tgetState: () => {\n\t\t\tconst snapshot = readBehaviorSnapshot(ref);\n\t\t\tif (snapshot) return FSM_STATE_BY_INDEX[snapshot.fsmState] ?? Platformer3DState.Idle;\n\t\t\treturn Platformer3DState.Idle;\n\t\t},\n\t\tisGrounded: () => readBehaviorSnapshot(ref)?.grounded ?? false,\n\t\tgetJumpCount: () => readBehaviorSnapshot(ref)?.jumpCount ?? 0,\n\t\tonPlatformCollision: (_ctx) => {},\n\t}),\n});\n"],"mappings":"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","names":["Platformer3DState","Platformer3DEvent"]}