@auraindustry/aurajs 0.0.7 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (334) hide show
  1. package/README.md +98 -2
  2. package/benchmarks/perf-thresholds.json +54 -0
  3. package/package.json +4 -7
  4. package/src/asset-pack.mjs +8 -1
  5. package/src/authored-project.mjs +1449 -0
  6. package/src/authored-runtime.mjs +2016 -0
  7. package/src/authoring/avatar-animation-graph.mjs +648 -0
  8. package/src/bin-integrity.mjs +272 -0
  9. package/src/build-contract/assets.mjs +130 -0
  10. package/src/build-contract/capabilities.mjs +116 -0
  11. package/src/build-contract/constants.mjs +6 -0
  12. package/src/build-contract/helpers.mjs +44 -0
  13. package/src/build-contract/web-templates.mjs +5993 -0
  14. package/src/build-contract.mjs +27 -2910
  15. package/src/bundler.mjs +188 -55
  16. package/src/cli.mjs +4840 -1512
  17. package/src/commands/project-authoring.mjs +454 -0
  18. package/src/config.mjs +44 -0
  19. package/src/conformance/cases/app-and-ui-runtime-cases.mjs +3309 -0
  20. package/src/conformance/cases/core-runtime-cases.mjs +1431 -0
  21. package/src/conformance/cases/index.mjs +11 -0
  22. package/src/conformance/cases/scene3d-and-media-cases.mjs +2094 -0
  23. package/src/conformance/cases/systems-and-gameplay-cases.mjs +1776 -0
  24. package/src/conformance/shared.mjs +27 -0
  25. package/src/conformance-runner.mjs +25 -13
  26. package/src/conformance.mjs +619 -4020
  27. package/src/cutscene.mjs +362 -5
  28. package/src/dev-cli-action.mjs +249 -0
  29. package/src/dev-cli-inspect.mjs +92 -0
  30. package/src/dev-cli-state.mjs +80 -0
  31. package/src/external-asset-cache.mjs +587 -0
  32. package/src/external-asset-policy.mjs +217 -0
  33. package/src/external-package-surface.mjs +206 -0
  34. package/src/game-action-runtime.mjs +869 -0
  35. package/src/game-state-runtime.mjs +206 -6
  36. package/src/headless-action.mjs +186 -0
  37. package/src/headless-test/runtime-animation.mjs +1173 -0
  38. package/src/headless-test/runtime-coordinator.mjs +1514 -0
  39. package/src/headless-test/runtime-primitives.mjs +320 -0
  40. package/src/headless-test/runtime-world.mjs +2253 -0
  41. package/src/headless-test.mjs +392 -4298
  42. package/src/host-binary.mjs +342 -14
  43. package/src/icon-discovery.mjs +64 -0
  44. package/src/make-catalog.mjs +109 -0
  45. package/src/make.mjs +197 -0
  46. package/src/package-integrity.mjs +586 -0
  47. package/src/perf-benchmark.mjs +353 -0
  48. package/src/postinstall.mjs +5 -5
  49. package/src/prefabs/index.mjs +34 -0
  50. package/src/prefabs/scene-serialization.mjs +184 -0
  51. package/src/project-importer.mjs +620 -0
  52. package/src/project-registry.mjs +24 -0
  53. package/src/publish-command.mjs +195 -0
  54. package/src/publish-env-example.mjs +83 -0
  55. package/src/publish-validation.mjs +708 -0
  56. package/src/retro/assets/compile.mjs +232 -0
  57. package/src/retro/backend-gba/authoring.mjs +1029 -0
  58. package/src/retro/backend-gba/rom.mjs +363 -0
  59. package/src/retro/backend-gbc/rom.mjs +85 -0
  60. package/src/retro/build.mjs +278 -0
  61. package/src/retro/cli/commands.mjs +292 -0
  62. package/src/retro/cli/templates.mjs +84 -0
  63. package/src/retro/diagnostics/catalog.mjs +110 -0
  64. package/src/retro/diagnostics/emit.mjs +72 -0
  65. package/src/retro/emulator/case-overlay.mjs +64 -0
  66. package/src/retro/emulator/discovery.mjs +158 -0
  67. package/src/retro/emulator/macos-case-overlay.swift +220 -0
  68. package/src/retro/emulator/profiles.mjs +146 -0
  69. package/src/retro/emulator/runner.mjs +289 -0
  70. package/src/retro/frontend/load-project.mjs +98 -0
  71. package/src/retro/index.mjs +30 -0
  72. package/src/retro/ir/build-ir.mjs +108 -0
  73. package/src/retro/runtime-gba/contract.mjs +151 -0
  74. package/src/retro/runtime-gbc/contract.mjs +117 -0
  75. package/src/retro/shared/span.mjs +26 -0
  76. package/src/retro/shared/targets.mjs +64 -0
  77. package/src/retro/validator/check-project.mjs +114 -0
  78. package/src/runtime-hotspot-audit.mjs +707 -0
  79. package/src/scaffold/config.mjs +1000 -0
  80. package/src/scaffold/fs.mjs +56 -0
  81. package/src/scaffold/layout.mjs +318 -0
  82. package/src/scaffold/project-docs.mjs +439 -0
  83. package/src/scaffold.mjs +93 -596
  84. package/src/scene-composition/index.mjs +326 -0
  85. package/src/scene-composition/runtime.mjs +751 -0
  86. package/src/self-hosted-assets.mjs +604 -0
  87. package/src/session-client.mjs +750 -0
  88. package/src/session-native-launcher.mjs +74 -0
  89. package/src/session-protocol.mjs +75 -0
  90. package/src/session-runtime.mjs +321 -0
  91. package/src/session-server.mjs +360 -0
  92. package/src/shader-kits/index.mjs +773 -0
  93. package/src/starter-content-registry.mjs +292 -0
  94. package/src/state-artifacts.mjs +662 -24
  95. package/src/state-dev-reload.mjs +99 -2
  96. package/src/terminal-ui.mjs +245 -0
  97. package/src/web-conformance.mjs +219 -0
  98. package/templates/create/2d/config/gameplay/shooter.config.js +26 -0
  99. package/templates/create/2d/content/gameplay/waves.json +26 -0
  100. package/templates/create/2d/content/registries/.gitkeep +1 -0
  101. package/templates/create/2d/docs/design/.gitkeep +1 -0
  102. package/templates/create/2d/docs/design/loop.md +5 -0
  103. package/templates/create/2d/prefabs/enemies.prefab.js +90 -0
  104. package/templates/create/2d/prefabs/enemy-basic.prefab.js +18 -0
  105. package/templates/create/2d/prefabs/player.prefab.js +36 -0
  106. package/templates/create/2d/prefabs/projectiles.prefab.js +35 -0
  107. package/templates/create/2d/scenes/boot.scene.js +12 -0
  108. package/templates/create/2d/scenes/gameplay.scene.js +230 -0
  109. package/templates/create/2d/scenes/menu.scene.js +9 -0
  110. package/templates/create/2d/src/main.js +6 -185
  111. package/templates/create/2d/src/runtime/app.js +49 -0
  112. package/templates/create/2d/src/runtime/capabilities.js +35 -0
  113. package/templates/create/2d/ui/hud.screen.js +40 -0
  114. package/templates/create/2d/ui/pause.screen.js +149 -0
  115. package/templates/create/2d/ui/settings.screen.js +347 -0
  116. package/templates/create/2d/ui/title.screen.js +13 -0
  117. package/templates/create/2d-adventure/aura.config.json +28 -0
  118. package/templates/create/2d-adventure/config/gameplay/adventure.config.js +14 -0
  119. package/templates/create/2d-adventure/content/gameplay/world.js +46 -0
  120. package/templates/create/2d-adventure/content/registries/.gitkeep +1 -0
  121. package/templates/create/2d-adventure/docs/design/loop.md +5 -0
  122. package/templates/create/2d-adventure/prefabs/player.prefab.js +54 -0
  123. package/templates/create/2d-adventure/prefabs/relic.prefab.js +38 -0
  124. package/templates/create/2d-adventure/prefabs/world.prefab.js +125 -0
  125. package/templates/create/2d-adventure/scenes/gameplay.scene.js +256 -0
  126. package/templates/create/2d-adventure/src/runtime/capabilities.js +34 -0
  127. package/templates/create/2d-adventure/ui/hud.screen.js +60 -0
  128. package/templates/create/2d-survivor/config/gameplay/survivor.config.js +33 -0
  129. package/templates/create/2d-survivor/content/gameplay/spawn-zones.json +29 -0
  130. package/templates/create/2d-survivor/content/registries/.gitkeep +1 -0
  131. package/templates/create/2d-survivor/docs/design/.gitkeep +1 -0
  132. package/templates/create/2d-survivor/docs/design/loop.md +5 -0
  133. package/templates/create/2d-survivor/prefabs/enemies.prefab.js +178 -0
  134. package/templates/create/2d-survivor/prefabs/enemy-swarm.prefab.js +18 -0
  135. package/templates/create/2d-survivor/prefabs/player.prefab.js +42 -0
  136. package/templates/create/2d-survivor/prefabs/projectiles.prefab.js +56 -0
  137. package/templates/create/2d-survivor/scenes/boot.scene.js +12 -0
  138. package/templates/create/2d-survivor/scenes/gameplay.scene.js +314 -0
  139. package/templates/create/2d-survivor/scenes/menu.scene.js +9 -0
  140. package/templates/create/2d-survivor/src/main.js +5 -332
  141. package/templates/create/2d-survivor/src/runtime/app.js +49 -0
  142. package/templates/create/2d-survivor/src/runtime/capabilities.js +35 -0
  143. package/templates/create/2d-survivor/ui/hud.screen.js +45 -0
  144. package/templates/create/2d-survivor/ui/title.screen.js +13 -0
  145. package/templates/create/3d/assets/models/starter-avatar.gltf +184 -0
  146. package/templates/create/3d/config/gameplay/.gitkeep +1 -0
  147. package/templates/create/3d/content/gameplay/checkpoints.json +33 -0
  148. package/templates/create/3d/content/gameplay/course.js +40 -0
  149. package/templates/create/3d/content/registries/.gitkeep +1 -0
  150. package/templates/create/3d/docs/design/.gitkeep +1 -0
  151. package/templates/create/3d/docs/design/loop.md +5 -0
  152. package/templates/create/3d/prefabs/checkpoint.prefab.js +15 -0
  153. package/templates/create/3d/prefabs/player.prefab.js +204 -0
  154. package/templates/create/3d/prefabs/world.prefab.js +112 -0
  155. package/templates/create/3d/scenes/boot.scene.js +12 -0
  156. package/templates/create/3d/scenes/checkpoint.scene.js +9 -0
  157. package/templates/create/3d/scenes/gameplay.scene.js +292 -0
  158. package/templates/create/3d/src/main.js +6 -295
  159. package/templates/create/3d/src/runtime/app.js +49 -0
  160. package/templates/create/3d/src/runtime/capabilities.js +53 -0
  161. package/templates/create/3d/src/runtime/materials.js +34 -0
  162. package/templates/create/3d/src/runtime/state.js +39 -0
  163. package/templates/create/3d/ui/hud.screen.js +75 -0
  164. package/templates/create/3d/ui/pause.screen.js +166 -0
  165. package/templates/create/3d/ui/settings.screen.js +387 -0
  166. package/templates/create/3d-adventure/assets/models/starter-avatar.gltf +184 -0
  167. package/templates/create/3d-adventure/aura.config.json +28 -0
  168. package/templates/create/3d-adventure/config/gameplay/adventure.config.js +9 -0
  169. package/templates/create/3d-adventure/content/gameplay/course.js +62 -0
  170. package/templates/create/3d-adventure/content/registries/.gitkeep +1 -0
  171. package/templates/create/3d-adventure/docs/design/loop.md +5 -0
  172. package/templates/create/3d-adventure/prefabs/player.prefab.js +168 -0
  173. package/templates/create/3d-adventure/prefabs/relic.prefab.js +35 -0
  174. package/templates/create/3d-adventure/prefabs/world.prefab.js +119 -0
  175. package/templates/create/3d-adventure/scenes/gameplay.scene.js +358 -0
  176. package/templates/create/3d-adventure/src/runtime/capabilities.js +56 -0
  177. package/templates/create/3d-adventure/src/runtime/materials.js +39 -0
  178. package/templates/create/3d-adventure/src/runtime/state.js +31 -0
  179. package/templates/create/3d-adventure/ui/hud.screen.js +70 -0
  180. package/templates/create/3d-adventure/ui/pause.screen.js +437 -0
  181. package/templates/create/3d-collectathon/assets/models/starter-avatar.gltf +184 -0
  182. package/templates/create/3d-collectathon/config/gameplay/.gitkeep +1 -0
  183. package/templates/create/3d-collectathon/content/gameplay/collectibles.json +26 -0
  184. package/templates/create/3d-collectathon/content/gameplay/course.js +46 -0
  185. package/templates/create/3d-collectathon/content/registries/.gitkeep +1 -0
  186. package/templates/create/3d-collectathon/docs/design/.gitkeep +1 -0
  187. package/templates/create/3d-collectathon/docs/design/loop.md +5 -0
  188. package/templates/create/3d-collectathon/prefabs/collectible.prefab.js +15 -0
  189. package/templates/create/3d-collectathon/prefabs/player.prefab.js +207 -0
  190. package/templates/create/3d-collectathon/prefabs/world.prefab.js +112 -0
  191. package/templates/create/3d-collectathon/scenes/boot.scene.js +12 -0
  192. package/templates/create/3d-collectathon/scenes/checkpoint.scene.js +9 -0
  193. package/templates/create/3d-collectathon/scenes/gameplay.scene.js +200 -0
  194. package/templates/create/3d-collectathon/src/main.js +5 -355
  195. package/templates/create/3d-collectathon/src/runtime/app.js +49 -0
  196. package/templates/create/3d-collectathon/src/runtime/capabilities.js +53 -0
  197. package/templates/create/3d-collectathon/src/runtime/materials.js +34 -0
  198. package/templates/create/3d-collectathon/src/runtime/state.js +27 -0
  199. package/templates/create/3d-collectathon/ui/hud.screen.js +66 -0
  200. package/templates/create/3d-collectathon/ui/pause.screen.js +13 -0
  201. package/templates/create/blank/config/gameplay/.gitkeep +1 -0
  202. package/templates/create/blank/content/gameplay/.gitkeep +1 -0
  203. package/templates/create/blank/content/registries/.gitkeep +1 -0
  204. package/templates/create/blank/docs/design/.gitkeep +1 -0
  205. package/templates/create/blank/docs/design/loop.md +5 -0
  206. package/templates/create/blank/prefabs/.gitkeep +1 -0
  207. package/templates/create/blank/scenes/.gitkeep +1 -0
  208. package/templates/create/blank/src/runtime/.gitkeep +1 -0
  209. package/templates/create/blank/ui/.gitkeep +1 -0
  210. package/templates/create/deckbuilder-2d/assets/audio/.gitkeep +1 -0
  211. package/templates/create/deckbuilder-2d/assets/fonts/.gitkeep +1 -0
  212. package/templates/create/deckbuilder-2d/assets/sprites/.gitkeep +1 -0
  213. package/templates/create/deckbuilder-2d/assets/starter/README.md +11 -0
  214. package/templates/create/deckbuilder-2d/assets/ui/.gitkeep +1 -0
  215. package/templates/create/deckbuilder-2d/aura.config.json +28 -0
  216. package/templates/create/deckbuilder-2d/config/gameplay/deckbuilder.config.js +26 -0
  217. package/templates/create/deckbuilder-2d/content/cards/guard.card.js +19 -0
  218. package/templates/create/deckbuilder-2d/content/cards/spark.card.js +20 -0
  219. package/templates/create/deckbuilder-2d/content/cards/starter.deck.js +69 -0
  220. package/templates/create/deckbuilder-2d/content/cards/strike.card.js +19 -0
  221. package/templates/create/deckbuilder-2d/content/cards/survey.card.js +20 -0
  222. package/templates/create/deckbuilder-2d/content/encounters/training-battle.encounter.js +14 -0
  223. package/templates/create/deckbuilder-2d/content/encounters/training-battle.js +65 -0
  224. package/templates/create/deckbuilder-2d/content/enemies/training-automaton.enemy.js +48 -0
  225. package/templates/create/deckbuilder-2d/content/gameplay/.gitkeep +1 -0
  226. package/templates/create/deckbuilder-2d/content/registries/cards.registry.js +26 -0
  227. package/templates/create/deckbuilder-2d/content/registries/encounters.registry.js +20 -0
  228. package/templates/create/deckbuilder-2d/content/registries/enemies.registry.js +20 -0
  229. package/templates/create/deckbuilder-2d/content/registries/relics.registry.js +20 -0
  230. package/templates/create/deckbuilder-2d/content/relics/ember-charm.relic.js +18 -0
  231. package/templates/create/deckbuilder-2d/docs/design/loop.md +12 -0
  232. package/templates/create/deckbuilder-2d/prefabs/.gitkeep +1 -0
  233. package/templates/create/deckbuilder-2d/scenes/boot.scene.js +84 -0
  234. package/templates/create/deckbuilder-2d/scenes/gameplay.scene.js +641 -0
  235. package/templates/create/deckbuilder-2d/src/components/.gitkeep +1 -0
  236. package/templates/create/deckbuilder-2d/src/main.js +17 -0
  237. package/templates/create/deckbuilder-2d/src/runtime/capabilities.js +22 -0
  238. package/templates/create/deckbuilder-2d/src/shared/.gitkeep +1 -0
  239. package/templates/create/deckbuilder-2d/src/systems/.gitkeep +1 -0
  240. package/templates/create/deckbuilder-2d/tests/smoke/.gitkeep +1 -0
  241. package/templates/create/deckbuilder-2d/ui/hud.screen.js +80 -0
  242. package/templates/create/deckbuilder-2d/ui/pause.screen.js +146 -0
  243. package/templates/create/deckbuilder-2d/ui/settings.screen.js +342 -0
  244. package/templates/create/local-multiplayer/aura.config.json +41 -0
  245. package/templates/create/local-multiplayer/config/gameplay/local-multiplayer.config.js +26 -0
  246. package/templates/create/local-multiplayer/content/gameplay/room-layout.js +13 -0
  247. package/templates/create/local-multiplayer/content/registries/.gitkeep +1 -0
  248. package/templates/create/local-multiplayer/docs/design/loop.md +16 -0
  249. package/templates/create/local-multiplayer/prefabs/player.prefab.js +99 -0
  250. package/templates/create/local-multiplayer/scenes/boot.scene.js +12 -0
  251. package/templates/create/local-multiplayer/scenes/gameplay.scene.js +472 -0
  252. package/templates/create/local-multiplayer/src/main.js +17 -0
  253. package/templates/create/local-multiplayer/src/runtime/capabilities.js +28 -0
  254. package/templates/create/local-multiplayer/ui/hud.screen.js +65 -0
  255. package/templates/create/shared/src/runtime/project-inspector.js +105 -0
  256. package/templates/create/shared/src/runtime/scene-flow.js +290 -0
  257. package/templates/create/shared/src/runtime/screen-shell.js +222 -0
  258. package/templates/create/shared/src/runtime/ui-forms.js +209 -0
  259. package/templates/create/shared/src/runtime/ui-settings.js +237 -0
  260. package/templates/create/shared/src/runtime/ui-theme.js +352 -0
  261. package/templates/create/shared/src/starter-utils/adventure-objectives.js +102 -0
  262. package/templates/create/shared/src/starter-utils/animation-2d.js +337 -0
  263. package/templates/create/shared/src/starter-utils/avatar-3d.js +404 -0
  264. package/templates/create/shared/src/starter-utils/combat-feedback-2d.js +320 -0
  265. package/templates/create/shared/src/starter-utils/core.js +39 -3
  266. package/templates/create/shared/src/starter-utils/index.js +8 -2
  267. package/templates/create/shared/src/starter-utils/platformer-3d.js +34 -3
  268. package/templates/create/shared/src/starter-utils/triggers.js +662 -0
  269. package/templates/create/shared/src/starter-utils/tween-2d.js +615 -0
  270. package/templates/create/video-cutscene/assets/video/.gitkeep +0 -0
  271. package/templates/create/video-cutscene/aura.config.json +28 -0
  272. package/templates/create/video-cutscene/config/gameplay/.gitkeep +0 -0
  273. package/templates/create/video-cutscene/content/gameplay/.gitkeep +0 -0
  274. package/templates/create/video-cutscene/content/registries/.gitkeep +0 -0
  275. package/templates/create/video-cutscene/docs/design/loop.md +22 -0
  276. package/templates/create/video-cutscene/prefabs/.gitkeep +0 -0
  277. package/templates/create/video-cutscene/scenes/boot.scene.js +11 -0
  278. package/templates/create/video-cutscene/scenes/cutscene.scene.js +113 -0
  279. package/templates/create/video-cutscene/scenes/gameplay.scene.js +50 -0
  280. package/templates/create/video-cutscene/src/main.js +17 -0
  281. package/templates/create/video-cutscene/src/runtime/app.js +52 -0
  282. package/templates/create/video-cutscene/src/runtime/capabilities.js +35 -0
  283. package/templates/create/video-cutscene/src/runtime/state.js +13 -0
  284. package/templates/create/video-cutscene/ui/.gitkeep +0 -0
  285. package/templates/create-bin/play.js +1192 -0
  286. package/templates/make/README.md +46 -0
  287. package/templates/make/catalog.json +51 -0
  288. package/templates/make/component/files/{{MAKE_NAME}}.component.js +20 -0
  289. package/templates/make/component/manifest.json +9 -0
  290. package/templates/make/data/files/{{MAKE_NAME}}.json +14 -0
  291. package/templates/make/data/manifest.json +9 -0
  292. package/templates/make/material/files/{{MAKE_NAME}}.material.json +17 -0
  293. package/templates/make/material/manifest.json +9 -0
  294. package/templates/make/prefab/files/{{MAKE_NAME}}.prefab.js +20 -0
  295. package/templates/make/prefab/manifest.json +9 -0
  296. package/templates/make/scene/files/{{MAKE_NAME}}.scene.js +31 -0
  297. package/templates/make/scene/manifest.json +9 -0
  298. package/templates/make/shader/files/{{MAKE_NAME}}.shader.js +23 -0
  299. package/templates/make/shader/manifest.json +9 -0
  300. package/templates/make/system/files/{{MAKE_NAME}}.system.js +15 -0
  301. package/templates/make/system/manifest.json +9 -0
  302. package/templates/make/ui-screen/files/{{MAKE_NAME}}.screen.js +16 -0
  303. package/templates/make/ui-screen/files/{{MAKE_NAME}}.screen.json +23 -0
  304. package/templates/make/ui-screen/manifest.json +10 -0
  305. package/templates/make-starters/deckbuilder-2d/card/files/{{MAKE_NAME}}.card.js +22 -0
  306. package/templates/make-starters/deckbuilder-2d/card/manifest.json +9 -0
  307. package/templates/make-starters/deckbuilder-2d/catalog.json +34 -0
  308. package/templates/make-starters/deckbuilder-2d/encounter/files/{{MAKE_NAME}}.encounter.js +18 -0
  309. package/templates/make-starters/deckbuilder-2d/encounter/manifest.json +9 -0
  310. package/templates/make-starters/deckbuilder-2d/enemy/files/{{MAKE_NAME}}.enemy.js +28 -0
  311. package/templates/make-starters/deckbuilder-2d/enemy/manifest.json +9 -0
  312. package/templates/make-starters/deckbuilder-2d/relic/files/{{MAKE_NAME}}.relic.js +23 -0
  313. package/templates/make-starters/deckbuilder-2d/relic/manifest.json +9 -0
  314. package/templates/retro/platformer/README.md +10 -0
  315. package/templates/retro/platformer/assets/retro/assets.json +91 -0
  316. package/templates/retro/platformer/aura.config.json +7 -0
  317. package/templates/retro/platformer/package.json +5 -0
  318. package/templates/retro/platformer/src/main.js +40 -0
  319. package/templates/retro/puzzle-grid/README.md +10 -0
  320. package/templates/retro/puzzle-grid/assets/retro/assets.json +90 -0
  321. package/templates/retro/puzzle-grid/aura.config.json +7 -0
  322. package/templates/retro/puzzle-grid/package.json +5 -0
  323. package/templates/retro/puzzle-grid/src/main.js +29 -0
  324. package/templates/retro/tactics-grid/README.md +10 -0
  325. package/templates/retro/tactics-grid/assets/retro/assets.json +90 -0
  326. package/templates/retro/tactics-grid/aura.config.json +7 -0
  327. package/templates/retro/tactics-grid/package.json +5 -0
  328. package/templates/retro/tactics-grid/src/main.js +35 -0
  329. package/templates/retro/topdown-adventure/README.md +10 -0
  330. package/templates/retro/topdown-adventure/assets/retro/assets.json +95 -0
  331. package/templates/retro/topdown-adventure/aura.config.json +7 -0
  332. package/templates/retro/topdown-adventure/package.json +5 -0
  333. package/templates/retro/topdown-adventure/src/main.js +29 -0
  334. package/templates/skills/aurajs/SKILL.md +61 -5
@@ -1,21 +1,26 @@
1
- import { createHash } from 'node:crypto';
2
- import {
3
- copyFileSync,
4
- existsSync,
5
- mkdirSync,
6
- readdirSync,
7
- readFileSync,
8
- rmSync,
9
- statSync,
10
- writeFileSync,
11
- } from 'node:fs';
12
- import { extname, relative, resolve, sep } from 'node:path';
1
+ import { mkdirSync, writeFileSync } from 'node:fs';
2
+ import { relative, resolve } from 'node:path';
13
3
 
14
- export const BUILD_MANIFEST_SCHEMA = 'aurajs.build-manifest.v1';
15
- export const WEB_BUILD_MANIFEST_SCHEMA = 'aurajs.web-build-manifest.v1';
16
- export const WEB_RUNTIME_CONFIG_SCHEMA = 'aurajs.web-runtime-config.v1';
17
- export const WEB_CAPABILITY_DECLARATION_SCHEMA = 'aurajs.web-capability-declaration.v1';
18
- const PROJECT_CAPABILITY_DECLARATION_FILE = 'aura.capabilities.json';
4
+ import { emitWebAssets } from './build-contract/assets.mjs';
5
+ import { buildRuntimeConfig, readProjectCapabilityDeclaration } from './build-contract/capabilities.mjs';
6
+ import { BUILD_MANIFEST_SCHEMA, WEB_BUILD_MANIFEST_SCHEMA } from './build-contract/constants.mjs';
7
+ import {
8
+ normalizeAssetMode,
9
+ resolveOptionalRelative,
10
+ resolveRequiredPath,
11
+ sha256,
12
+ toPosix,
13
+ writeCanonicalJsonFile,
14
+ } from './build-contract/helpers.mjs';
15
+ import { WEB_INDEX_HTML, WEB_LOADER_SOURCE } from './build-contract/web-templates.mjs';
16
+
17
+ export {
18
+ BUILD_MANIFEST_SCHEMA,
19
+ WEB_BUILD_MANIFEST_SCHEMA,
20
+ WEB_CAPABILITY_DECLARATION_SCHEMA,
21
+ WEB_RUNTIME_CONFIG_SCHEMA,
22
+ } from './build-contract/constants.mjs';
23
+ export { writeCanonicalJsonFile } from './build-contract/helpers.mjs';
19
24
 
20
25
  export function writeBuildManifest(options = {}) {
21
26
  const outRoot = resolve(options.outRoot || process.cwd());
@@ -47,6 +52,8 @@ export function writeBuildManifest(options = {}) {
47
52
  },
48
53
  icon: {
49
54
  configuredPath: typeof icon?.configuredPath === 'string' ? icon.configuredPath : null,
55
+ discoveredPath: typeof icon?.discoveredPath === 'string' ? icon.discoveredPath : null,
56
+ resolvedPath: typeof icon?.resolvedPath === 'string' ? icon.resolvedPath : null,
50
57
  sourcePath: resolveOptionalRelative(outRoot, icon?.sourcePath),
51
58
  outputPath: resolveOptionalRelative(outRoot, icon?.outputPath),
52
59
  status: iconStatus,
@@ -71,13 +78,7 @@ export function writeWebBuildArtifacts(options = {}) {
71
78
  }
72
79
 
73
80
  mkdirSync(resolve(outRoot, 'js'), { recursive: true });
74
- mkdirSync(resolve(outRoot, 'assets'), { recursive: true });
75
-
76
- const assets = emitWebAssets({
77
- projectRoot,
78
- outRoot,
79
- });
80
-
81
+ const assets = emitWebAssets({ projectRoot, outRoot });
81
82
  const capabilityDeclaration = readProjectCapabilityDeclaration({
82
83
  projectRoot,
83
84
  modules: options.modules || {},
@@ -88,7 +89,7 @@ export function writeWebBuildArtifacts(options = {}) {
88
89
  capabilityDeclaration,
89
90
  });
90
91
  const runtimeConfigPath = resolve(outRoot, 'runtime-config.json');
91
- writeCanonicalJson(runtimeConfigPath, runtimeConfig);
92
+ writeCanonicalJsonFile(runtimeConfigPath, runtimeConfig);
92
93
 
93
94
  const loaderPath = resolve(outRoot, 'js', 'aura-web-loader.js');
94
95
  writeFileSync(loaderPath, `${WEB_LOADER_SOURCE}\n`, 'utf8');
@@ -118,7 +119,7 @@ export function writeWebBuildArtifacts(options = {}) {
118
119
  };
119
120
 
120
121
  const manifestPath = resolve(outRoot, 'web-build-manifest.json');
121
- writeCanonicalJson(manifestPath, manifest);
122
+ writeCanonicalJsonFile(manifestPath, manifest);
122
123
 
123
124
  return {
124
125
  outRoot,
@@ -130,2887 +131,3 @@ export function writeWebBuildArtifacts(options = {}) {
130
131
  assetsRoot: assets.assetsOutRoot,
131
132
  };
132
133
  }
133
-
134
- function resolveRequiredPath(pathLike, fieldName) {
135
- if (typeof pathLike !== 'string' || pathLike.length === 0) {
136
- throw new Error(`build contract requires a non-empty "${fieldName}" path.`);
137
- }
138
- return resolve(pathLike);
139
- }
140
-
141
- function normalizeAssetMode(value) {
142
- if (value !== 'embed' && value !== 'sibling') {
143
- throw new Error(`unsupported asset mode "${value}" for build contract.`);
144
- }
145
- return value;
146
- }
147
-
148
- function toPosix(input) {
149
- return input.split(sep).join('/');
150
- }
151
-
152
- function resolveOptionalRelative(outRoot, pathLike) {
153
- if (typeof pathLike !== 'string' || pathLike.length === 0) {
154
- return null;
155
- }
156
- return toPosix(relative(outRoot, resolve(pathLike)));
157
- }
158
-
159
- function buildRuntimeConfig(options = {}) {
160
- const windowConfig = options.windowConfig && typeof options.windowConfig === 'object'
161
- ? options.windowConfig
162
- : {};
163
- const modules = options.modules && typeof options.modules === 'object'
164
- ? options.modules
165
- : {};
166
- const capabilityDeclaration = normalizeWebCapabilityDeclaration(
167
- options.capabilityDeclaration,
168
- normalizeOptionalModules(modules),
169
- options.capabilityDeclaration && typeof options.capabilityDeclaration === 'object'
170
- ? options.capabilityDeclaration.source || null
171
- : null,
172
- );
173
-
174
- return {
175
- schema: WEB_RUNTIME_CONFIG_SCHEMA,
176
- schemaVersion: '1.0.0',
177
- canvas: {
178
- id: 'aura-canvas',
179
- resizeMode: 'fit-container',
180
- width: normalizePositiveInt(windowConfig.width, 1280),
181
- height: normalizePositiveInt(windowConfig.height, 720),
182
- devicePixelRatioMode: 'clamped',
183
- },
184
- loop: {
185
- tickMode: 'raf',
186
- maxDeltaMs: 50,
187
- },
188
- modules: {
189
- physics: modules.physics === true,
190
- network: modules.network === true,
191
- multiplayer: modules.multiplayer === true,
192
- },
193
- capabilities: capabilityDeclaration,
194
- };
195
- }
196
-
197
- function normalizeRequiredApis(entries) {
198
- if (!Array.isArray(entries)) {
199
- return [];
200
- }
201
- return [...new Set(entries
202
- .filter((entry) => typeof entry === 'string')
203
- .map((entry) => entry.trim())
204
- .filter(Boolean))]
205
- .sort((a, b) => a.localeCompare(b));
206
- }
207
-
208
- function normalizeOptionalModules(modules) {
209
- const source = modules && typeof modules === 'object' ? modules : {};
210
- return {
211
- physics: source.physics === true,
212
- network: source.network === true || source.net === true,
213
- multiplayer: source.multiplayer === true,
214
- steam: source.steam === true,
215
- };
216
- }
217
-
218
- function normalizeWebCapabilityDeclaration(value, baseModules = {}, source = null) {
219
- const declaration = value && typeof value === 'object' && !Array.isArray(value)
220
- ? value
221
- : {};
222
- if (
223
- declaration.schema != null
224
- && declaration.schema !== 'aurajs.create-capabilities.v1'
225
- && declaration.schema !== 'aurajs.capability-declaration.v1'
226
- && declaration.schema !== WEB_CAPABILITY_DECLARATION_SCHEMA
227
- ) {
228
- throw new Error(
229
- `${source || 'Capability declaration'} must use `
230
- + '`aurajs.create-capabilities.v1`, `aurajs.capability-declaration.v1`, '
231
- + `or \`${WEB_CAPABILITY_DECLARATION_SCHEMA}\`.`,
232
- );
233
- }
234
-
235
- const declaredModules = normalizeOptionalModules(declaration.optionalModules);
236
- return {
237
- schema: WEB_CAPABILITY_DECLARATION_SCHEMA,
238
- source,
239
- requiredApis: normalizeRequiredApis(declaration.requiredApis),
240
- optionalModules: {
241
- physics: baseModules.physics || declaredModules.physics,
242
- network: baseModules.network || declaredModules.network,
243
- multiplayer: baseModules.multiplayer || declaredModules.multiplayer,
244
- steam: baseModules.steam || declaredModules.steam,
245
- },
246
- };
247
- }
248
-
249
- function readProjectCapabilityDeclaration({ projectRoot, modules }) {
250
- const declarationPath = resolve(projectRoot, PROJECT_CAPABILITY_DECLARATION_FILE);
251
- const baseModules = normalizeOptionalModules(modules);
252
- if (!existsSync(declarationPath)) {
253
- return normalizeWebCapabilityDeclaration({}, baseModules, null);
254
- }
255
-
256
- let parsed;
257
- try {
258
- parsed = JSON.parse(readFileSync(declarationPath, 'utf8'));
259
- } catch (error) {
260
- throw new Error(`Failed to parse ${PROJECT_CAPABILITY_DECLARATION_FILE}: ${error.message}`);
261
- }
262
-
263
- return normalizeWebCapabilityDeclaration(parsed, baseModules, PROJECT_CAPABILITY_DECLARATION_FILE);
264
- }
265
-
266
- function emitWebAssets({ projectRoot, outRoot }) {
267
- const sourceRoot = resolve(projectRoot, 'assets');
268
- const assetsOutRoot = resolve(outRoot, 'assets');
269
- rmSync(assetsOutRoot, { recursive: true, force: true });
270
- mkdirSync(assetsOutRoot, { recursive: true });
271
-
272
- const sourceFiles = collectFiles(sourceRoot);
273
- const entries = [];
274
- for (const sourcePath of sourceFiles) {
275
- const sourceRelative = toPosix(relative(sourceRoot, sourcePath));
276
- const sourceBytes = readFileSync(sourcePath);
277
- const contentHash = sha256(sourceBytes);
278
- const relativeHash = sha256(Buffer.from(sourceRelative, 'utf8')).slice(0, 8);
279
- const extension = extname(sourceRelative).toLowerCase();
280
- const stemSource = extension.length > 0
281
- ? sourceRelative.slice(0, sourceRelative.length - extension.length)
282
- : sourceRelative;
283
- const stem = sanitizeAssetStem(stemSource);
284
- const outputName = `${stem}.${relativeHash}.${contentHash.slice(0, 12)}${extension}`;
285
- const outputPath = resolve(assetsOutRoot, outputName);
286
-
287
- copyFileSync(sourcePath, outputPath);
288
- entries.push({
289
- path: `assets/${outputName}`,
290
- sourcePath: sourceRelative,
291
- bytes: sourceBytes.length,
292
- sha256: contentHash,
293
- mediaType: mediaTypeForExtension(extension),
294
- });
295
- }
296
-
297
- entries.sort((a, b) => a.path.localeCompare(b.path));
298
- removeUnexpectedFiles(assetsOutRoot, new Set(entries.map((entry) => entry.path.slice('assets/'.length))));
299
- return { entries, assetsOutRoot };
300
- }
301
-
302
- function collectFiles(rootPath) {
303
- if (!existsSync(rootPath)) {
304
- return [];
305
- }
306
- const output = [];
307
- walkFiles(rootPath, output);
308
- output.sort((a, b) => toPosix(a).localeCompare(toPosix(b)));
309
- return output;
310
- }
311
-
312
- function walkFiles(dirPath, output) {
313
- const names = readdirSync(dirPath).sort((a, b) => a.localeCompare(b));
314
- for (const name of names) {
315
- const fullPath = resolve(dirPath, name);
316
- const stat = statSync(fullPath);
317
- if (stat.isDirectory()) {
318
- walkFiles(fullPath, output);
319
- continue;
320
- }
321
- output.push(fullPath);
322
- }
323
- }
324
-
325
- function sanitizeAssetStem(value) {
326
- const normalized = String(value || '')
327
- .replace(/[\\/]+/g, '-')
328
- .replace(/[^A-Za-z0-9._-]+/g, '-')
329
- .replace(/-+/g, '-')
330
- .replace(/^[-._]+|[-._]+$/g, '');
331
- return normalized.length > 0 ? normalized : 'asset';
332
- }
333
-
334
- function mediaTypeForExtension(extension) {
335
- switch (extension) {
336
- case '.png':
337
- return 'image/png';
338
- case '.jpg':
339
- case '.jpeg':
340
- return 'image/jpeg';
341
- case '.gif':
342
- return 'image/gif';
343
- case '.webp':
344
- return 'image/webp';
345
- case '.wav':
346
- return 'audio/wav';
347
- case '.ogg':
348
- return 'audio/ogg';
349
- case '.mp3':
350
- return 'audio/mpeg';
351
- case '.json':
352
- return 'application/json';
353
- case '.txt':
354
- case '.md':
355
- case '.csv':
356
- return 'text/plain; charset=utf-8';
357
- default:
358
- return 'application/octet-stream';
359
- }
360
- }
361
-
362
- function normalizePositiveInt(value, fallback) {
363
- if (!Number.isFinite(value)) {
364
- return fallback;
365
- }
366
- const normalized = Math.floor(value);
367
- return normalized > 0 ? normalized : fallback;
368
- }
369
-
370
- function writeCanonicalJson(path, value) {
371
- writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
372
- }
373
-
374
- function removeUnexpectedFiles(rootPath, allowedNames) {
375
- if (!existsSync(rootPath)) {
376
- return;
377
- }
378
- for (const name of readdirSync(rootPath)) {
379
- if (allowedNames.has(name)) {
380
- continue;
381
- }
382
- rmSync(resolve(rootPath, name), { recursive: true, force: true });
383
- }
384
- }
385
-
386
- function sha256(value) {
387
- return createHash('sha256').update(value).digest('hex');
388
- }
389
-
390
- const WEB_INDEX_HTML = [
391
- '<!doctype html>',
392
- '<html lang="en">',
393
- '<head>',
394
- ' <meta charset="utf-8" />',
395
- ' <meta name="viewport" content="width=device-width, initial-scale=1" />',
396
- ' <title>AuraJS Web Build</title>',
397
- ' <style>',
398
- ' html, body { margin: 0; width: 100%; height: 100%; overflow: hidden; background: #060912; }',
399
- ' #aura-root { width: 100vw; height: 100vh; display: grid; place-items: center; }',
400
- ' #aura-canvas { display: block; max-width: 100%; max-height: 100%; }',
401
- ' </style>',
402
- '</head>',
403
- '<body>',
404
- ' <div id="aura-root">',
405
- ' <canvas id="aura-canvas"></canvas>',
406
- ' </div>',
407
- ' <script src="./js/aura-web-loader.js"></script>',
408
- ' <script>',
409
- ' window.addEventListener("load", function () {',
410
- ' if (!window.AuraWebLoader || typeof window.AuraWebLoader.mount !== "function") return;',
411
- ' window.AuraWebLoader.mount("#aura-root", { rootUrl: ".", mount: "#aura-root" }).catch(function (error) {',
412
- ' console.error(error);',
413
- ' });',
414
- ' });',
415
- ' </script>',
416
- '</body>',
417
- '</html>',
418
- ].join('\n');
419
-
420
- const WEB_LOADER_SOURCE = `
421
- (function (globalRef) {
422
- const state = {
423
- phase: 'idle',
424
- reasonCode: null,
425
- lastError: null,
426
- lifecycle: {
427
- running: false,
428
- setupCalls: 0,
429
- updateCalls: 0,
430
- drawCalls: 0,
431
- frameCount: 0,
432
- lastDeltaSeconds: 0
433
- }
434
- };
435
- let cachedManifest = null;
436
- let cachedRuntimeConfig = null;
437
- let cachedRootUrl = '.';
438
- let mountedRuntime = null;
439
- let auraRuntime = null;
440
-
441
- function normalizeCount(value) {
442
- const numeric = Number(value);
443
- if (!Number.isFinite(numeric) || numeric < 0) return 0;
444
- return Math.floor(numeric);
445
- }
446
-
447
- function normalizeDeltaSeconds(value) {
448
- const numeric = Number(value);
449
- if (!Number.isFinite(numeric) || numeric < 0) return 0;
450
- return Number(numeric.toFixed(6));
451
- }
452
-
453
- function cloneLifecycle(lifecycle) {
454
- const source = lifecycle && typeof lifecycle === 'object' ? lifecycle : {};
455
- return {
456
- running: source.running === true,
457
- setupCalls: normalizeCount(source.setupCalls),
458
- updateCalls: normalizeCount(source.updateCalls),
459
- drawCalls: normalizeCount(source.drawCalls),
460
- frameCount: normalizeCount(source.frameCount),
461
- lastDeltaSeconds: normalizeDeltaSeconds(source.lastDeltaSeconds)
462
- };
463
- }
464
-
465
- function setState(phase, reasonCode, error) {
466
- state.phase = phase;
467
- state.reasonCode = reasonCode || null;
468
- state.lastError = error || null;
469
- }
470
-
471
- function createError(reasonCode, message, layer, retryable, details) {
472
- const error = new Error(message);
473
- error.ok = false;
474
- error.reasonCode = reasonCode;
475
- error.layer = layer;
476
- error.retryable = Boolean(retryable);
477
- error.details = details || {};
478
- return error;
479
- }
480
-
481
- function createUnsupportedRuntimeError(namespaceName, methodName, reasonCode, details) {
482
- const normalizedDetails = details && typeof details === 'object' ? details : {};
483
- return createError(
484
- reasonCode,
485
- 'aura.' + namespaceName + '.' + methodName + '() is not supported in browser runtime. [reason:' + reasonCode + ']',
486
- 'runtime',
487
- false,
488
- Object.assign(
489
- {
490
- runtime: 'web',
491
- namespace: namespaceName,
492
- method: methodName
493
- },
494
- normalizedDetails
495
- )
496
- );
497
- }
498
-
499
- function createUnsupportedStateResult(methodName, reasonCode) {
500
- return {
501
- ok: false,
502
- reasonCode: reasonCode,
503
- detail: 'aura.state.' + methodName + '() is not supported in browser runtime. [reason:' + reasonCode + ']',
504
- runtime: 'web'
505
- };
506
- }
507
-
508
- function normalizeError(error, fallbackReasonCode, fallbackMessage, fallbackLayer, fallbackRetryable) {
509
- if (error && typeof error === 'object' && typeof error.reasonCode === 'string') {
510
- return error;
511
- }
512
- return createError(
513
- fallbackReasonCode,
514
- fallbackMessage,
515
- fallbackLayer,
516
- fallbackRetryable,
517
- { cause: String(error && error.message ? error.message : error) }
518
- );
519
- }
520
-
521
- async function captureFailure(fallback, operation) {
522
- try {
523
- return await operation();
524
- } catch (error) {
525
- const normalized = normalizeError(
526
- error,
527
- fallback.reasonCode,
528
- fallback.message,
529
- fallback.layer,
530
- fallback.retryable
531
- );
532
- setState('error', normalized.reasonCode, {
533
- reasonCode: normalized.reasonCode,
534
- layer: normalized.layer || fallback.layer,
535
- retryable: normalized.retryable === true,
536
- details: normalized.details || {}
537
- });
538
- throw normalized;
539
- }
540
- }
541
-
542
- async function readJson(path, missingCode, parseCode) {
543
- let response;
544
- try {
545
- response = await fetch(path, { cache: 'no-store' });
546
- } catch (error) {
547
- throw createError(missingCode, 'Failed to fetch ' + path + '.', 'loader', false, { cause: String(error) });
548
- }
549
- if (!response || response.ok !== true) {
550
- throw createError(missingCode, path + ' not found.', 'loader', false, { status: response ? response.status : null });
551
- }
552
- try {
553
- return await response.json();
554
- } catch (error) {
555
- throw createError(parseCode, path + ' is not valid JSON.', 'loader', false, { cause: String(error) });
556
- }
557
- }
558
-
559
- function normalizePath(path) {
560
- if (typeof path !== 'string') return '';
561
- return path.replace(/\\\\/g, '/').replace(/^\\.\\//, '');
562
- }
563
-
564
- function clampUnit(value, fallback) {
565
- const numeric = Number(value);
566
- if (!Number.isFinite(numeric)) return fallback;
567
- if (numeric <= 0) return 0;
568
- if (numeric >= 1) return 1;
569
- return numeric;
570
- }
571
-
572
- function createUnitColor(r, g, b, a) {
573
- return {
574
- r: clampUnit(r, 0),
575
- g: clampUnit(g, 0),
576
- b: clampUnit(b, 0),
577
- a: clampUnit(a == null ? 1 : a, 1)
578
- };
579
- }
580
-
581
- function createByteColor(r, g, b, a) {
582
- return {
583
- r: Math.max(0, Math.min(255, Math.round(Number(r) || 0))),
584
- g: Math.max(0, Math.min(255, Math.round(Number(g) || 0))),
585
- b: Math.max(0, Math.min(255, Math.round(Number(b) || 0))),
586
- a: Math.max(0, Math.min(255, Math.round(Number.isFinite(Number(a)) ? Number(a) : 255)))
587
- };
588
- }
589
-
590
- function normalizeColor(value, fallback) {
591
- const source = value && typeof value === 'object' ? value : null;
592
- const base = fallback && typeof fallback === 'object' ? fallback : createUnitColor(1, 1, 1, 1);
593
- if (!source) {
594
- return createUnitColor(base.r, base.g, base.b, base.a);
595
- }
596
-
597
- const rawR = Number(source.r);
598
- const rawG = Number(source.g);
599
- const rawB = Number(source.b);
600
- const rawA = source.a == null ? base.a : Number(source.a);
601
- const treatAsByteRange = [rawR, rawG, rawB, rawA].some((component) => Number.isFinite(component) && component > 1);
602
-
603
- if (treatAsByteRange) {
604
- return createUnitColor(
605
- Number.isFinite(rawR) ? rawR / 255 : base.r,
606
- Number.isFinite(rawG) ? rawG / 255 : base.g,
607
- Number.isFinite(rawB) ? rawB / 255 : base.b,
608
- Number.isFinite(rawA) ? rawA / 255 : base.a
609
- );
610
- }
611
-
612
- return createUnitColor(
613
- Number.isFinite(rawR) ? rawR : base.r,
614
- Number.isFinite(rawG) ? rawG : base.g,
615
- Number.isFinite(rawB) ? rawB : base.b,
616
- Number.isFinite(rawA) ? rawA : base.a
617
- );
618
- }
619
-
620
- function colorToCss(value, fallback) {
621
- const normalized = normalizeColor(value, fallback);
622
- return 'rgba('
623
- + Math.round(normalized.r * 255) + ', '
624
- + Math.round(normalized.g * 255) + ', '
625
- + Math.round(normalized.b * 255) + ', '
626
- + normalized.a + ')';
627
- }
628
-
629
- function normalizeCanvasSize(value, fallback) {
630
- const numeric = Number(value);
631
- if (!Number.isFinite(numeric) || numeric <= 0) return fallback;
632
- return Math.max(1, Math.floor(numeric));
633
- }
634
-
635
- function normalizePositiveNumber(value, fallback) {
636
- const numeric = Number(value);
637
- if (!Number.isFinite(numeric) || numeric <= 0) return fallback;
638
- return numeric;
639
- }
640
-
641
- function toFinite(value, fallback) {
642
- const numeric = Number(value);
643
- return Number.isFinite(numeric) ? numeric : fallback;
644
- }
645
-
646
- function toPositive(value, fallback) {
647
- const numeric = Number(value);
648
- return Number.isFinite(numeric) && numeric > 0 ? numeric : fallback;
649
- }
650
-
651
- function clamp01(value) {
652
- const numeric = Number(value);
653
- if (!Number.isFinite(numeric)) return 1;
654
- if (numeric <= 0) return 0;
655
- if (numeric >= 1) return 1;
656
- return numeric;
657
- }
658
-
659
- function isObject(value) {
660
- return value != null && typeof value === 'object';
661
- }
662
-
663
- function normalizeMouseButton(value) {
664
- const numeric = Number(value);
665
- if (!Number.isFinite(numeric) || numeric < 0) return 0;
666
- return Math.floor(numeric);
667
- }
668
-
669
- function sanitizeAssetSourcePath(value) {
670
- return String(value || '')
671
- .replace(/\\\\/g, '/')
672
- .replace(/^\\.\\//, '')
673
- .replace(/^\\/+/, '');
674
- }
675
-
676
- function isImageMediaType(value) {
677
- return typeof value === 'string' && value.startsWith('image/');
678
- }
679
-
680
- function normalizeTextAlign(value) {
681
- if (value === 'center' || value === 'right' || value === 'left') {
682
- return value;
683
- }
684
- return 'left';
685
- }
686
-
687
- function normalizeKeyName(value) {
688
- if (typeof value !== 'string' || value.length === 0) {
689
- return null;
690
- }
691
- const key = value.toLowerCase();
692
- switch (key) {
693
- case ' ':
694
- case 'spacebar':
695
- return 'space';
696
- case 'left':
697
- case 'arrowleft':
698
- return 'arrowleft';
699
- case 'right':
700
- case 'arrowright':
701
- return 'arrowright';
702
- case 'up':
703
- case 'arrowup':
704
- return 'arrowup';
705
- case 'down':
706
- case 'arrowdown':
707
- return 'arrowdown';
708
- case 'return':
709
- return 'enter';
710
- default:
711
- return key;
712
- }
713
- }
714
-
715
- function rectIntersects(a, b) {
716
- const ax = Number(a && a.x);
717
- const ay = Number(a && a.y);
718
- const aw = Number(a && a.w);
719
- const ah = Number(a && a.h);
720
- const bx = Number(b && b.x);
721
- const by = Number(b && b.y);
722
- const bw = Number(b && b.w);
723
- const bh = Number(b && b.h);
724
-
725
- if (![ax, ay, aw, ah, bx, by, bw, bh].every((value) => Number.isFinite(value))) {
726
- return false;
727
- }
728
-
729
- return ax < bx + bw && ax + aw > bx && ay < by + bh && ay + ah > by;
730
- }
731
-
732
- function resolveTarget(target) {
733
- if (typeof target === 'string') {
734
- return document.querySelector(target);
735
- }
736
- if (target && typeof target.appendChild === 'function') {
737
- return target;
738
- }
739
- return document.getElementById('aura-root') || document.body;
740
- }
741
-
742
- function ensureManifestValid(manifest) {
743
- if (!manifest || manifest.schema !== 'aurajs.web-build-manifest.v1') {
744
- throw createError(
745
- 'web_manifest_schema_unsupported',
746
- 'Manifest schema major version is unsupported.',
747
- 'loader',
748
- false,
749
- { schema: manifest && manifest.schema }
750
- );
751
- }
752
- if (!manifest.entrypoints || typeof manifest.entrypoints.bundle !== 'string' || manifest.entrypoints.bundle.length === 0) {
753
- throw createError('web_manifest_validation_failed', 'Manifest bundle entrypoint is missing.', 'loader', false, {});
754
- }
755
- }
756
-
757
- function ensureRuntimeConfigValid(runtimeConfig) {
758
- if (!runtimeConfig || runtimeConfig.schema !== 'aurajs.web-runtime-config.v1') {
759
- throw createError(
760
- 'web_runtime_config_validation_failed',
761
- 'Runtime config schema major version is unsupported.',
762
- 'loader',
763
- false,
764
- { schema: runtimeConfig && runtimeConfig.schema }
765
- );
766
- }
767
- }
768
-
769
- function normalizeCapabilityDeclaration(value) {
770
- const declaration = value && typeof value === 'object' ? value : {};
771
- const requiredApis = Array.isArray(declaration.requiredApis)
772
- ? Array.from(new Set(declaration.requiredApis
773
- .filter(function (entry) { return typeof entry === 'string'; })
774
- .map(function (entry) { return entry.trim(); })
775
- .filter(Boolean)))
776
- .sort(function (a, b) { return a.localeCompare(b); })
777
- : [];
778
- const declaredModules = declaration.optionalModules && typeof declaration.optionalModules === 'object'
779
- ? declaration.optionalModules
780
- : {};
781
- return {
782
- schema: typeof declaration.schema === 'string'
783
- ? declaration.schema
784
- : 'aurajs.web-capability-declaration.v1',
785
- source: typeof declaration.source === 'string' ? declaration.source : null,
786
- requiredApis: requiredApis,
787
- optionalModules: {
788
- physics: declaredModules.physics === true,
789
- network: declaredModules.network === true,
790
- multiplayer: declaredModules.multiplayer === true,
791
- steam: declaredModules.steam === true
792
- }
793
- };
794
- }
795
-
796
- function resolveDeclaredApi(root, apiPath) {
797
- if (typeof apiPath !== 'string' || apiPath.length === 0) {
798
- return { found: false, value: undefined };
799
- }
800
- const segments = apiPath.split('.').filter(Boolean);
801
- let current = root;
802
- for (const segment of segments) {
803
- if (
804
- current == null
805
- || (typeof current !== 'object' && typeof current !== 'function')
806
- || !(segment in current)
807
- ) {
808
- return { found: false, value: undefined };
809
- }
810
- current = current[segment];
811
- }
812
- return { found: current != null, value: current };
813
- }
814
-
815
- function collectCapabilityFailures(runtimeConfig, auraRef) {
816
- const declaration = normalizeCapabilityDeclaration(runtimeConfig && runtimeConfig.capabilities);
817
- const failures = [];
818
- const root = { aura: auraRef && typeof auraRef === 'object' ? auraRef : {} };
819
-
820
- for (const moduleName of ['physics', 'network', 'multiplayer', 'steam']) {
821
- if (declaration.optionalModules[moduleName] === true) {
822
- failures.push({
823
- kind: 'optionalModule',
824
- module: moduleName,
825
- reasonCode: 'web_optional_module_unsupported'
826
- });
827
- }
828
- }
829
-
830
- for (const apiPath of declaration.requiredApis) {
831
- const resolved = resolveDeclaredApi(root, apiPath);
832
- if (!resolved.found) {
833
- failures.push({
834
- kind: 'requiredApi',
835
- apiPath: apiPath,
836
- reasonCode: 'web_required_api_missing'
837
- });
838
- }
839
- }
840
-
841
- return {
842
- declaration: declaration,
843
- failures: failures
844
- };
845
- }
846
-
847
- function ensureCapabilityDeclarationSatisfied(runtimeConfig, auraRef) {
848
- const report = collectCapabilityFailures(runtimeConfig, auraRef);
849
- if (report.failures.length === 0) {
850
- return;
851
- }
852
-
853
- const missingRequiredApis = [];
854
- const unsupportedOptionalModules = [];
855
- for (const failure of report.failures) {
856
- if (failure.kind === 'requiredApi') {
857
- missingRequiredApis.push(failure.apiPath);
858
- } else if (failure.kind === 'optionalModule') {
859
- unsupportedOptionalModules.push(failure.module);
860
- }
861
- }
862
-
863
- let reasonCode = 'web_capability_gate_failed';
864
- if (missingRequiredApis.length > 0 && unsupportedOptionalModules.length === 0) {
865
- reasonCode = 'web_required_api_missing';
866
- } else if (unsupportedOptionalModules.length > 0 && missingRequiredApis.length === 0) {
867
- reasonCode = 'web_optional_module_unsupported';
868
- }
869
-
870
- throw createError(
871
- reasonCode,
872
- 'Browser runtime does not satisfy the declared capability contract.',
873
- 'loader',
874
- false,
875
- {
876
- schema: report.declaration.schema,
877
- source: report.declaration.source,
878
- missingRequiredApis: missingRequiredApis,
879
- unsupportedOptionalModules: unsupportedOptionalModules,
880
- failures: report.failures
881
- }
882
- );
883
- }
884
-
885
- function loadScript(path) {
886
- return new Promise((resolvePromise, rejectPromise) => {
887
- const script = document.createElement('script');
888
- script.src = path;
889
- script.async = false;
890
- script.onload = function () { resolvePromise(); };
891
- script.onerror = function () {
892
- rejectPromise(createError('web_bundle_load_failed', 'Failed to load ' + path + '.', 'loader', true, { path }));
893
- };
894
- document.head.appendChild(script);
895
- });
896
- }
897
-
898
- function createBrowserAuraSurface(runtimeConfig) {
899
- const defaultColor = createUnitColor(1, 1, 1, 1);
900
- let currentRuntimeConfig = runtimeConfig && typeof runtimeConfig === 'object' ? runtimeConfig : {};
901
- let currentCanvasConfig = currentRuntimeConfig.canvas && typeof currentRuntimeConfig.canvas === 'object'
902
- ? currentRuntimeConfig.canvas
903
- : {};
904
- let currentManifest = { assets: [] };
905
- let currentRootUrl = '.';
906
-
907
- const auraRef = globalRef.aura && typeof globalRef.aura === 'object'
908
- ? globalRef.aura
909
- : {};
910
- globalRef.aura = auraRef;
911
-
912
- const inputState = {
913
- down: new Set(),
914
- pendingPressed: new Set(),
915
- pendingReleased: new Set(),
916
- framePressed: new Set(),
917
- frameReleased: new Set(),
918
- mouseDown: new Set(),
919
- pendingMousePressed: new Set(),
920
- pendingMouseReleased: new Set(),
921
- frameMousePressed: new Set(),
922
- frameMouseReleased: new Set(),
923
- pendingMouseDeltaX: 0,
924
- pendingMouseDeltaY: 0,
925
- frameMouseDeltaX: 0,
926
- frameMouseDeltaY: 0
927
- };
928
-
929
- const assetState = {
930
- bySourcePath: new Map(),
931
- byOutputPath: new Map(),
932
- loaded: new Map(),
933
- storageFallback: new Map()
934
- };
935
-
936
- const runtime = {
937
- canvas: null,
938
- mountTarget: null,
939
- context2d: null,
940
- configuredWidth: normalizeCanvasSize(currentCanvasConfig.width, 1280),
941
- configuredHeight: normalizeCanvasSize(currentCanvasConfig.height, 720),
942
- resizeMode: currentCanvasConfig.resizeMode === 'fixed' ? 'fixed' : 'fit-container',
943
- pixelRatio: 1,
944
- width: normalizeCanvasSize(currentCanvasConfig.width, 1280),
945
- height: normalizeCanvasSize(currentCanvasConfig.height, 720),
946
- transformDepth: 0,
947
- worldTransformActive: false,
948
- cursorVisible: true,
949
- cursorLocked: false,
950
- listenersAttached: false,
951
- keydownListener: null,
952
- keyupListener: null,
953
- focusListener: null,
954
- blurListener: null,
955
- resizeListener: null,
956
- mousemoveListener: null,
957
- mousedownListener: null,
958
- mouseupListener: null,
959
- wheelListener: null
960
- };
961
-
962
- function ensureStyleObject(node) {
963
- if (!node || typeof node !== 'object') return null;
964
- if (!node.style || typeof node.style !== 'object') {
965
- node.style = {};
966
- }
967
- return node.style;
968
- }
969
-
970
- function ensureCanvasContext() {
971
- if (!runtime.canvas) return null;
972
- if (!runtime.context2d && typeof runtime.canvas.getContext === 'function') {
973
- runtime.context2d = runtime.canvas.getContext('2d');
974
- }
975
- return runtime.context2d;
976
- }
977
-
978
- function normalizeAssetKey(value) {
979
- return sanitizeAssetSourcePath(value);
980
- }
981
-
982
- function indexManifestAssets(manifest, rootUrl) {
983
- currentManifest = manifest && typeof manifest === 'object' ? manifest : { assets: [] };
984
- currentRootUrl = typeof rootUrl === 'string' && rootUrl.length > 0
985
- ? rootUrl.replace(/\\/$/, '')
986
- : '.';
987
- assetState.bySourcePath.clear();
988
- assetState.byOutputPath.clear();
989
- const entries = Array.isArray(currentManifest.assets) ? currentManifest.assets : [];
990
- for (const entry of entries) {
991
- if (!entry || typeof entry !== 'object') continue;
992
- const outputPath = normalizePath(entry.path);
993
- if (outputPath.length > 0) {
994
- assetState.byOutputPath.set(outputPath, entry);
995
- }
996
- const sourcePath = normalizeAssetKey(entry.sourcePath || outputPath);
997
- if (sourcePath.length > 0) {
998
- assetState.bySourcePath.set(sourcePath, entry);
999
- }
1000
- }
1001
- }
1002
-
1003
- function buildAssetUrl(entryPath) {
1004
- const normalized = normalizePath(entryPath);
1005
- const root = currentRootUrl && currentRootUrl.length > 0 ? currentRootUrl : '.';
1006
- return root + '/' + normalized;
1007
- }
1008
-
1009
- function resolveAssetEntry(source) {
1010
- const normalizedSource = normalizeAssetKey(source);
1011
- if (normalizedSource.length === 0) return null;
1012
- if (assetState.bySourcePath.has(normalizedSource)) {
1013
- return assetState.bySourcePath.get(normalizedSource);
1014
- }
1015
- const outputPath = normalizePath(normalizedSource);
1016
- if (assetState.byOutputPath.has(outputPath)) {
1017
- return assetState.byOutputPath.get(outputPath);
1018
- }
1019
- return null;
1020
- }
1021
-
1022
- function resolveAssetSourcePath(source) {
1023
- if (typeof source === 'string') {
1024
- return normalizeAssetKey(source);
1025
- }
1026
- if (source && typeof source === 'object') {
1027
- if (typeof source.sourcePath === 'string') return normalizeAssetKey(source.sourcePath);
1028
- if (typeof source.path === 'string') return normalizeAssetKey(source.path);
1029
- if (typeof source.name === 'string') return normalizeAssetKey(source.name);
1030
- }
1031
- return '';
1032
- }
1033
-
1034
- function resolveLoadedAsset(source) {
1035
- const key = resolveAssetSourcePath(source);
1036
- if (key.length === 0) return null;
1037
- return assetState.loaded.get(key) || null;
1038
- }
1039
-
1040
- function rememberLoadedAsset(sourcePath, handle) {
1041
- const key = normalizeAssetKey(sourcePath);
1042
- if (key.length === 0 || !handle || typeof handle !== 'object') return handle;
1043
- handle.sourcePath = key;
1044
- if (typeof handle.path !== 'string' || handle.path.length === 0) {
1045
- handle.path = key;
1046
- }
1047
- assetState.loaded.set(key, handle);
1048
- return handle;
1049
- }
1050
-
1051
- async function fetchAssetResponse(entry) {
1052
- if (!entry || typeof entry !== 'object') return null;
1053
- const assetUrl = buildAssetUrl(entry.path);
1054
- let response;
1055
- try {
1056
- response = await fetch(assetUrl, { cache: 'force-cache' });
1057
- } catch (_) {
1058
- return null;
1059
- }
1060
- if (!response || response.ok !== true) {
1061
- return null;
1062
- }
1063
- return response;
1064
- }
1065
-
1066
- async function readAssetBytes(entry) {
1067
- const response = await fetchAssetResponse(entry);
1068
- if (!response || typeof response.arrayBuffer !== 'function') {
1069
- return null;
1070
- }
1071
- try {
1072
- return new Uint8Array(await response.arrayBuffer());
1073
- } catch (_) {
1074
- return null;
1075
- }
1076
- }
1077
-
1078
- async function readAssetText(entry) {
1079
- const response = await fetchAssetResponse(entry);
1080
- if (!response || typeof response.text !== 'function') {
1081
- return null;
1082
- }
1083
- try {
1084
- return await response.text();
1085
- } catch (_) {
1086
- return null;
1087
- }
1088
- }
1089
-
1090
- async function loadImageHandle(sourcePath, entry) {
1091
- const existing = resolveLoadedAsset(sourcePath);
1092
- if (existing && existing.image) {
1093
- return existing;
1094
- }
1095
- const ImageCtor = typeof globalRef.Image === 'function' ? globalRef.Image : null;
1096
- const handle = existing || {
1097
- kind: 'image',
1098
- path: sourcePath,
1099
- sourcePath: sourcePath,
1100
- resolvedPath: entry && typeof entry.path === 'string' ? normalizePath(entry.path) : sourcePath,
1101
- mediaType: entry && typeof entry.mediaType === 'string' ? entry.mediaType : 'image/png',
1102
- image: null,
1103
- width: 0,
1104
- height: 0
1105
- };
1106
- if (!ImageCtor || !entry) {
1107
- return rememberLoadedAsset(sourcePath, handle);
1108
- }
1109
- try {
1110
- const image = await new Promise(function (resolvePromise, rejectPromise) {
1111
- const node = new ImageCtor();
1112
- node.onload = function () { resolvePromise(node); };
1113
- node.onerror = function () { rejectPromise(new Error('image_load_failed')); };
1114
- node.src = buildAssetUrl(entry.path);
1115
- });
1116
- handle.image = image;
1117
- handle.width = normalizeCanvasSize(image.naturalWidth || image.width, 1);
1118
- handle.height = normalizeCanvasSize(image.naturalHeight || image.height, 1);
1119
- } catch (_) {}
1120
- return rememberLoadedAsset(sourcePath, handle);
1121
- }
1122
-
1123
- function createBrowserSoundHandle(sourcePath, entry, bytes) {
1124
- return rememberLoadedAsset(sourcePath, {
1125
- kind: 'sound',
1126
- path: sourcePath,
1127
- sourcePath: sourcePath,
1128
- resolvedPath: entry && typeof entry.path === 'string' ? normalizePath(entry.path) : sourcePath,
1129
- mediaType: entry && typeof entry.mediaType === 'string' ? entry.mediaType : 'audio/ogg',
1130
- bytes: bytes instanceof Uint8Array ? bytes : new Uint8Array(),
1131
- playbackSupported: false,
1132
- reasonCode: 'web_audio_playback_unsupported',
1133
- detail: 'Browser runtime resolves sound assets but does not support aura.audio playback. [reason:web_audio_playback_unsupported]'
1134
- });
1135
- }
1136
-
1137
- async function loadAssetRecord(source) {
1138
- if (Array.isArray(source)) {
1139
- const loaded = [];
1140
- for (const entry of source) {
1141
- const next = await loadAssetRecord(entry);
1142
- if (next) loaded.push(next);
1143
- }
1144
- return loaded;
1145
- }
1146
- const sourcePath = resolveAssetSourcePath(source);
1147
- if (sourcePath.length === 0) return null;
1148
- const existing = resolveLoadedAsset(sourcePath);
1149
- if (existing) return existing;
1150
- const entry = resolveAssetEntry(sourcePath);
1151
- if (!entry) return null;
1152
- if (isImageMediaType(entry.mediaType)) {
1153
- return await loadImageHandle(sourcePath, entry);
1154
- }
1155
- const bytes = await readAssetBytes(entry);
1156
- if (entry.mediaType && entry.mediaType.startsWith('audio/')) {
1157
- return createBrowserSoundHandle(sourcePath, entry, bytes);
1158
- }
1159
- if (!bytes) {
1160
- return rememberLoadedAsset(sourcePath, {
1161
- kind: 'asset',
1162
- path: sourcePath,
1163
- sourcePath: sourcePath,
1164
- resolvedPath: normalizePath(entry.path),
1165
- mediaType: entry.mediaType,
1166
- bytes: new Uint8Array()
1167
- });
1168
- }
1169
- const handle = {
1170
- kind: 'asset',
1171
- path: sourcePath,
1172
- sourcePath: sourcePath,
1173
- resolvedPath: normalizePath(entry.path),
1174
- mediaType: entry.mediaType,
1175
- bytes: bytes
1176
- };
1177
- if (entry.mediaType === 'application/json') {
1178
- const text = typeof TextDecoder === 'function'
1179
- ? new TextDecoder('utf-8').decode(bytes)
1180
- : String.fromCharCode.apply(null, Array.from(bytes));
1181
- handle.text = text;
1182
- try {
1183
- handle.json = JSON.parse(text);
1184
- } catch (_) {
1185
- handle.json = null;
1186
- }
1187
- } else if (typeof entry.mediaType === 'string' && entry.mediaType.startsWith('text/')) {
1188
- handle.text = typeof TextDecoder === 'function'
1189
- ? new TextDecoder('utf-8').decode(bytes)
1190
- : String.fromCharCode.apply(null, Array.from(bytes));
1191
- }
1192
- return rememberLoadedAsset(sourcePath, handle);
1193
- }
1194
-
1195
- function normalizeMousePosition(event) {
1196
- const source = event && typeof event === 'object' ? event : {};
1197
- if (Number.isFinite(Number(source.offsetX)) && Number.isFinite(Number(source.offsetY))) {
1198
- return {
1199
- x: Number(source.offsetX),
1200
- y: Number(source.offsetY)
1201
- };
1202
- }
1203
- const canvas = runtime.canvas;
1204
- const rect = canvas && typeof canvas.getBoundingClientRect === 'function'
1205
- ? canvas.getBoundingClientRect()
1206
- : null;
1207
- const clientX = toFinite(source.clientX, auraRef.input.mouse.x);
1208
- const clientY = toFinite(source.clientY, auraRef.input.mouse.y);
1209
- if (rect) {
1210
- return {
1211
- x: clientX - toFinite(rect.left, 0),
1212
- y: clientY - toFinite(rect.top, 0)
1213
- };
1214
- }
1215
- return {
1216
- x: clientX,
1217
- y: clientY
1218
- };
1219
- }
1220
-
1221
- function syncMousePosition(event) {
1222
- const point = normalizeMousePosition(event);
1223
- const movementX = Number(event && event.movementX);
1224
- const movementY = Number(event && event.movementY);
1225
- const deltaX = Number.isFinite(movementX) ? movementX : point.x - auraRef.input.mouse.x;
1226
- const deltaY = Number.isFinite(movementY) ? movementY : point.y - auraRef.input.mouse.y;
1227
- inputState.pendingMouseDeltaX += deltaX;
1228
- inputState.pendingMouseDeltaY += deltaY;
1229
- auraRef.input.mouse.x = point.x;
1230
- auraRef.input.mouse.y = point.y;
1231
- }
1232
-
1233
- function clearMouseDeltaState() {
1234
- inputState.pendingMouseDeltaX = 0;
1235
- inputState.pendingMouseDeltaY = 0;
1236
- inputState.frameMouseDeltaX = 0;
1237
- inputState.frameMouseDeltaY = 0;
1238
- }
1239
-
1240
- function clearTransientInputState() {
1241
- inputState.pendingPressed.clear();
1242
- inputState.pendingReleased.clear();
1243
- inputState.framePressed.clear();
1244
- inputState.frameReleased.clear();
1245
- inputState.pendingMousePressed.clear();
1246
- inputState.pendingMouseReleased.clear();
1247
- inputState.frameMousePressed.clear();
1248
- inputState.frameMouseReleased.clear();
1249
- clearMouseDeltaState();
1250
- }
1251
-
1252
- function clearHeldInputState() {
1253
- inputState.down.clear();
1254
- inputState.mouseDown.clear();
1255
- clearTransientInputState();
1256
- }
1257
-
1258
- function applyCursorAppearance() {
1259
- const style = ensureStyleObject(runtime.canvas);
1260
- if (!style) return;
1261
- style.cursor = (!runtime.cursorVisible || runtime.cursorLocked) ? 'none' : 'default';
1262
- }
1263
-
1264
- function syncCanvasSize(notifyResize) {
1265
- let width = runtime.configuredWidth;
1266
- let height = runtime.configuredHeight;
1267
- if (runtime.resizeMode === 'fit-container') {
1268
- const containerWidth = runtime.mountTarget
1269
- ? normalizeCanvasSize(runtime.mountTarget.clientWidth, 0)
1270
- : 0;
1271
- const containerHeight = runtime.mountTarget
1272
- ? normalizeCanvasSize(runtime.mountTarget.clientHeight, 0)
1273
- : 0;
1274
- if (containerWidth > 0 && containerHeight > 0) {
1275
- width = containerWidth;
1276
- height = containerHeight;
1277
- }
1278
- }
1279
-
1280
- runtime.width = normalizeCanvasSize(width, runtime.configuredWidth);
1281
- runtime.height = normalizeCanvasSize(height, runtime.configuredHeight);
1282
- runtime.pixelRatio = Math.min(Math.max(normalizePositiveNumber(globalRef.devicePixelRatio, 1), 1), 2);
1283
-
1284
- auraRef.window.width = runtime.width;
1285
- auraRef.window.height = runtime.height;
1286
- auraRef.window.pixelRatio = runtime.pixelRatio;
1287
-
1288
- if (runtime.canvas) {
1289
- runtime.canvas.width = Math.max(1, Math.round(runtime.width * runtime.pixelRatio));
1290
- runtime.canvas.height = Math.max(1, Math.round(runtime.height * runtime.pixelRatio));
1291
- runtime.canvas.tabIndex = 0;
1292
- const style = ensureStyleObject(runtime.canvas);
1293
- if (style) {
1294
- style.width = runtime.width + 'px';
1295
- style.height = runtime.height + 'px';
1296
- style.display = 'block';
1297
- }
1298
- }
1299
-
1300
- if (notifyResize && typeof auraRef.onResize === 'function') {
1301
- auraRef.onResize(runtime.width, runtime.height);
1302
- }
1303
- }
1304
-
1305
- function resetDrawState() {
1306
- const ctx = ensureCanvasContext();
1307
- if (!ctx) return;
1308
- if (typeof ctx.setTransform === 'function') {
1309
- ctx.setTransform(runtime.pixelRatio, 0, 0, runtime.pixelRatio, 0, 0);
1310
- } else {
1311
- if (typeof ctx.resetTransform === 'function') {
1312
- ctx.resetTransform();
1313
- }
1314
- if (typeof ctx.scale === 'function') {
1315
- ctx.scale(runtime.pixelRatio, runtime.pixelRatio);
1316
- }
1317
- }
1318
- runtime.transformDepth = 0;
1319
- runtime.worldTransformActive = false;
1320
- ctx.globalAlpha = 1;
1321
- ctx.textAlign = 'left';
1322
- ctx.textBaseline = 'top';
1323
- }
1324
-
1325
- function applyWorldTransform() {
1326
- const ctx = ensureCanvasContext();
1327
- if (!ctx || runtime.worldTransformActive) return ctx;
1328
- const camera = auraRef.camera && typeof auraRef.camera === 'object' ? auraRef.camera : null;
1329
- if (camera) {
1330
- const zoom = normalizePositiveNumber(camera.zoom, 1);
1331
- const rotation = Number(camera.rotation) || 0;
1332
- const x = Number(camera.x) || 0;
1333
- const y = Number(camera.y) || 0;
1334
- if (typeof ctx.scale === 'function' && zoom !== 1) {
1335
- ctx.scale(zoom, zoom);
1336
- }
1337
- if (typeof ctx.rotate === 'function' && rotation !== 0) {
1338
- ctx.rotate(rotation);
1339
- }
1340
- if (typeof ctx.translate === 'function' && (x !== 0 || y !== 0)) {
1341
- ctx.translate(-x, -y);
1342
- }
1343
- }
1344
- runtime.worldTransformActive = true;
1345
- return ctx;
1346
- }
1347
-
1348
- function ensureWorldTransform() {
1349
- const ctx = ensureCanvasContext();
1350
- if (!ctx) return null;
1351
- return runtime.worldTransformActive ? ctx : applyWorldTransform();
1352
- }
1353
-
1354
- function normalizeTextOptions(sizeOrOptions, colorMaybe) {
1355
- if (sizeOrOptions && typeof sizeOrOptions === 'object' && !Array.isArray(sizeOrOptions)) {
1356
- return sizeOrOptions;
1357
- }
1358
- if (Number.isFinite(Number(sizeOrOptions))) {
1359
- return {
1360
- size: Number(sizeOrOptions),
1361
- color: colorMaybe
1362
- };
1363
- }
1364
- return {};
1365
- }
1366
-
1367
- function applyFont(options) {
1368
- const ctx = ensureCanvasContext();
1369
- const source = options && typeof options === 'object' ? options : {};
1370
- const size = normalizePositiveNumber(source.size, 16);
1371
- const family = typeof source.font === 'string' && source.font.trim().length > 0
1372
- ? source.font.trim()
1373
- : 'sans-serif';
1374
- if (ctx) {
1375
- ctx.font = size + 'px ' + family;
1376
- ctx.textAlign = normalizeTextAlign(source.align);
1377
- ctx.textBaseline = 'top';
1378
- }
1379
- return { size, align: normalizeTextAlign(source.align) };
1380
- }
1381
-
1382
- function withScreenSpace(callback) {
1383
- const ctx = ensureCanvasContext();
1384
- if (!ctx || typeof callback !== 'function') return null;
1385
- if (typeof ctx.save === 'function') {
1386
- ctx.save();
1387
- }
1388
- if (typeof ctx.setTransform === 'function') {
1389
- ctx.setTransform(runtime.pixelRatio, 0, 0, runtime.pixelRatio, 0, 0);
1390
- } else {
1391
- if (typeof ctx.resetTransform === 'function') {
1392
- ctx.resetTransform();
1393
- }
1394
- if (typeof ctx.scale === 'function') {
1395
- ctx.scale(runtime.pixelRatio, runtime.pixelRatio);
1396
- }
1397
- }
1398
- try {
1399
- return callback(ctx);
1400
- } finally {
1401
- if (typeof ctx.restore === 'function') {
1402
- ctx.restore();
1403
- }
1404
- }
1405
- }
1406
-
1407
- function resolveStorageBackend() {
1408
- return globalRef.localStorage && typeof globalRef.localStorage.getItem === 'function'
1409
- ? globalRef.localStorage
1410
- : null;
1411
- }
1412
-
1413
- function storageKey(key) {
1414
- return 'aurajs:' + String(key || '');
1415
- }
1416
-
1417
- function readStorage(key) {
1418
- const normalizedKey = String(key || '');
1419
- if (normalizedKey.length === 0) return null;
1420
- const backend = resolveStorageBackend();
1421
- const namespaced = storageKey(normalizedKey);
1422
- let raw = null;
1423
- if (backend) {
1424
- try {
1425
- raw = backend.getItem(namespaced);
1426
- } catch (_) {
1427
- raw = null;
1428
- }
1429
- } else if (assetState.storageFallback.has(namespaced)) {
1430
- raw = assetState.storageFallback.get(namespaced);
1431
- }
1432
- if (raw == null) return null;
1433
- try {
1434
- return JSON.parse(raw);
1435
- } catch (_) {
1436
- return raw;
1437
- }
1438
- }
1439
-
1440
- function writeStorage(key, value) {
1441
- const normalizedKey = String(key || '');
1442
- if (normalizedKey.length === 0) return false;
1443
- const payload = JSON.stringify(value);
1444
- const backend = resolveStorageBackend();
1445
- const namespaced = storageKey(normalizedKey);
1446
- if (backend) {
1447
- try {
1448
- backend.setItem(namespaced, payload);
1449
- return true;
1450
- } catch (_) {
1451
- return false;
1452
- }
1453
- }
1454
- assetState.storageFallback.set(namespaced, payload);
1455
- return true;
1456
- }
1457
-
1458
- function deleteStorage(key) {
1459
- const normalizedKey = String(key || '');
1460
- if (normalizedKey.length === 0) return false;
1461
- const namespaced = storageKey(normalizedKey);
1462
- const backend = resolveStorageBackend();
1463
- if (backend) {
1464
- try {
1465
- backend.removeItem(namespaced);
1466
- return true;
1467
- } catch (_) {
1468
- return false;
1469
- }
1470
- }
1471
- return assetState.storageFallback.delete(namespaced);
1472
- }
1473
-
1474
- const camera = auraRef.camera && typeof auraRef.camera === 'object' ? auraRef.camera : {};
1475
- let cameraBaseX = Number(camera.x) || 0;
1476
- let cameraBaseY = Number(camera.y) || 0;
1477
- let cameraBaseZoom = normalizePositiveNumber(camera.zoom, 1);
1478
- let cameraBaseRotation = Number(camera.rotation) || 0;
1479
- let cameraShakeX = 0;
1480
- let cameraShakeY = 0;
1481
- let cameraFollowState = null;
1482
- let cameraDeadzone = null;
1483
- let cameraBounds = null;
1484
- let nextCameraEffectId = 1;
1485
- let nextCameraListenerId = 1;
1486
- const cameraEffects = [];
1487
- const cameraEffectListeners = [];
1488
-
1489
- function applyCameraBounds() {
1490
- if (!cameraBounds) return;
1491
- const maxX = cameraBounds.x + cameraBounds.width;
1492
- const maxY = cameraBounds.y + cameraBounds.height;
1493
- cameraBaseX = Math.max(cameraBounds.x, Math.min(cameraBaseX, maxX));
1494
- cameraBaseY = Math.max(cameraBounds.y, Math.min(cameraBaseY, maxY));
1495
- }
1496
-
1497
- function normalizeFollowOptions(options) {
1498
- if (options == null) {
1499
- return {
1500
- lerpX: 1,
1501
- lerpY: 1,
1502
- offsetX: 0,
1503
- offsetY: 0
1504
- };
1505
- }
1506
- if (!isObject(options)) return null;
1507
- return {
1508
- lerpX: clamp01(options.lerpX),
1509
- lerpY: clamp01(options.lerpY),
1510
- offsetX: toFinite(options.offsetX, 0),
1511
- offsetY: toFinite(options.offsetY, 0)
1512
- };
1513
- }
1514
-
1515
- function normalizeDeadzone(value) {
1516
- const input = isObject(value) ? value : null;
1517
- const zoneWidth = toFinite(input && input.width, Number.NaN);
1518
- const zoneHeight = toFinite(input && input.height, Number.NaN);
1519
- if (!(zoneWidth > 0) || !(zoneHeight > 0)) return null;
1520
- return {
1521
- x: toFinite(input && input.x, 0),
1522
- y: toFinite(input && input.y, 0),
1523
- width: zoneWidth,
1524
- height: zoneHeight
1525
- };
1526
- }
1527
-
1528
- function normalizeBounds(value) {
1529
- const input = isObject(value) ? value : null;
1530
- const zoneWidth = toFinite(input && input.width, Number.NaN);
1531
- const zoneHeight = toFinite(input && input.height, Number.NaN);
1532
- if (!(zoneWidth >= 0) || !(zoneHeight >= 0)) return null;
1533
- return {
1534
- x: toFinite(input && input.x, 0),
1535
- y: toFinite(input && input.y, 0),
1536
- width: zoneWidth,
1537
- height: zoneHeight
1538
- };
1539
- }
1540
-
1541
- function resolveFollowTarget(target) {
1542
- let source = target;
1543
- if (typeof source === 'function') {
1544
- try {
1545
- source = source();
1546
- } catch (_) {
1547
- return null;
1548
- }
1549
- }
1550
- if (!isObject(source)) return null;
1551
- const x = toFinite(source.x, Number.NaN);
1552
- const y = toFinite(source.y, Number.NaN);
1553
- if (!Number.isFinite(x) || !Number.isFinite(y)) return null;
1554
- return { x: x, y: y };
1555
- }
1556
-
1557
- function emitCameraEffectEvent(event) {
1558
- if (cameraEffectListeners.length === 0) return;
1559
- const ordered = cameraEffectListeners.slice().sort(function (a, b) {
1560
- return (a.order - b.order) || (a.id - b.id);
1561
- });
1562
- for (const listener of ordered) {
1563
- try {
1564
- listener.callback(event);
1565
- } catch (_) {}
1566
- }
1567
- }
1568
-
1569
- Object.defineProperties(camera, {
1570
- x: {
1571
- enumerable: true,
1572
- configurable: false,
1573
- get: function () { return cameraBaseX + cameraShakeX; },
1574
- set: function (value) {
1575
- const numeric = Number(value);
1576
- if (Number.isFinite(numeric)) cameraBaseX = numeric;
1577
- }
1578
- },
1579
- y: {
1580
- enumerable: true,
1581
- configurable: false,
1582
- get: function () { return cameraBaseY + cameraShakeY; },
1583
- set: function (value) {
1584
- const numeric = Number(value);
1585
- if (Number.isFinite(numeric)) cameraBaseY = numeric;
1586
- }
1587
- },
1588
- zoom: {
1589
- enumerable: true,
1590
- configurable: false,
1591
- get: function () { return cameraBaseZoom; },
1592
- set: function (value) {
1593
- const numeric = Number(value);
1594
- if (Number.isFinite(numeric) && numeric > 0) cameraBaseZoom = numeric;
1595
- }
1596
- },
1597
- rotation: {
1598
- enumerable: true,
1599
- configurable: false,
1600
- get: function () { return cameraBaseRotation; },
1601
- set: function (value) {
1602
- const numeric = Number(value);
1603
- if (Number.isFinite(numeric)) cameraBaseRotation = numeric;
1604
- }
1605
- }
1606
- });
1607
-
1608
- camera.getState = function () {
1609
- return {
1610
- x: cameraBaseX + cameraShakeX,
1611
- y: cameraBaseY + cameraShakeY,
1612
- zoom: cameraBaseZoom,
1613
- rotation: cameraBaseRotation,
1614
- following: !!cameraFollowState,
1615
- activeEffects: cameraEffects.length,
1616
- deadzone: cameraDeadzone ? { x: cameraDeadzone.x, y: cameraDeadzone.y, width: cameraDeadzone.width, height: cameraDeadzone.height } : null,
1617
- bounds: cameraBounds ? { x: cameraBounds.x, y: cameraBounds.y, width: cameraBounds.width, height: cameraBounds.height } : null
1618
- };
1619
- };
1620
-
1621
- camera.follow = function (target, options) {
1622
- if (!(typeof target === 'function' || isObject(target))) {
1623
- return { ok: false, reasonCode: 'invalid_follow_target' };
1624
- }
1625
- const normalized = normalizeFollowOptions(options);
1626
- if (!normalized) return { ok: false, reasonCode: 'invalid_follow_options' };
1627
- cameraFollowState = {
1628
- target: target,
1629
- lerpX: normalized.lerpX,
1630
- lerpY: normalized.lerpY,
1631
- offsetX: normalized.offsetX,
1632
- offsetY: normalized.offsetY
1633
- };
1634
- return { ok: true, reasonCode: 'camera_follow_started' };
1635
- };
1636
-
1637
- camera.stopFollow = function () {
1638
- const stopped = !!cameraFollowState;
1639
- cameraFollowState = null;
1640
- return { ok: true, stopped: stopped, reasonCode: 'camera_follow_stopped' };
1641
- };
1642
-
1643
- camera.setDeadzone = function (value, maybeHeight) {
1644
- const normalized = isObject(value)
1645
- ? normalizeDeadzone(value)
1646
- : normalizeDeadzone({ width: value, height: maybeHeight });
1647
- if (!normalized) return { ok: false, reasonCode: 'invalid_deadzone' };
1648
- cameraDeadzone = normalized;
1649
- return { ok: true, reasonCode: 'camera_deadzone_set' };
1650
- };
1651
-
1652
- camera.clearDeadzone = function () {
1653
- cameraDeadzone = null;
1654
- return { ok: true, reasonCode: 'camera_deadzone_cleared' };
1655
- };
1656
-
1657
- camera.setBounds = function (xOrBounds, y, boundsWidth, boundsHeight) {
1658
- const normalized = isObject(xOrBounds)
1659
- ? normalizeBounds(xOrBounds)
1660
- : normalizeBounds({ x: xOrBounds, y: y, width: boundsWidth, height: boundsHeight });
1661
- if (!normalized) return { ok: false, reasonCode: 'invalid_bounds' };
1662
- cameraBounds = normalized;
1663
- applyCameraBounds();
1664
- return { ok: true, reasonCode: 'camera_bounds_set' };
1665
- };
1666
-
1667
- camera.clearBounds = function () {
1668
- cameraBounds = null;
1669
- return { ok: true, reasonCode: 'camera_bounds_cleared' };
1670
- };
1671
-
1672
- camera.pan = function (x, y, options) {
1673
- const targetX = Number(x);
1674
- const targetY = Number(y);
1675
- if (!Number.isFinite(targetX) || !Number.isFinite(targetY)) {
1676
- return { ok: false, reasonCode: 'invalid_pan_target' };
1677
- }
1678
- if (options != null && !isObject(options)) return { ok: false, reasonCode: 'invalid_pan_options' };
1679
- const duration = toPositive(options && options.duration, 0.25);
1680
- if (!(duration > 0)) return { ok: false, reasonCode: 'invalid_pan_duration' };
1681
- const effectId = nextCameraEffectId++;
1682
- cameraEffects.push({
1683
- id: effectId,
1684
- type: 'pan',
1685
- duration: duration,
1686
- elapsed: 0,
1687
- startX: cameraBaseX,
1688
- startY: cameraBaseY,
1689
- targetX: targetX,
1690
- targetY: targetY
1691
- });
1692
- return { ok: true, effectId: effectId, reasonCode: 'camera_pan_started' };
1693
- };
1694
- camera.panTo = camera.pan;
1695
-
1696
- camera.zoomTo = function (value, options) {
1697
- const targetZoom = Number(value);
1698
- if (!Number.isFinite(targetZoom) || !(targetZoom > 0)) {
1699
- return { ok: false, reasonCode: 'invalid_zoom_target' };
1700
- }
1701
- if (options != null && !isObject(options)) return { ok: false, reasonCode: 'invalid_zoom_options' };
1702
- const duration = toPositive(options && options.duration, 0.25);
1703
- if (!(duration > 0)) return { ok: false, reasonCode: 'invalid_zoom_duration' };
1704
- const effectId = nextCameraEffectId++;
1705
- cameraEffects.push({
1706
- id: effectId,
1707
- type: 'zoom',
1708
- duration: duration,
1709
- elapsed: 0,
1710
- startZoom: cameraBaseZoom,
1711
- targetZoom: targetZoom
1712
- });
1713
- return { ok: true, effectId: effectId, reasonCode: 'camera_zoom_started' };
1714
- };
1715
-
1716
- camera.rotateTo = function (value, options) {
1717
- const targetRotation = Number(value);
1718
- if (!Number.isFinite(targetRotation)) {
1719
- return { ok: false, reasonCode: 'invalid_rotation_target' };
1720
- }
1721
- if (options != null && !isObject(options)) return { ok: false, reasonCode: 'invalid_rotation_options' };
1722
- const duration = toPositive(options && options.duration, 0.25);
1723
- if (!(duration > 0)) return { ok: false, reasonCode: 'invalid_rotation_duration' };
1724
- const effectId = nextCameraEffectId++;
1725
- cameraEffects.push({
1726
- id: effectId,
1727
- type: 'rotate',
1728
- duration: duration,
1729
- elapsed: 0,
1730
- startRotation: cameraBaseRotation,
1731
- targetRotation: targetRotation
1732
- });
1733
- return { ok: true, effectId: effectId, reasonCode: 'camera_rotation_started' };
1734
- };
1735
-
1736
- camera.shake = function (options) {
1737
- const source = options == null ? {} : options;
1738
- if (!isObject(source)) return { ok: false, reasonCode: 'invalid_shake_options' };
1739
- const sharedIntensity = Number.isFinite(Number(source.intensity))
1740
- ? Number(source.intensity)
1741
- : null;
1742
- const intensityX = toFinite(source.intensityX, sharedIntensity != null ? sharedIntensity : 6);
1743
- const intensityY = toFinite(source.intensityY, sharedIntensity != null ? sharedIntensity : 6);
1744
- if (!(intensityX >= 0) || !(intensityY >= 0)) {
1745
- return { ok: false, reasonCode: 'invalid_shake_intensity' };
1746
- }
1747
- const duration = toPositive(source.duration, 0.3);
1748
- if (!(duration > 0)) return { ok: false, reasonCode: 'invalid_shake_duration' };
1749
- const frequency = toPositive(source.frequency, 30);
1750
- if (!(frequency > 0)) return { ok: false, reasonCode: 'invalid_shake_frequency' };
1751
- const effectId = nextCameraEffectId++;
1752
- cameraEffects.push({
1753
- id: effectId,
1754
- type: 'shake',
1755
- duration: duration,
1756
- elapsed: 0,
1757
- intensityX: intensityX,
1758
- intensityY: intensityY,
1759
- frequency: frequency,
1760
- seed: effectId * 0.61803398875
1761
- });
1762
- return { ok: true, effectId: effectId, reasonCode: 'camera_shake_started' };
1763
- };
1764
-
1765
- camera.clearEffects = function () {
1766
- const cleared = cameraEffects.length;
1767
- cameraEffects.length = 0;
1768
- cameraShakeX = 0;
1769
- cameraShakeY = 0;
1770
- return { ok: true, cleared: cleared, reasonCode: 'camera_effects_cleared' };
1771
- };
1772
-
1773
- camera.onEffectComplete = function (callback, order) {
1774
- if (typeof callback !== 'function') {
1775
- return { ok: false, reasonCode: 'invalid_effect_callback' };
1776
- }
1777
- const listener = {
1778
- id: nextCameraListenerId++,
1779
- callback: callback,
1780
- order: Number.isFinite(Number(order)) ? Number(order) : 0
1781
- };
1782
- cameraEffectListeners.push(listener);
1783
- return { ok: true, listenerId: listener.id, reasonCode: 'camera_effect_listener_registered' };
1784
- };
1785
-
1786
- camera.offEffectComplete = function (listenerId) {
1787
- if (!Number.isInteger(listenerId) || listenerId <= 0) return false;
1788
- const index = cameraEffectListeners.findIndex(function (entry) {
1789
- return entry.id === listenerId;
1790
- });
1791
- if (index < 0) return false;
1792
- cameraEffectListeners.splice(index, 1);
1793
- return true;
1794
- };
1795
-
1796
- camera.update = function (dt) {
1797
- const delta = Number(dt);
1798
- if (!Number.isFinite(delta) || !(delta > 0)) {
1799
- return { ok: false, reasonCode: 'invalid_dt' };
1800
- }
1801
-
1802
- cameraShakeX = 0;
1803
- cameraShakeY = 0;
1804
-
1805
- if (cameraFollowState) {
1806
- const targetPoint = resolveFollowTarget(cameraFollowState.target);
1807
- if (targetPoint) {
1808
- let targetX = targetPoint.x + cameraFollowState.offsetX;
1809
- let targetY = targetPoint.y + cameraFollowState.offsetY;
1810
-
1811
- if (cameraDeadzone) {
1812
- const left = cameraBaseX + cameraDeadzone.x;
1813
- const right = left + cameraDeadzone.width;
1814
- const top = cameraBaseY + cameraDeadzone.y;
1815
- const bottom = top + cameraDeadzone.height;
1816
-
1817
- if (targetX < left) targetX = targetX - cameraDeadzone.x;
1818
- else if (targetX > right) targetX = targetX - cameraDeadzone.x - cameraDeadzone.width;
1819
- else targetX = cameraBaseX;
1820
-
1821
- if (targetY < top) targetY = targetY - cameraDeadzone.y;
1822
- else if (targetY > bottom) targetY = targetY - cameraDeadzone.y - cameraDeadzone.height;
1823
- else targetY = cameraBaseY;
1824
- }
1825
-
1826
- cameraBaseX += (targetX - cameraBaseX) * cameraFollowState.lerpX;
1827
- cameraBaseY += (targetY - cameraBaseY) * cameraFollowState.lerpY;
1828
- }
1829
- }
1830
-
1831
- const completedEffects = [];
1832
- for (const effect of cameraEffects) {
1833
- effect.elapsed += delta;
1834
- const progress = effect.duration <= 0 ? 1 : Math.min(effect.elapsed / effect.duration, 1);
1835
- if (effect.type === 'pan') {
1836
- cameraBaseX = effect.startX + ((effect.targetX - effect.startX) * progress);
1837
- cameraBaseY = effect.startY + ((effect.targetY - effect.startY) * progress);
1838
- } else if (effect.type === 'zoom') {
1839
- cameraBaseZoom = effect.startZoom + ((effect.targetZoom - effect.startZoom) * progress);
1840
- } else if (effect.type === 'rotate') {
1841
- cameraBaseRotation = effect.startRotation + ((effect.targetRotation - effect.startRotation) * progress);
1842
- } else if (effect.type === 'shake') {
1843
- const amplitude = 1 - progress;
1844
- const angle = (effect.seed + (effect.elapsed * effect.frequency)) * 6.283185307179586;
1845
- cameraShakeX += Math.sin(angle) * effect.intensityX * amplitude;
1846
- cameraShakeY += Math.cos(angle * 1.17) * effect.intensityY * amplitude;
1847
- }
1848
- if (progress >= 1) completedEffects.push(effect);
1849
- }
1850
-
1851
- if (completedEffects.length > 0) {
1852
- for (const completed of completedEffects) {
1853
- const index = cameraEffects.indexOf(completed);
1854
- if (index >= 0) cameraEffects.splice(index, 1);
1855
- }
1856
- completedEffects.sort(function (a, b) { return a.id - b.id; });
1857
- for (const completed of completedEffects) {
1858
- emitCameraEffectEvent({
1859
- type: 'effect_complete',
1860
- effectType: completed.type,
1861
- effectId: completed.id,
1862
- reasonCode: 'camera_effect_complete'
1863
- });
1864
- }
1865
- }
1866
-
1867
- applyCameraBounds();
1868
-
1869
- return {
1870
- ok: true,
1871
- reasonCode: 'camera_updated',
1872
- x: cameraBaseX + cameraShakeX,
1873
- y: cameraBaseY + cameraShakeY,
1874
- zoom: cameraBaseZoom,
1875
- rotation: cameraBaseRotation,
1876
- following: !!cameraFollowState,
1877
- activeEffects: cameraEffects.length
1878
- };
1879
- };
1880
-
1881
- function attachListeners() {
1882
- if (runtime.listenersAttached) return;
1883
- runtime.listenersAttached = true;
1884
-
1885
- runtime.keydownListener = function (event) {
1886
- const key = normalizeKeyName(event && (event.key || event.code));
1887
- if (!key) return;
1888
- if (!inputState.down.has(key)) {
1889
- inputState.pendingPressed.add(key);
1890
- }
1891
- inputState.down.add(key);
1892
- if (event && typeof event.preventDefault === 'function' && (key === 'space' || key.startsWith('arrow'))) {
1893
- event.preventDefault();
1894
- }
1895
- };
1896
-
1897
- runtime.keyupListener = function (event) {
1898
- const key = normalizeKeyName(event && (event.key || event.code));
1899
- if (!key) return;
1900
- inputState.down.delete(key);
1901
- inputState.pendingReleased.add(key);
1902
- if (event && typeof event.preventDefault === 'function' && (key === 'space' || key.startsWith('arrow'))) {
1903
- event.preventDefault();
1904
- }
1905
- };
1906
-
1907
- runtime.mousemoveListener = function (event) {
1908
- syncMousePosition(event);
1909
- };
1910
-
1911
- runtime.mousedownListener = function (event) {
1912
- syncMousePosition(event);
1913
- const button = normalizeMouseButton(event && event.button);
1914
- if (!inputState.mouseDown.has(button)) {
1915
- inputState.pendingMousePressed.add(button);
1916
- }
1917
- inputState.mouseDown.add(button);
1918
- };
1919
-
1920
- runtime.mouseupListener = function (event) {
1921
- syncMousePosition(event);
1922
- const button = normalizeMouseButton(event && event.button);
1923
- inputState.mouseDown.delete(button);
1924
- inputState.pendingMouseReleased.add(button);
1925
- };
1926
-
1927
- runtime.wheelListener = function (event) {
1928
- if (event && Number.isFinite(Number(event.deltaY))) {
1929
- auraRef.input.mouse.scroll += Number(event.deltaY);
1930
- }
1931
- };
1932
-
1933
- runtime.focusListener = function () {
1934
- clearMouseDeltaState();
1935
- if (typeof auraRef.onFocus === 'function') {
1936
- auraRef.onFocus();
1937
- }
1938
- };
1939
-
1940
- runtime.blurListener = function () {
1941
- clearHeldInputState();
1942
- if (typeof auraRef.onBlur === 'function') {
1943
- auraRef.onBlur();
1944
- }
1945
- };
1946
-
1947
- runtime.resizeListener = function () {
1948
- syncCanvasSize(true);
1949
- };
1950
-
1951
- if (typeof globalRef.addEventListener === 'function') {
1952
- globalRef.addEventListener('keydown', runtime.keydownListener);
1953
- globalRef.addEventListener('keyup', runtime.keyupListener);
1954
- globalRef.addEventListener('focus', runtime.focusListener);
1955
- globalRef.addEventListener('mousemove', runtime.mousemoveListener);
1956
- globalRef.addEventListener('mousedown', runtime.mousedownListener);
1957
- globalRef.addEventListener('mouseup', runtime.mouseupListener);
1958
- globalRef.addEventListener('wheel', runtime.wheelListener);
1959
- globalRef.addEventListener('blur', runtime.blurListener);
1960
- globalRef.addEventListener('resize', runtime.resizeListener);
1961
- }
1962
- }
1963
-
1964
- function detachListeners() {
1965
- if (!runtime.listenersAttached) return;
1966
- runtime.listenersAttached = false;
1967
- if (typeof globalRef.removeEventListener === 'function') {
1968
- globalRef.removeEventListener('keydown', runtime.keydownListener);
1969
- globalRef.removeEventListener('keyup', runtime.keyupListener);
1970
- globalRef.removeEventListener('focus', runtime.focusListener);
1971
- globalRef.removeEventListener('mousemove', runtime.mousemoveListener);
1972
- globalRef.removeEventListener('mousedown', runtime.mousedownListener);
1973
- globalRef.removeEventListener('mouseup', runtime.mouseupListener);
1974
- globalRef.removeEventListener('wheel', runtime.wheelListener);
1975
- globalRef.removeEventListener('blur', runtime.blurListener);
1976
- globalRef.removeEventListener('resize', runtime.resizeListener);
1977
- }
1978
- }
1979
-
1980
- auraRef.setup = typeof auraRef.setup === 'function' ? auraRef.setup : null;
1981
- auraRef.update = typeof auraRef.update === 'function' ? auraRef.update : null;
1982
- auraRef.draw = typeof auraRef.draw === 'function' ? auraRef.draw : null;
1983
- auraRef.onResize = typeof auraRef.onResize === 'function' ? auraRef.onResize : null;
1984
- auraRef.onFocus = typeof auraRef.onFocus === 'function' ? auraRef.onFocus : null;
1985
- auraRef.onBlur = typeof auraRef.onBlur === 'function' ? auraRef.onBlur : null;
1986
- auraRef.onQuit = typeof auraRef.onQuit === 'function' ? auraRef.onQuit : null;
1987
-
1988
- auraRef.rgba = function (r, g, b, a) {
1989
- return createUnitColor(r, g, b, a == null ? 1 : a);
1990
- };
1991
- auraRef.rgb = function (r, g, b) {
1992
- return createUnitColor(r, g, b, 1);
1993
- };
1994
- auraRef.color = auraRef.rgba;
1995
- auraRef.Color = auraRef.Color && typeof auraRef.Color === 'object'
1996
- ? auraRef.Color
1997
- : {
1998
- WHITE: createUnitColor(1, 1, 1, 1),
1999
- BLACK: createUnitColor(0, 0, 0, 1),
2000
- RED: createUnitColor(1, 0, 0, 1),
2001
- YELLOW: createUnitColor(1, 1, 0, 1),
2002
- TRANSPARENT: createUnitColor(0, 0, 0, 0)
2003
- };
2004
- auraRef.colors = auraRef.colors && typeof auraRef.colors === 'object'
2005
- ? auraRef.colors
2006
- : {
2007
- white: createByteColor(255, 255, 255, 255),
2008
- black: createByteColor(0, 0, 0, 255),
2009
- red: createByteColor(255, 0, 0, 255),
2010
- yellow: createByteColor(255, 255, 0, 255),
2011
- transparent: createByteColor(0, 0, 0, 0)
2012
- };
2013
-
2014
- auraRef.math = auraRef.math && typeof auraRef.math === 'object' ? auraRef.math : {};
2015
- auraRef.math.clamp = typeof auraRef.math.clamp === 'function'
2016
- ? auraRef.math.clamp
2017
- : function (value, min, max) {
2018
- const numeric = Number(value);
2019
- const minValue = Number(min);
2020
- const maxValue = Number(max);
2021
- if (!Number.isFinite(numeric) || !Number.isFinite(minValue) || !Number.isFinite(maxValue)) {
2022
- return Number.isFinite(numeric) ? numeric : 0;
2023
- }
2024
- return Math.min(maxValue, Math.max(minValue, numeric));
2025
- };
2026
-
2027
- auraRef.window = auraRef.window && typeof auraRef.window === 'object' ? auraRef.window : {};
2028
- auraRef.window.width = runtime.width;
2029
- auraRef.window.height = runtime.height;
2030
- auraRef.window.pixelRatio = runtime.pixelRatio;
2031
- auraRef.window.fps = 60;
2032
- auraRef.window.setTitle = function (title) {
2033
- if (typeof title === 'string') {
2034
- document.title = title;
2035
- }
2036
- };
2037
- auraRef.window.setSize = function (width, height) {
2038
- runtime.configuredWidth = normalizeCanvasSize(width, runtime.configuredWidth);
2039
- runtime.configuredHeight = normalizeCanvasSize(height, runtime.configuredHeight);
2040
- syncCanvasSize(true);
2041
- resetDrawState();
2042
- return true;
2043
- };
2044
- auraRef.window.setFullscreen = function () {
2045
- return false;
2046
- };
2047
- auraRef.window.setCursorVisible = function (visible) {
2048
- runtime.cursorVisible = !!visible;
2049
- applyCursorAppearance();
2050
- return true;
2051
- };
2052
- auraRef.window.setCursorLocked = function (locked) {
2053
- runtime.cursorLocked = !!locked;
2054
- clearMouseDeltaState();
2055
- applyCursorAppearance();
2056
- if (runtime.canvas && typeof runtime.canvas.requestPointerLock === 'function' && runtime.cursorLocked) {
2057
- runtime.canvas.requestPointerLock();
2058
- } else if (
2059
- !runtime.cursorLocked &&
2060
- globalRef.document &&
2061
- typeof globalRef.document.exitPointerLock === 'function'
2062
- ) {
2063
- globalRef.document.exitPointerLock();
2064
- }
2065
- return true;
2066
- };
2067
- auraRef.window.getSize = function () {
2068
- return { width: runtime.width, height: runtime.height };
2069
- };
2070
- auraRef.window.getPixelRatio = function () {
2071
- return runtime.pixelRatio;
2072
- };
2073
- auraRef.window.getFPS = function () {
2074
- return auraRef.window.fps;
2075
- };
2076
- auraRef.window.close = function () {
2077
- return true;
2078
- };
2079
-
2080
- auraRef.collision = auraRef.collision && typeof auraRef.collision === 'object' ? auraRef.collision : {};
2081
- auraRef.collision.rectRect = function (a, b) {
2082
- return rectIntersects(a, b);
2083
- };
2084
- auraRef.collide = auraRef.collide && typeof auraRef.collide === 'object' ? auraRef.collide : auraRef.collision;
2085
- auraRef.collide.rectRect = auraRef.collision.rectRect;
2086
-
2087
- auraRef.camera = camera;
2088
-
2089
- auraRef.input = auraRef.input && typeof auraRef.input === 'object' ? auraRef.input : {};
2090
- auraRef.input.isDown = function (name) {
2091
- const key = normalizeKeyName(name);
2092
- return key ? inputState.down.has(key) : false;
2093
- };
2094
- auraRef.input.isPressed = function (name) {
2095
- const key = normalizeKeyName(name);
2096
- return key ? inputState.framePressed.has(key) : false;
2097
- };
2098
- auraRef.input.isReleased = function (name) {
2099
- const key = normalizeKeyName(name);
2100
- return key ? inputState.frameReleased.has(key) : false;
2101
- };
2102
- auraRef.input.isKeyDown = function (name) {
2103
- return auraRef.input.isDown(name);
2104
- };
2105
- auraRef.input.isKeyPressed = function (name) {
2106
- return auraRef.input.isPressed(name);
2107
- };
2108
- auraRef.input.isKeyReleased = function (name) {
2109
- return auraRef.input.isReleased(name);
2110
- };
2111
- auraRef.input.isGamepadConnected = typeof auraRef.input.isGamepadConnected === 'function'
2112
- ? auraRef.input.isGamepadConnected
2113
- : function () { return false; };
2114
- auraRef.input.mouse = auraRef.input.mouse && typeof auraRef.input.mouse === 'object' ? auraRef.input.mouse : {};
2115
- auraRef.input.mouse.x = Number(auraRef.input.mouse.x) || 0;
2116
- auraRef.input.mouse.y = Number(auraRef.input.mouse.y) || 0;
2117
- auraRef.input.mouse.scroll = Number(auraRef.input.mouse.scroll) || 0;
2118
- auraRef.input.mouse.isDown = function (button) {
2119
- return inputState.mouseDown.has(normalizeMouseButton(button));
2120
- };
2121
- auraRef.input.mouse.isPressed = function (button) {
2122
- return inputState.frameMousePressed.has(normalizeMouseButton(button));
2123
- };
2124
- auraRef.input.mouse.isReleased = function (button) {
2125
- return inputState.frameMouseReleased.has(normalizeMouseButton(button));
2126
- };
2127
- auraRef.input.isMouseDown = function (button) {
2128
- return auraRef.input.mouse.isDown(button);
2129
- };
2130
- auraRef.input.isMousePressed = function (button) {
2131
- return auraRef.input.mouse.isPressed(button);
2132
- };
2133
- auraRef.input.isMouseReleased = function (button) {
2134
- return auraRef.input.mouse.isReleased(button);
2135
- };
2136
- auraRef.input.getMousePosition = function () {
2137
- return { x: auraRef.input.mouse.x, y: auraRef.input.mouse.y };
2138
- };
2139
- auraRef.input.getMouseDelta = function () {
2140
- return { x: inputState.frameMouseDeltaX, y: inputState.frameMouseDeltaY };
2141
- };
2142
-
2143
- auraRef.state = auraRef.state && typeof auraRef.state === 'object' ? auraRef.state : {};
2144
- auraRef.state.export = typeof auraRef.state.export === 'function'
2145
- ? auraRef.state.export
2146
- : function () {
2147
- return createUnsupportedStateResult('export', 'web_state_export_unsupported');
2148
- };
2149
- auraRef.state.apply = typeof auraRef.state.apply === 'function'
2150
- ? auraRef.state.apply
2151
- : function () {
2152
- return createUnsupportedStateResult('apply', 'web_state_apply_unsupported');
2153
- };
2154
- auraRef.state.diff = typeof auraRef.state.diff === 'function'
2155
- ? auraRef.state.diff
2156
- : function () {
2157
- return createUnsupportedStateResult('diff', 'web_state_diff_unsupported');
2158
- };
2159
- auraRef.state.patch = typeof auraRef.state.patch === 'function'
2160
- ? auraRef.state.patch
2161
- : function () {
2162
- return createUnsupportedStateResult('patch', 'web_state_patch_unsupported');
2163
- };
2164
- auraRef.state.exportState = typeof auraRef.state.exportState === 'function'
2165
- ? auraRef.state.exportState
2166
- : function (options) {
2167
- return auraRef.state.export(options);
2168
- };
2169
- auraRef.state.applyState = typeof auraRef.state.applyState === 'function'
2170
- ? auraRef.state.applyState
2171
- : function (payload, options) {
2172
- return auraRef.state.apply(payload, options);
2173
- };
2174
- auraRef.state.diffState = typeof auraRef.state.diffState === 'function'
2175
- ? auraRef.state.diffState
2176
- : function (beforePayload, afterPayload) {
2177
- return auraRef.state.diff(beforePayload, afterPayload);
2178
- };
2179
- auraRef.state.patchState = typeof auraRef.state.patchState === 'function'
2180
- ? auraRef.state.patchState
2181
- : function (payload, patchPayload, options) {
2182
- return auraRef.state.patch(payload, patchPayload, options);
2183
- };
2184
-
2185
- auraRef.net = auraRef.net && typeof auraRef.net === 'object' ? auraRef.net : {};
2186
- auraRef.net.connect = typeof auraRef.net.connect === 'function'
2187
- ? auraRef.net.connect
2188
- : function () {
2189
- throw createUnsupportedRuntimeError('net', 'connect', 'web_net_connect_unsupported');
2190
- };
2191
- auraRef.net.websocket = typeof auraRef.net.websocket === 'function'
2192
- ? auraRef.net.websocket
2193
- : function () {
2194
- throw createUnsupportedRuntimeError('net', 'websocket', 'web_net_websocket_unsupported');
2195
- };
2196
- auraRef.net.fetch = typeof auraRef.net.fetch === 'function'
2197
- ? auraRef.net.fetch
2198
- : function () {
2199
- throw createUnsupportedRuntimeError('net', 'fetch', 'web_net_fetch_unsupported');
2200
- };
2201
- auraRef.net.get = typeof auraRef.net.get === 'function'
2202
- ? auraRef.net.get
2203
- : function () {
2204
- throw createUnsupportedRuntimeError('net', 'get', 'web_net_get_unsupported');
2205
- };
2206
- auraRef.net.post = typeof auraRef.net.post === 'function'
2207
- ? auraRef.net.post
2208
- : function () {
2209
- throw createUnsupportedRuntimeError('net', 'post', 'web_net_post_unsupported');
2210
- };
2211
-
2212
- auraRef.storage = auraRef.storage && typeof auraRef.storage === 'object' ? auraRef.storage : {};
2213
- auraRef.storage.save = typeof auraRef.storage.save === 'function'
2214
- ? auraRef.storage.save
2215
- : function (key, value) { return writeStorage(key, value); };
2216
- auraRef.storage.load = typeof auraRef.storage.load === 'function'
2217
- ? auraRef.storage.load
2218
- : function (key) { return readStorage(key); };
2219
- auraRef.storage.delete = typeof auraRef.storage.delete === 'function'
2220
- ? auraRef.storage.delete
2221
- : function (key) { return deleteStorage(key); };
2222
- auraRef.storage.keys = typeof auraRef.storage.keys === 'function'
2223
- ? auraRef.storage.keys
2224
- : function () {
2225
- const prefix = 'aurajs:';
2226
- const backend = resolveStorageBackend();
2227
- const keys = [];
2228
- if (backend && Number.isInteger(backend.length) && typeof backend.key === 'function') {
2229
- for (let index = 0; index < backend.length; index += 1) {
2230
- const nextKey = backend.key(index);
2231
- if (typeof nextKey === 'string' && nextKey.startsWith(prefix)) {
2232
- keys.push(nextKey.slice(prefix.length));
2233
- }
2234
- }
2235
- keys.sort(function (a, b) { return a.localeCompare(b); });
2236
- return keys;
2237
- }
2238
- for (const key of assetState.storageFallback.keys()) {
2239
- if (key.startsWith(prefix)) {
2240
- keys.push(key.slice(prefix.length));
2241
- }
2242
- }
2243
- keys.sort(function (a, b) { return a.localeCompare(b); });
2244
- return keys;
2245
- };
2246
- auraRef.storage.set = typeof auraRef.storage.set === 'function'
2247
- ? auraRef.storage.set
2248
- : function (key, value) { return writeStorage(key, value); };
2249
- auraRef.storage.get = typeof auraRef.storage.get === 'function'
2250
- ? auraRef.storage.get
2251
- : function (key, fallback) {
2252
- const value = readStorage(key);
2253
- return value == null ? fallback : value;
2254
- };
2255
-
2256
- auraRef.audio = auraRef.audio && typeof auraRef.audio === 'object' ? auraRef.audio : {};
2257
- if (auraRef.audio.supported !== true) {
2258
- auraRef.audio.supported = false;
2259
- }
2260
- if (typeof auraRef.audio.reasonCode !== 'string') {
2261
- auraRef.audio.reasonCode = 'web_audio_playback_unsupported';
2262
- }
2263
- if (typeof auraRef.audio.runtime !== 'string') {
2264
- auraRef.audio.runtime = 'web';
2265
- }
2266
- auraRef.audio.play = typeof auraRef.audio.play === 'function'
2267
- ? auraRef.audio.play
2268
- : function () {
2269
- throw createUnsupportedRuntimeError('audio', 'play', 'web_audio_play_unsupported', { playbackSupported: false });
2270
- };
2271
- auraRef.audio.stop = typeof auraRef.audio.stop === 'function'
2272
- ? auraRef.audio.stop
2273
- : function () {
2274
- throw createUnsupportedRuntimeError('audio', 'stop', 'web_audio_stop_unsupported', { playbackSupported: false });
2275
- };
2276
- auraRef.audio.pause = typeof auraRef.audio.pause === 'function'
2277
- ? auraRef.audio.pause
2278
- : function () {
2279
- throw createUnsupportedRuntimeError('audio', 'pause', 'web_audio_pause_unsupported', { playbackSupported: false });
2280
- };
2281
- auraRef.audio.resume = typeof auraRef.audio.resume === 'function'
2282
- ? auraRef.audio.resume
2283
- : function () {
2284
- throw createUnsupportedRuntimeError('audio', 'resume', 'web_audio_resume_unsupported', { playbackSupported: false });
2285
- };
2286
- auraRef.audio.setVolume = typeof auraRef.audio.setVolume === 'function'
2287
- ? auraRef.audio.setVolume
2288
- : function () {
2289
- throw createUnsupportedRuntimeError('audio', 'setVolume', 'web_audio_set_volume_unsupported', { playbackSupported: false });
2290
- };
2291
- auraRef.audio.setMasterVolume = typeof auraRef.audio.setMasterVolume === 'function'
2292
- ? auraRef.audio.setMasterVolume
2293
- : function () {
2294
- throw createUnsupportedRuntimeError('audio', 'setMasterVolume', 'web_audio_set_master_volume_unsupported', { playbackSupported: false });
2295
- };
2296
- auraRef.audio.stopAll = typeof auraRef.audio.stopAll === 'function'
2297
- ? auraRef.audio.stopAll
2298
- : function () {
2299
- throw createUnsupportedRuntimeError('audio', 'stopAll', 'web_audio_stop_all_unsupported', { playbackSupported: false });
2300
- };
2301
- auraRef.audio.setBusVolume = typeof auraRef.audio.setBusVolume === 'function'
2302
- ? auraRef.audio.setBusVolume
2303
- : function () {
2304
- throw createUnsupportedRuntimeError('audio', 'setBusVolume', 'web_audio_set_bus_volume_unsupported', { playbackSupported: false });
2305
- };
2306
- auraRef.audio.assignBus = typeof auraRef.audio.assignBus === 'function'
2307
- ? auraRef.audio.assignBus
2308
- : function () {
2309
- throw createUnsupportedRuntimeError('audio', 'assignBus', 'web_audio_assign_bus_unsupported', { playbackSupported: false });
2310
- };
2311
- auraRef.audio.fadeTrack = typeof auraRef.audio.fadeTrack === 'function'
2312
- ? auraRef.audio.fadeTrack
2313
- : function () {
2314
- throw createUnsupportedRuntimeError('audio', 'fadeTrack', 'web_audio_fade_track_unsupported', { playbackSupported: false });
2315
- };
2316
- auraRef.audio.fadeBus = typeof auraRef.audio.fadeBus === 'function'
2317
- ? auraRef.audio.fadeBus
2318
- : function () {
2319
- throw createUnsupportedRuntimeError('audio', 'fadeBus', 'web_audio_fade_bus_unsupported', { playbackSupported: false });
2320
- };
2321
- auraRef.audio.crossfade = typeof auraRef.audio.crossfade === 'function'
2322
- ? auraRef.audio.crossfade
2323
- : function () {
2324
- throw createUnsupportedRuntimeError('audio', 'crossfade', 'web_audio_crossfade_unsupported', { playbackSupported: false });
2325
- };
2326
- auraRef.audio.update = typeof auraRef.audio.update === 'function'
2327
- ? auraRef.audio.update
2328
- : function () {
2329
- throw createUnsupportedRuntimeError('audio', 'update', 'web_audio_update_unsupported', { playbackSupported: false });
2330
- };
2331
- auraRef.audio.clearEnvelopes = typeof auraRef.audio.clearEnvelopes === 'function'
2332
- ? auraRef.audio.clearEnvelopes
2333
- : function () {
2334
- throw createUnsupportedRuntimeError('audio', 'clearEnvelopes', 'web_audio_clear_envelopes_unsupported', { playbackSupported: false });
2335
- };
2336
- auraRef.audio.getMixerState = typeof auraRef.audio.getMixerState === 'function'
2337
- ? auraRef.audio.getMixerState
2338
- : function () {
2339
- throw createUnsupportedRuntimeError('audio', 'getMixerState', 'web_audio_get_mixer_state_unsupported', { playbackSupported: false });
2340
- };
2341
- auraRef.audio.play3d = typeof auraRef.audio.play3d === 'function'
2342
- ? auraRef.audio.play3d
2343
- : function () {
2344
- throw createUnsupportedRuntimeError('audio', 'play3d', 'web_audio_play3d_unsupported', { playbackSupported: false });
2345
- };
2346
- auraRef.audio.setListenerTransform = typeof auraRef.audio.setListenerTransform === 'function'
2347
- ? auraRef.audio.setListenerTransform
2348
- : function () {
2349
- throw createUnsupportedRuntimeError('audio', 'setListenerTransform', 'web_audio_set_listener_transform_unsupported', { playbackSupported: false });
2350
- };
2351
- auraRef.audio.attachListener = typeof auraRef.audio.attachListener === 'function'
2352
- ? auraRef.audio.attachListener
2353
- : function () {
2354
- throw createUnsupportedRuntimeError('audio', 'attachListener', 'web_audio_attach_listener_unsupported', { playbackSupported: false });
2355
- };
2356
- auraRef.audio.detachListener = typeof auraRef.audio.detachListener === 'function'
2357
- ? auraRef.audio.detachListener
2358
- : function () {
2359
- throw createUnsupportedRuntimeError('audio', 'detachListener', 'web_audio_detach_listener_unsupported', { playbackSupported: false });
2360
- };
2361
- auraRef.audio.setEmitterTransform = typeof auraRef.audio.setEmitterTransform === 'function'
2362
- ? auraRef.audio.setEmitterTransform
2363
- : function () {
2364
- throw createUnsupportedRuntimeError('audio', 'setEmitterTransform', 'web_audio_set_emitter_transform_unsupported', { playbackSupported: false });
2365
- };
2366
- auraRef.audio.attachEmitter = typeof auraRef.audio.attachEmitter === 'function'
2367
- ? auraRef.audio.attachEmitter
2368
- : function () {
2369
- throw createUnsupportedRuntimeError('audio', 'attachEmitter', 'web_audio_attach_emitter_unsupported', { playbackSupported: false });
2370
- };
2371
- auraRef.audio.detachEmitter = typeof auraRef.audio.detachEmitter === 'function'
2372
- ? auraRef.audio.detachEmitter
2373
- : function () {
2374
- throw createUnsupportedRuntimeError('audio', 'detachEmitter', 'web_audio_detach_emitter_unsupported', { playbackSupported: false });
2375
- };
2376
- auraRef.audio.updateSpatial = typeof auraRef.audio.updateSpatial === 'function'
2377
- ? auraRef.audio.updateSpatial
2378
- : function () {
2379
- throw createUnsupportedRuntimeError('audio', 'updateSpatial', 'web_audio_update_spatial_unsupported', { playbackSupported: false });
2380
- };
2381
- auraRef.audio.getSpatialState = typeof auraRef.audio.getSpatialState === 'function'
2382
- ? auraRef.audio.getSpatialState
2383
- : function () {
2384
- throw createUnsupportedRuntimeError('audio', 'getSpatialState', 'web_audio_get_spatial_state_unsupported', { playbackSupported: false });
2385
- };
2386
-
2387
- auraRef.assets = auraRef.assets && typeof auraRef.assets === 'object' ? auraRef.assets : {};
2388
- auraRef.assets.load = typeof auraRef.assets.load === 'function'
2389
- ? auraRef.assets.load
2390
- : async function (source) {
2391
- return await loadAssetRecord(source);
2392
- };
2393
- auraRef.assets.exists = typeof auraRef.assets.exists === 'function'
2394
- ? auraRef.assets.exists
2395
- : function (name) {
2396
- return !!resolveAssetEntry(name);
2397
- };
2398
- auraRef.assets.image = typeof auraRef.assets.image === 'function'
2399
- ? auraRef.assets.image
2400
- : function (name) {
2401
- const sourcePath = resolveAssetSourcePath(name);
2402
- const loaded = resolveLoadedAsset(sourcePath);
2403
- if (loaded) return loaded;
2404
- const entry = resolveAssetEntry(sourcePath);
2405
- return rememberLoadedAsset(sourcePath, {
2406
- kind: 'image',
2407
- path: sourcePath,
2408
- sourcePath: sourcePath,
2409
- resolvedPath: entry && typeof entry.path === 'string' ? normalizePath(entry.path) : sourcePath,
2410
- mediaType: entry && typeof entry.mediaType === 'string' ? entry.mediaType : 'image/png',
2411
- image: null,
2412
- width: 0,
2413
- height: 0
2414
- });
2415
- };
2416
- auraRef.assets.sound = typeof auraRef.assets.sound === 'function'
2417
- ? auraRef.assets.sound
2418
- : function (name) {
2419
- const sourcePath = resolveAssetSourcePath(name);
2420
- const loaded = resolveLoadedAsset(sourcePath);
2421
- if (loaded) return loaded;
2422
- const entry = resolveAssetEntry(sourcePath);
2423
- return createBrowserSoundHandle(sourcePath, entry, null);
2424
- };
2425
- auraRef.assets.text = typeof auraRef.assets.text === 'function'
2426
- ? auraRef.assets.text
2427
- : function (name) {
2428
- const loaded = resolveLoadedAsset(name);
2429
- return loaded && typeof loaded.text === 'string' ? loaded.text : '';
2430
- };
2431
- auraRef.assets.json = typeof auraRef.assets.json === 'function'
2432
- ? auraRef.assets.json
2433
- : function (name) {
2434
- const loaded = resolveLoadedAsset(name);
2435
- return loaded && loaded.json && typeof loaded.json === 'object' ? loaded.json : {};
2436
- };
2437
- auraRef.assets.bytes = typeof auraRef.assets.bytes === 'function'
2438
- ? auraRef.assets.bytes
2439
- : function (name) {
2440
- const loaded = resolveLoadedAsset(name);
2441
- return loaded && loaded.bytes instanceof Uint8Array ? loaded.bytes : new Uint8Array();
2442
- };
2443
- auraRef.assets.loadText = typeof auraRef.assets.loadText === 'function'
2444
- ? auraRef.assets.loadText
2445
- : async function (name) {
2446
- const loaded = await loadAssetRecord(name);
2447
- return loaded && typeof loaded.text === 'string' ? loaded.text : '';
2448
- };
2449
- auraRef.assets.loadJson = typeof auraRef.assets.loadJson === 'function'
2450
- ? auraRef.assets.loadJson
2451
- : async function (name) {
2452
- const loaded = await loadAssetRecord(name);
2453
- return loaded && loaded.json && typeof loaded.json === 'object' ? loaded.json : null;
2454
- };
2455
-
2456
- function drawResolvedImage(source, x, y, options, useSpriteFrame) {
2457
- const ctx = ensureWorldTransform();
2458
- if (!ctx || typeof ctx.drawImage !== 'function') return false;
2459
- const handle = source && typeof source === 'object' && source.image
2460
- ? source
2461
- : auraRef.assets.image(source);
2462
- if (!handle || !handle.image) return false;
2463
- const opts = options && typeof options === 'object' ? { ...options } : {};
2464
- const width = normalizePositiveNumber(opts.width, handle.width || handle.image.naturalWidth || handle.image.width || 1);
2465
- const height = normalizePositiveNumber(opts.height, handle.height || handle.image.naturalHeight || handle.image.height || 1);
2466
- const alpha = Number.isFinite(Number(opts.alpha)) ? Math.max(0, Math.min(1, Number(opts.alpha))) : 1;
2467
- const frameX = useSpriteFrame ? Math.max(0, Number(opts.frameX) || 0) : 0;
2468
- const frameY = useSpriteFrame ? Math.max(0, Number(opts.frameY) || 0) : 0;
2469
- const frameW = useSpriteFrame
2470
- ? normalizePositiveNumber(opts.frameW, handle.image.naturalWidth || handle.image.width || width)
2471
- : (handle.image.naturalWidth || handle.image.width || width);
2472
- const frameH = useSpriteFrame
2473
- ? normalizePositiveNumber(opts.frameH, handle.image.naturalHeight || handle.image.height || height)
2474
- : (handle.image.naturalHeight || handle.image.height || height);
2475
- const drawX = Number(x) || 0;
2476
- const drawY = Number(y) || 0;
2477
- const flipX = opts.flipX === true;
2478
- const flipY = opts.flipY === true;
2479
- if (typeof ctx.save === 'function') ctx.save();
2480
- ctx.globalAlpha = alpha;
2481
- if (flipX || flipY) {
2482
- if (typeof ctx.translate === 'function') {
2483
- ctx.translate(drawX + (flipX ? width : 0), drawY + (flipY ? height : 0));
2484
- }
2485
- if (typeof ctx.scale === 'function') {
2486
- ctx.scale(flipX ? -1 : 1, flipY ? -1 : 1);
2487
- }
2488
- ctx.drawImage(handle.image, frameX, frameY, frameW, frameH, 0, 0, width, height);
2489
- } else {
2490
- ctx.drawImage(handle.image, frameX, frameY, frameW, frameH, drawX, drawY, width, height);
2491
- }
2492
- if (typeof ctx.restore === 'function') ctx.restore();
2493
- return true;
2494
- }
2495
-
2496
- auraRef.draw2d = auraRef.draw2d && typeof auraRef.draw2d === 'object' ? auraRef.draw2d : {};
2497
- auraRef.draw2d.clear = function (colorOrR, g, b, a) {
2498
- const ctx = ensureCanvasContext();
2499
- if (!ctx) return;
2500
- const fillColor = arguments.length > 1
2501
- ? createUnitColor(colorOrR, g, b, a == null ? 1 : a)
2502
- : normalizeColor(colorOrR, createUnitColor(0, 0, 0, 1));
2503
- resetDrawState();
2504
- ctx.clearRect(0, 0, runtime.width, runtime.height);
2505
- ctx.fillStyle = colorToCss(fillColor, createUnitColor(0, 0, 0, 1));
2506
- ctx.fillRect(0, 0, runtime.width, runtime.height);
2507
- applyWorldTransform();
2508
- };
2509
- auraRef.draw2d.rect = function (x, y, w, h, color) {
2510
- const ctx = ensureWorldTransform();
2511
- if (!ctx) return;
2512
- ctx.strokeStyle = colorToCss(color, defaultColor);
2513
- ctx.lineWidth = 1;
2514
- ctx.strokeRect(Number(x) || 0, Number(y) || 0, Number(w) || 0, Number(h) || 0);
2515
- };
2516
- auraRef.draw2d.rectOutline = auraRef.draw2d.rect;
2517
- auraRef.draw2d.rectFill = function (x, y, w, h, color) {
2518
- const ctx = ensureWorldTransform();
2519
- if (!ctx) return;
2520
- ctx.fillStyle = colorToCss(color, defaultColor);
2521
- ctx.fillRect(Number(x) || 0, Number(y) || 0, Number(w) || 0, Number(h) || 0);
2522
- };
2523
- auraRef.draw2d.circle = function (x, y, radius, color) {
2524
- const ctx = ensureWorldTransform();
2525
- if (!ctx) return;
2526
- ctx.beginPath();
2527
- ctx.arc(Number(x) || 0, Number(y) || 0, Math.max(0, Number(radius) || 0), 0, Math.PI * 2);
2528
- ctx.strokeStyle = colorToCss(color, defaultColor);
2529
- ctx.lineWidth = 1;
2530
- ctx.stroke();
2531
- };
2532
- auraRef.draw2d.circleFill = function (x, y, radius, color) {
2533
- const ctx = ensureWorldTransform();
2534
- if (!ctx) return;
2535
- ctx.beginPath();
2536
- ctx.arc(Number(x) || 0, Number(y) || 0, Math.max(0, Number(radius) || 0), 0, Math.PI * 2);
2537
- ctx.fillStyle = colorToCss(color, defaultColor);
2538
- ctx.fill();
2539
- };
2540
- auraRef.draw2d.line = function (x1, y1, x2, y2, color, width) {
2541
- const ctx = ensureWorldTransform();
2542
- if (!ctx) return;
2543
- ctx.beginPath();
2544
- ctx.moveTo(Number(x1) || 0, Number(y1) || 0);
2545
- ctx.lineTo(Number(x2) || 0, Number(y2) || 0);
2546
- ctx.strokeStyle = colorToCss(color, defaultColor);
2547
- ctx.lineWidth = normalizePositiveNumber(width, 1);
2548
- ctx.stroke();
2549
- };
2550
- auraRef.draw2d.text = function (text, x, y, sizeOrOptions, colorMaybe) {
2551
- const options = normalizeTextOptions(sizeOrOptions, colorMaybe);
2552
- return withScreenSpace(function (ctx) {
2553
- const config = applyFont(options);
2554
- const source = options && typeof options === 'object' ? options : {};
2555
- ctx.fillStyle = colorToCss(source.color, defaultColor);
2556
- ctx.textAlign = config.align;
2557
- ctx.textBaseline = 'top';
2558
- ctx.fillText(String(text == null ? '' : text), Number(x) || 0, Number(y) || 0);
2559
- return true;
2560
- });
2561
- };
2562
- auraRef.draw2d.measureText = function (text, sizeOrOptions, colorMaybe) {
2563
- const options = normalizeTextOptions(sizeOrOptions, colorMaybe);
2564
- const source = options && typeof options === 'object' ? options : {};
2565
- const size = normalizePositiveNumber(source.size, 16);
2566
- const ctx = ensureCanvasContext();
2567
- if (!ctx) {
2568
- const fallbackWidth = String(text == null ? '' : text).length * size * 0.6;
2569
- return { width: Number(fallbackWidth.toFixed(3)), height: size };
2570
- }
2571
- const measuredWidth = withScreenSpace(function () {
2572
- applyFont(options);
2573
- const metrics = ctx.measureText(String(text == null ? '' : text));
2574
- return Number.isFinite(metrics && metrics.width)
2575
- ? metrics.width
2576
- : String(text == null ? '' : text).length * size * 0.6;
2577
- });
2578
- return { width: Number(Number(measuredWidth || 0).toFixed(3)), height: size };
2579
- };
2580
- auraRef.draw2d.image = typeof auraRef.draw2d.image === 'function'
2581
- ? auraRef.draw2d.image
2582
- : function (source, x, y, options) {
2583
- return drawResolvedImage(source, x, y, options, false);
2584
- };
2585
- auraRef.draw2d.sprite = typeof auraRef.draw2d.sprite === 'function'
2586
- ? auraRef.draw2d.sprite
2587
- : function (source, x, y, options) {
2588
- return drawResolvedImage(source, x, y, options, true);
2589
- };
2590
- auraRef.draw2d.pushTransform = function () {
2591
- const ctx = ensureWorldTransform();
2592
- if (!ctx || typeof ctx.save !== 'function') return;
2593
- runtime.transformDepth += 1;
2594
- ctx.save();
2595
- };
2596
- auraRef.draw2d.popTransform = function () {
2597
- const ctx = ensureCanvasContext();
2598
- if (!ctx || typeof ctx.restore !== 'function' || runtime.transformDepth <= 0) return;
2599
- runtime.transformDepth -= 1;
2600
- ctx.restore();
2601
- };
2602
- auraRef.draw2d.push = auraRef.draw2d.pushTransform;
2603
- auraRef.draw2d.pop = auraRef.draw2d.popTransform;
2604
- auraRef.draw2d.translate = function (x, y) {
2605
- const ctx = ensureWorldTransform();
2606
- if (!ctx || typeof ctx.translate !== 'function') return;
2607
- ctx.translate(Number(x) || 0, Number(y) || 0);
2608
- };
2609
- auraRef.draw2d.rotate = function (angle) {
2610
- const ctx = ensureWorldTransform();
2611
- if (!ctx || typeof ctx.rotate !== 'function') return;
2612
- ctx.rotate(Number(angle) || 0);
2613
- };
2614
- auraRef.draw2d.scale = function (x, y) {
2615
- const ctx = ensureWorldTransform();
2616
- if (!ctx || typeof ctx.scale !== 'function') return;
2617
- const scaleX = Number.isFinite(Number(x)) ? Number(x) : 1;
2618
- const scaleY = Number.isFinite(Number(y)) ? Number(y) : scaleX;
2619
- ctx.scale(scaleX, scaleY);
2620
- };
2621
-
2622
- return {
2623
- aura: auraRef,
2624
- setRuntimeConfig(nextRuntimeConfig) {
2625
- currentRuntimeConfig = nextRuntimeConfig && typeof nextRuntimeConfig === 'object' ? nextRuntimeConfig : {};
2626
- currentCanvasConfig = currentRuntimeConfig.canvas && typeof currentRuntimeConfig.canvas === 'object'
2627
- ? currentRuntimeConfig.canvas
2628
- : {};
2629
- runtime.configuredWidth = normalizeCanvasSize(currentCanvasConfig.width, runtime.configuredWidth);
2630
- runtime.configuredHeight = normalizeCanvasSize(currentCanvasConfig.height, runtime.configuredHeight);
2631
- runtime.resizeMode = currentCanvasConfig.resizeMode === 'fixed' ? 'fixed' : 'fit-container';
2632
- syncCanvasSize(false);
2633
- },
2634
- setManifest(nextManifest, rootUrl) {
2635
- indexManifestAssets(nextManifest, rootUrl);
2636
- },
2637
- mount(canvas, mountTarget) {
2638
- runtime.canvas = canvas || runtime.canvas;
2639
- runtime.mountTarget = mountTarget || runtime.mountTarget;
2640
- ensureCanvasContext();
2641
- syncCanvasSize(false);
2642
- resetDrawState();
2643
- attachListeners();
2644
- clearHeldInputState();
2645
- auraRef.input.mouse.scroll = 0;
2646
- applyCursorAppearance();
2647
- if (runtime.canvas && typeof runtime.canvas.focus === 'function') {
2648
- runtime.canvas.focus();
2649
- }
2650
- if (typeof auraRef.onFocus === 'function') {
2651
- auraRef.onFocus();
2652
- }
2653
- return true;
2654
- },
2655
- beginFrame() {
2656
- inputState.framePressed = new Set(inputState.pendingPressed);
2657
- inputState.frameReleased = new Set(inputState.pendingReleased);
2658
- inputState.pendingPressed.clear();
2659
- inputState.pendingReleased.clear();
2660
- inputState.frameMousePressed = new Set(inputState.pendingMousePressed);
2661
- inputState.frameMouseReleased = new Set(inputState.pendingMouseReleased);
2662
- inputState.pendingMousePressed.clear();
2663
- inputState.pendingMouseReleased.clear();
2664
- inputState.frameMouseDeltaX = inputState.pendingMouseDeltaX;
2665
- inputState.frameMouseDeltaY = inputState.pendingMouseDeltaY;
2666
- inputState.pendingMouseDeltaX = 0;
2667
- inputState.pendingMouseDeltaY = 0;
2668
- resetDrawState();
2669
- },
2670
- endFrame() {
2671
- const ctx = ensureCanvasContext();
2672
- if (ctx && typeof ctx.restore === 'function') {
2673
- while (runtime.transformDepth > 0) {
2674
- runtime.transformDepth -= 1;
2675
- ctx.restore();
2676
- }
2677
- }
2678
- },
2679
- unmount() {
2680
- detachListeners();
2681
- clearHeldInputState();
2682
- runtime.cursorLocked = false;
2683
- if (globalRef.document && typeof globalRef.document.exitPointerLock === 'function') {
2684
- globalRef.document.exitPointerLock();
2685
- }
2686
- applyCursorAppearance();
2687
- runtime.mountTarget = null;
2688
- runtime.canvas = null;
2689
- runtime.context2d = null;
2690
- runtime.transformDepth = 0;
2691
- runtime.worldTransformActive = false;
2692
- return true;
2693
- }
2694
- };
2695
- }
2696
-
2697
- function createDeterministicBootstrap() {
2698
- return async function bootstrap(input) {
2699
- const auraRef = auraRuntime && auraRuntime.aura
2700
- ? auraRuntime.aura
2701
- : (globalRef.aura && typeof globalRef.aura === 'object'
2702
- ? globalRef.aura
2703
- : (globalRef.aura = {}));
2704
- const runtimeConfig = input && typeof input.runtimeConfig === 'object' && input.runtimeConfig
2705
- ? input.runtimeConfig
2706
- : {};
2707
- const loopConfig = runtimeConfig.loop && typeof runtimeConfig.loop === 'object'
2708
- ? runtimeConfig.loop
2709
- : {};
2710
- const maxDeltaSeconds = normalizePositiveNumber(loopConfig.maxDeltaMs, 50) / 1000;
2711
- const fixedDeltaSeconds = Math.min(maxDeltaSeconds, 1 / 60);
2712
- const requestFrame = typeof globalRef.requestAnimationFrame === 'function'
2713
- ? globalRef.requestAnimationFrame.bind(globalRef)
2714
- : function (callback) {
2715
- return globalRef.setTimeout(function () {
2716
- callback(Date.now());
2717
- }, 16);
2718
- };
2719
- const cancelFrame = typeof globalRef.cancelAnimationFrame === 'function'
2720
- ? globalRef.cancelAnimationFrame.bind(globalRef)
2721
- : function (handle) {
2722
- globalRef.clearTimeout(handle);
2723
- };
2724
-
2725
- const runtimeState = {
2726
- disposed: false,
2727
- running: false,
2728
- setupCalls: 0,
2729
- updateCalls: 0,
2730
- drawCalls: 0,
2731
- frameCount: 0,
2732
- lastDeltaSeconds: 0,
2733
- rafHandle: null
2734
- };
2735
-
2736
- function getLifecycle() {
2737
- return {
2738
- running: runtimeState.running && runtimeState.disposed === false,
2739
- setupCalls: runtimeState.setupCalls,
2740
- updateCalls: runtimeState.updateCalls,
2741
- drawCalls: runtimeState.drawCalls,
2742
- frameCount: runtimeState.frameCount,
2743
- lastDeltaSeconds: runtimeState.lastDeltaSeconds
2744
- };
2745
- }
2746
-
2747
- function syncLifecycle() {
2748
- state.lifecycle = cloneLifecycle(getLifecycle());
2749
- }
2750
-
2751
- try {
2752
- if (typeof auraRef.setup === 'function') {
2753
- const setupResult = auraRef.setup();
2754
- if (setupResult && typeof setupResult.then === 'function') {
2755
- await setupResult;
2756
- }
2757
- runtimeState.setupCalls += 1;
2758
- }
2759
- } catch (error) {
2760
- throw createError(
2761
- 'web_runtime_bootstrap_failed',
2762
- 'Runtime setup failed.',
2763
- 'runtime',
2764
- true,
2765
- { stage: 'setup', cause: String(error && error.message ? error.message : error) }
2766
- );
2767
- }
2768
-
2769
- runtimeState.running = true;
2770
- syncLifecycle();
2771
-
2772
- function step() {
2773
- if (runtimeState.running === false || runtimeState.disposed === true) {
2774
- return;
2775
- }
2776
- runtimeState.frameCount += 1;
2777
- runtimeState.lastDeltaSeconds = fixedDeltaSeconds;
2778
-
2779
- try {
2780
- if (auraRuntime && typeof auraRuntime.beginFrame === 'function') {
2781
- auraRuntime.beginFrame();
2782
- }
2783
- if (typeof auraRef.update === 'function') {
2784
- auraRef.update(fixedDeltaSeconds);
2785
- runtimeState.updateCalls += 1;
2786
- }
2787
- if (typeof auraRef.draw === 'function') {
2788
- auraRef.draw();
2789
- runtimeState.drawCalls += 1;
2790
- }
2791
- if (auraRuntime && typeof auraRuntime.endFrame === 'function') {
2792
- auraRuntime.endFrame();
2793
- }
2794
- } catch (error) {
2795
- runtimeState.running = false;
2796
- syncLifecycle();
2797
- const normalized = normalizeError(
2798
- error,
2799
- 'web_runtime_bootstrap_failed',
2800
- 'Runtime lifecycle callback failed.',
2801
- 'runtime',
2802
- true
2803
- );
2804
- setState('error', normalized.reasonCode, {
2805
- reasonCode: normalized.reasonCode,
2806
- layer: normalized.layer || 'runtime',
2807
- retryable: normalized.retryable === true,
2808
- details: normalized.details || {}
2809
- });
2810
- return;
2811
- }
2812
-
2813
- syncLifecycle();
2814
- runtimeState.rafHandle = requestFrame(step);
2815
- }
2816
-
2817
- runtimeState.rafHandle = requestFrame(step);
2818
-
2819
- return {
2820
- getLifecycle,
2821
- async unmount() {
2822
- if (runtimeState.disposed === true) {
2823
- return true;
2824
- }
2825
- runtimeState.disposed = true;
2826
- runtimeState.running = false;
2827
- if (runtimeState.rafHandle != null) {
2828
- cancelFrame(runtimeState.rafHandle);
2829
- runtimeState.rafHandle = null;
2830
- }
2831
- if (auraRuntime && typeof auraRuntime.unmount === 'function') {
2832
- auraRuntime.unmount();
2833
- }
2834
- syncLifecycle();
2835
- return true;
2836
- }
2837
- };
2838
- };
2839
- }
2840
-
2841
- function resolveBootstrap() {
2842
- if (typeof globalRef.__AURA_WEB_BOOTSTRAP__ === 'function') {
2843
- return globalRef.__AURA_WEB_BOOTSTRAP__;
2844
- }
2845
- return createDeterministicBootstrap();
2846
- }
2847
-
2848
- function getLifecycleSnapshot() {
2849
- if (mountedRuntime && typeof mountedRuntime.getLifecycle === 'function') {
2850
- try {
2851
- return cloneLifecycle(mountedRuntime.getLifecycle());
2852
- } catch (_) {
2853
- return cloneLifecycle(state.lifecycle);
2854
- }
2855
- }
2856
- return cloneLifecycle(state.lifecycle);
2857
- }
2858
-
2859
- const loader = {
2860
- async load(options) {
2861
- return captureFailure(
2862
- {
2863
- reasonCode: 'web_loader_load_failed',
2864
- message: 'Loader failed to initialize web runtime assets.',
2865
- layer: 'loader',
2866
- retryable: true
2867
- },
2868
- async function () {
2869
- const opts = options || {};
2870
- const rootUrl = typeof opts.rootUrl === 'string' && opts.rootUrl.length > 0
2871
- ? opts.rootUrl.replace(/\\/$/, '')
2872
- : '.';
2873
- cachedRootUrl = rootUrl;
2874
- setState('loading', null, null);
2875
-
2876
- cachedManifest = await readJson(rootUrl + '/web-build-manifest.json', 'web_manifest_missing', 'web_manifest_parse_failed');
2877
- cachedRuntimeConfig = await readJson(rootUrl + '/runtime-config.json', 'web_runtime_config_missing', 'web_runtime_config_parse_failed');
2878
- ensureManifestValid(cachedManifest);
2879
- ensureRuntimeConfigValid(cachedRuntimeConfig);
2880
-
2881
- if (!auraRuntime) {
2882
- auraRuntime = createBrowserAuraSurface(cachedRuntimeConfig);
2883
- } else if (typeof auraRuntime.setRuntimeConfig === 'function') {
2884
- auraRuntime.setRuntimeConfig(cachedRuntimeConfig);
2885
- }
2886
- if (auraRuntime && typeof auraRuntime.setManifest === 'function') {
2887
- auraRuntime.setManifest(cachedManifest, cachedRootUrl);
2888
- }
2889
-
2890
- const bundleEntry = normalizePath(cachedManifest.entrypoints.bundle);
2891
- if (bundleEntry.length === 0) {
2892
- throw createError('web_entrypoint_missing', 'Bundle entrypoint is empty.', 'loader', false, {});
2893
- }
2894
- await loadScript(rootUrl + '/' + bundleEntry);
2895
- setState('loaded', null, null);
2896
- return true;
2897
- }
2898
- );
2899
- },
2900
- async mount(target, options) {
2901
- return captureFailure(
2902
- {
2903
- reasonCode: 'web_loader_mount_failed',
2904
- message: 'Loader mount sequence failed.',
2905
- layer: 'loader',
2906
- retryable: true
2907
- },
2908
- async function () {
2909
- if (!cachedManifest || !cachedRuntimeConfig) {
2910
- await loader.load(options || {});
2911
- }
2912
-
2913
- if (mountedRuntime && typeof mountedRuntime.unmount === 'function') {
2914
- await mountedRuntime.unmount();
2915
- mountedRuntime = null;
2916
- }
2917
-
2918
- setState('mounting', null, null);
2919
- const opts = options && typeof options === 'object' ? options : {};
2920
- const targetNode = resolveTarget(target == null ? opts.mount : target);
2921
- if (!targetNode) {
2922
- throw createError('web_loader_mount_target_invalid', 'Mount target was not found.', 'loader', false, {});
2923
- }
2924
- const canvas = targetNode.querySelector && targetNode.querySelector('canvas')
2925
- ? targetNode.querySelector('canvas')
2926
- : document.getElementById('aura-canvas');
2927
- if (!canvas) {
2928
- throw createError('web_loader_mount_failed', 'Canvas target was not found.', 'loader', true, {});
2929
- }
2930
-
2931
- if (!auraRuntime) {
2932
- auraRuntime = createBrowserAuraSurface(cachedRuntimeConfig || {});
2933
- }
2934
- if (auraRuntime && typeof auraRuntime.setManifest === 'function') {
2935
- auraRuntime.setManifest(cachedManifest || {}, cachedRootUrl);
2936
- }
2937
- ensureCapabilityDeclarationSatisfied(
2938
- cachedRuntimeConfig || {},
2939
- auraRuntime && auraRuntime.aura ? auraRuntime.aura : globalRef.aura,
2940
- );
2941
- if (typeof auraRuntime.mount === 'function') {
2942
- auraRuntime.mount(canvas, targetNode);
2943
- }
2944
-
2945
- const bootstrap = resolveBootstrap();
2946
- if (typeof bootstrap !== 'function') {
2947
- throw createError('web_runtime_bootstrap_missing', 'Bundle did not expose required bootstrap function.', 'runtime', false, {});
2948
- }
2949
-
2950
- let runtimeResult;
2951
- try {
2952
- runtimeResult = await bootstrap({
2953
- canvas: canvas,
2954
- runtimeConfig: cachedRuntimeConfig || {},
2955
- manifest: cachedManifest || {}
2956
- });
2957
- } catch (error) {
2958
- throw normalizeError(
2959
- error,
2960
- 'web_runtime_bootstrap_failed',
2961
- 'Runtime bootstrap threw an exception.',
2962
- 'runtime',
2963
- true
2964
- );
2965
- }
2966
-
2967
- if (!runtimeResult || typeof runtimeResult !== 'object') {
2968
- throw createError('web_runtime_bootstrap_failed', 'Runtime bootstrap returned invalid payload.', 'runtime', false, {});
2969
- }
2970
- if (typeof runtimeResult.unmount !== 'function') {
2971
- runtimeResult.unmount = async function () {
2972
- return true;
2973
- };
2974
- }
2975
-
2976
- mountedRuntime = runtimeResult;
2977
- state.lifecycle = getLifecycleSnapshot();
2978
- setState('mounted', null, null);
2979
- return true;
2980
- }
2981
- );
2982
- },
2983
- async unmount() {
2984
- return captureFailure(
2985
- {
2986
- reasonCode: 'web_loader_unmount_failed',
2987
- message: 'Loader unmount sequence failed.',
2988
- layer: 'loader',
2989
- retryable: true
2990
- },
2991
- async function () {
2992
- setState('unmounting', null, null);
2993
- if (mountedRuntime && typeof mountedRuntime.unmount === 'function') {
2994
- await mountedRuntime.unmount();
2995
- }
2996
- mountedRuntime = null;
2997
- state.lifecycle = cloneLifecycle(state.lifecycle);
2998
- state.lifecycle.running = false;
2999
- setState('unmounted', null, null);
3000
- return true;
3001
- }
3002
- );
3003
- },
3004
- getState() {
3005
- return {
3006
- phase: state.phase,
3007
- reasonCode: state.reasonCode,
3008
- lastError: state.lastError ? { ...state.lastError } : null,
3009
- lifecycle: getLifecycleSnapshot()
3010
- };
3011
- }
3012
- };
3013
-
3014
- globalRef.AuraWebLoader = loader;
3015
- })(typeof window !== 'undefined' ? window : globalThis);
3016
- `.trim();