@auraindustry/aurajs 0.0.7 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +5 -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 +4825 -1512
  17. package/src/commands/project-authoring.mjs +434 -0
  18. package/src/config.mjs +27 -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 +438 -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 +40 -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 +14 -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 +443 -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 +60 -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 +1187 -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
@@ -0,0 +1,773 @@
1
+ const CUSTOM_SHADER_SURFACE = Object.freeze([
2
+ 'createCustom',
3
+ 'setUniform',
4
+ 'setCustomTexture',
5
+ 'unload',
6
+ ]);
7
+
8
+ const COMMON_SHADER_KIT_NON_GOALS = Object.freeze([
9
+ 'shader graph authoring',
10
+ 'imported shader asset pipelines',
11
+ ]);
12
+
13
+ const SHADER_KIT_DEFINITIONS = Object.freeze({
14
+ hologram: createHologramDefinition(),
15
+ dissolve: createDissolveDefinition(),
16
+ foliageWind: createFoliageWindDefinition(),
17
+ rimAccent: createRimAccentDefinition(),
18
+ });
19
+
20
+ const SHADER_KIT_IDS = Object.freeze(Object.keys(SHADER_KIT_DEFINITIONS));
21
+
22
+ export { SHADER_KIT_IDS };
23
+
24
+ export function listShaderKitIds() {
25
+ return [...SHADER_KIT_IDS];
26
+ }
27
+
28
+ export function listShaderKitDefinitions() {
29
+ return SHADER_KIT_IDS.map((id) => getShaderKitDefinition(id));
30
+ }
31
+
32
+ export function getShaderKitDefinition(id) {
33
+ const definition = resolveShaderKitDefinition(id);
34
+ return definition ? toPublicShaderKitDefinition(definition) : null;
35
+ }
36
+
37
+ export function normalizeShaderKitMaterialSpec(spec) {
38
+ if (!isPlainObject(spec)) {
39
+ throw new TypeError('Shader kit material spec must be an object');
40
+ }
41
+ const presetId = typeof spec.preset === 'string'
42
+ ? spec.preset
43
+ : (typeof spec.presetId === 'string' ? spec.presetId : '');
44
+ const definition = resolveShaderKitDefinition(presetId);
45
+ if (!definition) {
46
+ throw new Error(`Unknown shader kit preset: ${presetId}`);
47
+ }
48
+ const normalizedUniforms = buildInitialState(definition, spec.uniforms);
49
+ const normalizedTextures = normalizeTextureBindings(definition, spec);
50
+ return {
51
+ preset: definition.id,
52
+ uniforms: cloneUniformObject(normalizedUniforms),
53
+ textures: cloneTextureBindings(normalizedTextures),
54
+ };
55
+ }
56
+
57
+ export function createShaderKitMaterial(aura, spec) {
58
+ const normalizedSpec = normalizeShaderKitMaterialSpec(spec);
59
+ const definition = resolveShaderKitDefinition(normalizedSpec.preset);
60
+ return createShaderKitFromNormalizedSpec(aura, definition, normalizedSpec);
61
+ }
62
+
63
+ export function createShaderKit(aura, presetId, options = {}) {
64
+ if (!isPlainObject(options)) {
65
+ throw new TypeError('Shader kit options must be an object when provided');
66
+ }
67
+ return createShaderKitMaterial(aura, {
68
+ preset: presetId,
69
+ ...options,
70
+ });
71
+ }
72
+
73
+ function createShaderKitFromNormalizedSpec(aura, definition, normalizedSpec) {
74
+ assertCustomMaterialSurface(aura);
75
+ const createOptions = {
76
+ vertex: definition.vertex,
77
+ fragment: definition.fragment,
78
+ uniforms: uniformTypeRecord(definition.uniformSchema),
79
+ };
80
+ if (definition.textureSlots.length === 1 && definition.textureSlots[0] === 'texture') {
81
+ createOptions.texture = true;
82
+ } else if (definition.textureSlots.length > 0) {
83
+ createOptions.textures = [...definition.textureSlots];
84
+ }
85
+
86
+ const handle = aura.material.createCustom(createOptions);
87
+ if (!Number.isInteger(handle) || handle <= 0) {
88
+ throw new Error(`Shader kit ${definition.id} did not return a valid material handle`);
89
+ }
90
+
91
+ const kit = createKitController(
92
+ aura,
93
+ definition,
94
+ handle,
95
+ normalizedSpec.uniforms,
96
+ normalizedSpec.textures,
97
+ );
98
+
99
+ try {
100
+ kit.apply(normalizedSpec.uniforms);
101
+ for (const [slotName, texturePath] of Object.entries(normalizedSpec.textures || {})) {
102
+ if (texturePath != null) {
103
+ kit.setTexture(slotName, texturePath);
104
+ }
105
+ }
106
+ } catch (error) {
107
+ safeUnload(aura, handle);
108
+ throw error;
109
+ }
110
+
111
+ return kit;
112
+ }
113
+
114
+ export function createHologramShaderKit(aura, options = {}) {
115
+ return createShaderKit(aura, 'hologram', options);
116
+ }
117
+
118
+ export function createDissolveShaderKit(aura, options = {}) {
119
+ return createShaderKit(aura, 'dissolve', options);
120
+ }
121
+
122
+ export function createFoliageWindShaderKit(aura, options = {}) {
123
+ return createShaderKit(aura, 'foliageWind', options);
124
+ }
125
+
126
+ export function createRimAccentShaderKit(aura, options = {}) {
127
+ return createShaderKit(aura, 'rimAccent', options);
128
+ }
129
+
130
+ function createKitController(aura, definition, handle, initialState, initialTextureBindings) {
131
+ let destroyed = false;
132
+ const state = { ...initialState };
133
+ const textureBindings = cloneTextureBindings(initialTextureBindings);
134
+
135
+ const controller = {
136
+ id: definition.id,
137
+ label: definition.label,
138
+ handle,
139
+ materialHandle: handle,
140
+ getDefinition() {
141
+ return toPublicShaderKitDefinition(definition);
142
+ },
143
+ apply(values = {}) {
144
+ ensureNotDestroyed(destroyed, definition.id);
145
+ if (!isPlainObject(values)) {
146
+ throw new TypeError(`Shader kit ${definition.id} apply(values) expects an object`);
147
+ }
148
+
149
+ for (const [name, value] of Object.entries(values)) {
150
+ const uniform = definition.uniformSchema[name];
151
+ if (!uniform) {
152
+ throw new Error(`Unknown shader kit uniform for ${definition.id}: ${name}`);
153
+ }
154
+ const normalized = uniform.normalize(value);
155
+ state[name] = cloneUniformValue(normalized);
156
+ assertMutationOk(
157
+ aura.material.setUniform(handle, name, normalized),
158
+ `setUniform(${name})`,
159
+ );
160
+ }
161
+ return controller.getState();
162
+ },
163
+ tick(dt) {
164
+ ensureNotDestroyed(destroyed, definition.id);
165
+ if (!definition.timeUniform) {
166
+ return controller.getState();
167
+ }
168
+ const step = Number.isFinite(dt) ? Number(dt) : 0;
169
+ const nextTime = Number(state[definition.timeUniform] || 0) + step;
170
+ controller.apply({ [definition.timeUniform]: nextTime });
171
+ return controller.getState();
172
+ },
173
+ setTexture(slotOrPath, maybePath) {
174
+ ensureNotDestroyed(destroyed, definition.id);
175
+ if (definition.textureSlots.length === 0) {
176
+ throw new Error(`Shader kit ${definition.id} does not declare custom textures`);
177
+ }
178
+ if (definition.textureSlots.length === 1 && arguments.length === 1) {
179
+ const slotName = definition.textureSlots[0];
180
+ const texturePath = normalizeTexturePath(slotOrPath);
181
+ assertMutationOk(
182
+ aura.material.setCustomTexture(handle, texturePath),
183
+ 'setCustomTexture(texture)',
184
+ );
185
+ textureBindings[slotName] = texturePath;
186
+ return controller.getState();
187
+ }
188
+ if (arguments.length !== 2) {
189
+ throw new TypeError(
190
+ `Shader kit ${definition.id} setTexture(slot, path) requires an explicit slot and path`,
191
+ );
192
+ }
193
+ const slotName = String(slotOrPath || '').trim();
194
+ if (!slotName) {
195
+ throw new TypeError(`Shader kit ${definition.id} requires a non-empty texture slot`);
196
+ }
197
+ const texturePath = normalizeTexturePath(maybePath);
198
+ assertMutationOk(
199
+ aura.material.setCustomTexture(handle, slotName, texturePath),
200
+ `setCustomTexture(${slotName})`,
201
+ );
202
+ textureBindings[slotName] = texturePath;
203
+ return controller.getState();
204
+ },
205
+ getState() {
206
+ return {
207
+ id: definition.id,
208
+ label: definition.label,
209
+ preset: definition.id,
210
+ handle,
211
+ materialHandle: handle,
212
+ uniforms: cloneUniformObject(state),
213
+ textures: [...definition.textureSlots],
214
+ textureBindings: cloneTextureBindings(textureBindings),
215
+ destroyed,
216
+ };
217
+ },
218
+ toMaterialSpec() {
219
+ ensureNotDestroyed(destroyed, definition.id);
220
+ return {
221
+ preset: definition.id,
222
+ uniforms: cloneUniformObject(state),
223
+ textures: cloneTextureBindings(textureBindings),
224
+ };
225
+ },
226
+ destroy() {
227
+ if (destroyed) return false;
228
+ safeUnload(aura, handle);
229
+ destroyed = true;
230
+ return true;
231
+ },
232
+ };
233
+
234
+ if (definition.timeUniform) {
235
+ controller.setTime = (value) => controller.apply({ [definition.timeUniform]: value });
236
+ }
237
+ if (definition.id === 'dissolve') {
238
+ controller.setProgress = (value) => controller.apply({ progress: value });
239
+ }
240
+ if (definition.id === 'hologram') {
241
+ controller.setEdgeColor = (value) => controller.apply({ edgeColor: value });
242
+ }
243
+ if (definition.id === 'rimAccent') {
244
+ controller.setRim = (value) => controller.apply(value);
245
+ }
246
+
247
+ return controller;
248
+ }
249
+
250
+ function buildInitialState(definition, authoredUniforms) {
251
+ const overrides = isPlainObject(authoredUniforms) ? authoredUniforms : {};
252
+ const state = {};
253
+ for (const [name, uniform] of Object.entries(definition.uniformSchema)) {
254
+ const nextValue = Object.prototype.hasOwnProperty.call(overrides, name)
255
+ ? overrides[name]
256
+ : uniform.defaultValue;
257
+ state[name] = cloneUniformValue(uniform.normalize(nextValue));
258
+ }
259
+ return state;
260
+ }
261
+
262
+ function resolveShaderKitDefinition(id) {
263
+ const presetId = String(id || '').trim();
264
+ return SHADER_KIT_DEFINITIONS[presetId] || null;
265
+ }
266
+
267
+ function toPublicShaderKitDefinition(definition) {
268
+ return {
269
+ id: definition.id,
270
+ label: definition.label,
271
+ category: definition.category,
272
+ description: definition.description,
273
+ uniforms: Object.keys(definition.uniformSchema),
274
+ uniformDefinitions: Object.entries(definition.uniformSchema).map(([name, uniform]) => ({
275
+ name,
276
+ type: uniform.type,
277
+ defaultValue: cloneUniformValue(uniform.defaultValue),
278
+ min: Number.isFinite(uniform.min) ? uniform.min : null,
279
+ max: Number.isFinite(uniform.max) ? uniform.max : null,
280
+ })),
281
+ textures: [...definition.textureSlots],
282
+ nonGoals: [...definition.nonGoals],
283
+ supportsTime: Boolean(definition.timeUniform),
284
+ };
285
+ }
286
+
287
+ function uniformTypeRecord(schema) {
288
+ const out = {};
289
+ for (const [name, entry] of Object.entries(schema)) {
290
+ out[name] = entry.type;
291
+ }
292
+ return out;
293
+ }
294
+
295
+ function createHologramDefinition() {
296
+ const fields = [
297
+ ['baseColor', 'vec4<f32>'],
298
+ ['edgeColor', 'vec4<f32>'],
299
+ ['time', 'f32'],
300
+ ['fresnelPower', 'f32'],
301
+ ['scanlineDensity', 'f32'],
302
+ ['scanlineSpeed', 'f32'],
303
+ ];
304
+ return {
305
+ id: 'hologram',
306
+ label: 'Hologram / Fresnel',
307
+ category: 'surface-fx',
308
+ description: 'Animated fresnel shell with scanline modulation for stylized props and diegetic UI.',
309
+ vertex: buildStandardVertexWGSL(fields),
310
+ fragment: `
311
+ ${buildUniformStruct('KitUniforms', fields)}
312
+
313
+ struct FragmentInput {
314
+ @builtin(position) clipPosition : vec4<f32>,
315
+ @location(0) uv : vec2<f32>,
316
+ @location(1) normal : vec3<f32>,
317
+ @location(2) worldPosition : vec3<f32>,
318
+ };
319
+
320
+ @group(2) @binding(0)
321
+ var<uniform> kit : KitUniforms;
322
+
323
+ @fragment
324
+ fn fs_main(input : FragmentInput) -> @location(0) vec4<f32> {
325
+ let normal = normalize(input.normal);
326
+ let fresnel = pow(1.0 - clamp(normal.z * 0.5 + 0.5, 0.0, 1.0), max(kit.fresnelPower, 0.1));
327
+ let scanline = 0.55 + (0.45 * sin((input.worldPosition.y * kit.scanlineDensity) + (kit.time * kit.scanlineSpeed)));
328
+ let beam = 0.6 + (0.4 * sin((input.uv.y * 28.0) + (kit.time * 4.0)));
329
+ let color = mix(kit.baseColor.rgb, kit.edgeColor.rgb, clamp(fresnel + 0.18, 0.0, 1.0));
330
+ let brightness = (0.26 + fresnel + (scanline * 0.22) + (beam * 0.18));
331
+ let alpha = clamp(kit.baseColor.a * (0.42 + (fresnel * 0.85)) * (0.7 + (scanline * 0.3)), 0.05, 1.0);
332
+ return vec4<f32>(color * brightness, alpha);
333
+ }
334
+ `,
335
+ uniformSchema: {
336
+ baseColor: vec4Uniform([0.16, 0.88, 1.0, 0.72]),
337
+ edgeColor: vec4Uniform([0.92, 0.98, 1.0, 1.0]),
338
+ time: floatUniform(0),
339
+ fresnelPower: floatUniform(2.6, 0.2, 8),
340
+ scanlineDensity: floatUniform(18, 1, 80),
341
+ scanlineSpeed: floatUniform(2.4, -30, 30),
342
+ },
343
+ textureSlots: [],
344
+ timeUniform: 'time',
345
+ nonGoals: COMMON_SHADER_KIT_NON_GOALS,
346
+ };
347
+ }
348
+
349
+ function createDissolveDefinition() {
350
+ const fields = [
351
+ ['baseColor', 'vec4<f32>'],
352
+ ['edgeColor', 'vec4<f32>'],
353
+ ['progress', 'f32'],
354
+ ['edgeWidth', 'f32'],
355
+ ['noiseScale', 'vec2<f32>'],
356
+ ];
357
+ return {
358
+ id: 'dissolve',
359
+ label: 'Dissolve',
360
+ category: 'surface-fx',
361
+ description: 'Hash-based dissolve transition with authored edge color and progress controls.',
362
+ vertex: buildStandardVertexWGSL(fields),
363
+ fragment: `
364
+ ${buildUniformStruct('KitUniforms', fields)}
365
+
366
+ struct FragmentInput {
367
+ @builtin(position) clipPosition : vec4<f32>,
368
+ @location(0) uv : vec2<f32>,
369
+ @location(1) normal : vec3<f32>,
370
+ @location(2) worldPosition : vec3<f32>,
371
+ };
372
+
373
+ @group(2) @binding(0)
374
+ var<uniform> kit : KitUniforms;
375
+
376
+ fn hash2(value : vec2<f32>) -> f32 {
377
+ return fract(sin(dot(value, vec2<f32>(12.9898, 78.233))) * 43758.5453);
378
+ }
379
+
380
+ @fragment
381
+ fn fs_main(input : FragmentInput) -> @location(0) vec4<f32> {
382
+ let scaled = floor(input.uv * kit.noiseScale);
383
+ let noise = hash2(scaled + vec2<f32>(input.worldPosition.x, input.worldPosition.z));
384
+ let edge_start = clamp(kit.progress - kit.edgeWidth, 0.0, 1.0);
385
+ if (noise < edge_start) {
386
+ discard;
387
+ }
388
+ let normal = normalize(input.normal);
389
+ let lambert = max(dot(normal, normalize(vec3<f32>(0.38, 0.88, 0.26))), 0.2);
390
+ let edge_mix = clamp((noise - edge_start) / max(kit.edgeWidth, 0.0001), 0.0, 1.0);
391
+ let color = mix(kit.edgeColor.rgb, kit.baseColor.rgb, edge_mix) * (lambert + 0.12);
392
+ let alpha = mix(0.92, kit.baseColor.a, edge_mix);
393
+ return vec4<f32>(color, alpha);
394
+ }
395
+ `,
396
+ uniformSchema: {
397
+ baseColor: vec4Uniform([0.9, 0.92, 1.0, 1.0]),
398
+ edgeColor: vec4Uniform([1.0, 0.5, 0.12, 1.0]),
399
+ progress: floatUniform(0, 0, 1),
400
+ edgeWidth: floatUniform(0.14, 0.01, 0.4),
401
+ noiseScale: vec2Uniform([10, 10], 0.1, 128),
402
+ },
403
+ textureSlots: [],
404
+ timeUniform: null,
405
+ nonGoals: COMMON_SHADER_KIT_NON_GOALS,
406
+ };
407
+ }
408
+
409
+ function createFoliageWindDefinition() {
410
+ const fields = [
411
+ ['baseColor', 'vec4<f32>'],
412
+ ['tipColor', 'vec4<f32>'],
413
+ ['time', 'f32'],
414
+ ['windAmplitude', 'f32'],
415
+ ['windFrequency', 'f32'],
416
+ ['windScale', 'f32'],
417
+ ];
418
+ return {
419
+ id: 'foliageWind',
420
+ label: 'Foliage / Wind',
421
+ category: 'deformation',
422
+ description: 'Vertex-sway kit for grass, reeds, and simple foliage cards without a shader graph.',
423
+ vertex: `
424
+ struct CameraUniform {
425
+ view : mat4x4<f32>,
426
+ projection : mat4x4<f32>,
427
+ };
428
+
429
+ struct ModelUniform {
430
+ model : mat4x4<f32>,
431
+ };
432
+
433
+ ${buildUniformStruct('KitUniforms', fields)}
434
+
435
+ struct VertexInput {
436
+ @location(0) position : vec3<f32>,
437
+ @location(1) normal : vec3<f32>,
438
+ @location(2) uv : vec2<f32>,
439
+ @location(3) color : vec4<f32>,
440
+ };
441
+
442
+ struct VertexOutput {
443
+ @builtin(position) clipPosition : vec4<f32>,
444
+ @location(0) uv : vec2<f32>,
445
+ @location(1) normal : vec3<f32>,
446
+ @location(2) sway : f32,
447
+ };
448
+
449
+ @group(0) @binding(0)
450
+ var<uniform> camera : CameraUniform;
451
+
452
+ @group(1) @binding(0)
453
+ var<uniform> model_uniform : ModelUniform;
454
+
455
+ @group(2) @binding(0)
456
+ var<uniform> kit : KitUniforms;
457
+
458
+ @vertex
459
+ fn vs_main(input : VertexInput) -> VertexOutput {
460
+ var out : VertexOutput;
461
+ let swayWeight = clamp(input.position.y * kit.windScale, 0.0, 1.0);
462
+ let phase = (input.position.x * 0.9) + (input.position.z * 0.6) + (input.uv.y * 4.0);
463
+ let sway = sin((phase * kit.windFrequency) + kit.time) * kit.windAmplitude * swayWeight;
464
+ let localPosition = vec3<f32>(
465
+ input.position.x + sway,
466
+ input.position.y,
467
+ input.position.z + (sway * 0.35),
468
+ );
469
+ let worldPosition = model_uniform.model * vec4<f32>(localPosition, 1.0);
470
+ out.clipPosition = camera.projection * camera.view * worldPosition;
471
+ out.uv = input.uv;
472
+ out.normal = normalize((model_uniform.model * vec4<f32>(input.normal, 0.0)).xyz);
473
+ out.sway = swayWeight;
474
+ return out;
475
+ }
476
+ `,
477
+ fragment: `
478
+ ${buildUniformStruct('KitUniforms', fields)}
479
+
480
+ struct FragmentInput {
481
+ @builtin(position) clipPosition : vec4<f32>,
482
+ @location(0) uv : vec2<f32>,
483
+ @location(1) normal : vec3<f32>,
484
+ @location(2) sway : f32,
485
+ };
486
+
487
+ @group(2) @binding(0)
488
+ var<uniform> kit : KitUniforms;
489
+
490
+ @fragment
491
+ fn fs_main(input : FragmentInput) -> @location(0) vec4<f32> {
492
+ let normal = normalize(input.normal);
493
+ let lambert = max(dot(normal, normalize(vec3<f32>(0.24, 0.92, 0.3))), 0.22);
494
+ let gradient = clamp((input.uv.y * 0.55) + (input.sway * 0.45), 0.0, 1.0);
495
+ let color = mix(kit.baseColor.rgb, kit.tipColor.rgb, gradient);
496
+ return vec4<f32>(color * (lambert + 0.16), mix(kit.baseColor.a, kit.tipColor.a, gradient));
497
+ }
498
+ `,
499
+ uniformSchema: {
500
+ baseColor: vec4Uniform([0.18, 0.58, 0.22, 1.0]),
501
+ tipColor: vec4Uniform([0.62, 0.88, 0.4, 1.0]),
502
+ time: floatUniform(0),
503
+ windAmplitude: floatUniform(0.18, 0, 2),
504
+ windFrequency: floatUniform(1.8, 0.1, 12),
505
+ windScale: floatUniform(1.1, 0.1, 6),
506
+ },
507
+ textureSlots: [],
508
+ timeUniform: 'time',
509
+ nonGoals: COMMON_SHADER_KIT_NON_GOALS,
510
+ };
511
+ }
512
+
513
+ function createRimAccentDefinition() {
514
+ const fields = [
515
+ ['baseColor', 'vec4<f32>'],
516
+ ['rimColor', 'vec4<f32>'],
517
+ ['rimPower', 'f32'],
518
+ ['rimIntensity', 'f32'],
519
+ ];
520
+ return {
521
+ id: 'rimAccent',
522
+ label: 'Rim / Emissive Accent',
523
+ category: 'surface-fx',
524
+ description: 'Rim-light accent pass for interactables, pickups, and stylized hero props.',
525
+ vertex: buildStandardVertexWGSL(fields),
526
+ fragment: `
527
+ ${buildUniformStruct('KitUniforms', fields)}
528
+
529
+ struct FragmentInput {
530
+ @builtin(position) clipPosition : vec4<f32>,
531
+ @location(0) uv : vec2<f32>,
532
+ @location(1) normal : vec3<f32>,
533
+ @location(2) worldPosition : vec3<f32>,
534
+ };
535
+
536
+ @group(2) @binding(0)
537
+ var<uniform> kit : KitUniforms;
538
+
539
+ @fragment
540
+ fn fs_main(input : FragmentInput) -> @location(0) vec4<f32> {
541
+ let normal = normalize(input.normal);
542
+ let lambert = max(dot(normal, normalize(vec3<f32>(0.44, 0.88, 0.24))), 0.18);
543
+ let rim = pow(1.0 - clamp(normal.z * 0.5 + 0.5, 0.0, 1.0), max(kit.rimPower, 0.1)) * kit.rimIntensity;
544
+ let color = (kit.baseColor.rgb * (lambert + 0.14)) + (kit.rimColor.rgb * rim);
545
+ let alpha = max(kit.baseColor.a, clamp(kit.rimColor.a * rim, 0.0, 1.0));
546
+ return vec4<f32>(color, alpha);
547
+ }
548
+ `,
549
+ uniformSchema: {
550
+ baseColor: vec4Uniform([0.2, 0.2, 0.24, 1.0]),
551
+ rimColor: vec4Uniform([1.0, 0.78, 0.24, 1.0]),
552
+ rimPower: floatUniform(2.2, 0.1, 8),
553
+ rimIntensity: floatUniform(1.3, 0, 6),
554
+ },
555
+ textureSlots: [],
556
+ timeUniform: null,
557
+ nonGoals: COMMON_SHADER_KIT_NON_GOALS,
558
+ };
559
+ }
560
+
561
+ function buildStandardVertexWGSL(fields) {
562
+ return `
563
+ struct CameraUniform {
564
+ view : mat4x4<f32>,
565
+ projection : mat4x4<f32>,
566
+ };
567
+
568
+ struct ModelUniform {
569
+ model : mat4x4<f32>,
570
+ };
571
+
572
+ ${buildUniformStruct('KitUniforms', fields)}
573
+
574
+ struct VertexInput {
575
+ @location(0) position : vec3<f32>,
576
+ @location(1) normal : vec3<f32>,
577
+ @location(2) uv : vec2<f32>,
578
+ @location(3) color : vec4<f32>,
579
+ };
580
+
581
+ struct VertexOutput {
582
+ @builtin(position) clipPosition : vec4<f32>,
583
+ @location(0) uv : vec2<f32>,
584
+ @location(1) normal : vec3<f32>,
585
+ @location(2) worldPosition : vec3<f32>,
586
+ };
587
+
588
+ @group(0) @binding(0)
589
+ var<uniform> camera : CameraUniform;
590
+
591
+ @group(1) @binding(0)
592
+ var<uniform> model_uniform : ModelUniform;
593
+
594
+ @group(2) @binding(0)
595
+ var<uniform> kit : KitUniforms;
596
+
597
+ @vertex
598
+ fn vs_main(input : VertexInput) -> VertexOutput {
599
+ var out : VertexOutput;
600
+ let worldPosition = model_uniform.model * vec4<f32>(input.position, 1.0);
601
+ out.clipPosition = camera.projection * camera.view * worldPosition;
602
+ out.uv = input.uv;
603
+ out.normal = normalize((model_uniform.model * vec4<f32>(input.normal, 0.0)).xyz);
604
+ out.worldPosition = worldPosition.xyz;
605
+ return out;
606
+ }
607
+ `;
608
+ }
609
+
610
+ function buildUniformStruct(name, fields) {
611
+ const body = fields.map(([fieldName, type]) => ` ${fieldName} : ${type},`).join('\n');
612
+ return `struct ${name} {\n${body}\n};`;
613
+ }
614
+
615
+ function normalizeTextureBindings(definition, spec) {
616
+ const bindings = Object.fromEntries(definition.textureSlots.map((slotName) => [slotName, null]));
617
+ if (definition.textureSlots.length === 0) {
618
+ if (Object.prototype.hasOwnProperty.call(spec, 'texture')) {
619
+ throw new Error(`Shader kit ${definition.id} does not declare custom textures`);
620
+ }
621
+ if (spec.textures != null) {
622
+ if (!isPlainObject(spec.textures) || Object.keys(spec.textures).length > 0) {
623
+ throw new Error(`Shader kit ${definition.id} does not declare custom textures`);
624
+ }
625
+ }
626
+ return bindings;
627
+ }
628
+
629
+ if (Object.prototype.hasOwnProperty.call(spec, 'texture')) {
630
+ if (!(definition.textureSlots.length === 1 && definition.textureSlots[0] === 'texture')) {
631
+ throw new Error(`Shader kit ${definition.id} requires explicit texture slots`);
632
+ }
633
+ bindings.texture = normalizeTexturePath(spec.texture);
634
+ }
635
+
636
+ if (spec.textures == null) {
637
+ return bindings;
638
+ }
639
+ if (!isPlainObject(spec.textures)) {
640
+ throw new TypeError(`Shader kit ${definition.id} textures must be an object`);
641
+ }
642
+ for (const [slotName, texturePath] of Object.entries(spec.textures)) {
643
+ if (!definition.textureSlots.includes(slotName)) {
644
+ throw new Error(`Unknown shader kit texture slot for ${definition.id}: ${slotName}`);
645
+ }
646
+ bindings[slotName] = normalizeTexturePath(texturePath);
647
+ }
648
+ return bindings;
649
+ }
650
+
651
+ function floatUniform(defaultValue, min = Number.NEGATIVE_INFINITY, max = Number.POSITIVE_INFINITY) {
652
+ return {
653
+ type: 'float',
654
+ defaultValue,
655
+ min,
656
+ max,
657
+ normalize(value) {
658
+ const number = Number.isFinite(value) ? Number(value) : Number(defaultValue);
659
+ return clamp(number, min, max);
660
+ },
661
+ };
662
+ }
663
+
664
+ function vec2Uniform(defaultValue, min = Number.NEGATIVE_INFINITY, max = Number.POSITIVE_INFINITY) {
665
+ return {
666
+ type: 'vec2',
667
+ defaultValue,
668
+ min,
669
+ max,
670
+ normalize(value) {
671
+ const [x, y] = normalizeVector(value, defaultValue, 2);
672
+ return {
673
+ x: clamp(x, min, max),
674
+ y: clamp(y, min, max),
675
+ };
676
+ },
677
+ };
678
+ }
679
+
680
+ function vec4Uniform(defaultValue) {
681
+ return {
682
+ type: 'vec4',
683
+ defaultValue,
684
+ min: null,
685
+ max: null,
686
+ normalize(value) {
687
+ const [x, y, z, w] = normalizeVector(value, defaultValue, 4);
688
+ return { x, y, z, w };
689
+ },
690
+ };
691
+ }
692
+
693
+ function normalizeVector(value, fallback, size) {
694
+ const values = Array.isArray(value)
695
+ ? value
696
+ : isPlainObject(value)
697
+ ? size === 2
698
+ ? [value.x, value.y]
699
+ : [value.x ?? value.r, value.y ?? value.g, value.z ?? value.b, value.w ?? value.a]
700
+ : [];
701
+ const out = [];
702
+ for (let i = 0; i < size; i += 1) {
703
+ const candidate = Number(values[i]);
704
+ out.push(Number.isFinite(candidate) ? candidate : Number(fallback[i]));
705
+ }
706
+ return out;
707
+ }
708
+
709
+ function normalizeTexturePath(value) {
710
+ if (value == null) return null;
711
+ if (typeof value !== 'string') {
712
+ throw new TypeError('Shader kit texture path must be a string or null');
713
+ }
714
+ return value;
715
+ }
716
+
717
+ function cloneUniformObject(state) {
718
+ const out = {};
719
+ for (const [name, value] of Object.entries(state)) {
720
+ out[name] = cloneUniformValue(value);
721
+ }
722
+ return out;
723
+ }
724
+
725
+ function cloneUniformValue(value) {
726
+ if (Array.isArray(value)) return value.slice();
727
+ if (isPlainObject(value)) return { ...value };
728
+ return value;
729
+ }
730
+
731
+ function cloneTextureBindings(bindings) {
732
+ return isPlainObject(bindings) ? { ...bindings } : {};
733
+ }
734
+
735
+ function assertCustomMaterialSurface(aura) {
736
+ if (!aura || typeof aura !== 'object' || !aura.material || typeof aura.material !== 'object') {
737
+ throw new Error('Shader kits require aura.material');
738
+ }
739
+ for (const name of CUSTOM_SHADER_SURFACE) {
740
+ if (typeof aura.material[name] !== 'function') {
741
+ throw new Error(`Shader kits require aura.material.${name}`);
742
+ }
743
+ }
744
+ }
745
+
746
+ function assertMutationOk(result, operation) {
747
+ if (result && result.ok === false) {
748
+ const reasonCode = typeof result.reasonCode === 'string'
749
+ ? result.reasonCode
750
+ : 'unknown_shader_kit_error';
751
+ throw new Error(`Shader kit mutation failed during ${operation}: ${reasonCode}`);
752
+ }
753
+ }
754
+
755
+ function safeUnload(aura, handle) {
756
+ try {
757
+ aura?.material?.unload?.(handle);
758
+ } catch (_) {}
759
+ }
760
+
761
+ function ensureNotDestroyed(destroyed, presetId) {
762
+ if (destroyed) {
763
+ throw new Error(`Shader kit ${presetId} has already been destroyed`);
764
+ }
765
+ }
766
+
767
+ function isPlainObject(value) {
768
+ return !!value && typeof value === 'object' && !Array.isArray(value);
769
+ }
770
+
771
+ function clamp(value, min, max) {
772
+ return Math.min(Math.max(value, min), max);
773
+ }