@relu-interactives/spatial-ecs 0.2.2

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 (308) hide show
  1. package/README.md +125 -0
  2. package/dist/System-rXAmagXA.d.cts +659 -0
  3. package/dist/System-rXAmagXA.d.ts +659 -0
  4. package/dist/Video-CDemv74U.d.cts +1261 -0
  5. package/dist/Video-ChKV1UI7.d.ts +1261 -0
  6. package/dist/assets/draco/draco_decoder.js +34 -0
  7. package/dist/assets/draco/draco_decoder.wasm +0 -0
  8. package/dist/assets/draco/draco_wasm_wrapper.js +117 -0
  9. package/dist/chunk-AYEF3X2P.js +223 -0
  10. package/dist/chunk-AYEF3X2P.js.map +1 -0
  11. package/dist/chunk-MAWBTMCG.js +1722 -0
  12. package/dist/chunk-MAWBTMCG.js.map +1 -0
  13. package/dist/chunk-NFDTIYR4.js +248 -0
  14. package/dist/chunk-NFDTIYR4.js.map +1 -0
  15. package/dist/chunk-OY7ZODZP.js +16 -0
  16. package/dist/chunk-OY7ZODZP.js.map +1 -0
  17. package/dist/chunk-P2YDX5DB.js +3304 -0
  18. package/dist/chunk-P2YDX5DB.js.map +1 -0
  19. package/dist/chunk-QHILSPT4.js +3 -0
  20. package/dist/chunk-QHILSPT4.js.map +1 -0
  21. package/dist/chunk-XWIEEJ7Z.js +1315 -0
  22. package/dist/chunk-XWIEEJ7Z.js.map +1 -0
  23. package/dist/components/index.cjs +1745 -0
  24. package/dist/components/index.cjs.map +1 -0
  25. package/dist/components/index.d.cts +4 -0
  26. package/dist/components/index.d.ts +4 -0
  27. package/dist/components/index.js +4 -0
  28. package/dist/components/index.js.map +1 -0
  29. package/dist/docs/api/Behaviour/classes/Behaviour.md +554 -0
  30. package/dist/docs/api/Behaviour/index.md +15 -0
  31. package/dist/docs/api/Component/classes/Component.md +57 -0
  32. package/dist/docs/api/Component/index.md +15 -0
  33. package/dist/docs/api/components/classes/AnimationComponent.md +318 -0
  34. package/dist/docs/api/components/classes/AudioComponent.md +114 -0
  35. package/dist/docs/api/components/classes/CameraComponent.md +59 -0
  36. package/dist/docs/api/components/classes/EntityType.md +48 -0
  37. package/dist/docs/api/components/classes/Environment.md +47 -0
  38. package/dist/docs/api/components/classes/ImageComponent.md +57 -0
  39. package/dist/docs/api/components/classes/ImageTarget.md +60 -0
  40. package/dist/docs/api/components/classes/ImageTargetAnchor.md +48 -0
  41. package/dist/docs/api/components/classes/LightComponent.md +70 -0
  42. package/dist/docs/api/components/classes/MaterialComponent.md +181 -0
  43. package/dist/docs/api/components/classes/MeshComponent.md +48 -0
  44. package/dist/docs/api/components/classes/MeshGeometryComponent.md +64 -0
  45. package/dist/docs/api/components/classes/ModelComponent.md +49 -0
  46. package/dist/docs/api/components/classes/Name.md +46 -0
  47. package/dist/docs/api/components/classes/Object3DRef.md +54 -0
  48. package/dist/docs/api/components/classes/ParentId.md +47 -0
  49. package/dist/docs/api/components/classes/PhysicsComponent.md +82 -0
  50. package/dist/docs/api/components/classes/Postprocessing.md +49 -0
  51. package/dist/docs/api/components/classes/ScriptComponent.md +54 -0
  52. package/dist/docs/api/components/classes/Selectable.md +46 -0
  53. package/dist/docs/api/components/classes/SelectionTransformState.md +54 -0
  54. package/dist/docs/api/components/classes/SpriteComponent.md +55 -0
  55. package/dist/docs/api/components/classes/TransformComponent.md +197 -0
  56. package/dist/docs/api/components/classes/VideoComponent.md +123 -0
  57. package/dist/docs/api/components/functions/normalizePhysicsState.md +23 -0
  58. package/dist/docs/api/components/index.md +94 -0
  59. package/dist/docs/api/components/type-aliases/AnimationComponentOptions.md +42 -0
  60. package/dist/docs/api/components/type-aliases/CameraComponentOptions.md +45 -0
  61. package/dist/docs/api/components/type-aliases/CameraProjection.md +15 -0
  62. package/dist/docs/api/components/type-aliases/CameraRuntimeType.md +15 -0
  63. package/dist/docs/api/components/type-aliases/ColliderShape.md +15 -0
  64. package/dist/docs/api/components/type-aliases/ColliderState.md +62 -0
  65. package/dist/docs/api/components/type-aliases/CubeMeshParameters.md +27 -0
  66. package/dist/docs/api/components/type-aliases/EditableMeshObjectKind.md +15 -0
  67. package/dist/docs/api/components/type-aliases/EnvironmentFogState.md +37 -0
  68. package/dist/docs/api/components/type-aliases/EnvironmentFogType.md +15 -0
  69. package/dist/docs/api/components/type-aliases/EnvironmentGradientEffect.md +15 -0
  70. package/dist/docs/api/components/type-aliases/EnvironmentSkyboxState.md +34 -0
  71. package/dist/docs/api/components/type-aliases/EnvironmentSkyboxType.md +15 -0
  72. package/dist/docs/api/components/type-aliases/EnvironmentState.md +29 -0
  73. package/dist/docs/api/components/type-aliases/ImageTargetAnchorOptions.md +25 -0
  74. package/dist/docs/api/components/type-aliases/ImageTargetReference.md +33 -0
  75. package/dist/docs/api/components/type-aliases/LightValueState.md +41 -0
  76. package/dist/docs/api/components/type-aliases/MaterialTypeValue.md +15 -0
  77. package/dist/docs/api/components/type-aliases/MaterialValueState.md +75 -0
  78. package/dist/docs/api/components/type-aliases/MeshGeometryParameters.md +13 -0
  79. package/dist/docs/api/components/type-aliases/MeshGeometryParametersByKind.md +33 -0
  80. package/dist/docs/api/components/type-aliases/PhysicsState.md +25 -0
  81. package/dist/docs/api/components/type-aliases/PlaneMeshParameters.md +25 -0
  82. package/dist/docs/api/components/type-aliases/PostprocessingState.md +164 -0
  83. package/dist/docs/api/components/type-aliases/RadiusHeightMeshParameters.md +25 -0
  84. package/dist/docs/api/components/type-aliases/RadiusMeshParameters.md +23 -0
  85. package/dist/docs/api/components/type-aliases/RigidbodyState.md +53 -0
  86. package/dist/docs/api/components/type-aliases/RigidbodyType.md +19 -0
  87. package/dist/docs/api/components/type-aliases/ScriptEntry.md +38 -0
  88. package/dist/docs/api/components/type-aliases/TextureFilteringValue.md +15 -0
  89. package/dist/docs/api/components/type-aliases/TransformData.md +27 -0
  90. package/dist/docs/api/components/type-aliases/TransformModeValue.md +15 -0
  91. package/dist/docs/api/components/type-aliases/TransformSpaceValue.md +15 -0
  92. package/dist/docs/api/components/type-aliases/Vec3.md +27 -0
  93. package/dist/docs/api/components/variables/DEFAULT_COLLIDER_STATE.md +13 -0
  94. package/dist/docs/api/components/variables/DEFAULT_ENVIRONMENT_STATE.md +13 -0
  95. package/dist/docs/api/components/variables/DEFAULT_MESH_GEOMETRY_PARAMETERS.md +13 -0
  96. package/dist/docs/api/components/variables/DEFAULT_PHYSICS_STATE.md +13 -0
  97. package/dist/docs/api/components/variables/DEFAULT_POSTPROCESSING_STATE.md +13 -0
  98. package/dist/docs/api/components/variables/DEFAULT_RIGIDBODY_STATE.md +13 -0
  99. package/dist/docs/api/index/classes/AnimationStateMachine.md +201 -0
  100. package/dist/docs/api/index/classes/AnimationStateManager.md +253 -0
  101. package/dist/docs/api/index/classes/AnimationSystem.md +68 -0
  102. package/dist/docs/api/index/classes/AudioSystem.md +98 -0
  103. package/dist/docs/api/index/classes/CameraSyncSystem.md +49 -0
  104. package/dist/docs/api/index/classes/EnvironmentSyncSystem.md +75 -0
  105. package/dist/docs/api/index/classes/InputSystem.md +449 -0
  106. package/dist/docs/api/index/classes/LightSyncSystem.md +49 -0
  107. package/dist/docs/api/index/classes/MaterialSyncSystem.md +67 -0
  108. package/dist/docs/api/index/classes/MeshGeometrySystem.md +49 -0
  109. package/dist/docs/api/index/classes/ObjectManagementSystem.md +298 -0
  110. package/dist/docs/api/index/classes/ObjectVisibilitySystem.md +49 -0
  111. package/dist/docs/api/index/classes/PhysicsSyncSystem.md +83 -0
  112. package/dist/docs/api/index/classes/PostprocessingSyncSystem.md +80 -0
  113. package/dist/docs/api/index/classes/RenderSystem.md +64 -0
  114. package/dist/docs/api/index/classes/ScriptBehaviourSystem.md +83 -0
  115. package/dist/docs/api/index/classes/TransformSyncSystem.md +49 -0
  116. package/dist/docs/api/index/classes/VideoSystem.md +97 -0
  117. package/dist/docs/api/index/classes/World.md +1405 -0
  118. package/dist/docs/api/index/functions/createAnimationComponent.md +28 -0
  119. package/dist/docs/api/index/functions/createAudioComponent.md +32 -0
  120. package/dist/docs/api/index/functions/createCameraComponent.md +28 -0
  121. package/dist/docs/api/index/functions/createEntityTypeComponent.md +28 -0
  122. package/dist/docs/api/index/functions/createEnvironmentComponent.md +28 -0
  123. package/dist/docs/api/index/functions/createImageComponent.md +28 -0
  124. package/dist/docs/api/index/functions/createImageTargetAnchorComponent.md +28 -0
  125. package/dist/docs/api/index/functions/createImageTargetComponent.md +28 -0
  126. package/dist/docs/api/index/functions/createLightComponent.md +28 -0
  127. package/dist/docs/api/index/functions/createMaterialComponent.md +28 -0
  128. package/dist/docs/api/index/functions/createMeshComponent.md +28 -0
  129. package/dist/docs/api/index/functions/createMeshGeometryComponent.md +28 -0
  130. package/dist/docs/api/index/functions/createModelComponent.md +28 -0
  131. package/dist/docs/api/index/functions/createNameComponent.md +28 -0
  132. package/dist/docs/api/index/functions/createObject3DRefComponent.md +28 -0
  133. package/dist/docs/api/index/functions/createParentIdComponent.md +28 -0
  134. package/dist/docs/api/index/functions/createPhysicsComponent.md +30 -0
  135. package/dist/docs/api/index/functions/createPostprocessingComponent.md +28 -0
  136. package/dist/docs/api/index/functions/createScriptComponent.md +28 -0
  137. package/dist/docs/api/index/functions/createSelectableComponent.md +28 -0
  138. package/dist/docs/api/index/functions/createSelectionTransformStateComponent.md +28 -0
  139. package/dist/docs/api/index/functions/createSpriteComponent.md +28 -0
  140. package/dist/docs/api/index/functions/createTransformComponent.md +28 -0
  141. package/dist/docs/api/index/functions/createVideoComponent.md +28 -0
  142. package/dist/docs/api/index/functions/hydrateWorldFromSnapshot.md +28 -0
  143. package/dist/docs/api/index/functions/hydrateWorldFromSnapshotDetailed.md +28 -0
  144. package/dist/docs/api/index/functions/registerDefaultComponentFactories.md +23 -0
  145. package/dist/docs/api/index/functions/registerDefaultFactories.md +23 -0
  146. package/dist/docs/api/index/index.md +249 -0
  147. package/dist/docs/api/index/interfaces/EcsSystem.md +50 -0
  148. package/dist/docs/api/index/interfaces/StateMachine.md +26 -0
  149. package/dist/docs/api/index/type-aliases/AnimationStateCallbacks.md +25 -0
  150. package/dist/docs/api/index/type-aliases/ComponentFactory.md +25 -0
  151. package/dist/docs/api/index/type-aliases/EcsComponentFactoryKind.md +37 -0
  152. package/dist/docs/api/index/type-aliases/EcsWorldComponentSnapshot.md +26 -0
  153. package/dist/docs/api/index/type-aliases/EcsWorldStateSnapshotLike.md +25 -0
  154. package/dist/docs/api/index/type-aliases/HydrateWorldFromSnapshotResult.md +23 -0
  155. package/dist/docs/api/index/type-aliases/KeyboardKey.md +13 -0
  156. package/dist/docs/api/index/type-aliases/MouseButton.md +13 -0
  157. package/dist/docs/api/index/type-aliases/SelectionContext.md +31 -0
  158. package/dist/docs/api/index/variables/HYDRATABLE_ENTITY_KINDS.md +13 -0
  159. package/dist/docs/api/index/variables/KeyboardKeys.md +195 -0
  160. package/dist/docs/api/index.md +15 -0
  161. package/dist/docs/api/typedoc-sidebar.json +1 -0
  162. package/dist/docs/api/types/index.md +34 -0
  163. package/dist/docs/api/types/type-aliases/AssetInput.md +23 -0
  164. package/dist/docs/api/types/type-aliases/CheckboxInput.md +13 -0
  165. package/dist/docs/api/types/type-aliases/ColorInput.md +13 -0
  166. package/dist/docs/api/types/type-aliases/ComponentInput.md +52 -0
  167. package/dist/docs/api/types/type-aliases/ComponentKind.md +37 -0
  168. package/dist/docs/api/types/type-aliases/DropdownInput.md +23 -0
  169. package/dist/docs/api/types/type-aliases/DropdownOption.md +23 -0
  170. package/dist/docs/api/types/type-aliases/EcsEntityEditorKind.md +15 -0
  171. package/dist/docs/api/types/type-aliases/EcsEntityKind.md +35 -0
  172. package/dist/docs/api/types/type-aliases/EntityId.md +16 -0
  173. package/dist/docs/api/types/type-aliases/EntityInput.md +23 -0
  174. package/dist/docs/api/types/type-aliases/FloatInput.md +13 -0
  175. package/dist/docs/api/types/type-aliases/IntersectionResult.md +29 -0
  176. package/dist/docs/api/types/type-aliases/ParentLookup.md +26 -0
  177. package/dist/docs/api/types/type-aliases/SelectionListener.md +25 -0
  178. package/dist/docs/api/types/type-aliases/SliderInput.md +27 -0
  179. package/dist/docs/api/types/type-aliases/TextInput.md +13 -0
  180. package/dist/docs/api/types/type-aliases/ToggleInput.md +13 -0
  181. package/dist/docs/api/types/type-aliases/Vec3.md +23 -0
  182. package/dist/docs/api/types/type-aliases/Vector2Input.md +23 -0
  183. package/dist/docs/api/types/type-aliases/Vector3Input.md +25 -0
  184. package/dist/docs/api/types/type-aliases/WorldEntityView.md +17 -0
  185. package/dist/docs/guide/accessing-components.md +399 -0
  186. package/dist/docs/guide/authoring-a-behaviour.md +166 -0
  187. package/dist/docs/guide/behaviour-lifecycle.md +43 -0
  188. package/dist/docs/guide/component-catalog.md +59 -0
  189. package/dist/docs/guide/components/_sidebar.json +78 -0
  190. package/dist/docs/guide/components/animation.md +171 -0
  191. package/dist/docs/guide/components/audio.md +181 -0
  192. package/dist/docs/guide/components/camera.md +179 -0
  193. package/dist/docs/guide/components/entity-type.md +141 -0
  194. package/dist/docs/guide/components/image-target-anchor.md +103 -0
  195. package/dist/docs/guide/components/image-target.md +122 -0
  196. package/dist/docs/guide/components/image.md +146 -0
  197. package/dist/docs/guide/components/light.md +157 -0
  198. package/dist/docs/guide/components/material.md +161 -0
  199. package/dist/docs/guide/components/mesh-geometry.md +153 -0
  200. package/dist/docs/guide/components/mesh.md +151 -0
  201. package/dist/docs/guide/components/model.md +96 -0
  202. package/dist/docs/guide/components/name.md +121 -0
  203. package/dist/docs/guide/components/object3d-ref.md +115 -0
  204. package/dist/docs/guide/components/parent-id.md +108 -0
  205. package/dist/docs/guide/components/physics.md +163 -0
  206. package/dist/docs/guide/components/script.md +142 -0
  207. package/dist/docs/guide/components/sprite.md +155 -0
  208. package/dist/docs/guide/components/transform.md +155 -0
  209. package/dist/docs/guide/components/video.md +153 -0
  210. package/dist/docs/guide/concepts.md +34 -0
  211. package/dist/docs/guide/getting-started/creating-objects.md +50 -0
  212. package/dist/docs/guide/getting-started/editing-objects.md +62 -0
  213. package/dist/docs/guide/getting-started/editor/assets-browser.md +55 -0
  214. package/dist/docs/guide/getting-started/editor/hierarchy.md +47 -0
  215. package/dist/docs/guide/getting-started/editor/index.md +16 -0
  216. package/dist/docs/guide/getting-started/editor/inspector.md +36 -0
  217. package/dist/docs/guide/getting-started/editor/modules.md +35 -0
  218. package/dist/docs/guide/getting-started/editor/scene-inspector.md +64 -0
  219. package/dist/docs/guide/getting-started/editor/toolbar.md +39 -0
  220. package/dist/docs/guide/getting-started/editor/viewport.md +43 -0
  221. package/dist/docs/guide/getting-started/first-launch.md +17 -0
  222. package/dist/docs/guide/getting-started/index.md +37 -0
  223. package/dist/docs/guide/getting-started/installation.md +59 -0
  224. package/dist/docs/guide/getting-started/preview-and-test.md +55 -0
  225. package/dist/docs/guide/getting-started/project-types/3d.md +30 -0
  226. package/dist/docs/guide/getting-started/project-types/ar.md +6 -0
  227. package/dist/docs/guide/getting-started/project-types/face-tracking.md +6 -0
  228. package/dist/docs/guide/getting-started/project-types/image-tracking.md +42 -0
  229. package/dist/docs/guide/getting-started/project-types/index.md +25 -0
  230. package/dist/docs/guide/getting-started/project-types/vr.md +6 -0
  231. package/dist/docs/guide/getting-started/projects.md +53 -0
  232. package/dist/docs/guide/getting-started/shortcuts.md +43 -0
  233. package/dist/docs/guide/inspector-data-binding.md +367 -0
  234. package/dist/docs/guide/reading-input.md +202 -0
  235. package/dist/docs/guide/scene/environment.md +101 -0
  236. package/dist/docs/guide/scene/index.md +36 -0
  237. package/dist/docs/guide/scene/postprocessing.md +108 -0
  238. package/dist/docs/guide/spawning/ambient-light.md +28 -0
  239. package/dist/docs/guide/spawning/area-light.md +32 -0
  240. package/dist/docs/guide/spawning/audio.md +42 -0
  241. package/dist/docs/guide/spawning/camera.md +50 -0
  242. package/dist/docs/guide/spawning/capsule.md +29 -0
  243. package/dist/docs/guide/spawning/cube.md +31 -0
  244. package/dist/docs/guide/spawning/cylinder.md +29 -0
  245. package/dist/docs/guide/spawning/directional-light.md +32 -0
  246. package/dist/docs/guide/spawning/empty.md +31 -0
  247. package/dist/docs/guide/spawning/image-target.md +48 -0
  248. package/dist/docs/guide/spawning/image.md +33 -0
  249. package/dist/docs/guide/spawning/index.md +79 -0
  250. package/dist/docs/guide/spawning/model.md +31 -0
  251. package/dist/docs/guide/spawning/plane.md +31 -0
  252. package/dist/docs/guide/spawning/point-light.md +32 -0
  253. package/dist/docs/guide/spawning/sphere.md +29 -0
  254. package/dist/docs/guide/spawning/spot-light.md +32 -0
  255. package/dist/docs/guide/spawning/sprite.md +31 -0
  256. package/dist/docs/guide/spawning/video.md +53 -0
  257. package/dist/docs/guide/system-overview.md +73 -0
  258. package/dist/docs/guide/systems/_sidebar.json +66 -0
  259. package/dist/docs/guide/systems/animation-system.md +32 -0
  260. package/dist/docs/guide/systems/audio-system.md +28 -0
  261. package/dist/docs/guide/systems/camera-sync-system.md +31 -0
  262. package/dist/docs/guide/systems/environment-sync-system.md +31 -0
  263. package/dist/docs/guide/systems/input-system.md +217 -0
  264. package/dist/docs/guide/systems/light-sync-system.md +29 -0
  265. package/dist/docs/guide/systems/material-sync-system.md +32 -0
  266. package/dist/docs/guide/systems/mesh-geometry-system.md +40 -0
  267. package/dist/docs/guide/systems/object-management-system.md +38 -0
  268. package/dist/docs/guide/systems/object-visibility-system.md +26 -0
  269. package/dist/docs/guide/systems/physics-sync-system.md +56 -0
  270. package/dist/docs/guide/systems/postprocessing-sync-system.md +43 -0
  271. package/dist/docs/guide/systems/render-system.md +22 -0
  272. package/dist/docs/guide/systems/script-behaviour-system.md +59 -0
  273. package/dist/docs/guide/systems/transform-sync-system.md +29 -0
  274. package/dist/docs/guide/systems/video-system.md +30 -0
  275. package/dist/docs/guide/world-api.md +405 -0
  276. package/dist/factories/index.cjs +3077 -0
  277. package/dist/factories/index.cjs.map +1 -0
  278. package/dist/factories/index.d.cts +69 -0
  279. package/dist/factories/index.d.ts +69 -0
  280. package/dist/factories/index.js +6 -0
  281. package/dist/factories/index.js.map +1 -0
  282. package/dist/index-B4-YyUNR.d.cts +73 -0
  283. package/dist/index-BZUOKeTO.d.ts +73 -0
  284. package/dist/index.cjs +8584 -0
  285. package/dist/index.cjs.map +1 -0
  286. package/dist/index.d.cts +283 -0
  287. package/dist/index.d.ts +283 -0
  288. package/dist/index.js +1729 -0
  289. package/dist/index.js.map +1 -0
  290. package/dist/systems/index.cjs +5119 -0
  291. package/dist/systems/index.cjs.map +1 -0
  292. package/dist/systems/index.d.cts +200 -0
  293. package/dist/systems/index.d.ts +200 -0
  294. package/dist/systems/index.js +6 -0
  295. package/dist/systems/index.js.map +1 -0
  296. package/dist/types.cjs +4 -0
  297. package/dist/types.cjs.map +1 -0
  298. package/dist/types.d.cts +3 -0
  299. package/dist/types.d.ts +3 -0
  300. package/dist/types.js +3 -0
  301. package/dist/types.js.map +1 -0
  302. package/dist/worldSnapshotUtils.cjs +259 -0
  303. package/dist/worldSnapshotUtils.cjs.map +1 -0
  304. package/dist/worldSnapshotUtils.d.cts +3 -0
  305. package/dist/worldSnapshotUtils.d.ts +3 -0
  306. package/dist/worldSnapshotUtils.js +4 -0
  307. package/dist/worldSnapshotUtils.js.map +1 -0
  308. package/package.json +80 -0
@@ -0,0 +1,3304 @@
1
+ import { resolveDracoDecoderPath, applyTransform } from './chunk-AYEF3X2P.js';
2
+ import { AnimationComponent, ModelComponent, CameraComponent, Object3DRef, Environment, Postprocessing, TransformComponent, PhysicsComponent, LightComponent, MaterialComponent, DEFAULT_MESH_GEOMETRY_PARAMETERS, MeshGeometryComponent, ParentId, ScriptComponent, AudioComponent, VideoComponent } from './chunk-MAWBTMCG.js';
3
+ import { __name } from './chunk-OY7ZODZP.js';
4
+ import * as THREE7 from 'three';
5
+ import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
6
+ import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js';
7
+ import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
8
+ import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
9
+ import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
10
+ import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass.js';
11
+ import { DotScreenPass } from 'three/examples/jsm/postprocessing/DotScreenPass.js';
12
+ import { GlitchPass } from 'three/examples/jsm/postprocessing/GlitchPass.js';
13
+ import { FilmPass } from 'three/examples/jsm/postprocessing/FilmPass.js';
14
+ import { BokehPass } from 'three/examples/jsm/postprocessing/BokehPass.js';
15
+ import { SSAOPass } from 'three/examples/jsm/postprocessing/SSAOPass.js';
16
+ import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
17
+ import { OutputPass } from 'three/examples/jsm/postprocessing/OutputPass.js';
18
+ import { HueSaturationShader } from 'three/examples/jsm/shaders/HueSaturationShader.js';
19
+ import { SepiaShader } from 'three/examples/jsm/shaders/SepiaShader.js';
20
+ import { VignetteShader } from 'three/examples/jsm/shaders/VignetteShader.js';
21
+
22
+ function createClipSourceLoader() {
23
+ const loader = new GLTFLoader();
24
+ try {
25
+ const dracoLoader = new DRACOLoader();
26
+ dracoLoader.setDecoderPath(resolveDracoDecoderPath());
27
+ loader.setDRACOLoader(dracoLoader);
28
+ } catch (error) {
29
+ console.warn("DRACOLoader could not be configured for clip source loading.", error);
30
+ }
31
+ return loader;
32
+ }
33
+ __name(createClipSourceLoader, "createClipSourceLoader");
34
+ function normalizeDeltaTime(deltaTime) {
35
+ return Number.isFinite(deltaTime) ? Math.max(0, deltaTime) : 0;
36
+ }
37
+ __name(normalizeDeltaTime, "normalizeDeltaTime");
38
+ function sanitizeTimeScale(timeScale) {
39
+ if (!Number.isFinite(timeScale) || Math.abs(timeScale) < 1e-4) {
40
+ return 1;
41
+ }
42
+ return Math.abs(timeScale);
43
+ }
44
+ __name(sanitizeTimeScale, "sanitizeTimeScale");
45
+ function sanitizeCrossFadeDuration(duration) {
46
+ if (!Number.isFinite(duration) || duration < 0) {
47
+ return 0;
48
+ }
49
+ return duration;
50
+ }
51
+ __name(sanitizeCrossFadeDuration, "sanitizeCrossFadeDuration");
52
+ function buildClipSignature(entries) {
53
+ return entries.map((entry) => entry.id).sort((a, b) => a.localeCompare(b)).join("|");
54
+ }
55
+ __name(buildClipSignature, "buildClipSignature");
56
+ function readRuntimeClipEntries(animation) {
57
+ if (Array.isArray(animation.clipCatalog) && animation.clipCatalog.length > 0) {
58
+ return animation.clipCatalog.map((entry) => ({
59
+ id: entry.id,
60
+ name: entry.name,
61
+ clip: entry.clip
62
+ }));
63
+ }
64
+ if (!Array.isArray(animation.clips)) {
65
+ return [];
66
+ }
67
+ return animation.clips.map((clip, index) => {
68
+ const name = typeof clip?.name === "string" ? clip.name : "";
69
+ if (!name) {
70
+ return null;
71
+ }
72
+ return {
73
+ id: `legacy:${index}:${name}`,
74
+ name,
75
+ clip
76
+ };
77
+ }).filter((entry) => entry !== null);
78
+ }
79
+ __name(readRuntimeClipEntries, "readRuntimeClipEntries");
80
+ function normalizeClipSources(value) {
81
+ if (!Array.isArray(value)) {
82
+ return [];
83
+ }
84
+ const seen = /* @__PURE__ */ new Set();
85
+ const sources = [];
86
+ for (const entry of value) {
87
+ if (typeof entry !== "string") {
88
+ continue;
89
+ }
90
+ const trimmed = entry.trim();
91
+ if (!trimmed || seen.has(trimmed)) {
92
+ continue;
93
+ }
94
+ seen.add(trimmed);
95
+ sources.push(trimmed);
96
+ }
97
+ return sources;
98
+ }
99
+ __name(normalizeClipSources, "normalizeClipSources");
100
+ function extractFileExtension(url) {
101
+ const clean = url.split("?")[0]?.split("#")[0] ?? "";
102
+ const ext = clean.split(".").pop();
103
+ return typeof ext === "string" ? ext.toLowerCase() : "";
104
+ }
105
+ __name(extractFileExtension, "extractFileExtension");
106
+ function createActions(mixer, entries) {
107
+ const actions = /* @__PURE__ */ new Map();
108
+ const clipNameToIds = /* @__PURE__ */ new Map();
109
+ for (const entry of entries) {
110
+ if (!entry.name) {
111
+ continue;
112
+ }
113
+ actions.set(entry.id, mixer.clipAction(entry.clip));
114
+ const ids = clipNameToIds.get(entry.name) ?? [];
115
+ ids.push(entry.id);
116
+ clipNameToIds.set(entry.name, ids);
117
+ }
118
+ return { actions, clipNameToIds };
119
+ }
120
+ __name(createActions, "createActions");
121
+ function stopAllActions(runtime) {
122
+ runtime.actions.forEach((action) => {
123
+ action.stop();
124
+ });
125
+ runtime.mixer.stopAllAction();
126
+ runtime.activeClipId = null;
127
+ }
128
+ __name(stopAllActions, "stopAllActions");
129
+ function transitionToClip(runtime, nextClipId, crossFadeDuration) {
130
+ if (runtime.activeClipId === nextClipId) {
131
+ return;
132
+ }
133
+ const previousAction = runtime.activeClipId ? runtime.actions.get(runtime.activeClipId) : void 0;
134
+ const nextAction = nextClipId ? runtime.actions.get(nextClipId) : void 0;
135
+ if (!nextAction) {
136
+ if (previousAction) {
137
+ previousAction.stop();
138
+ }
139
+ runtime.activeClipId = null;
140
+ return;
141
+ }
142
+ if (!previousAction || previousAction === nextAction) {
143
+ nextAction.reset();
144
+ nextAction.play();
145
+ runtime.activeClipId = nextClipId;
146
+ return;
147
+ }
148
+ if (crossFadeDuration > 0) {
149
+ nextAction.reset();
150
+ nextAction.play();
151
+ previousAction.crossFadeTo(nextAction, crossFadeDuration, true);
152
+ } else {
153
+ previousAction.stop();
154
+ nextAction.reset();
155
+ nextAction.play();
156
+ }
157
+ runtime.activeClipId = nextClipId;
158
+ }
159
+ __name(transitionToClip, "transitionToClip");
160
+ function applyActionState(action, component, paused, shouldLoop) {
161
+ const loopMode = shouldLoop ? THREE7.LoopRepeat : THREE7.LoopOnce;
162
+ const repetitions = shouldLoop ? Infinity : 1;
163
+ action.setLoop(loopMode, repetitions);
164
+ action.clampWhenFinished = !shouldLoop;
165
+ action.paused = paused;
166
+ const direction = component.reverse ? -1 : 1;
167
+ action.setEffectiveTimeScale(sanitizeTimeScale(component.timeScale) * direction);
168
+ }
169
+ __name(applyActionState, "applyActionState");
170
+ function applyPendingHydratedOptions(component, runtime) {
171
+ const pending = component.__pendingHydratedOptions;
172
+ if (!pending) {
173
+ return;
174
+ }
175
+ if (Array.isArray(pending.externalClipSources)) {
176
+ component.setExternalClipSources(pending.externalClipSources);
177
+ }
178
+ if (!Array.isArray(component.clips) || component.clips.length === 0) {
179
+ return;
180
+ }
181
+ if (runtime && runtime.pendingSources.size > 0) {
182
+ return;
183
+ }
184
+ const states = Array.isArray(pending.states) ? pending.states : [];
185
+ if (states.length > 0) {
186
+ component.setStates(states);
187
+ }
188
+ if (typeof pending.reverse === "boolean") {
189
+ component.reverse = pending.reverse;
190
+ }
191
+ if (typeof pending.timeScale === "number" && Number.isFinite(pending.timeScale)) {
192
+ component.timeScale = pending.timeScale;
193
+ }
194
+ if (typeof pending.crossFadeDuration === "number" && Number.isFinite(pending.crossFadeDuration)) {
195
+ component.crossFadeDuration = Math.max(0, pending.crossFadeDuration);
196
+ }
197
+ if (typeof pending.activeState === "string" && pending.activeState.length > 0) {
198
+ component.setActiveState(pending.activeState, !pending.paused);
199
+ }
200
+ if (typeof pending.paused === "boolean") {
201
+ if (pending.paused) {
202
+ component.pauseState(pending.activeState ?? void 0);
203
+ } else {
204
+ component.playState(pending.activeState ?? void 0);
205
+ }
206
+ }
207
+ delete component.__pendingHydratedOptions;
208
+ }
209
+ __name(applyPendingHydratedOptions, "applyPendingHydratedOptions");
210
+ var _AnimationSystem = class _AnimationSystem {
211
+ constructor() {
212
+ this.runtimeByEntity = /* @__PURE__ */ new Map();
213
+ this.gltfLoader = createClipSourceLoader();
214
+ this.fbxLoader = new FBXLoader();
215
+ }
216
+ async loadClipsFromSource(sourceUrl) {
217
+ const ext = extractFileExtension(sourceUrl);
218
+ if (ext === "fbx") {
219
+ return new Promise((resolve, reject) => {
220
+ this.fbxLoader.load(
221
+ sourceUrl,
222
+ (object) => {
223
+ const clips = Array.isArray(object.animations) ? object.animations : [];
224
+ resolve(clips);
225
+ },
226
+ void 0,
227
+ reject
228
+ );
229
+ });
230
+ }
231
+ if (ext === "glb" || ext === "gltf") {
232
+ return new Promise((resolve, reject) => {
233
+ this.gltfLoader.load(
234
+ sourceUrl,
235
+ (gltf) => {
236
+ const clips = Array.isArray(gltf.animations) ? gltf.animations : [];
237
+ resolve(clips);
238
+ },
239
+ void 0,
240
+ reject
241
+ );
242
+ });
243
+ }
244
+ return [];
245
+ }
246
+ refreshExternalClipSources(world, entityId, animation, runtime) {
247
+ const normalizedSources = normalizeClipSources(animation.externalClipSources);
248
+ const sourceSignature = normalizedSources.join("|");
249
+ if (runtime.sourceSignature !== sourceSignature) {
250
+ runtime.sourceSignature = sourceSignature;
251
+ runtime.sourceToken += 1;
252
+ runtime.pendingSources.clear();
253
+ runtime.importedSourceClips.clear();
254
+ animation.setImportedClips([]);
255
+ }
256
+ const sourceSet = new Set(normalizedSources);
257
+ for (const loadedSource of runtime.importedSourceClips.keys()) {
258
+ if (!sourceSet.has(loadedSource)) {
259
+ runtime.importedSourceClips.delete(loadedSource);
260
+ }
261
+ }
262
+ [...runtime.importedSourceClips.values()].flat();
263
+ animation.setImportedClips(
264
+ normalizedSources.flatMap((sourceUrl) => {
265
+ const clipsForSource = runtime.importedSourceClips.get(sourceUrl) ?? [];
266
+ return clipsForSource.map((clip) => ({ clip, sourceUrl }));
267
+ })
268
+ );
269
+ for (const sourceUrl of normalizedSources) {
270
+ if (runtime.importedSourceClips.has(sourceUrl) || runtime.pendingSources.has(sourceUrl)) {
271
+ continue;
272
+ }
273
+ runtime.pendingSources.add(sourceUrl);
274
+ const sourceToken = runtime.sourceToken;
275
+ void this.loadClipsFromSource(sourceUrl).then((clips) => {
276
+ const currentRuntime = this.runtimeByEntity.get(entityId);
277
+ if (!currentRuntime || currentRuntime.sourceToken !== sourceToken) {
278
+ return;
279
+ }
280
+ currentRuntime.pendingSources.delete(sourceUrl);
281
+ currentRuntime.importedSourceClips.set(sourceUrl, clips);
282
+ const currentAnimation = world.getComponent(entityId, AnimationComponent);
283
+ if (!currentAnimation) {
284
+ return;
285
+ }
286
+ currentAnimation.setImportedClips(
287
+ normalizedSources.flatMap((url) => {
288
+ const clipsForSource = currentRuntime.importedSourceClips.get(url) ?? [];
289
+ return clipsForSource.map((clip) => ({ clip, sourceUrl: url }));
290
+ })
291
+ );
292
+ }).catch((error) => {
293
+ const currentRuntime = this.runtimeByEntity.get(entityId);
294
+ if (!currentRuntime || currentRuntime.sourceToken !== sourceToken) {
295
+ return;
296
+ }
297
+ currentRuntime.pendingSources.delete(sourceUrl);
298
+ currentRuntime.importedSourceClips.delete(sourceUrl);
299
+ console.warn(`Failed to load animation source: ${sourceUrl}`, error);
300
+ });
301
+ }
302
+ }
303
+ release(entityId) {
304
+ const runtime = this.runtimeByEntity.get(entityId);
305
+ if (!runtime) {
306
+ return;
307
+ }
308
+ stopAllActions(runtime);
309
+ this.runtimeByEntity.delete(entityId);
310
+ }
311
+ update(world, deltaTime) {
312
+ const entityIds = world.query(AnimationComponent, ModelComponent);
313
+ const alive = new Set(entityIds);
314
+ for (const trackedEntityId of this.runtimeByEntity.keys()) {
315
+ if (!alive.has(trackedEntityId)) {
316
+ this.release(trackedEntityId);
317
+ }
318
+ }
319
+ const step = normalizeDeltaTime(deltaTime);
320
+ for (const entityId of entityIds) {
321
+ const animation = world.getComponent(entityId, AnimationComponent);
322
+ const model = world.getComponent(entityId, ModelComponent);
323
+ const root = model?.object ?? null;
324
+ if (!animation || !model || !root) {
325
+ this.release(entityId);
326
+ continue;
327
+ }
328
+ const existing = this.runtimeByEntity.get(entityId);
329
+ let runtime = existing;
330
+ if (!runtime || runtime.rootUuid !== root.uuid) {
331
+ if (runtime) {
332
+ stopAllActions(runtime);
333
+ }
334
+ const mixer = new THREE7.AnimationMixer(root);
335
+ const entries2 = readRuntimeClipEntries(animation);
336
+ const indexedActions = createActions(mixer, entries2);
337
+ runtime = {
338
+ rootUuid: root.uuid,
339
+ mixer,
340
+ actions: indexedActions.actions,
341
+ clipNameToIds: indexedActions.clipNameToIds,
342
+ activeClipId: null,
343
+ clipSignature: buildClipSignature(entries2),
344
+ sourceSignature: "",
345
+ sourceToken: 0,
346
+ importedSourceClips: /* @__PURE__ */ new Map(),
347
+ pendingSources: /* @__PURE__ */ new Set()
348
+ };
349
+ this.runtimeByEntity.set(entityId, runtime);
350
+ }
351
+ this.refreshExternalClipSources(world, entityId, animation, runtime);
352
+ applyPendingHydratedOptions(animation, runtime);
353
+ if (!world.isEntityVisible(entityId)) {
354
+ continue;
355
+ }
356
+ const entries = readRuntimeClipEntries(animation);
357
+ const clipSignature = buildClipSignature(entries);
358
+ if (runtime.clipSignature !== clipSignature) {
359
+ stopAllActions(runtime);
360
+ const indexedActions = createActions(runtime.mixer, entries);
361
+ runtime.actions = indexedActions.actions;
362
+ runtime.clipNameToIds = indexedActions.clipNameToIds;
363
+ runtime.clipSignature = clipSignature;
364
+ }
365
+ if (runtime.actions.size === 0) {
366
+ continue;
367
+ }
368
+ const activeState = animation.active;
369
+ const stateClipId = typeof activeState?.clipId === "string" && activeState.clipId.length > 0 ? activeState.clipId : null;
370
+ const stateClipName = activeState?.clip.name ?? null;
371
+ const fallbackClipId = stateClipName && runtime.clipNameToIds.has(stateClipName) ? runtime.clipNameToIds.get(stateClipName)?.[0] ?? null : null;
372
+ const nextClipId = stateClipId && runtime.actions.has(stateClipId) ? stateClipId : fallbackClipId && runtime.actions.has(fallbackClipId) ? fallbackClipId : null;
373
+ const hasActiveState = Boolean(activeState);
374
+ const isPaused = hasActiveState ? !(activeState?.isPlaying ?? false) : animation.paused;
375
+ if (hasActiveState) {
376
+ animation.paused = isPaused;
377
+ }
378
+ transitionToClip(
379
+ runtime,
380
+ nextClipId,
381
+ sanitizeCrossFadeDuration(animation.crossFadeDuration)
382
+ );
383
+ if (!runtime.activeClipId) {
384
+ continue;
385
+ }
386
+ const action = runtime.actions.get(runtime.activeClipId);
387
+ if (!action) {
388
+ continue;
389
+ }
390
+ applyActionState(action, animation, isPaused, Boolean(activeState?.loop));
391
+ if (animation.reverse && action.time <= 0) {
392
+ action.time = action.getClip().duration;
393
+ }
394
+ runtime.mixer.update(step);
395
+ if (activeState?.isPlaying) {
396
+ activeState.onPlaying();
397
+ }
398
+ }
399
+ }
400
+ dispose() {
401
+ for (const runtime of this.runtimeByEntity.values()) {
402
+ stopAllActions(runtime);
403
+ }
404
+ this.runtimeByEntity.clear();
405
+ }
406
+ };
407
+ __name(_AnimationSystem, "AnimationSystem");
408
+ var AnimationSystem = _AnimationSystem;
409
+ var MIN_NEAR = 1e-3;
410
+ var MIN_FAR_DELTA = 1e-3;
411
+ var MIN_FOV = 1;
412
+ var MAX_FOV = 179;
413
+ var MIN_ZOOM = 1e-3;
414
+ function clampNear(value) {
415
+ if (!Number.isFinite(value)) {
416
+ return MIN_NEAR;
417
+ }
418
+ return Math.max(MIN_NEAR, value);
419
+ }
420
+ __name(clampNear, "clampNear");
421
+ function clampFar(value, near) {
422
+ if (!Number.isFinite(value)) {
423
+ return near + 1e3;
424
+ }
425
+ return Math.max(near + MIN_FAR_DELTA, value);
426
+ }
427
+ __name(clampFar, "clampFar");
428
+ function clampFov(value) {
429
+ if (!Number.isFinite(value)) {
430
+ return 50;
431
+ }
432
+ return Math.min(MAX_FOV, Math.max(MIN_FOV, value));
433
+ }
434
+ __name(clampFov, "clampFov");
435
+ function clampZoom(value) {
436
+ if (!Number.isFinite(value)) {
437
+ return 1;
438
+ }
439
+ return Math.max(MIN_ZOOM, value);
440
+ }
441
+ __name(clampZoom, "clampZoom");
442
+ function normalizeOrthoBounds(component) {
443
+ let left = Number.isFinite(component.left) ? component.left : -5;
444
+ let right = Number.isFinite(component.right) ? component.right : 5;
445
+ let top = Number.isFinite(component.top) ? component.top : 5;
446
+ let bottom = Number.isFinite(component.bottom) ? component.bottom : -5;
447
+ if (right <= left) {
448
+ right = left + 0.01;
449
+ }
450
+ if (top <= bottom) {
451
+ top = bottom + 0.01;
452
+ }
453
+ component.left = left;
454
+ component.right = right;
455
+ component.top = top;
456
+ component.bottom = bottom;
457
+ }
458
+ __name(normalizeOrthoBounds, "normalizeOrthoBounds");
459
+ function isPerspectiveCamera(camera) {
460
+ return camera instanceof THREE7.PerspectiveCamera;
461
+ }
462
+ __name(isPerspectiveCamera, "isPerspectiveCamera");
463
+ function isOrthographicCamera(camera) {
464
+ return camera instanceof THREE7.OrthographicCamera;
465
+ }
466
+ __name(isOrthographicCamera, "isOrthographicCamera");
467
+ function readWindowAspect() {
468
+ if (typeof window === "undefined") {
469
+ return null;
470
+ }
471
+ const width = window.innerWidth;
472
+ const height = window.innerHeight;
473
+ if (Number.isFinite(width) && Number.isFinite(height) && width > 0 && height > 0) {
474
+ return width / height;
475
+ }
476
+ return null;
477
+ }
478
+ __name(readWindowAspect, "readWindowAspect");
479
+ function buildSignature(component, camera, windowAspect) {
480
+ return [
481
+ component.type,
482
+ component.isDefault,
483
+ component.projection,
484
+ component.fov,
485
+ component.near,
486
+ component.far,
487
+ component.left,
488
+ component.right,
489
+ component.top,
490
+ component.bottom,
491
+ component.zoom,
492
+ windowAspect ?? "na",
493
+ camera.uuid
494
+ ].join("|");
495
+ }
496
+ __name(buildSignature, "buildSignature");
497
+ var _CameraSyncSystem = class _CameraSyncSystem {
498
+ constructor() {
499
+ this.signatures = /* @__PURE__ */ new Map();
500
+ }
501
+ update(world) {
502
+ const entityIds = world.query(CameraComponent, Object3DRef);
503
+ const windowAspect = readWindowAspect();
504
+ const alive = new Set(entityIds);
505
+ for (const trackedId of this.signatures.keys()) {
506
+ if (!alive.has(trackedId)) {
507
+ this.signatures.delete(trackedId);
508
+ }
509
+ }
510
+ for (const entityId of entityIds) {
511
+ const component = world.getComponent(entityId, CameraComponent);
512
+ const objectRef = world.getComponent(entityId, Object3DRef);
513
+ if (!component || !objectRef) {
514
+ continue;
515
+ }
516
+ const camera = objectRef.object;
517
+ if (!(camera instanceof THREE7.Camera)) {
518
+ continue;
519
+ }
520
+ const nextSignature = buildSignature(component, camera, windowAspect);
521
+ if (this.signatures.get(entityId) === nextSignature) {
522
+ continue;
523
+ }
524
+ const near = clampNear(component.near);
525
+ const far = clampFar(component.far, near);
526
+ component.near = near;
527
+ component.far = far;
528
+ if (isPerspectiveCamera(camera)) {
529
+ camera.fov = clampFov(component.fov);
530
+ component.fov = camera.fov;
531
+ if (windowAspect !== null) {
532
+ camera.aspect = windowAspect;
533
+ }
534
+ camera.near = near;
535
+ camera.far = far;
536
+ camera.updateProjectionMatrix();
537
+ } else if (isOrthographicCamera(camera)) {
538
+ normalizeOrthoBounds(component);
539
+ camera.left = component.left;
540
+ camera.right = component.right;
541
+ camera.top = component.top;
542
+ camera.bottom = component.bottom;
543
+ camera.zoom = clampZoom(component.zoom);
544
+ component.zoom = camera.zoom;
545
+ camera.near = near;
546
+ camera.far = far;
547
+ camera.updateProjectionMatrix();
548
+ }
549
+ component.camera = camera;
550
+ this.signatures.set(entityId, buildSignature(component, camera, windowAspect));
551
+ }
552
+ }
553
+ };
554
+ __name(_CameraSyncSystem, "CameraSyncSystem");
555
+ var CameraSyncSystem = _CameraSyncSystem;
556
+
557
+ // core/systems/ObjectVisibilitySystem.ts
558
+ var _ObjectVisibilitySystem = class _ObjectVisibilitySystem {
559
+ update(world) {
560
+ const entityIds = world.query(Object3DRef);
561
+ for (const entityId of entityIds) {
562
+ const objectRef = world.getComponent(entityId, Object3DRef);
563
+ const object = objectRef?.object;
564
+ if (!objectRef || !object) {
565
+ continue;
566
+ }
567
+ const targetVisibility = Boolean(objectRef.visibility);
568
+ if (object.visible !== targetVisibility) {
569
+ object.visible = targetVisibility;
570
+ }
571
+ }
572
+ }
573
+ };
574
+ __name(_ObjectVisibilitySystem, "ObjectVisibilitySystem");
575
+ var ObjectVisibilitySystem = _ObjectVisibilitySystem;
576
+ var MIN_FOG_DELTA = 1e-3;
577
+ var MIN_DENSITY = 0;
578
+ function createGradientTexture(effect, colors) {
579
+ if (typeof document === "undefined") {
580
+ const pixel = new Uint8Array([30, 30, 30, 255]);
581
+ const fallback = new THREE7.DataTexture(pixel, 1, 1, THREE7.RGBAFormat);
582
+ fallback.needsUpdate = true;
583
+ return fallback;
584
+ }
585
+ const canvas = document.createElement("canvas");
586
+ canvas.width = 512;
587
+ canvas.height = 512;
588
+ const context = canvas.getContext("2d");
589
+ if (!context) {
590
+ const fallback = new THREE7.CanvasTexture(canvas);
591
+ fallback.needsUpdate = true;
592
+ return fallback;
593
+ }
594
+ const safeColors = colors.length > 0 ? colors : ["#0f172a", "#334155"];
595
+ const lastIndex = Math.max(1, safeColors.length - 1);
596
+ let gradient;
597
+ if (effect === "radial") {
598
+ gradient = context.createRadialGradient(256, 256, 16, 256, 256, 320);
599
+ } else if (effect === "angular") {
600
+ gradient = context.createLinearGradient(0, 0, 512, 512);
601
+ } else {
602
+ gradient = context.createLinearGradient(0, 0, 0, 512);
603
+ }
604
+ for (let index = 0; index < safeColors.length; index += 1) {
605
+ gradient.addColorStop(index / lastIndex, safeColors[index]);
606
+ }
607
+ context.fillStyle = gradient;
608
+ context.fillRect(0, 0, 512, 512);
609
+ if (effect === "angular") {
610
+ context.globalCompositeOperation = "overlay";
611
+ const overlay = context.createRadialGradient(256, 256, 32, 256, 256, 340);
612
+ overlay.addColorStop(0, "rgba(255,255,255,0.25)");
613
+ overlay.addColorStop(1, "rgba(0,0,0,0.2)");
614
+ context.fillStyle = overlay;
615
+ context.fillRect(0, 0, 512, 512);
616
+ context.globalCompositeOperation = "source-over";
617
+ }
618
+ const texture = new THREE7.CanvasTexture(canvas);
619
+ texture.colorSpace = THREE7.SRGBColorSpace;
620
+ texture.needsUpdate = true;
621
+ return texture;
622
+ }
623
+ __name(createGradientTexture, "createGradientTexture");
624
+ var _EnvironmentSyncSystem = class _EnvironmentSyncSystem {
625
+ constructor(scene) {
626
+ this.textureLoader = new THREE7.TextureLoader();
627
+ this.signature = null;
628
+ this.activeTexture = null;
629
+ this.pendingImageUrl = null;
630
+ this.scene = scene;
631
+ }
632
+ disposeActiveTexture() {
633
+ if (this.activeTexture) {
634
+ this.activeTexture.dispose();
635
+ this.activeTexture = null;
636
+ }
637
+ }
638
+ applySkybox(component) {
639
+ const skybox = component.values.skybox;
640
+ if (skybox.type === "none") {
641
+ this.disposeActiveTexture();
642
+ this.pendingImageUrl = null;
643
+ this.scene.background = null;
644
+ return;
645
+ }
646
+ if (skybox.type === "color") {
647
+ this.disposeActiveTexture();
648
+ this.pendingImageUrl = null;
649
+ this.scene.background = new THREE7.Color(skybox.color || "#1e1e1e");
650
+ return;
651
+ }
652
+ if (skybox.type === "gradient") {
653
+ this.disposeActiveTexture();
654
+ this.pendingImageUrl = null;
655
+ const texture = createGradientTexture(
656
+ skybox.gradient.effect,
657
+ skybox.gradient.colors
658
+ );
659
+ this.activeTexture = texture;
660
+ this.scene.background = texture;
661
+ return;
662
+ }
663
+ const imageUrl = skybox.imageUrl?.trim() ?? "";
664
+ if (!imageUrl) {
665
+ this.disposeActiveTexture();
666
+ this.pendingImageUrl = null;
667
+ this.scene.background = null;
668
+ return;
669
+ }
670
+ if (this.pendingImageUrl === imageUrl && this.activeTexture) {
671
+ this.scene.background = this.activeTexture;
672
+ return;
673
+ }
674
+ this.disposeActiveTexture();
675
+ this.pendingImageUrl = imageUrl;
676
+ this.textureLoader.load(
677
+ imageUrl,
678
+ (texture) => {
679
+ if (this.pendingImageUrl !== imageUrl) {
680
+ texture.dispose();
681
+ return;
682
+ }
683
+ texture.colorSpace = THREE7.SRGBColorSpace;
684
+ this.activeTexture = texture;
685
+ this.scene.background = texture;
686
+ },
687
+ void 0,
688
+ () => {
689
+ if (this.pendingImageUrl === imageUrl) {
690
+ this.pendingImageUrl = null;
691
+ this.scene.background = null;
692
+ }
693
+ }
694
+ );
695
+ }
696
+ applyFog(component) {
697
+ const fog = component.values.fog;
698
+ if (fog.type === "none") {
699
+ this.scene.fog = null;
700
+ return;
701
+ }
702
+ const fogColor = new THREE7.Color(fog.color || "#1e1e1e");
703
+ if (fog.type === "linear") {
704
+ const near = Number.isFinite(fog.linear.near) ? fog.linear.near : 1;
705
+ const farCandidate = Number.isFinite(fog.linear.far) ? fog.linear.far : near + 10;
706
+ const far = Math.max(near + MIN_FOG_DELTA, farCandidate);
707
+ this.scene.fog = new THREE7.Fog(fogColor, near, far);
708
+ return;
709
+ }
710
+ const density = Number.isFinite(fog.exponential.density) ? Math.max(MIN_DENSITY, fog.exponential.density) : 2e-3;
711
+ this.scene.fog = new THREE7.FogExp2(fogColor, density);
712
+ }
713
+ update(world) {
714
+ const entityIds = world.query(Environment);
715
+ if (entityIds.length === 0) {
716
+ if (this.signature !== null) {
717
+ this.signature = null;
718
+ this.pendingImageUrl = null;
719
+ this.disposeActiveTexture();
720
+ this.scene.background = null;
721
+ this.scene.fog = null;
722
+ }
723
+ return;
724
+ }
725
+ const entityId = entityIds[0];
726
+ const environment = world.getComponent(entityId, Environment);
727
+ if (!environment) {
728
+ return;
729
+ }
730
+ const nextSignature = JSON.stringify(environment.values);
731
+ if (this.signature === nextSignature) {
732
+ return;
733
+ }
734
+ this.signature = nextSignature;
735
+ this.applySkybox(environment);
736
+ this.applyFog(environment);
737
+ }
738
+ dispose() {
739
+ this.pendingImageUrl = null;
740
+ this.disposeActiveTexture();
741
+ }
742
+ };
743
+ __name(_EnvironmentSyncSystem, "EnvironmentSyncSystem");
744
+ var EnvironmentSyncSystem = _EnvironmentSyncSystem;
745
+ var _PostprocessingSyncSystem = class _PostprocessingSyncSystem {
746
+ constructor(renderer, scene, camera) {
747
+ this.signature = null;
748
+ this.composer = null;
749
+ this.composerEnabled = false;
750
+ this.renderer = renderer;
751
+ this.scene = scene;
752
+ this.camera = camera;
753
+ }
754
+ setComposerEnabled(enabled) {
755
+ this.composerEnabled = enabled;
756
+ this.scene.userData.ecsPostprocessingComposerActive = enabled;
757
+ if (!enabled) {
758
+ delete this.scene.userData.ecsPostprocessingComposer;
759
+ }
760
+ }
761
+ disposeComposer() {
762
+ if (!this.composer) {
763
+ this.setComposerEnabled(false);
764
+ return;
765
+ }
766
+ const maybeComposer = this.composer;
767
+ if (Array.isArray(maybeComposer.passes)) {
768
+ for (const pass of maybeComposer.passes) {
769
+ pass.dispose?.();
770
+ }
771
+ }
772
+ maybeComposer.dispose?.();
773
+ this.composer = null;
774
+ this.setComposerEnabled(false);
775
+ }
776
+ buildComposer(values) {
777
+ this.disposeComposer();
778
+ if (!values.postEnabled) {
779
+ return;
780
+ }
781
+ const composer = new EffectComposer(this.renderer);
782
+ composer.addPass(new RenderPass(this.scene, this.camera));
783
+ if (values.dof.enabled) {
784
+ composer.addPass(
785
+ new BokehPass(this.scene, this.camera, {
786
+ focus: values.dof.focusDistance,
787
+ aperture: Math.max(0, values.dof.focalLength),
788
+ maxblur: Math.max(0, values.dof.bokehScale)
789
+ })
790
+ );
791
+ }
792
+ if (values.bloom.enabled) {
793
+ const size = this.renderer.getSize(new THREE7.Vector2());
794
+ composer.addPass(
795
+ new UnrealBloomPass(
796
+ new THREE7.Vector2(size.width, size.height),
797
+ values.bloom.intensity,
798
+ values.bloom.radius,
799
+ values.bloom.threshold
800
+ )
801
+ );
802
+ }
803
+ if (values.vignette.enabled) {
804
+ const pass = new ShaderPass(VignetteShader);
805
+ const offset = pass.uniforms.offset;
806
+ const darkness = pass.uniforms.darkness;
807
+ if (offset) {
808
+ offset.value = values.vignette.offset;
809
+ }
810
+ if (darkness) {
811
+ darkness.value = values.vignette.darkness;
812
+ }
813
+ composer.addPass(pass);
814
+ }
815
+ if (values.hueSaturation.enabled) {
816
+ const pass = new ShaderPass(HueSaturationShader);
817
+ const hue = pass.uniforms.hue;
818
+ const saturation = pass.uniforms.saturation;
819
+ if (hue) {
820
+ hue.value = values.hueSaturation.hue;
821
+ }
822
+ if (saturation) {
823
+ saturation.value = values.hueSaturation.saturation;
824
+ }
825
+ composer.addPass(pass);
826
+ }
827
+ if (values.sepia.enabled) {
828
+ const pass = new ShaderPass(SepiaShader);
829
+ const amount = pass.uniforms.amount;
830
+ if (amount) {
831
+ amount.value = values.sepia.intensity;
832
+ }
833
+ composer.addPass(pass);
834
+ }
835
+ if (values.noise.enabled) {
836
+ composer.addPass(new FilmPass(values.noise.opacity));
837
+ }
838
+ if (values.dotScreen.enabled) {
839
+ composer.addPass(
840
+ new DotScreenPass(
841
+ new THREE7.Vector2(0, 0),
842
+ values.dotScreen.angle ?? values.dotScreen.dotScreenAngle,
843
+ values.dotScreen.scale ?? values.dotScreen.dotScreenScale
844
+ )
845
+ );
846
+ }
847
+ if (values.ssao.enabled) {
848
+ const pass = new SSAOPass(this.scene, this.camera);
849
+ pass.kernelRadius = values.ssao.radius;
850
+ pass.minDistance = 1e-3;
851
+ pass.maxDistance = Math.max(0.01, values.ssao.intensity);
852
+ composer.addPass(pass);
853
+ }
854
+ if (values.glitch.enabled) {
855
+ const pass = new GlitchPass();
856
+ pass.enabled = true;
857
+ pass.goWild = Boolean(values.glitch.active);
858
+ composer.addPass(pass);
859
+ }
860
+ composer.addPass(new OutputPass());
861
+ this.composer = composer;
862
+ this.scene.userData.ecsPostprocessingComposer = composer;
863
+ this.setComposerEnabled(true);
864
+ }
865
+ update(world) {
866
+ const entityIds = world.query(Postprocessing);
867
+ if (entityIds.length === 0) {
868
+ if (this.signature !== null) {
869
+ this.signature = null;
870
+ this.disposeComposer();
871
+ delete this.scene.userData.ecsPostprocessing;
872
+ }
873
+ return;
874
+ }
875
+ const postprocessing = world.getComponent(entityIds[0], Postprocessing);
876
+ if (!postprocessing) {
877
+ return;
878
+ }
879
+ const nextSignature = JSON.stringify(postprocessing.values);
880
+ if (this.signature === nextSignature) {
881
+ return;
882
+ }
883
+ this.signature = nextSignature;
884
+ this.buildComposer(postprocessing.values);
885
+ this.scene.userData.ecsPostprocessing = postprocessing.values;
886
+ }
887
+ dispose() {
888
+ this.signature = null;
889
+ this.disposeComposer();
890
+ delete this.scene.userData.ecsPostprocessing;
891
+ delete this.scene.userData.ecsPostprocessingComposerActive;
892
+ delete this.scene.userData.ecsPostprocessingComposer;
893
+ }
894
+ };
895
+ __name(_PostprocessingSyncSystem, "PostprocessingSyncSystem");
896
+ var PostprocessingSyncSystem = _PostprocessingSyncSystem;
897
+ var MIN_SIZE = 1e-4;
898
+ function createRigidBodyDesc(RAPIER, bodyType) {
899
+ if (bodyType === "fixed") {
900
+ return RAPIER.RigidBodyDesc.fixed();
901
+ }
902
+ if (bodyType === "kinematicPosition") {
903
+ return RAPIER.RigidBodyDesc.kinematicPositionBased();
904
+ }
905
+ if (bodyType === "kinematicVelocity") {
906
+ return RAPIER.RigidBodyDesc.kinematicVelocityBased();
907
+ }
908
+ return RAPIER.RigidBodyDesc.dynamic();
909
+ }
910
+ __name(createRigidBodyDesc, "createRigidBodyDesc");
911
+ function computeColliderState(colliderValues, object) {
912
+ if (!object) {
913
+ return colliderValues;
914
+ }
915
+ const scale = new THREE7.Vector3();
916
+ object.getWorldScale(scale);
917
+ return {
918
+ ...colliderValues,
919
+ size: {
920
+ x: Math.max(MIN_SIZE, colliderValues.size.x * Math.abs(scale.x || 1)),
921
+ y: Math.max(MIN_SIZE, colliderValues.size.y * Math.abs(scale.y || 1)),
922
+ z: Math.max(MIN_SIZE, colliderValues.size.z * Math.abs(scale.z || 1))
923
+ },
924
+ radius: Math.max(
925
+ MIN_SIZE,
926
+ colliderValues.radius * Math.max(Math.abs(scale.x || 1), Math.abs(scale.z || 1), 1)
927
+ ),
928
+ height: Math.max(MIN_SIZE, colliderValues.height * Math.abs(scale.y || 1))
929
+ };
930
+ }
931
+ __name(computeColliderState, "computeColliderState");
932
+ function createColliderDesc(RAPIER, values, triMeshData) {
933
+ let desc;
934
+ if (values.shape === "trimesh" && triMeshData) {
935
+ desc = RAPIER.ColliderDesc.trimesh(
936
+ triMeshData.vertices,
937
+ triMeshData.indices
938
+ );
939
+ } else if (values.shape === "ball") {
940
+ desc = RAPIER.ColliderDesc.ball(Math.max(MIN_SIZE, values.radius));
941
+ } else if (values.shape === "capsule") {
942
+ desc = RAPIER.ColliderDesc.capsule(
943
+ Math.max(MIN_SIZE, values.height / 2),
944
+ Math.max(MIN_SIZE, values.radius)
945
+ );
946
+ } else if (values.shape === "cylinder") {
947
+ desc = RAPIER.ColliderDesc.cylinder(
948
+ Math.max(MIN_SIZE, values.height / 2),
949
+ Math.max(MIN_SIZE, values.radius)
950
+ );
951
+ } else {
952
+ desc = RAPIER.ColliderDesc.cuboid(
953
+ Math.max(MIN_SIZE, values.size.x / 2),
954
+ Math.max(MIN_SIZE, values.size.y / 2),
955
+ Math.max(MIN_SIZE, values.size.z / 2)
956
+ );
957
+ }
958
+ desc.setRestitution(Math.max(0, values.restitution));
959
+ desc.setFriction(Math.max(0, values.friction));
960
+ desc.setSensor(values.isSensor);
961
+ desc.setTranslation(
962
+ values.offsetPosition.x,
963
+ values.offsetPosition.y,
964
+ values.offsetPosition.z
965
+ );
966
+ const offsetQuaternion = new THREE7.Quaternion().setFromEuler(
967
+ new THREE7.Euler(
968
+ values.offsetRotation.x,
969
+ values.offsetRotation.y,
970
+ values.offsetRotation.z
971
+ )
972
+ );
973
+ desc.setRotation(offsetQuaternion);
974
+ return desc;
975
+ }
976
+ __name(createColliderDesc, "createColliderDesc");
977
+ function findFirstMeshWithGeometry(object) {
978
+ if (object instanceof THREE7.Mesh && object.geometry) {
979
+ return object;
980
+ }
981
+ let found = null;
982
+ object.traverse((child) => {
983
+ if (found) {
984
+ return;
985
+ }
986
+ if (child instanceof THREE7.Mesh && child.geometry) {
987
+ found = child;
988
+ }
989
+ });
990
+ return found;
991
+ }
992
+ __name(findFirstMeshWithGeometry, "findFirstMeshWithGeometry");
993
+ function createTriMeshData(object) {
994
+ if (!object) {
995
+ return null;
996
+ }
997
+ const mesh = findFirstMeshWithGeometry(object);
998
+ if (!mesh) {
999
+ return null;
1000
+ }
1001
+ const geometry = mesh.geometry;
1002
+ const positionAttribute = geometry.getAttribute("position");
1003
+ if (!positionAttribute || positionAttribute.itemSize < 3) {
1004
+ return null;
1005
+ }
1006
+ const positionCount = positionAttribute.count;
1007
+ if (positionCount < 3) {
1008
+ return null;
1009
+ }
1010
+ object.updateWorldMatrix(true, true);
1011
+ mesh.updateWorldMatrix(true, true);
1012
+ const worldToObject = new THREE7.Matrix4().copy(object.matrixWorld).invert();
1013
+ const relativeMatrix = new THREE7.Matrix4().multiplyMatrices(
1014
+ worldToObject,
1015
+ mesh.matrixWorld
1016
+ );
1017
+ const vertices = new Float32Array(positionCount * 3);
1018
+ const point = new THREE7.Vector3();
1019
+ for (let index = 0; index < positionCount; index += 1) {
1020
+ point.set(
1021
+ positionAttribute.getX(index),
1022
+ positionAttribute.getY(index),
1023
+ positionAttribute.getZ(index)
1024
+ ).applyMatrix4(relativeMatrix);
1025
+ const outputIndex = index * 3;
1026
+ vertices[outputIndex] = point.x;
1027
+ vertices[outputIndex + 1] = point.y;
1028
+ vertices[outputIndex + 2] = point.z;
1029
+ }
1030
+ const indexAttribute = geometry.getIndex();
1031
+ let indices;
1032
+ if (indexAttribute) {
1033
+ indices = new Uint32Array(indexAttribute.count);
1034
+ for (let index = 0; index < indexAttribute.count; index += 1) {
1035
+ indices[index] = indexAttribute.getX(index);
1036
+ }
1037
+ } else {
1038
+ const triangleIndexCount = Math.floor(positionCount / 3) * 3;
1039
+ if (triangleIndexCount < 3) {
1040
+ return null;
1041
+ }
1042
+ indices = new Uint32Array(triangleIndexCount);
1043
+ for (let index = 0; index < triangleIndexCount; index += 1) {
1044
+ indices[index] = index;
1045
+ }
1046
+ }
1047
+ const matrixSignature = relativeMatrix.elements.map((value) => value.toFixed(5)).join(",");
1048
+ return {
1049
+ vertices,
1050
+ indices,
1051
+ signature: `${mesh.uuid}:${geometry.uuid}:${positionCount}:${indices.length}:${matrixSignature}`
1052
+ };
1053
+ }
1054
+ __name(createTriMeshData, "createTriMeshData");
1055
+ function syncBodyFromTransform(body, transform) {
1056
+ const quaternion = new THREE7.Quaternion().setFromEuler(
1057
+ new THREE7.Euler(transform.rotation.x, transform.rotation.y, transform.rotation.z)
1058
+ );
1059
+ body.setTranslation(
1060
+ {
1061
+ x: transform.position.x,
1062
+ y: transform.position.y,
1063
+ z: transform.position.z
1064
+ },
1065
+ true
1066
+ );
1067
+ body.setRotation(
1068
+ {
1069
+ x: quaternion.x,
1070
+ y: quaternion.y,
1071
+ z: quaternion.z,
1072
+ w: quaternion.w
1073
+ },
1074
+ true
1075
+ );
1076
+ }
1077
+ __name(syncBodyFromTransform, "syncBodyFromTransform");
1078
+ function syncTransformFromBody(transform, body) {
1079
+ const position = body.translation();
1080
+ const rotation = body.rotation();
1081
+ transform.position.x = position.x;
1082
+ transform.position.y = position.y;
1083
+ transform.position.z = position.z;
1084
+ const euler = new THREE7.Euler().setFromQuaternion(
1085
+ new THREE7.Quaternion(rotation.x, rotation.y, rotation.z, rotation.w)
1086
+ );
1087
+ transform.rotation.x = euler.x;
1088
+ transform.rotation.y = euler.y;
1089
+ transform.rotation.z = euler.z;
1090
+ }
1091
+ __name(syncTransformFromBody, "syncTransformFromBody");
1092
+ var _PhysicsSyncSystem = class _PhysicsSyncSystem {
1093
+ constructor(options) {
1094
+ this.rigidBodyHandles = /* @__PURE__ */ new Map();
1095
+ this.colliderHandles = /* @__PURE__ */ new Map();
1096
+ this.rigidBodySignatures = /* @__PURE__ */ new Map();
1097
+ this.colliderSignatures = /* @__PURE__ */ new Map();
1098
+ this.rapier = null;
1099
+ this.isBootstrappingWorld = false;
1100
+ this.accumulator = 0;
1101
+ this.isEditorMode = options?.isEditor ?? false;
1102
+ }
1103
+ async ensurePhysicsWorld(world) {
1104
+ if (this.rapier || this.isBootstrappingWorld) {
1105
+ return;
1106
+ }
1107
+ this.isBootstrappingWorld = true;
1108
+ try {
1109
+ const environmentEntityId = world.query(Environment)[0];
1110
+ const environment = typeof environmentEntityId === "number" ? world.getComponent(environmentEntityId, Environment) : void 0;
1111
+ const gravity = environment?.values.gravity;
1112
+ const rapierWorld = await world.createPhysicsWorld({
1113
+ gravity: {
1114
+ x: gravity?.x,
1115
+ y: gravity?.y,
1116
+ z: gravity?.z
1117
+ }
1118
+ });
1119
+ if (!rapierWorld) {
1120
+ return;
1121
+ }
1122
+ const moduleValue = await world.getRapierModule();
1123
+ this.rapier = moduleValue;
1124
+ } finally {
1125
+ this.isBootstrappingWorld = false;
1126
+ }
1127
+ }
1128
+ removeEntityPhysics(physicsWorld, entityId) {
1129
+ const rigidBodyHandle = this.rigidBodyHandles.get(entityId);
1130
+ if (typeof rigidBodyHandle === "number") {
1131
+ const rigidBody = physicsWorld.getRigidBody(rigidBodyHandle);
1132
+ if (rigidBody) {
1133
+ physicsWorld.removeRigidBody(rigidBody);
1134
+ }
1135
+ }
1136
+ this.rigidBodyHandles.delete(entityId);
1137
+ this.colliderHandles.delete(entityId);
1138
+ this.rigidBodySignatures.delete(entityId);
1139
+ this.colliderSignatures.delete(entityId);
1140
+ }
1141
+ update(world, deltaTime) {
1142
+ if (!this.rapier || !world.getPhysicsWorld()) {
1143
+ void this.ensurePhysicsWorld(world);
1144
+ return;
1145
+ }
1146
+ const physicsWorld = world.getPhysicsWorld();
1147
+ if (!physicsWorld) {
1148
+ return;
1149
+ }
1150
+ const entities = world.query(TransformComponent, PhysicsComponent);
1151
+ const activeEntities = new Set(entities);
1152
+ for (const entityId of this.rigidBodyHandles.keys()) {
1153
+ if (!activeEntities.has(entityId)) {
1154
+ this.removeEntityPhysics(physicsWorld, entityId);
1155
+ }
1156
+ }
1157
+ for (const entityId of entities) {
1158
+ const transform = world.getComponent(entityId, TransformComponent);
1159
+ const physics = world.getComponent(entityId, PhysicsComponent);
1160
+ const object = world.getComponent(entityId, Object3DRef)?.object ?? null;
1161
+ if (!transform || !physics) {
1162
+ continue;
1163
+ }
1164
+ if (!physics.values.rigidbody.enabled) {
1165
+ this.removeEntityPhysics(physicsWorld, entityId);
1166
+ physics.rigidBody = null;
1167
+ physics.collider = null;
1168
+ continue;
1169
+ }
1170
+ const rigidBodySignature = JSON.stringify(physics.values.rigidbody);
1171
+ const previousRigidBodySignature = this.rigidBodySignatures.get(entityId);
1172
+ const hasRigidBody = this.rigidBodyHandles.has(entityId);
1173
+ const shouldRecreateBody = !hasRigidBody || previousRigidBodySignature !== rigidBodySignature;
1174
+ if (shouldRecreateBody) {
1175
+ this.removeEntityPhysics(physicsWorld, entityId);
1176
+ const lockTranslationX = physics.values.rigidbody.lockTranslations || physics.values.rigidbody.lockTranslationX;
1177
+ const lockTranslationY = physics.values.rigidbody.lockTranslations || physics.values.rigidbody.lockTranslationY;
1178
+ const lockTranslationZ = physics.values.rigidbody.lockTranslations || physics.values.rigidbody.lockTranslationZ;
1179
+ const lockRotationX = physics.values.rigidbody.lockRotations || physics.values.rigidbody.lockRotationX;
1180
+ const lockRotationY = physics.values.rigidbody.lockRotations || physics.values.rigidbody.lockRotationY;
1181
+ const lockRotationZ = physics.values.rigidbody.lockRotations || physics.values.rigidbody.lockRotationZ;
1182
+ const bodyType = this.isEditorMode ? "fixed" : physics.values.rigidbody.type;
1183
+ const bodyDesc = createRigidBodyDesc(this.rapier, bodyType).setLinearDamping(physics.values.rigidbody.linearDamping).setAngularDamping(physics.values.rigidbody.angularDamping).setGravityScale(physics.values.rigidbody.gravityScale).setCanSleep(physics.values.rigidbody.canSleep).setCcdEnabled(physics.values.rigidbody.ccdEnabled).enabledTranslations(
1184
+ !lockTranslationX,
1185
+ !lockTranslationY,
1186
+ !lockTranslationZ
1187
+ ).enabledRotations(
1188
+ !lockRotationX,
1189
+ !lockRotationY,
1190
+ !lockRotationZ
1191
+ );
1192
+ bodyDesc.setTranslation(
1193
+ transform.position.x,
1194
+ transform.position.y,
1195
+ transform.position.z
1196
+ );
1197
+ const quaternion = new THREE7.Quaternion().setFromEuler(
1198
+ new THREE7.Euler(
1199
+ transform.rotation.x,
1200
+ transform.rotation.y,
1201
+ transform.rotation.z
1202
+ )
1203
+ );
1204
+ bodyDesc.setRotation(quaternion);
1205
+ const body2 = physicsWorld.createRigidBody(bodyDesc);
1206
+ if (!this.isEditorMode && physics.values.rigidbody.type === "dynamic") {
1207
+ body2.setAdditionalMass(physics.values.rigidbody.mass, true);
1208
+ }
1209
+ this.rigidBodyHandles.set(entityId, body2.handle);
1210
+ this.rigidBodySignatures.set(entityId, rigidBodySignature);
1211
+ physics.rigidBody = body2;
1212
+ }
1213
+ const rigidBodyHandle = this.rigidBodyHandles.get(entityId);
1214
+ if (typeof rigidBodyHandle !== "number") {
1215
+ continue;
1216
+ }
1217
+ const body = physicsWorld.getRigidBody(rigidBodyHandle);
1218
+ if (!body) {
1219
+ this.removeEntityPhysics(physicsWorld, entityId);
1220
+ physics.rigidBody = null;
1221
+ physics.collider = null;
1222
+ continue;
1223
+ }
1224
+ physics.rigidBody = body;
1225
+ if (this.isEditorMode || physics.values.rigidbody.type !== "dynamic") {
1226
+ syncBodyFromTransform(body, transform);
1227
+ }
1228
+ const effectiveCollider = computeColliderState(physics.values.collider, object);
1229
+ const triMeshData = effectiveCollider.shape === "trimesh" ? createTriMeshData(object) : null;
1230
+ if (!effectiveCollider || !effectiveCollider.enabled) {
1231
+ const colliderHandle = this.colliderHandles.get(entityId);
1232
+ if (typeof colliderHandle === "number") {
1233
+ const existingCollider = physicsWorld.getCollider(colliderHandle);
1234
+ if (existingCollider) {
1235
+ physicsWorld.removeCollider(existingCollider, true);
1236
+ }
1237
+ }
1238
+ this.colliderHandles.delete(entityId);
1239
+ this.colliderSignatures.delete(entityId);
1240
+ physics.collider = null;
1241
+ continue;
1242
+ }
1243
+ const colliderSignature = `${JSON.stringify(effectiveCollider)}:${triMeshData?.signature ?? ""}`;
1244
+ const previousColliderSignature = this.colliderSignatures.get(entityId);
1245
+ if (!this.colliderHandles.has(entityId) || previousColliderSignature !== colliderSignature) {
1246
+ const previousColliderHandle = this.colliderHandles.get(entityId);
1247
+ if (typeof previousColliderHandle === "number") {
1248
+ const previousCollider = physicsWorld.getCollider(previousColliderHandle);
1249
+ if (previousCollider) {
1250
+ physicsWorld.removeCollider(previousCollider, true);
1251
+ }
1252
+ }
1253
+ const colliderDesc = createColliderDesc(
1254
+ this.rapier,
1255
+ effectiveCollider,
1256
+ triMeshData
1257
+ );
1258
+ const createdCollider = physicsWorld.createCollider(colliderDesc, body);
1259
+ this.colliderHandles.set(entityId, createdCollider.handle);
1260
+ this.colliderSignatures.set(entityId, colliderSignature);
1261
+ physics.collider = createdCollider;
1262
+ } else {
1263
+ const colliderHandle = this.colliderHandles.get(entityId);
1264
+ physics.collider = typeof colliderHandle === "number" ? physicsWorld.getCollider(colliderHandle) ?? null : null;
1265
+ }
1266
+ }
1267
+ if (!this.isEditorMode) {
1268
+ const environmentEntityId = world.query(Environment)[0];
1269
+ const environment = typeof environmentEntityId === "number" ? world.getComponent(environmentEntityId, Environment) : void 0;
1270
+ const fixedTimeStep = typeof environment?.values.fixedTimeStep === "number" && environment.values.fixedTimeStep > 0 ? environment.values.fixedTimeStep : 0.02;
1271
+ const clampedDelta = Number.isFinite(deltaTime) && deltaTime > 0 ? Math.min(deltaTime, 0.1) : fixedTimeStep;
1272
+ this.accumulator += clampedDelta;
1273
+ while (this.accumulator >= fixedTimeStep) {
1274
+ physicsWorld.integrationParameters.dt = fixedTimeStep;
1275
+ physicsWorld.step();
1276
+ this.accumulator -= fixedTimeStep;
1277
+ }
1278
+ }
1279
+ for (const entityId of entities) {
1280
+ const physics = world.getComponent(entityId, PhysicsComponent);
1281
+ const transform = world.getComponent(entityId, TransformComponent);
1282
+ if (!physics || !transform || this.isEditorMode || physics.values.rigidbody.type !== "dynamic") {
1283
+ continue;
1284
+ }
1285
+ const rigidBodyHandle = this.rigidBodyHandles.get(entityId);
1286
+ if (typeof rigidBodyHandle !== "number") {
1287
+ continue;
1288
+ }
1289
+ const body = physicsWorld.getRigidBody(rigidBodyHandle);
1290
+ if (!body) {
1291
+ continue;
1292
+ }
1293
+ syncTransformFromBody(transform, body);
1294
+ }
1295
+ }
1296
+ dispose(world) {
1297
+ const physicsWorld = world.getPhysicsWorld();
1298
+ if (physicsWorld) {
1299
+ for (const entityId of this.rigidBodyHandles.keys()) {
1300
+ this.removeEntityPhysics(physicsWorld, entityId);
1301
+ }
1302
+ }
1303
+ this.rigidBodyHandles.clear();
1304
+ this.colliderHandles.clear();
1305
+ this.rigidBodySignatures.clear();
1306
+ this.colliderSignatures.clear();
1307
+ this.accumulator = 0;
1308
+ }
1309
+ };
1310
+ __name(_PhysicsSyncSystem, "PhysicsSyncSystem");
1311
+ var PhysicsSyncSystem = _PhysicsSyncSystem;
1312
+
1313
+ // core/systems/keyboardKeys.ts
1314
+ var KeyboardKeys = {
1315
+ A: "a",
1316
+ B: "b",
1317
+ C: "c",
1318
+ D: "d",
1319
+ E: "e",
1320
+ F: "f",
1321
+ G: "g",
1322
+ H: "h",
1323
+ I: "i",
1324
+ J: "j",
1325
+ K: "k",
1326
+ L: "l",
1327
+ M: "m",
1328
+ N: "n",
1329
+ O: "o",
1330
+ P: "p",
1331
+ Q: "q",
1332
+ R: "r",
1333
+ S: "s",
1334
+ T: "t",
1335
+ U: "u",
1336
+ V: "v",
1337
+ W: "w",
1338
+ X: "x",
1339
+ Y: "y",
1340
+ Z: "z",
1341
+ Digit0: "0",
1342
+ Digit1: "1",
1343
+ Digit2: "2",
1344
+ Digit3: "3",
1345
+ Digit4: "4",
1346
+ Digit5: "5",
1347
+ Digit6: "6",
1348
+ Digit7: "7",
1349
+ Digit8: "8",
1350
+ Digit9: "9",
1351
+ Space: " ",
1352
+ Enter: "enter",
1353
+ Escape: "escape",
1354
+ Tab: "tab",
1355
+ Backspace: "backspace",
1356
+ Delete: "delete",
1357
+ Insert: "insert",
1358
+ Home: "home",
1359
+ End: "end",
1360
+ PageUp: "pageup",
1361
+ PageDown: "pagedown",
1362
+ ArrowUp: "arrowup",
1363
+ ArrowDown: "arrowdown",
1364
+ ArrowLeft: "arrowleft",
1365
+ ArrowRight: "arrowright",
1366
+ Shift: "shift",
1367
+ ShiftLeft: "shiftleft",
1368
+ ShiftRight: "shiftright",
1369
+ Control: "control",
1370
+ ControlLeft: "controlleft",
1371
+ ControlRight: "controlright",
1372
+ Alt: "alt",
1373
+ Meta: "meta",
1374
+ CapsLock: "capslock",
1375
+ NumLock: "numlock",
1376
+ ScrollLock: "scrolllock",
1377
+ Pause: "pause",
1378
+ PrintScreen: "printscreen",
1379
+ ContextMenu: "contextmenu",
1380
+ Minus: "-",
1381
+ Equal: "=",
1382
+ BracketLeft: "[",
1383
+ BracketRight: "]",
1384
+ Backslash: "\\",
1385
+ Semicolon: ";",
1386
+ Quote: "'",
1387
+ Backquote: "`",
1388
+ Comma: ",",
1389
+ Period: ".",
1390
+ Slash: "/",
1391
+ F1: "f1",
1392
+ F2: "f2",
1393
+ F3: "f3",
1394
+ F4: "f4",
1395
+ F5: "f5",
1396
+ F6: "f6",
1397
+ F7: "f7",
1398
+ F8: "f8",
1399
+ F9: "f9",
1400
+ F10: "f10",
1401
+ F11: "f11",
1402
+ F12: "f12"
1403
+ };
1404
+
1405
+ // core/systems/InputSystem.ts
1406
+ function normalizeKey(key) {
1407
+ return key.toLowerCase();
1408
+ }
1409
+ __name(normalizeKey, "normalizeKey");
1410
+ function normalizeMouseButton(button) {
1411
+ if (typeof button === "number") {
1412
+ return button;
1413
+ }
1414
+ const normalized = button.toLowerCase();
1415
+ if (normalized === "left") {
1416
+ return 0;
1417
+ }
1418
+ if (normalized === "middle" || normalized === "scroll") {
1419
+ return 1;
1420
+ }
1421
+ if (normalized === "right") {
1422
+ return 2;
1423
+ }
1424
+ return Number.NaN;
1425
+ }
1426
+ __name(normalizeMouseButton, "normalizeMouseButton");
1427
+ var _InputSystem = class _InputSystem {
1428
+ constructor() {
1429
+ this.held = /* @__PURE__ */ new Set();
1430
+ this.down = /* @__PURE__ */ new Set();
1431
+ this.up = /* @__PURE__ */ new Set();
1432
+ this.pendingDown = /* @__PURE__ */ new Set();
1433
+ this.pendingUp = /* @__PURE__ */ new Set();
1434
+ this.heldMouse = /* @__PURE__ */ new Set();
1435
+ this.downMouse = /* @__PURE__ */ new Set();
1436
+ this.upMouse = /* @__PURE__ */ new Set();
1437
+ this.pendingMouseDown = /* @__PURE__ */ new Set();
1438
+ this.pendingMouseUp = /* @__PURE__ */ new Set();
1439
+ this.scrollDeltaX = 0;
1440
+ this.scrollDeltaY = 0;
1441
+ this.pendingScrollDeltaX = 0;
1442
+ this.pendingScrollDeltaY = 0;
1443
+ this.mouseDeltaX = 0;
1444
+ this.mouseDeltaY = 0;
1445
+ this.pendingMouseDeltaX = 0;
1446
+ this.pendingMouseDeltaY = 0;
1447
+ this.mousePosition = { x: 0, y: 0 };
1448
+ this.pointerLockElement = null;
1449
+ this.pendingPointerLockRequest = false;
1450
+ this.onKeyDown = /* @__PURE__ */ __name((event) => {
1451
+ const key = normalizeKey(event.key);
1452
+ const code = normalizeKey(event.code);
1453
+ if (!this.held.has(key)) {
1454
+ this.pendingDown.add(key);
1455
+ }
1456
+ this.held.add(key);
1457
+ if (code !== key) {
1458
+ if (!this.held.has(code)) {
1459
+ this.pendingDown.add(code);
1460
+ }
1461
+ this.held.add(code);
1462
+ }
1463
+ }, "onKeyDown");
1464
+ this.onKeyUp = /* @__PURE__ */ __name((event) => {
1465
+ const key = normalizeKey(event.key);
1466
+ const code = normalizeKey(event.code);
1467
+ this.held.delete(key);
1468
+ this.pendingUp.add(key);
1469
+ if (code !== key) {
1470
+ this.held.delete(code);
1471
+ this.pendingUp.add(code);
1472
+ }
1473
+ }, "onKeyUp");
1474
+ this.onWindowBlur = /* @__PURE__ */ __name(() => {
1475
+ this.clearAll();
1476
+ }, "onWindowBlur");
1477
+ this.onMouseDown = /* @__PURE__ */ __name((event) => {
1478
+ const button = event.button;
1479
+ if (!this.heldMouse.has(button)) {
1480
+ this.pendingMouseDown.add(button);
1481
+ }
1482
+ this.heldMouse.add(button);
1483
+ if (this.pendingPointerLockRequest) {
1484
+ this.pendingPointerLockRequest = false;
1485
+ const targetElement = this.pointerLockElement ?? document.body;
1486
+ if (targetElement && typeof targetElement.requestPointerLock === "function") {
1487
+ const result = targetElement.requestPointerLock();
1488
+ if (result instanceof Promise) {
1489
+ result.catch(() => {
1490
+ });
1491
+ }
1492
+ }
1493
+ }
1494
+ }, "onMouseDown");
1495
+ this.onMouseUp = /* @__PURE__ */ __name((event) => {
1496
+ const button = event.button;
1497
+ this.heldMouse.delete(button);
1498
+ this.pendingMouseUp.add(button);
1499
+ }, "onMouseUp");
1500
+ this.onMouseWheel = /* @__PURE__ */ __name((event) => {
1501
+ this.pendingScrollDeltaX += event.deltaX;
1502
+ this.pendingScrollDeltaY += event.deltaY;
1503
+ }, "onMouseWheel");
1504
+ this.onMouseMove = /* @__PURE__ */ __name((event) => {
1505
+ if (this.isMousePointerLocked()) {
1506
+ this.pendingMouseDeltaX += event.movementX;
1507
+ this.pendingMouseDeltaY += event.movementY;
1508
+ this.mousePosition = {
1509
+ x: this.mousePosition.x + event.movementX,
1510
+ y: this.mousePosition.y + event.movementY
1511
+ };
1512
+ return;
1513
+ }
1514
+ this.pendingMouseDeltaX += event.movementX;
1515
+ this.pendingMouseDeltaY += event.movementY;
1516
+ this.mousePosition = {
1517
+ x: event.clientX,
1518
+ y: event.clientY
1519
+ };
1520
+ }, "onMouseMove");
1521
+ this.onPointerLockChange = /* @__PURE__ */ __name(() => {
1522
+ if (!this.isMousePointerLocked()) {
1523
+ return;
1524
+ }
1525
+ const bounds = this.resolvePointerBounds();
1526
+ this.mousePosition = {
1527
+ x: (bounds.minX + bounds.maxX) / 2,
1528
+ y: (bounds.minY + bounds.maxY) / 2
1529
+ };
1530
+ }, "onPointerLockChange");
1531
+ this.onPointerLockError = /* @__PURE__ */ __name(() => {
1532
+ }, "onPointerLockError");
1533
+ if (typeof window === "undefined") {
1534
+ return;
1535
+ }
1536
+ window.addEventListener("keydown", this.onKeyDown);
1537
+ window.addEventListener("keyup", this.onKeyUp);
1538
+ window.addEventListener("mousedown", this.onMouseDown);
1539
+ window.addEventListener("mouseup", this.onMouseUp);
1540
+ document.addEventListener("mousemove", this.onMouseMove);
1541
+ window.addEventListener("wheel", this.onMouseWheel, { passive: true });
1542
+ window.addEventListener("blur", this.onWindowBlur);
1543
+ document.addEventListener("pointerlockchange", this.onPointerLockChange);
1544
+ document.addEventListener("pointerlockerror", this.onPointerLockError);
1545
+ }
1546
+ resolvePointerBounds() {
1547
+ const targetElement = this.pointerLockElement;
1548
+ if (targetElement) {
1549
+ const rect = targetElement.getBoundingClientRect();
1550
+ return {
1551
+ minX: rect.left,
1552
+ minY: rect.top,
1553
+ maxX: rect.right,
1554
+ maxY: rect.bottom
1555
+ };
1556
+ }
1557
+ return {
1558
+ minX: 0,
1559
+ minY: 0,
1560
+ maxX: typeof window !== "undefined" ? window.innerWidth : 0,
1561
+ maxY: typeof window !== "undefined" ? window.innerHeight : 0
1562
+ };
1563
+ }
1564
+ setPointerLockElement(element) {
1565
+ this.pointerLockElement = element;
1566
+ }
1567
+ lockMousePointer() {
1568
+ if (typeof document === "undefined") {
1569
+ return false;
1570
+ }
1571
+ const targetElement = this.pointerLockElement ?? document.body;
1572
+ if (!targetElement || typeof targetElement.requestPointerLock !== "function") {
1573
+ return false;
1574
+ }
1575
+ try {
1576
+ const result = targetElement.requestPointerLock();
1577
+ if (result instanceof Promise) {
1578
+ result.catch(() => {
1579
+ this.pendingPointerLockRequest = true;
1580
+ });
1581
+ }
1582
+ return true;
1583
+ } catch {
1584
+ return false;
1585
+ }
1586
+ }
1587
+ unlockMousePointer() {
1588
+ if (typeof document === "undefined") {
1589
+ return false;
1590
+ }
1591
+ this.pendingPointerLockRequest = false;
1592
+ if (!document.pointerLockElement || typeof document.exitPointerLock !== "function") {
1593
+ return false;
1594
+ }
1595
+ document.exitPointerLock();
1596
+ return true;
1597
+ }
1598
+ isMousePointerLocked() {
1599
+ if (typeof document === "undefined") {
1600
+ return false;
1601
+ }
1602
+ const activePointerLockElement = document.pointerLockElement;
1603
+ if (!activePointerLockElement) {
1604
+ return false;
1605
+ }
1606
+ if (!this.pointerLockElement) {
1607
+ return true;
1608
+ }
1609
+ return activePointerLockElement === this.pointerLockElement;
1610
+ }
1611
+ getKey(key) {
1612
+ return this.held.has(normalizeKey(key));
1613
+ }
1614
+ getKeyDown(key) {
1615
+ return this.down.has(normalizeKey(key));
1616
+ }
1617
+ getKeyUp(key) {
1618
+ return this.up.has(normalizeKey(key));
1619
+ }
1620
+ consumePressed(key) {
1621
+ const normalized = normalizeKey(key);
1622
+ if (!this.down.has(normalized)) {
1623
+ return false;
1624
+ }
1625
+ this.down.delete(normalized);
1626
+ return true;
1627
+ }
1628
+ getMouse(button) {
1629
+ const normalizedButton = normalizeMouseButton(button);
1630
+ if (!Number.isInteger(normalizedButton)) {
1631
+ return false;
1632
+ }
1633
+ return this.heldMouse.has(normalizedButton);
1634
+ }
1635
+ getMouseDown(button) {
1636
+ const normalizedButton = normalizeMouseButton(button);
1637
+ if (!Number.isInteger(normalizedButton)) {
1638
+ return false;
1639
+ }
1640
+ return this.downMouse.has(normalizedButton);
1641
+ }
1642
+ getMouseUp(button) {
1643
+ const normalizedButton = normalizeMouseButton(button);
1644
+ if (!Number.isInteger(normalizedButton)) {
1645
+ return false;
1646
+ }
1647
+ return this.upMouse.has(normalizedButton);
1648
+ }
1649
+ getScrollClick() {
1650
+ return this.getMouse("middle");
1651
+ }
1652
+ getScrollClickDown() {
1653
+ return this.getMouseDown("middle");
1654
+ }
1655
+ getScrollClickUp() {
1656
+ return this.getMouseUp("middle");
1657
+ }
1658
+ getScrollDelta() {
1659
+ return {
1660
+ x: this.scrollDeltaX,
1661
+ y: this.scrollDeltaY
1662
+ };
1663
+ }
1664
+ consumeScrollDelta() {
1665
+ const delta = this.getScrollDelta();
1666
+ this.scrollDeltaX = 0;
1667
+ this.scrollDeltaY = 0;
1668
+ return delta;
1669
+ }
1670
+ getMousePosition() {
1671
+ return {
1672
+ x: this.mousePosition.x,
1673
+ y: this.mousePosition.y
1674
+ };
1675
+ }
1676
+ getMouseDelta() {
1677
+ return {
1678
+ x: this.mouseDeltaX,
1679
+ y: this.mouseDeltaY
1680
+ };
1681
+ }
1682
+ consumeMouseDelta() {
1683
+ const delta = this.getMouseDelta();
1684
+ this.mouseDeltaX = 0;
1685
+ this.mouseDeltaY = 0;
1686
+ return delta;
1687
+ }
1688
+ update(_world, _deltaTime) {
1689
+ this.down.clear();
1690
+ this.up.clear();
1691
+ this.downMouse.clear();
1692
+ this.upMouse.clear();
1693
+ this.scrollDeltaX = this.pendingScrollDeltaX;
1694
+ this.scrollDeltaY = this.pendingScrollDeltaY;
1695
+ this.mouseDeltaX = this.pendingMouseDeltaX;
1696
+ this.mouseDeltaY = this.pendingMouseDeltaY;
1697
+ for (const key of this.pendingDown) {
1698
+ this.down.add(key);
1699
+ }
1700
+ for (const key of this.pendingUp) {
1701
+ this.up.add(key);
1702
+ }
1703
+ for (const button of this.pendingMouseDown) {
1704
+ this.downMouse.add(button);
1705
+ }
1706
+ for (const button of this.pendingMouseUp) {
1707
+ this.upMouse.add(button);
1708
+ }
1709
+ this.pendingDown.clear();
1710
+ this.pendingUp.clear();
1711
+ this.pendingMouseDown.clear();
1712
+ this.pendingMouseUp.clear();
1713
+ this.pendingScrollDeltaX = 0;
1714
+ this.pendingScrollDeltaY = 0;
1715
+ this.pendingMouseDeltaX = 0;
1716
+ this.pendingMouseDeltaY = 0;
1717
+ }
1718
+ dispose() {
1719
+ if (typeof window !== "undefined") {
1720
+ window.removeEventListener("keydown", this.onKeyDown);
1721
+ window.removeEventListener("keyup", this.onKeyUp);
1722
+ window.removeEventListener("mousedown", this.onMouseDown);
1723
+ window.removeEventListener("mouseup", this.onMouseUp);
1724
+ document.removeEventListener("mousemove", this.onMouseMove);
1725
+ window.removeEventListener("wheel", this.onMouseWheel);
1726
+ window.removeEventListener("blur", this.onWindowBlur);
1727
+ document.removeEventListener("pointerlockchange", this.onPointerLockChange);
1728
+ document.removeEventListener("pointerlockerror", this.onPointerLockError);
1729
+ }
1730
+ this.clearAll();
1731
+ }
1732
+ clearAll() {
1733
+ this.held.clear();
1734
+ this.down.clear();
1735
+ this.up.clear();
1736
+ this.pendingDown.clear();
1737
+ this.pendingUp.clear();
1738
+ this.heldMouse.clear();
1739
+ this.downMouse.clear();
1740
+ this.upMouse.clear();
1741
+ this.pendingMouseDown.clear();
1742
+ this.pendingMouseUp.clear();
1743
+ this.scrollDeltaX = 0;
1744
+ this.scrollDeltaY = 0;
1745
+ this.pendingScrollDeltaX = 0;
1746
+ this.pendingScrollDeltaY = 0;
1747
+ this.mouseDeltaX = 0;
1748
+ this.mouseDeltaY = 0;
1749
+ this.pendingMouseDeltaX = 0;
1750
+ this.pendingMouseDeltaY = 0;
1751
+ this.mousePosition = { x: 0, y: 0 };
1752
+ }
1753
+ };
1754
+ __name(_InputSystem, "InputSystem");
1755
+ var InputSystem = _InputSystem;
1756
+ var MIN_LIGHT_DISTANCE = 0;
1757
+ var MIN_LIGHT_INTENSITY = 0;
1758
+ var MIN_AREA_SIZE = 0.01;
1759
+ function applyLightValues(lightComponent) {
1760
+ const { light, values } = lightComponent;
1761
+ if (typeof values.color === "string") {
1762
+ light.color.set(values.color);
1763
+ }
1764
+ if (Number.isFinite(values.intensity)) {
1765
+ light.intensity = Math.max(MIN_LIGHT_INTENSITY, values.intensity);
1766
+ }
1767
+ light.frustumCulled = Boolean(values.frustumCulling);
1768
+ if ("castShadow" in light) {
1769
+ light.castShadow = Boolean(
1770
+ values.castShadow
1771
+ );
1772
+ }
1773
+ if (light instanceof THREE7.PointLight) {
1774
+ if (typeof values.distance === "number" && Number.isFinite(values.distance)) {
1775
+ light.distance = Math.max(MIN_LIGHT_DISTANCE, values.distance);
1776
+ }
1777
+ if (typeof values.decay === "number" && Number.isFinite(values.decay)) {
1778
+ light.decay = Math.max(0, values.decay);
1779
+ }
1780
+ }
1781
+ if (light instanceof THREE7.SpotLight) {
1782
+ if (typeof values.distance === "number" && Number.isFinite(values.distance)) {
1783
+ light.distance = Math.max(MIN_LIGHT_DISTANCE, values.distance);
1784
+ }
1785
+ if (typeof values.decay === "number" && Number.isFinite(values.decay)) {
1786
+ light.decay = Math.max(0, values.decay);
1787
+ }
1788
+ if (typeof values.angle === "number" && Number.isFinite(values.angle)) {
1789
+ light.angle = Math.max(0, Math.min(Math.PI / 2, values.angle));
1790
+ }
1791
+ if (typeof values.penumbra === "number" && Number.isFinite(values.penumbra)) {
1792
+ light.penumbra = Math.max(0, Math.min(1, values.penumbra));
1793
+ }
1794
+ }
1795
+ if (light instanceof THREE7.RectAreaLight) {
1796
+ if (typeof values.width === "number" && Number.isFinite(values.width)) {
1797
+ light.width = Math.max(MIN_AREA_SIZE, values.width);
1798
+ }
1799
+ if (typeof values.height === "number" && Number.isFinite(values.height)) {
1800
+ light.height = Math.max(MIN_AREA_SIZE, values.height);
1801
+ }
1802
+ }
1803
+ }
1804
+ __name(applyLightValues, "applyLightValues");
1805
+ var _LightSyncSystem = class _LightSyncSystem {
1806
+ constructor() {
1807
+ this.signatures = /* @__PURE__ */ new Map();
1808
+ }
1809
+ update(world) {
1810
+ const entityIds = world.query(LightComponent);
1811
+ const alive = new Set(entityIds);
1812
+ for (const trackedId of this.signatures.keys()) {
1813
+ if (!alive.has(trackedId)) {
1814
+ this.signatures.delete(trackedId);
1815
+ }
1816
+ }
1817
+ for (const entityId of entityIds) {
1818
+ const lightComponent = world.getComponent(entityId, LightComponent);
1819
+ if (!lightComponent) {
1820
+ continue;
1821
+ }
1822
+ const signature = JSON.stringify(lightComponent.values);
1823
+ if (this.signatures.get(entityId) === signature) {
1824
+ continue;
1825
+ }
1826
+ applyLightValues(lightComponent);
1827
+ this.signatures.set(entityId, signature);
1828
+ }
1829
+ }
1830
+ };
1831
+ __name(_LightSyncSystem, "LightSyncSystem");
1832
+ var LightSyncSystem = _LightSyncSystem;
1833
+ var materialTextureKeyMap = {
1834
+ textureMap: "map",
1835
+ alphaTextureMap: "alphaMap"
1836
+ };
1837
+ var materialTextureSlots = [
1838
+ "map",
1839
+ "alphaMap",
1840
+ "normalMap",
1841
+ "roughnessMap",
1842
+ "metalnessMap",
1843
+ "aoMap",
1844
+ "emissiveMap",
1845
+ "bumpMap",
1846
+ "displacementMap",
1847
+ "lightMap",
1848
+ "envMap"
1849
+ ];
1850
+ function resolveMaterialPropertyKey(key) {
1851
+ return materialTextureKeyMap[key] ?? key;
1852
+ }
1853
+ __name(resolveMaterialPropertyKey, "resolveMaterialPropertyKey");
1854
+ function createMaterialByType(type) {
1855
+ if (type === "basic") {
1856
+ return new THREE7.MeshBasicMaterial();
1857
+ }
1858
+ if (type === "phong") {
1859
+ return new THREE7.MeshPhongMaterial();
1860
+ }
1861
+ if (type === "physical") {
1862
+ return new THREE7.MeshPhysicalMaterial();
1863
+ }
1864
+ return new THREE7.MeshStandardMaterial();
1865
+ }
1866
+ __name(createMaterialByType, "createMaterialByType");
1867
+ function replaceMaterialAcrossObject(object, previous, next) {
1868
+ object.traverse((child) => {
1869
+ const mesh = child;
1870
+ const currentMaterial = mesh.material;
1871
+ if (!currentMaterial) {
1872
+ return;
1873
+ }
1874
+ if (Array.isArray(currentMaterial)) {
1875
+ let changed = false;
1876
+ const updated = currentMaterial.map((material) => {
1877
+ if (material === previous) {
1878
+ changed = true;
1879
+ return next;
1880
+ }
1881
+ return material;
1882
+ });
1883
+ if (changed) {
1884
+ mesh.material = updated;
1885
+ }
1886
+ return;
1887
+ }
1888
+ if (currentMaterial === previous) {
1889
+ mesh.material = next;
1890
+ }
1891
+ });
1892
+ }
1893
+ __name(replaceMaterialAcrossObject, "replaceMaterialAcrossObject");
1894
+ function extractObjectMaterials(object) {
1895
+ const materials = [];
1896
+ object.traverse((child) => {
1897
+ const mesh = child;
1898
+ const currentMaterial = mesh.material;
1899
+ if (!currentMaterial) {
1900
+ return;
1901
+ }
1902
+ const addMaterial = /* @__PURE__ */ __name((material) => {
1903
+ if (!materials.includes(material)) {
1904
+ materials.push(material);
1905
+ }
1906
+ }, "addMaterial");
1907
+ if (Array.isArray(currentMaterial)) {
1908
+ for (const material of currentMaterial) {
1909
+ addMaterial(material);
1910
+ }
1911
+ return;
1912
+ }
1913
+ addMaterial(currentMaterial);
1914
+ });
1915
+ return materials;
1916
+ }
1917
+ __name(extractObjectMaterials, "extractObjectMaterials");
1918
+ function applyTextureFiltering(material, filtering) {
1919
+ const sharp = filtering === "sharp";
1920
+ const target = material;
1921
+ for (const slot of materialTextureSlots) {
1922
+ const texture = target[slot];
1923
+ if (!texture || !(texture instanceof THREE7.Texture)) {
1924
+ continue;
1925
+ }
1926
+ const useMipmaps = texture.generateMipmaps !== false;
1927
+ texture.magFilter = sharp ? THREE7.NearestFilter : THREE7.LinearFilter;
1928
+ texture.minFilter = useMipmaps ? sharp ? THREE7.NearestMipmapNearestFilter : THREE7.LinearMipmapLinearFilter : sharp ? THREE7.NearestFilter : THREE7.LinearFilter;
1929
+ texture.needsUpdate = true;
1930
+ }
1931
+ material.needsUpdate = true;
1932
+ }
1933
+ __name(applyTextureFiltering, "applyTextureFiltering");
1934
+ function setTextureMipmaps(material, enabled) {
1935
+ const target = material;
1936
+ for (const slot of materialTextureSlots) {
1937
+ const texture = target[slot];
1938
+ if (!texture || !(texture instanceof THREE7.Texture)) {
1939
+ continue;
1940
+ }
1941
+ texture.generateMipmaps = enabled;
1942
+ const sharp = texture.magFilter === THREE7.NearestFilter;
1943
+ texture.minFilter = enabled ? sharp ? THREE7.NearestMipmapNearestFilter : THREE7.LinearMipmapLinearFilter : sharp ? THREE7.NearestFilter : THREE7.LinearFilter;
1944
+ texture.needsUpdate = true;
1945
+ }
1946
+ material.needsUpdate = true;
1947
+ }
1948
+ __name(setTextureMipmaps, "setTextureMipmaps");
1949
+ function assignMaterialTexture(material, rawKey, url, textureCache) {
1950
+ const target = material;
1951
+ const key = resolveMaterialPropertyKey(rawKey);
1952
+ let texture = textureCache.get(url);
1953
+ if (!texture) {
1954
+ texture = new THREE7.TextureLoader().load(url);
1955
+ textureCache.set(url, texture);
1956
+ }
1957
+ target[key] = texture;
1958
+ }
1959
+ __name(assignMaterialTexture, "assignMaterialTexture");
1960
+ function clearMaterialTexture(material, rawKey) {
1961
+ const target = material;
1962
+ const key = resolveMaterialPropertyKey(rawKey);
1963
+ target[key] = null;
1964
+ }
1965
+ __name(clearMaterialTexture, "clearMaterialTexture");
1966
+ function applyMaterialState(material, value, textureCache) {
1967
+ const target = material;
1968
+ if (target.color && typeof target.color.set === "function") {
1969
+ target.color.set(value.color);
1970
+ }
1971
+ if (typeof target.roughness === "number") {
1972
+ target.roughness = value.roughness;
1973
+ }
1974
+ if (typeof target.metalness === "number") {
1975
+ target.metalness = value.metalness;
1976
+ }
1977
+ if (target.normalScale && typeof target.normalScale.set === "function") {
1978
+ target.normalScale.set(
1979
+ value.normalScale,
1980
+ value.normalScale
1981
+ );
1982
+ }
1983
+ target.opacity = value.opacity;
1984
+ if (target.emissive && typeof target.emissive.set === "function") {
1985
+ target.emissive.set(value.emissive);
1986
+ }
1987
+ if (typeof target.emissiveIntensity === "number") {
1988
+ target.emissiveIntensity = value.emissiveIntensity;
1989
+ }
1990
+ target.side = value.side;
1991
+ target.blending = value.blending;
1992
+ target.depthTest = value.depthTest;
1993
+ target.depthWrite = value.depthWrite;
1994
+ target.wireframe = value.wireframe;
1995
+ target.transparent = value.transparent;
1996
+ const textureEntries = [
1997
+ ["textureMap", value.textureMap],
1998
+ ["alphaTextureMap", value.alphaTextureMap],
1999
+ ["normalMap", value.normalMap],
2000
+ ["roughnessMap", value.roughnessMap],
2001
+ ["metalnessMap", value.metalnessMap],
2002
+ ["aoMap", value.aoMap],
2003
+ ["emissiveMap", value.emissiveMap],
2004
+ ["bumpMap", value.bumpMap],
2005
+ ["displacementMap", value.displacementMap],
2006
+ ["lightMap", value.lightMap],
2007
+ ["envMap", value.envMap]
2008
+ ];
2009
+ for (const [key, url] of textureEntries) {
2010
+ if (typeof url === "string" && url.length > 0) {
2011
+ assignMaterialTexture(material, key, url, textureCache);
2012
+ } else {
2013
+ clearMaterialTexture(material, key);
2014
+ }
2015
+ }
2016
+ applyTextureFiltering(material, value.textureFiltering);
2017
+ setTextureMipmaps(material, value.useMipmaps);
2018
+ material.needsUpdate = true;
2019
+ }
2020
+ __name(applyMaterialState, "applyMaterialState");
2021
+ var _MaterialSyncSystem = class _MaterialSyncSystem {
2022
+ constructor() {
2023
+ this.signatures = /* @__PURE__ */ new Map();
2024
+ this.textureCache = /* @__PURE__ */ new Map();
2025
+ }
2026
+ update(world) {
2027
+ const entityIds = world.query(MaterialComponent);
2028
+ const alive = new Set(entityIds);
2029
+ for (const trackedId of this.signatures.keys()) {
2030
+ if (!alive.has(trackedId)) {
2031
+ this.signatures.delete(trackedId);
2032
+ }
2033
+ }
2034
+ for (const entityId of entityIds) {
2035
+ const materialComponent = world.getComponent(
2036
+ entityId,
2037
+ MaterialComponent
2038
+ );
2039
+ if (!materialComponent) {
2040
+ continue;
2041
+ }
2042
+ const signature = JSON.stringify(materialComponent.values);
2043
+ if (this.signatures.get(entityId) === signature) {
2044
+ continue;
2045
+ }
2046
+ const object = world.getComponent(entityId, Object3DRef)?.object;
2047
+ const objectMaterials = object ? extractObjectMaterials(object) : [];
2048
+ for (let index = 0; index < materialComponent.values.length; index += 1) {
2049
+ const value = materialComponent.values[index];
2050
+ if (!value) {
2051
+ continue;
2052
+ }
2053
+ const previousMaterial = materialComponent.materials[index];
2054
+ if (!previousMaterial) {
2055
+ continue;
2056
+ }
2057
+ if (object) {
2058
+ const currentObjectMaterial = objectMaterials[index];
2059
+ if (currentObjectMaterial && currentObjectMaterial !== previousMaterial) {
2060
+ replaceMaterialAcrossObject(
2061
+ object,
2062
+ currentObjectMaterial,
2063
+ previousMaterial
2064
+ );
2065
+ objectMaterials[index] = previousMaterial;
2066
+ }
2067
+ }
2068
+ const nextType = createMaterialByType(value.type).type;
2069
+ let targetMaterial = previousMaterial;
2070
+ if (previousMaterial.type !== nextType) {
2071
+ const replacement = createMaterialByType(value.type);
2072
+ if (object) {
2073
+ replaceMaterialAcrossObject(object, previousMaterial, replacement);
2074
+ objectMaterials[index] = replacement;
2075
+ }
2076
+ materialComponent.materials[index] = replacement;
2077
+ targetMaterial = replacement;
2078
+ if (index === 0) {
2079
+ materialComponent.material = replacement;
2080
+ }
2081
+ previousMaterial.dispose();
2082
+ }
2083
+ applyMaterialState(targetMaterial, value, this.textureCache);
2084
+ }
2085
+ this.signatures.set(entityId, JSON.stringify(materialComponent.values));
2086
+ }
2087
+ }
2088
+ dispose() {
2089
+ for (const texture of this.textureCache.values()) {
2090
+ texture.dispose();
2091
+ }
2092
+ this.textureCache.clear();
2093
+ this.signatures.clear();
2094
+ }
2095
+ };
2096
+ __name(_MaterialSyncSystem, "MaterialSyncSystem");
2097
+ var MaterialSyncSystem = _MaterialSyncSystem;
2098
+ var MIN_DIMENSION = 0.01;
2099
+ var MIN_RADIUS = 1e-3;
2100
+ function sanitizeDimension(value) {
2101
+ return Number.isFinite(value) ? Math.max(MIN_DIMENSION, value) : MIN_DIMENSION;
2102
+ }
2103
+ __name(sanitizeDimension, "sanitizeDimension");
2104
+ function sanitizeRadius(value) {
2105
+ return Number.isFinite(value) ? Math.max(MIN_RADIUS, value) : MIN_RADIUS;
2106
+ }
2107
+ __name(sanitizeRadius, "sanitizeRadius");
2108
+ function sanitizeMeshParameters(component) {
2109
+ switch (component.kind) {
2110
+ case "cube": {
2111
+ const params = component.parameters;
2112
+ const fallback = DEFAULT_MESH_GEOMETRY_PARAMETERS.cube;
2113
+ return {
2114
+ width: sanitizeDimension(params.width ?? fallback.width),
2115
+ height: sanitizeDimension(params.height ?? fallback.height),
2116
+ depth: sanitizeDimension(params.depth ?? fallback.depth)
2117
+ };
2118
+ }
2119
+ case "plane": {
2120
+ const params = component.parameters;
2121
+ const fallback = DEFAULT_MESH_GEOMETRY_PARAMETERS.plane;
2122
+ return {
2123
+ width: sanitizeDimension(params.width ?? fallback.width),
2124
+ height: sanitizeDimension(params.height ?? fallback.height)
2125
+ };
2126
+ }
2127
+ case "sphere": {
2128
+ const params = component.parameters;
2129
+ const fallback = DEFAULT_MESH_GEOMETRY_PARAMETERS.sphere;
2130
+ return {
2131
+ radius: sanitizeRadius(params.radius ?? fallback.radius)
2132
+ };
2133
+ }
2134
+ case "cylinder":
2135
+ case "capsule": {
2136
+ const params = component.parameters;
2137
+ const fallback = component.kind === "cylinder" ? DEFAULT_MESH_GEOMETRY_PARAMETERS.cylinder : DEFAULT_MESH_GEOMETRY_PARAMETERS.capsule;
2138
+ return {
2139
+ radius: sanitizeRadius(params.radius ?? fallback.radius),
2140
+ height: sanitizeDimension(params.height ?? fallback.height)
2141
+ };
2142
+ }
2143
+ case "model":
2144
+ return {};
2145
+ }
2146
+ }
2147
+ __name(sanitizeMeshParameters, "sanitizeMeshParameters");
2148
+ function resolvePrimaryMesh(object) {
2149
+ if (!object) {
2150
+ return null;
2151
+ }
2152
+ if (object instanceof THREE7.Mesh) {
2153
+ return object;
2154
+ }
2155
+ let found = null;
2156
+ object.traverse((child) => {
2157
+ if (!found && child instanceof THREE7.Mesh) {
2158
+ found = child;
2159
+ }
2160
+ });
2161
+ return found;
2162
+ }
2163
+ __name(resolvePrimaryMesh, "resolvePrimaryMesh");
2164
+ function applyGeometry(component) {
2165
+ if (component.kind === "model") {
2166
+ return;
2167
+ }
2168
+ const mesh = resolvePrimaryMesh(component.object);
2169
+ if (!mesh) {
2170
+ return;
2171
+ }
2172
+ const sanitized = sanitizeMeshParameters(component);
2173
+ component.parameters = sanitized;
2174
+ let nextGeometry;
2175
+ switch (component.kind) {
2176
+ case "cube": {
2177
+ const params = sanitized;
2178
+ nextGeometry = new THREE7.BoxGeometry(params.width, params.height, params.depth);
2179
+ break;
2180
+ }
2181
+ case "plane": {
2182
+ const params = sanitized;
2183
+ nextGeometry = new THREE7.PlaneGeometry(params.width, params.height);
2184
+ break;
2185
+ }
2186
+ case "sphere": {
2187
+ const params = sanitized;
2188
+ nextGeometry = new THREE7.SphereGeometry(params.radius, 24, 24);
2189
+ break;
2190
+ }
2191
+ case "cylinder": {
2192
+ const params = sanitized;
2193
+ nextGeometry = new THREE7.CylinderGeometry(
2194
+ params.radius,
2195
+ params.radius,
2196
+ params.height,
2197
+ 20
2198
+ );
2199
+ break;
2200
+ }
2201
+ case "capsule": {
2202
+ const params = sanitized;
2203
+ nextGeometry = new THREE7.CapsuleGeometry(params.radius, params.height, 4, 8);
2204
+ break;
2205
+ }
2206
+ default:
2207
+ return;
2208
+ }
2209
+ const previousGeometry = mesh.geometry;
2210
+ mesh.geometry = nextGeometry;
2211
+ previousGeometry.dispose();
2212
+ }
2213
+ __name(applyGeometry, "applyGeometry");
2214
+ function applyShadowFlags(component) {
2215
+ if (!component.object) {
2216
+ return;
2217
+ }
2218
+ component.object.traverse((child) => {
2219
+ if (child instanceof THREE7.Mesh) {
2220
+ child.castShadow = component.castShadow;
2221
+ child.receiveShadow = component.receiveShadow;
2222
+ }
2223
+ });
2224
+ }
2225
+ __name(applyShadowFlags, "applyShadowFlags");
2226
+ var _MeshGeometrySystem = class _MeshGeometrySystem {
2227
+ constructor() {
2228
+ this.geometrySignatures = /* @__PURE__ */ new Map();
2229
+ this.shadowSignatures = /* @__PURE__ */ new Map();
2230
+ }
2231
+ update(world) {
2232
+ const entityIds = world.query(MeshGeometryComponent);
2233
+ const alive = new Set(entityIds);
2234
+ for (const trackedId of this.geometrySignatures.keys()) {
2235
+ if (!alive.has(trackedId)) {
2236
+ this.geometrySignatures.delete(trackedId);
2237
+ this.shadowSignatures.delete(trackedId);
2238
+ }
2239
+ }
2240
+ for (const entityId of entityIds) {
2241
+ const meshGeometry = world.getComponent(
2242
+ entityId,
2243
+ MeshGeometryComponent
2244
+ );
2245
+ if (!meshGeometry) {
2246
+ continue;
2247
+ }
2248
+ if (!meshGeometry.object) {
2249
+ const objectRef = world.getComponent(entityId, Object3DRef);
2250
+ if (objectRef?.object) {
2251
+ meshGeometry.object = objectRef.object;
2252
+ }
2253
+ }
2254
+ const geometrySignature = `${meshGeometry.kind}:${JSON.stringify(meshGeometry.parameters)}:${meshGeometry.object?.uuid ?? ""}`;
2255
+ const shadowSignature = `${meshGeometry.castShadow}:${meshGeometry.receiveShadow}:${meshGeometry.object?.uuid ?? ""}`;
2256
+ if (this.geometrySignatures.get(entityId) !== geometrySignature) {
2257
+ applyGeometry(meshGeometry);
2258
+ this.geometrySignatures.set(
2259
+ entityId,
2260
+ `${meshGeometry.kind}:${JSON.stringify(meshGeometry.parameters)}:${meshGeometry.object?.uuid ?? ""}`
2261
+ );
2262
+ }
2263
+ if (this.shadowSignatures.get(entityId) !== shadowSignature) {
2264
+ applyShadowFlags(meshGeometry);
2265
+ this.shadowSignatures.set(entityId, shadowSignature);
2266
+ }
2267
+ }
2268
+ }
2269
+ };
2270
+ __name(_MeshGeometrySystem, "MeshGeometrySystem");
2271
+ var MeshGeometrySystem = _MeshGeometrySystem;
2272
+
2273
+ // core/systems/RenderSystem.ts
2274
+ var _RenderSystem = class _RenderSystem {
2275
+ constructor(renderer, scene, camera, afterRender) {
2276
+ this.renderer = renderer;
2277
+ this.scene = scene;
2278
+ this.camera = camera;
2279
+ this.afterRender = afterRender;
2280
+ }
2281
+ update(_world) {
2282
+ if (this.scene.userData.ecsPostprocessingComposerActive === true) {
2283
+ const composer = this.scene.userData.ecsPostprocessingComposer;
2284
+ if (composer) {
2285
+ const width = Math.max(1, this.renderer.domElement.clientWidth);
2286
+ const height = Math.max(1, this.renderer.domElement.clientHeight);
2287
+ composer.setSize(width, height);
2288
+ composer.render();
2289
+ } else {
2290
+ this.renderer.render(this.scene, this.camera);
2291
+ }
2292
+ this.afterRender?.();
2293
+ return;
2294
+ }
2295
+ this.renderer.render(this.scene, this.camera);
2296
+ this.afterRender?.();
2297
+ }
2298
+ };
2299
+ __name(_RenderSystem, "RenderSystem");
2300
+ var RenderSystem = _RenderSystem;
2301
+ var _Behaviour = class _Behaviour {
2302
+ /**
2303
+ * Engine-managed constructor. Hosts (`ScriptBehaviourSystem`) instantiate
2304
+ * subclasses with the owning world, the entity id, and the script's `data`
2305
+ * payload. User code should not call this directly.
2306
+ *
2307
+ * @param world - The owning ECS world.
2308
+ * @param entityId - The entity this script is bound to.
2309
+ * @param component - The `ScriptComponent.data` payload, or any object that
2310
+ * should be exposed to the script as `this.data`.
2311
+ */
2312
+ constructor(world, entityId, component) {
2313
+ /**
2314
+ * Inspector-bound payload from the entity's `ScriptComponent`. Override the
2315
+ * type on subclasses with `declare data: MyDataShape` to get type safety
2316
+ * inside hooks. Saved with the project so values persist across reloads.
2317
+ */
2318
+ this.data = {};
2319
+ /**
2320
+ * Seconds elapsed since the last frame. Set by the engine before each
2321
+ * {@link Behaviour.onUpdate}.
2322
+ */
2323
+ this.deltaTime = 0;
2324
+ this.world = world;
2325
+ this.entityId = entityId;
2326
+ if (component) this.data = component;
2327
+ this.entity = this.getEntity();
2328
+ this.threeRef = this.getComponent(Object3DRef);
2329
+ this.transform = this.getComponent(TransformComponent);
2330
+ }
2331
+ /**
2332
+ * Engine-managed per-frame entry point. Refreshes {@link Behaviour.deltaTime}
2333
+ * and delegates to {@link Behaviour.onUpdate}.
2334
+ *
2335
+ * @remarks Do **not** override this method — override
2336
+ * {@link Behaviour.onUpdate} instead.
2337
+ *
2338
+ * @param world - The owning world (may differ from the constructor world
2339
+ * after hot reload).
2340
+ * @param deltaTime - Seconds since the last frame.
2341
+ */
2342
+ update(world, deltaTime) {
2343
+ this.deltaTime = deltaTime;
2344
+ this.world = world;
2345
+ this.onUpdate();
2346
+ }
2347
+ /**
2348
+ * Optional cleanup hook invoked when the script is detached or the entity
2349
+ * is destroyed. Override to release timers, listeners, or other resources.
2350
+ *
2351
+ * @param world - The owning world at disposal time.
2352
+ */
2353
+ dispose(world) {
2354
+ }
2355
+ /**
2356
+ * Returns the entity's world-space position as a new `THREE.Vector3`, or
2357
+ * `null` if the entity has no scene presence.
2358
+ */
2359
+ getWorldPosition() {
2360
+ if (!this.threeRef) {
2361
+ return null;
2362
+ }
2363
+ const position = new THREE7.Vector3();
2364
+ this.threeRef.object.getWorldPosition(position);
2365
+ return position;
2366
+ }
2367
+ /**
2368
+ * Returns the entity's forward direction in world space (the +Z axis of its
2369
+ * world matrix), or `null` if the entity has no scene presence.
2370
+ */
2371
+ getWorldDirection() {
2372
+ if (!this.threeRef) {
2373
+ return null;
2374
+ }
2375
+ const target = new THREE7.Vector3();
2376
+ this.threeRef.object.getWorldDirection(target);
2377
+ return target;
2378
+ }
2379
+ /**
2380
+ * Returns a unit vector pointing from this entity toward the given world
2381
+ * position, or `null` if the entity has no scene presence.
2382
+ *
2383
+ * @param targetPosition - Destination point in world space.
2384
+ */
2385
+ directionTo(targetPosition) {
2386
+ const currentPosition = this.getWorldPosition();
2387
+ if (!currentPosition) {
2388
+ return null;
2389
+ }
2390
+ return targetPosition.clone().sub(currentPosition).normalize();
2391
+ }
2392
+ /**
2393
+ * Returns the world-space distance from this entity to the given position,
2394
+ * or `null` if the entity has no scene presence.
2395
+ *
2396
+ * @param targetPosition - Destination point in world space.
2397
+ */
2398
+ distanceTo(targetPosition) {
2399
+ const currentPosition = this.getWorldPosition();
2400
+ if (!currentPosition) {
2401
+ return null;
2402
+ }
2403
+ return currentPosition.distanceTo(targetPosition);
2404
+ }
2405
+ /**
2406
+ * Linearly interpolates the entity's position toward `targetPosition` and
2407
+ * writes the result back through {@link TransformComponent}. No-op if the
2408
+ * entity has no scene presence.
2409
+ *
2410
+ * @param targetPosition - Destination point in world space.
2411
+ * @param alpha - Interpolation factor in [0, 1]. Multiply by `deltaTime`
2412
+ * for frame-rate-independent smoothing.
2413
+ */
2414
+ lerpTo(targetPosition, alpha) {
2415
+ if (!this.threeRef) {
2416
+ return;
2417
+ }
2418
+ const currentPosition = this.getWorldPosition();
2419
+ if (!currentPosition) {
2420
+ return;
2421
+ }
2422
+ const newPosition = currentPosition.lerp(targetPosition, alpha);
2423
+ this.transform.setPosition(newPosition);
2424
+ }
2425
+ /**
2426
+ * Spherically interpolates the entity's rotation toward `targetRotation`
2427
+ * and writes the result back through {@link TransformComponent}. No-op if
2428
+ * the entity has no scene presence.
2429
+ *
2430
+ * @param targetRotation - Destination orientation as a quaternion.
2431
+ * @param alpha - Interpolation factor in [0, 1].
2432
+ */
2433
+ slerpTo(targetRotation, alpha) {
2434
+ if (!this.threeRef) {
2435
+ return;
2436
+ }
2437
+ const rotation = new THREE7.Quaternion();
2438
+ this.threeRef.object.getWorldQuaternion(rotation);
2439
+ rotation.slerp(targetRotation, alpha);
2440
+ this.transform.setRotation(rotation);
2441
+ }
2442
+ /**
2443
+ * Rotates the entity to face `targetPosition` in world space and writes the
2444
+ * resulting orientation back through {@link TransformComponent}. No-op if
2445
+ * the entity has no scene presence.
2446
+ *
2447
+ * @param targetPosition - Point in world space to face.
2448
+ */
2449
+ lookAt(targetPosition) {
2450
+ if (!this.threeRef) {
2451
+ return;
2452
+ }
2453
+ const clone = this.threeRef.object.clone();
2454
+ const rotation = new THREE7.Quaternion();
2455
+ clone.lookAt(targetPosition);
2456
+ clone.getWorldQuaternion(rotation);
2457
+ this.transform.setRotation(rotation);
2458
+ }
2459
+ /** Returns every component currently attached to this entity. */
2460
+ getComponents() {
2461
+ return this.world.getEntityById(this.entityId)?.components ?? [];
2462
+ }
2463
+ /**
2464
+ * Returns the entity's component of the given class, or `null` if it has
2465
+ * no such component.
2466
+ *
2467
+ * @typeParam T - Concrete component type.
2468
+ * @param componentClass - Component class constructor to look up.
2469
+ *
2470
+ * @example
2471
+ * ```ts
2472
+ * const mesh = this.getComponent(MeshComponent);
2473
+ * if (mesh) console.log(mesh.geometryRef);
2474
+ * ```
2475
+ */
2476
+ getComponent(componentClass) {
2477
+ return this.world.getComponent(this.entityId, componentClass) ?? null;
2478
+ }
2479
+ /**
2480
+ * Returns the latest {@link WorldEntityView} snapshot for this entity, or
2481
+ * `null` if it was destroyed.
2482
+ */
2483
+ getEntity() {
2484
+ return this.world.getEntityById(this.entityId);
2485
+ }
2486
+ /**
2487
+ * Resolves the entity's parent from the {@link ParentId} component, if any.
2488
+ *
2489
+ * @returns A {@link ParentLookup} with the parent component reference and
2490
+ * the parent entity view (or `null` if the entity is at the root).
2491
+ */
2492
+ getParent() {
2493
+ const parentIdComponent = this.getComponent(ParentId);
2494
+ const parentEntityId = parentIdComponent?.value ?? null;
2495
+ if (parentEntityId === null) {
2496
+ return {
2497
+ parentIdComponent,
2498
+ parent: null
2499
+ };
2500
+ }
2501
+ return {
2502
+ parentIdComponent,
2503
+ parent: this.world.getEntityById(parentEntityId)
2504
+ };
2505
+ }
2506
+ /**
2507
+ * Returns every direct child entity of this one (entities whose
2508
+ * {@link ParentId} matches `entityId`).
2509
+ */
2510
+ getChildren() {
2511
+ return this.world.getAllEntities().filter((entity) => {
2512
+ const parentIdComponent = entity.components.find(
2513
+ (component) => component instanceof ParentId
2514
+ );
2515
+ return parentIdComponent?.value === this.entityId;
2516
+ });
2517
+ }
2518
+ /**
2519
+ * Called once before the first {@link Behaviour.onUpdate}. Override to
2520
+ * default and validate {@link Behaviour.data}, cache references, or set
2521
+ * initial state.
2522
+ *
2523
+ * @remarks
2524
+ * Also called in editor mode when `executeInEditor` is `true` on the script
2525
+ * entry.
2526
+ */
2527
+ init() {
2528
+ }
2529
+ /**
2530
+ * Called every frame while the script is enabled. Override with the
2531
+ * script's main per-frame logic.
2532
+ *
2533
+ * @remarks
2534
+ * Also called every frame in editor mode when `executeInEditor` is `true`.
2535
+ * Access the Three.js scene with `this.world.getScene()` for editor-only
2536
+ * rendering work such as custom shaders or procedural geometry.
2537
+ */
2538
+ onUpdate() {
2539
+ }
2540
+ /** Called when the editor selects this entity. Optional UX hook. */
2541
+ onSelect() {
2542
+ }
2543
+ /** Called when the editor deselects this entity. Optional UX hook. */
2544
+ onDeselect() {
2545
+ }
2546
+ /**
2547
+ * Called when an image-tracking target this entity depends on becomes
2548
+ * visible. Optional AR hook.
2549
+ *
2550
+ * @param target - The newly-visible target entity view.
2551
+ */
2552
+ onTargetFound(target) {
2553
+ }
2554
+ /**
2555
+ * Called when an image-tracking target this entity depends on is lost.
2556
+ * Optional AR hook.
2557
+ *
2558
+ * @param target - The target entity view that became invisible.
2559
+ */
2560
+ onTargetLost(target) {
2561
+ }
2562
+ };
2563
+ __name(_Behaviour, "Behaviour");
2564
+ /**
2565
+ * Static marker used by `ScriptBehaviourSystem` to detect `Behaviour`
2566
+ * subclasses across bundle-identity splits (esbuild may produce a second
2567
+ * copy of the package when scripts are bundled, breaking `instanceof`).
2568
+ * Inherited by every subclass via the prototype chain.
2569
+ *
2570
+ * @internal
2571
+ */
2572
+ _Behaviour.__reluBehaviourClass = true;
2573
+ var Behaviour = _Behaviour;
2574
+
2575
+ // core/systems/ScriptBehaviourSystem.ts
2576
+ function toErrorMessage(error) {
2577
+ const sanitize = /* @__PURE__ */ __name((value) => value.replace(/localasset:\/\/[^/]+\//g, "localasset://").replace(/\/Users\/[^\s)]+/g, "[local path]"), "sanitize");
2578
+ if (error instanceof Error && error.message) {
2579
+ return sanitize(error.message);
2580
+ }
2581
+ if (typeof error === "string" && error) {
2582
+ return sanitize(error);
2583
+ }
2584
+ return "Unknown script error.";
2585
+ }
2586
+ __name(toErrorMessage, "toErrorMessage");
2587
+ function buildInstanceKey(entityId, scriptUrl, className) {
2588
+ return `${entityId}:${scriptUrl}:${className}`;
2589
+ }
2590
+ __name(buildInstanceKey, "buildInstanceKey");
2591
+ function resolveBehaviourCtor(moduleValue, className) {
2592
+ const named = moduleValue[className];
2593
+ const fallback = moduleValue.default;
2594
+ const candidate = typeof named === "function" ? named : typeof fallback === "function" ? fallback : null;
2595
+ if (!candidate) {
2596
+ return null;
2597
+ }
2598
+ if (!(candidate.prototype instanceof Behaviour)) {
2599
+ const isBehaviourSubclass = !!candidate.__reluBehaviourClass;
2600
+ if (!isBehaviourSubclass) {
2601
+ return null;
2602
+ }
2603
+ }
2604
+ return candidate;
2605
+ }
2606
+ __name(resolveBehaviourCtor, "resolveBehaviourCtor");
2607
+ function normalizeScriptData(value) {
2608
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
2609
+ }
2610
+ __name(normalizeScriptData, "normalizeScriptData");
2611
+ function isPlainObject(value) {
2612
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
2613
+ }
2614
+ __name(isPlainObject, "isPlainObject");
2615
+ function mergeValueByDefaultShape(defaultValue, currentValue) {
2616
+ if (Array.isArray(defaultValue)) {
2617
+ return Array.isArray(currentValue) ? currentValue : defaultValue;
2618
+ }
2619
+ if (isPlainObject(defaultValue)) {
2620
+ if (!isPlainObject(currentValue)) {
2621
+ return defaultValue;
2622
+ }
2623
+ const next = {};
2624
+ for (const key of Object.keys(defaultValue)) {
2625
+ next[key] = mergeValueByDefaultShape(defaultValue[key], currentValue[key]);
2626
+ }
2627
+ return next;
2628
+ }
2629
+ if (typeof defaultValue === "number") {
2630
+ return typeof currentValue === "number" ? currentValue : defaultValue;
2631
+ }
2632
+ if (typeof defaultValue === "string") {
2633
+ return typeof currentValue === "string" ? currentValue : defaultValue;
2634
+ }
2635
+ if (typeof defaultValue === "boolean") {
2636
+ return typeof currentValue === "boolean" ? currentValue : defaultValue;
2637
+ }
2638
+ if (defaultValue === null) {
2639
+ return currentValue !== void 0 ? currentValue : null;
2640
+ }
2641
+ return typeof currentValue === "undefined" ? defaultValue : currentValue;
2642
+ }
2643
+ __name(mergeValueByDefaultShape, "mergeValueByDefaultShape");
2644
+ function mergeDataByCurrentDefaults(defaults, current) {
2645
+ const next = {};
2646
+ for (const key of Object.keys(defaults)) {
2647
+ next[key] = mergeValueByDefaultShape(defaults[key], current[key]);
2648
+ }
2649
+ return next;
2650
+ }
2651
+ __name(mergeDataByCurrentDefaults, "mergeDataByCurrentDefaults");
2652
+ function isRawEntityInput(value) {
2653
+ if (!isPlainObject(value)) return false;
2654
+ return value.type === "entity";
2655
+ }
2656
+ __name(isRawEntityInput, "isRawEntityInput");
2657
+ function isRawComponentInput(value) {
2658
+ if (!isPlainObject(value)) return false;
2659
+ return value.type === "component";
2660
+ }
2661
+ __name(isRawComponentInput, "isRawComponentInput");
2662
+ function findComponentByKind(components, componentKind) {
2663
+ return components.find(
2664
+ (c) => c.constructor.name === `${componentKind}Component` || c.constructor.name === componentKind
2665
+ ) ?? null;
2666
+ }
2667
+ __name(findComponentByKind, "findComponentByKind");
2668
+ function resolveInputData(world, rawData) {
2669
+ const resolved = { ...rawData };
2670
+ for (const [key, value] of Object.entries(rawData)) {
2671
+ if (isRawEntityInput(value)) {
2672
+ const entityId = value.value;
2673
+ const entityView = typeof entityId === "number" ? world.getEntityById(entityId) : null;
2674
+ resolved[key] = { ...value, value: entityView };
2675
+ } else if (isRawComponentInput(value)) {
2676
+ const ref = value.value;
2677
+ if (isPlainObject(ref) && typeof ref.entityId === "number" && typeof ref.componentKind === "string") {
2678
+ const { entityId: refEntityId, componentKind } = ref;
2679
+ const entityView = world.getEntityById(refEntityId);
2680
+ const component = entityView ? findComponentByKind(entityView.components, componentKind) : null;
2681
+ resolved[key] = { ...value, value: component };
2682
+ }
2683
+ }
2684
+ }
2685
+ return resolved;
2686
+ }
2687
+ __name(resolveInputData, "resolveInputData");
2688
+ function serializeDataForStorage(rawData, behaviourData) {
2689
+ const result = { ...behaviourData };
2690
+ for (const [key, rawValue] of Object.entries(rawData)) {
2691
+ if (isRawEntityInput(rawValue) || isRawComponentInput(rawValue)) {
2692
+ result[key] = rawValue;
2693
+ }
2694
+ }
2695
+ return result;
2696
+ }
2697
+ __name(serializeDataForStorage, "serializeDataForStorage");
2698
+ function normalizeEntry(value, fallbackEntityId) {
2699
+ return {
2700
+ entityId: typeof value?.entityId === "number" ? value.entityId : fallbackEntityId,
2701
+ className: typeof value?.className === "string" ? value.className : "",
2702
+ scriptUrl: typeof value?.scriptUrl === "string" ? value.scriptUrl : "",
2703
+ enabled: typeof value?.enabled === "boolean" ? value.enabled : true,
2704
+ executeInEditor: typeof value?.executeInEditor === "boolean" ? value.executeInEditor : false,
2705
+ data: normalizeScriptData(value?.data),
2706
+ runtimeState: value?.runtimeState === "idle" || value?.runtimeState === "loading" || value?.runtimeState === "ready" || value?.runtimeState === "error" ? value.runtimeState : void 0,
2707
+ runtimeMessage: typeof value?.runtimeMessage === "string" ? value.runtimeMessage : void 0
2708
+ };
2709
+ }
2710
+ __name(normalizeEntry, "normalizeEntry");
2711
+ function readScriptEntries(component, entityId) {
2712
+ if (Array.isArray(component.entries) && component.entries.length > 0) {
2713
+ return component.entries.map((entry) => normalizeEntry(entry, entityId)).filter((entry) => entry.className || entry.scriptUrl);
2714
+ }
2715
+ return [];
2716
+ }
2717
+ __name(readScriptEntries, "readScriptEntries");
2718
+ function writeScriptEntries(component, entries) {
2719
+ const normalized = entries.map((entry) => normalizeEntry(entry, entry.entityId));
2720
+ component.entries = normalized;
2721
+ const active = normalized[0];
2722
+ if (!active) {
2723
+ component.scriptInstance = null;
2724
+ }
2725
+ }
2726
+ __name(writeScriptEntries, "writeScriptEntries");
2727
+ async function defaultModuleLoader(scriptUrl) {
2728
+ return await import(
2729
+ /* webpackIgnore: true */
2730
+ scriptUrl
2731
+ );
2732
+ }
2733
+ __name(defaultModuleLoader, "defaultModuleLoader");
2734
+ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
2735
+ constructor(moduleLoader, selectionContext) {
2736
+ this.instances = /* @__PURE__ */ new Map();
2737
+ this.loading = /* @__PURE__ */ new Map();
2738
+ this.selectedEntityId = null;
2739
+ // undefined = nothing queued; null = queued "deselect all"; number = queued entity
2740
+ this.pendingEntityId = void 0;
2741
+ this.pointerDownPos = null;
2742
+ this.onPointerDown = /* @__PURE__ */ __name((event) => {
2743
+ this.pointerDownPos = { x: event.clientX, y: event.clientY };
2744
+ }, "onPointerDown");
2745
+ this.onPointerUp = /* @__PURE__ */ __name((event) => {
2746
+ if (!this.pointerDownPos) return;
2747
+ const dx = event.clientX - this.pointerDownPos.x;
2748
+ const dy = event.clientY - this.pointerDownPos.y;
2749
+ this.pointerDownPos = null;
2750
+ if (Math.sqrt(dx * dx + dy * dy) > _ScriptBehaviourSystem.CLICK_THRESHOLD) return;
2751
+ this.queueRaycast(event.clientX, event.clientY);
2752
+ }, "onPointerUp");
2753
+ this.moduleLoader = moduleLoader ?? defaultModuleLoader;
2754
+ this.selectionCtx = selectionContext ?? null;
2755
+ this.raycaster = new THREE7.Raycaster();
2756
+ this.ndcPointer = new THREE7.Vector2();
2757
+ if (this.selectionCtx) {
2758
+ this.selectionCtx.domElement.addEventListener("pointerdown", this.onPointerDown);
2759
+ this.selectionCtx.domElement.addEventListener("pointerup", this.onPointerUp);
2760
+ }
2761
+ }
2762
+ // ── Raycast selection helpers ──────────────────────────────────────────────
2763
+ /** Walk up the object hierarchy to find the nearest userData.entityId. */
2764
+ resolveEntityId(object) {
2765
+ let current = object;
2766
+ while (current) {
2767
+ const id = current.userData?.entityId;
2768
+ if (typeof id === "number") return id;
2769
+ current = current.parent;
2770
+ }
2771
+ return null;
2772
+ }
2773
+ /** Convert client (screen) coordinates to normalised device coordinates. */
2774
+ toNdc(clientX, clientY) {
2775
+ if (!this.selectionCtx) return;
2776
+ const rect = this.selectionCtx.domElement.getBoundingClientRect();
2777
+ this.ndcPointer.x = (clientX - rect.left) / rect.width * 2 - 1;
2778
+ this.ndcPointer.y = -((clientY - rect.top) / rect.height) * 2 + 1;
2779
+ }
2780
+ /** Fire raycast and queue the result to be dispatched in the next update(). */
2781
+ queueRaycast(clientX, clientY) {
2782
+ if (!this.selectionCtx) return;
2783
+ this.toNdc(clientX, clientY);
2784
+ this.raycaster.setFromCamera(this.ndcPointer, this.selectionCtx.camera);
2785
+ const hits = this.raycaster.intersectObjects(this.selectionCtx.scene.children, true);
2786
+ for (const hit of hits) {
2787
+ if (hit.object.userData?.ecsPreviewHidden) continue;
2788
+ const entityId = this.resolveEntityId(hit.object);
2789
+ if (entityId !== null) {
2790
+ this.pendingEntityId = entityId;
2791
+ return;
2792
+ }
2793
+ }
2794
+ this.pendingEntityId = null;
2795
+ }
2796
+ /**
2797
+ * Apply a queued selection change.
2798
+ * Calls onDeselect() on all behaviours of the previous entity and
2799
+ * onSelect() on all behaviours of the newly selected entity.
2800
+ */
2801
+ applySelection(nextEntityId) {
2802
+ if (nextEntityId === this.selectedEntityId) return;
2803
+ const prevEntityId = this.selectedEntityId;
2804
+ this.selectedEntityId = nextEntityId;
2805
+ if (prevEntityId !== null) {
2806
+ for (const record of this.instances.values()) {
2807
+ if (record.entityId === prevEntityId) {
2808
+ try {
2809
+ record.behaviour.onDeselect();
2810
+ } catch {
2811
+ }
2812
+ }
2813
+ }
2814
+ }
2815
+ if (nextEntityId !== null) {
2816
+ for (const record of this.instances.values()) {
2817
+ if (record.entityId === nextEntityId) {
2818
+ try {
2819
+ record.behaviour.onSelect();
2820
+ } catch {
2821
+ }
2822
+ }
2823
+ }
2824
+ }
2825
+ }
2826
+ // ── ECS lifecycle ──────────────────────────────────────────────────────────
2827
+ update(world, deltaTime) {
2828
+ if (this.pendingEntityId !== void 0) {
2829
+ const next = this.pendingEntityId;
2830
+ this.pendingEntityId = void 0;
2831
+ this.applySelection(next);
2832
+ }
2833
+ const active = /* @__PURE__ */ new Map();
2834
+ const entityIds = world.query(ScriptComponent);
2835
+ for (const entityId of entityIds) {
2836
+ const scriptComponent = world.getComponent(entityId, ScriptComponent);
2837
+ if (!scriptComponent) {
2838
+ continue;
2839
+ }
2840
+ const entries = readScriptEntries(scriptComponent, entityId);
2841
+ if (entries.length === 0) {
2842
+ scriptComponent.scriptInstance = null;
2843
+ continue;
2844
+ }
2845
+ const nextEntries = [...entries];
2846
+ let hasEnabledScript = false;
2847
+ for (let entryIndex = 0; entryIndex < nextEntries.length; entryIndex += 1) {
2848
+ const entry = nextEntries[entryIndex];
2849
+ const skipInEditor = world.isEditorMode() && !entry.executeInEditor;
2850
+ if (!entry.enabled || !entry.scriptUrl || skipInEditor) {
2851
+ nextEntries[entryIndex] = {
2852
+ ...entry,
2853
+ runtimeState: skipInEditor ? "idle" : "idle",
2854
+ runtimeMessage: void 0
2855
+ };
2856
+ continue;
2857
+ }
2858
+ hasEnabledScript = true;
2859
+ const key = buildInstanceKey(entityId, entry.scriptUrl, entry.className);
2860
+ active.set(key, {
2861
+ entityId,
2862
+ scriptComponent,
2863
+ entryIndex,
2864
+ scriptEntry: entry
2865
+ });
2866
+ }
2867
+ writeScriptEntries(scriptComponent, nextEntries);
2868
+ if (!hasEnabledScript) {
2869
+ scriptComponent.scriptInstance = null;
2870
+ }
2871
+ }
2872
+ for (const [key, record] of this.instances.entries()) {
2873
+ const script = active.get(key);
2874
+ if (!script) {
2875
+ const liveComponent = world.getComponent(record.entityId, ScriptComponent);
2876
+ if (liveComponent) {
2877
+ if (record.entryIndex === 0) {
2878
+ liveComponent.scriptInstance = null;
2879
+ }
2880
+ liveComponent.scriptInstances.delete(record.entryIndex);
2881
+ }
2882
+ record.behaviour.dispose?.(world);
2883
+ this.instances.delete(key);
2884
+ continue;
2885
+ }
2886
+ const entries = readScriptEntries(script.scriptComponent, script.entityId);
2887
+ const liveEntry = entries[script.entryIndex];
2888
+ if (!liveEntry) {
2889
+ record.behaviour.dispose?.(world);
2890
+ this.instances.delete(key);
2891
+ continue;
2892
+ }
2893
+ if (!world.isEntityVisible(record.entityId)) {
2894
+ continue;
2895
+ }
2896
+ try {
2897
+ script.scriptComponent.scriptInstance = script.entryIndex === 0 ? record.behaviour : script.scriptComponent.scriptInstance;
2898
+ script.scriptComponent.scriptInstances.set(script.entryIndex, record.behaviour);
2899
+ entries[script.entryIndex] = {
2900
+ ...liveEntry,
2901
+ data: serializeDataForStorage(record.rawData, normalizeScriptData(record.behaviour.data))
2902
+ };
2903
+ record.behaviour.update(world, deltaTime);
2904
+ entries[script.entryIndex] = {
2905
+ ...entries[script.entryIndex],
2906
+ data: serializeDataForStorage(record.rawData, normalizeScriptData(record.behaviour.data)),
2907
+ runtimeState: "ready",
2908
+ runtimeMessage: void 0
2909
+ };
2910
+ writeScriptEntries(script.scriptComponent, entries);
2911
+ } catch (error) {
2912
+ entries[script.entryIndex] = {
2913
+ ...entries[script.entryIndex],
2914
+ runtimeState: "error",
2915
+ runtimeMessage: toErrorMessage(error)
2916
+ };
2917
+ writeScriptEntries(script.scriptComponent, entries);
2918
+ if (script.entryIndex === 0) {
2919
+ script.scriptComponent.scriptInstance = null;
2920
+ }
2921
+ record.behaviour.dispose?.(world);
2922
+ this.instances.delete(key);
2923
+ }
2924
+ }
2925
+ if (this.selectedEntityId !== null) {
2926
+ let stillActive = false;
2927
+ for (const record of this.instances.values()) {
2928
+ if (record.entityId === this.selectedEntityId) {
2929
+ stillActive = true;
2930
+ break;
2931
+ }
2932
+ }
2933
+ if (!stillActive) {
2934
+ this.selectedEntityId = null;
2935
+ }
2936
+ }
2937
+ for (const [key, script] of active.entries()) {
2938
+ if (this.instances.has(key) || this.loading.has(key)) {
2939
+ continue;
2940
+ }
2941
+ const entries = readScriptEntries(script.scriptComponent, script.entityId);
2942
+ const targetEntry = entries[script.entryIndex];
2943
+ if (targetEntry) {
2944
+ entries[script.entryIndex] = {
2945
+ ...targetEntry,
2946
+ runtimeState: "loading",
2947
+ runtimeMessage: void 0
2948
+ };
2949
+ writeScriptEntries(script.scriptComponent, entries);
2950
+ }
2951
+ const promise = this.loadBehaviour(world, script).catch((error) => {
2952
+ const liveEntries = readScriptEntries(script.scriptComponent, script.entityId);
2953
+ const liveEntry = liveEntries[script.entryIndex];
2954
+ if (liveEntry) {
2955
+ liveEntries[script.entryIndex] = {
2956
+ ...liveEntry,
2957
+ runtimeState: "error",
2958
+ runtimeMessage: "Failed to load script."
2959
+ };
2960
+ writeScriptEntries(script.scriptComponent, liveEntries);
2961
+ }
2962
+ if (script.entryIndex === 0) {
2963
+ script.scriptComponent.scriptInstance = null;
2964
+ }
2965
+ console.error(
2966
+ `[ScriptBehaviourSystem] Failed loading script ${script.scriptEntry.className}`,
2967
+ error
2968
+ );
2969
+ }).finally(() => {
2970
+ this.loading.delete(key);
2971
+ });
2972
+ this.loading.set(key, promise);
2973
+ }
2974
+ for (const key of this.loading.keys()) {
2975
+ if (active.has(key)) {
2976
+ continue;
2977
+ }
2978
+ this.loading.delete(key);
2979
+ }
2980
+ }
2981
+ dispose(world) {
2982
+ if (this.selectionCtx) {
2983
+ this.selectionCtx.domElement.removeEventListener("pointerdown", this.onPointerDown);
2984
+ this.selectionCtx.domElement.removeEventListener("pointerup", this.onPointerUp);
2985
+ }
2986
+ for (const record of this.instances.values()) {
2987
+ const liveComponent = world.getComponent(record.entityId, ScriptComponent);
2988
+ if (liveComponent) {
2989
+ if (record.entryIndex === 0) {
2990
+ liveComponent.scriptInstance = null;
2991
+ }
2992
+ liveComponent.scriptInstances.delete(record.entryIndex);
2993
+ }
2994
+ record.behaviour.dispose?.(world);
2995
+ }
2996
+ this.instances.clear();
2997
+ this.loading.clear();
2998
+ }
2999
+ async loadBehaviour(world, script) {
3000
+ const { entityId, scriptComponent, entryIndex, scriptEntry } = script;
3001
+ const key = buildInstanceKey(
3002
+ entityId,
3003
+ scriptEntry.scriptUrl,
3004
+ scriptEntry.className
3005
+ );
3006
+ const moduleValue = await this.moduleLoader(scriptEntry.scriptUrl);
3007
+ const ctor = resolveBehaviourCtor(moduleValue, scriptEntry.className);
3008
+ if (!ctor) {
3009
+ throw new Error(
3010
+ `Missing Behaviour export '${scriptEntry.className}' in ${scriptEntry.scriptUrl}`
3011
+ );
3012
+ }
3013
+ if (!world.hasEntity(entityId)) {
3014
+ return;
3015
+ }
3016
+ const liveComponent = world.getComponent(entityId, ScriptComponent);
3017
+ if (!liveComponent) {
3018
+ return;
3019
+ }
3020
+ const liveEntries = readScriptEntries(liveComponent, entityId);
3021
+ const liveEntry = liveEntries[entryIndex];
3022
+ if (!liveEntry || !liveEntry.enabled || !liveEntry.scriptUrl || liveEntry.scriptUrl !== scriptEntry.scriptUrl || liveEntry.className !== scriptEntry.className) {
3023
+ return;
3024
+ }
3025
+ const currentData = normalizeScriptData(liveEntry.data);
3026
+ let behaviour;
3027
+ try {
3028
+ behaviour = new ctor(
3029
+ world,
3030
+ entityId,
3031
+ void 0
3032
+ );
3033
+ } catch {
3034
+ behaviour = new ctor(world, entityId, currentData);
3035
+ }
3036
+ const defaults = normalizeScriptData(behaviour.data);
3037
+ const mergedData = mergeDataByCurrentDefaults(defaults, currentData);
3038
+ const resolvedData = resolveInputData(world, mergedData);
3039
+ behaviour.data = resolvedData;
3040
+ if (!world.isEditorMode() || liveEntry.executeInEditor === true) {
3041
+ behaviour.init();
3042
+ }
3043
+ liveEntries[entryIndex] = {
3044
+ ...liveEntry,
3045
+ data: mergedData,
3046
+ runtimeState: "ready",
3047
+ runtimeMessage: void 0
3048
+ };
3049
+ writeScriptEntries(liveComponent, liveEntries);
3050
+ if (entryIndex === 0) {
3051
+ liveComponent.scriptInstance = behaviour;
3052
+ }
3053
+ liveComponent.scriptInstances.set(entryIndex, behaviour);
3054
+ this.instances.set(key, {
3055
+ entityId,
3056
+ scriptUrl: scriptEntry.scriptUrl,
3057
+ className: scriptEntry.className,
3058
+ entryIndex,
3059
+ behaviour,
3060
+ rawData: mergedData
3061
+ });
3062
+ }
3063
+ };
3064
+ __name(_ScriptBehaviourSystem, "ScriptBehaviourSystem");
3065
+ _ScriptBehaviourSystem.CLICK_THRESHOLD = 6;
3066
+ var ScriptBehaviourSystem = _ScriptBehaviourSystem;
3067
+
3068
+ // core/systems/TransformSyncSystem.ts
3069
+ var _TransformSyncSystem = class _TransformSyncSystem {
3070
+ update(world) {
3071
+ const entities = world.query(TransformComponent, Object3DRef);
3072
+ for (const entityId of entities) {
3073
+ const transform = world.getComponent(entityId, TransformComponent);
3074
+ const object = world.getComponent(entityId, Object3DRef)?.object;
3075
+ if (!transform || !object) {
3076
+ continue;
3077
+ }
3078
+ applyTransform(object, transform);
3079
+ object.updateMatrixWorld(true);
3080
+ }
3081
+ }
3082
+ };
3083
+ __name(_TransformSyncSystem, "TransformSyncSystem");
3084
+ var TransformSyncSystem = _TransformSyncSystem;
3085
+ function snapshotOptions(opts) {
3086
+ return {
3087
+ loop: opts.loop,
3088
+ pitch: opts.pitch,
3089
+ volume: opts.volume,
3090
+ refDistance: opts.refDistance,
3091
+ distanceModel: opts.distanceModel,
3092
+ rolloffFactor: opts.rolloffFactor
3093
+ };
3094
+ }
3095
+ __name(snapshotOptions, "snapshotOptions");
3096
+ var _AudioSystem = class _AudioSystem {
3097
+ constructor({ isEditor = false } = {}) {
3098
+ /** THREE.js `isPlaying` state captured at the end of the previous frame. */
3099
+ this.prevPlayingState = /* @__PURE__ */ new Map();
3100
+ /** Snapshot of options applied in the previous frame, for change detection. */
3101
+ this.prevOptions = /* @__PURE__ */ new Map();
3102
+ this.isEditor = isEditor;
3103
+ }
3104
+ update(world, _deltaTime) {
3105
+ if (this.isEditor) return;
3106
+ const entities = world.query(AudioComponent);
3107
+ const liveEntityIds = new Set(entities);
3108
+ for (const entityId of entities) {
3109
+ const component = world.getComponent(entityId, AudioComponent);
3110
+ if (!component?.audio) continue;
3111
+ const sound = component.audio;
3112
+ if (!world.isEntityVisible(entityId)) {
3113
+ if (sound.isPlaying) sound.stop();
3114
+ continue;
3115
+ }
3116
+ this._syncOptions(entityId, component, sound);
3117
+ const prevWasPlaying = this.prevPlayingState.get(entityId) ?? false;
3118
+ if (prevWasPlaying && !sound.isPlaying && component.isPlaying && !component.isPaused) {
3119
+ component.isPlaying = false;
3120
+ }
3121
+ if (component.isPlaying && !sound.isPlaying) {
3122
+ if (sound.buffer) {
3123
+ sound.play();
3124
+ }
3125
+ } else if (!component.isPlaying && sound.isPlaying) {
3126
+ if (component.isPaused) {
3127
+ sound.pause();
3128
+ } else {
3129
+ sound.stop();
3130
+ }
3131
+ }
3132
+ this.prevPlayingState.set(entityId, sound.isPlaying);
3133
+ }
3134
+ for (const entityId of this.prevPlayingState.keys()) {
3135
+ if (!liveEntityIds.has(entityId)) {
3136
+ this.prevPlayingState.delete(entityId);
3137
+ this.prevOptions.delete(entityId);
3138
+ }
3139
+ }
3140
+ }
3141
+ /** Apply any changed options from the component to the THREE.js audio node. */
3142
+ _syncOptions(entityId, component, sound) {
3143
+ const opts = component.options;
3144
+ const prev = this.prevOptions.get(entityId);
3145
+ if (!prev || prev.loop !== opts.loop) {
3146
+ sound.setLoop(opts.loop);
3147
+ }
3148
+ if (!prev || prev.pitch !== opts.pitch) {
3149
+ sound.setPlaybackRate(opts.pitch);
3150
+ }
3151
+ if (!prev || prev.volume !== opts.volume) {
3152
+ sound.setVolume(opts.volume);
3153
+ }
3154
+ if (opts.positional && sound instanceof THREE7.PositionalAudio) {
3155
+ if (!prev || prev.refDistance !== opts.refDistance) {
3156
+ sound.setRefDistance(opts.refDistance);
3157
+ }
3158
+ if (!prev || prev.distanceModel !== opts.distanceModel) {
3159
+ sound.setDistanceModel(opts.distanceModel);
3160
+ }
3161
+ if (!prev || prev.rolloffFactor !== opts.rolloffFactor) {
3162
+ sound.setRolloffFactor(opts.rolloffFactor);
3163
+ }
3164
+ }
3165
+ this.prevOptions.set(entityId, snapshotOptions(opts));
3166
+ }
3167
+ dispose(_world) {
3168
+ this.prevPlayingState.clear();
3169
+ this.prevOptions.clear();
3170
+ }
3171
+ };
3172
+ __name(_AudioSystem, "AudioSystem");
3173
+ var AudioSystem = _AudioSystem;
3174
+ function snapshotOptions2(opts) {
3175
+ return {
3176
+ loop: opts.loop,
3177
+ volume: opts.volume,
3178
+ width: opts.width,
3179
+ height: opts.height,
3180
+ backgroundColor: opts.backgroundColor,
3181
+ similarity: opts.similarity,
3182
+ smoothness: opts.smoothness,
3183
+ spill: opts.spill,
3184
+ positional: opts.positional,
3185
+ refDistance: opts.refDistance,
3186
+ distanceModel: opts.distanceModel,
3187
+ rolloffFactor: opts.rolloffFactor
3188
+ };
3189
+ }
3190
+ __name(snapshotOptions2, "snapshotOptions");
3191
+ var _VideoSystem = class _VideoSystem {
3192
+ constructor({ isEditor = false } = {}) {
3193
+ /** Playback intent captured at the end of the previous frame. */
3194
+ this.prevIntent = /* @__PURE__ */ new Map();
3195
+ /** Snapshot of options applied in the previous frame, for change detection. */
3196
+ this.prevOptions = /* @__PURE__ */ new Map();
3197
+ this.isEditor = isEditor;
3198
+ }
3199
+ update(world, _deltaTime) {
3200
+ if (this.isEditor) return;
3201
+ const entities = world.query(VideoComponent);
3202
+ const liveEntityIds = new Set(entities);
3203
+ for (const entityId of entities) {
3204
+ const component = world.getComponent(entityId, VideoComponent);
3205
+ if (!component?.videoElement) continue;
3206
+ const video = component.videoElement;
3207
+ if (!world.isEntityVisible(entityId)) {
3208
+ if (!video.paused) video.pause();
3209
+ continue;
3210
+ }
3211
+ this._syncOptions(entityId, component, video);
3212
+ const prev = this.prevIntent.get(entityId) ?? { isPlaying: false, isPaused: false };
3213
+ if (prev.isPlaying && video.paused && !video.seeking && component.isPlaying && !component.isPaused) {
3214
+ component.isPlaying = false;
3215
+ }
3216
+ const isStoppedNow = !component.isPlaying && !component.isPaused;
3217
+ const wasStoppedPrev = !prev.isPlaying && !prev.isPaused;
3218
+ const justStopped = !wasStoppedPrev && isStoppedNow;
3219
+ if (component.isPlaying) {
3220
+ if (video.paused) {
3221
+ video.play().catch(() => {
3222
+ });
3223
+ }
3224
+ } else if (component.isPaused) {
3225
+ if (!video.paused) {
3226
+ video.pause();
3227
+ }
3228
+ } else {
3229
+ if (!video.paused) {
3230
+ video.pause();
3231
+ }
3232
+ if (justStopped) {
3233
+ video.currentTime = 0;
3234
+ }
3235
+ }
3236
+ this.prevIntent.set(entityId, {
3237
+ isPlaying: component.isPlaying,
3238
+ isPaused: component.isPaused
3239
+ });
3240
+ }
3241
+ for (const entityId of this.prevIntent.keys()) {
3242
+ if (!liveEntityIds.has(entityId)) {
3243
+ this.prevIntent.delete(entityId);
3244
+ this.prevOptions.delete(entityId);
3245
+ }
3246
+ }
3247
+ }
3248
+ /** Apply any changed options from the component to the video element and mesh. */
3249
+ _syncOptions(entityId, component, video) {
3250
+ const opts = component.options;
3251
+ const prev = this.prevOptions.get(entityId);
3252
+ if (!prev || prev.loop !== opts.loop) {
3253
+ video.loop = opts.loop;
3254
+ }
3255
+ if (!prev || prev.volume !== opts.volume) {
3256
+ if (component.audioNode) {
3257
+ component.audioNode.setVolume(Math.max(0, Math.min(1, opts.volume)));
3258
+ } else {
3259
+ video.volume = Math.max(0, Math.min(1, opts.volume));
3260
+ }
3261
+ }
3262
+ if ((!prev || prev.width !== opts.width || prev.height !== opts.height) && component.object) {
3263
+ component.object.scale.set(opts.width, opts.height, 1);
3264
+ }
3265
+ const material = component.material;
3266
+ if (material instanceof THREE7.ShaderMaterial) {
3267
+ if (!prev || prev.backgroundColor !== opts.backgroundColor) {
3268
+ material.uniforms.keyColor.value.set(opts.backgroundColor);
3269
+ }
3270
+ if (!prev || prev.similarity !== opts.similarity) {
3271
+ material.uniforms.similarity.value = opts.similarity;
3272
+ }
3273
+ if (!prev || prev.smoothness !== opts.smoothness) {
3274
+ material.uniforms.smoothness.value = opts.smoothness;
3275
+ }
3276
+ if (!prev || prev.spill !== opts.spill) {
3277
+ material.uniforms.spill.value = opts.spill;
3278
+ }
3279
+ }
3280
+ if (opts.positional && component.audioNode instanceof THREE7.PositionalAudio) {
3281
+ const posAudio = component.audioNode;
3282
+ if (!prev || prev.refDistance !== opts.refDistance) {
3283
+ posAudio.setRefDistance(opts.refDistance);
3284
+ }
3285
+ if (!prev || prev.distanceModel !== opts.distanceModel) {
3286
+ posAudio.setDistanceModel(opts.distanceModel);
3287
+ }
3288
+ if (!prev || prev.rolloffFactor !== opts.rolloffFactor) {
3289
+ posAudio.setRolloffFactor(opts.rolloffFactor);
3290
+ }
3291
+ }
3292
+ this.prevOptions.set(entityId, snapshotOptions2(opts));
3293
+ }
3294
+ dispose(_world) {
3295
+ this.prevIntent.clear();
3296
+ this.prevOptions.clear();
3297
+ }
3298
+ };
3299
+ __name(_VideoSystem, "VideoSystem");
3300
+ var VideoSystem = _VideoSystem;
3301
+
3302
+ export { AnimationSystem, AudioSystem, Behaviour, CameraSyncSystem, EnvironmentSyncSystem, InputSystem, KeyboardKeys, LightSyncSystem, MaterialSyncSystem, MeshGeometrySystem, ObjectVisibilitySystem, PhysicsSyncSystem, PostprocessingSyncSystem, RenderSystem, ScriptBehaviourSystem, TransformSyncSystem, VideoSystem };
3303
+ //# sourceMappingURL=chunk-P2YDX5DB.js.map
3304
+ //# sourceMappingURL=chunk-P2YDX5DB.js.map