@zylem/game-lib 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (441) hide show
  1. package/README.md +23 -41
  2. package/dist/actions.d.ts +25 -0
  3. package/dist/actions.js +287 -8
  4. package/dist/actions.js.map +1 -0
  5. package/dist/behaviors.d.ts +106 -0
  6. package/dist/behaviors.js +396 -6
  7. package/dist/behaviors.js.map +1 -0
  8. package/dist/blueprints-BOCc3Wve.d.ts +26 -0
  9. package/dist/{src/lib/camera/zylem-camera.d.ts → camera-CpbDr4-V.d.ts} +48 -27
  10. package/dist/camera.d.ts +5 -0
  11. package/dist/camera.js +608 -4
  12. package/dist/camera.js.map +1 -0
  13. package/dist/core-CZhozNRH.d.ts +466 -0
  14. package/dist/core.d.ts +10 -0
  15. package/dist/core.js +5761 -9
  16. package/dist/core.js.map +1 -0
  17. package/dist/entities-BAxfJOkk.d.ts +307 -0
  18. package/dist/entities.d.ts +6 -0
  19. package/dist/entities.js +2284 -17
  20. package/dist/entities.js.map +1 -0
  21. package/dist/{src/lib/interfaces/entity.d.ts → entity-Bq_eNEDI.d.ts} +8 -6
  22. package/dist/entity-COvRtFNG.d.ts +395 -0
  23. package/dist/main.d.ts +211 -0
  24. package/dist/main.js +7600 -56
  25. package/dist/main.js.map +1 -0
  26. package/dist/moveable-B_vyA6cw.d.ts +67 -0
  27. package/dist/stage-types-CD21XoIU.d.ts +338 -0
  28. package/dist/stage.d.ts +46 -0
  29. package/dist/stage.js +2765 -4
  30. package/dist/stage.js.map +1 -0
  31. package/dist/transformable-CUhvyuYO.d.ts +67 -0
  32. package/package.json +11 -47
  33. package/dist/.vite/manifest.json +0 -716
  34. package/dist/assets/zylem-logo.png +0 -0
  35. package/dist/examples/00-readme-example.d.ts +0 -2
  36. package/dist/examples/00-readme-example.d.ts.map +0 -1
  37. package/dist/examples/01-basic.d.ts +0 -2
  38. package/dist/examples/01-basic.d.ts.map +0 -1
  39. package/dist/examples/01.1-basic-ball.d.ts +0 -9
  40. package/dist/examples/01.1-basic-ball.d.ts.map +0 -1
  41. package/dist/examples/01.2-ricochet-test.d.ts +0 -2
  42. package/dist/examples/01.2-ricochet-test.d.ts.map +0 -1
  43. package/dist/examples/01.3-rect.d.ts +0 -2
  44. package/dist/examples/01.3-rect.d.ts.map +0 -1
  45. package/dist/examples/02-input.d.ts +0 -2
  46. package/dist/examples/02-input.d.ts.map +0 -1
  47. package/dist/examples/03-stage-test/03-stage-test.d.ts +0 -2
  48. package/dist/examples/03-stage-test/03-stage-test.d.ts.map +0 -1
  49. package/dist/examples/03-stage-test/stage0.d.ts +0 -2
  50. package/dist/examples/03-stage-test/stage0.d.ts.map +0 -1
  51. package/dist/examples/03-stage-test/stage1.d.ts +0 -2
  52. package/dist/examples/03-stage-test/stage1.d.ts.map +0 -1
  53. package/dist/examples/03-stage-test/stage2.d.ts +0 -2
  54. package/dist/examples/03-stage-test/stage2.d.ts.map +0 -1
  55. package/dist/examples/03-stage-test/stage3.d.ts +0 -2
  56. package/dist/examples/03-stage-test/stage3.d.ts.map +0 -1
  57. package/dist/examples/03.1-stage-variable.d.ts +0 -2
  58. package/dist/examples/03.1-stage-variable.d.ts.map +0 -1
  59. package/dist/examples/04-vessel-test.d.ts +0 -18
  60. package/dist/examples/04-vessel-test.d.ts.map +0 -1
  61. package/dist/examples/05-camera-test.d.ts +0 -2
  62. package/dist/examples/05-camera-test.d.ts.map +0 -1
  63. package/dist/examples/06-entity-test.d.ts +0 -2
  64. package/dist/examples/06-entity-test.d.ts.map +0 -1
  65. package/dist/examples/07-behaviors.d.ts +0 -2
  66. package/dist/examples/07-behaviors.d.ts.map +0 -1
  67. package/dist/examples/07.01-behavior-context.d.ts +0 -2
  68. package/dist/examples/07.01-behavior-context.d.ts.map +0 -1
  69. package/dist/examples/08-pong.d.ts +0 -2
  70. package/dist/examples/08-pong.d.ts.map +0 -1
  71. package/dist/examples/08.01-breakout.d.ts +0 -2
  72. package/dist/examples/08.01-breakout.d.ts.map +0 -1
  73. package/dist/examples/09-space-invaders.d.ts +0 -2
  74. package/dist/examples/09-space-invaders.d.ts.map +0 -1
  75. package/dist/examples/10-asteroids.d.ts +0 -2
  76. package/dist/examples/10-asteroids.d.ts.map +0 -1
  77. package/dist/examples/11-2d-platformer.d.ts +0 -2
  78. package/dist/examples/11-2d-platformer.d.ts.map +0 -1
  79. package/dist/examples/12-3d-platformer.d.ts +0 -2
  80. package/dist/examples/12-3d-platformer.d.ts.map +0 -1
  81. package/dist/examples/13-fps.d.ts +0 -2
  82. package/dist/examples/13-fps.d.ts.map +0 -1
  83. package/dist/examples/14-strategy.d.ts +0 -2
  84. package/dist/examples/14-strategy.d.ts.map +0 -1
  85. package/dist/examples/15-zylem-planet-demo.d.ts +0 -2
  86. package/dist/examples/15-zylem-planet-demo.d.ts.map +0 -1
  87. package/dist/examples/16-timbotron.d.ts +0 -2
  88. package/dist/examples/16-timbotron.d.ts.map +0 -1
  89. package/dist/examples/17-stress-test.d.ts +0 -2
  90. package/dist/examples/17-stress-test.d.ts.map +0 -1
  91. package/dist/examples/architecture-test.d.ts +0 -2
  92. package/dist/examples/architecture-test.d.ts.map +0 -1
  93. package/dist/examples/utils.d.ts +0 -10
  94. package/dist/examples/utils.d.ts.map +0 -1
  95. package/dist/lib/actions/behaviors/actions.js +0 -35
  96. package/dist/lib/actions/behaviors/boundaries/boundary.js +0 -40
  97. package/dist/lib/actions/behaviors/ricochet/ricochet-2d-collision.js +0 -100
  98. package/dist/lib/actions/behaviors/ricochet/ricochet-2d-in-bounds.js +0 -37
  99. package/dist/lib/actions/behaviors/ricochet/ricochet.js +0 -6
  100. package/dist/lib/actions/capabilities/moveable.js +0 -108
  101. package/dist/lib/actions/capabilities/rotatable.js +0 -82
  102. package/dist/lib/actions/capabilities/transformable.js +0 -9
  103. package/dist/lib/actions/global-change.js +0 -40
  104. package/dist/lib/camera/camera.js +0 -19
  105. package/dist/lib/camera/fixed-2d.js +0 -30
  106. package/dist/lib/camera/perspective.js +0 -10
  107. package/dist/lib/camera/third-person.js +0 -42
  108. package/dist/lib/camera/zylem-camera.js +0 -208
  109. package/dist/lib/collision/collision-builder.js +0 -46
  110. package/dist/lib/collision/collision-delegate.js +0 -6
  111. package/dist/lib/collision/utils.js +0 -24
  112. package/dist/lib/collision/world.js +0 -77
  113. package/dist/lib/core/base-node.js +0 -61
  114. package/dist/lib/core/entity-asset-loader.js +0 -54
  115. package/dist/lib/core/lifecycle-base.js +0 -20
  116. package/dist/lib/core/preset-shader.js +0 -26
  117. package/dist/lib/core/three-addons/Timer.js +0 -103
  118. package/dist/lib/core/utility/nodes.js +0 -31
  119. package/dist/lib/core/utility/strings.js +0 -14
  120. package/dist/lib/core/utility/vector.js +0 -8
  121. package/dist/lib/core/vessel.js +0 -26
  122. package/dist/lib/debug/console/console-state.js +0 -11
  123. package/dist/lib/debug/debug-state.js +0 -40
  124. package/dist/lib/device/aspect-ratio.js +0 -44
  125. package/dist/lib/entities/actor.js +0 -122
  126. package/dist/lib/entities/box.js +0 -68
  127. package/dist/lib/entities/builder.js +0 -79
  128. package/dist/lib/entities/create.js +0 -31
  129. package/dist/lib/entities/delegates/animation.js +0 -58
  130. package/dist/lib/entities/delegates/debug.js +0 -71
  131. package/dist/lib/entities/delegates/loader.js +0 -19
  132. package/dist/lib/entities/destroy.js +0 -15
  133. package/dist/lib/entities/entity-factory.js +0 -24
  134. package/dist/lib/entities/entity.js +0 -121
  135. package/dist/lib/entities/plane.js +0 -81
  136. package/dist/lib/entities/rect.js +0 -160
  137. package/dist/lib/entities/sphere.js +0 -68
  138. package/dist/lib/entities/sprite.js +0 -125
  139. package/dist/lib/entities/text.js +0 -140
  140. package/dist/lib/entities/zone.js +0 -103
  141. package/dist/lib/game/game-canvas.js +0 -57
  142. package/dist/lib/game/game-config.js +0 -78
  143. package/dist/lib/game/game-default.js +0 -23
  144. package/dist/lib/game/game-retro-resolutions.js +0 -80
  145. package/dist/lib/game/game-state.js +0 -17
  146. package/dist/lib/game/game.js +0 -131
  147. package/dist/lib/game/zylem-game.js +0 -140
  148. package/dist/lib/graphics/geometries/XZPlaneGeometry.js +0 -34
  149. package/dist/lib/graphics/material.js +0 -64
  150. package/dist/lib/graphics/mesh.js +0 -14
  151. package/dist/lib/graphics/render-pass.js +0 -56
  152. package/dist/lib/graphics/shaders/fragment/debug.glsl.js +0 -23
  153. package/dist/lib/graphics/shaders/fragment/fire.glsl.js +0 -52
  154. package/dist/lib/graphics/shaders/fragment/standard.glsl.js +0 -11
  155. package/dist/lib/graphics/shaders/fragment/stars.glsl.js +0 -44
  156. package/dist/lib/graphics/shaders/vertex/debug.glsl.js +0 -15
  157. package/dist/lib/graphics/shaders/vertex/object-shader.glsl.js +0 -11
  158. package/dist/lib/graphics/shaders/vertex/standard.glsl.js +0 -9
  159. package/dist/lib/graphics/zylem-scene.js +0 -75
  160. package/dist/lib/input/gamepad-provider.js +0 -58
  161. package/dist/lib/input/input-manager.js +0 -70
  162. package/dist/lib/input/keyboard-provider.js +0 -120
  163. package/dist/lib/stage/debug-entity-cursor.js +0 -53
  164. package/dist/lib/stage/entity-spawner.js +0 -27
  165. package/dist/lib/stage/stage-debug-delegate.js +0 -100
  166. package/dist/lib/stage/stage-default.js +0 -32
  167. package/dist/lib/stage/stage-factory.js +0 -22
  168. package/dist/lib/stage/stage-manager.js +0 -49
  169. package/dist/lib/stage/stage-state.js +0 -36
  170. package/dist/lib/stage/stage.js +0 -67
  171. package/dist/lib/stage/zylem-stage.js +0 -268
  172. package/dist/lib/systems/transformable.system.js +0 -43
  173. package/dist/node_modules/.pnpm/idb-keyval@6.2.2/node_modules/idb-keyval/dist/index.js +0 -34
  174. package/dist/node_modules/.pnpm/msgpackr@1.11.5/node_modules/msgpackr/pack.js +0 -520
  175. package/dist/node_modules/.pnpm/msgpackr@1.11.5/node_modules/msgpackr/unpack.js +0 -672
  176. package/dist/src/api/actions.d.ts +0 -5
  177. package/dist/src/api/actions.d.ts.map +0 -1
  178. package/dist/src/api/behaviors.d.ts +0 -4
  179. package/dist/src/api/behaviors.d.ts.map +0 -1
  180. package/dist/src/api/camera.d.ts +0 -4
  181. package/dist/src/api/camera.d.ts.map +0 -1
  182. package/dist/src/api/core.d.ts +0 -6
  183. package/dist/src/api/core.d.ts.map +0 -1
  184. package/dist/src/api/entities.d.ts +0 -9
  185. package/dist/src/api/entities.d.ts.map +0 -1
  186. package/dist/src/api/main.d.ts +0 -32
  187. package/dist/src/api/main.d.ts.map +0 -1
  188. package/dist/src/api/stage.d.ts +0 -5
  189. package/dist/src/api/stage.d.ts.map +0 -1
  190. package/dist/src/lib/actions/behaviors/actions.d.ts +0 -11
  191. package/dist/src/lib/actions/behaviors/actions.d.ts.map +0 -1
  192. package/dist/src/lib/actions/behaviors/behavior.d.ts +0 -6
  193. package/dist/src/lib/actions/behaviors/behavior.d.ts.map +0 -1
  194. package/dist/src/lib/actions/behaviors/boundaries/boundary.d.ts +0 -37
  195. package/dist/src/lib/actions/behaviors/boundaries/boundary.d.ts.map +0 -1
  196. package/dist/src/lib/actions/behaviors/character-controller.d.ts +0 -6
  197. package/dist/src/lib/actions/behaviors/character-controller.d.ts.map +0 -1
  198. package/dist/src/lib/actions/behaviors/debug/debug-collision.d.ts +0 -6
  199. package/dist/src/lib/actions/behaviors/debug/debug-collision.d.ts.map +0 -1
  200. package/dist/src/lib/actions/behaviors/debug/debug-update.d.ts +0 -5
  201. package/dist/src/lib/actions/behaviors/debug/debug-update.d.ts.map +0 -1
  202. package/dist/src/lib/actions/behaviors/debug/debug.d.ts +0 -10
  203. package/dist/src/lib/actions/behaviors/debug/debug.d.ts.map +0 -1
  204. package/dist/src/lib/actions/behaviors/movement/movement-sequence-2d.d.ts +0 -24
  205. package/dist/src/lib/actions/behaviors/movement/movement-sequence-2d.d.ts.map +0 -1
  206. package/dist/src/lib/actions/behaviors/ricochet/ricochet-2d-collision.d.ts +0 -11
  207. package/dist/src/lib/actions/behaviors/ricochet/ricochet-2d-collision.d.ts.map +0 -1
  208. package/dist/src/lib/actions/behaviors/ricochet/ricochet-2d-in-bounds.d.ts +0 -12
  209. package/dist/src/lib/actions/behaviors/ricochet/ricochet-2d-in-bounds.d.ts.map +0 -1
  210. package/dist/src/lib/actions/behaviors/ricochet/ricochet.d.ts +0 -44
  211. package/dist/src/lib/actions/behaviors/ricochet/ricochet.d.ts.map +0 -1
  212. package/dist/src/lib/actions/behaviors/zylem-behavior.d.ts +0 -2
  213. package/dist/src/lib/actions/behaviors/zylem-behavior.d.ts.map +0 -1
  214. package/dist/src/lib/actions/capabilities/moveable.d.ts +0 -125
  215. package/dist/src/lib/actions/capabilities/moveable.d.ts.map +0 -1
  216. package/dist/src/lib/actions/capabilities/rotatable.d.ts +0 -111
  217. package/dist/src/lib/actions/capabilities/rotatable.d.ts.map +0 -1
  218. package/dist/src/lib/actions/capabilities/transformable.d.ts +0 -7
  219. package/dist/src/lib/actions/capabilities/transformable.d.ts.map +0 -1
  220. package/dist/src/lib/actions/global-change.d.ts +0 -23
  221. package/dist/src/lib/actions/global-change.d.ts.map +0 -1
  222. package/dist/src/lib/camera/camera.d.ts +0 -16
  223. package/dist/src/lib/camera/camera.d.ts.map +0 -1
  224. package/dist/src/lib/camera/fixed-2d.d.ts +0 -32
  225. package/dist/src/lib/camera/fixed-2d.d.ts.map +0 -1
  226. package/dist/src/lib/camera/perspective.d.ts +0 -9
  227. package/dist/src/lib/camera/perspective.d.ts.map +0 -1
  228. package/dist/src/lib/camera/third-person.d.ts +0 -32
  229. package/dist/src/lib/camera/third-person.d.ts.map +0 -1
  230. package/dist/src/lib/camera/zylem-camera.d.ts.map +0 -1
  231. package/dist/src/lib/collision/collision-builder.d.ts +0 -17
  232. package/dist/src/lib/collision/collision-builder.d.ts.map +0 -1
  233. package/dist/src/lib/collision/collision-delegate.d.ts +0 -6
  234. package/dist/src/lib/collision/collision-delegate.d.ts.map +0 -1
  235. package/dist/src/lib/collision/collision-group.d.ts +0 -11
  236. package/dist/src/lib/collision/collision-group.d.ts.map +0 -1
  237. package/dist/src/lib/collision/collision-mask.d.ts +0 -18
  238. package/dist/src/lib/collision/collision-mask.d.ts.map +0 -1
  239. package/dist/src/lib/collision/collision.d.ts +0 -19
  240. package/dist/src/lib/collision/collision.d.ts.map +0 -1
  241. package/dist/src/lib/collision/utils.d.ts +0 -15
  242. package/dist/src/lib/collision/utils.d.ts.map +0 -1
  243. package/dist/src/lib/collision/world.d.ts +0 -23
  244. package/dist/src/lib/collision/world.d.ts.map +0 -1
  245. package/dist/src/lib/core/asset-manager.d.ts +0 -2
  246. package/dist/src/lib/core/asset-manager.d.ts.map +0 -1
  247. package/dist/src/lib/core/base-node-life-cycle.d.ts +0 -54
  248. package/dist/src/lib/core/base-node-life-cycle.d.ts.map +0 -1
  249. package/dist/src/lib/core/base-node.d.ts +0 -36
  250. package/dist/src/lib/core/base-node.d.ts.map +0 -1
  251. package/dist/src/lib/core/blueprints.d.ts +0 -22
  252. package/dist/src/lib/core/blueprints.d.ts.map +0 -1
  253. package/dist/src/lib/core/entity-asset-loader.d.ts +0 -16
  254. package/dist/src/lib/core/entity-asset-loader.d.ts.map +0 -1
  255. package/dist/src/lib/core/errors.d.ts +0 -5
  256. package/dist/src/lib/core/errors.d.ts.map +0 -1
  257. package/dist/src/lib/core/flags.d.ts +0 -3
  258. package/dist/src/lib/core/flags.d.ts.map +0 -1
  259. package/dist/src/lib/core/index.d.ts +0 -5
  260. package/dist/src/lib/core/index.d.ts.map +0 -1
  261. package/dist/src/lib/core/interfaces.d.ts +0 -25
  262. package/dist/src/lib/core/interfaces.d.ts.map +0 -1
  263. package/dist/src/lib/core/lazy-loader.d.ts +0 -80
  264. package/dist/src/lib/core/lazy-loader.d.ts.map +0 -1
  265. package/dist/src/lib/core/lifecycle-base.d.ts +0 -17
  266. package/dist/src/lib/core/lifecycle-base.d.ts.map +0 -1
  267. package/dist/src/lib/core/node-interface.d.ts +0 -12
  268. package/dist/src/lib/core/node-interface.d.ts.map +0 -1
  269. package/dist/src/lib/core/preset-shader.d.ts +0 -8
  270. package/dist/src/lib/core/preset-shader.d.ts.map +0 -1
  271. package/dist/src/lib/core/three-addons/Timer.d.ts +0 -92
  272. package/dist/src/lib/core/three-addons/Timer.d.ts.map +0 -1
  273. package/dist/src/lib/core/utility/nodes.d.ts +0 -13
  274. package/dist/src/lib/core/utility/nodes.d.ts.map +0 -1
  275. package/dist/src/lib/core/utility/strings.d.ts +0 -3
  276. package/dist/src/lib/core/utility/strings.d.ts.map +0 -1
  277. package/dist/src/lib/core/utility/vector.d.ts +0 -8
  278. package/dist/src/lib/core/utility/vector.d.ts.map +0 -1
  279. package/dist/src/lib/core/vector.d.ts +0 -4
  280. package/dist/src/lib/core/vector.d.ts.map +0 -1
  281. package/dist/src/lib/core/vessel.d.ts +0 -13
  282. package/dist/src/lib/core/vessel.d.ts.map +0 -1
  283. package/dist/src/lib/debug/console/console-state.d.ts +0 -20
  284. package/dist/src/lib/debug/console/console-state.d.ts.map +0 -1
  285. package/dist/src/lib/debug/console/console-store.d.ts +0 -6
  286. package/dist/src/lib/debug/console/console-store.d.ts.map +0 -1
  287. package/dist/src/lib/debug/debug-state.d.ts +0 -38
  288. package/dist/src/lib/debug/debug-state.d.ts.map +0 -1
  289. package/dist/src/lib/debug/debug-store.d.ts +0 -15
  290. package/dist/src/lib/debug/debug-store.d.ts.map +0 -1
  291. package/dist/src/lib/debug/state-based-debug-loader.d.ts +0 -8
  292. package/dist/src/lib/debug/state-based-debug-loader.d.ts.map +0 -1
  293. package/dist/src/lib/device/aspect-ratio.d.ts +0 -38
  294. package/dist/src/lib/device/aspect-ratio.d.ts.map +0 -1
  295. package/dist/src/lib/device/desktop.d.ts +0 -2
  296. package/dist/src/lib/device/desktop.d.ts.map +0 -1
  297. package/dist/src/lib/device/mobile.d.ts +0 -2
  298. package/dist/src/lib/device/mobile.d.ts.map +0 -1
  299. package/dist/src/lib/device/tablet.d.ts +0 -2
  300. package/dist/src/lib/device/tablet.d.ts.map +0 -1
  301. package/dist/src/lib/entities/actor.d.ts +0 -44
  302. package/dist/src/lib/entities/actor.d.ts.map +0 -1
  303. package/dist/src/lib/entities/box.d.ts +0 -27
  304. package/dist/src/lib/entities/box.d.ts.map +0 -1
  305. package/dist/src/lib/entities/builder.d.ts +0 -28
  306. package/dist/src/lib/entities/builder.d.ts.map +0 -1
  307. package/dist/src/lib/entities/create.d.ts +0 -15
  308. package/dist/src/lib/entities/create.d.ts.map +0 -1
  309. package/dist/src/lib/entities/delegates/animation.d.ts +0 -33
  310. package/dist/src/lib/entities/delegates/animation.d.ts.map +0 -1
  311. package/dist/src/lib/entities/delegates/debug.d.ts +0 -29
  312. package/dist/src/lib/entities/delegates/debug.d.ts.map +0 -1
  313. package/dist/src/lib/entities/delegates/loader.d.ts +0 -12
  314. package/dist/src/lib/entities/delegates/loader.d.ts.map +0 -1
  315. package/dist/src/lib/entities/destroy.d.ts +0 -4
  316. package/dist/src/lib/entities/destroy.d.ts.map +0 -1
  317. package/dist/src/lib/entities/entity-factory.d.ts +0 -10
  318. package/dist/src/lib/entities/entity-factory.d.ts.map +0 -1
  319. package/dist/src/lib/entities/entity.d.ts +0 -98
  320. package/dist/src/lib/entities/entity.d.ts.map +0 -1
  321. package/dist/src/lib/entities/index.d.ts +0 -12
  322. package/dist/src/lib/entities/index.d.ts.map +0 -1
  323. package/dist/src/lib/entities/plane.d.ts +0 -36
  324. package/dist/src/lib/entities/plane.d.ts.map +0 -1
  325. package/dist/src/lib/entities/rect.d.ts +0 -63
  326. package/dist/src/lib/entities/rect.d.ts.map +0 -1
  327. package/dist/src/lib/entities/sphere.d.ts +0 -29
  328. package/dist/src/lib/entities/sphere.d.ts.map +0 -1
  329. package/dist/src/lib/entities/sprite.d.ts +0 -54
  330. package/dist/src/lib/entities/sprite.d.ts.map +0 -1
  331. package/dist/src/lib/entities/text.d.ts +0 -49
  332. package/dist/src/lib/entities/text.d.ts.map +0 -1
  333. package/dist/src/lib/entities/zone.d.ts +0 -54
  334. package/dist/src/lib/entities/zone.d.ts.map +0 -1
  335. package/dist/src/lib/game/game-blueprint.d.ts +0 -38
  336. package/dist/src/lib/game/game-blueprint.d.ts.map +0 -1
  337. package/dist/src/lib/game/game-canvas.d.ts +0 -35
  338. package/dist/src/lib/game/game-canvas.d.ts.map +0 -1
  339. package/dist/src/lib/game/game-config.d.ts +0 -59
  340. package/dist/src/lib/game/game-config.d.ts.map +0 -1
  341. package/dist/src/lib/game/game-default.d.ts +0 -14
  342. package/dist/src/lib/game/game-default.d.ts.map +0 -1
  343. package/dist/src/lib/game/game-interfaces.d.ts +0 -29
  344. package/dist/src/lib/game/game-interfaces.d.ts.map +0 -1
  345. package/dist/src/lib/game/game-retro-resolutions.d.ts +0 -25
  346. package/dist/src/lib/game/game-retro-resolutions.d.ts.map +0 -1
  347. package/dist/src/lib/game/game-state.d.ts +0 -11
  348. package/dist/src/lib/game/game-state.d.ts.map +0 -1
  349. package/dist/src/lib/game/game.d.ts +0 -39
  350. package/dist/src/lib/game/game.d.ts.map +0 -1
  351. package/dist/src/lib/game/zylem-game.d.ts +0 -58
  352. package/dist/src/lib/game/zylem-game.d.ts.map +0 -1
  353. package/dist/src/lib/graphics/geometries/XZPlaneGeometry.d.ts +0 -8
  354. package/dist/src/lib/graphics/geometries/XZPlaneGeometry.d.ts.map +0 -1
  355. package/dist/src/lib/graphics/material.d.ts +0 -29
  356. package/dist/src/lib/graphics/material.d.ts.map +0 -1
  357. package/dist/src/lib/graphics/mesh.d.ts +0 -19
  358. package/dist/src/lib/graphics/mesh.d.ts.map +0 -1
  359. package/dist/src/lib/graphics/render-pass.d.ts +0 -17
  360. package/dist/src/lib/graphics/render-pass.d.ts.map +0 -1
  361. package/dist/src/lib/graphics/zylem-scene.d.ts +0 -50
  362. package/dist/src/lib/graphics/zylem-scene.d.ts.map +0 -1
  363. package/dist/src/lib/input/gamepad-provider.d.ts +0 -14
  364. package/dist/src/lib/input/gamepad-provider.d.ts.map +0 -1
  365. package/dist/src/lib/input/input-manager.d.ts +0 -15
  366. package/dist/src/lib/input/input-manager.d.ts.map +0 -1
  367. package/dist/src/lib/input/input-provider.d.ts +0 -7
  368. package/dist/src/lib/input/input-provider.d.ts.map +0 -1
  369. package/dist/src/lib/input/input.d.ts +0 -48
  370. package/dist/src/lib/input/input.d.ts.map +0 -1
  371. package/dist/src/lib/input/keyboard-provider.d.ts +0 -21
  372. package/dist/src/lib/input/keyboard-provider.d.ts.map +0 -1
  373. package/dist/src/lib/interfaces/entity.d.ts.map +0 -1
  374. package/dist/src/lib/sounds/index.d.ts +0 -3
  375. package/dist/src/lib/sounds/index.d.ts.map +0 -1
  376. package/dist/src/lib/sounds/ping-pong-sound.d.ts +0 -5
  377. package/dist/src/lib/sounds/ping-pong-sound.d.ts.map +0 -1
  378. package/dist/src/lib/sounds/ricochet-sound.d.ts +0 -5
  379. package/dist/src/lib/sounds/ricochet-sound.d.ts.map +0 -1
  380. package/dist/src/lib/stage/debug-entity-cursor.d.ts +0 -24
  381. package/dist/src/lib/stage/debug-entity-cursor.d.ts.map +0 -1
  382. package/dist/src/lib/stage/entity-spawner.d.ts +0 -9
  383. package/dist/src/lib/stage/entity-spawner.d.ts.map +0 -1
  384. package/dist/src/lib/stage/stage-camera-debug-delegate.d.ts +0 -14
  385. package/dist/src/lib/stage/stage-camera-debug-delegate.d.ts.map +0 -1
  386. package/dist/src/lib/stage/stage-debug-delegate.d.ts +0 -26
  387. package/dist/src/lib/stage/stage-debug-delegate.d.ts.map +0 -1
  388. package/dist/src/lib/stage/stage-default.d.ts +0 -3
  389. package/dist/src/lib/stage/stage-default.d.ts.map +0 -1
  390. package/dist/src/lib/stage/stage-factory.d.ts +0 -6
  391. package/dist/src/lib/stage/stage-factory.d.ts.map +0 -1
  392. package/dist/src/lib/stage/stage-manager.d.ts +0 -30
  393. package/dist/src/lib/stage/stage-manager.d.ts.map +0 -1
  394. package/dist/src/lib/stage/stage-state.d.ts +0 -14
  395. package/dist/src/lib/stage/stage-state.d.ts.map +0 -1
  396. package/dist/src/lib/stage/stage.d.ts +0 -35
  397. package/dist/src/lib/stage/stage.d.ts.map +0 -1
  398. package/dist/src/lib/stage/zylem-stage.d.ts +0 -128
  399. package/dist/src/lib/stage/zylem-stage.d.ts.map +0 -1
  400. package/dist/src/lib/systems/test-system.d.ts +0 -2
  401. package/dist/src/lib/systems/test-system.d.ts.map +0 -1
  402. package/dist/src/lib/systems/transformable.system.d.ts +0 -25
  403. package/dist/src/lib/systems/transformable.system.d.ts.map +0 -1
  404. package/dist/src/lib/types/entity-types.d.ts +0 -24
  405. package/dist/src/lib/types/entity-types.d.ts.map +0 -1
  406. package/dist/src/lib/types/index.d.ts +0 -3
  407. package/dist/src/lib/types/index.d.ts.map +0 -1
  408. package/dist/src/lib/types/stage-types.d.ts +0 -26
  409. package/dist/src/lib/types/stage-types.d.ts.map +0 -1
  410. package/dist/src/lib/ui/Debug.d.ts +0 -6
  411. package/dist/src/lib/ui/Debug.d.ts.map +0 -1
  412. package/dist/src/lib/ui/console/Console.d.ts +0 -7
  413. package/dist/src/lib/ui/console/Console.d.ts.map +0 -1
  414. package/dist/src/lib/ui/debug-panel/AccordionMenu.d.ts +0 -7
  415. package/dist/src/lib/ui/debug-panel/AccordionMenu.d.ts.map +0 -1
  416. package/dist/src/lib/ui/debug-panel/Menu.d.ts +0 -6
  417. package/dist/src/lib/ui/debug-panel/Menu.d.ts.map +0 -1
  418. package/dist/src/lib/ui/debug-panel/sections/EntitiesSection.d.ts +0 -4
  419. package/dist/src/lib/ui/debug-panel/sections/EntitiesSection.d.ts.map +0 -1
  420. package/dist/src/lib/ui/debug-panel/sections/GameSection.d.ts +0 -3
  421. package/dist/src/lib/ui/debug-panel/sections/GameSection.d.ts.map +0 -1
  422. package/dist/src/lib/ui/debug-panel/sections/StagesSection.d.ts +0 -3
  423. package/dist/src/lib/ui/debug-panel/sections/StagesSection.d.ts.map +0 -1
  424. package/dist/src/lib/ui/debug-panel/sections/all.d.ts +0 -4
  425. package/dist/src/lib/ui/debug-panel/sections/all.d.ts.map +0 -1
  426. package/dist/src/lib/ui/toolbar/Toolbar.d.ts +0 -6
  427. package/dist/src/lib/ui/toolbar/Toolbar.d.ts.map +0 -1
  428. package/dist/tests/e2e/basic-game.spec.d.ts +0 -2
  429. package/dist/tests/e2e/basic-game.spec.d.ts.map +0 -1
  430. package/dist/tests/integration/debug.sim.spec.d.ts +0 -2
  431. package/dist/tests/integration/debug.sim.spec.d.ts.map +0 -1
  432. package/dist/tests/unit/collision/collision.spec.d.ts +0 -2
  433. package/dist/tests/unit/collision/collision.spec.d.ts.map +0 -1
  434. package/dist/tests/unit/core/base-node.spec.d.ts +0 -2
  435. package/dist/tests/unit/core/base-node.spec.d.ts.map +0 -1
  436. package/dist/tests/unit/core/game.spec.d.ts +0 -2
  437. package/dist/tests/unit/core/game.spec.d.ts.map +0 -1
  438. package/dist/tests/unit/core/stage.spec.d.ts +0 -2
  439. package/dist/tests/unit/core/stage.spec.d.ts.map +0 -1
  440. package/dist/tests/unit/core/vessel.spec.d.ts +0 -2
  441. package/dist/tests/unit/core/vessel.spec.d.ts.map +0 -1
package/dist/stage.js CHANGED
@@ -1,6 +1,2767 @@
1
- import { createStage as t } from "./lib/stage/stage.js";
2
- import { entitySpawner as a } from "./lib/stage/entity-spawner.js";
1
+ // src/lib/stage/zylem-stage.ts
2
+ import { addComponent, addEntity, createWorld as createECS, removeEntity } from "bitecs";
3
+ import { Color as Color7, Vector3 as Vector311 } from "three";
4
+
5
+ // src/lib/collision/world.ts
6
+ import RAPIER from "@dimforge/rapier3d-compat";
7
+
8
+ // src/lib/game/game-state.ts
9
+ import { proxy, subscribe } from "valtio/vanilla";
10
+
11
+ // src/lib/game/game-event-bus.ts
12
+ var GameEventBus = class {
13
+ listeners = /* @__PURE__ */ new Map();
14
+ /**
15
+ * Subscribe to an event type.
16
+ */
17
+ on(event, callback) {
18
+ if (!this.listeners.has(event)) {
19
+ this.listeners.set(event, /* @__PURE__ */ new Set());
20
+ }
21
+ this.listeners.get(event).add(callback);
22
+ return () => this.off(event, callback);
23
+ }
24
+ /**
25
+ * Unsubscribe from an event type.
26
+ */
27
+ off(event, callback) {
28
+ this.listeners.get(event)?.delete(callback);
29
+ }
30
+ /**
31
+ * Emit an event to all subscribers.
32
+ */
33
+ emit(event, payload) {
34
+ const callbacks = this.listeners.get(event);
35
+ if (!callbacks) return;
36
+ for (const cb of callbacks) {
37
+ try {
38
+ cb(payload);
39
+ } catch (e) {
40
+ console.error(`Error in event handler for ${event}`, e);
41
+ }
42
+ }
43
+ }
44
+ /**
45
+ * Clear all listeners.
46
+ */
47
+ dispose() {
48
+ this.listeners.clear();
49
+ }
50
+ };
51
+ var gameEventBus = new GameEventBus();
52
+
53
+ // src/lib/game/game-state.ts
54
+ var state = proxy({
55
+ id: "",
56
+ globals: {},
57
+ time: 0
58
+ });
59
+ function getGlobals() {
60
+ return state.globals;
61
+ }
62
+
63
+ // src/lib/entities/actor.ts
64
+ import { ActiveCollisionTypes, ColliderDesc } from "@dimforge/rapier3d-compat";
65
+ import { SkinnedMesh, Group as Group2, Vector3 } from "three";
66
+
67
+ // src/lib/entities/entity.ts
68
+ import { ShaderMaterial } from "three";
69
+
70
+ // src/lib/systems/transformable.system.ts
71
+ import {
72
+ defineSystem,
73
+ defineQuery,
74
+ defineComponent,
75
+ Types,
76
+ removeQuery
77
+ } from "bitecs";
78
+ import { Quaternion } from "three";
79
+ var position = defineComponent({
80
+ x: Types.f32,
81
+ y: Types.f32,
82
+ z: Types.f32
83
+ });
84
+ var rotation = defineComponent({
85
+ x: Types.f32,
86
+ y: Types.f32,
87
+ z: Types.f32,
88
+ w: Types.f32
89
+ });
90
+ var scale = defineComponent({
91
+ x: Types.f32,
92
+ y: Types.f32,
93
+ z: Types.f32
94
+ });
95
+ var _tempQuaternion = new Quaternion();
96
+ function createTransformSystem(stage) {
97
+ const queryTerms = [position, rotation];
98
+ const transformQuery = defineQuery(queryTerms);
99
+ const stageEntities = stage._childrenMap;
100
+ const system = defineSystem((world) => {
101
+ const entities = transformQuery(world);
102
+ if (stageEntities === void 0) {
103
+ return world;
104
+ }
105
+ for (const [key, stageEntity] of stageEntities) {
106
+ if (!stageEntity?.body || stageEntity.markedForRemoval) {
107
+ continue;
108
+ }
109
+ const id = entities[key];
110
+ const body = stageEntity.body;
111
+ const target = stageEntity.group ?? stageEntity.mesh;
112
+ const translation = body.translation();
113
+ position.x[id] = translation.x;
114
+ position.y[id] = translation.y;
115
+ position.z[id] = translation.z;
116
+ if (target) {
117
+ target.position.set(translation.x, translation.y, translation.z);
118
+ }
119
+ if (stageEntity.controlledRotation) {
120
+ continue;
121
+ }
122
+ const rot = body.rotation();
123
+ rotation.x[id] = rot.x;
124
+ rotation.y[id] = rot.y;
125
+ rotation.z[id] = rot.z;
126
+ rotation.w[id] = rot.w;
127
+ if (target) {
128
+ _tempQuaternion.set(rot.x, rot.y, rot.z, rot.w);
129
+ target.setRotationFromQuaternion(_tempQuaternion);
130
+ }
131
+ }
132
+ return world;
133
+ });
134
+ const destroy = (world) => {
135
+ removeQuery(world, transformQuery);
136
+ };
137
+ return { system, destroy };
138
+ }
139
+
140
+ // src/lib/core/flags.ts
141
+ var DEBUG_FLAG = import.meta.env.VITE_DEBUG_FLAG === "true";
142
+
143
+ // src/lib/core/base-node.ts
144
+ import { nanoid } from "nanoid";
145
+ var BaseNode = class _BaseNode {
146
+ parent = null;
147
+ children = [];
148
+ options;
149
+ eid = 0;
150
+ uuid = "";
151
+ name = "";
152
+ markedForRemoval = false;
153
+ /**
154
+ * Lifecycle callback arrays - use onSetup(), onUpdate(), etc. to add callbacks
155
+ */
156
+ lifecycleCallbacks = {
157
+ setup: [],
158
+ loaded: [],
159
+ update: [],
160
+ destroy: [],
161
+ cleanup: []
162
+ };
163
+ constructor(args = []) {
164
+ const options = args.filter((arg) => !(arg instanceof _BaseNode)).reduce((acc, opt) => ({ ...acc, ...opt }), {});
165
+ this.options = options;
166
+ this.uuid = nanoid();
167
+ }
168
+ // ─────────────────────────────────────────────────────────────────────────────
169
+ // Fluent API for adding lifecycle callbacks
170
+ // ─────────────────────────────────────────────────────────────────────────────
171
+ /**
172
+ * Add setup callbacks to be executed in order during nodeSetup
173
+ */
174
+ onSetup(...callbacks) {
175
+ this.lifecycleCallbacks.setup.push(...callbacks);
176
+ return this;
177
+ }
178
+ /**
179
+ * Add loaded callbacks to be executed in order during nodeLoaded
180
+ */
181
+ onLoaded(...callbacks) {
182
+ this.lifecycleCallbacks.loaded.push(...callbacks);
183
+ return this;
184
+ }
185
+ /**
186
+ * Add update callbacks to be executed in order during nodeUpdate
187
+ */
188
+ onUpdate(...callbacks) {
189
+ this.lifecycleCallbacks.update.push(...callbacks);
190
+ return this;
191
+ }
192
+ /**
193
+ * Add destroy callbacks to be executed in order during nodeDestroy
194
+ */
195
+ onDestroy(...callbacks) {
196
+ this.lifecycleCallbacks.destroy.push(...callbacks);
197
+ return this;
198
+ }
199
+ /**
200
+ * Add cleanup callbacks to be executed in order during nodeCleanup
201
+ */
202
+ onCleanup(...callbacks) {
203
+ this.lifecycleCallbacks.cleanup.push(...callbacks);
204
+ return this;
205
+ }
206
+ /**
207
+ * Prepend setup callbacks (run before existing ones)
208
+ */
209
+ prependSetup(...callbacks) {
210
+ this.lifecycleCallbacks.setup.unshift(...callbacks);
211
+ return this;
212
+ }
213
+ /**
214
+ * Prepend update callbacks (run before existing ones)
215
+ */
216
+ prependUpdate(...callbacks) {
217
+ this.lifecycleCallbacks.update.unshift(...callbacks);
218
+ return this;
219
+ }
220
+ // ─────────────────────────────────────────────────────────────────────────────
221
+ // Tree structure
222
+ // ─────────────────────────────────────────────────────────────────────────────
223
+ setParent(parent) {
224
+ this.parent = parent;
225
+ }
226
+ getParent() {
227
+ return this.parent;
228
+ }
229
+ add(baseNode) {
230
+ this.children.push(baseNode);
231
+ baseNode.setParent(this);
232
+ }
233
+ remove(baseNode) {
234
+ const index = this.children.indexOf(baseNode);
235
+ if (index !== -1) {
236
+ this.children.splice(index, 1);
237
+ baseNode.setParent(null);
238
+ }
239
+ }
240
+ getChildren() {
241
+ return this.children;
242
+ }
243
+ isComposite() {
244
+ return this.children.length > 0;
245
+ }
246
+ // ─────────────────────────────────────────────────────────────────────────────
247
+ // Node lifecycle execution - runs internal + callback arrays
248
+ // ─────────────────────────────────────────────────────────────────────────────
249
+ nodeSetup(params) {
250
+ if (DEBUG_FLAG) {
251
+ }
252
+ this.markedForRemoval = false;
253
+ if (typeof this._setup === "function") {
254
+ this._setup(params);
255
+ }
256
+ for (const callback of this.lifecycleCallbacks.setup) {
257
+ callback(params);
258
+ }
259
+ this.children.forEach((child) => child.nodeSetup(params));
260
+ }
261
+ nodeUpdate(params) {
262
+ if (this.markedForRemoval) {
263
+ return;
264
+ }
265
+ if (typeof this._update === "function") {
266
+ this._update(params);
267
+ }
268
+ for (const callback of this.lifecycleCallbacks.update) {
269
+ callback(params);
270
+ }
271
+ this.children.forEach((child) => child.nodeUpdate(params));
272
+ }
273
+ nodeDestroy(params) {
274
+ this.children.forEach((child) => child.nodeDestroy(params));
275
+ for (const callback of this.lifecycleCallbacks.destroy) {
276
+ callback(params);
277
+ }
278
+ if (typeof this._destroy === "function") {
279
+ this._destroy(params);
280
+ }
281
+ this.markedForRemoval = true;
282
+ }
283
+ async nodeLoaded(params) {
284
+ if (typeof this._loaded === "function") {
285
+ await this._loaded(params);
286
+ }
287
+ for (const callback of this.lifecycleCallbacks.loaded) {
288
+ callback(params);
289
+ }
290
+ }
291
+ async nodeCleanup(params) {
292
+ for (const callback of this.lifecycleCallbacks.cleanup) {
293
+ callback(params);
294
+ }
295
+ if (typeof this._cleanup === "function") {
296
+ await this._cleanup(params);
297
+ }
298
+ }
299
+ // ─────────────────────────────────────────────────────────────────────────────
300
+ // Options
301
+ // ─────────────────────────────────────────────────────────────────────────────
302
+ getOptions() {
303
+ return this.options;
304
+ }
305
+ setOptions(options) {
306
+ this.options = { ...this.options, ...options };
307
+ }
308
+ };
309
+
310
+ // src/lib/entities/entity.ts
311
+ var GameEntity = class extends BaseNode {
312
+ behaviors = [];
313
+ group;
314
+ mesh;
315
+ materials;
316
+ bodyDesc = null;
317
+ body = null;
318
+ colliderDesc;
319
+ collider;
320
+ custom = {};
321
+ debugInfo = {};
322
+ debugMaterial;
323
+ collisionDelegate = {
324
+ collision: []
325
+ };
326
+ collisionType;
327
+ behaviorCallbackMap = {
328
+ setup: [],
329
+ update: [],
330
+ destroy: [],
331
+ collision: []
332
+ };
333
+ constructor() {
334
+ super();
335
+ }
336
+ create() {
337
+ const { position: setupPosition } = this.options;
338
+ const { x, y, z } = setupPosition || { x: 0, y: 0, z: 0 };
339
+ this.behaviors = [
340
+ { component: position, values: { x, y, z } },
341
+ { component: scale, values: { x: 0, y: 0, z: 0 } },
342
+ { component: rotation, values: { x: 0, y: 0, z: 0, w: 0 } }
343
+ ];
344
+ this.name = this.options.name || "";
345
+ return this;
346
+ }
347
+ /**
348
+ * Add collision callbacks
349
+ */
350
+ onCollision(...callbacks) {
351
+ const existing = this.collisionDelegate.collision ?? [];
352
+ this.collisionDelegate.collision = [...existing, ...callbacks];
353
+ return this;
354
+ }
355
+ /**
356
+ * Entity-specific setup - runs behavior callbacks
357
+ * (User callbacks are handled by BaseNode's lifecycleCallbacks.setup)
358
+ */
359
+ _setup(params) {
360
+ this.behaviorCallbackMap.setup.forEach((callback) => {
361
+ callback({ ...params, me: this });
362
+ });
363
+ }
364
+ async _loaded(_params) {
365
+ }
366
+ /**
367
+ * Entity-specific update - updates materials and runs behavior callbacks
368
+ * (User callbacks are handled by BaseNode's lifecycleCallbacks.update)
369
+ */
370
+ _update(params) {
371
+ this.updateMaterials(params);
372
+ this.behaviorCallbackMap.update.forEach((callback) => {
373
+ callback({ ...params, me: this });
374
+ });
375
+ }
376
+ /**
377
+ * Entity-specific destroy - runs behavior callbacks
378
+ * (User callbacks are handled by BaseNode's lifecycleCallbacks.destroy)
379
+ */
380
+ _destroy(params) {
381
+ this.behaviorCallbackMap.destroy.forEach((callback) => {
382
+ callback({ ...params, me: this });
383
+ });
384
+ }
385
+ async _cleanup(_params) {
386
+ }
387
+ _collision(other, globals) {
388
+ if (this.collisionDelegate.collision?.length) {
389
+ const callbacks = this.collisionDelegate.collision;
390
+ callbacks.forEach((callback) => {
391
+ callback({ entity: this, other, globals });
392
+ });
393
+ }
394
+ this.behaviorCallbackMap.collision.forEach((callback) => {
395
+ callback({ entity: this, other, globals });
396
+ });
397
+ }
398
+ addBehavior(behaviorCallback) {
399
+ const handler = behaviorCallback.handler;
400
+ if (handler) {
401
+ this.behaviorCallbackMap[behaviorCallback.type].push(handler);
402
+ }
403
+ return this;
404
+ }
405
+ addBehaviors(behaviorCallbacks) {
406
+ behaviorCallbacks.forEach((callback) => {
407
+ const handler = callback.handler;
408
+ if (handler) {
409
+ this.behaviorCallbackMap[callback.type].push(handler);
410
+ }
411
+ });
412
+ return this;
413
+ }
414
+ updateMaterials(params) {
415
+ if (!this.materials?.length) {
416
+ return;
417
+ }
418
+ for (const material of this.materials) {
419
+ if (material instanceof ShaderMaterial) {
420
+ if (material.uniforms) {
421
+ material.uniforms.iTime && (material.uniforms.iTime.value += params.delta);
422
+ }
423
+ }
424
+ }
425
+ }
426
+ buildInfo() {
427
+ const info = {};
428
+ info.name = this.name;
429
+ info.uuid = this.uuid;
430
+ info.eid = this.eid.toString();
431
+ return info;
432
+ }
433
+ };
434
+
435
+ // src/lib/core/entity-asset-loader.ts
436
+ import { FBXLoader } from "three/addons/loaders/FBXLoader.js";
437
+ import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
438
+ var FBXAssetLoader = class {
439
+ loader = new FBXLoader();
440
+ isSupported(file) {
441
+ return file.toLowerCase().endsWith("fbx" /* FBX */);
442
+ }
443
+ async load(file) {
444
+ return new Promise((resolve, reject) => {
445
+ this.loader.load(
446
+ file,
447
+ (object) => {
448
+ const animation = object.animations[0];
449
+ resolve({
450
+ object,
451
+ animation
452
+ });
453
+ },
454
+ void 0,
455
+ reject
456
+ );
457
+ });
458
+ }
459
+ };
460
+ var GLTFAssetLoader = class {
461
+ loader = new GLTFLoader();
462
+ isSupported(file) {
463
+ return file.toLowerCase().endsWith("gltf" /* GLTF */);
464
+ }
465
+ async load(file) {
466
+ return new Promise((resolve, reject) => {
467
+ this.loader.load(
468
+ file,
469
+ (gltf) => {
470
+ resolve({
471
+ object: gltf.scene,
472
+ gltf
473
+ });
474
+ },
475
+ void 0,
476
+ reject
477
+ );
478
+ });
479
+ }
480
+ };
481
+ var EntityAssetLoader = class {
482
+ loaders = [
483
+ new FBXAssetLoader(),
484
+ new GLTFAssetLoader()
485
+ ];
486
+ async loadFile(file) {
487
+ const loader = this.loaders.find((l) => l.isSupported(file));
488
+ if (!loader) {
489
+ throw new Error(`Unsupported file type: ${file}`);
490
+ }
491
+ return loader.load(file);
492
+ }
493
+ };
494
+
495
+ // src/lib/entities/delegates/animation.ts
496
+ import {
497
+ AnimationMixer,
498
+ LoopOnce,
499
+ LoopRepeat
500
+ } from "three";
501
+ var AnimationDelegate = class {
502
+ constructor(target) {
503
+ this.target = target;
504
+ }
505
+ _mixer = null;
506
+ _actions = {};
507
+ _animations = [];
508
+ _currentAction = null;
509
+ _pauseAtPercentage = 0;
510
+ _isPaused = false;
511
+ _queuedKey = null;
512
+ _fadeDuration = 0.5;
513
+ _currentKey = "";
514
+ _assetLoader = new EntityAssetLoader();
515
+ async loadAnimations(animations) {
516
+ if (!animations.length) return;
517
+ const results = await Promise.all(animations.map((a) => this._assetLoader.loadFile(a.path)));
518
+ this._animations = results.filter((r) => !!r.animation).map((r) => r.animation);
519
+ if (!this._animations.length) return;
520
+ this._mixer = new AnimationMixer(this.target);
521
+ this._animations.forEach((clip, i) => {
522
+ const key = animations[i].key || i.toString();
523
+ this._actions[key] = this._mixer.clipAction(clip);
524
+ });
525
+ this.playAnimation({ key: Object.keys(this._actions)[0] });
526
+ }
527
+ update(delta) {
528
+ if (!this._mixer || !this._currentAction) return;
529
+ this._mixer.update(delta);
530
+ const pauseAtTime = this._currentAction.getClip().duration * (this._pauseAtPercentage / 100);
531
+ if (!this._isPaused && this._pauseAtPercentage > 0 && this._currentAction.time >= pauseAtTime) {
532
+ this._currentAction.time = pauseAtTime;
533
+ this._currentAction.paused = true;
534
+ this._isPaused = true;
535
+ if (this._queuedKey !== null) {
536
+ const next = this._actions[this._queuedKey];
537
+ next.reset().play();
538
+ this._currentAction.crossFadeTo(next, this._fadeDuration, false);
539
+ this._currentAction = next;
540
+ this._currentKey = this._queuedKey;
541
+ this._queuedKey = null;
542
+ }
543
+ }
544
+ }
545
+ playAnimation(opts) {
546
+ if (!this._mixer) return;
547
+ const { key, pauseAtPercentage = 0, pauseAtEnd = false, fadeToKey, fadeDuration = 0.5 } = opts;
548
+ if (key === this._currentKey) return;
549
+ this._queuedKey = fadeToKey || null;
550
+ this._fadeDuration = fadeDuration;
551
+ this._pauseAtPercentage = pauseAtEnd ? 100 : pauseAtPercentage;
552
+ this._isPaused = false;
553
+ const prev = this._currentAction;
554
+ if (prev) prev.stop();
555
+ const action = this._actions[key];
556
+ if (!action) return;
557
+ if (this._pauseAtPercentage > 0) {
558
+ action.setLoop(LoopOnce, Infinity);
559
+ action.clampWhenFinished = true;
560
+ } else {
561
+ action.setLoop(LoopRepeat, Infinity);
562
+ action.clampWhenFinished = false;
563
+ }
564
+ if (prev) {
565
+ prev.crossFadeTo(action, fadeDuration, false);
566
+ }
567
+ action.reset().play();
568
+ this._currentAction = action;
569
+ this._currentKey = key;
570
+ }
571
+ /**
572
+ * Dispose of all animation resources
573
+ */
574
+ dispose() {
575
+ Object.values(this._actions).forEach((action) => {
576
+ action.stop();
577
+ });
578
+ if (this._mixer) {
579
+ this._mixer.stopAllAction();
580
+ this._mixer.uncacheRoot(this.target);
581
+ this._mixer = null;
582
+ }
583
+ this._actions = {};
584
+ this._animations = [];
585
+ this._currentAction = null;
586
+ this._currentKey = "";
587
+ }
588
+ get currentAnimationKey() {
589
+ return this._currentKey;
590
+ }
591
+ get animations() {
592
+ return this._animations;
593
+ }
594
+ };
595
+
596
+ // src/lib/graphics/shaders/fragment/standard.glsl
597
+ var standard_default = "uniform sampler2D tDiffuse;\nvarying vec2 vUv;\n\nvoid main() {\n vec4 texel = texture2D( tDiffuse, vUv );\n\n gl_FragColor = texel;\n}";
598
+
599
+ // src/lib/entities/actor.ts
600
+ var actorDefaults = {
601
+ position: { x: 0, y: 0, z: 0 },
602
+ collision: {
603
+ static: false,
604
+ size: new Vector3(0.5, 0.5, 0.5),
605
+ position: new Vector3(0, 0, 0)
606
+ },
607
+ material: {
608
+ shader: "standard"
609
+ },
610
+ animations: [],
611
+ models: []
612
+ };
613
+ var ACTOR_TYPE = /* @__PURE__ */ Symbol("Actor");
614
+ var ZylemActor = class extends GameEntity {
615
+ static type = ACTOR_TYPE;
616
+ _object = null;
617
+ _animationDelegate = null;
618
+ _modelFileNames = [];
619
+ _assetLoader = new EntityAssetLoader();
620
+ controlledRotation = false;
621
+ constructor(options) {
622
+ super();
623
+ this.options = { ...actorDefaults, ...options };
624
+ this.prependUpdate(this.actorUpdate.bind(this));
625
+ this.controlledRotation = true;
626
+ }
627
+ async load() {
628
+ this._modelFileNames = this.options.models || [];
629
+ await this.loadModels();
630
+ if (this._object) {
631
+ this._animationDelegate = new AnimationDelegate(this._object);
632
+ await this._animationDelegate.loadAnimations(this.options.animations || []);
633
+ }
634
+ }
635
+ async data() {
636
+ return {
637
+ animations: this._animationDelegate?.animations,
638
+ objectModel: this._object
639
+ };
640
+ }
641
+ async actorUpdate(params) {
642
+ this._animationDelegate?.update(params.delta);
643
+ }
644
+ /**
645
+ * Clean up actor resources including animations, models, and groups
646
+ */
647
+ actorDestroy() {
648
+ if (this._animationDelegate) {
649
+ this._animationDelegate.dispose();
650
+ this._animationDelegate = null;
651
+ }
652
+ if (this._object) {
653
+ this._object.traverse((child) => {
654
+ if (child.isMesh) {
655
+ const mesh = child;
656
+ mesh.geometry?.dispose();
657
+ if (Array.isArray(mesh.material)) {
658
+ mesh.material.forEach((m) => m.dispose());
659
+ } else if (mesh.material) {
660
+ mesh.material.dispose();
661
+ }
662
+ }
663
+ });
664
+ this._object = null;
665
+ }
666
+ if (this.group) {
667
+ this.group.clear();
668
+ this.group = null;
669
+ }
670
+ this._modelFileNames = [];
671
+ }
672
+ async loadModels() {
673
+ if (this._modelFileNames.length === 0) return;
674
+ const promises = this._modelFileNames.map((file) => this._assetLoader.loadFile(file));
675
+ const results = await Promise.all(promises);
676
+ if (results[0]?.object) {
677
+ this._object = results[0].object;
678
+ }
679
+ if (this._object) {
680
+ this.group = new Group2();
681
+ this.group.attach(this._object);
682
+ this.group.scale.set(
683
+ this.options.scale?.x || 1,
684
+ this.options.scale?.y || 1,
685
+ this.options.scale?.z || 1
686
+ );
687
+ }
688
+ }
689
+ playAnimation(animationOptions) {
690
+ this._animationDelegate?.playAnimation(animationOptions);
691
+ }
692
+ get object() {
693
+ return this._object;
694
+ }
695
+ /**
696
+ * Provide custom debug information for the actor
697
+ * This will be merged with the default debug information
698
+ */
699
+ getDebugInfo() {
700
+ const debugInfo = {
701
+ type: "Actor",
702
+ models: this._modelFileNames.length > 0 ? this._modelFileNames : "none",
703
+ modelLoaded: !!this._object,
704
+ scale: this.options.scale ? `${this.options.scale.x}, ${this.options.scale.y}, ${this.options.scale.z}` : "1, 1, 1"
705
+ };
706
+ if (this._animationDelegate) {
707
+ debugInfo.currentAnimation = this._animationDelegate.currentAnimationKey || "none";
708
+ debugInfo.animationsCount = this.options.animations?.length || 0;
709
+ }
710
+ if (this._object) {
711
+ let meshCount = 0;
712
+ let vertexCount = 0;
713
+ this._object.traverse((child) => {
714
+ if (child.isMesh) {
715
+ meshCount++;
716
+ const geometry = child.geometry;
717
+ if (geometry && geometry.attributes.position) {
718
+ vertexCount += geometry.attributes.position.count;
719
+ }
720
+ }
721
+ });
722
+ debugInfo.meshCount = meshCount;
723
+ debugInfo.vertexCount = vertexCount;
724
+ }
725
+ return debugInfo;
726
+ }
727
+ };
728
+
729
+ // src/lib/collision/world.ts
730
+ function isCollisionHandlerDelegate(obj) {
731
+ return typeof obj?.handlePostCollision === "function" && typeof obj?.handleIntersectionEvent === "function";
732
+ }
733
+ var ZylemWorld = class {
734
+ type = "World";
735
+ world;
736
+ collisionMap = /* @__PURE__ */ new Map();
737
+ collisionBehaviorMap = /* @__PURE__ */ new Map();
738
+ _removalMap = /* @__PURE__ */ new Map();
739
+ static async loadPhysics(gravity) {
740
+ await RAPIER.init();
741
+ const physicsWorld = new RAPIER.World(gravity);
742
+ return physicsWorld;
743
+ }
744
+ constructor(world) {
745
+ this.world = world;
746
+ }
747
+ addEntity(entity) {
748
+ const rigidBody = this.world.createRigidBody(entity.bodyDesc);
749
+ entity.body = rigidBody;
750
+ entity.body.userData = { uuid: entity.uuid, ref: entity };
751
+ if (this.world.gravity.x === 0 && this.world.gravity.y === 0 && this.world.gravity.z === 0) {
752
+ entity.body.lockTranslations(true, true);
753
+ entity.body.lockRotations(true, true);
754
+ }
755
+ const collider = this.world.createCollider(entity.colliderDesc, entity.body);
756
+ entity.collider = collider;
757
+ if (entity.controlledRotation || entity instanceof ZylemActor) {
758
+ entity.body.lockRotations(true, true);
759
+ entity.characterController = this.world.createCharacterController(0.01);
760
+ entity.characterController.setMaxSlopeClimbAngle(45 * Math.PI / 180);
761
+ entity.characterController.setMinSlopeSlideAngle(30 * Math.PI / 180);
762
+ entity.characterController.enableSnapToGround(0.01);
763
+ entity.characterController.setSlideEnabled(true);
764
+ entity.characterController.setApplyImpulsesToDynamicBodies(true);
765
+ entity.characterController.setCharacterMass(1);
766
+ }
767
+ this.collisionMap.set(entity.uuid, entity);
768
+ }
769
+ setForRemoval(entity) {
770
+ if (entity.body) {
771
+ this._removalMap.set(entity.uuid, entity);
772
+ }
773
+ }
774
+ destroyEntity(entity) {
775
+ if (entity.collider) {
776
+ this.world.removeCollider(entity.collider, true);
777
+ }
778
+ if (entity.body) {
779
+ this.world.removeRigidBody(entity.body);
780
+ this.collisionMap.delete(entity.uuid);
781
+ this._removalMap.delete(entity.uuid);
782
+ }
783
+ }
784
+ setup() {
785
+ }
786
+ update(params) {
787
+ const { delta } = params;
788
+ if (!this.world) {
789
+ return;
790
+ }
791
+ this.updateColliders(delta);
792
+ this.updatePostCollisionBehaviors(delta);
793
+ this.world.step();
794
+ }
795
+ updatePostCollisionBehaviors(delta) {
796
+ const dictionaryRef = this.collisionBehaviorMap;
797
+ for (let [id, collider] of dictionaryRef) {
798
+ const gameEntity = collider;
799
+ if (!isCollisionHandlerDelegate(gameEntity)) {
800
+ return;
801
+ }
802
+ const active = gameEntity.handlePostCollision({ entity: gameEntity, delta });
803
+ if (!active) {
804
+ this.collisionBehaviorMap.delete(id);
805
+ }
806
+ }
807
+ }
808
+ updateColliders(delta) {
809
+ const dictionaryRef = this.collisionMap;
810
+ for (let [id, collider] of dictionaryRef) {
811
+ const gameEntity = collider;
812
+ if (!gameEntity.body) {
813
+ continue;
814
+ }
815
+ if (this._removalMap.get(gameEntity.uuid)) {
816
+ this.destroyEntity(gameEntity);
817
+ continue;
818
+ }
819
+ this.world.contactsWith(gameEntity.body.collider(0), (otherCollider) => {
820
+ const uuid = otherCollider._parent.userData.uuid;
821
+ const entity = dictionaryRef.get(uuid);
822
+ if (!entity) {
823
+ return;
824
+ }
825
+ if (gameEntity._collision) {
826
+ gameEntity._collision(entity, state.globals);
827
+ }
828
+ });
829
+ this.world.intersectionsWith(gameEntity.body.collider(0), (otherCollider) => {
830
+ const uuid = otherCollider._parent.userData.uuid;
831
+ const entity = dictionaryRef.get(uuid);
832
+ if (!entity) {
833
+ return;
834
+ }
835
+ if (gameEntity._collision) {
836
+ gameEntity._collision(entity, state.globals);
837
+ }
838
+ if (isCollisionHandlerDelegate(entity)) {
839
+ entity.handleIntersectionEvent({ entity, other: gameEntity, delta });
840
+ this.collisionBehaviorMap.set(uuid, entity);
841
+ }
842
+ });
843
+ }
844
+ }
845
+ destroy() {
846
+ try {
847
+ for (const [, entity] of this.collisionMap) {
848
+ try {
849
+ this.destroyEntity(entity);
850
+ } catch {
851
+ }
852
+ }
853
+ this.collisionMap.clear();
854
+ this.collisionBehaviorMap.clear();
855
+ this._removalMap.clear();
856
+ this.world = void 0;
857
+ } catch {
858
+ }
859
+ }
860
+ };
861
+
862
+ // src/lib/graphics/zylem-scene.ts
863
+ import {
864
+ Scene,
865
+ Color as Color2,
866
+ AmbientLight,
867
+ DirectionalLight,
868
+ Vector3 as Vector32,
869
+ TextureLoader,
870
+ GridHelper
871
+ } from "three";
872
+
873
+ // src/lib/debug/debug-state.ts
874
+ import { proxy as proxy2 } from "valtio";
875
+ var debugState = proxy2({
876
+ enabled: false,
877
+ paused: false,
878
+ tool: "none",
879
+ selectedEntity: null,
880
+ hoveredEntity: null,
881
+ flags: /* @__PURE__ */ new Set()
882
+ });
883
+ function getDebugTool() {
884
+ return debugState.tool;
885
+ }
886
+ function setSelectedEntity(entity) {
887
+ debugState.selectedEntity = entity;
888
+ }
889
+ function getHoveredEntity() {
890
+ return debugState.hoveredEntity;
891
+ }
892
+ function setHoveredEntity(entity) {
893
+ debugState.hoveredEntity = entity;
894
+ }
895
+ function resetHoveredEntity() {
896
+ debugState.hoveredEntity = null;
897
+ }
898
+
899
+ // src/lib/graphics/zylem-scene.ts
900
+ var ZylemScene = class {
901
+ type = "Scene";
902
+ _setup;
903
+ scene;
904
+ zylemCamera;
905
+ containerElement = null;
906
+ update = () => {
907
+ };
908
+ _collision;
909
+ _destroy;
910
+ name;
911
+ tag;
912
+ constructor(id, camera, state2) {
913
+ const scene = new Scene();
914
+ const isColor = state2.backgroundColor instanceof Color2;
915
+ const backgroundColor = isColor ? state2.backgroundColor : new Color2(state2.backgroundColor);
916
+ scene.background = backgroundColor;
917
+ if (state2.backgroundImage) {
918
+ const loader = new TextureLoader();
919
+ const texture = loader.load(state2.backgroundImage);
920
+ scene.background = texture;
921
+ }
922
+ this.scene = scene;
923
+ this.zylemCamera = camera;
924
+ this.setupLighting(scene);
925
+ this.setupCamera(scene, camera);
926
+ if (debugState.enabled) {
927
+ this.debugScene();
928
+ }
929
+ }
930
+ setup() {
931
+ if (this._setup) {
932
+ this._setup({ me: this, camera: this.zylemCamera, globals: getGlobals() });
933
+ }
934
+ }
935
+ destroy() {
936
+ if (this.zylemCamera && this.zylemCamera.destroy) {
937
+ this.zylemCamera.destroy();
938
+ }
939
+ if (this.scene) {
940
+ this.scene.traverse((obj) => {
941
+ if (obj.geometry) {
942
+ obj.geometry.dispose?.();
943
+ }
944
+ if (obj.material) {
945
+ if (Array.isArray(obj.material)) {
946
+ obj.material.forEach((m) => m.dispose?.());
947
+ } else {
948
+ obj.material.dispose?.();
949
+ }
950
+ }
951
+ });
952
+ }
953
+ }
954
+ /**
955
+ * Setup camera with the scene
956
+ */
957
+ setupCamera(scene, camera) {
958
+ if (camera.cameraRig) {
959
+ scene.add(camera.cameraRig);
960
+ } else {
961
+ scene.add(camera.camera);
962
+ }
963
+ camera.setup(scene);
964
+ }
965
+ /**
966
+ * Setup scene lighting
967
+ */
968
+ setupLighting(scene) {
969
+ const ambientLight = new AmbientLight(16777215, 2);
970
+ scene.add(ambientLight);
971
+ const directionalLight = new DirectionalLight(16777215, 2);
972
+ directionalLight.name = "Light";
973
+ directionalLight.position.set(0, 100, 0);
974
+ directionalLight.castShadow = true;
975
+ directionalLight.shadow.camera.near = 0.1;
976
+ directionalLight.shadow.camera.far = 2e3;
977
+ directionalLight.shadow.camera.left = -100;
978
+ directionalLight.shadow.camera.right = 100;
979
+ directionalLight.shadow.camera.top = 100;
980
+ directionalLight.shadow.camera.bottom = -100;
981
+ directionalLight.shadow.mapSize.width = 2048;
982
+ directionalLight.shadow.mapSize.height = 2048;
983
+ scene.add(directionalLight);
984
+ }
985
+ /**
986
+ * Update renderer size - delegates to camera
987
+ */
988
+ updateRenderer(width, height) {
989
+ this.zylemCamera.resize(width, height);
990
+ }
991
+ /**
992
+ * Add object to scene
993
+ */
994
+ add(object, position2 = new Vector32(0, 0, 0)) {
995
+ object.position.set(position2.x, position2.y, position2.z);
996
+ this.scene.add(object);
997
+ }
998
+ /**
999
+ * Add game entity to scene
1000
+ */
1001
+ addEntity(entity) {
1002
+ if (entity.group) {
1003
+ this.add(entity.group, entity.options.position);
1004
+ } else if (entity.mesh) {
1005
+ this.add(entity.mesh, entity.options.position);
1006
+ }
1007
+ }
1008
+ /**
1009
+ * Add debug helpers to scene
1010
+ */
1011
+ debugScene() {
1012
+ const size = 1e3;
1013
+ const divisions = 100;
1014
+ const gridHelper = new GridHelper(size, divisions);
1015
+ this.scene.add(gridHelper);
1016
+ }
1017
+ };
1018
+
1019
+ // src/lib/stage/stage-state.ts
1020
+ import { Color as Color3, Vector3 as Vector33 } from "three";
1021
+ import { proxy as proxy3, subscribe as subscribe2 } from "valtio/vanilla";
1022
+ var stageState = proxy3({
1023
+ backgroundColor: new Color3(Color3.NAMES.cornflowerblue),
1024
+ backgroundImage: null,
1025
+ inputs: {
1026
+ p1: ["gamepad-1", "keyboard-1"],
1027
+ p2: ["gamepad-2", "keyboard-2"]
1028
+ },
1029
+ variables: {},
1030
+ gravity: new Vector33(0, 0, 0),
1031
+ entities: []
1032
+ });
1033
+ var setStageBackgroundColor = (value) => {
1034
+ stageState.backgroundColor = value;
1035
+ };
1036
+ var setStageBackgroundImage = (value) => {
1037
+ stageState.backgroundImage = value;
1038
+ };
1039
+ var setStageVariables = (variables) => {
1040
+ stageState.variables = { ...variables };
1041
+ };
1042
+ var resetStageVariables = () => {
1043
+ stageState.variables = {};
1044
+ };
1045
+ var variableProxyStore = /* @__PURE__ */ new Map();
1046
+ function clearVariables(target) {
1047
+ variableProxyStore.delete(target);
1048
+ }
1049
+
1050
+ // src/lib/core/utility/vector.ts
1051
+ import { Color as Color4 } from "three";
1052
+ import { Vector3 as Vector34 } from "@dimforge/rapier3d-compat";
1053
+ var ZylemBlueColor = new Color4("#0333EC");
1054
+ var Vec0 = new Vector34(0, 0, 0);
1055
+ var Vec1 = new Vector34(1, 1, 1);
1056
+
1057
+ // src/lib/stage/zylem-stage.ts
1058
+ import { subscribe as subscribe4 } from "valtio/vanilla";
1059
+
1060
+ // src/lib/core/lifecycle-base.ts
1061
+ var LifeCycleBase = class {
1062
+ update = () => {
1063
+ };
1064
+ setup = () => {
1065
+ };
1066
+ destroy = () => {
1067
+ };
1068
+ nodeSetup(context) {
1069
+ if (typeof this._setup === "function") {
1070
+ this._setup(context);
1071
+ }
1072
+ if (this.setup) {
1073
+ this.setup(context);
1074
+ }
1075
+ }
1076
+ nodeUpdate(context) {
1077
+ if (typeof this._update === "function") {
1078
+ this._update(context);
1079
+ }
1080
+ if (this.update) {
1081
+ this.update(context);
1082
+ }
1083
+ }
1084
+ nodeDestroy(context) {
1085
+ if (this.destroy) {
1086
+ this.destroy(context);
1087
+ }
1088
+ if (typeof this._destroy === "function") {
1089
+ this._destroy(context);
1090
+ }
1091
+ }
1092
+ };
1093
+
1094
+ // src/lib/stage/zylem-stage.ts
1095
+ import { nanoid as nanoid2 } from "nanoid";
1096
+
1097
+ // src/lib/stage/stage-debug-delegate.ts
1098
+ import { Ray } from "@dimforge/rapier3d-compat";
1099
+ import { BufferAttribute, BufferGeometry as BufferGeometry2, LineBasicMaterial as LineBasicMaterial2, LineSegments as LineSegments2, Raycaster, Vector2 } from "three";
1100
+
1101
+ // src/lib/stage/debug-entity-cursor.ts
1102
+ import {
1103
+ Box3,
1104
+ BoxGeometry,
1105
+ Color as Color5,
1106
+ EdgesGeometry,
1107
+ Group as Group3,
1108
+ LineBasicMaterial,
1109
+ LineSegments,
1110
+ Mesh as Mesh2,
1111
+ MeshBasicMaterial,
1112
+ Vector3 as Vector35
1113
+ } from "three";
1114
+ var DebugEntityCursor = class {
1115
+ scene;
1116
+ container;
1117
+ fillMesh;
1118
+ edgeLines;
1119
+ currentColor = new Color5(65280);
1120
+ bbox = new Box3();
1121
+ size = new Vector35();
1122
+ center = new Vector35();
1123
+ constructor(scene) {
1124
+ this.scene = scene;
1125
+ const initialGeometry = new BoxGeometry(1, 1, 1);
1126
+ this.fillMesh = new Mesh2(
1127
+ initialGeometry,
1128
+ new MeshBasicMaterial({
1129
+ color: this.currentColor,
1130
+ transparent: true,
1131
+ opacity: 0.12,
1132
+ depthWrite: false
1133
+ })
1134
+ );
1135
+ const edges = new EdgesGeometry(initialGeometry);
1136
+ this.edgeLines = new LineSegments(
1137
+ edges,
1138
+ new LineBasicMaterial({ color: this.currentColor, linewidth: 1 })
1139
+ );
1140
+ this.container = new Group3();
1141
+ this.container.name = "DebugEntityCursor";
1142
+ this.container.add(this.fillMesh);
1143
+ this.container.add(this.edgeLines);
1144
+ this.container.visible = false;
1145
+ this.scene.add(this.container);
1146
+ }
1147
+ setColor(color) {
1148
+ this.currentColor.set(color);
1149
+ this.fillMesh.material.color.set(this.currentColor);
1150
+ this.edgeLines.material.color.set(this.currentColor);
1151
+ }
1152
+ /**
1153
+ * Update the cursor to enclose the provided Object3D using a world-space AABB.
1154
+ */
1155
+ updateFromObject(object) {
1156
+ if (!object) {
1157
+ this.hide();
1158
+ return;
1159
+ }
1160
+ this.bbox.setFromObject(object);
1161
+ if (!isFinite(this.bbox.min.x) || !isFinite(this.bbox.max.x)) {
1162
+ this.hide();
1163
+ return;
1164
+ }
1165
+ this.bbox.getSize(this.size);
1166
+ this.bbox.getCenter(this.center);
1167
+ const newGeom = new BoxGeometry(
1168
+ Math.max(this.size.x, 1e-6),
1169
+ Math.max(this.size.y, 1e-6),
1170
+ Math.max(this.size.z, 1e-6)
1171
+ );
1172
+ this.fillMesh.geometry.dispose();
1173
+ this.fillMesh.geometry = newGeom;
1174
+ const newEdges = new EdgesGeometry(newGeom);
1175
+ this.edgeLines.geometry.dispose();
1176
+ this.edgeLines.geometry = newEdges;
1177
+ this.container.position.copy(this.center);
1178
+ this.container.visible = true;
1179
+ }
1180
+ hide() {
1181
+ this.container.visible = false;
1182
+ }
1183
+ dispose() {
1184
+ this.scene.remove(this.container);
1185
+ this.fillMesh.geometry.dispose();
1186
+ this.fillMesh.material.dispose();
1187
+ this.edgeLines.geometry.dispose();
1188
+ this.edgeLines.material.dispose();
1189
+ }
1190
+ };
1191
+
1192
+ // src/lib/stage/stage-debug-delegate.ts
1193
+ var SELECT_TOOL_COLOR = 2293538;
1194
+ var DELETE_TOOL_COLOR = 16724787;
1195
+ var StageDebugDelegate = class {
1196
+ stage;
1197
+ options;
1198
+ mouseNdc = new Vector2(-2, -2);
1199
+ raycaster = new Raycaster();
1200
+ isMouseDown = false;
1201
+ disposeFns = [];
1202
+ debugCursor = null;
1203
+ debugLines = null;
1204
+ constructor(stage, options) {
1205
+ this.stage = stage;
1206
+ this.options = {
1207
+ maxRayDistance: options?.maxRayDistance ?? 5e3,
1208
+ addEntityFactory: options?.addEntityFactory ?? null
1209
+ };
1210
+ if (this.stage.scene) {
1211
+ this.debugLines = new LineSegments2(
1212
+ new BufferGeometry2(),
1213
+ new LineBasicMaterial2({ vertexColors: true })
1214
+ );
1215
+ this.stage.scene.scene.add(this.debugLines);
1216
+ this.debugLines.visible = true;
1217
+ this.debugCursor = new DebugEntityCursor(this.stage.scene.scene);
1218
+ }
1219
+ this.attachDomListeners();
1220
+ }
1221
+ update() {
1222
+ if (!debugState.enabled) return;
1223
+ if (!this.stage.scene || !this.stage.world || !this.stage.cameraRef) return;
1224
+ const { world, cameraRef } = this.stage;
1225
+ if (this.debugLines) {
1226
+ const { vertices, colors } = world.world.debugRender();
1227
+ this.debugLines.geometry.setAttribute("position", new BufferAttribute(vertices, 3));
1228
+ this.debugLines.geometry.setAttribute("color", new BufferAttribute(colors, 4));
1229
+ }
1230
+ const tool = getDebugTool();
1231
+ const isCursorTool = tool === "select" || tool === "delete";
1232
+ this.raycaster.setFromCamera(this.mouseNdc, cameraRef.camera);
1233
+ const origin = this.raycaster.ray.origin.clone();
1234
+ const direction = this.raycaster.ray.direction.clone().normalize();
1235
+ const rapierRay = new Ray(
1236
+ { x: origin.x, y: origin.y, z: origin.z },
1237
+ { x: direction.x, y: direction.y, z: direction.z }
1238
+ );
1239
+ const hit = world.world.castRay(rapierRay, this.options.maxRayDistance, true);
1240
+ if (hit && isCursorTool) {
1241
+ const rigidBody = hit.collider?._parent;
1242
+ const hoveredUuid2 = rigidBody?.userData?.uuid;
1243
+ if (hoveredUuid2) {
1244
+ const entity = this.stage._debugMap.get(hoveredUuid2);
1245
+ if (entity) setHoveredEntity(entity);
1246
+ } else {
1247
+ resetHoveredEntity();
1248
+ }
1249
+ if (this.isMouseDown) {
1250
+ this.handleActionOnHit(hoveredUuid2 ?? null, origin, direction, hit.toi);
1251
+ }
1252
+ }
1253
+ this.isMouseDown = false;
1254
+ const hoveredUuid = getHoveredEntity();
1255
+ if (!hoveredUuid) {
1256
+ this.debugCursor?.hide();
1257
+ return;
1258
+ }
1259
+ const hoveredEntity = this.stage._debugMap.get(`${hoveredUuid}`);
1260
+ const targetObject = hoveredEntity?.group ?? hoveredEntity?.mesh ?? null;
1261
+ if (!targetObject) {
1262
+ this.debugCursor?.hide();
1263
+ return;
1264
+ }
1265
+ switch (tool) {
1266
+ case "select":
1267
+ this.debugCursor?.setColor(SELECT_TOOL_COLOR);
1268
+ break;
1269
+ case "delete":
1270
+ this.debugCursor?.setColor(DELETE_TOOL_COLOR);
1271
+ break;
1272
+ default:
1273
+ this.debugCursor?.setColor(16777215);
1274
+ break;
1275
+ }
1276
+ this.debugCursor?.updateFromObject(targetObject);
1277
+ }
1278
+ dispose() {
1279
+ this.disposeFns.forEach((fn) => fn());
1280
+ this.disposeFns = [];
1281
+ this.debugCursor?.dispose();
1282
+ if (this.debugLines && this.stage.scene) {
1283
+ this.stage.scene.scene.remove(this.debugLines);
1284
+ this.debugLines.geometry.dispose();
1285
+ this.debugLines.material.dispose();
1286
+ this.debugLines = null;
1287
+ }
1288
+ }
1289
+ handleActionOnHit(hoveredUuid, origin, direction, toi) {
1290
+ const tool = getDebugTool();
1291
+ switch (tool) {
1292
+ case "select": {
1293
+ if (hoveredUuid) {
1294
+ const entity = this.stage._debugMap.get(hoveredUuid);
1295
+ if (entity) setSelectedEntity(entity);
1296
+ }
1297
+ break;
1298
+ }
1299
+ case "delete": {
1300
+ if (hoveredUuid) {
1301
+ this.stage.removeEntityByUuid(hoveredUuid);
1302
+ }
1303
+ break;
1304
+ }
1305
+ case "scale": {
1306
+ if (!this.options.addEntityFactory) break;
1307
+ const hitPosition = origin.clone().add(direction.clone().multiplyScalar(toi));
1308
+ const newNode = this.options.addEntityFactory({ position: hitPosition });
1309
+ if (newNode) {
1310
+ Promise.resolve(newNode).then((node) => {
1311
+ if (node) this.stage.spawnEntity(node);
1312
+ }).catch(() => {
1313
+ });
1314
+ }
1315
+ break;
1316
+ }
1317
+ default:
1318
+ break;
1319
+ }
1320
+ }
1321
+ attachDomListeners() {
1322
+ const canvas = this.stage.cameraRef?.renderer.domElement ?? this.stage.scene?.zylemCamera.renderer.domElement;
1323
+ if (!canvas) return;
1324
+ const onMouseMove = (e) => {
1325
+ const rect = canvas.getBoundingClientRect();
1326
+ const x = (e.clientX - rect.left) / rect.width * 2 - 1;
1327
+ const y = -((e.clientY - rect.top) / rect.height * 2 - 1);
1328
+ this.mouseNdc.set(x, y);
1329
+ };
1330
+ const onMouseDown = (e) => {
1331
+ this.isMouseDown = true;
1332
+ };
1333
+ canvas.addEventListener("mousemove", onMouseMove);
1334
+ canvas.addEventListener("mousedown", onMouseDown);
1335
+ this.disposeFns.push(() => canvas.removeEventListener("mousemove", onMouseMove));
1336
+ this.disposeFns.push(() => canvas.removeEventListener("mousedown", onMouseDown));
1337
+ }
1338
+ };
1339
+
1340
+ // src/lib/stage/stage-camera-debug-delegate.ts
1341
+ import { subscribe as subscribe3 } from "valtio/vanilla";
1342
+ var StageCameraDebugDelegate = class {
1343
+ stage;
1344
+ constructor(stage) {
1345
+ this.stage = stage;
1346
+ }
1347
+ subscribe(listener) {
1348
+ const notify = () => listener(this.snapshot());
1349
+ notify();
1350
+ return subscribe3(debugState, notify);
1351
+ }
1352
+ resolveTarget(uuid) {
1353
+ const entity = this.stage._debugMap.get(uuid) || this.stage.world?.collisionMap.get(uuid) || null;
1354
+ const target = entity?.group ?? entity?.mesh ?? null;
1355
+ return target ?? null;
1356
+ }
1357
+ snapshot() {
1358
+ return {
1359
+ enabled: debugState.enabled,
1360
+ selected: debugState.selectedEntity ? [debugState.selectedEntity.uuid] : []
1361
+ };
1362
+ }
1363
+ };
1364
+
1365
+ // src/lib/stage/stage-camera-delegate.ts
1366
+ import { Vector2 as Vector24 } from "three";
1367
+
1368
+ // src/lib/camera/zylem-camera.ts
1369
+ import { PerspectiveCamera, Vector3 as Vector39, Object3D as Object3D6, OrthographicCamera, WebGLRenderer as WebGLRenderer3 } from "three";
1370
+
1371
+ // src/lib/camera/perspective.ts
1372
+ var Perspectives = {
1373
+ FirstPerson: "first-person",
1374
+ ThirdPerson: "third-person",
1375
+ Isometric: "isometric",
1376
+ Flat2D: "flat-2d",
1377
+ Fixed2D: "fixed-2d"
1378
+ };
1379
+
1380
+ // src/lib/camera/third-person.ts
1381
+ import { Vector3 as Vector37 } from "three";
1382
+ var ThirdPersonCamera = class {
1383
+ distance;
1384
+ screenResolution = null;
1385
+ renderer = null;
1386
+ scene = null;
1387
+ cameraRef = null;
1388
+ constructor() {
1389
+ this.distance = new Vector37(0, 5, 8);
1390
+ }
1391
+ /**
1392
+ * Setup the third person camera controller
1393
+ */
1394
+ setup(params) {
1395
+ const { screenResolution, renderer, scene, camera } = params;
1396
+ this.screenResolution = screenResolution;
1397
+ this.renderer = renderer;
1398
+ this.scene = scene;
1399
+ this.cameraRef = camera;
1400
+ }
1401
+ /**
1402
+ * Update the third person camera
1403
+ */
1404
+ update(delta) {
1405
+ if (!this.cameraRef.target) {
1406
+ return;
1407
+ }
1408
+ const desiredCameraPosition = this.cameraRef.target.group.position.clone().add(this.distance);
1409
+ this.cameraRef.camera.position.lerp(desiredCameraPosition, 0.1);
1410
+ this.cameraRef.camera.lookAt(this.cameraRef.target.group.position);
1411
+ }
1412
+ /**
1413
+ * Handle resize events
1414
+ */
1415
+ resize(width, height) {
1416
+ if (this.screenResolution) {
1417
+ this.screenResolution.set(width, height);
1418
+ }
1419
+ }
1420
+ /**
1421
+ * Set the distance from the target
1422
+ */
1423
+ setDistance(distance) {
1424
+ this.distance = distance;
1425
+ }
1426
+ };
1427
+
1428
+ // src/lib/camera/fixed-2d.ts
1429
+ var Fixed2DCamera = class {
1430
+ screenResolution = null;
1431
+ renderer = null;
1432
+ scene = null;
1433
+ cameraRef = null;
1434
+ constructor() {
1435
+ }
1436
+ /**
1437
+ * Setup the fixed 2D camera controller
1438
+ */
1439
+ setup(params) {
1440
+ const { screenResolution, renderer, scene, camera } = params;
1441
+ this.screenResolution = screenResolution;
1442
+ this.renderer = renderer;
1443
+ this.scene = scene;
1444
+ this.cameraRef = camera;
1445
+ this.cameraRef.camera.position.set(0, 0, 10);
1446
+ this.cameraRef.camera.lookAt(0, 0, 0);
1447
+ }
1448
+ /**
1449
+ * Update the fixed 2D camera
1450
+ * Fixed cameras don't need to update position/rotation automatically
1451
+ */
1452
+ update(delta) {
1453
+ }
1454
+ /**
1455
+ * Handle resize events for 2D camera
1456
+ */
1457
+ resize(width, height) {
1458
+ if (this.screenResolution) {
1459
+ this.screenResolution.set(width, height);
1460
+ }
1461
+ }
1462
+ };
1463
+
1464
+ // src/lib/camera/zylem-camera.ts
1465
+ import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
1466
+
1467
+ // src/lib/graphics/render-pass.ts
1468
+ import * as THREE from "three";
1469
+
1470
+ // src/lib/graphics/shaders/vertex/standard.glsl
1471
+ var standard_default2 = "varying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}";
1472
+
1473
+ // src/lib/graphics/render-pass.ts
1474
+ import { WebGLRenderTarget } from "three";
1475
+ import { Pass, FullScreenQuad } from "three/addons/postprocessing/Pass.js";
1476
+ var RenderPass = class extends Pass {
1477
+ fsQuad;
1478
+ resolution;
1479
+ scene;
1480
+ camera;
1481
+ rgbRenderTarget;
1482
+ normalRenderTarget;
1483
+ normalMaterial;
1484
+ constructor(resolution, scene, camera) {
1485
+ super();
1486
+ this.resolution = resolution;
1487
+ this.fsQuad = new FullScreenQuad(this.material());
1488
+ this.scene = scene;
1489
+ this.camera = camera;
1490
+ this.rgbRenderTarget = new WebGLRenderTarget(resolution.x * 4, resolution.y * 4);
1491
+ this.normalRenderTarget = new WebGLRenderTarget(resolution.x * 4, resolution.y * 4);
1492
+ this.normalMaterial = new THREE.MeshNormalMaterial();
1493
+ }
1494
+ render(renderer, writeBuffer) {
1495
+ renderer.setRenderTarget(this.rgbRenderTarget);
1496
+ renderer.render(this.scene, this.camera);
1497
+ const overrideMaterial_old = this.scene.overrideMaterial;
1498
+ renderer.setRenderTarget(this.normalRenderTarget);
1499
+ this.scene.overrideMaterial = this.normalMaterial;
1500
+ renderer.render(this.scene, this.camera);
1501
+ this.scene.overrideMaterial = overrideMaterial_old;
1502
+ const uniforms = this.fsQuad.material.uniforms;
1503
+ uniforms.tDiffuse.value = this.rgbRenderTarget.texture;
1504
+ uniforms.tDepth.value = this.rgbRenderTarget.depthTexture;
1505
+ uniforms.tNormal.value = this.normalRenderTarget.texture;
1506
+ uniforms.iTime.value += 0.01;
1507
+ if (this.renderToScreen) {
1508
+ renderer.setRenderTarget(null);
1509
+ } else {
1510
+ renderer.setRenderTarget(writeBuffer);
1511
+ }
1512
+ this.fsQuad.render(renderer);
1513
+ }
1514
+ material() {
1515
+ return new THREE.ShaderMaterial({
1516
+ uniforms: {
1517
+ iTime: { value: 0 },
1518
+ tDiffuse: { value: null },
1519
+ tDepth: { value: null },
1520
+ tNormal: { value: null },
1521
+ resolution: {
1522
+ value: new THREE.Vector4(
1523
+ this.resolution.x,
1524
+ this.resolution.y,
1525
+ 1 / this.resolution.x,
1526
+ 1 / this.resolution.y
1527
+ )
1528
+ }
1529
+ },
1530
+ vertexShader: standard_default2,
1531
+ fragmentShader: standard_default
1532
+ });
1533
+ }
1534
+ dispose() {
1535
+ try {
1536
+ this.fsQuad?.dispose?.();
1537
+ } catch {
1538
+ }
1539
+ try {
1540
+ this.rgbRenderTarget?.dispose?.();
1541
+ this.normalRenderTarget?.dispose?.();
1542
+ } catch {
1543
+ }
1544
+ try {
1545
+ this.normalMaterial?.dispose?.();
1546
+ } catch {
1547
+ }
1548
+ }
1549
+ };
1550
+
1551
+ // src/lib/camera/camera-debug-delegate.ts
1552
+ import { Vector3 as Vector38 } from "three";
1553
+ import { OrbitControls } from "three/addons/controls/OrbitControls.js";
1554
+ var CameraOrbitController = class {
1555
+ camera;
1556
+ domElement;
1557
+ orbitControls = null;
1558
+ orbitTarget = null;
1559
+ orbitTargetWorldPos = new Vector38();
1560
+ debugDelegate = null;
1561
+ debugUnsubscribe = null;
1562
+ debugStateSnapshot = { enabled: false, selected: [] };
1563
+ // Saved camera state for restoration when exiting debug mode
1564
+ savedCameraPosition = null;
1565
+ savedCameraQuaternion = null;
1566
+ savedCameraZoom = null;
1567
+ constructor(camera, domElement) {
1568
+ this.camera = camera;
1569
+ this.domElement = domElement;
1570
+ }
1571
+ /**
1572
+ * Check if debug mode is currently active (orbit controls enabled).
1573
+ */
1574
+ get isActive() {
1575
+ return this.debugStateSnapshot.enabled;
1576
+ }
1577
+ /**
1578
+ * Update orbit controls each frame.
1579
+ * Should be called from the camera's update loop.
1580
+ */
1581
+ update() {
1582
+ if (this.orbitControls && this.orbitTarget) {
1583
+ this.orbitTarget.getWorldPosition(this.orbitTargetWorldPos);
1584
+ this.orbitControls.target.copy(this.orbitTargetWorldPos);
1585
+ }
1586
+ this.orbitControls?.update();
1587
+ }
1588
+ /**
1589
+ * Attach a delegate to react to debug state changes.
1590
+ */
1591
+ setDebugDelegate(delegate) {
1592
+ if (this.debugDelegate === delegate) {
1593
+ return;
1594
+ }
1595
+ this.detachDebugDelegate();
1596
+ this.debugDelegate = delegate;
1597
+ if (!delegate) {
1598
+ this.applyDebugState({ enabled: false, selected: [] });
1599
+ return;
1600
+ }
1601
+ const unsubscribe = delegate.subscribe((state2) => {
1602
+ this.applyDebugState(state2);
1603
+ });
1604
+ this.debugUnsubscribe = () => {
1605
+ unsubscribe?.();
1606
+ };
1607
+ }
1608
+ /**
1609
+ * Clean up resources.
1610
+ */
1611
+ dispose() {
1612
+ this.disableOrbitControls();
1613
+ this.detachDebugDelegate();
1614
+ }
1615
+ /**
1616
+ * Get the current debug state snapshot.
1617
+ */
1618
+ get debugState() {
1619
+ return this.debugStateSnapshot;
1620
+ }
1621
+ applyDebugState(state2) {
1622
+ const wasEnabled = this.debugStateSnapshot.enabled;
1623
+ this.debugStateSnapshot = {
1624
+ enabled: state2.enabled,
1625
+ selected: [...state2.selected]
1626
+ };
1627
+ if (state2.enabled && !wasEnabled) {
1628
+ this.saveCameraState();
1629
+ this.enableOrbitControls();
1630
+ this.updateOrbitTargetFromSelection(state2.selected);
1631
+ } else if (!state2.enabled && wasEnabled) {
1632
+ this.orbitTarget = null;
1633
+ this.disableOrbitControls();
1634
+ this.restoreCameraState();
1635
+ } else if (state2.enabled) {
1636
+ this.updateOrbitTargetFromSelection(state2.selected);
1637
+ }
1638
+ }
1639
+ enableOrbitControls() {
1640
+ if (this.orbitControls) {
1641
+ return;
1642
+ }
1643
+ this.orbitControls = new OrbitControls(this.camera, this.domElement);
1644
+ this.orbitControls.enableDamping = true;
1645
+ this.orbitControls.dampingFactor = 0.05;
1646
+ this.orbitControls.screenSpacePanning = false;
1647
+ this.orbitControls.minDistance = 1;
1648
+ this.orbitControls.maxDistance = 500;
1649
+ this.orbitControls.maxPolarAngle = Math.PI / 2;
1650
+ this.orbitControls.target.set(0, 0, 0);
1651
+ }
1652
+ disableOrbitControls() {
1653
+ if (!this.orbitControls) {
1654
+ return;
1655
+ }
1656
+ this.orbitControls.dispose();
1657
+ this.orbitControls = null;
1658
+ }
1659
+ updateOrbitTargetFromSelection(selected) {
1660
+ if (!this.debugDelegate || selected.length === 0) {
1661
+ this.orbitTarget = null;
1662
+ if (this.orbitControls) {
1663
+ this.orbitControls.target.set(0, 0, 0);
1664
+ }
1665
+ return;
1666
+ }
1667
+ for (let i = selected.length - 1; i >= 0; i -= 1) {
1668
+ const uuid = selected[i];
1669
+ const targetObject = this.debugDelegate.resolveTarget(uuid);
1670
+ if (targetObject) {
1671
+ this.orbitTarget = targetObject;
1672
+ if (this.orbitControls) {
1673
+ targetObject.getWorldPosition(this.orbitTargetWorldPos);
1674
+ this.orbitControls.target.copy(this.orbitTargetWorldPos);
1675
+ }
1676
+ return;
1677
+ }
1678
+ }
1679
+ this.orbitTarget = null;
1680
+ }
1681
+ detachDebugDelegate() {
1682
+ if (this.debugUnsubscribe) {
1683
+ try {
1684
+ this.debugUnsubscribe();
1685
+ } catch {
1686
+ }
1687
+ }
1688
+ this.debugUnsubscribe = null;
1689
+ this.debugDelegate = null;
1690
+ }
1691
+ /**
1692
+ * Save camera position, rotation, and zoom before entering debug mode.
1693
+ */
1694
+ saveCameraState() {
1695
+ this.savedCameraPosition = this.camera.position.clone();
1696
+ this.savedCameraQuaternion = this.camera.quaternion.clone();
1697
+ if ("zoom" in this.camera) {
1698
+ this.savedCameraZoom = this.camera.zoom;
1699
+ }
1700
+ }
1701
+ /**
1702
+ * Restore camera position, rotation, and zoom when exiting debug mode.
1703
+ */
1704
+ restoreCameraState() {
1705
+ if (this.savedCameraPosition) {
1706
+ this.camera.position.copy(this.savedCameraPosition);
1707
+ this.savedCameraPosition = null;
1708
+ }
1709
+ if (this.savedCameraQuaternion) {
1710
+ this.camera.quaternion.copy(this.savedCameraQuaternion);
1711
+ this.savedCameraQuaternion = null;
1712
+ }
1713
+ if (this.savedCameraZoom !== null && "zoom" in this.camera) {
1714
+ this.camera.zoom = this.savedCameraZoom;
1715
+ this.camera.updateProjectionMatrix?.();
1716
+ this.savedCameraZoom = null;
1717
+ }
1718
+ }
1719
+ };
1720
+
1721
+ // src/lib/camera/zylem-camera.ts
1722
+ var ZylemCamera = class {
1723
+ cameraRig = null;
1724
+ camera;
1725
+ screenResolution;
1726
+ renderer;
1727
+ composer;
1728
+ _perspective;
1729
+ target = null;
1730
+ sceneRef = null;
1731
+ frustumSize = 10;
1732
+ // Perspective controller delegation
1733
+ perspectiveController = null;
1734
+ // Debug/orbit controls delegation
1735
+ orbitController = null;
1736
+ constructor(perspective, screenResolution, frustumSize = 10) {
1737
+ this._perspective = perspective;
1738
+ this.screenResolution = screenResolution;
1739
+ this.frustumSize = frustumSize;
1740
+ this.renderer = new WebGLRenderer3({ antialias: false, alpha: true });
1741
+ this.renderer.setSize(screenResolution.x, screenResolution.y);
1742
+ this.renderer.shadowMap.enabled = true;
1743
+ this.composer = new EffectComposer(this.renderer);
1744
+ const aspectRatio = screenResolution.x / screenResolution.y;
1745
+ this.camera = this.createCameraForPerspective(aspectRatio);
1746
+ if (this.needsRig()) {
1747
+ this.cameraRig = new Object3D6();
1748
+ this.cameraRig.position.set(0, 3, 10);
1749
+ this.cameraRig.add(this.camera);
1750
+ this.camera.lookAt(new Vector39(0, 2, 0));
1751
+ } else {
1752
+ this.camera.position.set(0, 0, 10);
1753
+ this.camera.lookAt(new Vector39(0, 0, 0));
1754
+ }
1755
+ this.initializePerspectiveController();
1756
+ this.orbitController = new CameraOrbitController(this.camera, this.renderer.domElement);
1757
+ }
1758
+ /**
1759
+ * Setup the camera with a scene
1760
+ */
1761
+ async setup(scene) {
1762
+ this.sceneRef = scene;
1763
+ let renderResolution = this.screenResolution.clone().divideScalar(2);
1764
+ renderResolution.x |= 0;
1765
+ renderResolution.y |= 0;
1766
+ const pass = new RenderPass(renderResolution, scene, this.camera);
1767
+ this.composer.addPass(pass);
1768
+ if (this.perspectiveController) {
1769
+ this.perspectiveController.setup({
1770
+ screenResolution: this.screenResolution,
1771
+ renderer: this.renderer,
1772
+ scene,
1773
+ camera: this
1774
+ });
1775
+ }
1776
+ this.renderer.setAnimationLoop((delta) => {
1777
+ this.update(delta || 0);
1778
+ });
1779
+ }
1780
+ /**
1781
+ * Update camera and render
1782
+ */
1783
+ update(delta) {
1784
+ this.orbitController?.update();
1785
+ if (this.perspectiveController && !this.isDebugModeActive()) {
1786
+ this.perspectiveController.update(delta);
1787
+ }
1788
+ this.composer.render(delta);
1789
+ }
1790
+ /**
1791
+ * Check if debug mode is active (orbit controls taking over camera)
1792
+ */
1793
+ isDebugModeActive() {
1794
+ return this.orbitController?.isActive ?? false;
1795
+ }
1796
+ /**
1797
+ * Dispose renderer, composer, controls, and detach from scene
1798
+ */
1799
+ destroy() {
1800
+ try {
1801
+ this.renderer.setAnimationLoop(null);
1802
+ } catch {
1803
+ }
1804
+ try {
1805
+ this.orbitController?.dispose();
1806
+ } catch {
1807
+ }
1808
+ try {
1809
+ this.composer?.passes?.forEach((p) => p.dispose?.());
1810
+ this.composer?.dispose?.();
1811
+ } catch {
1812
+ }
1813
+ try {
1814
+ this.renderer.dispose();
1815
+ } catch {
1816
+ }
1817
+ this.sceneRef = null;
1818
+ }
1819
+ /**
1820
+ * Attach a delegate to react to debug state changes.
1821
+ */
1822
+ setDebugDelegate(delegate) {
1823
+ this.orbitController?.setDebugDelegate(delegate);
1824
+ }
1825
+ /**
1826
+ * Resize camera and renderer
1827
+ */
1828
+ resize(width, height) {
1829
+ this.screenResolution.set(width, height);
1830
+ this.renderer.setSize(width, height, false);
1831
+ this.composer.setSize(width, height);
1832
+ if (this.camera instanceof PerspectiveCamera) {
1833
+ this.camera.aspect = width / height;
1834
+ this.camera.updateProjectionMatrix();
1835
+ }
1836
+ if (this.perspectiveController) {
1837
+ this.perspectiveController.resize(width, height);
1838
+ }
1839
+ }
1840
+ /**
1841
+ * Update renderer pixel ratio (DPR)
1842
+ */
1843
+ setPixelRatio(dpr) {
1844
+ const safe = Math.max(1, Number.isFinite(dpr) ? dpr : 1);
1845
+ this.renderer.setPixelRatio(safe);
1846
+ }
1847
+ /**
1848
+ * Create camera based on perspective type
1849
+ */
1850
+ createCameraForPerspective(aspectRatio) {
1851
+ switch (this._perspective) {
1852
+ case Perspectives.ThirdPerson:
1853
+ return this.createThirdPersonCamera(aspectRatio);
1854
+ case Perspectives.FirstPerson:
1855
+ return this.createFirstPersonCamera(aspectRatio);
1856
+ case Perspectives.Isometric:
1857
+ return this.createIsometricCamera(aspectRatio);
1858
+ case Perspectives.Flat2D:
1859
+ return this.createFlat2DCamera(aspectRatio);
1860
+ case Perspectives.Fixed2D:
1861
+ return this.createFixed2DCamera(aspectRatio);
1862
+ default:
1863
+ return this.createThirdPersonCamera(aspectRatio);
1864
+ }
1865
+ }
1866
+ /**
1867
+ * Initialize perspective-specific controller
1868
+ */
1869
+ initializePerspectiveController() {
1870
+ switch (this._perspective) {
1871
+ case Perspectives.ThirdPerson:
1872
+ this.perspectiveController = new ThirdPersonCamera();
1873
+ break;
1874
+ case Perspectives.Fixed2D:
1875
+ this.perspectiveController = new Fixed2DCamera();
1876
+ break;
1877
+ default:
1878
+ this.perspectiveController = new ThirdPersonCamera();
1879
+ }
1880
+ }
1881
+ createThirdPersonCamera(aspectRatio) {
1882
+ return new PerspectiveCamera(75, aspectRatio, 0.1, 1e3);
1883
+ }
1884
+ createFirstPersonCamera(aspectRatio) {
1885
+ return new PerspectiveCamera(75, aspectRatio, 0.1, 1e3);
1886
+ }
1887
+ createIsometricCamera(aspectRatio) {
1888
+ return new OrthographicCamera(
1889
+ this.frustumSize * aspectRatio / -2,
1890
+ this.frustumSize * aspectRatio / 2,
1891
+ this.frustumSize / 2,
1892
+ this.frustumSize / -2,
1893
+ 1,
1894
+ 1e3
1895
+ );
1896
+ }
1897
+ createFlat2DCamera(aspectRatio) {
1898
+ return new OrthographicCamera(
1899
+ this.frustumSize * aspectRatio / -2,
1900
+ this.frustumSize * aspectRatio / 2,
1901
+ this.frustumSize / 2,
1902
+ this.frustumSize / -2,
1903
+ 1,
1904
+ 1e3
1905
+ );
1906
+ }
1907
+ createFixed2DCamera(aspectRatio) {
1908
+ return this.createFlat2DCamera(aspectRatio);
1909
+ }
1910
+ // Movement methods
1911
+ moveCamera(position2) {
1912
+ if (this._perspective === Perspectives.Flat2D || this._perspective === Perspectives.Fixed2D) {
1913
+ this.frustumSize = position2.z;
1914
+ }
1915
+ if (this.cameraRig) {
1916
+ this.cameraRig.position.set(position2.x, position2.y, position2.z);
1917
+ } else {
1918
+ this.camera.position.set(position2.x, position2.y, position2.z);
1919
+ }
1920
+ }
1921
+ move(position2) {
1922
+ this.moveCamera(position2);
1923
+ }
1924
+ rotate(pitch, yaw, roll) {
1925
+ if (this.cameraRig) {
1926
+ this.cameraRig.rotateX(pitch);
1927
+ this.cameraRig.rotateY(yaw);
1928
+ this.cameraRig.rotateZ(roll);
1929
+ } else {
1930
+ this.camera.rotateX(pitch);
1931
+ this.camera.rotateY(yaw);
1932
+ this.camera.rotateZ(roll);
1933
+ }
1934
+ }
1935
+ /**
1936
+ * Check if this perspective type needs a camera rig
1937
+ */
1938
+ needsRig() {
1939
+ return this._perspective === Perspectives.ThirdPerson;
1940
+ }
1941
+ /**
1942
+ * Get the DOM element for the renderer
1943
+ */
1944
+ getDomElement() {
1945
+ return this.renderer.domElement;
1946
+ }
1947
+ };
1948
+
1949
+ // src/lib/stage/stage-camera-delegate.ts
1950
+ var StageCameraDelegate = class {
1951
+ stage;
1952
+ constructor(stage) {
1953
+ this.stage = stage;
1954
+ }
1955
+ /**
1956
+ * Create a default third-person camera based on window size.
1957
+ */
1958
+ createDefaultCamera() {
1959
+ const width = window.innerWidth;
1960
+ const height = window.innerHeight;
1961
+ const screenResolution = new Vector24(width, height);
1962
+ return new ZylemCamera(Perspectives.ThirdPerson, screenResolution);
1963
+ }
1964
+ /**
1965
+ * Resolve the camera to use for the stage.
1966
+ * Uses the provided camera, stage camera wrapper, or creates a default.
1967
+ *
1968
+ * @param cameraOverride Optional camera override
1969
+ * @param cameraWrapper Optional camera wrapper from stage options
1970
+ * @returns The resolved ZylemCamera instance
1971
+ */
1972
+ resolveCamera(cameraOverride, cameraWrapper) {
1973
+ if (cameraOverride) {
1974
+ return cameraOverride;
1975
+ }
1976
+ if (cameraWrapper) {
1977
+ return cameraWrapper.cameraRef;
1978
+ }
1979
+ return this.createDefaultCamera();
1980
+ }
1981
+ };
1982
+
1983
+ // src/lib/stage/stage-loading-delegate.ts
1984
+ var StageLoadingDelegate = class {
1985
+ loadingHandlers = [];
1986
+ stageName;
1987
+ stageIndex;
1988
+ /**
1989
+ * Set stage context for event bus emissions.
1990
+ */
1991
+ setStageContext(stageName, stageIndex) {
1992
+ this.stageName = stageName;
1993
+ this.stageIndex = stageIndex;
1994
+ }
1995
+ /**
1996
+ * Subscribe to loading events.
1997
+ *
1998
+ * @param callback Invoked for each loading event (start, progress, complete)
1999
+ * @returns Unsubscribe function
2000
+ */
2001
+ onLoading(callback) {
2002
+ this.loadingHandlers.push(callback);
2003
+ return () => {
2004
+ this.loadingHandlers = this.loadingHandlers.filter((h) => h !== callback);
2005
+ };
2006
+ }
2007
+ /**
2008
+ * Emit a loading event to all subscribers and to the game event bus.
2009
+ *
2010
+ * @param event The loading event to broadcast
2011
+ */
2012
+ emit(event) {
2013
+ for (const handler of this.loadingHandlers) {
2014
+ try {
2015
+ handler(event);
2016
+ } catch (e) {
2017
+ console.error("Loading handler failed", e);
2018
+ }
2019
+ }
2020
+ const payload = {
2021
+ ...event,
2022
+ stageName: this.stageName,
2023
+ stageIndex: this.stageIndex
2024
+ };
2025
+ if (event.type === "start") {
2026
+ gameEventBus.emit("stage:loading:start", payload);
2027
+ } else if (event.type === "progress") {
2028
+ gameEventBus.emit("stage:loading:progress", payload);
2029
+ } else if (event.type === "complete") {
2030
+ gameEventBus.emit("stage:loading:complete", payload);
2031
+ }
2032
+ }
2033
+ /**
2034
+ * Emit a start loading event.
2035
+ */
2036
+ emitStart(message = "Loading stage...") {
2037
+ this.emit({ type: "start", message, progress: 0 });
2038
+ }
2039
+ /**
2040
+ * Emit a progress loading event.
2041
+ */
2042
+ emitProgress(message, current, total) {
2043
+ const progress = total > 0 ? current / total : 0;
2044
+ this.emit({ type: "progress", message, progress, current, total });
2045
+ }
2046
+ /**
2047
+ * Emit a complete loading event.
2048
+ */
2049
+ emitComplete(message = "Stage loaded") {
2050
+ this.emit({ type: "complete", message, progress: 1 });
2051
+ }
2052
+ /**
2053
+ * Clear all loading handlers.
2054
+ */
2055
+ dispose() {
2056
+ this.loadingHandlers = [];
2057
+ }
2058
+ };
2059
+
2060
+ // src/lib/stage/stage-config.ts
2061
+ import { Vector3 as Vector310 } from "three";
2062
+
2063
+ // src/lib/core/utility/options-parser.ts
2064
+ function isBaseNode(item) {
2065
+ return !!item && typeof item === "object" && typeof item.create === "function";
2066
+ }
2067
+ function isThenable(item) {
2068
+ return !!item && typeof item.then === "function";
2069
+ }
2070
+ function isCameraWrapper(item) {
2071
+ return !!item && typeof item === "object" && item.constructor?.name === "CameraWrapper";
2072
+ }
2073
+ function isConfigObject(item) {
2074
+ if (!item || typeof item !== "object") return false;
2075
+ if (isBaseNode(item)) return false;
2076
+ if (isCameraWrapper(item)) return false;
2077
+ if (isThenable(item)) return false;
2078
+ if (typeof item.then === "function") return false;
2079
+ return item.constructor === Object || item.constructor?.name === "Object";
2080
+ }
2081
+ function isEntityInput(item) {
2082
+ if (!item) return false;
2083
+ if (isBaseNode(item)) return true;
2084
+ if (typeof item === "function") return true;
2085
+ if (isThenable(item)) return true;
2086
+ return false;
2087
+ }
2088
+
2089
+ // src/lib/stage/stage-config.ts
2090
+ var StageConfig = class {
2091
+ constructor(inputs, backgroundColor, backgroundImage, gravity, variables) {
2092
+ this.inputs = inputs;
2093
+ this.backgroundColor = backgroundColor;
2094
+ this.backgroundImage = backgroundImage;
2095
+ this.gravity = gravity;
2096
+ this.variables = variables;
2097
+ }
2098
+ };
2099
+ function createDefaultStageConfig() {
2100
+ return new StageConfig(
2101
+ {
2102
+ p1: ["gamepad-1", "keyboard-1"],
2103
+ p2: ["gamepad-2", "keyboard-2"]
2104
+ },
2105
+ ZylemBlueColor,
2106
+ null,
2107
+ new Vector310(0, 0, 0),
2108
+ {}
2109
+ );
2110
+ }
2111
+ function parseStageOptions(options = []) {
2112
+ const defaults = createDefaultStageConfig();
2113
+ let config = {};
2114
+ const entities = [];
2115
+ const asyncEntities = [];
2116
+ let camera;
2117
+ for (const item of options) {
2118
+ if (isCameraWrapper(item)) {
2119
+ camera = item;
2120
+ } else if (isBaseNode(item)) {
2121
+ entities.push(item);
2122
+ } else if (isEntityInput(item) && !isBaseNode(item)) {
2123
+ asyncEntities.push(item);
2124
+ } else if (isConfigObject(item)) {
2125
+ config = { ...config, ...item };
2126
+ }
2127
+ }
2128
+ const resolvedConfig = new StageConfig(
2129
+ config.inputs ?? defaults.inputs,
2130
+ config.backgroundColor ?? defaults.backgroundColor,
2131
+ config.backgroundImage ?? defaults.backgroundImage,
2132
+ config.gravity ?? defaults.gravity,
2133
+ config.variables ?? defaults.variables
2134
+ );
2135
+ return { config: resolvedConfig, entities, asyncEntities, camera };
2136
+ }
2137
+
2138
+ // src/lib/stage/zylem-stage.ts
2139
+ var STAGE_TYPE = "Stage";
2140
+ var ZylemStage = class extends LifeCycleBase {
2141
+ type = STAGE_TYPE;
2142
+ state = {
2143
+ backgroundColor: ZylemBlueColor,
2144
+ backgroundImage: null,
2145
+ inputs: {
2146
+ p1: ["gamepad-1", "keyboard"],
2147
+ p2: ["gamepad-2", "keyboard"]
2148
+ },
2149
+ gravity: new Vector311(0, 0, 0),
2150
+ variables: {},
2151
+ entities: []
2152
+ };
2153
+ gravity;
2154
+ world;
2155
+ scene;
2156
+ children = [];
2157
+ _childrenMap = /* @__PURE__ */ new Map();
2158
+ _removalMap = /* @__PURE__ */ new Map();
2159
+ pendingEntities = [];
2160
+ pendingPromises = [];
2161
+ isLoaded = false;
2162
+ _debugMap = /* @__PURE__ */ new Map();
2163
+ entityAddedHandlers = [];
2164
+ ecs = createECS();
2165
+ testSystem = null;
2166
+ transformSystem = null;
2167
+ debugDelegate = null;
2168
+ cameraDebugDelegate = null;
2169
+ debugStateUnsubscribe = null;
2170
+ uuid;
2171
+ wrapperRef = null;
2172
+ camera;
2173
+ cameraRef = null;
2174
+ // Delegates
2175
+ cameraDelegate;
2176
+ loadingDelegate;
2177
+ /**
2178
+ * Create a new stage.
2179
+ * @param options Stage options: partial config, camera, and initial entities or factories
2180
+ */
2181
+ constructor(options = []) {
2182
+ super();
2183
+ this.world = null;
2184
+ this.scene = null;
2185
+ this.uuid = nanoid2();
2186
+ this.cameraDelegate = new StageCameraDelegate(this);
2187
+ this.loadingDelegate = new StageLoadingDelegate();
2188
+ const parsed = parseStageOptions(options);
2189
+ this.camera = parsed.camera;
2190
+ this.children = parsed.entities;
2191
+ this.pendingEntities = parsed.asyncEntities;
2192
+ this.saveState({
2193
+ ...this.state,
2194
+ inputs: parsed.config.inputs,
2195
+ backgroundColor: parsed.config.backgroundColor,
2196
+ backgroundImage: parsed.config.backgroundImage,
2197
+ gravity: parsed.config.gravity,
2198
+ variables: parsed.config.variables,
2199
+ entities: []
2200
+ });
2201
+ this.gravity = parsed.config.gravity ?? new Vector311(0, 0, 0);
2202
+ }
2203
+ handleEntityImmediatelyOrQueue(entity) {
2204
+ if (this.isLoaded) {
2205
+ this.spawnEntity(entity);
2206
+ } else {
2207
+ this.children.push(entity);
2208
+ }
2209
+ }
2210
+ handlePromiseWithSpawnOnResolve(promise) {
2211
+ if (this.isLoaded) {
2212
+ promise.then((entity) => this.spawnEntity(entity)).catch((e) => console.error("Failed to build async entity", e));
2213
+ } else {
2214
+ this.pendingPromises.push(promise);
2215
+ }
2216
+ }
2217
+ saveState(state2) {
2218
+ this.state = state2;
2219
+ }
2220
+ setState() {
2221
+ const { backgroundColor, backgroundImage } = this.state;
2222
+ const color = backgroundColor instanceof Color7 ? backgroundColor : new Color7(backgroundColor);
2223
+ setStageBackgroundColor(color);
2224
+ setStageBackgroundImage(backgroundImage);
2225
+ setStageVariables(this.state.variables ?? {});
2226
+ }
2227
+ /**
2228
+ * Load and initialize the stage's scene and world.
2229
+ * Uses generator pattern to yield control to event loop for real-time progress.
2230
+ * @param id DOM element id for the renderer container
2231
+ * @param camera Optional camera override
2232
+ */
2233
+ async load(id, camera) {
2234
+ this.setState();
2235
+ const zylemCamera = this.cameraDelegate.resolveCamera(camera, this.camera);
2236
+ this.cameraRef = zylemCamera;
2237
+ this.scene = new ZylemScene(id, zylemCamera, this.state);
2238
+ const physicsWorld = await ZylemWorld.loadPhysics(this.gravity ?? new Vector311(0, 0, 0));
2239
+ this.world = new ZylemWorld(physicsWorld);
2240
+ this.scene.setup();
2241
+ this.loadingDelegate.emitStart();
2242
+ await this.runEntityLoadGenerator();
2243
+ this.transformSystem = createTransformSystem(this);
2244
+ this.isLoaded = true;
2245
+ this.loadingDelegate.emitComplete();
2246
+ }
2247
+ /**
2248
+ * Generator that yields between entity loads for real-time progress updates.
2249
+ */
2250
+ *entityLoadGenerator() {
2251
+ const total = this.children.length + this.pendingEntities.length + this.pendingPromises.length;
2252
+ let current = 0;
2253
+ for (const child of this.children) {
2254
+ this.spawnEntity(child);
2255
+ current++;
2256
+ yield { current, total, name: child.name || "unknown" };
2257
+ }
2258
+ if (this.pendingEntities.length) {
2259
+ this.enqueue(...this.pendingEntities);
2260
+ current += this.pendingEntities.length;
2261
+ this.pendingEntities = [];
2262
+ yield { current, total, name: "pending entities" };
2263
+ }
2264
+ if (this.pendingPromises.length) {
2265
+ for (const promise of this.pendingPromises) {
2266
+ promise.then((entity) => {
2267
+ this.spawnEntity(entity);
2268
+ }).catch((e) => console.error("Failed to resolve pending stage entity", e));
2269
+ }
2270
+ current += this.pendingPromises.length;
2271
+ this.pendingPromises = [];
2272
+ yield { current, total, name: "async entities" };
2273
+ }
2274
+ }
2275
+ /**
2276
+ * Runs the entity load generator, yielding to the event loop between loads.
2277
+ * This allows the browser to process events and update the UI in real-time.
2278
+ */
2279
+ async runEntityLoadGenerator() {
2280
+ const gen = this.entityLoadGenerator();
2281
+ for (const progress of gen) {
2282
+ this.loadingDelegate.emitProgress(`Loaded ${progress.name}`, progress.current, progress.total);
2283
+ await new Promise((resolve) => setTimeout(resolve, 0));
2284
+ }
2285
+ }
2286
+ _setup(params) {
2287
+ if (!this.scene || !this.world) {
2288
+ this.logMissingEntities();
2289
+ return;
2290
+ }
2291
+ this.updateDebugDelegate();
2292
+ this.debugStateUnsubscribe = subscribe4(debugState, () => {
2293
+ this.updateDebugDelegate();
2294
+ });
2295
+ }
2296
+ updateDebugDelegate() {
2297
+ if (debugState.enabled && !this.debugDelegate && this.scene && this.world) {
2298
+ this.debugDelegate = new StageDebugDelegate(this);
2299
+ if (this.cameraRef && !this.cameraDebugDelegate) {
2300
+ this.cameraDebugDelegate = new StageCameraDebugDelegate(this);
2301
+ this.cameraRef.setDebugDelegate(this.cameraDebugDelegate);
2302
+ }
2303
+ } else if (!debugState.enabled && this.debugDelegate) {
2304
+ this.debugDelegate.dispose();
2305
+ this.debugDelegate = null;
2306
+ if (this.cameraRef) {
2307
+ this.cameraRef.setDebugDelegate(null);
2308
+ }
2309
+ this.cameraDebugDelegate = null;
2310
+ }
2311
+ }
2312
+ _update(params) {
2313
+ const { delta } = params;
2314
+ if (!this.scene || !this.world) {
2315
+ this.logMissingEntities();
2316
+ return;
2317
+ }
2318
+ this.world.update(params);
2319
+ this.transformSystem?.system(this.ecs);
2320
+ this._childrenMap.forEach((child, eid) => {
2321
+ child.nodeUpdate({
2322
+ ...params,
2323
+ me: child
2324
+ });
2325
+ if (child.markedForRemoval) {
2326
+ this.removeEntityByUuid(child.uuid);
2327
+ }
2328
+ });
2329
+ this.scene.update({ delta });
2330
+ }
2331
+ outOfLoop() {
2332
+ this.debugUpdate();
2333
+ }
2334
+ /** Update debug overlays and helpers if enabled. */
2335
+ debugUpdate() {
2336
+ if (debugState.enabled) {
2337
+ this.debugDelegate?.update();
2338
+ }
2339
+ }
2340
+ /** Cleanup owned resources when the stage is destroyed. */
2341
+ _destroy(params) {
2342
+ this._childrenMap.forEach((child) => {
2343
+ try {
2344
+ child.nodeDestroy({ me: child, globals: getGlobals() });
2345
+ } catch {
2346
+ }
2347
+ });
2348
+ this._childrenMap.clear();
2349
+ this._removalMap.clear();
2350
+ this._debugMap.clear();
2351
+ this.world?.destroy();
2352
+ this.scene?.destroy();
2353
+ if (this.debugStateUnsubscribe) {
2354
+ this.debugStateUnsubscribe();
2355
+ this.debugStateUnsubscribe = null;
2356
+ }
2357
+ this.debugDelegate?.dispose();
2358
+ this.debugDelegate = null;
2359
+ this.cameraRef?.setDebugDelegate(null);
2360
+ this.cameraDebugDelegate = null;
2361
+ this.isLoaded = false;
2362
+ this.world = null;
2363
+ this.scene = null;
2364
+ this.cameraRef = null;
2365
+ this.transformSystem?.destroy(this.ecs);
2366
+ this.transformSystem = null;
2367
+ resetStageVariables();
2368
+ clearVariables(this);
2369
+ }
2370
+ /**
2371
+ * Create, register, and add an entity to the scene/world.
2372
+ * Safe to call only after `load` when scene/world exist.
2373
+ */
2374
+ async spawnEntity(child) {
2375
+ if (!this.scene || !this.world) {
2376
+ return;
2377
+ }
2378
+ const entity = child.create();
2379
+ const eid = addEntity(this.ecs);
2380
+ entity.eid = eid;
2381
+ this.scene.addEntity(entity);
2382
+ if (child.behaviors) {
2383
+ for (let behavior of child.behaviors) {
2384
+ addComponent(this.ecs, behavior.component, entity.eid);
2385
+ const keys = Object.keys(behavior.values);
2386
+ for (const key of keys) {
2387
+ behavior.component[key][entity.eid] = behavior.values[key];
2388
+ }
2389
+ }
2390
+ }
2391
+ if (entity.colliderDesc) {
2392
+ this.world.addEntity(entity);
2393
+ }
2394
+ child.nodeSetup({
2395
+ me: child,
2396
+ globals: getGlobals(),
2397
+ camera: this.scene.zylemCamera
2398
+ });
2399
+ this.addEntityToStage(entity);
2400
+ }
2401
+ buildEntityState(child) {
2402
+ if (child instanceof GameEntity) {
2403
+ return { ...child.buildInfo() };
2404
+ }
2405
+ return {
2406
+ uuid: child.uuid,
2407
+ name: child.name,
2408
+ eid: child.eid
2409
+ };
2410
+ }
2411
+ /** Add the entity to internal maps and notify listeners. */
2412
+ addEntityToStage(entity) {
2413
+ this._childrenMap.set(entity.eid, entity);
2414
+ if (debugState.enabled) {
2415
+ this._debugMap.set(entity.uuid, entity);
2416
+ }
2417
+ for (const handler of this.entityAddedHandlers) {
2418
+ try {
2419
+ handler(entity);
2420
+ } catch (e) {
2421
+ console.error("onEntityAdded handler failed", e);
2422
+ }
2423
+ }
2424
+ }
2425
+ /**
2426
+ * Subscribe to entity-added events.
2427
+ * @param callback Invoked for each entity when added
2428
+ * @param options.replayExisting If true and stage already loaded, replays existing entities
2429
+ * @returns Unsubscribe function
2430
+ */
2431
+ onEntityAdded(callback, options) {
2432
+ this.entityAddedHandlers.push(callback);
2433
+ if (options?.replayExisting && this.isLoaded) {
2434
+ this._childrenMap.forEach((entity) => {
2435
+ try {
2436
+ callback(entity);
2437
+ } catch (e) {
2438
+ console.error("onEntityAdded replay failed", e);
2439
+ }
2440
+ });
2441
+ }
2442
+ return () => {
2443
+ this.entityAddedHandlers = this.entityAddedHandlers.filter((h) => h !== callback);
2444
+ };
2445
+ }
2446
+ onLoading(callback) {
2447
+ return this.loadingDelegate.onLoading(callback);
2448
+ }
2449
+ /**
2450
+ * Remove an entity and its resources by its UUID.
2451
+ * @returns true if removed, false if not found or stage not ready
2452
+ */
2453
+ removeEntityByUuid(uuid) {
2454
+ if (!this.scene || !this.world) return false;
2455
+ const mapEntity = this.world.collisionMap.get(uuid);
2456
+ const entity = mapEntity ?? this._debugMap.get(uuid);
2457
+ if (!entity) return false;
2458
+ this.world.destroyEntity(entity);
2459
+ if (entity.group) {
2460
+ this.scene.scene.remove(entity.group);
2461
+ } else if (entity.mesh) {
2462
+ this.scene.scene.remove(entity.mesh);
2463
+ }
2464
+ removeEntity(this.ecs, entity.eid);
2465
+ let foundKey = null;
2466
+ this._childrenMap.forEach((value, key) => {
2467
+ if (value.uuid === uuid) {
2468
+ foundKey = key;
2469
+ }
2470
+ });
2471
+ if (foundKey !== null) {
2472
+ this._childrenMap.delete(foundKey);
2473
+ }
2474
+ this._debugMap.delete(uuid);
2475
+ return true;
2476
+ }
2477
+ /** Get an entity by its name; returns null if not found. */
2478
+ getEntityByName(name) {
2479
+ const arr = Object.entries(Object.fromEntries(this._childrenMap)).map((entry) => entry[1]);
2480
+ const entity = arr.find((child) => child.name === name);
2481
+ if (!entity) {
2482
+ console.warn(`Entity ${name} not found`);
2483
+ }
2484
+ return entity ?? null;
2485
+ }
2486
+ logMissingEntities() {
2487
+ console.warn("Zylem world or scene is null");
2488
+ }
2489
+ /** Resize renderer viewport. */
2490
+ resize(width, height) {
2491
+ if (this.scene) {
2492
+ this.scene.updateRenderer(width, height);
2493
+ }
2494
+ }
2495
+ /**
2496
+ * Enqueue items to be spawned. Items can be:
2497
+ * - BaseNode instances (immediate or deferred until load)
2498
+ * - Factory functions returning BaseNode or Promise<BaseNode>
2499
+ * - Promises resolving to BaseNode
2500
+ */
2501
+ enqueue(...items) {
2502
+ for (const item of items) {
2503
+ if (!item) continue;
2504
+ if (isBaseNode(item)) {
2505
+ this.handleEntityImmediatelyOrQueue(item);
2506
+ continue;
2507
+ }
2508
+ if (typeof item === "function") {
2509
+ try {
2510
+ const result = item();
2511
+ if (isBaseNode(result)) {
2512
+ this.handleEntityImmediatelyOrQueue(result);
2513
+ } else if (isThenable(result)) {
2514
+ this.handlePromiseWithSpawnOnResolve(result);
2515
+ }
2516
+ } catch (error) {
2517
+ console.error("Error executing entity factory", error);
2518
+ }
2519
+ continue;
2520
+ }
2521
+ if (isThenable(item)) {
2522
+ this.handlePromiseWithSpawnOnResolve(item);
2523
+ }
2524
+ }
2525
+ }
2526
+ };
2527
+
2528
+ // src/lib/camera/camera.ts
2529
+ import { Vector2 as Vector26, Vector3 as Vector312 } from "three";
2530
+ var CameraWrapper = class {
2531
+ cameraRef;
2532
+ constructor(camera) {
2533
+ this.cameraRef = camera;
2534
+ }
2535
+ };
2536
+
2537
+ // src/lib/stage/stage-default.ts
2538
+ import { proxy as proxy4 } from "valtio/vanilla";
2539
+ import { Vector3 as Vector313 } from "three";
2540
+ var initialDefaults = {
2541
+ backgroundColor: ZylemBlueColor,
2542
+ backgroundImage: null,
2543
+ inputs: {
2544
+ p1: ["gamepad-1", "keyboard"],
2545
+ p2: ["gamepad-2", "keyboard"]
2546
+ },
2547
+ gravity: new Vector313(0, 0, 0),
2548
+ variables: {}
2549
+ };
2550
+ var stageDefaultsState = proxy4({
2551
+ ...initialDefaults
2552
+ });
2553
+ function getStageOptions(options) {
2554
+ const defaults = getStageDefaultConfig();
2555
+ let originalConfig = {};
2556
+ if (typeof options[0] === "object") {
2557
+ originalConfig = options.shift() ?? {};
2558
+ }
2559
+ const combinedConfig = { ...defaults, ...originalConfig };
2560
+ return [combinedConfig, ...options];
2561
+ }
2562
+ function getStageDefaultConfig() {
2563
+ return {
2564
+ backgroundColor: stageDefaultsState.backgroundColor,
2565
+ backgroundImage: stageDefaultsState.backgroundImage ?? null,
2566
+ inputs: stageDefaultsState.inputs ? { ...stageDefaultsState.inputs } : void 0,
2567
+ gravity: stageDefaultsState.gravity,
2568
+ variables: stageDefaultsState.variables ? { ...stageDefaultsState.variables } : void 0
2569
+ };
2570
+ }
2571
+
2572
+ // src/lib/stage/stage.ts
2573
+ var Stage = class {
2574
+ wrappedStage;
2575
+ options = [];
2576
+ // Entities added after construction, consumed on each load
2577
+ _pendingEntities = [];
2578
+ // Lifecycle callback arrays
2579
+ setupCallbacks = [];
2580
+ updateCallbacks = [];
2581
+ destroyCallbacks = [];
2582
+ pendingLoadingCallbacks = [];
2583
+ constructor(options) {
2584
+ this.options = options;
2585
+ this.wrappedStage = null;
2586
+ }
2587
+ async load(id, camera) {
2588
+ stageState.entities = [];
2589
+ const loadOptions = [...this.options, ...this._pendingEntities];
2590
+ this._pendingEntities = [];
2591
+ this.wrappedStage = new ZylemStage(loadOptions);
2592
+ this.wrappedStage.wrapperRef = this;
2593
+ this.pendingLoadingCallbacks.forEach((cb) => {
2594
+ this.wrappedStage.onLoading(cb);
2595
+ });
2596
+ this.pendingLoadingCallbacks = [];
2597
+ const zylemCamera = camera instanceof CameraWrapper ? camera.cameraRef : camera;
2598
+ await this.wrappedStage.load(id, zylemCamera);
2599
+ this.wrappedStage.onEntityAdded((child) => {
2600
+ const next = this.wrappedStage.buildEntityState(child);
2601
+ stageState.entities = [...stageState.entities, next];
2602
+ }, { replayExisting: true });
2603
+ this.applyLifecycleCallbacks();
2604
+ }
2605
+ applyLifecycleCallbacks() {
2606
+ if (!this.wrappedStage) return;
2607
+ if (this.setupCallbacks.length > 0) {
2608
+ this.wrappedStage.setup = (params) => {
2609
+ const extended = { ...params, stage: this };
2610
+ this.setupCallbacks.forEach((cb) => cb(extended));
2611
+ };
2612
+ }
2613
+ if (this.updateCallbacks.length > 0) {
2614
+ this.wrappedStage.update = (params) => {
2615
+ const extended = { ...params, stage: this };
2616
+ this.updateCallbacks.forEach((cb) => cb(extended));
2617
+ };
2618
+ }
2619
+ if (this.destroyCallbacks.length > 0) {
2620
+ this.wrappedStage.destroy = (params) => {
2621
+ const extended = { ...params, stage: this };
2622
+ this.destroyCallbacks.forEach((cb) => cb(extended));
2623
+ };
2624
+ }
2625
+ }
2626
+ async addEntities(entities) {
2627
+ this._pendingEntities.push(...entities);
2628
+ if (!this.wrappedStage) {
2629
+ return;
2630
+ }
2631
+ this.wrappedStage.enqueue(...entities);
2632
+ }
2633
+ add(...inputs) {
2634
+ this.addToBlueprints(...inputs);
2635
+ this.addToStage(...inputs);
2636
+ }
2637
+ addToBlueprints(...inputs) {
2638
+ if (this.wrappedStage) {
2639
+ return;
2640
+ }
2641
+ this.options.push(...inputs);
2642
+ }
2643
+ addToStage(...inputs) {
2644
+ if (!this.wrappedStage) {
2645
+ return;
2646
+ }
2647
+ this.wrappedStage.enqueue(...inputs);
2648
+ }
2649
+ start(params) {
2650
+ this.wrappedStage?.nodeSetup(params);
2651
+ }
2652
+ // Fluent API for adding lifecycle callbacks
2653
+ onUpdate(...callbacks) {
2654
+ this.updateCallbacks.push(...callbacks);
2655
+ if (this.wrappedStage) {
2656
+ this.wrappedStage.update = (params) => {
2657
+ const extended = { ...params, stage: this };
2658
+ this.updateCallbacks.forEach((cb) => cb(extended));
2659
+ };
2660
+ }
2661
+ return this;
2662
+ }
2663
+ onSetup(...callbacks) {
2664
+ this.setupCallbacks.push(...callbacks);
2665
+ if (this.wrappedStage) {
2666
+ this.wrappedStage.setup = (params) => {
2667
+ const extended = { ...params, stage: this };
2668
+ this.setupCallbacks.forEach((cb) => cb(extended));
2669
+ };
2670
+ }
2671
+ return this;
2672
+ }
2673
+ onDestroy(...callbacks) {
2674
+ this.destroyCallbacks.push(...callbacks);
2675
+ if (this.wrappedStage) {
2676
+ this.wrappedStage.destroy = (params) => {
2677
+ const extended = { ...params, stage: this };
2678
+ this.destroyCallbacks.forEach((cb) => cb(extended));
2679
+ };
2680
+ }
2681
+ return this;
2682
+ }
2683
+ onLoading(callback) {
2684
+ if (!this.wrappedStage) {
2685
+ this.pendingLoadingCallbacks.push(callback);
2686
+ return () => {
2687
+ this.pendingLoadingCallbacks = this.pendingLoadingCallbacks.filter((c) => c !== callback);
2688
+ };
2689
+ }
2690
+ return this.wrappedStage.onLoading(callback);
2691
+ }
2692
+ /**
2693
+ * Find an entity by name on the current stage.
2694
+ * @param name The name of the entity to find
2695
+ * @param type Optional type symbol for type inference (e.g., TEXT_TYPE, SPRITE_TYPE)
2696
+ * @returns The entity if found, or undefined
2697
+ * @example stage.getEntityByName('scoreText', TEXT_TYPE)
2698
+ */
2699
+ getEntityByName(name, type) {
2700
+ const entity = this.wrappedStage?.children.find((c) => c.name === name);
2701
+ return entity;
2702
+ }
2703
+ };
2704
+ function createStage(...options) {
2705
+ const _options = getStageOptions(options);
2706
+ return new Stage([..._options]);
2707
+ }
2708
+
2709
+ // src/lib/stage/entity-spawner.ts
2710
+ import { Euler, Quaternion as Quaternion3, Vector2 as Vector27 } from "three";
2711
+ function entitySpawner(factory) {
2712
+ return {
2713
+ spawn: async (stage, x, y) => {
2714
+ const instance = await Promise.resolve(factory(x, y));
2715
+ stage.add(instance);
2716
+ return instance;
2717
+ },
2718
+ spawnRelative: async (source, stage, offset = new Vector27(0, 1)) => {
2719
+ if (!source.body) {
2720
+ console.warn("body missing for entity during spawnRelative");
2721
+ return void 0;
2722
+ }
2723
+ const { x, y, z } = source.body.translation();
2724
+ let rz = source._rotation2DAngle ?? 0;
2725
+ try {
2726
+ const r = source.body.rotation();
2727
+ const q = new Quaternion3(r.x, r.y, r.z, r.w);
2728
+ const e = new Euler().setFromQuaternion(q, "XYZ");
2729
+ rz = e.z;
2730
+ } catch {
2731
+ }
2732
+ const offsetX = Math.sin(-rz) * (offset.x ?? 0);
2733
+ const offsetY = Math.cos(-rz) * (offset.y ?? 0);
2734
+ const instance = await Promise.resolve(factory(x + offsetX, y + offsetY));
2735
+ stage.add(instance);
2736
+ return instance;
2737
+ }
2738
+ };
2739
+ }
2740
+
2741
+ // src/lib/stage/stage-events.ts
2742
+ import { subscribe as subscribe5 } from "valtio/vanilla";
2743
+ var STAGE_STATE_CHANGE = "STAGE_STATE_CHANGE";
2744
+ function initStageStateDispatcher() {
2745
+ return subscribe5(stageState, () => {
2746
+ const detail = {
2747
+ entities: stageState.entities,
2748
+ variables: stageState.variables
2749
+ };
2750
+ window.dispatchEvent(new CustomEvent(STAGE_STATE_CHANGE, { detail }));
2751
+ });
2752
+ }
2753
+ function dispatchStageState() {
2754
+ const detail = {
2755
+ entities: stageState.entities,
2756
+ variables: stageState.variables
2757
+ };
2758
+ window.dispatchEvent(new CustomEvent(STAGE_STATE_CHANGE, { detail }));
2759
+ }
3
2760
  export {
4
- t as createStage,
5
- a as entitySpawner
2761
+ STAGE_STATE_CHANGE,
2762
+ createStage,
2763
+ dispatchStageState,
2764
+ entitySpawner,
2765
+ initStageStateDispatcher
6
2766
  };
2767
+ //# sourceMappingURL=stage.js.map