@auraindustry/aurajs 0.0.6 → 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 +103 -7
  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,2094 @@
1
+ export const SCENE3D_AND_MEDIA_CONFORMANCE_CASES = [
2
+ {
3
+ id: 'scene3d-transform-hierarchy',
4
+ modes: ['shim', 'native'],
5
+ namespaces: ['scene3d'],
6
+ functions: [
7
+ 'aura.scene3d.createNode',
8
+ 'aura.scene3d.removeNode',
9
+ 'aura.scene3d.setParent',
10
+ 'aura.scene3d.getParent',
11
+ 'aura.scene3d.setLocalTransform',
12
+ 'aura.scene3d.getLocalTransform',
13
+ 'aura.scene3d.getWorldTransform',
14
+ 'aura.scene3d.traverse',
15
+ ],
16
+ nativeChecks: [
17
+ {
18
+ id: 'scene3d.parent-child.world-transform.propagates',
19
+ expression: "(() => { const root = aura.scene3d.createNode({ position: { x: 1, y: 0, z: 0 } }); const child = aura.scene3d.createNode({ position: { x: 2, y: 0, z: 0 } }); const linked = aura.scene3d.setParent(child, root); const world = aura.scene3d.getWorldTransform(child); return linked === true && !!world && Number(world.position.x.toFixed(6)) === 3; })()",
20
+ },
21
+ {
22
+ id: 'scene3d.reparent.detach.semantics.stable',
23
+ expression: "(() => { const parentA = aura.scene3d.createNode({ position: { x: 10, y: 0, z: 0 } }); const parentB = aura.scene3d.createNode({ position: { x: 20, y: 0, z: 0 } }); const child = aura.scene3d.createNode({ position: { x: 1, y: 0, z: 0 } }); const linkA = aura.scene3d.setParent(child, parentA); const worldA = aura.scene3d.getWorldTransform(child); const localA = aura.scene3d.getLocalTransform(child); const linkB = aura.scene3d.setParent(child, parentB); const worldB = aura.scene3d.getWorldTransform(child); const localB = aura.scene3d.getLocalTransform(child); const detached = aura.scene3d.setParent(child, null); const worldDetached = aura.scene3d.getWorldTransform(child); const localDetached = aura.scene3d.getLocalTransform(child); return linkA === true && linkB === true && detached === true && Number(worldA.position.x.toFixed(6)) === 11 && Number(worldB.position.x.toFixed(6)) === 21 && Number(worldDetached.position.x.toFixed(6)) === 1 && Number(localA.position.x.toFixed(6)) === 1 && Number(localB.position.x.toFixed(6)) === 1 && Number(localDetached.position.x.toFixed(6)) === 1 && aura.scene3d.getParent(child) === null; })()",
24
+ },
25
+ {
26
+ id: 'scene3d.traverse.deterministic-order',
27
+ expression: "(() => { const root = aura.scene3d.createNode({ position: { x: 1, y: 0, z: 0 } }); const childZ = aura.scene3d.createNode({ position: { x: 3, y: 0, z: 0 } }); const childA = aura.scene3d.createNode({ position: { x: 2, y: 0, z: 0 } }); const leaf = aura.scene3d.createNode({ position: { x: 4, y: 0, z: 0 } }); aura.scene3d.setParent(childZ, root); aura.scene3d.setParent(childA, root); aura.scene3d.setParent(leaf, childA); const sample = () => { const trace = []; aura.scene3d.traverse(root, (id, world) => trace.push(`${id}:${Number(world.position.x.toFixed(3))}`)); return trace.join('|'); }; const first = sample(); const second = sample(); return first === second && first === `${root}:1|${childZ}:4|${childA}:3|${leaf}:7`; })()",
28
+ },
29
+ {
30
+ id: 'scene3d.local-update.ordering.deterministic',
31
+ expression: "(() => { const sample = () => { const root = aura.scene3d.createNode({ position: { x: 1, y: 0, z: 0 } }); const child = aura.scene3d.createNode({ position: { x: 2, y: 0, z: 0 } }); const link = aura.scene3d.setParent(child, root); const before = aura.scene3d.getWorldTransform(child); const updated = aura.scene3d.setLocalTransform(root, { position: { x: 5, y: 0, z: 0 } }); const after = aura.scene3d.getWorldTransform(child); const trace = []; aura.scene3d.traverse(root, (_id, world) => trace.push(Number(world.position.x.toFixed(3)))); return JSON.stringify({ link, updated, before: before ? Number(before.position.x.toFixed(3)) : null, after: after ? Number(after.position.x.toFixed(3)) : null, trace }); }; const first = sample(); const second = sample(); const expected = JSON.stringify({ link: true, updated: true, before: 3, after: 7, trace: [5, 7] }); return first === second && first === expected; })()",
32
+ },
33
+ {
34
+ id: 'scene3d.invalid-input.safe-false',
35
+ expression: "(() => { const root = aura.scene3d.createNode(); const child = aura.scene3d.createNode(); return aura.scene3d.setParent(root, root) === false && aura.scene3d.setParent(root, 999999) === false && aura.scene3d.setLocalTransform(root, null) === false && aura.scene3d.getWorldTransform(999999) === null && aura.scene3d.traverse(999999, () => {}) === false && aura.scene3d.setParent(child, root) === true && aura.scene3d.setParent(root, child) === false; })()",
36
+ },
37
+ ],
38
+ source: `
39
+ aura.setup = function () {
40
+ const root = aura.scene3d.createNode({ position: { x: 1, y: 2, z: 3 } });
41
+ const child = aura.scene3d.createNode({ position: { x: 0.5, y: 0, z: 0 } });
42
+ aura.scene3d.setParent(child, root);
43
+ };
44
+ `,
45
+ frames: 2,
46
+ },
47
+ {
48
+ id: 'threejs-scene3d-visibility-layer-culling-runtime',
49
+ modes: ['native'],
50
+ namespaces: ['scene3d', 'draw3d', 'mesh', 'material', 'debug'],
51
+ functions: [
52
+ 'aura.scene3d.bindRenderNode',
53
+ 'aura.scene3d.unbindRenderNode',
54
+ 'aura.scene3d.setNodeVisibility',
55
+ 'aura.scene3d.setNodeLayer',
56
+ 'aura.scene3d.setNodeCulling',
57
+ 'aura.scene3d.setCameraLayerMask',
58
+ 'aura.scene3d.setCullBounds',
59
+ 'aura.scene3d.clearCullBounds',
60
+ 'aura.scene3d.submitRenderBindings',
61
+ 'aura.scene3d.getRenderSubmissionState',
62
+ 'aura.debug.inspectorStats',
63
+ ],
64
+ nativeChecks: [
65
+ {
66
+ id: 'scene3d.render-state.surface.methods',
67
+ expression: "(() => ['bindRenderNode','unbindRenderNode','setNodeVisibility','setNodeLayer','setNodeCulling','setCameraLayerMask','setCullBounds','clearCullBounds','submitRenderBindings','getRenderSubmissionState'].every((name) => typeof aura.scene3d?.[name] === 'function'))()",
68
+ },
69
+ {
70
+ id: 'scene3d.render-state.submission.deterministic',
71
+ expression: "(() => { const runSample = () => { const mesh = aura.mesh.createBox(1, 1, 1); const material = aura.material.create({ color: { r: 0.8, g: 0.7, b: 0.6, a: 1 }, metallic: 0.1, roughness: 0.9 }); const inside = aura.scene3d.createNode({ position: { x: 0, y: 0, z: -2 } }); const layerFiltered = aura.scene3d.createNode({ position: { x: 0, y: 0, z: -2 } }); const hidden = aura.scene3d.createNode({ position: { x: 0, y: 0, z: -2 } }); const boundsFiltered = aura.scene3d.createNode({ position: { x: 4, y: 0, z: -2 } }); const bindInside = aura.scene3d.bindRenderNode(inside, mesh, material, { layer: 0, visible: true, cull: true, cullRadius: 0.5 }); const bindLayer = aura.scene3d.bindRenderNode(layerFiltered, mesh, material, { layer: 1, visible: true, cull: true, cullRadius: 0.5 }); const bindHidden = aura.scene3d.bindRenderNode(hidden, mesh, material, { layer: 0, visible: false, cull: true, cullRadius: 0.5 }); const bindBounds = aura.scene3d.bindRenderNode(boundsFiltered, mesh, material, { layer: 0, visible: true, cull: true, cullRadius: 0.5 }); const setMask = aura.scene3d.setCameraLayerMask(1); const setBounds = aura.scene3d.setCullBounds({ min: { x: -1, y: -1, z: -3 }, max: { x: 1, y: 1, z: -1 } }); aura.debug.enableInspector(true); const before = aura.debug.inspectorStats(); const submit = aura.scene3d.submitRenderBindings(); const after = aura.debug.inspectorStats(); aura.debug.enableInspector(false); const beforeSubmission = before?.scene3dRuntime?.submission || {}; const afterSubmission = after?.scene3dRuntime?.submission || {}; const render = aura.scene3d.getRenderSubmissionState(); const delta = Number(afterSubmission.drawMeshPending || 0) - Number(beforeSubmission.drawMeshPending || 0); aura.scene3d.removeNode(boundsFiltered); aura.scene3d.removeNode(hidden); aura.scene3d.removeNode(layerFiltered); aura.scene3d.removeNode(inside); aura.scene3d.clearCullBounds(); aura.material.unload(material); aura.mesh.unload(mesh); return { bindInside: bindInside?.ok === true, bindLayer: bindLayer?.ok === true, bindHidden: bindHidden?.ok === true, bindBounds: bindBounds?.ok === true, setMask: setMask?.ok === true, setBounds: setBounds?.ok === true, submitOk: submit?.ok === true, submitted: Number(submit?.submitted || 0), culledHidden: Number(submit?.culledHidden || 0), culledLayer: Number(submit?.culledLayer || 0), culledBounds: Number(submit?.culledBounds || 0), skippedMissingNode: Number(submit?.skippedMissingNode || 0), delta, renderSubmitted: Number(render?.submitted || 0), renderFingerprint: Number(render?.orderFingerprint || 0), inspectorSubmitted: Number(afterSubmission.scene3dSubmitted || 0), inspectorCulledHidden: Number(afterSubmission.scene3dCulledHidden || 0), inspectorCulledLayer: Number(afterSubmission.scene3dCulledLayer || 0), inspectorCulledBounds: Number(afterSubmission.scene3dCulledBounds || 0), inspectorReasonCode: afterSubmission.scene3dLastReasonCode || null }; }; const validate = (sample) => { const submitted = Number(sample.submitted || 0); const culledHidden = Number(sample.culledHidden || 0); const culledLayer = Number(sample.culledLayer || 0); const culledBounds = Number(sample.culledBounds || 0); const skippedMissingNode = Number(sample.skippedMissingNode || 0); return sample.bindInside && sample.bindLayer && sample.bindHidden && sample.bindBounds && sample.setMask && sample.setBounds && sample.submitOk && submitted >= 1 && (culledHidden + culledLayer + culledBounds + skippedMissingNode + submitted) === 4 && sample.delta === submitted && sample.renderSubmitted === submitted && Number.isFinite(sample.renderFingerprint) && sample.renderFingerprint > 0 && sample.inspectorSubmitted === submitted && sample.inspectorCulledHidden === culledHidden && sample.inspectorCulledLayer === culledLayer && sample.inspectorCulledBounds === culledBounds && (sample.inspectorReasonCode === 'scene3d_render_submitted' || sample.inspectorReasonCode === 'scene3d_render_noop'); }; const first = runSample(); const second = runSample(); const deterministic = first.submitted === second.submitted && first.culledHidden === second.culledHidden && first.culledLayer === second.culledLayer && first.culledBounds === second.culledBounds && first.skippedMissingNode === second.skippedMissingNode && first.delta === second.delta; return validate(first) && validate(second) && deterministic; })()",
72
+ },
73
+ {
74
+ id: 'scene3d.render-state.reason-codes',
75
+ expression: "(() => { const reasonOf = (entry) => entry && (entry.reasonCode || entry.reason); const mesh = aura.mesh.createBox(1, 1, 1); const material = aura.material.create({ color: { r: 1, g: 1, b: 1, a: 1 } }); const node = aura.scene3d.createNode(); const invalidNode = aura.scene3d.bindRenderNode(0, mesh, material); const invalidMesh = aura.scene3d.bindRenderNode(node, 0, material); const invalidMaterial = aura.scene3d.bindRenderNode(node, mesh, 0); const invalidOptions = aura.scene3d.bindRenderNode(node, mesh, material, 'bad'); const bound = aura.scene3d.bindRenderNode(node, mesh, material); const invalidVisibility = aura.scene3d.setNodeVisibility(node, 'yes'); const invalidLayer = aura.scene3d.setNodeLayer(node, 42); const invalidCull = aura.scene3d.setNodeCulling(node, 'yes'); const invalidCullRadius = aura.scene3d.setNodeCulling(node, true, { cullRadius: -1 }); const invalidMask = aura.scene3d.setCameraLayerMask(-1); const invalidBounds = aura.scene3d.setCullBounds({ min: { x: 1, y: 0, z: 0 }, max: { x: 0, y: 1, z: 1 } }); const missingBinding = aura.scene3d.setNodeLayer(999999, 0); const unbound = aura.scene3d.unbindRenderNode(node); const missingAfterUnbind = aura.scene3d.unbindRenderNode(node); aura.scene3d.removeNode(node); aura.material.unload(material); aura.mesh.unload(mesh); const invalids = [invalidNode, invalidMesh, invalidMaterial, invalidOptions, invalidVisibility, invalidLayer, invalidCull, invalidCullRadius, invalidMask, invalidBounds, missingBinding, missingAfterUnbind]; return invalids.every((entry) => typeof reasonOf(entry) === 'string' && reasonOf(entry).length > 0) && bound?.ok === true && unbound?.ok === true; })()",
76
+ },
77
+ ],
78
+ source: `
79
+ aura.setup = function () {};
80
+ `,
81
+ nativeFrames: 2,
82
+ },
83
+ {
84
+ id: 'terrain-runtime-native',
85
+ modes: ['native'],
86
+ namespaces: ['terrain', 'camera3d', 'draw3d', 'debug'],
87
+ functions: [
88
+ 'aura.terrain.create',
89
+ 'aura.terrain.setSplatMap',
90
+ 'aura.terrain.setLayerTexture',
91
+ 'aura.terrain.setHeightmap',
92
+ 'aura.terrain.addVegetation',
93
+ 'aura.terrain.getInfo',
94
+ 'aura.terrain.getVegetationInfo',
95
+ 'aura.terrain.getSubmissionState',
96
+ 'aura.terrain.sampleHeight',
97
+ 'aura.camera3d.perspective',
98
+ 'aura.camera3d.setPosition',
99
+ 'aura.camera3d.lookAt',
100
+ 'aura.draw3d.clear3d',
101
+ 'aura.debug.inspectorStats',
102
+ ],
103
+ nativeChecks: [
104
+ {
105
+ id: 'terrain.runtime.surface.methods',
106
+ expression: "(() => ['create','setSplatMap','setLayerTexture','setHeightmap','addVegetation','getInfo','getVegetationInfo','getSubmissionState','sampleHeight'].every((name) => typeof aura.terrain?.[name] === 'function') && ['perspective','setPosition','lookAt'].every((name) => typeof aura.camera3d?.[name] === 'function') && typeof aura.draw3d?.clear3d === 'function' && typeof aura.debug?.inspectorStats === 'function')()",
107
+ },
108
+ {
109
+ id: 'terrain.runtime.setup',
110
+ expression: `(() => {
111
+ try {
112
+ const fixtureRoot = 'src/cli/test-fixtures/terrain';
113
+ const assets = {
114
+ splat: \`\${fixtureRoot}/terrain-splat-rgba.png\`,
115
+ grass: \`\${fixtureRoot}/terrain-layer-grass.png\`,
116
+ rock: \`\${fixtureRoot}/terrain-layer-rock.png\`,
117
+ earth: \`\${fixtureRoot}/terrain-layer-earth.png\`,
118
+ vegetation: \`\${fixtureRoot}/terrain-vegetation-blade.png\`,
119
+ };
120
+ const terrainId = aura.terrain.create({
121
+ width: 16,
122
+ depth: 16,
123
+ segmentsX: 6,
124
+ segmentsZ: 6,
125
+ maxHeight: 5,
126
+ });
127
+ const rowSize = 7;
128
+ const heightmap = Array.from({ length: rowSize * rowSize }, (_, index) => {
129
+ const x = index % rowSize;
130
+ const z = Math.floor(index / rowSize);
131
+ const ridge = x === 3 || z === 3 ? 0.72 : 0.18;
132
+ const detail = ((x + z) % 2 === 0 ? 0.08 : 0.02);
133
+ return Math.min(1, ridge + detail);
134
+ });
135
+ aura.terrain.setSplatMap(terrainId, assets.splat);
136
+ aura.terrain.setLayerTexture(terrainId, 0, assets.grass, 4);
137
+ aura.terrain.setLayerTexture(terrainId, 1, assets.rock, 5);
138
+ aura.terrain.setLayerTexture(terrainId, 2, assets.earth, 6);
139
+ aura.terrain.setHeightmap(terrainId, heightmap);
140
+ const centerHeight = aura.terrain.sampleHeight(terrainId, 0, 0);
141
+ const edgeHeight = aura.terrain.sampleHeight(terrainId, 7.5, 7.5);
142
+ const vegetationId = aura.terrain.addVegetation(terrainId, {
143
+ texture: assets.vegetation,
144
+ density: 0.45,
145
+ minHeight: 0.7,
146
+ maxHeight: 1.35,
147
+ splatChannel: 0,
148
+ alphaCutoff: 0.1,
149
+ windDirection: [1, 0.25],
150
+ windStrength: 0.45,
151
+ windFrequency: 1.8,
152
+ });
153
+ let badLayer = null;
154
+ try {
155
+ aura.terrain.setLayerTexture(terrainId, 8, assets.grass, 4);
156
+ } catch (error) {
157
+ badLayer = String(error && error.message || error);
158
+ }
159
+ let badMissingTerrain = null;
160
+ try {
161
+ aura.terrain.setSplatMap(999999, assets.splat);
162
+ } catch (error) {
163
+ badMissingTerrain = String(error && error.message || error);
164
+ }
165
+ let badVegetation = null;
166
+ try {
167
+ aura.terrain.addVegetation(terrainId, { density: 1 });
168
+ } catch (error) {
169
+ badVegetation = String(error && error.message || error);
170
+ }
171
+ const info = aura.terrain.getInfo(terrainId);
172
+ const vegetation = aura.terrain.getVegetationInfo(vegetationId);
173
+ aura.camera3d.perspective(55, 0.1, 80);
174
+ aura.camera3d.setPosition(0, 8.2, 13.6);
175
+ aura.camera3d.lookAt(0, 1.4, 0);
176
+ const baseDraw = aura.draw;
177
+ globalThis.__terrainRuntimeProbe = {
178
+ assets,
179
+ terrainId,
180
+ vegetationId,
181
+ info,
182
+ vegetation,
183
+ centerHeight,
184
+ edgeHeight,
185
+ badLayer,
186
+ badMissingTerrain,
187
+ badVegetation,
188
+ frames: [],
189
+ };
190
+ aura.draw = function () {
191
+ const probe = globalThis.__terrainRuntimeProbe || {};
192
+ const frames = Array.isArray(probe.frames) ? probe.frames : [];
193
+ const frameIndex = frames.length;
194
+ const orbitX = Number((Math.sin(frameIndex * 0.42) * 2.2).toFixed(3));
195
+ const orbitZ = Number((13.6 - frameIndex * 0.28).toFixed(3));
196
+ aura.camera3d.setPosition(orbitX, 8.2, orbitZ);
197
+ aura.camera3d.lookAt(0, 1.4, 0);
198
+ aura.draw3d.clear3d({ r: 0.17, g: 0.2, b: 0.24, a: 1 });
199
+ frames.push({ frameIndex, orbitX, orbitZ });
200
+ if (typeof baseDraw === 'function') baseDraw();
201
+ };
202
+ return Number.isInteger(terrainId)
203
+ && terrainId > 0
204
+ && Number.isInteger(vegetationId)
205
+ && vegetationId > 0
206
+ && info?.ok === true
207
+ && info?.hasSplatMap === true
208
+ && info?.layers?.[0]?.texturePath === assets.grass
209
+ && info?.layers?.[1]?.texturePath === assets.rock
210
+ && info?.layers?.[2]?.texturePath === assets.earth
211
+ && vegetation?.ok === true
212
+ && vegetation?.texturePath === assets.vegetation
213
+ && Number(vegetation?.totalInstances || 0) > 0
214
+ && Number(centerHeight || 0) > Number(edgeHeight || 0)
215
+ && badLayer?.includes('[reason:invalid_layer]')
216
+ && badMissingTerrain?.includes('[reason:missing_terrain]')
217
+ && badVegetation?.includes('[reason:invalid_vegetation_texture]');
218
+ } catch (_) {
219
+ return false;
220
+ }
221
+ })()`,
222
+ },
223
+ ],
224
+ nativePostChecks: [
225
+ {
226
+ id: 'terrain.runtime.evidence',
227
+ expression: `(() => {
228
+ try {
229
+ const probe = globalThis.__terrainRuntimeProbe || {};
230
+ const frames = Array.isArray(probe.frames) ? probe.frames : [];
231
+ aura.debug.enableInspector(true);
232
+ const stats = aura.debug.inspectorStats() || {};
233
+ aura.debug.enableInspector(false);
234
+ const terrainState = aura.terrain.getSubmissionState() || {};
235
+ const info = aura.terrain.getInfo(probe.terrainId) || {};
236
+ const vegetation = aura.terrain.getVegetationInfo(probe.vegetationId) || {};
237
+ const terrainRuntime = stats.terrainRuntime || {};
238
+ const scene3d = stats.scene3dRuntime || {};
239
+ const submission = scene3d.submission || {};
240
+ const cameraTrace = new Set(frames.map((frame) => \`\${frame.orbitX}:\${frame.orbitZ}\`));
241
+ return Number.isInteger(probe.terrainId)
242
+ && probe.terrainId > 0
243
+ && Number.isInteger(probe.vegetationId)
244
+ && probe.vegetationId > 0
245
+ && frames.length === 5
246
+ && cameraTrace.size >= 3
247
+ && info?.ok === true
248
+ && info?.hasSplatMap === true
249
+ && vegetation?.ok === true
250
+ && Number(terrainState.terrainCount || 0) === 1
251
+ && Number(terrainState.visibleTerrainCount || 0) === 1
252
+ && Number(terrainState.terrainVertexCount || 0) > 0
253
+ && Number(terrainState.terrainIndexCount || 0) > 0
254
+ && Number(terrainState.vegetationLayerCount || 0) >= 1
255
+ && Number(terrainState.vegetationInstanceCount || 0) > 0
256
+ && Number(terrainState.lastRenderedTerrainBatchCount || 0) >= 1
257
+ && Number(terrainState.lastRenderedTerrainIndexCount || 0) > 0
258
+ && Number(terrainState.lastRenderedVegetationInstanceCount || 0) > 0
259
+ && String(terrainState.lastRenderReasonCode || '') === 'terrain_render_submitted'
260
+ && Number(terrainRuntime.lastRenderedTerrainBatchCount || 0) === Number(terrainState.lastRenderedTerrainBatchCount || 0)
261
+ && Number(terrainRuntime.lastRenderedVegetationBatchCount || 0) === Number(terrainState.lastRenderedVegetationBatchCount || 0)
262
+ && Number(submission.terrainLastRenderedTerrainBatchCount || 0) === Number(terrainState.lastRenderedTerrainBatchCount || 0)
263
+ && Number(submission.terrainLastRenderedTerrainIndexCount || 0) === Number(terrainState.lastRenderedTerrainIndexCount || 0)
264
+ && Number(submission.terrainLastRenderedVegetationBatchCount || 0) === Number(terrainState.lastRenderedVegetationBatchCount || 0)
265
+ && Number(submission.terrainLastRenderedVegetationInstanceCount || 0) === Number(terrainState.lastRenderedVegetationInstanceCount || 0)
266
+ && String(submission.terrainLastRenderReasonCode || '') === 'terrain_render_submitted'
267
+ && Number(probe.centerHeight || 0) > Number(probe.edgeHeight || 0);
268
+ } catch (_) {
269
+ return false;
270
+ }
271
+ })()`,
272
+ debugExpression: `(() => {
273
+ try {
274
+ const probe = globalThis.__terrainRuntimeProbe || {};
275
+ aura.debug.enableInspector(true);
276
+ const stats = aura.debug.inspectorStats() || {};
277
+ aura.debug.enableInspector(false);
278
+ return {
279
+ probe,
280
+ terrainState: aura.terrain.getSubmissionState() || null,
281
+ info: aura.terrain.getInfo(probe.terrainId) || null,
282
+ vegetation: aura.terrain.getVegetationInfo(probe.vegetationId) || null,
283
+ scene3dRuntime: stats.scene3dRuntime || null,
284
+ terrainRuntime: stats.terrainRuntime || null,
285
+ };
286
+ } catch (error) {
287
+ return { debugError: String(error && error.message ? error.message : error) };
288
+ }
289
+ })()`,
290
+ },
291
+ ],
292
+ source: `
293
+ globalThis.__terrainRuntimeProbe = { frames: [] };
294
+ `,
295
+ nativeFrames: 5,
296
+ },
297
+ {
298
+ id: 'threejs-terrain-canonical-runtime',
299
+ modes: ['native'],
300
+ namespaces: ['terrain', 'draw3d', 'camera3d', 'debug'],
301
+ functions: [
302
+ 'aura.terrain.create',
303
+ 'aura.terrain.destroy',
304
+ 'aura.terrain.setSplatMap',
305
+ 'aura.terrain.setLayerTexture',
306
+ 'aura.terrain.setHeightmap',
307
+ 'aura.terrain.sampleHeight',
308
+ 'aura.terrain.getInfo',
309
+ 'aura.terrain.getVegetationInfo',
310
+ 'aura.terrain.getSubmissionState',
311
+ 'aura.terrain.addVegetation',
312
+ 'aura.terrain.removeVegetation',
313
+ 'aura.terrain.setVisible',
314
+ 'aura.draw3d.clear3d',
315
+ 'aura.camera3d.perspective',
316
+ 'aura.camera3d.setPosition',
317
+ 'aura.camera3d.lookAt',
318
+ 'aura.debug.inspectorStats',
319
+ ],
320
+ nativeChecks: [
321
+ {
322
+ id: 'terrain.surface.methods',
323
+ expression: "(() => ['create','destroy','setSplatMap','setLayerTexture','setHeightmap','sampleHeight','getInfo','getVegetationInfo','getSubmissionState','addVegetation','removeVegetation','setVisible'].every((name) => typeof aura.terrain?.[name] === 'function') && typeof aura.draw3d?.clear3d === 'function' && ['perspective','setPosition','lookAt'].every((name) => typeof aura.camera3d?.[name] === 'function') && typeof aura.debug?.inspectorStats === 'function')()",
324
+ },
325
+ {
326
+ id: 'terrain.reason-codes',
327
+ expression: "(() => { const capture = (invoke) => { try { invoke(); return ''; } catch (error) { return String(error && error.message ? error.message : error); } }; const terrainId = aura.terrain.create({ width: 4, depth: 4, segmentsX: 2, segmentsZ: 2, maxHeight: 1.25 }); const missingInfo = aura.terrain.getInfo(999999); const missingVegetation = aura.terrain.getVegetationInfo(999999); const badLayer = capture(() => aura.terrain.setLayerTexture(terrainId, 9, 'bad.png')); const badSplat = capture(() => aura.terrain.setSplatMap(terrainId, ' ')); const badVegetation = capture(() => aura.terrain.addVegetation(terrainId, { density: 1 })); aura.terrain.destroy(terrainId); return missingInfo?.reasonCode === 'missing_terrain' && missingVegetation?.reasonCode === 'missing_vegetation' && badLayer.includes('[reason:invalid_layer]') && badSplat.includes('[reason:invalid_splat_texture_path]') && badVegetation.includes('[reason:invalid_vegetation_texture]'); })()",
328
+ },
329
+ {
330
+ id: 'terrain.runtime.setup',
331
+ expression: `(() => { try { const splatPath = 'src/cli/test-fixtures/terrain/terrain-splat.png'; const grassPath = 'src/cli/test-fixtures/terrain/terrain-grass.png'; const rockPath = 'src/cli/test-fixtures/terrain/terrain-rock.png'; const sandPath = 'src/cli/test-fixtures/terrain/terrain-sand.png'; const soilPath = 'src/cli/test-fixtures/terrain/terrain-soil.png'; const bladePath = 'src/cli/test-fixtures/terrain/terrain-grass-blade.png'; const texturePaths = [grassPath, rockPath, sandPath, soilPath]; const terrainId = aura.terrain.create({ width: 6, depth: 6, segmentsX: 4, segmentsZ: 4, maxHeight: 2.4 }); const heightmap = [0.05, 0.12, 0.22, 0.12, 0.05, 0.12, 0.35, 0.68, 0.42, 0.14, 0.18, 0.74, 1.35, 0.86, 0.2, 0.1, 0.42, 0.82, 0.56, 0.12, 0.02, 0.08, 0.18, 0.08, 0.02]; aura.terrain.setSplatMap(terrainId, splatPath); texturePaths.forEach((texturePath, index) => { aura.terrain.setLayerTexture(terrainId, index, texturePath, index === 2 ? 6 : 4); }); aura.terrain.setHeightmap(terrainId, heightmap); const vegetationId = aura.terrain.addVegetation(terrainId, { texture: bladePath, density: 2.4, minHeight: 0.05, maxHeight: 2.4, windStrength: 0.3, windFrequency: 1.1, alphaCutoff: 0.35, maxDistance: 32, lodLevels: 1, splatChannel: 0, windDirection: [1, 0.15] }); const info = aura.terrain.getInfo(terrainId); const vegetation = aura.terrain.getVegetationInfo(vegetationId); const sampleHeight = Number(aura.terrain.sampleHeight(terrainId, 0, 0) || 0); const edgeHeight = Number(aura.terrain.sampleHeight(terrainId, -2.5, -2.5) || 0); aura.camera3d.perspective(58, 0.1, 64); aura.camera3d.setPosition(4.6, 3.4, 5.8); aura.camera3d.lookAt(0, 0.7, 0); const baseDraw = aura.draw; globalThis.__terrainRuntimeProbe = { terrainId, vegetationId, texturePaths, splatPath, bladePath, sampleHeight, edgeHeight, frames: [] }; aura.draw = function () { const probe = globalThis.__terrainRuntimeProbe || {}; const frameIndex = Array.isArray(probe.frames) ? probe.frames.length : 0; aura.camera3d.setPosition(4.6 - (frameIndex * 0.35), 3.4, 5.8 - (frameIndex * 0.2)); aura.camera3d.lookAt(0, 0.7, 0); aura.draw3d.clear3d({ r: 0.67, g: 0.78, b: 0.92, a: 1 }); aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); const terrainState = stats.terrainRuntime || aura.terrain.getSubmissionState() || {}; probe.frames.push({ frameIndex, visibleTerrain: Number(terrainState.lastRenderVisibleTerrainCount || 0), terrainBatches: Number(terrainState.lastRenderedTerrainBatchCount || 0), terrainIndices: Number(terrainState.lastRenderedTerrainIndexCount || 0), vegetationBatches: Number(terrainState.lastRenderedVegetationBatchCount || 0), vegetationInstances: Number(terrainState.lastRenderedVegetationInstanceCount || 0), renderReason: terrainState.lastRenderReasonCode || null }); baseDraw(); }; return Number.isInteger(terrainId) && terrainId > 0 && Number.isInteger(vegetationId) && vegetationId > 0 && info?.reasonCode === 'terrain_info_ok' && info?.hasSplatMap === true && info?.layers?.[0]?.texturePath === grassPath && info?.layers?.[1]?.texturePath === rockPath && vegetation?.reasonCode === 'terrain_vegetation_info_ok' && vegetation?.texturePath === bladePath && Number(vegetation?.totalInstances || 0) > 0 && sampleHeight > edgeHeight && sampleHeight > 0.5; } catch (_) { return false; } })()`,
332
+ },
333
+ ],
334
+ nativePostChecks: [
335
+ {
336
+ id: 'terrain.runtime.evidence',
337
+ expression: `(() => { try { const probe = globalThis.__terrainRuntimeProbe || {}; const frames = Array.isArray(probe.frames) ? probe.frames : []; const terrainState = aura.terrain.getSubmissionState() || {}; const info = aura.terrain.getInfo(probe.terrainId); const vegetation = aura.terrain.getVegetationInfo(probe.vegetationId); aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); const terrainRuntime = stats.terrainRuntime || {}; const submission = stats?.scene3dRuntime?.submission || {}; const renderedTerrainBatchSet = new Set(frames.map((frame) => Number(frame.terrainBatches || 0)).filter((value) => value > 0)); return Number.isInteger(probe.terrainId) && probe.terrainId > 0 && Number.isInteger(probe.vegetationId) && probe.vegetationId > 0 && frames.length === 4 && frames.every((frame, index) => frame.frameIndex === index) && renderedTerrainBatchSet.size === 1 && [...renderedTerrainBatchSet][0] >= 1 && frames.slice(1).every((frame) => frame.visibleTerrain >= 1 && frame.terrainIndices > 0 && frame.vegetationInstances > 0 && frame.renderReason === 'terrain_render_submitted') && Number(terrainState.pendingCommandCount || 0) === 0 && Number(terrainState.lastRenderVisibleTerrainCount || 0) >= 1 && Number(terrainState.lastRenderedTerrainBatchCount || 0) >= 1 && Number(terrainState.lastRenderedTerrainIndexCount || 0) > 0 && Number(terrainState.lastRenderedVegetationInstanceCount || 0) > 0 && terrainState.lastRenderReasonCode === 'terrain_render_submitted' && info?.hasSplatMap === true && vegetation?.reasonCode === 'terrain_vegetation_info_ok' && Number(probe.sampleHeight || 0) > Number(probe.edgeHeight || 0) && Number(terrainRuntime.lastRenderedTerrainBatchCount || 0) >= 1 && Number(terrainRuntime.lastRenderedVegetationInstanceCount || 0) > 0 && terrainRuntime.lastRenderReasonCode === 'terrain_render_submitted' && Number(submission.terrainQueueDepth || 0) === 0 && Number(submission.terrainLastRenderedTerrainBatchCount || 0) >= 1 && Number(submission.terrainLastRenderedVegetationInstanceCount || 0) > 0 && submission.terrainLastRenderReasonCode === 'terrain_render_submitted'; } catch (_) { return false; } })()`,
338
+ debugExpression: `(() => { try { const probe = globalThis.__terrainRuntimeProbe || {}; aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); return { probe, terrainState: aura.terrain.getSubmissionState() || null, terrainInfo: aura.terrain.getInfo(probe.terrainId) || null, vegetationInfo: aura.terrain.getVegetationInfo(probe.vegetationId) || null, scene3dRuntime: stats.scene3dRuntime || null, terrainRuntime: stats.terrainRuntime || null }; } catch (error) { return { debugError: String(error && error.message ? error.message : error) }; } })()`,
339
+ },
340
+ ],
341
+ source: `
342
+ globalThis.__terrainRuntimeProbe = { frames: [] };
343
+ `,
344
+ nativeFrames: 4,
345
+ },
346
+ {
347
+ id: 'terrain-biome-world-authoring-runtime',
348
+ modes: ['native'],
349
+ namespaces: ['terrain', 'draw3d', 'camera3d', 'debug'],
350
+ functions: [
351
+ 'aura.terrain.createWorld',
352
+ 'aura.terrain.registerBiome',
353
+ 'aura.terrain.addRegion',
354
+ 'aura.terrain.applyBiome',
355
+ 'aura.terrain.streamWorld',
356
+ 'aura.terrain.getWorldInfo',
357
+ 'aura.terrain.getRegionInfo',
358
+ 'aura.terrain.sampleWorldHeight',
359
+ 'aura.terrain.getSubmissionState',
360
+ 'aura.draw3d.clear3d',
361
+ 'aura.camera3d.perspective',
362
+ 'aura.camera3d.setPosition',
363
+ 'aura.camera3d.lookAt',
364
+ 'aura.debug.inspectorStats',
365
+ ],
366
+ nativeChecks: [
367
+ {
368
+ id: 'terrain.world-authoring.surface.methods',
369
+ expression: "(() => ['createWorld','registerBiome','addRegion','applyBiome','streamWorld','getWorldInfo','getRegionInfo','sampleWorldHeight','getSubmissionState'].every((name) => typeof aura.terrain?.[name] === 'function') && typeof aura.draw3d?.clear3d === 'function' && ['perspective','setPosition','lookAt'].every((name) => typeof aura.camera3d?.[name] === 'function') && typeof aura.debug?.inspectorStats === 'function')()",
370
+ },
371
+ {
372
+ id: 'terrain.world-authoring.runtime.setup',
373
+ expression: `(() => { try { const state = globalThis.__terrainWorldAuthoringRuntime || {}; const fixtureRoot = 'src/cli/test-fixtures/terrain'; const assets = { splat: \`\${fixtureRoot}/terrain-splat.png\`, grass: \`\${fixtureRoot}/terrain-grass.png\`, rock: \`\${fixtureRoot}/terrain-rock.png\`, sand: \`\${fixtureRoot}/terrain-sand.png\`, soil: \`\${fixtureRoot}/terrain-soil.png\`, blade: \`\${fixtureRoot}/terrain-grass-blade.png\` }; const ridge = (crest, bias) => Array.from({ length: 25 }, (_, index) => { const x = index % 5; const z = Math.floor(index / 5); const major = x === 2 || z === 2 ? crest : bias; const detail = ((x + z) % 2 === 0 ? 0.05 : 0.02); return Math.min(1, major + detail); }); const meadow = aura.terrain.registerBiome('meadow', { splatMap: assets.splat, layers: [ { texture: assets.grass, uvScale: 4 }, { texture: assets.rock, uvScale: 6 }, { texture: assets.soil, uvScale: 5 } ], vegetation: [ { texture: assets.blade, density: 0.55, minHeight: 0.45, maxHeight: 1.15, maxDistance: 30, lodLevels: 1, windDirection: [1, 0.15], windStrength: 0.35, windFrequency: 1.1 } ] }); const dry = aura.terrain.registerBiome('dry', { splatMap: assets.splat, layers: [ { texture: assets.sand, uvScale: 5 }, { texture: assets.rock, uvScale: 7 }, { texture: assets.soil, uvScale: 4 } ], vegetation: [ { texture: assets.blade, density: 0.18, minHeight: 0.3, maxHeight: 0.7, maxDistance: 24, lodLevels: 1, windDirection: [0.75, 0.05], windStrength: 0.2, windFrequency: 0.8 } ] }); const worldId = aura.terrain.createWorld({ loadRadius: 10, unloadRadius: 14 }); const regionA = aura.terrain.addRegion(worldId, { key: 'meadow-a', origin: { x: 0, y: 0, z: 0 }, terrain: { width: 8, depth: 8, segmentsX: 4, segmentsZ: 4, maxHeight: 2.6 }, heightmap: ridge(0.82, 0.08), biome: 'meadow' }); const regionB = aura.terrain.addRegion(worldId, { key: 'dry-b', origin: { x: 10, y: 0, z: 0 }, terrain: { width: 8, depth: 8, segmentsX: 4, segmentsZ: 4, maxHeight: 1.9 }, heightmap: ridge(0.56, 0.03), biome: 'dry' }); const regionC = aura.terrain.addRegion(worldId, { key: 'meadow-c', origin: { x: 20, y: 0, z: 0 }, terrain: { width: 8, depth: 8, segmentsX: 4, segmentsZ: 4, maxHeight: 2.4 }, heightmap: ridge(0.74, 0.07), biome: 'meadow' }); const initialStream = aura.terrain.streamWorld(worldId, { x: 0, y: 0, z: 0 }); const worldInfo = aura.terrain.getWorldInfo(worldId); const regionInfoA = aura.terrain.getRegionInfo(regionA.regionId); const regionInfoB = aura.terrain.getRegionInfo(regionB.regionId); const regionInfoC = aura.terrain.getRegionInfo(regionC.regionId); const sampleA = aura.terrain.sampleWorldHeight(worldId, 0, 0); const sampleB = aura.terrain.sampleWorldHeight(worldId, 10, 0); const sampleC = aura.terrain.sampleWorldHeight(worldId, 20, 0); const outside = aura.terrain.sampleWorldHeight(worldId, 64, 64); const missingWorld = aura.terrain.getWorldInfo(999999); const missingRegion = aura.terrain.getRegionInfo(999999); state.assets = assets; state.worldId = worldId; state.regionIds = [regionA.regionId, regionB.regionId, regionC.regionId]; state.focus = { x: 0, y: 0, z: 0 }; state.streamHistory = []; state.samples = { a: sampleA, b: sampleB, c: sampleC, outside }; state.regionInfoAtSetup = { a: regionInfoA, b: regionInfoB, c: regionInfoC }; state.initialStream = initialStream; state.missingWorld = missingWorld; state.missingRegion = missingRegion; state.frameCount = 0; aura.camera3d.perspective(56, 0.1, 80); const updateCamera = () => { const orbit = 12; const x = state.focus.x + (Math.sin(state.frameCount * 0.08) * orbit); const z = 12 + (Math.cos(state.frameCount * 0.08) * 4); aura.camera3d.setPosition(x, 6.2, z); aura.camera3d.lookAt(state.focus.x + 2, 0.9, 0); }; const baseUpdate = aura.update; const baseDraw = aura.draw; aura.update = function (dt) { state.frameCount += 1; if (state.frameCount === 36) { state.focus = { x: 20, y: 0, z: 0 }; } const stream = aura.terrain.streamWorld(worldId, state.focus); const info = aura.terrain.getWorldInfo(worldId); state.streamHistory.push({ frame: state.frameCount, focusX: state.focus.x, changed: Number(stream?.changedRegionCount || 0), visible: Number(stream?.visibleRegionCount || 0), infoVisible: Number(info?.visibleRegionCount || 0), lastChanged: Number(info?.lastChangedRegionCount || 0) }); updateCamera(); if (typeof baseUpdate === 'function') baseUpdate(dt); }; aura.draw = function () { aura.draw3d.clear3d({ r: 0.62, g: 0.75, b: 0.9, a: 1 }); if (typeof baseDraw === 'function') baseDraw(); }; updateCamera(); return meadow?.ok === true && dry?.ok === true && Number.isInteger(worldId) && worldId > 0 && regionA?.ok === true && regionB?.ok === true && regionC?.ok === true && initialStream?.ok === true && worldInfo?.ok === true && worldInfo?.regionCount === 3 && worldInfo?.visibleRegionCount === 2 && regionInfoA?.biome === 'meadow' && regionInfoB?.biome === 'dry' && regionInfoC?.biome === 'meadow' && Array.isArray(regionInfoA?.vegetationIds) && regionInfoA.vegetationIds.length >= 1 && regionInfoC?.visible === false && Number(sampleA || 0) > 0.6 && Number(sampleB || 0) > 0.2 && Number(sampleC || 0) > 0.5 && outside === null && missingWorld?.reasonCode === 'missing_world' && missingRegion?.reasonCode === 'missing_region'; } catch (_) { return false; } })()`,
374
+ },
375
+ ],
376
+ nativePostChecks: [
377
+ {
378
+ id: 'terrain.world-authoring.runtime.evidence',
379
+ expression: `(() => { try { const state = globalThis.__terrainWorldAuthoringRuntime || {}; const worldInfo = aura.terrain.getWorldInfo(state.worldId || 0); const regions = Array.isArray(state.regionIds) ? state.regionIds.map((regionId) => aura.terrain.getRegionInfo(regionId)) : []; const terrainState = aura.terrain.getSubmissionState() || {}; aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); const terrainRuntime = stats.terrainRuntime || {}; const submission = stats?.scene3dRuntime?.submission || {}; const frames = Array.isArray(state.streamHistory) ? state.streamHistory : []; const early = frames.filter((frame) => frame.frame <= 10); const late = frames.filter((frame) => frame.frame >= 36); return Number.isInteger(state.worldId) && state.worldId > 0 && frames.length === 72 && early.every((frame) => frame.visible === 2 && frame.focusX === 0) && late.some((frame) => frame.changed === 2) && late.every((frame) => frame.visible === 2 && frame.focusX === 20) && worldInfo?.ok === true && worldInfo?.visibleRegionCount === 2 && worldInfo?.lastChangedRegionCount === 0 && Array.isArray(regions) && regions.length === 3 && regions[0]?.visible === false && regions[1]?.visible === true && regions[2]?.visible === true && regions[0]?.biome === 'meadow' && regions[1]?.biome === 'dry' && regions[2]?.biome === 'meadow' && Array.isArray(regions[2]?.vegetationIds) && regions[2].vegetationIds.length >= 1 && Number(terrainState.worldCount || 0) === 1 && Number(terrainState.regionCount || 0) === 3 && Number(terrainState.visibleRegionCount || 0) === 2 && Number(terrainState.biomeCount || 0) === 2 && Number(terrainState.terrainCount || 0) === 3 && Number(terrainState.vegetationLayerCount || 0) >= 3 && Number(terrainState.lastRenderVisibleTerrainCount || 0) >= 2 && Number(terrainState.lastRenderedTerrainBatchCount || 0) >= 2 && Number(terrainState.lastRenderedVegetationInstanceCount || 0) > 0 && terrainState.lastRenderReasonCode === 'terrain_render_submitted' && Number(terrainRuntime.worldCount || terrainState.worldCount || 0) === 1 && Number(submission.terrainQueueDepth || 0) === 0 && Number(submission.terrainLastRenderedTerrainBatchCount || 0) >= 2 && Number(submission.terrainLastRenderedVegetationInstanceCount || 0) > 0 && submission.terrainLastRenderReasonCode === 'terrain_render_submitted' && Number(state.samples?.a || 0) > 0.6 && Number(state.samples?.b || 0) > 0.2 && Number(state.samples?.c || 0) > 0.5 && state.samples?.outside === null && state.missingWorld?.reasonCode === 'missing_world' && state.missingRegion?.reasonCode === 'missing_region'; } catch (_) { return false; } })()`,
380
+ debugExpression: `(() => { try { const state = globalThis.__terrainWorldAuthoringRuntime || {}; aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); return { state, worldInfo: aura.terrain.getWorldInfo(state.worldId || 0) || null, regions: Array.isArray(state.regionIds) ? state.regionIds.map((regionId) => aura.terrain.getRegionInfo(regionId) || null) : [], terrainState: aura.terrain.getSubmissionState() || null, scene3dRuntime: stats.scene3dRuntime || null, terrainRuntime: stats.terrainRuntime || null }; } catch (error) { return { debugError: String(error && error.message ? error.message : error) }; } })()`,
381
+ },
382
+ ],
383
+ source: `
384
+ globalThis.__terrainWorldAuthoringRuntime = {
385
+ worldId: 0,
386
+ regionIds: [],
387
+ focus: { x: 0, y: 0, z: 0 },
388
+ streamHistory: [],
389
+ samples: {},
390
+ regionInfoAtSetup: {},
391
+ initialStream: null,
392
+ missingWorld: null,
393
+ missingRegion: null,
394
+ frameCount: 0,
395
+ };
396
+ `,
397
+ nativeFrames: 72,
398
+ },
399
+ {
400
+ id: 'threejs-scene3d-gltf-scene-import-runtime',
401
+ modes: ['native'],
402
+ namespaces: ['scene3d', 'mesh', 'material', 'debug'],
403
+ functions: [
404
+ 'aura.scene3d.loadGltfScene',
405
+ 'aura.scene3d.unloadGltfScene',
406
+ 'aura.scene3d.getImportedScene',
407
+ 'aura.scene3d.getImportedSceneMetadata',
408
+ 'aura.scene3d.getImportedCameras',
409
+ 'aura.scene3d.getImportedLights',
410
+ 'aura.scene3d.getImportedAnimations',
411
+ 'aura.scene3d.playImportedAnimation',
412
+ 'aura.scene3d.submitRenderBindings',
413
+ 'aura.scene3d.getRenderSubmissionState',
414
+ 'aura.scene3d.removeNode',
415
+ 'aura.scene3d.setCameraLayerMask',
416
+ 'aura.debug.inspectorStats',
417
+ 'aura.material.unload',
418
+ 'aura.mesh.unload',
419
+ ],
420
+ nativeChecks: [
421
+ {
422
+ id: 'scene3d.gltf-import.surface.methods',
423
+ expression: "(() => ['loadGltfScene','unloadGltfScene','getImportedScene','getImportedSceneMetadata','getImportedCameras','getImportedLights','getImportedAnimations','playImportedAnimation','submitRenderBindings','getRenderSubmissionState'].every((name) => typeof aura.scene3d?.[name] === 'function'))()",
424
+ },
425
+ {
426
+ id: 'scene3d.gltf-import.reason-codes',
427
+ expression: "(() => { const reasonOf = (entry) => entry && (entry.reasonCode || entry.reason); const expectReason = (invoke, allowMissingAsset = false) => { try { const entry = invoke(); const reason = reasonOf(entry); return typeof reason === 'string' && reason.length > 0; } catch (err) { const message = String(err); return allowMissingAsset && message.includes('Asset not found:'); } }; return expectReason(() => aura.scene3d.loadGltfScene(' '), true) && expectReason(() => aura.scene3d.loadGltfScene('ok.gltf', 'bad'), true) && expectReason(() => aura.scene3d.getImportedScene(999999)) && expectReason(() => aura.scene3d.getImportedScene('bad')) && expectReason(() => aura.scene3d.loadGltfScene('__missing__/scene.gltf'), true); })()",
428
+ },
429
+ {
430
+ id: 'scene3d.gltf-import.metadata-camera-light-animation-native',
431
+ expression: `(() => {
432
+ const scenePaths = [
433
+ '../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
434
+ '../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
435
+ '../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
436
+ '../../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
437
+ '../../../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
438
+ '../../../../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
439
+ '../../../../../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
440
+ 'src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
441
+ ];
442
+ const round = (value) => Number(Number(value || 0).toFixed(6));
443
+ const toSortedNumericArray = (values) => (Array.isArray(values)
444
+ ? values.map((value) => Number(value)).filter((value) => Number.isInteger(value) && value >= 0).sort((a, b) => a - b)
445
+ : []);
446
+ const toRoundedArray = (values) => (Array.isArray(values)
447
+ ? values.map((value) => round(value))
448
+ : []);
449
+ const loadScene = () => {
450
+ for (const scenePath of scenePaths) {
451
+ let imported = null;
452
+ try {
453
+ imported = aura.scene3d.loadGltfScene(scenePath);
454
+ } catch (_) {
455
+ continue;
456
+ }
457
+ if (imported?.ok === true && Number.isInteger(imported.importId) && imported.importId > 0) {
458
+ return { scenePath, importId: imported.importId };
459
+ }
460
+ }
461
+ return null;
462
+ };
463
+ const sample = () => {
464
+ const loaded = loadScene();
465
+ if (!loaded) return null;
466
+ const metadata = aura.scene3d.getImportedSceneMetadata(loaded.importId);
467
+ const cameras = aura.scene3d.getImportedCameras(loaded.importId);
468
+ const lights = aura.scene3d.getImportedLights(loaded.importId);
469
+ const animations = aura.scene3d.getImportedAnimations(loaded.importId);
470
+ const playback = aura.scene3d.playImportedAnimation(loaded.importId, 'TranslateMesh', { loop: false, speed: 1.25 });
471
+ const mesh = Array.isArray(metadata?.meshes) ? metadata.meshes[0] : null;
472
+ const material = Array.isArray(metadata?.materials) ? metadata.materials[0] : null;
473
+ const texture = Array.isArray(metadata?.textures) ? metadata.textures[0] : null;
474
+ if (typeof aura.scene3d.unloadGltfScene === 'function') {
475
+ try { aura.scene3d.unloadGltfScene(loaded.importId); } catch (_) {}
476
+ }
477
+ return {
478
+ loadedPath: loaded.scenePath,
479
+ defaultSceneIndex: Number(metadata?.defaultSceneIndex ?? -1),
480
+ sceneName: typeof metadata?.scenes?.[0]?.name === 'string' ? metadata.scenes[0].name : null,
481
+ rootNodes: toSortedNumericArray(metadata?.scenes?.[0]?.rootNodeIndices),
482
+ meshName: typeof mesh?.name === 'string' ? mesh.name : null,
483
+ meshSourceIndex: Number(mesh?.sourceMeshIndex ?? -1),
484
+ meshPrimitiveCount: Number(mesh?.primitiveCount ?? 0),
485
+ meshHasMorphTargets: mesh?.hasMorphTargets === true,
486
+ meshWeights: toRoundedArray(mesh?.weights),
487
+ meshMorphTargetCounts: toSortedNumericArray(mesh?.primitiveMorphTargetCounts),
488
+ meshMaterialIndices: toSortedNumericArray(mesh?.primitiveMaterialIndices),
489
+ materialName: typeof material?.name === 'string' ? material.name : null,
490
+ materialSourceIndex: Number(material?.sourceMaterialIndex ?? -1),
491
+ materialBaseColor: {
492
+ r: round(material?.baseColor?.r),
493
+ g: round(material?.baseColor?.g),
494
+ b: round(material?.baseColor?.b),
495
+ a: round(material?.baseColor?.a),
496
+ },
497
+ materialEmissive: {
498
+ r: round(material?.emissive?.r),
499
+ g: round(material?.emissive?.g),
500
+ b: round(material?.emissive?.b),
501
+ },
502
+ materialMetallic: round(material?.metallic),
503
+ materialRoughness: round(material?.roughness),
504
+ materialAlphaMode: typeof material?.alphaMode === 'string' ? material.alphaMode : null,
505
+ materialAlphaCutoff: round(material?.alphaCutoff),
506
+ materialDoubleSided: material?.doubleSided === true,
507
+ baseColorTextureIndex: Number(material?.baseColorTextureIndex ?? -1),
508
+ metallicRoughnessTextureIndex: Number(material?.metallicRoughnessTextureIndex ?? -1),
509
+ normalTextureIndex: Number(material?.normalTextureIndex ?? -1),
510
+ normalTextureScale: round(material?.normalTextureScale),
511
+ occlusionTextureIndex: Number(material?.occlusionTextureIndex ?? -1),
512
+ occlusionTextureStrength: round(material?.occlusionTextureStrength),
513
+ emissiveTextureIndex: Number(material?.emissiveTextureIndex ?? -1),
514
+ textureName: typeof texture?.name === 'string' ? texture.name : null,
515
+ textureSourceIndex: Number(texture?.sourceTextureIndex ?? -1),
516
+ textureImageIndex: Number(texture?.sourceImageIndex ?? -1),
517
+ textureImageName: typeof texture?.imageName === 'string' ? texture.imageName : null,
518
+ textureImageUri: typeof texture?.imageUri === 'string' ? texture.imageUri : null,
519
+ textureSamplerIndex: Number(texture?.samplerIndex ?? -1),
520
+ textureMinFilter: Number(texture?.minFilter ?? -1),
521
+ textureMagFilter: Number(texture?.magFilter ?? -1),
522
+ textureWrapS: Number(texture?.wrapS ?? 0),
523
+ textureWrapT: Number(texture?.wrapT ?? 0),
524
+ cameraName: typeof cameras?.[0]?.name === 'string' ? cameras[0].name : null,
525
+ cameraType: typeof cameras?.[0]?.type === 'string' ? cameras[0].type : null,
526
+ cameraNode: Number(cameras?.[0]?.nodeIndex ?? -1),
527
+ cameraNear: round(cameras?.[0]?.near),
528
+ cameraFar: round(cameras?.[0]?.far),
529
+ lightName: typeof lights?.[0]?.name === 'string' ? lights[0].name : null,
530
+ lightType: typeof lights?.[0]?.type === 'string' ? lights[0].type : null,
531
+ lightNode: Number(lights?.[0]?.nodeIndex ?? -1),
532
+ lightIntensity: round(lights?.[0]?.intensity),
533
+ lightColor: { r: round(lights?.[0]?.color?.r), g: round(lights?.[0]?.color?.g), b: round(lights?.[0]?.color?.b) },
534
+ animationName: typeof animations?.[0]?.name === 'string' ? animations[0].name : null,
535
+ animationDuration: round(animations?.[0]?.duration),
536
+ animationChannelCount: Array.isArray(animations?.[0]?.channels) ? animations[0].channels.length : 0,
537
+ animationTargetNode: Number(animations?.[0]?.channels?.[0]?.targetNode ?? -1),
538
+ animationPath: typeof animations?.[0]?.channels?.[0]?.path === 'string' ? animations[0].channels[0].path : null,
539
+ animationKeyframeCount: Number(animations?.[0]?.channels?.[0]?.keyframeCount ?? 0),
540
+ playbackName: typeof playback?.name === 'string' ? playback.name : null,
541
+ playbackDuration: round(playback?.duration),
542
+ playbackLoop: playback?.loop === false,
543
+ playbackSpeed: round(playback?.speed),
544
+ playbackChannelCount: Number(playback?.channelCount ?? 0),
545
+ };
546
+ };
547
+ const first = sample();
548
+ const second = sample();
549
+ return !!first
550
+ && !!second
551
+ && JSON.stringify(first) === JSON.stringify(second)
552
+ && first.defaultSceneIndex === 0
553
+ && first.sceneName === 'Gameplay'
554
+ && JSON.stringify(first.rootNodes) === '[0]'
555
+ && first.meshName === 'MorphHull'
556
+ && first.meshSourceIndex === 0
557
+ && first.meshPrimitiveCount === 1
558
+ && first.meshHasMorphTargets === true
559
+ && JSON.stringify(first.meshWeights) === '[0.25,0.75]'
560
+ && JSON.stringify(first.meshMorphTargetCounts) === '[2]'
561
+ && JSON.stringify(first.meshMaterialIndices) === '[0]'
562
+ && first.materialName === 'Hull'
563
+ && first.materialSourceIndex === 0
564
+ && JSON.stringify(first.materialBaseColor) === '{"r":0.7,"g":0.75,"b":0.9,"a":0.85}'
565
+ && JSON.stringify(first.materialEmissive) === '{"r":0.1,"g":0.2,"b":0.3}'
566
+ && first.materialMetallic === 0.2
567
+ && first.materialRoughness === 0.65
568
+ && first.materialAlphaMode === 'BLEND'
569
+ && first.materialAlphaCutoff === 0.4
570
+ && first.materialDoubleSided === true
571
+ && first.baseColorTextureIndex === 0
572
+ && first.metallicRoughnessTextureIndex === 0
573
+ && first.normalTextureIndex === 0
574
+ && first.normalTextureScale === 0.5
575
+ && first.occlusionTextureIndex === 0
576
+ && first.occlusionTextureStrength === 0.8
577
+ && first.emissiveTextureIndex === 0
578
+ && first.textureName === 'HullTex'
579
+ && first.textureSourceIndex === 0
580
+ && first.textureImageIndex === 0
581
+ && first.textureImageName === 'HullImage'
582
+ && first.textureImageUri === 'textures/hull-base.png'
583
+ && first.textureSamplerIndex === 0
584
+ && first.textureMinFilter === 9987
585
+ && first.textureMagFilter === 9729
586
+ && first.textureWrapS === 33071
587
+ && first.textureWrapT === 33648
588
+ && first.cameraName === 'MainCam'
589
+ && first.cameraType === 'perspective'
590
+ && first.cameraNode === 1
591
+ && first.cameraNear === 0.1
592
+ && first.cameraFar === 250
593
+ && first.lightName === 'Sun'
594
+ && first.lightType === 'directional'
595
+ && first.lightNode === 2
596
+ && first.lightIntensity === 3
597
+ && JSON.stringify(first.lightColor) === '{"r":1,"g":0.95,"b":0.9}'
598
+ && first.animationName === 'TranslateMesh'
599
+ && first.animationDuration === 2
600
+ && first.animationChannelCount === 1
601
+ && first.animationTargetNode === 3
602
+ && first.animationPath === 'translation'
603
+ && first.animationKeyframeCount === 3
604
+ && first.playbackName === 'TranslateMesh'
605
+ && first.playbackDuration === 2
606
+ && first.playbackLoop === true
607
+ && first.playbackSpeed === 1.25
608
+ && first.playbackChannelCount === 1;
609
+ })()`,
610
+ },
611
+ {
612
+ id: 'scene3d.gltf-import.material-texture-fidelity-native',
613
+ expression: `(() => {
614
+ const scenePaths = [
615
+ '../../../src/cli/test-fixtures/scene3d/import-scene-material-fidelity.gltf',
616
+ '../../../../src/cli/test-fixtures/scene3d/import-scene-material-fidelity.gltf',
617
+ '../../../../../src/cli/test-fixtures/scene3d/import-scene-material-fidelity.gltf',
618
+ '../../../../../../src/cli/test-fixtures/scene3d/import-scene-material-fidelity.gltf',
619
+ '../../../../../../../src/cli/test-fixtures/scene3d/import-scene-material-fidelity.gltf',
620
+ '../../../../../../../../src/cli/test-fixtures/scene3d/import-scene-material-fidelity.gltf',
621
+ '../../../../../../../../../src/cli/test-fixtures/scene3d/import-scene-material-fidelity.gltf',
622
+ 'src/cli/test-fixtures/scene3d/import-scene-material-fidelity.gltf',
623
+ ];
624
+ const round = (value) => Number(Number(value || 0).toFixed(6));
625
+ const vec2 = (value) => value ? { x: round(value.x), y: round(value.y) } : null;
626
+ const vec3 = (value) => value ? { r: round(value.r), g: round(value.g), b: round(value.b) } : null;
627
+ const loadScene = () => {
628
+ for (const scenePath of scenePaths) {
629
+ let imported = null;
630
+ try {
631
+ imported = aura.scene3d.loadGltfScene(scenePath);
632
+ } catch (_) {
633
+ continue;
634
+ }
635
+ if (imported?.ok === true && Number.isInteger(imported.importId) && imported.importId > 0) {
636
+ return { scenePath, importId: imported.importId };
637
+ }
638
+ }
639
+ return null;
640
+ };
641
+ const unload = (importId) => {
642
+ if (!Number.isInteger(importId) || importId <= 0) return;
643
+ try { aura.scene3d.unloadGltfScene(importId); } catch (_) {}
644
+ };
645
+ const sample = () => {
646
+ const loaded = loadScene();
647
+ if (!loaded) return null;
648
+ const metadata = aura.scene3d.getImportedSceneMetadata(loaded.importId);
649
+ const material = Array.isArray(metadata?.materials) ? metadata.materials[0] : null;
650
+ const texture = Array.isArray(metadata?.textures) ? metadata.textures[0] : null;
651
+ unload(loaded.importId);
652
+ return {
653
+ loadedPath: loaded.scenePath,
654
+ sceneName: typeof metadata?.scenes?.[0]?.name === 'string' ? metadata.scenes[0].name : null,
655
+ extensionsUsed: Array.isArray(metadata?.extensionsUsed) ? metadata.extensionsUsed.slice() : [],
656
+ extensionsRequired: Array.isArray(metadata?.extensionsRequired) ? metadata.extensionsRequired.slice() : [],
657
+ unsupportedExtensionsUsed: Array.isArray(metadata?.unsupportedExtensionsUsed) ? metadata.unsupportedExtensionsUsed.slice() : [],
658
+ unsupportedExtensionsRequired: Array.isArray(metadata?.unsupportedExtensionsRequired) ? metadata.unsupportedExtensionsRequired.slice() : [],
659
+ materialName: typeof material?.name === 'string' ? material.name : null,
660
+ baseColorTextureIndex: Number(material?.baseColorTextureIndex ?? -1),
661
+ baseColorTexCoord: Number(material?.baseColorTexture?.texCoord ?? -1),
662
+ baseColorTransform: {
663
+ offset: vec2(material?.baseColorTexture?.transform?.offset),
664
+ rotation: round(material?.baseColorTexture?.transform?.rotation),
665
+ scale: vec2(material?.baseColorTexture?.transform?.scale),
666
+ texCoord: Number(material?.baseColorTexture?.transform?.texCoord ?? -1),
667
+ },
668
+ metallicRoughnessTexCoord: Number(material?.metallicRoughnessTexture?.texCoord ?? -1),
669
+ normalTextureTexCoord: Number(material?.normalTexture?.texture?.texCoord ?? -1),
670
+ normalTextureScale: round(material?.normalTexture?.scale),
671
+ normalTransform: {
672
+ offset: vec2(material?.normalTexture?.texture?.transform?.offset),
673
+ rotation: round(material?.normalTexture?.texture?.transform?.rotation),
674
+ scale: vec2(material?.normalTexture?.texture?.transform?.scale),
675
+ texCoord: material?.normalTexture?.texture?.transform?.texCoord ?? null,
676
+ },
677
+ occlusionTextureTexCoord: Number(material?.occlusionTexture?.texture?.texCoord ?? -1),
678
+ occlusionTextureStrength: round(material?.occlusionTexture?.strength),
679
+ occlusionTransformRotation: round(material?.occlusionTexture?.texture?.transform?.rotation),
680
+ emissiveTextureTexCoord: Number(material?.emissiveTexture?.texCoord ?? -1),
681
+ extensions: {
682
+ unlit: material?.extensions?.unlit === true,
683
+ emissiveStrength: round(material?.extensions?.emissiveStrength),
684
+ clearcoatFactor: round(material?.extensions?.clearcoat?.factor),
685
+ clearcoatTextureTexCoord: Number(material?.extensions?.clearcoat?.texture?.texCoord ?? -1),
686
+ clearcoatRoughnessFactor: round(material?.extensions?.clearcoat?.roughnessFactor),
687
+ clearcoatRoughnessTextureTexCoord: Number(material?.extensions?.clearcoat?.roughnessTexture?.texCoord ?? -1),
688
+ clearcoatNormalScale: round(material?.extensions?.clearcoat?.normalTexture?.scale),
689
+ clearcoatNormalTexCoord: Number(material?.extensions?.clearcoat?.normalTexture?.texture?.texCoord ?? -1),
690
+ sheenColorFactor: vec3(material?.extensions?.sheen?.colorFactor),
691
+ sheenColorTextureTexCoord: Number(material?.extensions?.sheen?.colorTexture?.texCoord ?? -1),
692
+ sheenRoughnessFactor: round(material?.extensions?.sheen?.roughnessFactor),
693
+ sheenRoughnessTextureTexCoord: Number(material?.extensions?.sheen?.roughnessTexture?.texCoord ?? -1),
694
+ transmissionFactor: round(material?.extensions?.transmission?.factor),
695
+ transmissionTextureTexCoord: Number(material?.extensions?.transmission?.texture?.texCoord ?? -1),
696
+ ior: round(material?.extensions?.ior),
697
+ },
698
+ textureName: typeof texture?.name === 'string' ? texture.name : null,
699
+ textureImageUri: typeof texture?.imageUri === 'string' ? texture.imageUri : null,
700
+ textureWrapS: Number(texture?.wrapS ?? 0),
701
+ textureWrapT: Number(texture?.wrapT ?? 0),
702
+ };
703
+ };
704
+ const first = sample();
705
+ const second = sample();
706
+ return !!first
707
+ && !!second
708
+ && JSON.stringify(first) === JSON.stringify(second)
709
+ && first.sceneName === 'MaterialFidelity'
710
+ && JSON.stringify(first.extensionsUsed) === '["KHR_materials_clearcoat","KHR_materials_emissive_strength","KHR_materials_ior","KHR_materials_sheen","KHR_materials_specular","KHR_materials_transmission","KHR_materials_unlit","KHR_texture_basisu","KHR_texture_transform"]'
711
+ && JSON.stringify(first.extensionsRequired) === '["KHR_materials_ior","KHR_texture_transform"]'
712
+ && JSON.stringify(first.unsupportedExtensionsUsed) === '["KHR_texture_basisu"]'
713
+ && JSON.stringify(first.unsupportedExtensionsRequired) === '[]'
714
+ && first.materialName === 'FidelityHull'
715
+ && first.baseColorTextureIndex === 0
716
+ && first.baseColorTexCoord === 1
717
+ && JSON.stringify(first.baseColorTransform) === '{"offset":{"x":0.25,"y":0.5},"rotation":0.75,"scale":{"x":1.5,"y":0.5},"texCoord":0}'
718
+ && first.metallicRoughnessTexCoord === 2
719
+ && first.normalTextureTexCoord === 3
720
+ && first.normalTextureScale === 0.5
721
+ && JSON.stringify(first.normalTransform) === '{"offset":{"x":0.1,"y":0.2},"rotation":0,"scale":{"x":0.8,"y":0.9},"texCoord":null}'
722
+ && first.occlusionTextureTexCoord === 4
723
+ && first.occlusionTextureStrength === 0.8
724
+ && first.occlusionTransformRotation === 0.2
725
+ && first.emissiveTextureTexCoord === 5
726
+ && first.extensions.unlit === true
727
+ && first.extensions.emissiveStrength === 2.5
728
+ && first.extensions.clearcoatFactor === 0.6
729
+ && first.extensions.clearcoatTextureTexCoord === 6
730
+ && first.extensions.clearcoatRoughnessFactor === 0.35
731
+ && first.extensions.clearcoatRoughnessTextureTexCoord === 7
732
+ && first.extensions.clearcoatNormalScale === 0.25
733
+ && first.extensions.clearcoatNormalTexCoord === 8
734
+ && JSON.stringify(first.extensions.sheenColorFactor) === '{"r":0.55,"g":0.3,"b":0.1}'
735
+ && first.extensions.sheenColorTextureTexCoord === 10
736
+ && first.extensions.sheenRoughnessFactor === 0.45
737
+ && first.extensions.sheenRoughnessTextureTexCoord === 11
738
+ && first.extensions.transmissionFactor === 0.45
739
+ && first.extensions.transmissionTextureTexCoord === 9
740
+ && first.extensions.ior === 1.7
741
+ && first.textureName === 'FidelityTex'
742
+ && first.textureImageUri === 'textures/fidelity-base.png'
743
+ && first.textureWrapS === 33071
744
+ && first.textureWrapT === 33648;
745
+ })()`,
746
+ },
747
+ {
748
+ id: 'scene3d.gltf-import.imported-animation-playback-runtime',
749
+ expression: `(() => {
750
+ const scenePaths = [
751
+ '../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
752
+ '../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
753
+ '../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
754
+ '../../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
755
+ '../../../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
756
+ '../../../../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
757
+ '../../../../../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
758
+ 'src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
759
+ ];
760
+ const importOptions = { bindRenderNodes: true, layer: 2, visible: true, cull: false };
761
+ const metadataOnlyOptions = { bindRenderNodes: false };
762
+ const round = (value) => Number(Number(value || 0).toFixed(6));
763
+ const loadScene = (options) => {
764
+ for (const scenePath of scenePaths) {
765
+ let imported = null;
766
+ try {
767
+ imported = aura.scene3d.loadGltfScene(scenePath, options);
768
+ } catch (_) {
769
+ continue;
770
+ }
771
+ if (imported?.ok === true && Number.isInteger(imported.importId) && imported.importId > 0) {
772
+ return { scenePath, importId: imported.importId };
773
+ }
774
+ }
775
+ return null;
776
+ };
777
+ const unload = (importId) => {
778
+ if (!Number.isInteger(importId) || importId <= 0) return;
779
+ if (typeof aura.scene3d.unloadGltfScene !== 'function') return;
780
+ try { aura.scene3d.unloadGltfScene(importId); } catch (_) {}
781
+ };
782
+ const sample = () => {
783
+ const loaded = loadScene(importOptions);
784
+ if (!loaded) return null;
785
+ const metadataOnly = loadScene(metadataOnlyOptions);
786
+ const invalidImport = aura.scene3d.playImportedAnimation(0, 'TranslateMesh');
787
+ const invalidName = aura.scene3d.playImportedAnimation(loaded.importId, ' ');
788
+ const missingAnimation = aura.scene3d.playImportedAnimation(loaded.importId, 'MissingClip');
789
+ const metadataOnlyPlayback = metadataOnly
790
+ ? aura.scene3d.playImportedAnimation(metadataOnly.importId, 'TranslateMesh')
791
+ : { reason: null };
792
+ const playback = aura.scene3d.playImportedAnimation(loaded.importId, 'TranslateMesh', {
793
+ loop: false,
794
+ speed: 1.25,
795
+ });
796
+ const stateStart = playback?.ok === true ? aura.scene3d.getClipState(playback.clipId) : null;
797
+ const stepA = playback?.ok === true ? aura.scene3d.updateClips(0.5) : null;
798
+ const stateA = playback?.ok === true ? aura.scene3d.getClipState(playback.clipId) : null;
799
+ const stepB = playback?.ok === true ? aura.scene3d.updateClips(1.2) : null;
800
+ const stateB = playback?.ok === true ? aura.scene3d.getClipState(playback.clipId) : null;
801
+ aura.debug.enableInspector(true);
802
+ const stats = aura.debug.inspectorStats() || {};
803
+ aura.debug.enableInspector(false);
804
+ unload(metadataOnly?.importId);
805
+ unload(loaded.importId);
806
+ const animation = stats?.scene3dRuntime?.animation || {};
807
+ return {
808
+ invalidImportReason: typeof invalidImport?.reason === 'string' ? invalidImport.reason : null,
809
+ invalidNameReason: typeof invalidName?.reason === 'string' ? invalidName.reason : null,
810
+ missingAnimationReason: typeof missingAnimation?.reason === 'string' ? missingAnimation.reason : null,
811
+ metadataOnlyReason: typeof metadataOnlyPlayback?.reason === 'string'
812
+ ? metadataOnlyPlayback.reason
813
+ : null,
814
+ playbackOk: playback?.ok === true,
815
+ playbackName: typeof playback?.name === 'string' ? playback.name : null,
816
+ playbackLoop: playback?.loop === false,
817
+ playbackSpeed: round(playback?.speed),
818
+ playbackChannelCount: Number(playback?.channelCount || 0),
819
+ playbackTargetNode: Number(playback?.targetNode ?? -1),
820
+ playbackTargetPath: typeof playback?.targetPath === 'string' ? playback.targetPath : null,
821
+ clipIdPositive: Number.isInteger(playback?.clipId) && playback.clipId > 0,
822
+ nodeIdPositive: Number.isInteger(playback?.nodeId) && playback.nodeId > 0,
823
+ stateStartTime: round(stateStart?.time),
824
+ stateStartPlaying: stateStart?.playing === true,
825
+ stepAOk: stepA?.ok === true,
826
+ stateATime: round(stateA?.time),
827
+ stateAProgress: round(stateA?.progress),
828
+ stateAPlaying: stateA?.playing === true,
829
+ stepBOk: stepB?.ok === true,
830
+ stateBTime: round(stateB?.time),
831
+ stateBProgress: round(stateB?.progress),
832
+ stateBCompleted: stateB?.completed === true,
833
+ stateBPlaying: stateB?.playing === false,
834
+ stateBLoops: Number(stateB?.loops || 0),
835
+ anim: {
836
+ clipCount: Number(animation.clipCount || 0),
837
+ playingClipCount: Number(animation.playingClipCount || 0),
838
+ activeWeightSum: round(animation.activeWeightSum),
839
+ completeEventsDispatched: Number(animation.completeEventsDispatched || 0) > 0 ? 1 : 0,
840
+ blendEventsDispatched: Number(animation.blendEventsDispatched || 0) > 0 ? 1 : 0,
841
+ },
842
+ };
843
+ };
844
+ const first = sample();
845
+ const second = sample();
846
+ return !!first
847
+ && !!second
848
+ && JSON.stringify(first) === JSON.stringify(second)
849
+ && first.invalidImportReason === 'invalid_import_id'
850
+ && first.invalidNameReason === 'invalid_animation_name'
851
+ && first.missingAnimationReason === 'missing_imported_animation'
852
+ && first.metadataOnlyReason === 'scene_import_metadata_only'
853
+ && first.playbackOk === true
854
+ && first.playbackName === 'TranslateMesh'
855
+ && first.playbackLoop === true
856
+ && first.playbackSpeed === 1.25
857
+ && first.playbackChannelCount === 1
858
+ && first.playbackTargetNode === 3
859
+ && first.playbackTargetPath === 'translation'
860
+ && first.clipIdPositive === true
861
+ && first.nodeIdPositive === true
862
+ && first.stateStartTime === 0
863
+ && first.stateStartPlaying === true
864
+ && first.stepAOk === true
865
+ && first.stateATime === 0.625
866
+ && first.stateAProgress === 0.3125
867
+ && first.stateAPlaying === true
868
+ && first.stepBOk === true
869
+ && first.stateBTime === 2
870
+ && first.stateBProgress === 1
871
+ && first.stateBCompleted === true
872
+ && first.stateBPlaying === true
873
+ && first.stateBLoops === 0
874
+ && first.anim.clipCount === 1
875
+ && first.anim.playingClipCount === 0
876
+ && first.anim.activeWeightSum === 1
877
+ && first.anim.completeEventsDispatched === 1
878
+ && first.anim.blendEventsDispatched === 0;
879
+ })()`,
880
+ },
881
+ {
882
+ id: 'scene3d.gltf-import.imported-morph-runtime-setup',
883
+ expression: `(() => {
884
+ const scenePaths = [
885
+ '../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
886
+ '../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
887
+ '../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
888
+ '../../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
889
+ '../../../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
890
+ '../../../../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
891
+ '../../../../../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
892
+ 'src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
893
+ ];
894
+ const importOptions = { bindRenderNodes: true, layer: 2, visible: true, cull: false };
895
+ const round = (value) => Number(Number(value || 0).toFixed(6));
896
+ const roundArray = (values) => (Array.isArray(values) ? values.map((value) => round(value)) : []);
897
+ const baseState = globalThis.__importedMorphRuntime || {};
898
+ const loadScene = () => {
899
+ for (const scenePath of scenePaths) {
900
+ let imported = null;
901
+ try {
902
+ imported = aura.scene3d.loadGltfScene(scenePath, importOptions);
903
+ } catch (_) {
904
+ continue;
905
+ }
906
+ if (imported?.ok === true && Number.isInteger(imported.importId) && imported.importId > 0) {
907
+ return { scenePath, importId: imported.importId };
908
+ }
909
+ }
910
+ return null;
911
+ };
912
+ const loaded = loadScene();
913
+ if (!loaded) return false;
914
+ const queried = aura.scene3d.getImportedScene(loaded.importId);
915
+ if (!queried || queried.ok !== true) return false;
916
+ const morphBinding = (Array.isArray(queried.primitiveBindings) ? queried.primitiveBindings : [])
917
+ .find((entry) => entry?.hasMorphTargets === true) || null;
918
+ const runtimeBinding = queried.materials?.[0]?.runtimeBinding || null;
919
+ const runtimeTexture = queried.textures?.[0] || null;
920
+ aura.scene3d.setCameraLayerMask(1 << 2);
921
+ const baseDraw = typeof aura.draw === 'function' ? aura.draw.bind(aura) : function () {};
922
+ aura.draw = function () {
923
+ aura.scene3d.submitRenderBindings();
924
+ baseDraw();
925
+ };
926
+ globalThis.__importedMorphRuntime = {
927
+ ...baseState,
928
+ importId: loaded.importId,
929
+ scenePath: loaded.scenePath,
930
+ };
931
+ return queried.runtimeReasonCode === 'scene_import_runtime_bound'
932
+ && Number(queried.importedMorphPrimitiveCount || 0) === 1
933
+ && Number(queried.boundMorphPrimitiveCount || 0) === 1
934
+ && Number(queried.morphTargetCount || 0) === 2
935
+ && Number(queried.nonZeroMorphWeightPrimitiveCount || 0) === 1
936
+ && morphBinding?.primitiveIndex === 0
937
+ && Number(morphBinding?.morphTargetCount || 0) === 2
938
+ && morphBinding?.hasNonZeroMorphWeights === true
939
+ && JSON.stringify(roundArray(morphBinding?.weights || [])) === '[0.25,0.75]'
940
+ && runtimeBinding?.alphaMode === 'blend'
941
+ && round(runtimeBinding?.alphaCutoff) === 0.4
942
+ && runtimeBinding?.doubleSided === true
943
+ && runtimeBinding?.textureFilter === 'linear'
944
+ && JSON.stringify(Array.isArray(runtimeBinding?.omissions) ? runtimeBinding.omissions.slice().sort() : []) === '[\"normal_texture_scale_unapplied\",\"texture_sampler_modes_quantized\"]'
945
+ && Number(runtimeTexture?.sourceTextureIndex || 0) === 0
946
+ && runtimeTexture?.textureFilter === 'linear'
947
+ && runtimeTexture?.runtimeBindable === true
948
+ && runtimeTexture?.reasonCode === 'scene_texture_runtime_bindable'
949
+ && String(runtimeTexture?.resolvedPath || '').endsWith('textures/hull-base.png');
950
+ })()`,
951
+ },
952
+ {
953
+ id: 'scene3d.gltf-import.deterministic-hierarchy-material-bindings',
954
+ expression: `(() => {
955
+ const scenePaths = [
956
+ '../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
957
+ '../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
958
+ '../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
959
+ '../../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
960
+ '../../../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
961
+ '../../../../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
962
+ '../../../../../../../../../src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
963
+ 'src/cli/test-fixtures/scene3d/import-scene-rich.gltf',
964
+ ];
965
+ const importOptions = { bindRenderNodes: true, layer: 2, visible: true, cull: false };
966
+ const toSortedNumericArray = (values) => (Array.isArray(values)
967
+ ? values.map((value) => Number(value)).filter((value) => Number.isInteger(value) && value >= 0).sort((a, b) => a - b)
968
+ : []);
969
+ const normalizeColor = (color) => ({
970
+ r: Number((Number(color?.r ?? 0)).toFixed(6)),
971
+ g: Number((Number(color?.g ?? 0)).toFixed(6)),
972
+ b: Number((Number(color?.b ?? 0)).toFixed(6)),
973
+ a: Number((Number(color?.a ?? 0)).toFixed(6)),
974
+ });
975
+ const loadScene = () => {
976
+ for (const scenePath of scenePaths) {
977
+ let imported = null;
978
+ try {
979
+ imported = aura.scene3d.loadGltfScene(scenePath, importOptions);
980
+ } catch (_) {
981
+ continue;
982
+ }
983
+ if (imported?.ok === true && Number.isInteger(imported.importId) && imported.importId > 0) {
984
+ return { scenePath, importId: imported.importId };
985
+ }
986
+ }
987
+ return null;
988
+ };
989
+ const sample = () => {
990
+ const loaded = loadScene();
991
+ if (!loaded) return null;
992
+ const queried = aura.scene3d.getImportedScene(loaded.importId);
993
+ if (!queried || queried.ok !== true) {
994
+ if (typeof aura.scene3d.unloadGltfScene === 'function') {
995
+ try { aura.scene3d.unloadGltfScene(loaded.importId); } catch (_) {}
996
+ }
997
+ return null;
998
+ }
999
+ const nodeHandles = (Array.isArray(queried.nodeHandles) ? queried.nodeHandles : []).map((entry) => ({
1000
+ sourceNodeIndex: Number(entry?.sourceNodeIndex || 0),
1001
+ parentSourceNodeIndex: Number.isInteger(entry?.parentSourceNodeIndex) ? Number(entry.parentSourceNodeIndex) : null,
1002
+ nodeId: Number(entry?.nodeId || 0),
1003
+ parentNodeId: Number.isInteger(entry?.parentNodeId) ? Number(entry.parentNodeId) : null,
1004
+ })).sort((a, b) => (a.sourceNodeIndex - b.sourceNodeIndex) || (a.nodeId - b.nodeId));
1005
+ const primitiveBindings = (Array.isArray(queried.primitiveBindings) ? queried.primitiveBindings : []).map((entry) => ({
1006
+ primitiveIndex: Number(entry?.primitiveIndex || 0),
1007
+ nodeId: Number(entry?.nodeId || 0),
1008
+ meshHandle: Number(entry?.meshHandle || 0),
1009
+ materialHandle: Number(entry?.materialHandle || 0),
1010
+ sourceMeshIndex: Number(entry?.sourceMeshIndex || 0),
1011
+ sourcePrimitiveIndex: Number(entry?.sourcePrimitiveIndex || 0),
1012
+ materialIndex: Number.isInteger(entry?.materialIndex) ? Number(entry.materialIndex) : null,
1013
+ })).sort((a, b) => (a.primitiveIndex - b.primitiveIndex) || (a.nodeId - b.nodeId));
1014
+ const materials = (Array.isArray(queried.materials) ? queried.materials : []).map((entry) => ({
1015
+ sourceMaterialIndex: Number(entry?.sourceMaterialIndex || 0),
1016
+ materialHandle: Number(entry?.materialHandle || 0),
1017
+ name: typeof entry?.name === 'string' ? entry.name : null,
1018
+ baseColor: normalizeColor(entry?.baseColor),
1019
+ metallic: Number((Number(entry?.metallic ?? 0)).toFixed(6)),
1020
+ roughness: Number((Number(entry?.roughness ?? 0)).toFixed(6)),
1021
+ alphaMode: typeof entry?.alphaMode === 'string' ? entry.alphaMode : null,
1022
+ alphaCutoff: Number((Number(entry?.alphaCutoff ?? 0)).toFixed(6)),
1023
+ doubleSided: entry?.doubleSided === true,
1024
+ textureFilter: typeof entry?.textureFilter === 'string' ? entry.textureFilter : null,
1025
+ runtimeBinding: entry?.runtimeBinding ? {
1026
+ alphaMode: typeof entry.runtimeBinding.alphaMode === 'string' ? entry.runtimeBinding.alphaMode : null,
1027
+ alphaCutoff: Number((Number(entry.runtimeBinding.alphaCutoff ?? 0)).toFixed(6)),
1028
+ doubleSided: entry.runtimeBinding.doubleSided === true,
1029
+ textureFilter: typeof entry.runtimeBinding.textureFilter === 'string' ? entry.runtimeBinding.textureFilter : null,
1030
+ } : null,
1031
+ })).sort((a, b) => a.sourceMaterialIndex - b.sourceMaterialIndex);
1032
+ const textures = (Array.isArray(queried.textures) ? queried.textures : []).map((entry) => ({
1033
+ sourceTextureIndex: Number(entry?.sourceTextureIndex || 0),
1034
+ imageUri: typeof entry?.imageUri === 'string' ? entry.imageUri : null,
1035
+ textureFilter: typeof entry?.textureFilter === 'string' ? entry.textureFilter : null,
1036
+ runtimeBindable: entry?.runtimeBindable === true,
1037
+ reasonCode: typeof entry?.reasonCode === 'string' ? entry.reasonCode : null,
1038
+ resolvedAsset: String(entry?.resolvedPath || '').endsWith('textures/hull-base.png'),
1039
+ })).sort((a, b) => a.sourceTextureIndex - b.sourceTextureIndex);
1040
+ const minNodeId = nodeHandles.reduce((min, entry) => (entry.nodeId > 0 && entry.nodeId < min ? entry.nodeId : min), Number.POSITIVE_INFINITY);
1041
+ const minMeshHandle = primitiveBindings.reduce((min, entry) => (entry.meshHandle > 0 && entry.meshHandle < min ? entry.meshHandle : min), Number.POSITIVE_INFINITY);
1042
+ const minMaterialHandle = materials.reduce((min, entry) => (entry.materialHandle > 0 && entry.materialHandle < min ? entry.materialHandle : min), Number.POSITIVE_INFINITY);
1043
+ const nodeBase = Number.isFinite(minNodeId) ? minNodeId : 0;
1044
+ const meshBase = Number.isFinite(minMeshHandle) ? minMeshHandle : 0;
1045
+ const materialBase = Number.isFinite(minMaterialHandle) ? minMaterialHandle : 0;
1046
+ const normalizedNodeHandles = nodeHandles.map((entry) => ({
1047
+ sourceNodeIndex: entry.sourceNodeIndex,
1048
+ parentSourceNodeIndex: entry.parentSourceNodeIndex,
1049
+ nodeOffset: entry.nodeId > 0 ? entry.nodeId - nodeBase : 0,
1050
+ parentNodeOffset: entry.parentNodeId != null && entry.parentNodeId > 0 ? entry.parentNodeId - nodeBase : null,
1051
+ }));
1052
+ const normalizedPrimitiveBindings = primitiveBindings.map((entry) => ({
1053
+ primitiveIndex: entry.primitiveIndex,
1054
+ nodeOffset: entry.nodeId > 0 ? entry.nodeId - nodeBase : 0,
1055
+ meshOffset: entry.meshHandle > 0 ? entry.meshHandle - meshBase : 0,
1056
+ materialOffset: entry.materialHandle > 0 ? entry.materialHandle - materialBase : 0,
1057
+ sourceMeshIndex: entry.sourceMeshIndex,
1058
+ sourcePrimitiveIndex: entry.sourcePrimitiveIndex,
1059
+ materialIndex: entry.materialIndex,
1060
+ }));
1061
+ const normalizedMaterials = materials.map((entry) => ({
1062
+ sourceMaterialIndex: entry.sourceMaterialIndex,
1063
+ materialOffset: entry.materialHandle > 0 ? entry.materialHandle - materialBase : 0,
1064
+ name: entry.name,
1065
+ baseColor: entry.baseColor,
1066
+ metallic: entry.metallic,
1067
+ roughness: entry.roughness,
1068
+ alphaMode: entry.alphaMode,
1069
+ alphaCutoff: entry.alphaCutoff,
1070
+ doubleSided: entry.doubleSided,
1071
+ textureFilter: entry.textureFilter,
1072
+ runtimeBinding: entry.runtimeBinding,
1073
+ }));
1074
+ aura.scene3d.setCameraLayerMask(1 << 2);
1075
+ aura.debug.enableInspector(true);
1076
+ const submit = aura.scene3d.submitRenderBindings();
1077
+ const render = aura.scene3d.getRenderSubmissionState();
1078
+ const stats = aura.debug.inspectorStats() || {};
1079
+ aura.debug.enableInspector(false);
1080
+ if (typeof aura.scene3d.unloadGltfScene === 'function') {
1081
+ try { aura.scene3d.unloadGltfScene(loaded.importId); } catch (_) {}
1082
+ }
1083
+ const importStats = stats?.scene3dRuntime?.importedScenes || {};
1084
+ const queryOrderFingerprint = Number((queried.orderFingerprint >>> 0) || 0);
1085
+ const querySceneFingerprint = Number((queried.sceneFingerprint >>> 0) || 0);
1086
+ const queryRuntimeFingerprint = Number((queried.runtimeFingerprint >>> 0) || 0);
1087
+ return {
1088
+ loadedPath: loaded.scenePath,
1089
+ runtimeReasonCode: queried.runtimeReasonCode || null,
1090
+ nodeCount: Number(queried.nodeCount || 0),
1091
+ primitiveCount: Number(queried.primitiveCount || 0),
1092
+ materialCount: Number(queried.materialCount || 0),
1093
+ roots: toSortedNumericArray(queried.rootSourceNodeIndices),
1094
+ orderFingerprint: queryOrderFingerprint,
1095
+ sceneFingerprint: querySceneFingerprint,
1096
+ runtimeFingerprint: queryRuntimeFingerprint,
1097
+ normalizedNodeHandles,
1098
+ normalizedPrimitiveBindings,
1099
+ normalizedMaterials,
1100
+ textures,
1101
+ importTelemetry: {
1102
+ count: Number(importStats?.count || 0),
1103
+ nodeCount: Number(importStats?.nodeCount || 0),
1104
+ primitiveBindingCount: Number(importStats?.primitiveBindingCount || 0),
1105
+ lastOrderFingerprint: Number(importStats?.lastOrderFingerprint || 0),
1106
+ lastSceneFingerprint: Number(importStats?.lastSceneFingerprint || 0),
1107
+ lastRuntimeFingerprint: Number(importStats?.lastRuntimeFingerprint || 0),
1108
+ lastRuntimeReasonCode: typeof importStats?.lastRuntimeReasonCode === 'string'
1109
+ ? importStats.lastRuntimeReasonCode
1110
+ : null,
1111
+ },
1112
+ submitOk: submit?.ok === true,
1113
+ submitted: Number(submit?.submitted || 0),
1114
+ renderSubmitted: Number(render?.submitted || 0),
1115
+ renderReason: render?.lastReasonCode || null,
1116
+ };
1117
+ };
1118
+ const first = sample();
1119
+ const second = sample();
1120
+ const expectedMaterialSignature = JSON.stringify([
1121
+ {
1122
+ sourceMaterialIndex: 0,
1123
+ materialOffset: 0,
1124
+ name: 'Hull',
1125
+ baseColor: { r: 0.7, g: 0.75, b: 0.9, a: 0.85 },
1126
+ metallic: 0.2,
1127
+ roughness: 0.65,
1128
+ alphaMode: 'blend',
1129
+ alphaCutoff: 0.4,
1130
+ doubleSided: true,
1131
+ textureFilter: 'linear',
1132
+ runtimeBinding: {
1133
+ alphaMode: 'blend',
1134
+ alphaCutoff: 0.4,
1135
+ doubleSided: true,
1136
+ textureFilter: 'linear',
1137
+ },
1138
+ },
1139
+ ]);
1140
+ const expectedTextureSignature = JSON.stringify([
1141
+ {
1142
+ sourceTextureIndex: 0,
1143
+ imageUri: 'textures/hull-base.png',
1144
+ textureFilter: 'linear',
1145
+ runtimeBindable: true,
1146
+ reasonCode: 'scene_texture_runtime_bindable',
1147
+ resolvedAsset: true,
1148
+ },
1149
+ ]);
1150
+ return !!first
1151
+ && !!second
1152
+ && JSON.stringify(first) === JSON.stringify(second)
1153
+ && first.runtimeReasonCode === 'scene_import_runtime_bound'
1154
+ && first.nodeCount === 4
1155
+ && first.primitiveCount === 1
1156
+ && first.materialCount === 1
1157
+ && JSON.stringify(first.roots) === '[0]'
1158
+ && first.normalizedNodeHandles.length === 4
1159
+ && first.normalizedPrimitiveBindings.length === 1
1160
+ && first.normalizedMaterials.length === 1
1161
+ && first.textures.length === 1
1162
+ && first.orderFingerprint > 0
1163
+ && first.sceneFingerprint > 0
1164
+ && first.runtimeFingerprint > 0
1165
+ && first.submitOk === true
1166
+ && first.submitted >= 1
1167
+ && first.renderSubmitted >= 1
1168
+ && (first.renderReason === 'scene3d_render_submitted' || first.renderReason === 'scene3d_render_noop')
1169
+ && first.importTelemetry.count >= 1
1170
+ && first.importTelemetry.nodeCount >= first.nodeCount
1171
+ && first.importTelemetry.primitiveBindingCount >= first.primitiveCount
1172
+ && first.importTelemetry.lastOrderFingerprint === first.orderFingerprint
1173
+ && first.importTelemetry.lastSceneFingerprint === first.sceneFingerprint
1174
+ && first.importTelemetry.lastRuntimeFingerprint === first.runtimeFingerprint
1175
+ && first.importTelemetry.lastRuntimeReasonCode === 'scene_import_runtime_bound'
1176
+ && JSON.stringify(first.normalizedMaterials) === expectedMaterialSignature
1177
+ && JSON.stringify(first.textures) === expectedTextureSignature;
1178
+ })()`,
1179
+ },
1180
+ ],
1181
+ nativePostChecks: [
1182
+ {
1183
+ id: 'scene3d.gltf-import.imported-morph-runtime-telemetry',
1184
+ expression: `(() => {
1185
+ const round = (value) => Number(Number(value || 0).toFixed(6));
1186
+ const roundArray = (values) => (Array.isArray(values) ? values.map((value) => round(value)) : []);
1187
+ const state = globalThis.__importedMorphRuntime || {};
1188
+ const importId = Number(state.importId || 0);
1189
+ if (!Number.isInteger(importId) || importId <= 0) return false;
1190
+ const queried = aura.scene3d.getImportedScene(importId);
1191
+ if (!queried || queried.ok !== true) return false;
1192
+ const morphBinding = (Array.isArray(queried.primitiveBindings) ? queried.primitiveBindings : [])
1193
+ .find((entry) => entry?.hasMorphTargets === true) || null;
1194
+ aura.debug.enableInspector(true);
1195
+ const stats = aura.debug.inspectorStats() || {};
1196
+ aura.debug.enableInspector(false);
1197
+ const importTelemetry = stats?.scene3dRuntime?.importedScenes || {};
1198
+ const resources = stats?.scene3dRuntime?.resources || {};
1199
+ const submission = stats?.scene3dRuntime?.submission || {};
1200
+ const render = aura.scene3d.getRenderSubmissionState() || {};
1201
+ return queried.runtimeReasonCode === 'scene_import_runtime_bound'
1202
+ && Number(queried.importedMorphPrimitiveCount || 0) === 1
1203
+ && Number(queried.boundMorphPrimitiveCount || 0) === 1
1204
+ && Number(queried.morphTargetCount || 0) === 2
1205
+ && Number(queried.nonZeroMorphWeightPrimitiveCount || 0) === 1
1206
+ && morphBinding?.primitiveIndex === 0
1207
+ && Number(morphBinding?.morphTargetCount || 0) === 2
1208
+ && morphBinding?.hasNonZeroMorphWeights === true
1209
+ && JSON.stringify(roundArray(morphBinding?.weights || [])) === '[0.25,0.75]'
1210
+ && Number(importTelemetry.count || 0) >= 1
1211
+ && Number(importTelemetry.importedMorphPrimitiveCount || 0) >= 1
1212
+ && Number(importTelemetry.boundMorphPrimitiveCount || 0) >= 1
1213
+ && Number(importTelemetry.morphTargetCount || 0) >= 2
1214
+ && Number(importTelemetry.nonZeroMorphWeightPrimitiveCount || 0) >= 1
1215
+ && importTelemetry.lastRuntimeReasonCode === 'scene_import_runtime_bound'
1216
+ && Number(resources.morphTrackedMeshCount || 0) >= 1
1217
+ && Number(resources.morphPendingUploadCount || 0) === 0
1218
+ && Number(submission.morphCandidateDrawCount || 0) >= 1
1219
+ && Number(submission.morphPreparedBindGroupCount || 0) >= 1
1220
+ && Number(submission.morphExecutedBindGroupCount || 0) >= 1
1221
+ && Number(submission.morphExecutedMeshCount || 0) >= 1
1222
+ && Number(submission.morphExecutedNonZeroWeightDrawCount || 0) >= 1
1223
+ && Number(submission.morphExecutedNonZeroWeightMeshCount || 0) >= 1
1224
+ && submission.morphLastReasonCode === 'live_non_zero_weights'
1225
+ && Number(render.submitted || 0) >= 1
1226
+ && (render.lastReasonCode === 'scene3d_render_submitted' || render.lastReasonCode === 'scene3d_render_noop');
1227
+ })()`,
1228
+ },
1229
+ ],
1230
+ source: `
1231
+ globalThis.__importedMorphRuntime = { importId: 0, scenePath: null };
1232
+ `,
1233
+ nativeFrames: 4,
1234
+ },
1235
+ {
1236
+ id: 'threejs-3d-vertical-slice-runtime',
1237
+ modes: ['native'],
1238
+ namespaces: ['draw3d', 'camera3d', 'debug', 'light', 'material', 'mesh', 'scene3d'],
1239
+ functions: [
1240
+ 'aura.draw3d.clear3d',
1241
+ 'aura.draw3d.drawMesh',
1242
+ 'aura.draw3d.setPostFXPass',
1243
+ 'aura.draw3d.setPostFXEnabled',
1244
+ 'aura.draw3d.removePostFXPass',
1245
+ 'aura.draw3d.getPostFXState',
1246
+ 'aura.camera3d.perspective',
1247
+ 'aura.camera3d.setPosition',
1248
+ 'aura.camera3d.setTarget',
1249
+ 'aura.camera3d.lookAt',
1250
+ 'aura.camera3d.getViewMatrix',
1251
+ 'aura.camera3d.getProjectionMatrix',
1252
+ 'aura.light.ambient',
1253
+ 'aura.light.configureDirectionalShadows',
1254
+ 'aura.light.configureShadow',
1255
+ 'aura.light.directional',
1256
+ 'aura.light.getShadowState',
1257
+ 'aura.light.getShadowStats',
1258
+ 'aura.light.point',
1259
+ 'aura.light.setShadowBudget',
1260
+ 'aura.light.spot',
1261
+ 'aura.light.update',
1262
+ 'aura.light.remove',
1263
+ 'aura.debug.enableInspector',
1264
+ 'aura.debug.inspectorStats',
1265
+ 'aura.material.create',
1266
+ 'aura.material.clone',
1267
+ 'aura.material.setColor',
1268
+ 'aura.material.setMetallicRoughness',
1269
+ 'aura.material.unload',
1270
+ 'aura.mesh.createBox',
1271
+ 'aura.mesh.unload',
1272
+ 'aura.scene3d.createNode',
1273
+ 'aura.scene3d.setParent',
1274
+ 'aura.scene3d.setLocalTransform',
1275
+ 'aura.scene3d.getWorldTransform',
1276
+ 'aura.scene3d.traverse',
1277
+ 'aura.scene3d.removeNode',
1278
+ ],
1279
+ nativeChecks: [
1280
+ {
1281
+ id: 'light.shadow-runtime-control.surface.methods',
1282
+ expression: "(() => ['configureDirectionalShadows','configureShadow','getShadowState','getShadowStats'].every((name) => typeof aura.light?.[name] === 'function'))()",
1283
+ },
1284
+ {
1285
+ id: 'draw3d.postfx.surface.methods',
1286
+ expression: "(() => ['setPostFXPass','setPostFXEnabled','removePostFXPass','getPostFXState'].every((name) => typeof aura.draw3d?.[name] === 'function'))()",
1287
+ },
1288
+ {
1289
+ id: 'light.shadow-runtime-control.roundtrip.native',
1290
+ expression: "(() => { const approx = (value, expected) => Math.abs(Number(value) - expected) <= 1e-6; aura.debug.enableInspector(true); const sun = aura.light.directional({ x: -0.6, y: -1.0, z: -0.2 }, { r: 1, g: 0.95, b: 0.9, a: 1 }, 1.2); const point = aura.light.point({ x: 2, y: 3, z: 1 }, { r: 0.2, g: 0.4, b: 1, a: 1 }, 1.0, 14); const spot = aura.light.spot({ x: -1, y: 4, z: 2 }, { x: 0, y: -1, z: 0 }, { r: 1, g: 0.8, b: 0.6, a: 1 }, 1.1, 20, 0.8); aura.light.setShadowBudget(4); aura.light.configureDirectionalShadows({ enabled: true, quality: 'high', bias: 1, normalBias: 9, filterMode: 'soft', filterRadius: 99, cascadeCount: 99, tileResolution: 999999, lambda: -1, blendWidth: -4, shadowFar: 5, stabilizeCascades: true }); aura.light.configureShadow(point, { enabled: true, quality: 'low', bias: 1, normalBias: 5, filterMode: 'hard', filterRadius: -2 }); aura.light.configureShadow(spot, { enabled: true, quality: 'medium', bias: 0.015, normalBias: 0.04, filterMode: 'pcf', filterRadius: 1.5 }); const directional = aura.light.getShadowState(); const pointState = aura.light.getShadowState(point); const spotState = aura.light.getShadowState(spot); const stats = aura.light.getShadowStats(); const inspector = aura.debug.inspectorStats(); aura.debug.enableInspector(false); aura.light.remove(spot); aura.light.remove(point); aura.light.remove(sun); return directional.directional.enabled === true && directional.directional.quality === 'high' && approx(directional.directional.bias, 0.05) && approx(directional.directional.normalBias, 0.1) && directional.directional.filterMode === 'pcf' && approx(directional.directional.filterRadius, 4.0) && directional.directional.cascadeCount === 4 && directional.directional.tileResolution === 4096 && directional.directional.lambda === 0 && directional.directional.blendWidth === 0 && directional.directional.shadowFar === 10 && directional.directional.stabilizeCascades === true && pointState.type === 'point' && pointState.enabled === true && pointState.quality === 'low' && approx(pointState.bias, 0.05) && approx(pointState.normalBias, 0.1) && pointState.filterMode === 'hard' && approx(pointState.filterRadius, 0.0) && spotState.type === 'spot' && approx(spotState.normalBias, 0.04) && spotState.filterMode === 'pcf' && approx(spotState.filterRadius, 1.5) && stats.shadowCastingCount === 3 && stats.shadowBudget === 4 && stats.budgetSaturated === false && stats.directionalShadowEnabled === true && approx(stats.directionalNormalBias, 0.1) && stats.directionalFilterMode === 'pcf' && approx(stats.directionalFilterRadius, 4.0) && stats.directionalCascadeCount === 4 && stats.directionalStabilizeCascades === true && stats.shadowedPointLightCount === 1 && stats.shadowedSpotLightCount === 1 && inspector?.scene3dRuntime?.shadow?.shadowCastingCount === 3 && inspector?.scene3dRuntime?.shadow?.directionalCascadeCount === 4 && approx(inspector?.scene3dRuntime?.shadow?.directionalNormalBias, 0.1) && inspector?.scene3dRuntime?.shadow?.directionalFilterMode === 'pcf' && approx(inspector?.scene3dRuntime?.shadow?.directionalFilterRadius, 4.0) && inspector?.scene3dRuntime?.shadow?.directionalStabilizeCascades === true; })()",
1291
+ },
1292
+ {
1293
+ id: 'threejs.vertical-slice.scene-runtime.deterministic',
1294
+ expression: "(() => { const runSample = () => { const root = aura.scene3d.createNode({ position: { x: 1, y: 0, z: 0 } }); const orbit = aura.scene3d.createNode({ position: { x: 0, y: 1, z: 0 }, rotation: { x: 0, y: 0.5, z: 0 } }); const meshNode = aura.scene3d.createNode({ position: { x: 2, y: 0, z: -1 }, scale: { x: 1.5, y: 1.5, z: 1.5 } }); const parentOrbit = aura.scene3d.setParent(orbit, root); const parentMesh = aura.scene3d.setParent(meshNode, orbit); aura.scene3d.setLocalTransform(root, { position: { x: 1.25, y: 0, z: -0.5 } }); const world = aura.scene3d.getWorldTransform(meshNode); const traversal = []; aura.scene3d.traverse(root, (_id, worldTransform) => traversal.push([ Number(worldTransform.position.x.toFixed(3)), Number(worldTransform.position.y.toFixed(3)), Number(worldTransform.position.z.toFixed(3)) ])); aura.camera3d.perspective(60, 0.1, 200); aura.camera3d.setPosition(4, 3, 6); aura.camera3d.setTarget(world.position.x, world.position.y, world.position.z); aura.camera3d.lookAt(world.position.x, world.position.y, world.position.z); const ambient = aura.light.ambient({ r: 0.15, g: 0.15, b: 0.2, a: 1 }, 0.4); const sun = aura.light.directional({ x: -0.7, y: -1, z: -0.2 }, { r: 1, g: 0.95, b: 0.9, a: 1 }, 1.2); const rim = aura.light.point({ x: 3, y: 2, z: 1 }, { r: 0.25, g: 0.45, b: 1, a: 1 }, 2.0, 20); aura.light.update(rim, { position: { x: 2.5, y: 2, z: -0.5 }, intensity: 1.5, range: 18 }); const mesh = aura.mesh.createBox(1, 1, 1); const base = aura.material.create({ color: { r: 0.4, g: 0.6, b: 0.85, a: 1 }, metallic: 0.15, roughness: 0.65 }); const accent = aura.material.clone(base); aura.material.setMetallicRoughness(accent, 0.85, 0.2); aura.material.setColor(accent, { r: 0.95, g: 0.45, b: 0.3, a: 1 }); aura.draw3d.clear3d({ r: 0.04, g: 0.05, b: 0.08, a: 1 }); aura.draw3d.drawMesh(mesh, base, world); aura.draw3d.drawMesh(mesh, accent, { position: { x: world.position.x + 1.2, y: world.position.y, z: world.position.z }, rotation: world.rotation, scale: world.scale }); const view = aura.camera3d.getViewMatrix(); const projection = aura.camera3d.getProjectionMatrix(); const summary = { parentOrbit, parentMesh, world: [ Number(world.position.x.toFixed(3)), Number(world.position.y.toFixed(3)), Number(world.position.z.toFixed(3)) ], traversal, handlesAreNumeric: [ambient, sun, rim, mesh, base, accent].every((handle) => typeof handle === 'number' && Number.isFinite(handle) && handle >= 0), cloneDistinct: accent !== base, matricesFinite: Array.isArray(view) && view.length === 16 && view.every((value) => Number.isFinite(value)) && Array.isArray(projection) && projection.length === 16 && projection.every((value) => Number.isFinite(value)), viewLead: Number(view[0].toFixed(6)), projectionLead: Number(projection[5].toFixed(6)) }; aura.material.unload(accent); aura.material.unload(base); aura.mesh.unload(mesh); aura.light.remove(sun); aura.light.remove(rim); aura.scene3d.removeNode(meshNode); aura.scene3d.removeNode(orbit); aura.scene3d.removeNode(root); return summary; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.parentOrbit === true && first.parentMesh === true && first.cloneDistinct === true && first.handlesAreNumeric === true && first.matricesFinite === true && first.world[0] === 3.25 && first.world[1] === 1 && first.world[2] === -1.5 && first.traversal.length === 3; })()",
1295
+ },
1296
+ {
1297
+ id: 'draw3d.postfx.chain-mutation.deterministic',
1298
+ expression: "(() => { const runSample = () => { const baseline = aura.draw3d.getPostFXState(); aura.draw3d.removePostFXPass('bloom'); aura.draw3d.removePostFXPass('colorGrade'); aura.draw3d.removePostFXPass('vignette'); aura.draw3d.removePostFXPass('fxaa'); const setBloom = aura.draw3d.setPostFXPass('bloom', { strength: 1.25, radius: 0.6, threshold: 0.7 }); const setFxaa = aura.draw3d.setPostFXPass('fxaa', { enabled: true, strength: 1.0 }); const setColorGrade = aura.draw3d.setPostFXPass('colorGrade', { strength: 0.8 }); const disableBloom = aura.draw3d.setPostFXEnabled('bloom', false); const enableBloom = aura.draw3d.setPostFXEnabled('bloom', true); const removeFxaa = aura.draw3d.removePostFXPass('fxaa'); const setVignette = aura.draw3d.setPostFXPass('vignette', { strength: 0.4, radius: 0.9 }); const state = aura.draw3d.getPostFXState(); return { status: [setBloom?.reasonCode, setFxaa?.reasonCode, setColorGrade?.reasonCode, disableBloom?.reasonCode, enableBloom?.reasonCode, removeFxaa?.reasonCode, setVignette?.reasonCode].join('|'), order: Array.isArray(state?.passes) ? state.passes.map((pass) => pass.pass).join('|') : '', enabled: state?.enabledPasses, total: state?.totalPasses, fingerprint: state?.orderFingerprint, mutationDelta: Number(state?.mutationCount || 0) - Number(baseline?.mutationCount || 0), lastReasonCode: state?.lastReasonCode, lastOk: state?.lastOk }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.status === 'postfx_ok|postfx_ok|postfx_ok|postfx_ok|postfx_ok|postfx_ok|postfx_ok' && first.order === 'colorGrade|bloom|vignette' && first.total === 3 && first.enabled === 3 && Number.isFinite(first.fingerprint) && first.fingerprint > 0 && first.mutationDelta === 11 && first.lastReasonCode === 'postfx_ok' && first.lastOk === true; })()",
1299
+ },
1300
+ {
1301
+ id: 'threejs.vertical-slice.camera-hierarchy-churn.deterministic',
1302
+ expression: "(() => { const runSample = () => { const root = aura.scene3d.createNode({ position: { x: 0, y: 0, z: 0 } }); const pivot = aura.scene3d.createNode({ position: { x: 1, y: 0, z: 0 } }); const targetNode = aura.scene3d.createNode({ position: { x: 0, y: 0, z: -2 } }); const linkedPivot = aura.scene3d.setParent(pivot, root); const linkedTarget = aura.scene3d.setParent(targetNode, pivot); const trace = []; for (let step = 0; step < 4; step += 1) { aura.scene3d.setLocalTransform(root, { position: { x: step * 0.25, y: 0, z: -step * 0.1 } }); aura.scene3d.setLocalTransform(pivot, { position: { x: 1 + step * 0.5, y: step * 0.25, z: 0 } }); const world = aura.scene3d.getWorldTransform(targetNode); aura.camera3d.perspective(55 + (step * 5), 0.1, 300); aura.camera3d.setPosition(6 - step, 3 + (step * 0.5), 8 - (step * 0.4)); aura.camera3d.lookAt(world.position.x, world.position.y, world.position.z); const view = aura.camera3d.getViewMatrix(); const projection = aura.camera3d.getProjectionMatrix(); trace.push({ target: [Number(world.position.x.toFixed(3)), Number(world.position.y.toFixed(3)), Number(world.position.z.toFixed(3))], viewLead: Number(view[0].toFixed(6)), projectionLead: Number(projection[5].toFixed(6)) }); } aura.scene3d.removeNode(targetNode); aura.scene3d.removeNode(pivot); aura.scene3d.removeNode(root); return { linkedPivot, linkedTarget, trace }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.linkedPivot === true && first.linkedTarget === true && first.trace.length === 4 && first.trace.every((entry) => Number.isFinite(entry.viewLead) && Number.isFinite(entry.projectionLead)); })()",
1303
+ },
1304
+ {
1305
+ id: 'threejs.vertical-slice.light-mutation.hierarchy-churn.deterministic',
1306
+ expression: "(() => { const runSample = () => { const root = aura.scene3d.createNode({ position: { x: 0, y: 0, z: 0 } }); const orbit = aura.scene3d.createNode({ position: { x: 1, y: 0, z: 0 } }); const meshNode = aura.scene3d.createNode({ position: { x: 0, y: 0, z: -2 } }); aura.scene3d.setParent(orbit, root); aura.scene3d.setParent(meshNode, orbit); const ambient = aura.light.ambient({ r: 0.1, g: 0.1, b: 0.15, a: 1 }, 0.35); const sun = aura.light.directional({ x: -0.8, y: -1, z: -0.2 }, { r: 1, g: 0.95, b: 0.9, a: 1 }, 1.1); const rim = aura.light.point({ x: 2, y: 2, z: 0 }, { r: 0.2, g: 0.35, b: 1, a: 1 }, 1.4, 18); const mesh = aura.mesh.createBox(1, 1, 1); const material = aura.material.create({ color: { r: 0.45, g: 0.6, b: 0.8, a: 1 }, metallic: 0.2, roughness: 0.6 }); const positions = []; for (let step = 0; step < 3; step += 1) { aura.scene3d.setLocalTransform(root, { position: { x: step * 0.3, y: 0, z: -step * 0.2 } }); aura.scene3d.setLocalTransform(orbit, { position: { x: 1 + (step * 0.4), y: step * 0.2, z: 0 } }); const world = aura.scene3d.getWorldTransform(meshNode); aura.light.update(sun, { direction: { x: -0.8 + (step * 0.1), y: -1, z: -0.2 } }); aura.light.update(rim, { position: { x: world.position.x + 0.75, y: world.position.y + 1.25, z: world.position.z + 0.5 }, intensity: 1.4 + (step * 0.2), range: 18 - step }); aura.draw3d.drawMesh(mesh, material, world); positions.push([Number(world.position.x.toFixed(3)), Number(world.position.y.toFixed(3)), Number(world.position.z.toFixed(3))]); } aura.light.remove(rim); const rimReplacement = aura.light.point({ x: -1, y: 1, z: -1 }, { r: 0.4, g: 0.5, b: 1, a: 1 }, 1.0, 12); aura.light.update(rimReplacement, { intensity: 1.1, range: 10 }); const summary = { handlesNumeric: [ambient, sun, rim, rimReplacement].every((handle) => typeof handle === 'number' && Number.isFinite(handle) && handle >= 0), rimReplaced: rimReplacement !== rim, rimReplacementAdvanced: rimReplacement > rim, positions }; aura.material.unload(material); aura.mesh.unload(mesh); aura.light.remove(rimReplacement); aura.light.remove(sun); aura.scene3d.removeNode(meshNode); aura.scene3d.removeNode(orbit); aura.scene3d.removeNode(root); return summary; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.rimReplaced === true && first.rimReplacementAdvanced === true && first.positions.length === 3 && first.handlesNumeric === true; })()",
1307
+ },
1308
+ {
1309
+ id: 'threejs.vertical-slice.material-mutation.hierarchy-churn.deterministic',
1310
+ expression: "(() => { const runSample = () => { const root = aura.scene3d.createNode({ position: { x: 0, y: 0, z: 0 } }); const pivot = aura.scene3d.createNode({ position: { x: 0.5, y: 0.25, z: 0 } }); const meshNode = aura.scene3d.createNode({ position: { x: 1.5, y: 0, z: -1.5 }, scale: { x: 1.2, y: 1.2, z: 1.2 } }); aura.scene3d.setParent(pivot, root); aura.scene3d.setParent(meshNode, pivot); const mesh = aura.mesh.createBox(1, 1, 1); const base = aura.material.create({ color: { r: 0.35, g: 0.55, b: 0.85, a: 1 }, metallic: 0.1, roughness: 0.75 }); const accent = aura.material.clone(base); const trail = aura.material.clone(base); const trace = []; for (let step = 0; step < 4; step += 1) { aura.scene3d.setLocalTransform(pivot, { position: { x: 0.5 + (step * 0.2), y: 0.25 + (step * 0.1), z: -step * 0.15 }, rotation: { x: 0, y: step * 0.25, z: 0 } }); const world = aura.scene3d.getWorldTransform(meshNode); const metallic = Number((0.2 + (step * 0.2)).toFixed(3)); const roughness = Number((0.8 - (step * 0.15)).toFixed(3)); aura.material.setMetallicRoughness(accent, metallic, roughness); aura.material.setColor(trail, { r: 0.3 + (step * 0.1), g: 0.45, b: 0.9 - (step * 0.1), a: 1 }); aura.draw3d.drawMesh(mesh, base, world); aura.draw3d.drawMesh(mesh, accent, { position: { x: world.position.x + 0.6, y: world.position.y, z: world.position.z }, rotation: world.rotation, scale: world.scale }); aura.draw3d.drawMesh(mesh, trail, { position: { x: world.position.x - 0.6, y: world.position.y, z: world.position.z }, rotation: world.rotation, scale: world.scale }); trace.push([Number(world.position.x.toFixed(3)), Number(world.rotation.y.toFixed(3)), Number(world.scale.x.toFixed(3)), metallic, roughness]); } const summary = { handlesNumeric: [base, accent, trail].every((handle) => typeof handle === 'number' && Number.isFinite(handle) && handle > 0), distinctHandles: base !== accent && base !== trail && accent !== trail, cloneOrderPreserved: accent > base && trail > accent, trace }; aura.material.unload(trail); aura.material.unload(accent); aura.material.unload(base); aura.mesh.unload(mesh); aura.scene3d.removeNode(meshNode); aura.scene3d.removeNode(pivot); aura.scene3d.removeNode(root); return summary; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.distinctHandles === true && first.cloneOrderPreserved === true && first.trace.length === 4 && first.handlesNumeric === true; })()",
1311
+ },
1312
+ {
1313
+ id: 'draw3d.postfx.reason-codes.stable',
1314
+ expression: "(() => { const reasonOf = (entry) => (entry && entry.reasonCode) || null; const collect = () => { aura.draw3d.removePostFXPass('bloom'); aura.draw3d.removePostFXPass('custom:glow'); const invalidPassEmpty = aura.draw3d.setPostFXPass('', {}); const invalidPassType = aura.draw3d.setPostFXPass(42, {}); const configuredSsao = aura.draw3d.setPostFXPass('ssao', { radius: 0.6, intensity: 0.8 }); const removeSsao = aura.draw3d.removePostFXPass('ssao'); const invalidOptions = aura.draw3d.setPostFXPass('bloom', 'bad'); const invalidTargetChain = aura.draw3d.setPostFXPass('bloom', { targetChain: 'bad' }); const invalidIntermediateTargetType = aura.draw3d.setPostFXPass('bloom', { targetChain: { intermediateTargets: 'bad' } }); const invalidIntermediateTargetEntry = aura.draw3d.setPostFXPass('bloom', { targetChain: { intermediateTargets: ['ok', 'bad!'] } }); const invalidComposeMode = aura.draw3d.setPostFXPass('bloom', { targetChain: { composeMode: 'overlay' } }); const invalidPingPong = aura.draw3d.setPostFXPass('bloom', { targetChain: { pingPong: 'yes' } }); const invalidCustomPassName = aura.draw3d.setPostFXPass('custom:bad name', {}); const invalidCustomParams = aura.draw3d.setPostFXPass('custom:glow', { customParams: { intensity: 'high' } }); const unsupportedCustomParams = aura.draw3d.setPostFXPass('bloom', { customParams: { intensity: 1 } }); const configured = aura.draw3d.setPostFXPass('custom:glow', { customParams: { intensity: 0.25 } }); const invalidEnabled = aura.draw3d.setPostFXEnabled('custom:glow', 'yes'); const removeConfigured = aura.draw3d.removePostFXPass('custom:glow'); const missingToggle = aura.draw3d.setPostFXEnabled('custom:glow', true); const missingRemove = aura.draw3d.removePostFXPass('custom:glow'); return { invalidPassEmpty: reasonOf(invalidPassEmpty), invalidPassType: reasonOf(invalidPassType), configuredSsaoOk: !!configuredSsao && configuredSsao.ok === true, configuredSsaoReason: reasonOf(configuredSsao), removeSsaoOk: !!removeSsao && removeSsao.ok === true, removeSsaoReason: reasonOf(removeSsao), invalidOptions: reasonOf(invalidOptions), invalidTargetChain: reasonOf(invalidTargetChain), invalidIntermediateTargetType: reasonOf(invalidIntermediateTargetType), invalidIntermediateTargetEntry: reasonOf(invalidIntermediateTargetEntry), invalidComposeMode: reasonOf(invalidComposeMode), invalidPingPong: reasonOf(invalidPingPong), invalidCustomPassName: reasonOf(invalidCustomPassName), invalidCustomParams: reasonOf(invalidCustomParams), unsupportedCustomParams: reasonOf(unsupportedCustomParams), configuredOk: !!configured && configured.ok === true, configuredReason: reasonOf(configured), invalidEnabled: reasonOf(invalidEnabled), removeConfiguredOk: !!removeConfigured && removeConfigured.ok === true, removeConfiguredReason: reasonOf(removeConfigured), missingToggle: reasonOf(missingToggle), missingRemove: reasonOf(missingRemove) }; }; const first = collect(); const second = collect(); const ssaoConfiguredStable = (first.configuredSsaoOk === true && first.configuredSsaoReason === 'postfx_ok') || (first.configuredSsaoOk === false && first.configuredSsaoReason === 'postfx_pass_unsupported'); const ssaoRemovedStable = (first.removeSsaoOk === true && first.removeSsaoReason === 'postfx_ok') || (first.removeSsaoOk === false && first.removeSsaoReason === 'postfx_pass_unsupported'); return JSON.stringify(first) === JSON.stringify(second) && first.invalidPassEmpty === 'postfx_invalid_pass_name' && first.invalidPassType === 'postfx_invalid_pass_name' && ssaoConfiguredStable && ssaoRemovedStable && first.invalidOptions === 'postfx_invalid_options' && first.invalidTargetChain === 'postfx_invalid_target_chain' && first.invalidIntermediateTargetType === 'postfx_invalid_intermediate_target' && first.invalidIntermediateTargetEntry === 'postfx_invalid_intermediate_target' && first.invalidComposeMode === 'postfx_invalid_compose_mode' && first.invalidPingPong === 'postfx_invalid_ping_pong' && first.invalidCustomPassName === 'postfx_invalid_custom_pass_name' && first.invalidCustomParams === 'postfx_invalid_custom_params' && first.unsupportedCustomParams === 'postfx_custom_param_unsupported' && first.configuredOk === true && first.configuredReason === 'postfx_ok' && first.invalidEnabled === 'postfx_invalid_enabled' && first.removeConfiguredOk === true && first.removeConfiguredReason === 'postfx_ok' && first.missingToggle === 'postfx_pass_missing' && first.missingRemove === 'postfx_pass_missing'; })()",
1315
+ },
1316
+ {
1317
+ id: 'light.shadow-runtime-control.runtime.probe.setup.native',
1318
+ expression: "(() => { try { const mesh = aura.mesh.createBox(1, 1, 1); const material = aura.material.create({ color: { r: 0.65, g: 0.75, b: 0.9, a: 1 }, metallic: 0.1, roughness: 0.7 }); const sun = aura.light.directional({ x: -0.6, y: -1.0, z: -0.2 }, { r: 1, g: 0.95, b: 0.9, a: 1 }, 1.2); const point = aura.light.point({ x: 2, y: 3, z: 1 }, { r: 0.2, g: 0.4, b: 1, a: 1 }, 1.0, 14); const spot = aura.light.spot({ x: -1, y: 4, z: 2 }, { x: 0, y: -1, z: 0 }, { r: 1, g: 0.8, b: 0.6, a: 1 }, 1.1, 20, 0.8); const shadowConfig = { enabled: true, quality: 'high', bias: 1, normalBias: 9, filterMode: 'soft', filterRadius: 99, cascadeCount: 99, tileResolution: 999999, lambda: -1, blendWidth: -4, shadowFar: 5, stabilizeCascades: true }; const applyShadowConfig = (stabilizeCascades) => aura.light.configureDirectionalShadows({ ...shadowConfig, stabilizeCascades }); const sweep = [ { label: 'raw-base', stabilize: false, cameraX: 4.0 }, { label: 'raw-shift-a', stabilize: false, cameraX: 4.01 }, { label: 'raw-shift-b', stabilize: false, cameraX: 4.02 }, { label: 'stable-base', stabilize: true, cameraX: 4.0 }, { label: 'stable-shift-a', stabilize: true, cameraX: 4.01 }, { label: 'stable-shift-b', stabilize: true, cameraX: 4.02 } ]; aura.light.setShadowBudget(4); applyShadowConfig(true); aura.light.configureShadow(point, { enabled: true, quality: 'low', bias: 0.01, normalBias: 0.08, filterMode: 'hard', filterRadius: -1 }); aura.light.configureShadow(spot, { enabled: true, quality: 'medium', bias: 0.015, normalBias: 0.04, filterMode: 'pcf', filterRadius: 1.5 }); aura.camera3d.perspective(60, 0.1, 100); aura.camera3d.setPosition(4, 3, 6); aura.camera3d.lookAt(0, 0.5, 0); const baseDraw = aura.draw; aura.draw = function () { const probe = globalThis.__shadowRuntimeProbe; if (probe && probe.pendingSample) { aura.debug.enableInspector(true); const inspector = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); const shadow = inspector?.scene3dRuntime?.shadow || {}; const stats = aura.light.getShadowStats(); probe.trace.push({ label: probe.pendingSample.label, stabilize: probe.pendingSample.stabilize, cameraX: probe.pendingSample.cameraX, statsSnapError: Number(stats?.directionalTexelSnapErrorMax || 0), inspectorSnapError: Number(shadow?.directionalTexelSnapErrorMax || 0), directionalPassCount: Number(stats?.directionalPassCount || 0), cascadeCount: Number(stats?.directionalCascadeCount || 0) }); } const sample = sweep[Math.min(globalThis.__shadowRuntimeProbe.sampleIndex, sweep.length - 1)]; applyShadowConfig(sample.stabilize); aura.camera3d.perspective(60, 0.1, 100); aura.camera3d.setPosition(sample.cameraX, 3, 6); aura.camera3d.lookAt(0, 0.5, 0); globalThis.__shadowRuntimeProbe.pendingSample = sample; globalThis.__shadowRuntimeProbe.sampleIndex += 1; aura.draw3d.clear3d({ r: 0.03, g: 0.04, b: 0.06, a: 1 }); aura.draw3d.drawMesh(mesh, material, { position: { x: 0, y: 0.5, z: 0 }, scale: { x: 1.5, y: 1.5, z: 1.5 } }); baseDraw(); }; globalThis.__shadowRuntimeProbe = { mesh, material, sun, point, spot, trace: [], pendingSample: null, sampleIndex: 0 }; return Number.isInteger(mesh) && mesh > 0 && Number.isInteger(material) && material > 0 && Number.isInteger(sun) && sun > 0 && Number.isInteger(point) && point > 0 && Number.isInteger(spot) && spot > 0; } catch (_) { return false; } })()",
1319
+ },
1320
+ ],
1321
+ nativePostChecks: [
1322
+ {
1323
+ id: 'light.shadow-runtime-control.runtime.probe.evidence.native',
1324
+ expression: "(() => { try { const approx = (value, expected) => Math.abs(Number(value) - expected) <= 1e-6; const state = globalThis.__shadowRuntimeProbe || {}; aura.debug.enableInspector(true); const inspector = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); const stats = aura.light.getShadowStats(); const rootState = aura.light.getShadowState(); const sunState = aura.light.getShadowState(state.sun); const pointState = aura.light.getShadowState(state.point); const spotState = aura.light.getShadowState(state.spot); const shadow = inspector?.scene3dRuntime?.shadow || {}; return Number.isInteger(state.sun) && state.sun > 0 && Number.isInteger(state.point) && state.point > 0 && Number.isInteger(state.spot) && state.spot > 0 && stats.shadowCastingCount === 3 && stats.shadowBudget === 4 && stats.directionalShadowEnabled === true && approx(stats.directionalNormalBias, 0.1) && stats.directionalFilterMode === 'pcf' && approx(stats.directionalFilterRadius, 4.0) && stats.directionalCascadeCount === 4 && approx(stats.directionalTexelSnapErrorMax, 0.0) && stats.directionalStabilizeCascades === true && stats.shadowedPointLightCount === 1 && stats.shadowedSpotLightCount === 1 && stats.rendererActive === true && stats.directionalPassCount === 4 && stats.multiLightSlotCount === 2 && stats.multiLightPassCount === 2 && stats.effectiveShadowCastingCount === 3 && stats.effectivePointLightCount === 1 && stats.effectiveSpotLightCount === 1 && stats.shadowDrawCount === 1 && rootState.rendererActive === true && rootState.effectiveShadowCastingCount === 3 && rootState.directional?.enabled === true && approx(rootState.directional?.normalBias, 0.1) && rootState.directional?.filterMode === 'pcf' && approx(rootState.directional?.filterRadius, 4.0) && rootState.directional?.stabilizeCascades === true && rootState.directional?.cascadeCount === 4 && sunState.type === 'directional' && approx(sunState.normalBias, 0.1) && sunState.filterMode === 'pcf' && approx(sunState.filterRadius, 4.0) && sunState.stabilizeCascades === true && sunState.effectiveEnabled === true && sunState.effectiveQuality === 'high' && approx(sunState.effectiveBias, 0.05) && sunState.effectiveSlotCount === 4 && pointState.type === 'point' && pointState.enabled === true && approx(pointState.normalBias, 0.08) && pointState.filterMode === 'hard' && approx(pointState.filterRadius, 0.0) && pointState.effectiveEnabled === true && pointState.effectiveQuality === 'low' && approx(pointState.effectiveBias, 0.01) && pointState.effectiveSlotCount === 1 && spotState.type === 'spot' && spotState.enabled === true && approx(spotState.normalBias, 0.04) && spotState.filterMode === 'pcf' && approx(spotState.filterRadius, 1.5) && spotState.effectiveEnabled === true && spotState.effectiveQuality === 'medium' && approx(spotState.effectiveBias, 0.015) && spotState.effectiveSlotCount === 1 && shadow.rendererActive === true && approx(shadow.directionalNormalBias, 0.1) && shadow.directionalFilterMode === 'pcf' && approx(shadow.directionalFilterRadius, 4.0) && approx(shadow.directionalTexelSnapErrorMax, 0.0) && shadow.directionalStabilizeCascades === true && shadow.directionalPassCount === 4 && shadow.multiLightSlotCount === 2 && shadow.multiLightPassCount === 2 && shadow.shadowDrawCount === 1 && shadow.directionalPassCount === stats.directionalPassCount && shadow.multiLightSlotCount === stats.multiLightSlotCount && shadow.multiLightPassCount === stats.multiLightPassCount && shadow.shadowDrawCount === stats.shadowDrawCount; } catch (_) { return false; } })()",
1325
+ debugExpression: "(() => { try { const state = globalThis.__shadowRuntimeProbe || {}; aura.debug.enableInspector(true); const inspector = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); return { state, stats: aura.light.getShadowStats(), rootState: aura.light.getShadowState(), sunState: aura.light.getShadowState(state.sun), pointState: aura.light.getShadowState(state.point), spotState: aura.light.getShadowState(state.spot), shadow: inspector?.scene3dRuntime?.shadow || null }; } catch (error) { return { debugError: String(error && error.message ? error.message : error) }; } })()",
1326
+ },
1327
+ {
1328
+ id: 'light.shadow-runtime-control.runtime.probe.camera-sweep.native',
1329
+ expression: "(() => { try { const state = globalThis.__shadowRuntimeProbe || {}; const trace = Array.isArray(state.trace) ? state.trace : []; const raw = trace.filter((entry) => entry && entry.stabilize === false); const stabilized = trace.filter((entry) => entry && entry.stabilize === true); const movedRawCamera = raw.length === 3 && raw[0].cameraX !== raw[1].cameraX && raw[1].cameraX !== raw[2].cameraX; const movedStableCamera = stabilized.length === 3 && stabilized[0].cameraX !== stabilized[1].cameraX && stabilized[1].cameraX !== stabilized[2].cameraX; const rawShowsJitter = raw.some((entry) => Number(entry.statsSnapError) > 1e-3 && Number(entry.inspectorSnapError) > 1e-3); const stabilizedQuantized = stabilized.every((entry) => Number(entry.statsSnapError) <= 1e-4 && Number(entry.inspectorSnapError) <= 1e-4); const passCountsStable = trace.every((entry) => Number(entry.directionalPassCount) === 4 && Number(entry.cascadeCount) === 4); return trace.length === 6 && movedRawCamera && movedStableCamera && rawShowsJitter && stabilizedQuantized && passCountsStable; } catch (_) { return false; } })()",
1330
+ debugExpression: "(() => { try { return { state: globalThis.__shadowRuntimeProbe || null }; } catch (error) { return { debugError: String(error && error.message ? error.message : error) }; } })()",
1331
+ },
1332
+ ],
1333
+ source: `
1334
+ globalThis.__shadowRuntimeProbe = {
1335
+ mesh: 0,
1336
+ material: 0,
1337
+ sun: 0,
1338
+ point: 0,
1339
+ spot: 0,
1340
+ trace: [],
1341
+ pendingSample: null,
1342
+ sampleIndex: 0,
1343
+ };
1344
+ `,
1345
+ nativeFrames: 7,
1346
+ },
1347
+ {
1348
+ id: 'threejs-controls-raycast-interaction',
1349
+ modes: ['native'],
1350
+ namespaces: ['camera3d', 'scene3d'],
1351
+ functions: [
1352
+ 'aura.camera3d.setControlProfile',
1353
+ 'aura.camera3d.updateControls',
1354
+ 'aura.camera3d.getControlState',
1355
+ 'aura.scene3d.queryRaycast',
1356
+ ],
1357
+ nativeChecks: [
1358
+ {
1359
+ id: 'threejs.controls.surface.methods',
1360
+ expression: "(() => ['setControlProfile','updateControls','getControlState'].every((name) => typeof aura.camera3d?.[name] === 'function'))()",
1361
+ },
1362
+ {
1363
+ id: 'threejs.raycast.surface.method',
1364
+ expression: "typeof aura.scene3d?.queryRaycast === 'function'",
1365
+ },
1366
+ {
1367
+ id: 'threejs.controls.raycast.deterministic',
1368
+ expression: "(() => { const root = aura.scene3d.createNode({ position: { x: 0, y: 0, z: -3 }, scale: { x: 1.5, y: 1.5, z: 1.5 } }); const near = aura.scene3d.createNode({ position: { x: 0, y: 0, z: -1.5 }, scale: { x: 0.8, y: 0.8, z: 0.8 } }); const far = aura.scene3d.createNode({ position: { x: 0, y: 0, z: -5 }, scale: { x: 2, y: 2, z: 2 } }); aura.scene3d.setParent(near, root); const profile = aura.camera3d.setControlProfile('orbit', { target: { x: 0, y: 0, z: -3 }, distance: 6, damping: 0.15, minDistance: 2, maxDistance: 12 }); const stepA = aura.camera3d.updateControls(1 / 60, { rotateX: 0.2, rotateY: -0.1, panX: 0.05, panY: 0.02, zoom: -0.15 }); const stepB = aura.camera3d.updateControls(1 / 60, { rotateX: 0.2, rotateY: -0.1, panX: 0.05, panY: 0.02, zoom: -0.15 }); const state = aura.camera3d.getControlState(); const cast = aura.scene3d.queryRaycast({ origin: { x: 0, y: 0, z: 0 }, direction: { x: 0, y: 0, z: -1 }, maxDistance: 32 }); const castAgain = aura.scene3d.queryRaycast({ origin: { x: 0, y: 0, z: 0 }, direction: { x: 0, y: 0, z: -1 }, maxDistance: 32 }); aura.scene3d.removeNode(near); aura.scene3d.removeNode(far); aura.scene3d.removeNode(root); const order = Array.isArray(cast?.hits) ? cast.hits.map((entry) => `${entry.nodeId}:${Number(entry.toi).toFixed(6)}`).join('|') : ''; const orderAgain = Array.isArray(castAgain?.hits) ? castAgain.hits.map((entry) => `${entry.nodeId}:${Number(entry.toi).toFixed(6)}`).join('|') : ''; return profile === undefined && stepA === undefined && stepB === undefined && state?.profile === 'orbit' && state?.active === true && cast?.ok === true && cast?.hit === true && cast?.hitCount >= 2 && cast?.firstHit && Number.isFinite(cast.firstHit.toi) && order.length > 0 && order === orderAgain; })()",
1369
+ },
1370
+ {
1371
+ id: 'threejs.controls.raycast.reason-codes',
1372
+ expression: "(() => { const invalidProfile = aura.camera3d.setControlProfile('freecam'); const invalidControls = aura.camera3d.updateControls(-1, {}); const invalidRayA = aura.scene3d.queryRaycast(null); const invalidRayB = aura.scene3d.queryRaycast({ origin: { x: 0, y: 0, z: 0 }, direction: { x: 0, y: 0, z: 0 } }); return invalidProfile === undefined && invalidControls === undefined && invalidRayA && invalidRayA.ok === false && invalidRayA.reason === 'invalid_raycast_args' && invalidRayB && invalidRayB.ok === false && invalidRayB.reason === 'invalid_raycast_args'; })()",
1373
+ },
1374
+ ],
1375
+ source: `
1376
+ aura.setup = function () {};
1377
+ `,
1378
+ nativeFrames: 2,
1379
+ },
1380
+ {
1381
+ id: 'threejs-occlusion-skinned-runtime',
1382
+ modes: ['native'],
1383
+ namespaces: ['draw3d', 'camera3d', 'mesh', 'material', 'skinnedMesh', 'debug'],
1384
+ functions: [
1385
+ 'aura.draw3d.clear3d',
1386
+ 'aura.draw3d.drawMesh',
1387
+ 'aura.draw3d.setOcclusionCulling',
1388
+ 'aura.camera3d.perspective',
1389
+ 'aura.camera3d.setPosition',
1390
+ 'aura.camera3d.lookAt',
1391
+ 'aura.mesh.createBox',
1392
+ 'aura.material.create',
1393
+ 'aura.skinnedMesh.create',
1394
+ 'aura.skinnedMesh.addClip',
1395
+ 'aura.skinnedMesh.playAnimation',
1396
+ 'aura.skinnedMesh.getJointPosition',
1397
+ 'aura.debug.inspectorStats',
1398
+ ],
1399
+ nativeChecks: [
1400
+ {
1401
+ id: 'scene3d.occlusion-skinned.surface.methods',
1402
+ expression: "(() => ['clear3d','drawMesh','setOcclusionCulling'].every((name) => typeof aura.draw3d?.[name] === 'function') && ['perspective','setPosition','lookAt'].every((name) => typeof aura.camera3d?.[name] === 'function') && ['createBox'].every((name) => typeof aura.mesh?.[name] === 'function') && typeof aura.material?.create === 'function' && ['create','addClip','playAnimation','getJointPosition'].every((name) => typeof aura.skinnedMesh?.[name] === 'function'))()",
1403
+ },
1404
+ {
1405
+ id: 'scene3d.occlusion-skinned.runtime.setup',
1406
+ expression: "(() => { try { const wallMesh = aura.mesh.createBox(20, 20, 0.5); const boxMesh = aura.mesh.createBox(1, 1, 1); const wallMaterial = aura.material.create({ color: { r: 0.75, g: 0.75, b: 0.78, a: 1 }, metallic: 0.05, roughness: 0.95 }); const boxMaterial = aura.material.create({ color: { r: 0.35, g: 0.7, b: 0.95, a: 1 }, metallic: 0.15, roughness: 0.55 }); const skinnedId = aura.skinnedMesh.create(boxMesh, { jointCount: 1 }); const jointMatrix = (tx) => new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, tx, 0, 0, 1]); aura.skinnedMesh.addClip({ name: 'wag', duration: 1, loop: true, channels: [{ jointIndex: 0, keyframes: [{ time: 0, transform: jointMatrix(0) }, { time: 0.5, transform: jointMatrix(1) }, { time: 1, transform: jointMatrix(0) }] }] }); aura.skinnedMesh.playAnimation(skinnedId, 'wag', { speed: 12, loop: true }); aura.draw3d.setOcclusionCulling({ enabled: true, conservative: true }); aura.camera3d.perspective(60, 0.1, 100); aura.camera3d.setPosition(0, 0, 6); aura.camera3d.lookAt(0, 0, 0); const baseDraw = aura.draw; aura.draw = function () { aura.draw3d.clear3d({ r: 0.02, g: 0.02, b: 0.03, a: 1 }); aura.draw3d.drawMesh(wallMesh, wallMaterial, { position: { x: 0, y: 0, z: 3 }, scale: { x: 1, y: 1, z: 1 } }); aura.draw3d.drawMesh(boxMesh, boxMaterial, { position: { x: 0, y: 0, z: -8 }, scale: { x: 0.1, y: 0.1, z: 0.1 } }); baseDraw(); }; globalThis.__occlusionSkinned = { skinnedId }; return Number.isInteger(wallMesh) && wallMesh > 0 && Number.isInteger(boxMesh) && boxMesh > 0 && Number.isInteger(wallMaterial) && wallMaterial > 0 && Number.isInteger(boxMaterial) && boxMaterial > 0 && Number.isInteger(skinnedId) && skinnedId > 0; } catch (_) { return false; } })()",
1407
+ },
1408
+ ],
1409
+ nativePostChecks: [
1410
+ {
1411
+ id: 'scene3d.occlusion-skinned.runtime.evidence',
1412
+ expression: "(() => { try { const state = globalThis.__occlusionSkinned || {}; aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); const scene3d = stats.scene3dRuntime || {}; const submission = scene3d.submission || {}; const resources = scene3d.resources || {}; const animation = scene3d.animation || {}; const occlusion = scene3d.occlusion || {}; const joint = aura.skinnedMesh.getJointPosition(state.skinnedId, 0); const tested = Number(occlusion.tested || 0); const culled = Number(occlusion.culled || 0); const passed = Number(occlusion.passed || 0); const renderedGroups = Number(submission.skinnedRenderedGroups || 0); const fallbackGroups = Number(submission.skinnedGroupsUsingDefaultSkinningData || 0); const hasLastFrameOutcomes = occlusion.hasLastFrameOutcomes === true; const occlusionCountersConsistent = tested >= 1 && (culled + passed) === tested && culled >= 1 && passed >= 1; return Number.isFinite(joint?.x) && Math.abs(Number(joint.x)) > 0.05 && occlusion.enabled === true && occlusion.conservative === true && Number(occlusion.hizLevelCount || 0) >= 1 && Number(occlusion.viewportWidth || 0) >= 1 && Number(occlusion.viewportHeight || 0) >= 1 && hasLastFrameOutcomes && occlusionCountersConsistent && Number(resources.skinnedGroupCount || 0) >= 1 && Number(resources.skinnedAnimationClipCount || 0) >= 1 && Number(resources.skinnedAnimationPlaybackCount || 0) >= 1 && renderedGroups >= 1 && Number(submission.skinnedRenderedInstances || 0) >= 1 && Number(submission.skinnedUploadedJointMatrices || 0) >= 1 && fallbackGroups === renderedGroups && fallbackGroups >= 1 && Number(animation.skinnedTrackedMeshCount || 0) >= 1 && Number(animation.skinnedLastJointUpdateCount || 0) >= 1 && Number(animation.skinnedTotalJointUpdateCount || 0) >= Number(animation.skinnedLastJointUpdateCount || 0) && Number(animation.skinnedLastAdvancedPlaybackCount || 0) >= 1; } catch (_) { return false; } })()",
1413
+ debugExpression: "(() => { try { aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); return { state: globalThis.__occlusionSkinned || null, scene3dRuntime: stats.scene3dRuntime || null, joint: aura.skinnedMesh.getJointPosition(globalThis.__occlusionSkinned?.skinnedId || 0, 0) || null }; } catch (error) { return { debugError: String(error && error.message ? error.message : error) }; } })()",
1414
+ },
1415
+ ],
1416
+ source: `
1417
+ globalThis.__occlusionSkinned = { skinnedId: 0 };
1418
+ `,
1419
+ nativeFrames: 12,
1420
+ },
1421
+ {
1422
+ id: 'skinned-authored-input-runtime',
1423
+ modes: ['native'],
1424
+ namespaces: ['mesh', 'skinnedMesh', 'camera3d', 'draw3d', 'debug'],
1425
+ functions: [
1426
+ 'aura.mesh.createFromVertices',
1427
+ 'aura.skinnedMesh.create',
1428
+ 'aura.skinnedMesh.addClip',
1429
+ 'aura.skinnedMesh.playAnimation',
1430
+ 'aura.skinnedMesh.getJointPosition',
1431
+ 'aura.debug.inspectorStats',
1432
+ ],
1433
+ nativeChecks: [
1434
+ {
1435
+ id: 'skinned.authored-input.surface.methods',
1436
+ expression: "(() => typeof aura.mesh?.createFromVertices === 'function' && ['create','addClip','playAnimation','getJointPosition'].every((name) => typeof aura.skinnedMesh?.[name] === 'function') && ['perspective','setPosition','lookAt'].every((name) => typeof aura.camera3d?.[name] === 'function') && typeof aura.draw3d?.clear3d === 'function' && typeof aura.debug?.inspectorStats === 'function')()",
1437
+ },
1438
+ {
1439
+ id: 'skinned.authored-input.runtime.setup',
1440
+ expression: `(() => { try { const positions = new Float32Array([-1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0]); const indices = new Uint32Array([0, 1, 2, 0, 2, 3]); const normals = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]); const uvs = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]); const colors = new Float32Array([1, 0.22, 0.22, 1, 0.22, 1, 0.36, 1, 0.28, 0.56, 1, 1, 1, 0.9, 0.28, 1]); const jointIndices = new Uint32Array([0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]); const jointWeights = new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]); const coloredMesh = aura.mesh.createFromVertices(positions, indices, normals, uvs, colors, { jointIndices, jointWeights }); const legacyMesh = aura.mesh.createFromVertices(positions, indices, normals, uvs, { jointIndices, jointWeights }); const coloredSkinnedId = aura.skinnedMesh.create(coloredMesh, { jointCount: 2 }); const legacySkinnedId = aura.skinnedMesh.create(legacyMesh, { jointCount: 2 }); const jointMatrix = (tx) => new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, tx, 0, 0, 1]); aura.skinnedMesh.addClip({ name: 'authored', duration: 1, loop: true, channels: [{ jointIndex: 1, keyframes: [{ time: 0, transform: jointMatrix(0) }, { time: 0.5, transform: jointMatrix(0.5) }, { time: 1, transform: jointMatrix(0) }] }] }); aura.skinnedMesh.playAnimation(coloredSkinnedId, 'authored', { speed: 12, loop: true }); aura.skinnedMesh.playAnimation(legacySkinnedId, 'authored', { speed: 12, loop: true }); aura.camera3d.perspective(60, 0.1, 100); aura.camera3d.setPosition(0, 0, 4); aura.camera3d.lookAt(0, 0, 0); const baseDraw = aura.draw; aura.draw = function () { aura.draw3d.clear3d({ r: 0.02, g: 0.02, b: 0.03, a: 1 }); baseDraw(); }; globalThis.__authoredSkinningRuntime = { coloredMesh, legacyMesh, coloredSkinnedId, legacySkinnedId, vertexColorEntries: colors.length / 4 }; return [coloredMesh, legacyMesh, coloredSkinnedId, legacySkinnedId].every((handle) => Number.isInteger(handle) && handle > 0) && globalThis.__authoredSkinningRuntime.vertexColorEntries === 4; } catch (_) { return false; } })()`,
1441
+ },
1442
+ ],
1443
+ nativePostChecks: [
1444
+ {
1445
+ id: 'skinned.authored-input.runtime.evidence',
1446
+ expression: "(() => { try { const state = globalThis.__authoredSkinningRuntime || {}; aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); const scene3d = stats.scene3dRuntime || {}; const submission = scene3d.submission || {}; const resources = scene3d.resources || {}; const coloredJoint = aura.skinnedMesh.getJointPosition(state.coloredSkinnedId, 1); const legacyJoint = aura.skinnedMesh.getJointPosition(state.legacySkinnedId, 1); const renderedGroups = Number(submission.skinnedRenderedGroups || 0); const defaultGroups = Number(submission.skinnedGroupsUsingDefaultSkinningData || 0); const suppliedGroups = Number(submission.skinnedGroupsUsingSuppliedSkinningData || 0); return state.vertexColorEntries === 4 && state.coloredMesh !== state.legacyMesh && Number.isFinite(coloredJoint?.x) && Math.abs(Number(coloredJoint.x)) > 0.05 && Number.isFinite(legacyJoint?.x) && Math.abs(Number(legacyJoint.x)) > 0.05 && renderedGroups >= 2 && Number(submission.skinnedRenderedInstances || 0) >= 2 && Number(submission.skinnedUploadedJointMatrices || 0) >= 2 && suppliedGroups >= 2 && defaultGroups === 0 && suppliedGroups === renderedGroups && Number(resources.skinnedGroupCount || 0) >= 2; } catch (_) { return false; } })()",
1447
+ debugExpression: "(() => { try { aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); return { state: globalThis.__authoredSkinningRuntime || null, scene3dRuntime: stats.scene3dRuntime || null, coloredJoint: aura.skinnedMesh.getJointPosition(globalThis.__authoredSkinningRuntime?.coloredSkinnedId || 0, 1) || null, legacyJoint: aura.skinnedMesh.getJointPosition(globalThis.__authoredSkinningRuntime?.legacySkinnedId || 0, 1) || null }; } catch (error) { return { debugError: String(error && error.message ? error.message : error) }; } })()",
1448
+ },
1449
+ ],
1450
+ source: `
1451
+ globalThis.__authoredSkinningRuntime = {
1452
+ coloredMesh: 0,
1453
+ legacyMesh: 0,
1454
+ coloredSkinnedId: 0,
1455
+ legacySkinnedId: 0,
1456
+ vertexColorEntries: 0,
1457
+ };
1458
+ `,
1459
+ nativeFrames: 6,
1460
+ },
1461
+ {
1462
+ id: 'skinned-crowd-instancing-runtime',
1463
+ modes: ['native'],
1464
+ namespaces: ['mesh', 'skinnedMesh', 'camera3d', 'draw3d', 'debug'],
1465
+ functions: [
1466
+ 'aura.mesh.createFromVertices',
1467
+ 'aura.skinnedMesh.addClip',
1468
+ 'aura.skinnedMesh.createCrowd',
1469
+ 'aura.skinnedMesh.setCrowdInstanceTransform',
1470
+ 'aura.skinnedMesh.playCrowdAnimation',
1471
+ 'aura.skinnedMesh.blendCrowdAnimations',
1472
+ 'aura.skinnedMesh.getCrowdJointPosition',
1473
+ 'aura.skinnedMesh.getCrowdInfo',
1474
+ 'aura.debug.inspectorStats',
1475
+ ],
1476
+ nativeChecks: [
1477
+ {
1478
+ id: 'skinned.crowd-instancing.surface.methods',
1479
+ expression: "(() => typeof aura.mesh?.createFromVertices === 'function' && ['addClip','createCrowd','setCrowdInstanceTransform','playCrowdAnimation','blendCrowdAnimations','getCrowdJointPosition','getCrowdInfo'].every((name) => typeof aura.skinnedMesh?.[name] === 'function') && ['perspective','setPosition','lookAt'].every((name) => typeof aura.camera3d?.[name] === 'function') && typeof aura.draw3d?.clear3d === 'function' && typeof aura.debug?.inspectorStats === 'function')()",
1480
+ },
1481
+ {
1482
+ id: 'skinned.crowd-instancing.runtime.setup',
1483
+ expression: `(() => {
1484
+ try {
1485
+ const state = globalThis.__crowdSkinningRuntime;
1486
+ const leadColumns = 16;
1487
+ const leadRows = 12;
1488
+ const supportColumns = 8;
1489
+ const supportRows = 8;
1490
+ const leadCount = leadColumns * leadRows;
1491
+ const supportCount = supportColumns * supportRows;
1492
+ const positions = new Float32Array([-0.4, -0.6, 0, 0.4, -0.6, 0, 0.4, 0.6, 0, -0.4, 0.6, 0]);
1493
+ const indices = new Uint32Array([0, 1, 2, 0, 2, 3]);
1494
+ const normals = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]);
1495
+ const uvs = new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]);
1496
+ const colors = new Float32Array([0.95, 0.55, 0.35, 1, 0.95, 0.75, 0.3, 1, 0.35, 0.85, 0.95, 1, 0.25, 0.45, 0.95, 1]);
1497
+ const jointIndices = new Uint32Array([0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]);
1498
+ const jointWeights = new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]);
1499
+ const crowdMesh = aura.mesh.createFromVertices(positions, indices, normals, uvs, colors, { jointIndices, jointWeights });
1500
+ const jointXMatrix = (tx) => new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, tx, 0, 0, 1]);
1501
+ const jointYMatrix = (ty) => new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, ty, 0, 1]);
1502
+ const instanceMatrix = (tx, ty, tz, scale = 1) => new Float32Array([scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, scale, 0, tx, ty, tz, 1]);
1503
+ aura.skinnedMesh.addClip({
1504
+ name: 'crowd-step',
1505
+ duration: 1,
1506
+ loop: true,
1507
+ channels: [{ jointIndex: 1, keyframes: [{ time: 0, transform: jointXMatrix(0) }, { time: 0.5, transform: jointXMatrix(0.45) }, { time: 1, transform: jointXMatrix(0) }] }],
1508
+ });
1509
+ aura.skinnedMesh.addClip({
1510
+ name: 'crowd-lift',
1511
+ duration: 1,
1512
+ loop: true,
1513
+ channels: [{ jointIndex: 1, keyframes: [{ time: 0, transform: jointYMatrix(0) }, { time: 0.5, transform: jointYMatrix(0.22) }, { time: 1, transform: jointYMatrix(0) }] }],
1514
+ });
1515
+
1516
+ let overLimitError = '';
1517
+ try {
1518
+ aura.skinnedMesh.createCrowd(crowdMesh, { jointCount: 2 }, { instanceCount: 4097 });
1519
+ } catch (error) {
1520
+ overLimitError = String(error && error.message || error);
1521
+ }
1522
+
1523
+ const leadCrowdId = aura.skinnedMesh.createCrowd(crowdMesh, { jointCount: 2 }, { instanceCount: leadCount });
1524
+ const supportCrowdId = aura.skinnedMesh.createCrowd(crowdMesh, { jointCount: 2 }, { instanceCount: supportCount });
1525
+
1526
+ let leadIndex = 0;
1527
+ for (let row = 0; row < leadRows; row += 1) {
1528
+ for (let col = 0; col < leadColumns; col += 1) {
1529
+ const x = (col - ((leadColumns - 1) * 0.5)) * 0.78;
1530
+ const z = 1.2 + ((row - ((leadRows - 1) * 0.5)) * 0.72);
1531
+ const y = Math.sin((col * 0.75) + (row * 0.55)) * 0.04;
1532
+ const scale = 0.92 + ((leadIndex % 5) * 0.03);
1533
+ const phase = (leadIndex % leadColumns) / leadColumns;
1534
+ const speed = 5 + ((leadIndex % 4) * 0.3);
1535
+ aura.skinnedMesh.setCrowdInstanceTransform(leadCrowdId, leadIndex, instanceMatrix(x, y, z, scale));
1536
+ aura.skinnedMesh.playCrowdAnimation(leadCrowdId, leadIndex, 'crowd-step', {
1537
+ loop: true,
1538
+ speed,
1539
+ time: phase,
1540
+ });
1541
+ leadIndex += 1;
1542
+ }
1543
+ }
1544
+
1545
+ let supportIndex = 0;
1546
+ for (let row = 0; row < supportRows; row += 1) {
1547
+ for (let col = 0; col < supportColumns; col += 1) {
1548
+ const x = (col - ((supportColumns - 1) * 0.5)) * 1.0;
1549
+ const z = -6.2 + ((row - ((supportRows - 1) * 0.5)) * 0.84);
1550
+ const y = 0.18 + (Math.cos((col * 0.7) + (row * 0.9)) * 0.03);
1551
+ const scale = 0.8 + ((supportIndex % 4) * 0.035);
1552
+ const phase = (supportIndex % supportColumns) / supportColumns;
1553
+ aura.skinnedMesh.setCrowdInstanceTransform(supportCrowdId, supportIndex, instanceMatrix(x, y, z, scale));
1554
+ if (supportIndex % 2 === 0) {
1555
+ aura.skinnedMesh.blendCrowdAnimations(supportCrowdId, supportIndex, [
1556
+ { name: 'crowd-step', weight: 0.72, time: phase },
1557
+ { name: 'crowd-lift', weight: 0.28, time: Number((phase * 0.5).toFixed(3)) },
1558
+ ]);
1559
+ } else {
1560
+ aura.skinnedMesh.playCrowdAnimation(supportCrowdId, supportIndex, 'crowd-step', {
1561
+ loop: true,
1562
+ speed: 4.6 + ((supportIndex % 3) * 0.4),
1563
+ time: phase,
1564
+ });
1565
+ }
1566
+ supportIndex += 1;
1567
+ }
1568
+ }
1569
+
1570
+ aura.camera3d.perspective(55, 0.1, 100);
1571
+ aura.camera3d.setPosition(0, 10.5, 18.5);
1572
+ aura.camera3d.lookAt(0, 0.45, -1.5);
1573
+ const baseDraw = aura.draw;
1574
+ aura.draw = function () {
1575
+ aura.draw3d.clear3d({ r: 0.018, g: 0.02, b: 0.028, a: 1 });
1576
+ baseDraw();
1577
+ };
1578
+ state.crowdMesh = crowdMesh;
1579
+ state.leadCrowdId = leadCrowdId;
1580
+ state.supportCrowdId = supportCrowdId;
1581
+ state.overLimitError = overLimitError;
1582
+ state.expectedRenderedGroups = 2;
1583
+ state.expectedRenderedInstances = leadCount + supportCount;
1584
+ state.expectedAdvancedPlaybackCount = leadCount + (supportCount / 2);
1585
+ return [crowdMesh, leadCrowdId, supportCrowdId].every((handle) => Number.isInteger(handle) && handle > 0)
1586
+ && overLimitError.includes('opts.instanceCount must be 1..4096');
1587
+ } catch (_) {
1588
+ return false;
1589
+ }
1590
+ })()`,
1591
+ },
1592
+ ],
1593
+ nativePostChecks: [
1594
+ {
1595
+ id: 'skinned.crowd-instancing.runtime.evidence',
1596
+ expression: "(() => { try { const state = globalThis.__crowdSkinningRuntime || {}; aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); const leadInfo = aura.skinnedMesh.getCrowdInfo(state.leadCrowdId || 0); const supportInfo = aura.skinnedMesh.getCrowdInfo(state.supportCrowdId || 0); const leadJoints = [0, 47, 143].map((index) => aura.skinnedMesh.getCrowdJointPosition(state.leadCrowdId || 0, index, 1)); const supportJoints = [2, 4, 34].map((index) => aura.skinnedMesh.getCrowdJointPosition(state.supportCrowdId || 0, index, 1)); const allJoints = [...leadJoints, ...supportJoints]; const scene3d = stats.scene3dRuntime || {}; const submission = scene3d.submission || {}; const resources = scene3d.resources || {}; const animation = scene3d.animation || {}; const jointTrace = allJoints.map((joint) => `${Number(Number(joint?.x || 0).toFixed(3))}:${Number(Number(joint?.y || 0).toFixed(3))}`); const uniqueJointTraceCount = new Set(jointTrace).size; const liftedJointCount = supportJoints.filter((joint) => Math.abs(Number(joint?.y || 0)) > 0.01).length; const renderedGroups = Number(submission.skinnedRenderedGroups || 0); const suppliedGroups = Number(submission.skinnedGroupsUsingSuppliedSkinningData || 0); const defaultGroups = Number(submission.skinnedGroupsUsingDefaultSkinningData || 0); const expectedRenderedInstances = Number(state.expectedRenderedInstances || 0); const expectedAdvancedPlaybackCount = Number(state.expectedAdvancedPlaybackCount || 0); return Number.isInteger(state.crowdMesh) && state.crowdMesh > 0 && leadInfo?.meshHandle === state.crowdMesh && supportInfo?.meshHandle === state.crowdMesh && leadInfo?.jointCount === 2 && supportInfo?.jointCount === 2 && leadInfo?.instanceCount === 192 && supportInfo?.instanceCount === 64 && leadInfo?.animatedInstanceCount === 192 && supportInfo?.animatedInstanceCount === 64 && leadInfo?.maxInstanceCount === 4096 && supportInfo?.maxInstanceCount === 4096 && leadInfo?.maxJointCount === 128 && supportInfo?.maxJointCount === 128 && allJoints.every((joint) => Number.isFinite(joint?.x) && Number.isFinite(joint?.y)) && uniqueJointTraceCount >= 4 && liftedJointCount >= 2 && state.overLimitError?.includes('opts.instanceCount must be 1..4096') && renderedGroups >= Number(state.expectedRenderedGroups || 0) && Number(resources.skinnedGroupCount || 0) >= Number(state.expectedRenderedGroups || 0) && Number(submission.skinnedRenderedInstances || 0) >= expectedRenderedInstances && Number(submission.skinnedUploadedTransforms || 0) >= expectedRenderedInstances && Number(submission.skinnedUploadedJointMatrices || 0) >= expectedRenderedInstances * 2 && suppliedGroups === renderedGroups && defaultGroups === 0 && Number(resources.skinnedAnimationPlaybackCount || 0) >= expectedAdvancedPlaybackCount && Number(animation.skinnedTrackedMeshCount || 0) >= expectedRenderedInstances && Number(animation.skinnedLastJointUpdateCount || 0) >= expectedRenderedInstances * 2 && Number(animation.skinnedLastAdvancedPlaybackCount || 0) >= expectedAdvancedPlaybackCount; } catch (_) { return false; } })()",
1597
+ debugExpression: "(() => { try { aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); const state = globalThis.__crowdSkinningRuntime || {}; return { state, scene3dRuntime: stats.scene3dRuntime || null, leadInfo: aura.skinnedMesh.getCrowdInfo(state.leadCrowdId || 0) || null, supportInfo: aura.skinnedMesh.getCrowdInfo(state.supportCrowdId || 0) || null, leadJoints: [0, 47, 143].map((index) => aura.skinnedMesh.getCrowdJointPosition(state.leadCrowdId || 0, index, 1) || null), supportJoints: [2, 4, 34].map((index) => aura.skinnedMesh.getCrowdJointPosition(state.supportCrowdId || 0, index, 1) || null) }; } catch (error) { return { debugError: String(error && error.message ? error.message : error) }; } })()",
1598
+ },
1599
+ ],
1600
+ source: `
1601
+ globalThis.__crowdSkinningRuntime = {
1602
+ crowdMesh: 0,
1603
+ leadCrowdId: 0,
1604
+ supportCrowdId: 0,
1605
+ overLimitError: '',
1606
+ expectedRenderedGroups: 0,
1607
+ expectedRenderedInstances: 0,
1608
+ };
1609
+ `,
1610
+ nativeFrames: 10,
1611
+ },
1612
+ {
1613
+ id: 'navmesh-crowd-locomotion-runtime',
1614
+ modes: ['native'],
1615
+ namespaces: ['navmesh', 'character3d'],
1616
+ functions: [
1617
+ 'aura.navmesh.bakeFromMesh',
1618
+ 'aura.navmesh.findPath',
1619
+ 'aura.navmesh.createCrowd',
1620
+ 'aura.navmesh.addAgent',
1621
+ 'aura.navmesh.setAgentTarget',
1622
+ 'aura.navmesh.bindAgentCharacter',
1623
+ 'aura.navmesh.setAgentFollowTarget',
1624
+ 'aura.navmesh.clearAgentFollowTarget',
1625
+ 'aura.navmesh.stepCrowd',
1626
+ 'aura.navmesh.getAgentPosition',
1627
+ 'aura.navmesh.getAgentVelocity',
1628
+ 'aura.navmesh.getAgentState',
1629
+ 'aura.navmesh.getCrowdInfo',
1630
+ 'aura.character3d.create',
1631
+ 'aura.character3d.getPosition',
1632
+ ],
1633
+ nativeChecks: [
1634
+ {
1635
+ id: 'navmesh.crowd-locomotion.surface.methods',
1636
+ expression: "(() => ['bakeFromMesh','findPath','createCrowd','addAgent','setAgentTarget','bindAgentCharacter','setAgentFollowTarget','clearAgentFollowTarget','stepCrowd','getAgentPosition','getAgentVelocity','getAgentState','getCrowdInfo'].every((name) => typeof aura.navmesh?.[name] === 'function') && ['create','getPosition'].every((name) => typeof aura.character3d?.[name] === 'function'))()",
1637
+ },
1638
+ {
1639
+ id: 'navmesh.crowd-locomotion.runtime.setup',
1640
+ expression: `(() => { try { const state = globalThis.__navmeshCrowdRuntime; const buildGrid = (size, subdivisions) => { const positions = []; const indices = []; const row = subdivisions + 1; const step = size / subdivisions; for (let z = 0; z <= subdivisions; z += 1) { for (let x = 0; x <= subdivisions; x += 1) { positions.push(x * step, 0, z * step); } } for (let z = 0; z < subdivisions; z += 1) { for (let x = 0; x < subdivisions; x += 1) { const i = (z * row) + x; indices.push(i, i + 1, i + row + 1); indices.push(i + 1, i + row + 2, i + row + 1); } } return { positions: new Float32Array(positions), indices: new Uint32Array(indices) }; }; const fingerprintPath = (path) => Array.isArray(path) ? path.map((point) => \`\${Number(Number(point?.x || 0).toFixed(3))}:\${Number(Number(point?.z || 0).toFixed(3))}\`).join('|') : ''; const previewStart = { x: 1.2, y: 0, z: 1.2 }; const previewEnd = { x: 8.2, y: 0, z: 7.8 }; const redirectEnd = { x: 2.4, y: 0, z: 8.4 }; const escortBEnd = { x: 9.6, y: 0, z: 2.4 }; const grid = buildGrid(12, 4); const meshId = aura.navmesh.bakeFromMesh(grid.positions, grid.indices, { cellSize: 1.0, agentRadius: 0.45, agentHeight: 1.8 }); const previewPath = aura.navmesh.findPath(meshId, previewStart.x, previewStart.y, previewStart.z, previewEnd.x, previewEnd.y, previewEnd.z); const missingPath = aura.navmesh.findPath(999999, 0, 0, 0, 1, 0, 1); const crowdId = aura.navmesh.createCrowd(meshId, { maxAgents: 8, neighborDist: 3.5, maxNeighbors: 6, timeHorizon: 2.5, obstacleTimeHorizon: 2.5 }); const leaderCharacter = aura.character3d.create({ x: previewStart.x, y: 0.9, z: previewStart.z, radius: 0.35, height: 1.8 }); const escortACharacter = aura.character3d.create({ x: 0.2, y: 0.9, z: 0.6, radius: 0.35, height: 1.8 }); const escortBCharacter = aura.character3d.create({ x: 2.1, y: 0.9, z: 0.4, radius: 0.35, height: 1.8 }); const leader = aura.navmesh.addAgent(crowdId, { x: previewStart.x, y: 0, z: previewStart.z, radius: 0.45, maxSpeed: 2.3 }); const escortA = aura.navmesh.addAgent(crowdId, { x: 0.2, y: 0, z: 0.6, radius: 0.45, maxSpeed: 2.1 }); const escortB = aura.navmesh.addAgent(crowdId, { x: 2.1, y: 0, z: 0.4, radius: 0.45, maxSpeed: 2.1 }); const bindLeader = aura.navmesh.bindAgentCharacter(crowdId, leader, leaderCharacter, { offset: { x: 0, y: 0.9, z: 0 } }); const bindEscortA = aura.navmesh.bindAgentCharacter(crowdId, escortA, escortACharacter, { offset: { x: 0, y: 0.9, z: 0 } }); const bindEscortB = aura.navmesh.bindAgentCharacter(crowdId, escortB, escortBCharacter, { offset: { x: 0, y: 0.9, z: 0 } }); const invalidFollow = aura.navmesh.setAgentFollowTarget(crowdId, escortA, { agentId: 999999 }, { replanDistance: 0.2 }); const invalidStep = aura.navmesh.stepCrowd(crowdId, 0); const leaderTarget = aura.navmesh.setAgentTarget(crowdId, leader, previewEnd.x, previewEnd.y, previewEnd.z); const escortAFollow = aura.navmesh.setAgentFollowTarget(crowdId, escortA, { agentId: leader }, { offset: { x: -1.1, y: 0, z: -0.9 }, stopDistance: 0.7, replanDistance: 0.25 }); const escortBFollow = aura.navmesh.setAgentFollowTarget(crowdId, escortB, { characterId: leaderCharacter }, { offset: { x: 1.1, y: -0.9, z: -0.9 }, stopDistance: 0.7, replanDistance: 0.25 }); state.meshId = meshId; state.crowdId = crowdId; state.characters = { leader: leaderCharacter, escortA: escortACharacter, escortB: escortBCharacter }; state.agents = { leader, escortA, escortB }; state.starts = { leader: { x: previewStart.x, z: previewStart.z }, escortA: { x: 0.2, z: 0.6 }, escortB: { x: 2.1, z: 0.4 } }; state.invalidFollow = invalidFollow; state.invalidStep = invalidStep; state.bindings = { bindLeader, bindEscortA, bindEscortB, leaderTarget, escortAFollow, escortBFollow }; state.pathQueries = { previewStart, previewEnd, redirectStart: null, redirectEnd, escortBStart: null, escortBEnd }; state.previewPath = Array.isArray(previewPath) ? previewPath : null; state.previewFingerprint = fingerprintPath(previewPath); state.missingPath = missingPath; state.initialLeaderPosition = aura.navmesh.getAgentPosition(crowdId, leader); state.initialLeaderVelocity = aura.navmesh.getAgentVelocity(crowdId, leader); state.redirectPath = null; state.redirectFingerprint = ''; state.clearEscortB = null; state.escortBRetarget = null; state.escortBPath = null; state.escortBFingerprint = ''; state.maxLeaderSpeed = 0; state.maxEscortBSpeed = 0; state.stepCount = 0; state.lastStep = null; state.redirect = null; aura.update = function () { state.stepCount += 1; state.lastStep = aura.navmesh.stepCrowd(crowdId, 1 / 60); const leaderVelocity = aura.navmesh.getAgentVelocity(crowdId, leader) || {}; const escortBVelocity = aura.navmesh.getAgentVelocity(crowdId, escortB) || {}; const leaderSpeed = Math.hypot(Number(leaderVelocity.x || 0), Number(leaderVelocity.z || 0)); const escortBSpeed = Math.hypot(Number(escortBVelocity.x || 0), Number(escortBVelocity.z || 0)); state.maxLeaderSpeed = Math.max(Number(state.maxLeaderSpeed || 0), leaderSpeed); state.maxEscortBSpeed = Math.max(Number(state.maxEscortBSpeed || 0), escortBSpeed); if (state.stepCount === 45) { const leaderPosition = aura.navmesh.getAgentPosition(crowdId, leader) || previewStart; state.pathQueries.redirectStart = leaderPosition; state.redirectPath = aura.navmesh.findPath(meshId, leaderPosition.x, leaderPosition.y, leaderPosition.z, redirectEnd.x, redirectEnd.y, redirectEnd.z); state.redirectFingerprint = fingerprintPath(state.redirectPath); state.redirect = aura.navmesh.setAgentTarget(crowdId, leader, redirectEnd.x, redirectEnd.y, redirectEnd.z); } if (state.stepCount === 60) { const escortBPosition = aura.navmesh.getAgentPosition(crowdId, escortB) || state.starts.escortB; state.pathQueries.escortBStart = escortBPosition; state.clearEscortB = aura.navmesh.clearAgentFollowTarget(crowdId, escortB); state.escortBPath = aura.navmesh.findPath(meshId, escortBPosition.x, escortBPosition.y, escortBPosition.z, escortBEnd.x, escortBEnd.y, escortBEnd.z); state.escortBFingerprint = fingerprintPath(state.escortBPath); state.escortBRetarget = aura.navmesh.setAgentTarget(crowdId, escortB, escortBEnd.x, escortBEnd.y, escortBEnd.z); } }; return Number.isInteger(meshId) && meshId > 0 && Number.isInteger(crowdId) && crowdId > 0 && [leaderCharacter, escortACharacter, escortBCharacter, leader, escortA, escortB].every((handle) => Number.isInteger(handle) && handle > 0) && bindLeader?.ok === true && bindEscortA?.ok === true && bindEscortB?.ok === true && leaderTarget?.ok === true && escortAFollow?.ok === true && escortBFollow?.ok === true && Array.isArray(previewPath) && previewPath.length >= 1 && typeof state.previewFingerprint === 'string' && state.previewFingerprint.length > 0 && missingPath === null && Number.isFinite(state.initialLeaderPosition?.x) && Number.isFinite(state.initialLeaderVelocity?.x); } catch (_) { return false; } })()`,
1641
+ },
1642
+ ],
1643
+ nativePostChecks: [
1644
+ {
1645
+ id: 'navmesh.crowd-locomotion.runtime.evidence',
1646
+ expression: "(() => { try { const state = globalThis.__navmeshCrowdRuntime || {}; const fingerprintPath = (path) => Array.isArray(path) ? path.map((point) => `${Number(Number(point?.x || 0).toFixed(3))}:${Number(Number(point?.z || 0).toFixed(3))}`).join('|') : ''; const closeTo = (value, target, tolerance = 0.01) => Math.abs(Number(value || 0) - target) <= tolerance; const info = aura.navmesh.getCrowdInfo(state.crowdId || 0); const leader = aura.navmesh.getAgentState(state.crowdId || 0, state.agents?.leader || 0); const escortA = aura.navmesh.getAgentState(state.crowdId || 0, state.agents?.escortA || 0); const escortB = aura.navmesh.getAgentState(state.crowdId || 0, state.agents?.escortB || 0); const leaderPosition = aura.navmesh.getAgentPosition(state.crowdId || 0, state.agents?.leader || 0); const leaderVelocity = aura.navmesh.getAgentVelocity(state.crowdId || 0, state.agents?.leader || 0); const escortBPosition = aura.navmesh.getAgentPosition(state.crowdId || 0, state.agents?.escortB || 0); const escortBVelocity = aura.navmesh.getAgentVelocity(state.crowdId || 0, state.agents?.escortB || 0); const leaderCharacter = aura.character3d.getPosition(state.characters?.leader || 0); const escortACharacter = aura.character3d.getPosition(state.characters?.escortA || 0); const escortBCharacter = aura.character3d.getPosition(state.characters?.escortB || 0); const moved = (position, start) => Math.hypot(Number(position?.x || 0) - Number(start?.x || 0), Number(position?.z || 0) - Number(start?.z || 0)) > 1.0; const synced = (agent, character) => Math.abs((Number(agent?.y || 0) + 0.9) - Number(character?.y || 0)) < 0.05; const previewCheck = aura.navmesh.findPath(state.meshId || 0, state.pathQueries?.previewStart?.x || 0, state.pathQueries?.previewStart?.y || 0, state.pathQueries?.previewStart?.z || 0, state.pathQueries?.previewEnd?.x || 0, state.pathQueries?.previewEnd?.y || 0, state.pathQueries?.previewEnd?.z || 0); const redirectCheck = aura.navmesh.findPath(state.meshId || 0, state.pathQueries?.redirectStart?.x || 0, state.pathQueries?.redirectStart?.y || 0, state.pathQueries?.redirectStart?.z || 0, state.pathQueries?.redirectEnd?.x || 0, state.pathQueries?.redirectEnd?.y || 0, state.pathQueries?.redirectEnd?.z || 0); const escortBCheck = aura.navmesh.findPath(state.meshId || 0, state.pathQueries?.escortBStart?.x || 0, state.pathQueries?.escortBStart?.y || 0, state.pathQueries?.escortBStart?.z || 0, state.pathQueries?.escortBEnd?.x || 0, state.pathQueries?.escortBEnd?.y || 0, state.pathQueries?.escortBEnd?.z || 0); return state.invalidFollow?.ok === false && state.invalidFollow?.reasonCode === 'invalid_follow_target' && state.invalidStep?.ok === false && state.invalidStep?.reasonCode === 'invalid_dt' && state.bindings?.escortAFollow?.reasonCode === 'navmesh_agent_follow_target_set' && state.bindings?.escortBFollow?.reasonCode === 'navmesh_agent_follow_target_set' && state.redirect?.ok === true && state.clearEscortB?.ok === true && state.clearEscortB?.reasonCode === 'navmesh_agent_follow_target_cleared' && state.escortBRetarget?.ok === true && state.escortBRetarget?.reasonCode === 'navmesh_agent_target_set' && info?.ok === true && info?.agentCount === 3 && info?.followingAgents === 3 && info?.boundCharacterCount === 3 && Number(info?.totalReplans || 0) > 0 && state.lastStep?.ok === true && Number(state.lastStep?.syncedCharacters || 0) >= 3 && leader?.ok === true && leader?.followMode === 'point' && escortA?.ok === true && escortA?.followMode === 'agent' && escortB?.ok === true && escortB?.followMode === 'point' && moved(leader?.position, state.starts?.leader) && moved(escortA?.position, state.starts?.escortA) && moved(escortB?.position, state.starts?.escortB) && synced(leader?.position, leaderCharacter) && synced(escortA?.position, escortACharacter) && synced(escortB?.position, escortBCharacter) && closeTo(escortA?.replanDistance, 0.25, 0.001) && closeTo(escortB?.stopDistance, 0.7, 0.01) && Number(state.maxLeaderSpeed || 0) > 0.1 && Number(state.maxEscortBSpeed || 0) > 0.1 && Number.isFinite(leaderPosition?.x) && Number.isFinite(leaderVelocity?.x) && Number.isFinite(escortBPosition?.x) && Number.isFinite(escortBVelocity?.x) && Array.isArray(state.previewPath) && state.previewPath.length >= 1 && typeof state.previewFingerprint === 'string' && state.previewFingerprint === fingerprintPath(previewCheck) && Array.isArray(state.redirectPath) && state.redirectPath.length >= 1 && typeof state.redirectFingerprint === 'string' && state.redirectFingerprint === fingerprintPath(redirectCheck) && Array.isArray(state.escortBPath) && state.escortBPath.length >= 1 && typeof state.escortBFingerprint === 'string' && state.escortBFingerprint === fingerprintPath(escortBCheck) && state.missingPath === null; } catch (_) { return false; } })()",
1647
+ debugExpression: "(() => { try { const state = globalThis.__navmeshCrowdRuntime || {}; return { state, info: aura.navmesh.getCrowdInfo(state.crowdId || 0), leader: aura.navmesh.getAgentState(state.crowdId || 0, state.agents?.leader || 0), escortA: aura.navmesh.getAgentState(state.crowdId || 0, state.agents?.escortA || 0), escortB: aura.navmesh.getAgentState(state.crowdId || 0, state.agents?.escortB || 0), positions: { leader: aura.navmesh.getAgentPosition(state.crowdId || 0, state.agents?.leader || 0), escortB: aura.navmesh.getAgentPosition(state.crowdId || 0, state.agents?.escortB || 0) }, velocities: { leader: aura.navmesh.getAgentVelocity(state.crowdId || 0, state.agents?.leader || 0), escortB: aura.navmesh.getAgentVelocity(state.crowdId || 0, state.agents?.escortB || 0) }, characters: { leader: aura.character3d.getPosition(state.characters?.leader || 0), escortA: aura.character3d.getPosition(state.characters?.escortA || 0), escortB: aura.character3d.getPosition(state.characters?.escortB || 0) } }; } catch (error) { return { debugError: String(error && error.message ? error.message : error) }; } })()",
1648
+ },
1649
+ ],
1650
+ source: `
1651
+ globalThis.__navmeshCrowdRuntime = {
1652
+ meshId: 0,
1653
+ crowdId: 0,
1654
+ agents: {},
1655
+ characters: {},
1656
+ starts: {},
1657
+ pathQueries: {},
1658
+ previewPath: null,
1659
+ previewFingerprint: '',
1660
+ missingPath: null,
1661
+ bindings: {},
1662
+ invalidFollow: null,
1663
+ invalidStep: null,
1664
+ redirectPath: null,
1665
+ redirectFingerprint: '',
1666
+ clearEscortB: null,
1667
+ escortBRetarget: null,
1668
+ escortBPath: null,
1669
+ escortBFingerprint: '',
1670
+ lastStep: null,
1671
+ redirect: null,
1672
+ initialLeaderPosition: null,
1673
+ initialLeaderVelocity: null,
1674
+ maxLeaderSpeed: 0,
1675
+ maxEscortBSpeed: 0,
1676
+ stepCount: 0,
1677
+ };
1678
+ `,
1679
+ nativeFrames: 90,
1680
+ },
1681
+ {
1682
+ id: 'mesh-procedural-generators-runtime',
1683
+ modes: ['native'],
1684
+ namespaces: ['mesh'],
1685
+ functions: [
1686
+ 'aura.mesh.createRing',
1687
+ 'aura.mesh.createExtrude',
1688
+ 'aura.mesh.createLathe',
1689
+ 'aura.mesh.createTorus',
1690
+ 'aura.mesh.getData',
1691
+ ],
1692
+ nativeChecks: [
1693
+ {
1694
+ id: 'mesh.procedural-generators.surface.methods',
1695
+ expression: "(() => ['createRing','createExtrude','createLathe','createTorus','getData'].every((name) => typeof aura.mesh?.[name] === 'function'))()",
1696
+ },
1697
+ {
1698
+ id: 'mesh.procedural-generators.runtime.setup',
1699
+ expression: "(() => { try { const square = [{ x: -1, y: -1 }, { x: 1, y: -1 }, { x: 1, y: 1 }, { x: -1, y: 1 }]; const profile = [{ x: 1, y: 0 }, { x: 1, y: 1 }, { x: 1, y: 2 }]; const ring = aura.mesh.createRing(0.5, 1.0, 8); const extrudeLegacy = aura.mesh.createExtrude(square, 1.0, 1); const extrudeOptions = aura.mesh.createExtrude(square, { depth: 1.0, segments: 1 }); const latheLegacy = aura.mesh.createLathe(profile, 8, 0, Math.PI * 2); const latheOptions = aura.mesh.createLathe(profile, { segments: 8, phiStart: 0, phiLength: Math.PI * 2 }); const torus = aura.mesh.createTorus(1.0, 0.3, 24, 16); const ringData = aura.mesh.getData(ring); const extrudeLegacyData = aura.mesh.getData(extrudeLegacy); const extrudeOptionsData = aura.mesh.getData(extrudeOptions); const latheLegacyData = aura.mesh.getData(latheLegacy); const latheOptionsData = aura.mesh.getData(latheOptions); const torusData = aura.mesh.getData(torus); globalThis.__proceduralGeometryRuntime = { ring, extrudeLegacy, extrudeOptions, latheLegacy, latheOptions, torus, initial: { ring: ringData, extrudeLegacy: extrudeLegacyData, extrudeOptions: extrudeOptionsData, latheLegacy: latheLegacyData, latheOptions: latheOptionsData, torus: torusData } }; return Number.isInteger(ring) && ring > 0 && Number.isInteger(extrudeLegacy) && extrudeLegacy > 0 && Number.isInteger(extrudeOptions) && extrudeOptions > 0 && Number.isInteger(latheLegacy) && latheLegacy > 0 && Number.isInteger(latheOptions) && latheOptions > 0 && Number.isInteger(torus) && torus > 0 && Number(ringData?.vertexCount || 0) === 18 && Number(ringData?.indexCount || 0) === 48 && Number(extrudeLegacyData?.vertexCount || 0) === 24 && Number(extrudeLegacyData?.indexCount || 0) === 36 && Number(extrudeOptionsData?.vertexCount || 0) === 24 && Number(extrudeOptionsData?.indexCount || 0) === 36 && Number(latheLegacyData?.vertexCount || 0) === 27 && Number(latheLegacyData?.indexCount || 0) === 96 && Number(latheOptionsData?.vertexCount || 0) === 27 && Number(latheOptionsData?.indexCount || 0) === 96 && Number(torusData?.vertexCount || 0) === 425 && Number(torusData?.indexCount || 0) === 2304 && Number(ringData?.bounds?.max?.x || 0) >= 0.99 && Number(ringData?.bounds?.min?.x || 0) <= -0.99 && Number(extrudeLegacyData?.bounds?.min?.z || 0) <= -0.49 && Number(extrudeLegacyData?.bounds?.max?.z || 0) >= 0.49 && Number(latheLegacyData?.bounds?.max?.y || 0) >= 1.99 && Number(latheLegacyData?.bounds?.min?.y || 0) <= 0.01 && Number(torusData?.bounds?.max?.x || 0) >= 1.29 && Number(torusData?.bounds?.min?.x || 0) <= -1.29 && Number(torusData?.bounds?.max?.y || 0) >= 0.29 && Number(torusData?.bounds?.min?.y || 0) <= -0.29; } catch (_) { return false; } })()",
1700
+ },
1701
+ {
1702
+ id: 'mesh.procedural-generators.runtime.invalid-authored-input',
1703
+ expression: "(() => { const matchesError = (factory, message) => { try { factory(); return false; } catch (error) { return String(error).includes(message); } }; return matchesError(() => aura.mesh.createRing(1.0, 1.0, 8), 'outerRadius must be a finite number greater than innerRadius') && matchesError(() => aura.mesh.createExtrude([{ x: 0, y: 0 }, { x: Number.NaN, y: 0 }, { x: 0.5, y: 1 }], 1, 1), 'shape2d[1].x must be a finite number') && matchesError(() => aura.mesh.createExtrude([{ x: 0, y: 0 }, { x: 1, y: 0 }, { x: 0.5, y: 1 }], { depth: 1.0 }, 1), 'options cannot be combined with positional depth or segments') && matchesError(() => aura.mesh.createLathe([{ x: -0.5, y: 0 }, { x: 1, y: 1 }], 8, 0, Math.PI * 2), 'lathe profile point 0.x must be >= 0') && matchesError(() => aura.mesh.createLathe([{ x: 0.5, y: 0 }, { x: 1, y: 1 }], { segments: 8 }, 0, Math.PI * 2), 'options cannot be combined with positional segments, phiStart, or phiLength'); })()",
1704
+ },
1705
+ ],
1706
+ nativePostChecks: [
1707
+ {
1708
+ id: 'mesh.procedural-generators.runtime.evidence',
1709
+ expression: "(() => { try { const state = globalThis.__proceduralGeometryRuntime || {}; const current = { ring: aura.mesh.getData(state.ring || 0), extrudeLegacy: aura.mesh.getData(state.extrudeLegacy || 0), extrudeOptions: aura.mesh.getData(state.extrudeOptions || 0), latheLegacy: aura.mesh.getData(state.latheLegacy || 0), latheOptions: aura.mesh.getData(state.latheOptions || 0), torus: aura.mesh.getData(state.torus || 0) }; return Number(state.initial?.ring?.vertexCount || 0) === 18 && Number(state.initial?.ring?.indexCount || 0) === 48 && Number(state.initial?.extrudeLegacy?.vertexCount || 0) === 24 && Number(state.initial?.extrudeLegacy?.indexCount || 0) === 36 && Number(state.initial?.extrudeOptions?.vertexCount || 0) === 24 && Number(state.initial?.extrudeOptions?.indexCount || 0) === 36 && Number(state.initial?.latheLegacy?.vertexCount || 0) === 27 && Number(state.initial?.latheLegacy?.indexCount || 0) === 96 && Number(state.initial?.latheOptions?.vertexCount || 0) === 27 && Number(state.initial?.latheOptions?.indexCount || 0) === 96 && Number(state.initial?.torus?.vertexCount || 0) === 425 && Number(state.initial?.torus?.indexCount || 0) === 2304 && Number(current.ring?.vertexCount || 0) === Number(state.initial?.ring?.vertexCount || 0) && Number(current.ring?.indexCount || 0) === Number(state.initial?.ring?.indexCount || 0) && Number(current.extrudeLegacy?.vertexCount || 0) === Number(state.initial?.extrudeLegacy?.vertexCount || 0) && Number(current.extrudeLegacy?.indexCount || 0) === Number(state.initial?.extrudeLegacy?.indexCount || 0) && Number(current.extrudeOptions?.vertexCount || 0) === Number(state.initial?.extrudeOptions?.vertexCount || 0) && Number(current.extrudeOptions?.indexCount || 0) === Number(state.initial?.extrudeOptions?.indexCount || 0) && Number(current.latheLegacy?.vertexCount || 0) === Number(state.initial?.latheLegacy?.vertexCount || 0) && Number(current.latheLegacy?.indexCount || 0) === Number(state.initial?.latheLegacy?.indexCount || 0) && Number(current.latheOptions?.vertexCount || 0) === Number(state.initial?.latheOptions?.vertexCount || 0) && Number(current.latheOptions?.indexCount || 0) === Number(state.initial?.latheOptions?.indexCount || 0) && Number(current.torus?.vertexCount || 0) === Number(state.initial?.torus?.vertexCount || 0) && Number(current.torus?.indexCount || 0) === Number(state.initial?.torus?.indexCount || 0); } catch (_) { return false; } })()",
1710
+ },
1711
+ ],
1712
+ source: `
1713
+ globalThis.__proceduralGeometryRuntime = {
1714
+ ring: 0,
1715
+ extrudeLegacy: 0,
1716
+ extrudeOptions: 0,
1717
+ latheLegacy: 0,
1718
+ latheOptions: 0,
1719
+ torus: 0,
1720
+ initial: {},
1721
+ };
1722
+ `,
1723
+ nativeFrames: 1,
1724
+ },
1725
+ {
1726
+ id: 'custom-shader-material-runtime',
1727
+ modes: ['native'],
1728
+ namespaces: ['material', 'mesh', 'draw3d', 'camera3d', 'light'],
1729
+ functions: [
1730
+ 'aura.material.create',
1731
+ 'aura.material.createCustom',
1732
+ 'aura.material.setUniform',
1733
+ 'aura.material.setCustomTexture',
1734
+ 'aura.mesh.createBox',
1735
+ 'aura.draw3d.clear3d',
1736
+ 'aura.draw3d.drawMesh',
1737
+ 'aura.camera3d.perspective',
1738
+ 'aura.camera3d.setPosition',
1739
+ 'aura.camera3d.lookAt',
1740
+ 'aura.light.ambient',
1741
+ 'aura.light.directional',
1742
+ ],
1743
+ nativeChecks: [
1744
+ {
1745
+ id: 'material.custom-shader.surface.methods',
1746
+ expression: "(() => ['create','createCustom','setUniform','setCustomTexture'].every((name) => typeof aura.material?.[name] === 'function') && typeof aura.mesh?.createBox === 'function' && typeof aura.draw3d?.drawMesh === 'function')()",
1747
+ },
1748
+ {
1749
+ id: 'material.custom-shader.runtime.setup',
1750
+ expression: "(() => { try { const state = globalThis.__customShaderRuntime || {}; const mutationReason = globalThis.__customShaderMutationReason; state.floor = aura.mesh.createBox(5, 0.2, 5); state.cube = aura.mesh.createBox(1.25, 1.25, 1.25); state.plain = aura.material.create({ color: { r: 0.2, g: 0.22, b: 0.27, a: 1 }, roughness: 0.92, metallic: 0.04 }); state.textured = aura.material.createCustom({ vertex: state.vertex, fragment: state.texturedFragment, uniforms: { tint: 'vec4', uvScale: 'vec2', pulse: 'float' }, texture: true }); state.solid = aura.material.createCustom({ vertex: state.vertex, fragment: state.solidFragment, uniforms: { tint: 'vec4', pulse: 'float' } }); state.broken = 999999; state.initial.uniformOk = [mutationReason(aura.material.setUniform(state.textured, 'tint', [0.88, 0.94, 1, 1])), mutationReason(aura.material.setUniform(state.textured, 'uvScale', { x: 1.2, y: 0.85 })), mutationReason(aura.material.setUniform(state.textured, 'pulse', 0.72)), mutationReason(aura.material.setUniform(state.solid, 'tint', [0.72, 0.86, 1, 1])), mutationReason(aura.material.setUniform(state.solid, 'pulse', 0.61))]; state.initial.textureOk = mutationReason(aura.material.setCustomTexture(state.textured, state.texturePath)); aura.camera3d.perspective(56, 0.1, 48); aura.camera3d.setPosition(3.1, 2.2, 4.6); aura.camera3d.lookAt(0, 0.35, 0); aura.light.ambient({ r: 1, g: 1, b: 1, a: 1 }, 0.22); aura.light.directional({ x: -0.42, y: -1, z: -0.25 }, { r: 1, g: 0.97, b: 0.94, a: 1 }, 1.08); const baseDraw = aura.draw; aura.draw = function () { const probe = globalThis.__customShaderRuntime || {}; probe.frames.push(probe.frames.length); aura.draw3d.clear3d({ r: 0.03, g: 0.035, b: 0.045, a: 1 }); aura.draw3d.drawMesh(probe.floor, probe.plain, { position: { x: 0, y: -1.05, z: 0 } }); aura.draw3d.drawMesh(probe.cube, probe.textured, { position: { x: -0.82, y: 0, z: 0 }, rotation: { x: 0.14, y: 0.52, z: 0 } }); aura.draw3d.drawMesh(probe.cube, probe.solid, { position: { x: 0.96, y: 0.08, z: 0 }, rotation: { x: 0.08, y: -0.41, z: 0 } }); if (typeof baseDraw === 'function') baseDraw(); }; return Number.isInteger(state.floor) && state.floor > 0 && Number.isInteger(state.cube) && state.cube > 0 && Number.isInteger(state.plain) && state.plain > 0 && Number.isInteger(state.textured) && state.textured > 0 && Number.isInteger(state.solid) && state.solid > 0 && Number.isInteger(state.broken) && state.broken > 0 && Array.isArray(state.initial.uniformOk) && state.initial.uniformOk.every((reason) => reason === 'ok') && state.initial.textureOk === 'ok'; } catch (_) { return false; } })()",
1751
+ },
1752
+ {
1753
+ id: 'material.custom-shader.runtime.invalid-authored-input',
1754
+ expression: "(() => { const state = globalThis.__customShaderRuntime || {}; const mutationReason = globalThis.__customShaderMutationReason; const matchesError = globalThis.__customShaderMatchError; return matchesError(() => aura.material.createCustom(), 'aura.material.createCustom: options is required') && matchesError(() => aura.material.createCustom({ vertex: state.vertex, fragment: state.solidFragment, uniforms: { texture: 'texture' } }), 'aura.material.createCustom: declare texture access with `texture: true`, not `uniforms.texture = \\'texture\\'`') && mutationReason(aura.material.setUniform(state.textured, '', 1)) === 'invalid_uniform_name' && mutationReason(aura.material.setUniform(state.textured, 'missingUniform', 1)) === 'unknown_custom_uniform' && mutationReason(aura.material.setUniform(state.textured, 'pulse', { x: 1 })) === 'invalid_uniform_value' && mutationReason(aura.material.setUniform(state.plain, 'pulse', 1)) === 'not_custom_shader_material' && mutationReason(aura.material.setUniform('bad-handle', 'pulse', 1)) === 'not_custom_shader_material' && mutationReason(aura.material.setCustomTexture(state.solid, state.texturePath)) === 'custom_texture_not_declared' && mutationReason(aura.material.setCustomTexture(state.textured, 42)) === 'invalid_custom_texture_path'; })()",
1755
+ },
1756
+ ],
1757
+ nativePostChecks: [
1758
+ {
1759
+ id: 'material.custom-shader.runtime.evidence',
1760
+ expression: "(() => { try { const state = globalThis.__customShaderRuntime || {}; const mutationReason = globalThis.__customShaderMutationReason; const reasons = [mutationReason(aura.material.setUniform(state.textured, 'tint', [0.76, 0.84, 1, 1])), mutationReason(aura.material.setUniform(state.textured, 'uvScale', { x: 0.95, y: 1.1 })), mutationReason(aura.material.setUniform(state.textured, 'pulse', 0.55)), mutationReason(aura.material.setUniform(state.solid, 'pulse', 0.48)), mutationReason(aura.material.setCustomTexture(state.textured, state.altTexturePath))]; const brokenReason = mutationReason(aura.material.setUniform(state.broken, 'pulse', 0.5)); return Array.isArray(state.frames) && state.frames.length === 2 && state.frames[0] === 0 && state.frames[1] === 1 && reasons.every((reason) => reason === 'ok') && brokenReason === 'missing_material_handle' && state.initial?.textureOk === 'ok'; } catch (_) { return false; } })()",
1761
+ },
1762
+ ],
1763
+ source: `
1764
+ globalThis.__customShaderMutationReason = (result) => (
1765
+ result && result.ok === false && typeof result.reasonCode === 'string'
1766
+ ? result.reasonCode
1767
+ : 'ok'
1768
+ );
1769
+ globalThis.__customShaderMatchError = (factory, message) => {
1770
+ try {
1771
+ factory();
1772
+ return false;
1773
+ } catch (error) {
1774
+ return String(error && error.message ? error.message : error).includes(message);
1775
+ }
1776
+ };
1777
+ globalThis.__customShaderRuntime = {
1778
+ texturePath: 'src/cli/test-fixtures/terrain/terrain-grass.png',
1779
+ altTexturePath: 'src/cli/test-fixtures/terrain/terrain-rock.png',
1780
+ vertex: [
1781
+ 'struct CameraUniform { view : mat4x4<f32>, projection : mat4x4<f32> };',
1782
+ 'struct ModelUniform { model : mat4x4<f32> };',
1783
+ 'struct ProofUniforms { tint : vec4<f32>, uvScale : vec2<f32>, pulse : f32 };',
1784
+ 'struct VertexInput { @location(0) position : vec3<f32>, @location(1) normal : vec3<f32>, @location(2) uv : vec2<f32>, @location(3) color : vec4<f32> };',
1785
+ 'struct VertexOutput { @builtin(position) clipPosition : vec4<f32>, @location(0) uv : vec2<f32>, @location(1) normal : vec3<f32>, @location(2) color : vec4<f32> };',
1786
+ '@group(0) @binding(0) var<uniform> camera : CameraUniform;',
1787
+ '@group(1) @binding(0) var<uniform> model_uniform : ModelUniform;',
1788
+ '@group(2) @binding(0) var<uniform> proof : ProofUniforms;',
1789
+ '@vertex',
1790
+ 'fn vs_main(input : VertexInput) -> VertexOutput {',
1791
+ ' var out : VertexOutput;',
1792
+ ' let worldPosition = model_uniform.model * vec4<f32>(input.position, 1.0);',
1793
+ ' out.clipPosition = camera.projection * camera.view * worldPosition;',
1794
+ ' out.uv = input.uv * proof.uvScale;',
1795
+ ' out.normal = normalize((model_uniform.model * vec4<f32>(input.normal, 0.0)).xyz);',
1796
+ ' out.color = input.color;',
1797
+ ' return out;',
1798
+ '}',
1799
+ ].join('\\n'),
1800
+ texturedFragment: [
1801
+ '@group(3) @binding(0) var custom_texture : texture_2d<f32>;',
1802
+ '@group(3) @binding(1) var custom_sampler : sampler;',
1803
+ '@fragment',
1804
+ 'fn fs_main(input : VertexOutput) -> @location(0) vec4<f32> {',
1805
+ ' let normal = normalize(input.normal);',
1806
+ ' let lightDir = normalize(vec3<f32>(0.36, 0.88, 0.31));',
1807
+ ' let lambert = max(dot(normal, lightDir), 0.22);',
1808
+ ' let texel = textureSample(custom_texture, custom_sampler, fract(input.uv));',
1809
+ ' let shaded = texel.rgb * proof.tint.rgb * ((lambert * (0.72 + (proof.pulse * 0.28))) + 0.1);',
1810
+ ' return vec4<f32>(shaded, texel.a * proof.tint.a);',
1811
+ '}',
1812
+ ].join('\\n'),
1813
+ solidFragment: [
1814
+ '@fragment',
1815
+ 'fn fs_main(input : VertexOutput) -> @location(0) vec4<f32> {',
1816
+ ' let normal = normalize(input.normal);',
1817
+ ' let lightDir = normalize(vec3<f32>(0.36, 0.88, 0.31));',
1818
+ ' let lambert = max(dot(normal, lightDir), 0.2);',
1819
+ ' let shaded = proof.tint.rgb * ((lambert * (0.74 + (proof.pulse * 0.26))) + 0.12);',
1820
+ ' return vec4<f32>(shaded, proof.tint.a);',
1821
+ '}',
1822
+ ].join('\\n'),
1823
+ badFragment: 'not wgsl',
1824
+ floor: 0,
1825
+ cube: 0,
1826
+ plain: 0,
1827
+ textured: 0,
1828
+ solid: 0,
1829
+ broken: 0,
1830
+ frames: [],
1831
+ initial: {},
1832
+ };
1833
+ `,
1834
+ nativeFrames: 2,
1835
+ },
1836
+ {
1837
+ id: 'video-texture-runtime-native',
1838
+ modes: ['native'],
1839
+ namespaces: ['video', 'draw3d', 'camera3d', 'debug'],
1840
+ functions: [
1841
+ 'aura.video.load',
1842
+ 'aura.video.play',
1843
+ 'aura.video.pause',
1844
+ 'aura.video.stop',
1845
+ 'aura.video.seek',
1846
+ 'aura.video.getTexture',
1847
+ 'aura.video.getInfo',
1848
+ 'aura.video.setLooping',
1849
+ 'aura.video.unload',
1850
+ 'aura.draw3d.clear3d',
1851
+ 'aura.draw3d.billboard',
1852
+ 'aura.camera3d.perspective',
1853
+ 'aura.camera3d.setPosition',
1854
+ 'aura.camera3d.lookAt',
1855
+ 'aura.debug.inspectorStats',
1856
+ ],
1857
+ nativeChecks: [
1858
+ {
1859
+ id: 'video.surface.methods',
1860
+ expression: "(() => ['load','play','pause','stop','seek','getTexture','getInfo','setLooping','unload'].every((name) => typeof aura.video?.[name] === 'function'))()",
1861
+ },
1862
+ {
1863
+ id: 'video.texture-runtime.setup',
1864
+ expression: "(() => { try { const candidatePaths = ['../../../src/cli/test-fixtures/video/video-native.mp4', '../../../../src/cli/test-fixtures/video/video-native.mp4', '../../../../../src/cli/test-fixtures/video/video-native.mp4', '../../../../../../src/cli/test-fixtures/video/video-native.mp4', '../../../../../../../src/cli/test-fixtures/video/video-native.mp4', '../../../../../../../../src/cli/test-fixtures/video/video-native.mp4', '../../../../../../../../../src/cli/test-fixtures/video/video-native.mp4', 'src/cli/test-fixtures/video/video-native.mp4']; let handle = 0; let resolvedPath = null; for (const candidate of candidatePaths) { try { const loaded = aura.video.load(candidate, { type: 'mp4', looping: false }); if (Number.isInteger(loaded) && loaded > 0) { handle = loaded; resolvedPath = candidate; break; } } catch (_) {} } if (!Number.isInteger(handle) || handle <= 0) return false; const idleInfo = aura.video.getInfo(handle); aura.video.play(handle); const playingInfo = aura.video.getInfo(handle); aura.video.pause(handle); const pausedInfo = aura.video.getInfo(handle); aura.video.seek(handle, 0.2); aura.video.setLooping(handle, false); aura.video.play(handle); const textureHandle = aura.video.getTexture(handle); aura.camera3d.perspective(55, 0.1, 50); aura.camera3d.setPosition(0, 0, 4); aura.camera3d.lookAt(0, 0, 0); const baseDraw = aura.draw; aura.draw = function () { aura.draw3d.clear3d({ r: 0.01, g: 0.01, b: 0.015, a: 1 }); aura.draw3d.billboard(textureHandle, { x: 0, y: 0, z: 0, width: 2, height: 2, mode: 'face' }); baseDraw(); }; globalThis.__videoRuntime = { handle, textureHandle, resolvedPath }; return idleInfo?.state === 'idle' && idleInfo?.sourceKind === 'mp4' && playingInfo?.state === 'playing' && pausedInfo?.state === 'paused' && Number.isInteger(textureHandle) && textureHandle > 0 && Number(idleInfo?.frameCount || 0) >= 2 && Number(idleInfo?.width || 0) >= 1 && Number(idleInfo?.height || 0) >= 1; } catch (_) { return false; } })()",
1865
+ },
1866
+ ],
1867
+ nativePostChecks: [
1868
+ {
1869
+ id: 'video.texture-runtime.evidence',
1870
+ expression: "(() => { try { const state = globalThis.__videoRuntime || {}; aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); const scene3d = stats.scene3dRuntime || {}; const submission = scene3d.submission || {}; const resources = scene3d.resources || {}; const video = scene3d.video || {}; const info = aura.video.getInfo(state.handle); return Number.isInteger(state.handle) && state.handle > 0 && Number.isInteger(state.textureHandle) && state.textureHandle > 0 && typeof state.resolvedPath === 'string' && state.resolvedPath.length > 0 && !!info && info.sourceKind === 'mp4' && Number(info.frameCount || 0) >= 2 && Number(info.width || 0) >= 1 && Number(info.height || 0) >= 1 && Number(info.currentFrame || 0) >= 1 && Number(info.currentTime || 0) > 0 && ['playing', 'paused', 'stopped'].includes(info.state) && Number(video.activePlayerCount || 0) >= 1 && Number(video.totalTickUploadCount || 0) >= 1 && Number(video.totalProcessedUploadCount || 0) >= 1 && Number(video.lastUploadedVideoHandle || 0) === Number(state.handle) && Number(video.lastUploadedTextureHandle || 0) === Number(state.textureHandle) && Number(video.lastUploadedWidth || 0) >= 1 && Number(video.lastUploadedHeight || 0) >= 1 && Number(video.textureHandleCount || 0) >= 1 && Number(resources.videoTextureHandleCount || 0) >= 1 && Number(submission.billboardLastCommandCount || 0) >= 1 && Number(submission.billboardLastRenderedCount || 0) >= 1 && Number(submission.billboardLastBatchCount || 0) >= 1 && submission.billboardLastReasonCode === 'billboard_submitted'; } catch (_) { return false; } })()",
1871
+ debugExpression: "(() => { try { aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); const state = globalThis.__videoRuntime || {}; return { state, info: aura.video.getInfo(state.handle) || null, scene3dRuntime: stats.scene3dRuntime || null }; } catch (error) { return { debugError: String(error && error.message ? error.message : error) }; } })()",
1872
+ },
1873
+ ],
1874
+ source: `
1875
+ globalThis.__videoRuntime = { handle: 0, textureHandle: 0, resolvedPath: null };
1876
+ `,
1877
+ nativeFrames: 6,
1878
+ },
1879
+ {
1880
+ id: 'billboard-actor-effect-runtime-native',
1881
+ modes: ['native'],
1882
+ namespaces: ['video', 'mesh', 'material', 'draw3d', 'camera3d', 'debug'],
1883
+ functions: [
1884
+ 'aura.video.load',
1885
+ 'aura.video.play',
1886
+ 'aura.video.getTexture',
1887
+ 'aura.video.getInfo',
1888
+ 'aura.mesh.createBox',
1889
+ 'aura.material.create',
1890
+ 'aura.draw3d.drawMesh',
1891
+ 'aura.draw3d.clear3d',
1892
+ 'aura.draw3d.billboard',
1893
+ 'aura.camera3d.perspective',
1894
+ 'aura.camera3d.setPosition',
1895
+ 'aura.camera3d.lookAt',
1896
+ 'aura.debug.inspectorStats',
1897
+ ],
1898
+ nativeChecks: [
1899
+ {
1900
+ id: 'billboard.actor-effect.surface.methods',
1901
+ expression: "(() => ['load','play','getTexture','getInfo'].every((name) => typeof aura.video?.[name] === 'function') && typeof aura.mesh?.createBox === 'function' && typeof aura.material?.create === 'function' && ['drawMesh','clear3d','billboard'].every((name) => typeof aura.draw3d?.[name] === 'function') && ['perspective','setPosition','lookAt'].every((name) => typeof aura.camera3d?.[name] === 'function') && typeof aura.debug?.inspectorStats === 'function')()",
1902
+ },
1903
+ {
1904
+ id: 'billboard.actor-effect.runtime.setup',
1905
+ expression: `(() => { try { const resolvedPath = 'src/cli/test-fixtures/video/video-spritesheet.png'; const billboardVideoHandle = aura.video.load(resolvedPath, { type: 'spritesheet', columns: 2, rows: 1, frameCount: 2, fps: 12, looping: true }); aura.video.play(billboardVideoHandle); const billboardTexture = aura.video.getTexture(billboardVideoHandle); const billboardInfo = aura.video.getInfo(billboardVideoHandle); const atlasWidth = Number(billboardInfo?.width || 0); const atlasHeight = Number(billboardInfo?.height || 0); const frameWidth = atlasWidth / 2; const frameHeight = atlasHeight; if (!Number.isInteger(billboardTexture) || billboardTexture <= 0 || !Number.isFinite(atlasWidth) || atlasWidth <= 0 || !Number.isFinite(atlasHeight) || atlasHeight <= 0 || !Number.isFinite(frameWidth) || frameWidth <= 0 || !Number.isFinite(frameHeight) || frameHeight <= 0) return false; const floorMesh = aura.mesh.createBox(8, 0.25, 8); const coverMesh = aura.mesh.createBox(0.8, 2.2, 0.8); const floorMaterial = aura.material.create({ color: { r: 0.2, g: 0.24, b: 0.3, a: 1 }, roughness: 0.95, metallic: 0.02 }); const coverMaterial = aura.material.create({ color: { r: 0.42, g: 0.36, b: 0.32, a: 1 }, roughness: 0.9, metallic: 0.04 }); aura.camera3d.perspective(58, 0.1, 80); aura.camera3d.setPosition(0, 2.2, 5.4); aura.camera3d.lookAt(0, 0.8, 0); const baseDraw = aura.draw; globalThis.__billboardActorEffect = { resolvedPath, billboardTexture, billboardVideoHandle, atlasWidth, atlasHeight, frameWidth, frameHeight, floorMesh, coverMesh, floorMaterial, coverMaterial, frames: [] }; aura.draw = function () { const probe = globalThis.__billboardActorEffect || {}; const frameIndex = Array.isArray(probe.frames) ? probe.frames.length : 0; const cameraX = Number((Math.sin(frameIndex * 0.45) * 1.35).toFixed(3)); const cameraZ = Number((5.4 - (frameIndex * 0.16)).toFixed(3)); aura.camera3d.setPosition(cameraX, 2.2, cameraZ); aura.camera3d.lookAt(0, 0.8, 0); aura.draw3d.clear3d({ r: 0.025, g: 0.03, b: 0.04, a: 1 }); aura.draw3d.drawMesh(probe.floorMesh, probe.floorMaterial, { position: { x: 0, y: -1.1, z: 0 } }); aura.draw3d.drawMesh(probe.coverMesh, probe.coverMaterial, { position: { x: 0.45, y: -0.05, z: 0.75 } }); aura.draw3d.billboard(probe.billboardTexture, { x: -1.2, y: 0.1, z: 0.2, width: 1.1, height: 1.7, mode: 'face', frameX: 0, frameY: 0, frameW: probe.frameWidth, frameH: probe.frameHeight, atlasWidth: probe.atlasWidth, atlasHeight: probe.atlasHeight }); aura.draw3d.billboard(probe.billboardTexture, { x: 0, y: 0.1, z: -0.35, width: 1.1, height: 1.7, mode: 'face', frameX: 0, frameY: 0, frameW: probe.frameWidth, frameH: probe.frameHeight, atlasWidth: probe.atlasWidth, atlasHeight: probe.atlasHeight }); aura.draw3d.billboard(probe.billboardTexture, { x: 1.15, y: 0.1, z: -0.1, width: 1.1, height: 1.7, mode: 'face', frameX: 0, frameY: 0, frameW: probe.frameWidth, frameH: probe.frameHeight, atlasWidth: probe.atlasWidth, atlasHeight: probe.atlasHeight }); aura.draw3d.billboard(probe.billboardTexture, { x: 0.95, y: -0.05, z: 1.2, width: 1.3, height: 1.3, mode: 'axis', color: { r: 1, g: 0.9, b: 0.75, a: 0.85 }, frameX: probe.frameWidth, frameY: 0, frameW: probe.frameWidth, frameH: probe.frameHeight, atlasWidth: probe.atlasWidth, atlasHeight: probe.atlasHeight }); probe.frames.push({ frameIndex, cameraX, cameraZ, commandCount: 4, modes: 'face|axis', atlasFrameTrace: 'actor0|actor0|actor0|effect1' }); baseDraw(); }; return Number.isInteger(floorMesh) && floorMesh > 0 && Number.isInteger(coverMesh) && coverMesh > 0 && Number.isInteger(floorMaterial) && floorMaterial > 0 && Number.isInteger(coverMaterial) && coverMaterial > 0 && Number(billboardInfo?.frameCount || 0) === 2; } catch (_) { return false; } })()`,
1906
+ },
1907
+ ],
1908
+ nativePostChecks: [
1909
+ {
1910
+ id: 'billboard.actor-effect.runtime.evidence',
1911
+ expression: `(() => { try { const probe = globalThis.__billboardActorEffect || {}; const frames = Array.isArray(probe.frames) ? probe.frames : []; aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); const scene3d = stats.scene3dRuntime || {}; const submission = scene3d.submission || {}; const resources = scene3d.resources || {}; const billboardInfo = aura.video.getInfo(probe.billboardVideoHandle); const cameraTrace = new Set(frames.map((frame) => \`\${frame.cameraX}:\${frame.cameraZ}\`)); return typeof probe.resolvedPath === 'string' && probe.resolvedPath.length > 0 && Number.isInteger(probe.billboardTexture) && probe.billboardTexture > 0 && Number.isInteger(probe.billboardVideoHandle) && probe.billboardVideoHandle > 0 && Number(probe.frameWidth || 0) > 0 && Number(probe.frameHeight || 0) > 0 && Number(probe.atlasWidth || 0) === Number(probe.frameWidth || 0) * 2 && Number(probe.atlasHeight || 0) === Number(probe.frameHeight || 0) && frames.length === 6 && frames.every((frame) => frame.commandCount === 4 && frame.modes === 'face|axis' && frame.atlasFrameTrace === 'actor0|actor0|actor0|effect1') && cameraTrace.size >= 3 && Number(billboardInfo?.frameCount || 0) === 2 && Number(billboardInfo?.currentTime || 0) > 0 && Number(resources.videoTextureHandleCount || 0) >= 1 && Number(submission.billboardCommandsPending || 0) >= 4 && Number(submission.billboardUniqueTextureHandles || 0) === 1 && Number(submission.billboardLastCommandCount || 0) === 4 && Number(submission.billboardLastRenderedCount || 0) === 4 && Number(submission.billboardLastBatchCount || 0) === 1 && String(submission.billboardLastReasonCode || '') === 'billboard_submitted'; } catch (_) { return false; } })()`,
1912
+ debugExpression: `(() => { try { const probe = globalThis.__billboardActorEffect || {}; aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); return { probe, billboardInfo: aura.video.getInfo(probe.billboardVideoHandle) || null, scene3dRuntime: stats.scene3dRuntime || null }; } catch (error) { return { debugError: String(error && error.message ? error.message : error) }; } })()`,
1913
+ },
1914
+ ],
1915
+ source: `
1916
+ globalThis.__billboardActorEffect = { frames: [] };
1917
+ `,
1918
+ nativeFrames: 6,
1919
+ },
1920
+ {
1921
+ id: 'worldspace-ui-runtime-native',
1922
+ modes: ['native'],
1923
+ namespaces: ['video', 'mesh', 'material', 'draw2d', 'draw3d', 'camera3d', 'scene3d', 'debug'],
1924
+ functions: [
1925
+ 'aura.video.load',
1926
+ 'aura.video.play',
1927
+ 'aura.video.getTexture',
1928
+ 'aura.video.getInfo',
1929
+ 'aura.mesh.createBox',
1930
+ 'aura.material.create',
1931
+ 'aura.draw2d.text',
1932
+ 'aura.draw3d.clear3d',
1933
+ 'aura.draw3d.drawMesh',
1934
+ 'aura.draw3d.billboard',
1935
+ 'aura.camera3d.perspective',
1936
+ 'aura.camera3d.setPosition',
1937
+ 'aura.camera3d.lookAt',
1938
+ 'aura.scene3d.projectToViewport',
1939
+ 'aura.scene3d.createWorldUiLayer',
1940
+ 'aura.scene3d.getWorldUiState',
1941
+ 'aura.debug.inspectorStats',
1942
+ ],
1943
+ nativeChecks: [
1944
+ {
1945
+ id: 'worldspace-ui.surface.methods',
1946
+ expression: "(() => ['load','play','getTexture','getInfo'].every((name) => typeof aura.video?.[name] === 'function') && typeof aura.mesh?.createBox === 'function' && typeof aura.material?.create === 'function' && typeof aura.draw2d?.text === 'function' && ['clear3d','drawMesh','billboard'].every((name) => typeof aura.draw3d?.[name] === 'function') && ['perspective','setPosition','lookAt'].every((name) => typeof aura.camera3d?.[name] === 'function') && ['projectToViewport','createWorldUiLayer','getWorldUiState'].every((name) => typeof aura.scene3d?.[name] === 'function') && typeof aura.debug?.inspectorStats === 'function')()",
1947
+ },
1948
+ {
1949
+ id: 'worldspace-ui.runtime.setup',
1950
+ expression: `(() => { try { const resolvedPath = 'src/cli/test-fixtures/video/video-spritesheet.png'; const iconVideoHandle = aura.video.load(resolvedPath, { type: 'spritesheet', columns: 2, rows: 1, frameCount: 2, fps: 12, looping: true }); aura.video.play(iconVideoHandle); const iconTexture = aura.video.getTexture(iconVideoHandle); const floorMesh = aura.mesh.createBox(10, 0.2, 10); const actorMesh = aura.mesh.createBox(0.8, 1.8, 0.8); const floorMaterial = aura.material.create({ color: { r: 0.14, g: 0.16, b: 0.2, a: 1 }, roughness: 0.96, metallic: 0.02 }); const leaderMaterial = aura.material.create({ color: { r: 0.92, g: 0.46, b: 0.34, a: 1 }, roughness: 0.86, metallic: 0.03 }); const pickupMaterial = aura.material.create({ color: { r: 0.28, g: 0.84, b: 0.9, a: 1 }, roughness: 0.84, metallic: 0.05 }); const beaconMaterial = aura.material.create({ color: { r: 0.54, g: 0.92, b: 0.42, a: 1 }, roughness: 0.88, metallic: 0.04 }); aura.camera3d.perspective(56, 0.1, 80); aura.camera3d.setPosition(0, 3.2, 8.4); aura.camera3d.lookAt(0, 1.1, 0); const ui = aura.scene3d.createWorldUiLayer({ labelFontSize: 13, damageFontSize: 18, padding: 14 }); const state = globalThis.__worldspaceUiRuntime || {}; state.resolvedPath = resolvedPath; state.iconVideoHandle = iconVideoHandle; state.iconTexture = iconTexture; state.floorMesh = floorMesh; state.actorMesh = actorMesh; state.materials = { floorMaterial, leaderMaterial, pickupMaterial, beaconMaterial }; state.targets = { leader: { x: -1.3, y: 0, z: 0.15 }, pickup: { x: 0, y: 0, z: -0.5 }, beacon: { x: 1.5, y: 0, z: 0.55 } }; state.ui = ui; state.frames = []; state.projections = []; state.emitted = 0; state.initialProjection = aura.scene3d.projectToViewport({ x: state.targets.leader.x, y: 1.9, z: state.targets.leader.z }, { clamp: true, padding: 14 }); const callout = ui.upsertCallout('leader', () => state.targets.leader, { text: 'Guide', textureHandle: iconTexture, offset: { x: 0, y: 1.9, z: 0 }, width: 0.74, height: 0.74, screenOffset: { x: 0, y: -10 }, scaleByDistance: true, clampToViewport: true, markerColor: { r: 1, g: 0.95, b: 0.86, a: 0.95 }, labelColor: { r: 1, g: 0.96, b: 0.9, a: 1 } }); const label = ui.upsertLabel('pickup', 'Objective', () => state.targets.pickup, { offset: { x: 0, y: 1.35, z: 0 }, screenOffset: { x: 0, y: -12 }, clampToViewport: true, color: { r: 0.86, g: 0.94, b: 1, a: 1 } }); const marker = ui.upsertMarker('beacon', iconTexture, () => state.targets.beacon, { offset: { x: 0, y: 1.8, z: 0 }, width: 0.68, height: 0.68, mode: 'axis', scaleByDistance: true, markerColor: { r: 0.86, g: 1, b: 0.78, a: 0.92 } }); const baseUpdate = aura.update; const baseDraw = aura.draw; aura.update = function (dt) { const probe = globalThis.__worldspaceUiRuntime || {}; probe.frameCount = Number(probe.frameCount || 0) + 1; const elapsed = probe.frameCount / 60; const cameraX = Number((Math.sin(elapsed * 0.8) * 2.4).toFixed(3)); const cameraZ = Number((8.4 - (Math.cos(elapsed * 0.6) * 1.1)).toFixed(3)); aura.camera3d.setPosition(cameraX, 3.2, cameraZ); aura.camera3d.lookAt(0, 1.1, 0); probe.targets.pickup.x = Number((Math.sin(elapsed * 1.4) * 0.45).toFixed(3)); probe.targets.beacon.z = Number((0.55 + (Math.cos(elapsed * 1.2) * 0.38)).toFixed(3)); if (probe.frameCount === 4 || probe.frameCount === 12) { const emitted = probe.ui.emitDamageNumber('-24', () => probe.targets.leader, { offset: { x: 0, y: 1.55, z: 0 }, lifetime: 1.1, floatHeight: 0.82, color: { r: 1, g: 0.82, b: 0.38, a: 1 } }); if (emitted?.ok === true) probe.emitted = Number(probe.emitted || 0) + 1; } probe.ui.update(dt || (1 / 60)); const projection = aura.scene3d.projectToViewport({ x: probe.targets.pickup.x, y: 1.35, z: probe.targets.pickup.z }, { clamp: true, padding: 14 }); probe.projections.push({ frame: probe.frameCount, visible: projection?.visible === true, screenX: Number(projection?.clampedScreenX || 0), screenY: Number(projection?.clampedScreenY || 0) }); probe.frames.push({ frame: probe.frameCount, cameraX, cameraZ, pickupX: probe.targets.pickup.x, beaconZ: probe.targets.beacon.z }); if (typeof baseUpdate === 'function') baseUpdate(dt); }; aura.draw = function () { const probe = globalThis.__worldspaceUiRuntime || {}; aura.draw3d.clear3d({ r: 0.02, g: 0.022, b: 0.03, a: 1 }); aura.draw3d.drawMesh(probe.floorMesh, probe.materials.floorMaterial, { position: { x: 0, y: -0.1, z: 0 } }); aura.draw3d.drawMesh(probe.actorMesh, probe.materials.leaderMaterial, { position: { x: probe.targets.leader.x, y: 0.9, z: probe.targets.leader.z } }); aura.draw3d.drawMesh(probe.actorMesh, probe.materials.pickupMaterial, { position: { x: probe.targets.pickup.x, y: 0.9, z: probe.targets.pickup.z }, scale: { x: 0.7, y: 0.7, z: 0.7 } }); aura.draw3d.drawMesh(probe.actorMesh, probe.materials.beaconMaterial, { position: { x: probe.targets.beacon.x, y: 0.9, z: probe.targets.beacon.z }, scale: { x: 0.8, y: 1.1, z: 0.8 } }); probe.ui.draw(); if (typeof baseDraw === 'function') baseDraw(); }; return Number.isInteger(iconVideoHandle) && iconVideoHandle > 0 && Number.isInteger(iconTexture) && iconTexture > 0 && Number.isInteger(floorMesh) && floorMesh > 0 && Number.isInteger(actorMesh) && actorMesh > 0 && Number.isInteger(floorMaterial) && floorMaterial > 0 && Number.isInteger(leaderMaterial) && leaderMaterial > 0 && Number.isInteger(pickupMaterial) && pickupMaterial > 0 && Number.isInteger(beaconMaterial) && beaconMaterial > 0 && state.initialProjection?.ok === true && callout?.ok === true && label?.ok === true && marker?.ok === true; } catch (_) { return false; } })()`,
1951
+ },
1952
+ ],
1953
+ nativePostChecks: [
1954
+ {
1955
+ id: 'worldspace-ui.runtime.evidence',
1956
+ expression: `(() => { try { const state = globalThis.__worldspaceUiRuntime || {}; const layerState = state.ui?.getState ? state.ui.getState() : null; const summary = aura.scene3d.getWorldUiState(); aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); const scene3d = stats.scene3dRuntime || {}; const submission = scene3d.submission || {}; const video = scene3d.video || {}; const info = aura.video.getInfo(state.iconVideoHandle); const frames = Array.isArray(state.frames) ? state.frames : []; const projections = Array.isArray(state.projections) ? state.projections : []; return state.initialProjection?.ok === true && Number.isInteger(state.iconTexture) && state.iconTexture > 0 && typeof state.resolvedPath === 'string' && state.resolvedPath.length > 0 && Number(state.emitted || 0) === 2 && layerState?.ok === true && layerState?.pinnedEntryCount === 3 && Number(layerState?.activeDamageNumberCount || 0) >= 1 && Number(layerState?.lastMarkerDrawCount || 0) >= 2 && Number(layerState?.lastLabelDrawCount || 0) >= 2 && Number(layerState?.lastDamageDrawCount || 0) >= 1 && layerState?.lastReasonCode === 'world_ui_layer_drawn' && Number(layerState?.lastProjectionFingerprint || 0) > 0 && summary?.ok === true && summary?.layerCount === 1 && summary?.pinnedEntryCount === 3 && Number(summary?.activeDamageNumberCount || 0) >= 1 && Number(summary?.lastProjectionFingerprint || 0) > 0 && frames.length === 24 && projections.length === 24 && projections.every((entry) => Number.isFinite(entry.screenX) && Number.isFinite(entry.screenY)) && projections.some((entry) => entry.visible === true) && Number(info?.currentTime || 0) > 0 && Number(video?.activePlayerCount || 0) >= 1 && Number(submission?.billboardLastCommandCount || 0) >= 2 && Number(submission?.billboardLastRenderedCount || 0) >= 2 && Number(submission?.billboardLastBatchCount || 0) >= 1 && submission?.billboardLastReasonCode === 'billboard_submitted'; } catch (_) { return false; } })()`,
1957
+ debugExpression: `(() => { try { const state = globalThis.__worldspaceUiRuntime || {}; aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); return { state, layerState: state.ui?.getState ? state.ui.getState() : null, summary: aura.scene3d.getWorldUiState(), videoInfo: aura.video.getInfo(state.iconVideoHandle) || null, scene3dRuntime: stats.scene3dRuntime || null }; } catch (error) { return { debugError: String(error && error.message ? error.message : error) }; } })()`,
1958
+ },
1959
+ ],
1960
+ source: `
1961
+ globalThis.__worldspaceUiRuntime = {
1962
+ frameCount: 0,
1963
+ emitted: 0,
1964
+ frames: [],
1965
+ projections: [],
1966
+ initialProjection: null,
1967
+ };
1968
+ `,
1969
+ nativeFrames: 24,
1970
+ },
1971
+ {
1972
+ id: 'media-presentation-runtime-native',
1973
+ modes: ['native'],
1974
+ namespaces: ['audio', 'video', 'mesh', 'material', 'draw3d', 'camera3d', 'debug'],
1975
+ functions: [
1976
+ 'aura.audio.createSpatialEmitter',
1977
+ 'aura.video.createBillboardSurface',
1978
+ 'aura.video.createPresentation',
1979
+ 'aura.video.getInfo',
1980
+ 'aura.mesh.createBox',
1981
+ 'aura.material.create',
1982
+ 'aura.draw3d.clear3d',
1983
+ 'aura.draw3d.drawMesh',
1984
+ 'aura.draw3d.billboard',
1985
+ 'aura.camera3d.perspective',
1986
+ 'aura.camera3d.setPosition',
1987
+ 'aura.camera3d.lookAt',
1988
+ 'aura.debug.inspectorStats',
1989
+ ],
1990
+ nativeChecks: [
1991
+ {
1992
+ id: 'media.presentation.surface.methods',
1993
+ expression: "(() => typeof aura.audio?.createSpatialEmitter === 'function' && ['createBillboardSurface','createPresentation','getInfo'].every((name) => typeof aura.video?.[name] === 'function') && typeof aura.mesh?.createBox === 'function' && typeof aura.material?.create === 'function' && ['clear3d','drawMesh','billboard'].every((name) => typeof aura.draw3d?.[name] === 'function') && ['perspective','setPosition','lookAt'].every((name) => typeof aura.camera3d?.[name] === 'function') && typeof aura.debug?.inspectorStats === 'function')()",
1994
+ },
1995
+ {
1996
+ id: 'media.presentation.runtime.setup',
1997
+ expression: `(() => { try { const videoCandidates = ['../../../src/cli/test-fixtures/video/video-native.mp4', '../../../../src/cli/test-fixtures/video/video-native.mp4', '../../../../../src/cli/test-fixtures/video/video-native.mp4', '../../../../../../src/cli/test-fixtures/video/video-native.mp4', '../../../../../../../src/cli/test-fixtures/video/video-native.mp4', 'src/cli/test-fixtures/video/video-native.mp4']; const audioCandidates = ['audio/presentation-beacon.wav', 'assets/audio/presentation-beacon.wav']; const resolveVideoPath = () => { for (const candidate of videoCandidates) { try { const surface = aura.video.createBillboardSurface(candidate, { target: { x: 0, y: 0, z: 0 }, width: 1, height: 1, loadOptions: { type: 'mp4', looping: true } }); const played = surface.play(); const state = surface.getState(); surface.unload(); if (played?.ok === true && Number.isInteger(state?.handle) && state.handle > 0 && Number.isInteger(state?.textureHandle) && state.textureHandle > 0 && state?.info?.sourceKind === 'mp4') return candidate; } catch (_) {} } return null; }; const resolveAudioPath = () => { for (const candidate of audioCandidates) { try { const emitter = aura.audio.createSpatialEmitter(candidate, { position: { x: 0, y: 0, z: 0 }, syncListener: false, refDistance: 1.5, maxDistance: 8, rolloff: 1.1 }); const played = emitter.play({ volume: 0.02 }); if (played?.ok === true && Number.isInteger(played.handle) && played.handle > 0) { emitter.stop(); return candidate; } } catch (_) {} } return null; }; const videoPath = resolveVideoPath(); const audioPath = resolveAudioPath(); const state = globalThis.__mediaPresentationRuntime || {}; state.videoPath = videoPath; state.audioPath = audioPath; if (!videoPath || !audioPath) return false; const floorMesh = aura.mesh.createBox(10, 0.2, 10); const screenMesh = aura.mesh.createBox(2.95, 1.8, 0.16); const standMesh = aura.mesh.createBox(0.32, 2.2, 0.32); const beaconMesh = aura.mesh.createBox(0.7, 1.6, 0.7); const floorMaterial = aura.material.create({ color: { r: 0.15, g: 0.17, b: 0.2, a: 1 }, roughness: 0.96, metallic: 0.02 }); const screenMaterial = aura.material.create({ color: { r: 0.12, g: 0.13, b: 0.16, a: 1 }, roughness: 0.82, metallic: 0.12 }); const standMaterial = aura.material.create({ color: { r: 0.42, g: 0.36, b: 0.31, a: 1 }, roughness: 0.88, metallic: 0.04 }); const beaconMaterial = aura.material.create({ color: { r: 0.32, g: 0.86, b: 0.98, a: 1 }, roughness: 0.84, metallic: 0.06 }); aura.camera3d.perspective(56, 0.1, 80); aura.camera3d.setPosition(0, 3.1, 8.1); aura.camera3d.lookAt(0, 1.2, -0.4); state.floorMesh = floorMesh; state.screenMesh = screenMesh; state.standMesh = standMesh; state.beaconMesh = beaconMesh; state.materials = { floorMaterial, screenMaterial, standMaterial, beaconMaterial }; state.targets = { screen: { x: 0, y: 1.4, z: -1.45 }, beacon: { x: 1.55, y: 0.8, z: 0.55 } }; state.frames = []; state.elapsed = 0; state.presentation = aura.video.createPresentation(videoPath, { target: () => state.targets.screen, audioPath, width: 2.62, height: 1.46, mode: 'face', offset: { x: 0, y: 0, z: 0.11 }, loadOptions: { type: 'mp4', looping: true }, audio: { offset: { x: 0, y: 0, z: 0.14 }, refDistance: 2.4, maxDistance: 16, rolloff: 1.12, volume: 0.14, loop: true, seekStrategy: 'restart' } }); state.beaconSurface = aura.video.createBillboardSurface(videoPath, { target: () => state.targets.beacon, width: 0.82, height: 0.82, mode: 'axis', offset: { x: 0, y: 1.25, z: 0 }, loadOptions: { type: 'mp4', looping: true } }); state.beaconEmitter = aura.audio.createSpatialEmitter(audioPath, { target: () => state.targets.beacon, offset: { x: 0, y: 0.85, z: 0 }, volume: 0.09, loop: true, refDistance: 1.8, maxDistance: 12, rolloff: 1.3, occlusion: 0.18 }); state.attachPresentation = state.presentation.attach(() => state.targets.screen, { surface: { offset: { x: 0, y: 0, z: 0.11 }, width: 2.62, height: 1.46 }, audio: { offset: { x: 0, y: 0, z: 0.14 } } }); state.attachSurface = state.beaconSurface.attach(() => state.targets.beacon, { offset: { x: 0, y: 1.25, z: 0 }, width: 0.82, height: 0.82, mode: 'axis' }); state.attachEmitter = state.beaconEmitter.attach(() => state.targets.beacon, { offset: { x: 0, y: 0.85, z: 0 } }); state.presentationPlay = state.presentation.play(); state.surfacePlay = state.beaconSurface.play(); state.emitterPlay = state.beaconEmitter.play({ volume: 0.09, loop: true }); state.presentationSeek = state.presentation.seek(0.04); state.surfaceSeek = state.beaconSurface.seek(0.02); state.occlusionResult = state.beaconEmitter.setOcclusion(0.22); const baseUpdate = aura.update; const baseDraw = aura.draw; aura.update = function (dt) { const probe = globalThis.__mediaPresentationRuntime || {}; const delta = Number(dt || (1 / 60)); probe.elapsed = Number(probe.elapsed || 0) + delta; const frame = Array.isArray(probe.frames) ? (probe.frames.length + 1) : 1; const cameraX = Number((Math.sin(probe.elapsed * 0.75) * 2.1).toFixed(3)); const cameraZ = Number((8.1 - (Math.cos(probe.elapsed * 0.6) * 0.95)).toFixed(3)); aura.camera3d.setPosition(cameraX, 3.1, cameraZ); aura.camera3d.lookAt(0, 1.2, -0.35); probe.targets.beacon.x = Number((1.55 + (Math.sin(probe.elapsed * 1.25) * 0.36)).toFixed(3)); probe.targets.beacon.z = Number((0.55 + (Math.cos(probe.elapsed * 1.1) * 0.42)).toFixed(3)); probe.targets.screen.x = Number((Math.sin(probe.elapsed * 0.35) * 0.18).toFixed(3)); probe.presentation.update(); probe.beaconSurface.update(); probe.beaconEmitter.update(); probe.frames.push({ frame, cameraX, cameraZ, beaconX: probe.targets.beacon.x, beaconZ: probe.targets.beacon.z, screenX: probe.targets.screen.x }); if (typeof baseUpdate === 'function') baseUpdate(dt); }; aura.draw = function () { const probe = globalThis.__mediaPresentationRuntime || {}; aura.draw3d.clear3d({ r: 0.018, g: 0.02, b: 0.028, a: 1 }); aura.draw3d.drawMesh(probe.floorMesh, probe.materials.floorMaterial, { position: { x: 0, y: -0.1, z: 0 } }); aura.draw3d.drawMesh(probe.standMesh, probe.materials.standMaterial, { position: { x: probe.targets.screen.x, y: 0.35, z: probe.targets.screen.z } }); aura.draw3d.drawMesh(probe.screenMesh, probe.materials.screenMaterial, { position: { x: probe.targets.screen.x, y: probe.targets.screen.y, z: probe.targets.screen.z } }); aura.draw3d.drawMesh(probe.beaconMesh, probe.materials.beaconMaterial, { position: { x: probe.targets.beacon.x, y: probe.targets.beacon.y, z: probe.targets.beacon.z } }); probe.presentation.draw(); probe.beaconSurface.draw({ color: { r: 0.92, g: 0.98, b: 1, a: 0.9 } }); if (typeof baseDraw === 'function') baseDraw(); }; return state.attachPresentation?.ok === true && state.attachSurface?.ok === true && state.attachEmitter?.ok === true && state.presentationPlay?.ok === true && state.presentationPlay?.audioResult?.ok === true && state.surfacePlay?.ok === true && state.emitterPlay?.ok === true && state.presentationSeek?.ok === true && state.surfaceSeek?.ok === true && state.occlusionResult?.ok === true; } catch (_) { return false; } })()`,
1998
+ },
1999
+ ],
2000
+ nativePostChecks: [
2001
+ {
2002
+ id: 'media.presentation.runtime.evidence',
2003
+ expression: `(() => { try { const state = globalThis.__mediaPresentationRuntime || {}; const frames = Array.isArray(state.frames) ? state.frames : []; const presentationState = state.presentation?.getState ? state.presentation.getState() : null; const beaconSurfaceState = state.beaconSurface?.getState ? state.beaconSurface.getState() : null; const beaconEmitterState = state.beaconEmitter?.getState ? state.beaconEmitter.getState() : null; aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); const scene3d = stats.scene3dRuntime || {}; const submission = scene3d.submission || {}; const resources = scene3d.resources || {}; const video = scene3d.video || {}; const presentationInfo = aura.video.getInfo(presentationState?.surface?.handle || 0); const beaconInfo = aura.video.getInfo(beaconSurfaceState?.handle || 0); const cameraTrace = new Set(frames.map((entry) => \`\${entry.cameraX}:\${entry.cameraZ}\`)); const beaconTrace = new Set(frames.map((entry) => \`\${entry.beaconX}:\${entry.beaconZ}\`)); return typeof state.videoPath === 'string' && state.videoPath.includes('video-native.mp4') && typeof state.audioPath === 'string' && state.audioPath.includes('presentation-beacon.wav') && presentationState?.ok === true && Number.isInteger(presentationState?.surface?.handle) && presentationState.surface.handle > 0 && Number.isInteger(presentationState?.surface?.textureHandle) && presentationState.surface.textureHandle > 0 && presentationState?.surface?.info?.sourceKind === 'mp4' && Number.isInteger(presentationState?.emitter?.handle) && presentationState.emitter.handle > 0 && typeof presentationState?.emitter?.playbackState === 'string' && presentationState.emitter.listener != null && beaconSurfaceState?.ok === true && Number.isInteger(beaconSurfaceState?.handle) && beaconSurfaceState.handle > 0 && Number.isInteger(beaconSurfaceState?.textureHandle) && beaconSurfaceState.textureHandle > 0 && beaconSurfaceState?.info?.sourceKind === 'mp4' && beaconEmitterState?.ok === true && Number.isInteger(beaconEmitterState?.handle) && beaconEmitterState.handle > 0 && beaconEmitterState.attached === true && typeof beaconEmitterState?.playbackState === 'string' && Math.abs(Number(beaconEmitterState.occlusion || 0) - 0.22) < 0.001 && frames.length === 18 && cameraTrace.size >= 3 && beaconTrace.size >= 3 && Number(presentationInfo?.currentTime || 0) > 0 && Number(beaconInfo?.currentTime || 0) > 0 && presentationInfo?.sourceKind === 'mp4' && beaconInfo?.sourceKind === 'mp4' && Number(presentationInfo?.textureHandle || 0) === Number(presentationState.surface.textureHandle || 0) && Number(beaconInfo?.textureHandle || 0) === Number(beaconSurfaceState.textureHandle || 0) && Number(video.activePlayerCount || 0) >= 2 && Number(video.totalTickUploadCount || 0) >= 2 && Number(video.totalProcessedUploadCount || 0) >= 2 && Number(video.textureHandleCount || 0) >= 2 && Number(resources.videoTextureHandleCount || 0) >= 2 && Number(submission.billboardLastCommandCount || 0) >= 2 && Number(submission.billboardLastRenderedCount || 0) >= 2 && Number(submission.billboardLastBatchCount || 0) >= 1 && submission.billboardLastReasonCode === 'billboard_submitted'; } catch (_) { return false; } })()`,
2004
+ debugExpression: `(() => { try { const state = globalThis.__mediaPresentationRuntime || {}; aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); return { state: { videoPath: state.videoPath || null, audioPath: state.audioPath || null, frames: Array.isArray(state.frames) ? state.frames : [] }, presentationState: state.presentation?.getState ? state.presentation.getState() : null, beaconSurfaceState: state.beaconSurface?.getState ? state.beaconSurface.getState() : null, beaconEmitterState: state.beaconEmitter?.getState ? state.beaconEmitter.getState() : null, scene3dRuntime: stats.scene3dRuntime || null }; } catch (error) { return { debugError: String(error && error.message ? error.message : error) }; } })()`,
2005
+ },
2006
+ ],
2007
+ source: `
2008
+ globalThis.__mediaPresentationRuntime = {
2009
+ elapsed: 0,
2010
+ frames: [],
2011
+ videoPath: null,
2012
+ audioPath: null,
2013
+ };
2014
+ `,
2015
+ nativeFrames: 18,
2016
+ },
2017
+ {
2018
+ id: 'threejs-morph-target-runtime',
2019
+ modes: ['native'],
2020
+ namespaces: ['mesh', 'material', 'draw3d', 'camera3d', 'debug'],
2021
+ functions: [
2022
+ 'aura.mesh.createBox',
2023
+ 'aura.mesh.setMorphTargets',
2024
+ 'aura.mesh.setMorphWeights',
2025
+ 'aura.mesh.getData',
2026
+ 'aura.material.create',
2027
+ 'aura.draw3d.drawMesh',
2028
+ 'aura.draw3d.clear3d',
2029
+ 'aura.camera3d.perspective',
2030
+ 'aura.camera3d.setPosition',
2031
+ 'aura.camera3d.lookAt',
2032
+ 'aura.debug.inspectorStats',
2033
+ ],
2034
+ nativeChecks: [
2035
+ {
2036
+ id: 'mesh.morph-runtime.surface.methods',
2037
+ expression: "(() => ['createBox','setMorphTargets','setMorphWeights','getData'].every((name) => typeof aura.mesh?.[name] === 'function') && typeof aura.material?.create === 'function' && typeof aura.draw3d?.drawMesh === 'function' && typeof aura.draw3d?.clear3d === 'function' && ['perspective','setPosition','lookAt'].every((name) => typeof aura.camera3d?.[name] === 'function') && typeof aura.debug?.inspectorStats === 'function')()",
2038
+ },
2039
+ {
2040
+ id: 'mesh.morph-runtime.setup',
2041
+ expression: "(() => { try { const mesh = aura.mesh.createBox(1, 1, 1); const initial = aura.mesh.getData(mesh); if (!initial || Number(initial.vertexCount || 0) <= 0) return false; const material = aura.material.create({ color: { r: 0.76, g: 0.68, b: 0.9, a: 1 }, roughness: 0.72, metallic: 0.08 }); const makeTarget = (offset) => ({ positions: Array.from({ length: initial.vertexCount * 3 }, (_, index) => (index % 3 === 0 ? offset : 0)), normals: Array.from({ length: initial.vertexCount * 3 }, () => 0) }); aura.mesh.setMorphTargets(mesh, [makeTarget(0.18), makeTarget(-0.11), makeTarget(0.07), makeTarget(0.03)]); aura.mesh.setMorphWeights(mesh, [0.4, 0.0, 0.0, 0.0]); const updated = aura.mesh.getData(mesh); aura.camera3d.perspective(60, 0.1, 100); aura.camera3d.setPosition(0, 0, 4); aura.camera3d.lookAt(0, 0, 0); const baseDraw = aura.draw; aura.draw = function () { aura.draw3d.clear3d({ r: 0.025, g: 0.025, b: 0.035, a: 1 }); aura.draw3d.drawMesh(mesh, material, { position: { x: 0, y: 0, z: 0 } }); baseDraw(); }; globalThis.__morphRuntime = { mesh, material, morphTargetCount: Number(updated?.morphTargetCount || 0) }; return Number.isInteger(mesh) && mesh > 0 && Number.isInteger(material) && material > 0 && Number(updated?.morphTargetCount || 0) === 4; } catch (_) { return false; } })()",
2042
+ },
2043
+ ],
2044
+ nativePostChecks: [
2045
+ {
2046
+ id: 'mesh.morph-runtime.evidence',
2047
+ expression: "(() => { try { const state = globalThis.__morphRuntime || {}; aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); const scene3d = stats.scene3dRuntime || {}; const submission = scene3d.submission || {}; const resources = scene3d.resources || {}; return Number.isInteger(state.mesh) && state.mesh > 0 && Number.isInteger(state.material) && state.material > 0 && Number(state.morphTargetCount || 0) === 4 && Number(resources.morphTrackedMeshCount || 0) >= 1 && Number(resources.morphPendingUploadCount || 0) === 0 && Number(submission.morphCandidateDrawCount || 0) >= 1 && Number(submission.morphPreparedBindGroupCount || 0) >= 1 && Number(submission.morphExecutedBindGroupCount || 0) >= 1 && Number(submission.morphExecutedMeshCount || 0) >= 1 && Number(submission.morphExecutedNonZeroWeightDrawCount || 0) >= 1 && Number(submission.morphExecutedNonZeroWeightMeshCount || 0) >= 1 && submission.morphLastReasonCode === 'live_non_zero_weights'; } catch (_) { return false; } })()",
2048
+ debugExpression: "(() => { try { aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats() || {}; aura.debug.enableInspector(false); return { state: globalThis.__morphRuntime || null, scene3dRuntime: stats.scene3dRuntime || null, meshData: aura.mesh.getData(globalThis.__morphRuntime?.mesh || 0) || null }; } catch (error) { return { debugError: String(error && error.message ? error.message : error) }; } })()",
2049
+ },
2050
+ ],
2051
+ source: `
2052
+ globalThis.__morphRuntime = { mesh: 0, material: 0, morphTargetCount: 0 };
2053
+ `,
2054
+ nativeFrames: 4,
2055
+ },
2056
+ {
2057
+ id: 'threejs-scene3d-clip-skinning-runtime',
2058
+ modes: ['native'],
2059
+ namespaces: ['scene3d', 'debug'],
2060
+ functions: [
2061
+ 'aura.scene3d.createClip',
2062
+ 'aura.scene3d.playClip',
2063
+ 'aura.scene3d.pauseClip',
2064
+ 'aura.scene3d.resumeClip',
2065
+ 'aura.scene3d.seekClip',
2066
+ 'aura.scene3d.setClipWeight',
2067
+ 'aura.scene3d.setClipLoop',
2068
+ 'aura.scene3d.setClipSkinning',
2069
+ 'aura.scene3d.crossfadeClips',
2070
+ 'aura.scene3d.updateClips',
2071
+ 'aura.scene3d.onClipEvent',
2072
+ 'aura.scene3d.getClipState',
2073
+ 'aura.debug.inspectorStats',
2074
+ ],
2075
+ nativeChecks: [
2076
+ {
2077
+ id: 'scene3d.clip.surface.methods',
2078
+ expression: "(() => ['createClip','playClip','pauseClip','resumeClip','seekClip','setClipWeight','setClipLoop','setClipSkinning','crossfadeClips','updateClips','onClipEvent','getClipState'].every((name) => typeof aura.scene3d?.[name] === 'function'))()",
2079
+ },
2080
+ {
2081
+ id: 'scene3d.clip-skinning.deterministic',
2082
+ expression: "(() => { const runSample = () => { const nodeId = aura.scene3d.createNode(); const clipA = aura.scene3d.createClip({ nodeId, name: 'idle', duration: 1, time: 0, playing: true, loop: false, weight: 1, skinningInfluence: 1, boneCount: 4 }); const clipB = aura.scene3d.createClip({ nodeId, name: 'run', duration: 1, time: 0, playing: false, loop: true, weight: 0, skinningInfluence: 0.5, boneCount: 6 }); if (!clipA?.ok || !clipB?.ok) return null; const clipAId = clipA.clipId; const clipBId = clipB.clipId; const calls = []; const early = aura.scene3d.onClipEvent(clipAId, (evt) => calls.push(`early:${evt.type}:${evt.tag || ''}:${evt.loops || 0}`), 5); const late = aura.scene3d.onClipEvent(clipAId, (evt) => calls.push(`late:${evt.type}:${evt.tag || ''}:${evt.loops || 0}`), 20); const fade = aura.scene3d.crossfadeClips(clipAId, clipBId, { duration: 0.5, toTime: 0.2, eventTag: 'mix' }); const stepA = aura.scene3d.updateClips(0.5); const skin = aura.scene3d.setClipSkinning(clipBId, { influence: 0.75, boneCount: 8 }); const stepB = aura.scene3d.updateClips(0.25); const stateA = aura.scene3d.getClipState(clipAId); const stateB = aura.scene3d.getClipState(clipBId); aura.debug.enableInspector(true); const stats = aura.debug.inspectorStats(); aura.debug.enableInspector(false); const anim = stats?.scene3dRuntime?.animation || {}; aura.scene3d.removeNode(nodeId); return { fade: fade?.ok === true, stepA: stepA?.ok === true, skin: skin?.ok === true, stepB: stepB?.ok === true, early: early?.ok === true, late: late?.ok === true, stateAPlaying: stateA?.playing === false, stateACompleted: stateA?.completed === true, stateAWeight: stateA ? Number(stateA.weight.toFixed(6)) : null, stateBPlaying: stateB?.playing === true, stateBTime: stateB ? Number(stateB.time.toFixed(6)) : null, stateBWeight: stateB ? Number(stateB.weight.toFixed(6)) : null, stateBSkinInfluence: stateB ? Number((stateB.skinning?.influence ?? 0).toFixed(6)) : null, stateBBoneCount: stateB?.skinning?.boneCount ?? 0, calls: calls.join('|'), anim: { clipCount: anim.clipCount, playingClipCount: anim.playingClipCount, transitionCount: anim.transitionCount, activeWeightSum: Number((anim.activeWeightSum ?? 0).toFixed(6)), blendEventsDispatched: anim.blendEventsDispatched, skinnedClipCount: anim.skinnedClipCount, totalBoneCount: anim.totalBoneCount, skinningInfluenceSum: Number((anim.skinningInfluenceSum ?? 0).toFixed(6)), skinningUpdates: anim.skinningUpdates } }; }; const first = runSample(); const second = runSample(); if (!first || !second) return false; const stableFirst = JSON.stringify({ ...first, anim: { ...first.anim, blendEventsDispatched: first.anim.blendEventsDispatched > 0 ? 1 : 0, skinningUpdates: first.anim.skinningUpdates > 0 ? 1 : 0 } }); const stableSecond = JSON.stringify({ ...second, anim: { ...second.anim, blendEventsDispatched: second.anim.blendEventsDispatched > 0 ? 1 : 0, skinningUpdates: second.anim.skinningUpdates > 0 ? 1 : 0 } }); return stableFirst === stableSecond && first.fade && first.stepA && first.skin && first.stepB && first.early && first.late && first.stateAPlaying && first.stateACompleted && first.stateAWeight === 0 && first.stateBPlaying && first.stateBTime === 0.95 && first.stateBWeight === 1 && first.stateBSkinInfluence === 0.75 && first.stateBBoneCount === 8 && first.calls === 'early:blend_complete:mix:0|late:blend_complete:mix:0' && first.anim.clipCount === 2 && first.anim.playingClipCount === 1 && first.anim.transitionCount === 0 && first.anim.activeWeightSum === 1 && first.anim.skinnedClipCount === 2 && first.anim.totalBoneCount === 12 && first.anim.skinningInfluenceSum === 1.75 && first.anim.blendEventsDispatched >= 1 && first.anim.skinningUpdates >= 1; })()",
2083
+ },
2084
+ {
2085
+ id: 'scene3d.clip.reason-codes',
2086
+ expression: "(() => { const nodeId = aura.scene3d.createNode(); const invalidOptions = aura.scene3d.createClip(null); const invalidNode = aura.scene3d.createClip({ nodeId: 999999, duration: 1 }); const invalidDuration = aura.scene3d.createClip({ nodeId, duration: 0 }); const invalidName = aura.scene3d.createClip({ nodeId, duration: 1, name: ' ' }); const invalidWeight = aura.scene3d.createClip({ nodeId, duration: 1, weight: 2 }); const invalidSkinInfluence = aura.scene3d.createClip({ nodeId, duration: 1, skinningInfluence: 2 }); const invalidBoneCount = aura.scene3d.createClip({ nodeId, duration: 1, boneCount: -1 }); const createdA = aura.scene3d.createClip({ nodeId, duration: 1 }); const createdB = aura.scene3d.createClip({ nodeId, duration: 1 }); if (!createdA?.ok || !createdB?.ok) return false; const clipAId = createdA.clipId; const clipBId = createdB.clipId; const invalidClipId = aura.scene3d.playClip('oops'); const missingClip = aura.scene3d.playClip(999999); const invalidSeek = aura.scene3d.seekClip(clipAId, -1); const invalidSetWeight = aura.scene3d.setClipWeight(clipAId, 2); const invalidSetLoop = aura.scene3d.setClipLoop(clipAId, 'yes'); const invalidSkinOptions = aura.scene3d.setClipSkinning(clipAId, null); const invalidSetSkinInfluence = aura.scene3d.setClipSkinning(clipAId, { influence: 2 }); const invalidSetBoneCount = aura.scene3d.setClipSkinning(clipAId, { boneCount: -1 }); const invalidCrossfadeOptions = aura.scene3d.crossfadeClips(clipAId, clipBId, null); const invalidCrossfadeDuration = aura.scene3d.crossfadeClips(clipAId, clipBId, { duration: 0 }); const invalidTargetClip = aura.scene3d.crossfadeClips(clipAId, clipAId, { duration: 0.2 }); const missingTargetClip = aura.scene3d.crossfadeClips(clipAId, 999999, { duration: 0.2 }); const invalidOnEvent = aura.scene3d.onClipEvent(clipAId, null); const invalidDt = aura.scene3d.updateClips(0); aura.scene3d.removeNode(nodeId); return invalidOptions?.reason === 'invalid_clip_options' && invalidNode?.reason === 'invalid_node_id' && invalidDuration?.reason === 'invalid_clip_duration' && invalidName?.reason === 'invalid_clip_name' && invalidWeight?.reason === 'invalid_weight' && invalidSkinInfluence?.reason === 'invalid_skinning_influence' && invalidBoneCount?.reason === 'invalid_skinning_bone_count' && invalidClipId?.reason === 'invalid_clip_id' && missingClip?.reason === 'missing_clip' && invalidSeek?.reason === 'invalid_time' && invalidSetWeight?.reason === 'invalid_weight' && invalidSetLoop?.reason === 'invalid_loop_flag' && invalidSkinOptions?.reason === 'invalid_skinning_options' && invalidSetSkinInfluence?.reason === 'invalid_skinning_influence' && invalidSetBoneCount?.reason === 'invalid_skinning_bone_count' && invalidCrossfadeOptions?.reason === 'invalid_crossfade_options' && invalidCrossfadeDuration?.reason === 'invalid_crossfade_duration' && invalidTargetClip?.reason === 'invalid_target_clip' && missingTargetClip?.reason === 'missing_target_clip' && invalidOnEvent?.reason === 'invalid_callback' && invalidDt?.reason === 'invalid_dt'; })()",
2087
+ },
2088
+ ],
2089
+ source: `
2090
+ aura.setup = function () {};
2091
+ `,
2092
+ nativeFrames: 2,
2093
+ }
2094
+ ];