@auraindustry/aurajs 0.0.7 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (334) hide show
  1. package/README.md +98 -2
  2. package/benchmarks/perf-thresholds.json +54 -0
  3. package/package.json +4 -7
  4. package/src/asset-pack.mjs +5 -1
  5. package/src/authored-project.mjs +1449 -0
  6. package/src/authored-runtime.mjs +2016 -0
  7. package/src/authoring/avatar-animation-graph.mjs +648 -0
  8. package/src/bin-integrity.mjs +272 -0
  9. package/src/build-contract/assets.mjs +130 -0
  10. package/src/build-contract/capabilities.mjs +116 -0
  11. package/src/build-contract/constants.mjs +6 -0
  12. package/src/build-contract/helpers.mjs +44 -0
  13. package/src/build-contract/web-templates.mjs +5993 -0
  14. package/src/build-contract.mjs +27 -2910
  15. package/src/bundler.mjs +188 -55
  16. package/src/cli.mjs +4825 -1512
  17. package/src/commands/project-authoring.mjs +434 -0
  18. package/src/config.mjs +27 -0
  19. package/src/conformance/cases/app-and-ui-runtime-cases.mjs +3309 -0
  20. package/src/conformance/cases/core-runtime-cases.mjs +1431 -0
  21. package/src/conformance/cases/index.mjs +11 -0
  22. package/src/conformance/cases/scene3d-and-media-cases.mjs +2094 -0
  23. package/src/conformance/cases/systems-and-gameplay-cases.mjs +1776 -0
  24. package/src/conformance/shared.mjs +27 -0
  25. package/src/conformance-runner.mjs +25 -13
  26. package/src/conformance.mjs +619 -4020
  27. package/src/cutscene.mjs +362 -5
  28. package/src/dev-cli-action.mjs +249 -0
  29. package/src/dev-cli-inspect.mjs +92 -0
  30. package/src/dev-cli-state.mjs +80 -0
  31. package/src/external-asset-cache.mjs +587 -0
  32. package/src/external-asset-policy.mjs +217 -0
  33. package/src/external-package-surface.mjs +206 -0
  34. package/src/game-action-runtime.mjs +869 -0
  35. package/src/game-state-runtime.mjs +206 -6
  36. package/src/headless-action.mjs +186 -0
  37. package/src/headless-test/runtime-animation.mjs +1173 -0
  38. package/src/headless-test/runtime-coordinator.mjs +1514 -0
  39. package/src/headless-test/runtime-primitives.mjs +320 -0
  40. package/src/headless-test/runtime-world.mjs +2253 -0
  41. package/src/headless-test.mjs +392 -4298
  42. package/src/host-binary.mjs +342 -14
  43. package/src/icon-discovery.mjs +64 -0
  44. package/src/make-catalog.mjs +109 -0
  45. package/src/make.mjs +197 -0
  46. package/src/package-integrity.mjs +586 -0
  47. package/src/perf-benchmark.mjs +353 -0
  48. package/src/postinstall.mjs +5 -5
  49. package/src/prefabs/index.mjs +34 -0
  50. package/src/prefabs/scene-serialization.mjs +184 -0
  51. package/src/project-importer.mjs +620 -0
  52. package/src/project-registry.mjs +24 -0
  53. package/src/publish-command.mjs +195 -0
  54. package/src/publish-env-example.mjs +83 -0
  55. package/src/publish-validation.mjs +708 -0
  56. package/src/retro/assets/compile.mjs +232 -0
  57. package/src/retro/backend-gba/authoring.mjs +1029 -0
  58. package/src/retro/backend-gba/rom.mjs +363 -0
  59. package/src/retro/backend-gbc/rom.mjs +85 -0
  60. package/src/retro/build.mjs +278 -0
  61. package/src/retro/cli/commands.mjs +292 -0
  62. package/src/retro/cli/templates.mjs +84 -0
  63. package/src/retro/diagnostics/catalog.mjs +110 -0
  64. package/src/retro/diagnostics/emit.mjs +72 -0
  65. package/src/retro/emulator/case-overlay.mjs +64 -0
  66. package/src/retro/emulator/discovery.mjs +158 -0
  67. package/src/retro/emulator/macos-case-overlay.swift +220 -0
  68. package/src/retro/emulator/profiles.mjs +146 -0
  69. package/src/retro/emulator/runner.mjs +289 -0
  70. package/src/retro/frontend/load-project.mjs +98 -0
  71. package/src/retro/index.mjs +30 -0
  72. package/src/retro/ir/build-ir.mjs +108 -0
  73. package/src/retro/runtime-gba/contract.mjs +151 -0
  74. package/src/retro/runtime-gbc/contract.mjs +117 -0
  75. package/src/retro/shared/span.mjs +26 -0
  76. package/src/retro/shared/targets.mjs +64 -0
  77. package/src/retro/validator/check-project.mjs +114 -0
  78. package/src/runtime-hotspot-audit.mjs +707 -0
  79. package/src/scaffold/config.mjs +1000 -0
  80. package/src/scaffold/fs.mjs +56 -0
  81. package/src/scaffold/layout.mjs +318 -0
  82. package/src/scaffold/project-docs.mjs +438 -0
  83. package/src/scaffold.mjs +93 -596
  84. package/src/scene-composition/index.mjs +326 -0
  85. package/src/scene-composition/runtime.mjs +751 -0
  86. package/src/self-hosted-assets.mjs +604 -0
  87. package/src/session-client.mjs +750 -0
  88. package/src/session-native-launcher.mjs +74 -0
  89. package/src/session-protocol.mjs +75 -0
  90. package/src/session-runtime.mjs +321 -0
  91. package/src/session-server.mjs +360 -0
  92. package/src/shader-kits/index.mjs +773 -0
  93. package/src/starter-content-registry.mjs +292 -0
  94. package/src/state-artifacts.mjs +662 -24
  95. package/src/state-dev-reload.mjs +99 -2
  96. package/src/terminal-ui.mjs +245 -0
  97. package/src/web-conformance.mjs +219 -0
  98. package/templates/create/2d/config/gameplay/shooter.config.js +26 -0
  99. package/templates/create/2d/content/gameplay/waves.json +26 -0
  100. package/templates/create/2d/content/registries/.gitkeep +1 -0
  101. package/templates/create/2d/docs/design/.gitkeep +1 -0
  102. package/templates/create/2d/docs/design/loop.md +5 -0
  103. package/templates/create/2d/prefabs/enemies.prefab.js +90 -0
  104. package/templates/create/2d/prefabs/enemy-basic.prefab.js +18 -0
  105. package/templates/create/2d/prefabs/player.prefab.js +36 -0
  106. package/templates/create/2d/prefabs/projectiles.prefab.js +35 -0
  107. package/templates/create/2d/scenes/boot.scene.js +12 -0
  108. package/templates/create/2d/scenes/gameplay.scene.js +230 -0
  109. package/templates/create/2d/scenes/menu.scene.js +9 -0
  110. package/templates/create/2d/src/main.js +6 -185
  111. package/templates/create/2d/src/runtime/app.js +49 -0
  112. package/templates/create/2d/src/runtime/capabilities.js +35 -0
  113. package/templates/create/2d/ui/hud.screen.js +40 -0
  114. package/templates/create/2d/ui/pause.screen.js +149 -0
  115. package/templates/create/2d/ui/settings.screen.js +347 -0
  116. package/templates/create/2d/ui/title.screen.js +13 -0
  117. package/templates/create/2d-adventure/aura.config.json +28 -0
  118. package/templates/create/2d-adventure/config/gameplay/adventure.config.js +14 -0
  119. package/templates/create/2d-adventure/content/gameplay/world.js +46 -0
  120. package/templates/create/2d-adventure/content/registries/.gitkeep +1 -0
  121. package/templates/create/2d-adventure/docs/design/loop.md +5 -0
  122. package/templates/create/2d-adventure/prefabs/player.prefab.js +54 -0
  123. package/templates/create/2d-adventure/prefabs/relic.prefab.js +38 -0
  124. package/templates/create/2d-adventure/prefabs/world.prefab.js +125 -0
  125. package/templates/create/2d-adventure/scenes/gameplay.scene.js +256 -0
  126. package/templates/create/2d-adventure/src/runtime/capabilities.js +34 -0
  127. package/templates/create/2d-adventure/ui/hud.screen.js +60 -0
  128. package/templates/create/2d-survivor/config/gameplay/survivor.config.js +33 -0
  129. package/templates/create/2d-survivor/content/gameplay/spawn-zones.json +29 -0
  130. package/templates/create/2d-survivor/content/registries/.gitkeep +1 -0
  131. package/templates/create/2d-survivor/docs/design/.gitkeep +1 -0
  132. package/templates/create/2d-survivor/docs/design/loop.md +5 -0
  133. package/templates/create/2d-survivor/prefabs/enemies.prefab.js +178 -0
  134. package/templates/create/2d-survivor/prefabs/enemy-swarm.prefab.js +18 -0
  135. package/templates/create/2d-survivor/prefabs/player.prefab.js +42 -0
  136. package/templates/create/2d-survivor/prefabs/projectiles.prefab.js +56 -0
  137. package/templates/create/2d-survivor/scenes/boot.scene.js +12 -0
  138. package/templates/create/2d-survivor/scenes/gameplay.scene.js +314 -0
  139. package/templates/create/2d-survivor/scenes/menu.scene.js +9 -0
  140. package/templates/create/2d-survivor/src/main.js +5 -332
  141. package/templates/create/2d-survivor/src/runtime/app.js +49 -0
  142. package/templates/create/2d-survivor/src/runtime/capabilities.js +35 -0
  143. package/templates/create/2d-survivor/ui/hud.screen.js +45 -0
  144. package/templates/create/2d-survivor/ui/title.screen.js +13 -0
  145. package/templates/create/3d/assets/models/starter-avatar.gltf +184 -0
  146. package/templates/create/3d/config/gameplay/.gitkeep +1 -0
  147. package/templates/create/3d/content/gameplay/checkpoints.json +33 -0
  148. package/templates/create/3d/content/gameplay/course.js +40 -0
  149. package/templates/create/3d/content/registries/.gitkeep +1 -0
  150. package/templates/create/3d/docs/design/.gitkeep +1 -0
  151. package/templates/create/3d/docs/design/loop.md +5 -0
  152. package/templates/create/3d/prefabs/checkpoint.prefab.js +15 -0
  153. package/templates/create/3d/prefabs/player.prefab.js +204 -0
  154. package/templates/create/3d/prefabs/world.prefab.js +112 -0
  155. package/templates/create/3d/scenes/boot.scene.js +12 -0
  156. package/templates/create/3d/scenes/checkpoint.scene.js +9 -0
  157. package/templates/create/3d/scenes/gameplay.scene.js +292 -0
  158. package/templates/create/3d/src/main.js +6 -295
  159. package/templates/create/3d/src/runtime/app.js +49 -0
  160. package/templates/create/3d/src/runtime/capabilities.js +53 -0
  161. package/templates/create/3d/src/runtime/materials.js +34 -0
  162. package/templates/create/3d/src/runtime/state.js +39 -0
  163. package/templates/create/3d/ui/hud.screen.js +75 -0
  164. package/templates/create/3d/ui/pause.screen.js +166 -0
  165. package/templates/create/3d/ui/settings.screen.js +387 -0
  166. package/templates/create/3d-adventure/assets/models/starter-avatar.gltf +184 -0
  167. package/templates/create/3d-adventure/aura.config.json +28 -0
  168. package/templates/create/3d-adventure/config/gameplay/adventure.config.js +9 -0
  169. package/templates/create/3d-adventure/content/gameplay/course.js +62 -0
  170. package/templates/create/3d-adventure/content/registries/.gitkeep +1 -0
  171. package/templates/create/3d-adventure/docs/design/loop.md +5 -0
  172. package/templates/create/3d-adventure/prefabs/player.prefab.js +168 -0
  173. package/templates/create/3d-adventure/prefabs/relic.prefab.js +35 -0
  174. package/templates/create/3d-adventure/prefabs/world.prefab.js +119 -0
  175. package/templates/create/3d-adventure/scenes/gameplay.scene.js +358 -0
  176. package/templates/create/3d-adventure/src/runtime/capabilities.js +56 -0
  177. package/templates/create/3d-adventure/src/runtime/materials.js +39 -0
  178. package/templates/create/3d-adventure/src/runtime/state.js +31 -0
  179. package/templates/create/3d-adventure/ui/hud.screen.js +70 -0
  180. package/templates/create/3d-adventure/ui/pause.screen.js +437 -0
  181. package/templates/create/3d-collectathon/assets/models/starter-avatar.gltf +184 -0
  182. package/templates/create/3d-collectathon/config/gameplay/.gitkeep +1 -0
  183. package/templates/create/3d-collectathon/content/gameplay/collectibles.json +26 -0
  184. package/templates/create/3d-collectathon/content/gameplay/course.js +46 -0
  185. package/templates/create/3d-collectathon/content/registries/.gitkeep +1 -0
  186. package/templates/create/3d-collectathon/docs/design/.gitkeep +1 -0
  187. package/templates/create/3d-collectathon/docs/design/loop.md +5 -0
  188. package/templates/create/3d-collectathon/prefabs/collectible.prefab.js +15 -0
  189. package/templates/create/3d-collectathon/prefabs/player.prefab.js +207 -0
  190. package/templates/create/3d-collectathon/prefabs/world.prefab.js +112 -0
  191. package/templates/create/3d-collectathon/scenes/boot.scene.js +12 -0
  192. package/templates/create/3d-collectathon/scenes/checkpoint.scene.js +9 -0
  193. package/templates/create/3d-collectathon/scenes/gameplay.scene.js +200 -0
  194. package/templates/create/3d-collectathon/src/main.js +5 -355
  195. package/templates/create/3d-collectathon/src/runtime/app.js +49 -0
  196. package/templates/create/3d-collectathon/src/runtime/capabilities.js +53 -0
  197. package/templates/create/3d-collectathon/src/runtime/materials.js +34 -0
  198. package/templates/create/3d-collectathon/src/runtime/state.js +27 -0
  199. package/templates/create/3d-collectathon/ui/hud.screen.js +66 -0
  200. package/templates/create/3d-collectathon/ui/pause.screen.js +13 -0
  201. package/templates/create/blank/config/gameplay/.gitkeep +1 -0
  202. package/templates/create/blank/content/gameplay/.gitkeep +1 -0
  203. package/templates/create/blank/content/registries/.gitkeep +1 -0
  204. package/templates/create/blank/docs/design/.gitkeep +1 -0
  205. package/templates/create/blank/docs/design/loop.md +5 -0
  206. package/templates/create/blank/prefabs/.gitkeep +1 -0
  207. package/templates/create/blank/scenes/.gitkeep +1 -0
  208. package/templates/create/blank/src/runtime/.gitkeep +1 -0
  209. package/templates/create/blank/ui/.gitkeep +1 -0
  210. package/templates/create/deckbuilder-2d/assets/audio/.gitkeep +1 -0
  211. package/templates/create/deckbuilder-2d/assets/fonts/.gitkeep +1 -0
  212. package/templates/create/deckbuilder-2d/assets/sprites/.gitkeep +1 -0
  213. package/templates/create/deckbuilder-2d/assets/starter/README.md +11 -0
  214. package/templates/create/deckbuilder-2d/assets/ui/.gitkeep +1 -0
  215. package/templates/create/deckbuilder-2d/aura.config.json +28 -0
  216. package/templates/create/deckbuilder-2d/config/gameplay/deckbuilder.config.js +26 -0
  217. package/templates/create/deckbuilder-2d/content/cards/guard.card.js +19 -0
  218. package/templates/create/deckbuilder-2d/content/cards/spark.card.js +20 -0
  219. package/templates/create/deckbuilder-2d/content/cards/starter.deck.js +69 -0
  220. package/templates/create/deckbuilder-2d/content/cards/strike.card.js +19 -0
  221. package/templates/create/deckbuilder-2d/content/cards/survey.card.js +20 -0
  222. package/templates/create/deckbuilder-2d/content/encounters/training-battle.encounter.js +14 -0
  223. package/templates/create/deckbuilder-2d/content/encounters/training-battle.js +65 -0
  224. package/templates/create/deckbuilder-2d/content/enemies/training-automaton.enemy.js +48 -0
  225. package/templates/create/deckbuilder-2d/content/gameplay/.gitkeep +1 -0
  226. package/templates/create/deckbuilder-2d/content/registries/cards.registry.js +26 -0
  227. package/templates/create/deckbuilder-2d/content/registries/encounters.registry.js +20 -0
  228. package/templates/create/deckbuilder-2d/content/registries/enemies.registry.js +20 -0
  229. package/templates/create/deckbuilder-2d/content/registries/relics.registry.js +20 -0
  230. package/templates/create/deckbuilder-2d/content/relics/ember-charm.relic.js +18 -0
  231. package/templates/create/deckbuilder-2d/docs/design/loop.md +12 -0
  232. package/templates/create/deckbuilder-2d/prefabs/.gitkeep +1 -0
  233. package/templates/create/deckbuilder-2d/scenes/boot.scene.js +84 -0
  234. package/templates/create/deckbuilder-2d/scenes/gameplay.scene.js +641 -0
  235. package/templates/create/deckbuilder-2d/src/components/.gitkeep +1 -0
  236. package/templates/create/deckbuilder-2d/src/main.js +17 -0
  237. package/templates/create/deckbuilder-2d/src/runtime/capabilities.js +22 -0
  238. package/templates/create/deckbuilder-2d/src/shared/.gitkeep +1 -0
  239. package/templates/create/deckbuilder-2d/src/systems/.gitkeep +1 -0
  240. package/templates/create/deckbuilder-2d/tests/smoke/.gitkeep +1 -0
  241. package/templates/create/deckbuilder-2d/ui/hud.screen.js +80 -0
  242. package/templates/create/deckbuilder-2d/ui/pause.screen.js +146 -0
  243. package/templates/create/deckbuilder-2d/ui/settings.screen.js +342 -0
  244. package/templates/create/local-multiplayer/aura.config.json +40 -0
  245. package/templates/create/local-multiplayer/config/gameplay/local-multiplayer.config.js +26 -0
  246. package/templates/create/local-multiplayer/content/gameplay/room-layout.js +13 -0
  247. package/templates/create/local-multiplayer/content/registries/.gitkeep +1 -0
  248. package/templates/create/local-multiplayer/docs/design/loop.md +14 -0
  249. package/templates/create/local-multiplayer/prefabs/player.prefab.js +99 -0
  250. package/templates/create/local-multiplayer/scenes/boot.scene.js +12 -0
  251. package/templates/create/local-multiplayer/scenes/gameplay.scene.js +443 -0
  252. package/templates/create/local-multiplayer/src/main.js +17 -0
  253. package/templates/create/local-multiplayer/src/runtime/capabilities.js +28 -0
  254. package/templates/create/local-multiplayer/ui/hud.screen.js +60 -0
  255. package/templates/create/shared/src/runtime/project-inspector.js +105 -0
  256. package/templates/create/shared/src/runtime/scene-flow.js +290 -0
  257. package/templates/create/shared/src/runtime/screen-shell.js +222 -0
  258. package/templates/create/shared/src/runtime/ui-forms.js +209 -0
  259. package/templates/create/shared/src/runtime/ui-settings.js +237 -0
  260. package/templates/create/shared/src/runtime/ui-theme.js +352 -0
  261. package/templates/create/shared/src/starter-utils/adventure-objectives.js +102 -0
  262. package/templates/create/shared/src/starter-utils/animation-2d.js +337 -0
  263. package/templates/create/shared/src/starter-utils/avatar-3d.js +404 -0
  264. package/templates/create/shared/src/starter-utils/combat-feedback-2d.js +320 -0
  265. package/templates/create/shared/src/starter-utils/core.js +39 -3
  266. package/templates/create/shared/src/starter-utils/index.js +8 -2
  267. package/templates/create/shared/src/starter-utils/platformer-3d.js +34 -3
  268. package/templates/create/shared/src/starter-utils/triggers.js +662 -0
  269. package/templates/create/shared/src/starter-utils/tween-2d.js +615 -0
  270. package/templates/create/video-cutscene/assets/video/.gitkeep +0 -0
  271. package/templates/create/video-cutscene/aura.config.json +28 -0
  272. package/templates/create/video-cutscene/config/gameplay/.gitkeep +0 -0
  273. package/templates/create/video-cutscene/content/gameplay/.gitkeep +0 -0
  274. package/templates/create/video-cutscene/content/registries/.gitkeep +0 -0
  275. package/templates/create/video-cutscene/docs/design/loop.md +22 -0
  276. package/templates/create/video-cutscene/prefabs/.gitkeep +0 -0
  277. package/templates/create/video-cutscene/scenes/boot.scene.js +11 -0
  278. package/templates/create/video-cutscene/scenes/cutscene.scene.js +113 -0
  279. package/templates/create/video-cutscene/scenes/gameplay.scene.js +50 -0
  280. package/templates/create/video-cutscene/src/main.js +17 -0
  281. package/templates/create/video-cutscene/src/runtime/app.js +52 -0
  282. package/templates/create/video-cutscene/src/runtime/capabilities.js +35 -0
  283. package/templates/create/video-cutscene/src/runtime/state.js +13 -0
  284. package/templates/create/video-cutscene/ui/.gitkeep +0 -0
  285. package/templates/create-bin/play.js +1187 -0
  286. package/templates/make/README.md +46 -0
  287. package/templates/make/catalog.json +51 -0
  288. package/templates/make/component/files/{{MAKE_NAME}}.component.js +20 -0
  289. package/templates/make/component/manifest.json +9 -0
  290. package/templates/make/data/files/{{MAKE_NAME}}.json +14 -0
  291. package/templates/make/data/manifest.json +9 -0
  292. package/templates/make/material/files/{{MAKE_NAME}}.material.json +17 -0
  293. package/templates/make/material/manifest.json +9 -0
  294. package/templates/make/prefab/files/{{MAKE_NAME}}.prefab.js +20 -0
  295. package/templates/make/prefab/manifest.json +9 -0
  296. package/templates/make/scene/files/{{MAKE_NAME}}.scene.js +31 -0
  297. package/templates/make/scene/manifest.json +9 -0
  298. package/templates/make/shader/files/{{MAKE_NAME}}.shader.js +23 -0
  299. package/templates/make/shader/manifest.json +9 -0
  300. package/templates/make/system/files/{{MAKE_NAME}}.system.js +15 -0
  301. package/templates/make/system/manifest.json +9 -0
  302. package/templates/make/ui-screen/files/{{MAKE_NAME}}.screen.js +16 -0
  303. package/templates/make/ui-screen/files/{{MAKE_NAME}}.screen.json +23 -0
  304. package/templates/make/ui-screen/manifest.json +10 -0
  305. package/templates/make-starters/deckbuilder-2d/card/files/{{MAKE_NAME}}.card.js +22 -0
  306. package/templates/make-starters/deckbuilder-2d/card/manifest.json +9 -0
  307. package/templates/make-starters/deckbuilder-2d/catalog.json +34 -0
  308. package/templates/make-starters/deckbuilder-2d/encounter/files/{{MAKE_NAME}}.encounter.js +18 -0
  309. package/templates/make-starters/deckbuilder-2d/encounter/manifest.json +9 -0
  310. package/templates/make-starters/deckbuilder-2d/enemy/files/{{MAKE_NAME}}.enemy.js +28 -0
  311. package/templates/make-starters/deckbuilder-2d/enemy/manifest.json +9 -0
  312. package/templates/make-starters/deckbuilder-2d/relic/files/{{MAKE_NAME}}.relic.js +23 -0
  313. package/templates/make-starters/deckbuilder-2d/relic/manifest.json +9 -0
  314. package/templates/retro/platformer/README.md +10 -0
  315. package/templates/retro/platformer/assets/retro/assets.json +91 -0
  316. package/templates/retro/platformer/aura.config.json +7 -0
  317. package/templates/retro/platformer/package.json +5 -0
  318. package/templates/retro/platformer/src/main.js +40 -0
  319. package/templates/retro/puzzle-grid/README.md +10 -0
  320. package/templates/retro/puzzle-grid/assets/retro/assets.json +90 -0
  321. package/templates/retro/puzzle-grid/aura.config.json +7 -0
  322. package/templates/retro/puzzle-grid/package.json +5 -0
  323. package/templates/retro/puzzle-grid/src/main.js +29 -0
  324. package/templates/retro/tactics-grid/README.md +10 -0
  325. package/templates/retro/tactics-grid/assets/retro/assets.json +90 -0
  326. package/templates/retro/tactics-grid/aura.config.json +7 -0
  327. package/templates/retro/tactics-grid/package.json +5 -0
  328. package/templates/retro/tactics-grid/src/main.js +35 -0
  329. package/templates/retro/topdown-adventure/README.md +10 -0
  330. package/templates/retro/topdown-adventure/assets/retro/assets.json +95 -0
  331. package/templates/retro/topdown-adventure/aura.config.json +7 -0
  332. package/templates/retro/topdown-adventure/package.json +5 -0
  333. package/templates/retro/topdown-adventure/src/main.js +29 -0
  334. package/templates/skills/aurajs/SKILL.md +61 -5
@@ -0,0 +1,3309 @@
1
+ import { readConformanceSource } from '../shared.mjs';
2
+
3
+ const STARTER_SCENE_FLOW_RUNTIME_SOURCE = readConformanceSource(
4
+ 'src/cli/templates/create/shared/src/runtime/scene-flow.js',
5
+ ).replace(/^export\s+/gm, '');
6
+
7
+ const STARTER_SCREEN_SHELL_RUNTIME_SOURCE = readConformanceSource(
8
+ 'src/cli/templates/create/shared/src/runtime/screen-shell.js',
9
+ ).replace(/^export\s+/gm, '');
10
+
11
+ export const APP_AND_UI_RUNTIME_CONFORMANCE_CASES = [
12
+ {
13
+ id: 'tilemap-import-draw-culling',
14
+ modes: ['shim', 'native'],
15
+ namespaces: ['tilemap'],
16
+ functions: [
17
+ 'aura.tilemap.import',
18
+ 'aura.tilemap.unload',
19
+ 'aura.tilemap.getInfo',
20
+ 'aura.tilemap.drawLayer',
21
+ 'aura.tilemap.draw',
22
+ ],
23
+ nativeChecks: [
24
+ {
25
+ id: 'tilemap.import.draw.layer-order.deterministic',
26
+ expression: "(() => { const fixture = { width: 8, height: 8, tilewidth: 16, tileheight: 16, properties: [{ name: 'theme', type: 'string', value: 'forest' }], layers: [ { name: 'ground', type: 'tilelayer', width: 8, height: 8, properties: [{ name: 'solid', type: 'bool', value: true }], data: Array.from({ length: 64 }, () => 1) }, { name: 'spawn', type: 'objectgroup', properties: [{ name: 'kind', type: 'string', value: 'spawns' }], objects: [ { id: 10, name: 'hero', x: 16, y: 16, width: 16, height: 16, properties: [{ name: 'faction', type: 'string', value: 'player' }] }, { id: 11, name: 'loot', x: 32, y: 32, point: true, properties: { rarity: 'common', value: 1 } } ] }, { name: 'decor', type: 'tilelayer', width: 8, height: 8, data: Array.from({ length: 64 }, (_, i) => (i % 5 === 0 ? 1 : 0)) } ], tilesets: [ { firstgid: 1, image: 'tiles.png', tilewidth: 16, tileheight: 16, tilecount: 1, columns: 1, properties: [{ name: 'atlas', value: 'base' }] } ] }; const mapId = aura.tilemap.import(fixture); const first = aura.tilemap.draw(mapId, { camera: { x: 0, y: 0, width: 32, height: 32 } }); const second = aura.tilemap.draw(mapId, { camera: { x: 0, y: 0, width: 32, height: 32 } }); const info = aura.tilemap.getInfo(mapId); aura.tilemap.unload(mapId); return !!info && info.layerCount === 2 && info.objectLayerCount === 1 && info.objectCount === 2 && info.mapPropertyCount === 1 && first && second && first.layerOrder.join(',') === 'ground,decor' && JSON.stringify(first.layerOrder) === JSON.stringify(second.layerOrder) && first.drawnTiles === second.drawnTiles; })()",
27
+ },
28
+ {
29
+ id: 'tilemap.import.expanded-schema.acceptance.deterministic',
30
+ expression: "(() => { const runSample = () => { const fixture = { width: 4, height: 4, tilewidth: 16, tileheight: 16, properties: { difficulty: 'hard', seed: 7 }, solidLayerNames: ['collision'], layers: [ { name: 'ground', type: 'tilelayer', width: 4, height: 4, offsetx: 2, offsety: 4, data: Array.from({ length: 16 }, () => 1), properties: { solid: true } }, { name: 'collision', type: 'tilelayer', width: 4, height: 4, data: [0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], properties: [{ name: 'solid', value: true }] }, { name: 'objects', type: 'objectgroup', draworder: 'index', objects: [ { id: 1, name: 'rect', x: 0, y: 0, width: 16, height: 16, properties: { loot: false } }, { id: 2, name: 'point', x: 16, y: 16, point: true, properties: [{ name: 'kind', value: 'spawn' }] }, { id: 3, name: 'ellipse', x: 32, y: 16, width: 16, height: 8, ellipse: true }, { id: 4, name: 'poly', x: 48, y: 16, polygon: [{ x: 0, y: 0 }, { x: 8, y: 0 }, { x: 8, y: 8 }] }, { id: 5, name: 'path', x: 48, y: 32, polyline: [{ x: 0, y: 0 }, { x: 8, y: 8 }] }, { id: 6, name: 'tileobj', x: 0, y: 32, gid: 5, width: 16, height: 16 } ] } ], tilesets: [ { firstgid: 1, image: 'tiles_a.png', tilewidth: 16, tileheight: 16, tilecount: 1, columns: 1, margin: 1, spacing: 0, properties: { atlas: 'a' } }, { firstgid: 5, image: 'tiles_b.png', tilewidth: 16, tileheight: 16, tilecount: 2, columns: 1, margin: 0, spacing: 1, properties: [{ name: 'atlas', value: 'b' }] } ] }; const mapId = aura.tilemap.import(fixture); const info = aura.tilemap.getInfo(mapId); const draw = aura.tilemap.draw(mapId, { cull: false }); const ground = aura.tilemap.drawLayer(mapId, 'ground', { cull: false }); const unload = aura.tilemap.unload(mapId); return { layerCount: Number(info?.layerCount || 0), objectLayerCount: Number(info?.objectLayerCount || 0), objectCount: Number(info?.objectCount || 0), tilesetCount: Number(info?.tilesetCount || 0), mapPropertyCount: Number(info?.mapPropertyCount || 0), layerOrder: Array.isArray(draw?.layerOrder) ? draw.layerOrder.join(',') : '', drawnTiles: Number(draw?.drawnTiles || 0), groundDrawnTiles: Number(ground?.drawnTiles || 0), unload }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.layerCount === 2 && first.objectLayerCount === 1 && first.objectCount === 6 && first.tilesetCount === 2 && first.mapPropertyCount === 2 && first.layerOrder === 'ground,collision' && first.drawnTiles === 17 && first.groundDrawnTiles === 16 && first.unload === true; })()",
31
+ },
32
+ {
33
+ id: 'tilemap.culling.reduces-draw-submissions',
34
+ expression: "(() => { const size = 32; const fixture = { width: size, height: size, tilewidth: 16, tileheight: 16, layers: [ { name: 'ground', type: 'tilelayer', width: size, height: size, data: Array.from({ length: size * size }, () => 1) } ], tilesets: [ { firstgid: 1, image: 'tiles.png', tilewidth: 16, tileheight: 16, tilecount: 1, columns: 1 } ] }; const mapId = aura.tilemap.import(fixture); const full = aura.tilemap.drawLayer(mapId, 'ground', { cull: false }); const culled = aura.tilemap.drawLayer(mapId, 'ground', { camera: { x: 0, y: 0, width: 64, height: 64 } }); aura.tilemap.unload(mapId); return !!full && !!culled && full.drawnTiles === (size * size) && culled.drawnTiles < full.drawnTiles && culled.consideredTiles < full.consideredTiles && culled.culledTiles > 0; })()",
35
+ },
36
+ {
37
+ id: 'tilemap.import.invalid-schema.reason-code',
38
+ expression: "(() => { try { aura.tilemap.import({ width: 2, height: 2, tilewidth: 16, tileheight: 16, layers: [{ name: 'bad', type: 'tilelayer', data: [1, 1, 1] }], tilesets: [{ firstgid: 1, image: 'tiles.png', columns: 1, tilecount: 1 }] }); return false; } catch (e) { return String(e).includes('aura.tilemap.import: invalid-layer-data'); } })()",
39
+ },
40
+ {
41
+ id: 'tilemap.import.invalid-object-property.reason-code',
42
+ expression: "(() => { try { aura.tilemap.import({ width: 2, height: 2, tilewidth: 16, tileheight: 16, layers: [ { name: 'ground', type: 'tilelayer', width: 2, height: 2, data: [1, 1, 1, 1] }, { name: 'objects', type: 'objectgroup', objects: [ { id: 1, x: 0, y: 0, properties: [ { name: 'bad', value: { nested: true } } ] } ] } ], tilesets: [{ firstgid: 1, image: 'tiles.png', columns: 1, tilecount: 1 }] }); return false; } catch (e) { return String(e).includes('aura.tilemap.import: invalid-property-value'); } })()",
43
+ },
44
+ {
45
+ id: 'tilemap.import.expanded-schema.rejection.reason-codes',
46
+ expression: "(() => { const runSample = () => { const expectImportFailure = (factory, reasonCode) => { try { aura.tilemap.import(factory()); return false; } catch (err) { return String(err).includes('aura.tilemap.import: ' + reasonCode); } }; return { compression: expectImportFailure(() => ({ width: 2, height: 2, tilewidth: 16, tileheight: 16, layers: [{ name: 'ground', type: 'tilelayer', width: 2, height: 2, compression: 'zlib', data: [1, 1, 1, 1] }], tilesets: [{ firstgid: 1, image: 'tiles.png', columns: 1, tilecount: 1 }] }), 'unsupported-layer-compression'), encoding: expectImportFailure(() => ({ width: 2, height: 2, tilewidth: 16, tileheight: 16, layers: [{ name: 'ground', type: 'tilelayer', width: 2, height: 2, encoding: 'base64', data: [1, 1, 1, 1] }], tilesets: [{ firstgid: 1, image: 'tiles.png', columns: 1, tilecount: 1 }] }), 'unsupported-layer-encoding'), invalidObjectShape: expectImportFailure(() => ({ width: 2, height: 2, tilewidth: 16, tileheight: 16, layers: [ { name: 'ground', type: 'tilelayer', width: 2, height: 2, data: [1, 1, 1, 1] }, { name: 'objects', type: 'objectgroup', objects: [ { id: 1, x: 0, y: 0, polygon: [{ x: 0, y: 0 }, { x: 1, y: 0 }], polyline: [{ x: 0, y: 0 }, { x: 1, y: 1 }] } ] } ], tilesets: [{ firstgid: 1, image: 'tiles.png', columns: 1, tilecount: 1 }] }), 'invalid-object-shape'), unmappedObjectGid: expectImportFailure(() => ({ width: 2, height: 2, tilewidth: 16, tileheight: 16, layers: [ { name: 'ground', type: 'tilelayer', width: 2, height: 2, data: [1, 1, 1, 1] }, { name: 'objects', type: 'objectgroup', objects: [ { id: 1, x: 0, y: 0, gid: 99 } ] } ], tilesets: [{ firstgid: 1, image: 'tiles.png', columns: 1, tilecount: 1 }] }), 'unmapped-object-gid') }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.compression === true && first.encoding === true && first.invalidObjectShape === true && first.unmappedObjectGid === true; })()",
47
+ },
48
+ ],
49
+ source: `
50
+ let tilemapId = 0;
51
+ let verified = false;
52
+ const fixture = {
53
+ width: 8,
54
+ height: 8,
55
+ tilewidth: 16,
56
+ tileheight: 16,
57
+ properties: [{ name: 'theme', type: 'string', value: 'forest' }],
58
+ layers: [
59
+ {
60
+ name: 'ground',
61
+ type: 'tilelayer',
62
+ width: 8,
63
+ height: 8,
64
+ properties: [{ name: 'solid', type: 'bool', value: true }],
65
+ data: Array.from({ length: 64 }, () => 1),
66
+ },
67
+ {
68
+ name: 'spawn',
69
+ type: 'objectgroup',
70
+ properties: [{ name: 'kind', type: 'string', value: 'spawns' }],
71
+ objects: [
72
+ {
73
+ id: 10,
74
+ name: 'hero',
75
+ x: 16,
76
+ y: 16,
77
+ width: 16,
78
+ height: 16,
79
+ properties: [{ name: 'faction', type: 'string', value: 'player' }],
80
+ },
81
+ {
82
+ id: 11,
83
+ name: 'loot',
84
+ x: 32,
85
+ y: 32,
86
+ point: true,
87
+ properties: { rarity: 'common', value: 1 },
88
+ },
89
+ ],
90
+ },
91
+ {
92
+ name: 'decor',
93
+ type: 'tilelayer',
94
+ width: 8,
95
+ height: 8,
96
+ data: Array.from({ length: 64 }, (_, i) => (i % 5 === 0 ? 1 : 0)),
97
+ },
98
+ ],
99
+ tilesets: [
100
+ { firstgid: 1, image: 'tiles.png', tilewidth: 16, tileheight: 16, tilecount: 1, columns: 1, properties: [{ name: 'atlas', value: 'base' }] },
101
+ ],
102
+ };
103
+
104
+ aura.setup = function () {
105
+ tilemapId = aura.tilemap.import(fixture);
106
+ };
107
+
108
+ aura.draw = function () {
109
+ if (verified) return;
110
+ const first = aura.tilemap.draw(tilemapId, { camera: { x: 0, y: 0, width: 32, height: 32 } });
111
+ const second = aura.tilemap.draw(tilemapId, { camera: { x: 0, y: 0, width: 32, height: 32 } });
112
+ const full = aura.tilemap.drawLayer(tilemapId, 'ground', { cull: false });
113
+ const culled = aura.tilemap.drawLayer(tilemapId, 'ground', { camera: { x: 0, y: 0, width: 32, height: 32 } });
114
+ const info = aura.tilemap.getInfo(tilemapId);
115
+
116
+ aura.test.assert(!!first && !!second, 'tilemap draw summary should exist');
117
+ aura.test.equal(first.layerOrder.join(','), 'ground,decor', 'tilemap layer draw order must be deterministic');
118
+ aura.test.equal(first.drawnTiles, second.drawnTiles, 'tilemap draw totals must be deterministic');
119
+ aura.test.assert(!!full && !!culled && culled.drawnTiles < full.drawnTiles, 'tilemap culling should reduce submissions');
120
+ aura.test.assert(culled.culledTiles > 0, 'tilemap culling should report culled tiles');
121
+ aura.test.assert(!!info && info.objectLayerCount === 1 && info.objectCount === 2 && info.mapPropertyCount === 1, 'tilemap object layer/property metadata should be exposed');
122
+ aura.test.equal(aura.tilemap.unload(tilemapId), true, 'tilemap unload should return true');
123
+ aura.test.equal(aura.tilemap.getInfo(tilemapId), null, 'tilemap getInfo should return null after unload');
124
+ verified = true;
125
+ };
126
+ `,
127
+ frames: 2,
128
+ },
129
+ {
130
+ id: 'anim2d-state-machine',
131
+ modes: ['shim', 'native'],
132
+ namespaces: ['anim2d'],
133
+ functions: [
134
+ 'aura.anim2d.registerClip',
135
+ 'aura.anim2d.createMachine',
136
+ 'aura.anim2d.defineState',
137
+ 'aura.anim2d.play',
138
+ 'aura.anim2d.update',
139
+ 'aura.anim2d.getState',
140
+ 'aura.anim2d.onComplete',
141
+ ],
142
+ nativeChecks: [
143
+ {
144
+ id: 'anim2d.clip-and-state.registration',
145
+ expression: "(() => { const machine = aura.anim2d.createMachine(); const clipOk = aura.anim2d.registerClip('run', [0, 1, 2], { frameDuration: 0.1, loop: false }); const stateOk = aura.anim2d.defineState(machine, 'run', 'run'); return clipOk === true && stateOk === true; })()",
146
+ },
147
+ {
148
+ id: 'anim2d.completion.callback-ordering.deterministic',
149
+ expression: "(() => { const machine = aura.anim2d.createMachine(); aura.anim2d.registerClip('jump', [0, 1, 2], { frameDuration: 0.1, loop: false }); aura.anim2d.defineState(machine, 'jump', 'jump'); const calls = []; aura.anim2d.onComplete(machine, () => calls.push('late'), 20); aura.anim2d.onComplete(machine, () => calls.push('early'), 5); const started = aura.anim2d.play(machine, 'jump'); aura.anim2d.update(0.35); const state = aura.anim2d.getState(machine); return started === true && !!state && state.completed === true && state.frameIndex === 2 && state.frame === 2 && calls.join(',') === 'early,late'; })()",
150
+ },
151
+ {
152
+ id: 'anim2d.invalid-input.safe-false',
153
+ expression: "(() => { const machine = aura.anim2d.createMachine(); return aura.anim2d.registerClip('', [0, 1]) === false && aura.anim2d.defineState(machine, 'idle', 'missing') === false && aura.anim2d.play(machine, 'missing') === false && aura.anim2d.onComplete(machine, null, 0) === false; })()",
154
+ },
155
+ {
156
+ id: 'anim2d.deterministic-rerun-sequence',
157
+ expression: "(() => { const runSample = () => { const machine = aura.anim2d.createMachine(); aura.anim2d.registerClip('sample', [0, 1, 2], { frameDuration: 0.05, loop: true }); aura.anim2d.defineState(machine, 'sample', 'sample'); aura.anim2d.play(machine, 'sample'); const trace = []; for (const dt of [0.05, 0.05, 0.1, 0.05]) { aura.anim2d.update(dt); const state = aura.anim2d.getState(machine); trace.push(state ? state.frame : null); } return trace.join(','); }; return runSample() === runSample(); })()",
158
+ },
159
+ ],
160
+ source: `
161
+ aura.setup = function () {
162
+ const machine = aura.anim2d.createMachine();
163
+ aura.anim2d.registerClip('idle', [0, 1], { frameDuration: 0.1, loop: true });
164
+ aura.anim2d.defineState(machine, 'idle', 'idle');
165
+ aura.anim2d.play(machine, 'idle');
166
+ };
167
+ aura.update = function (dt) {
168
+ aura.anim2d.update(dt);
169
+ };
170
+ `,
171
+ frames: 2,
172
+ },
173
+ {
174
+ id: 'material-runtime-controls',
175
+ modes: ['shim', 'native'],
176
+ namespaces: ['material'],
177
+ functions: [
178
+ 'aura.material.create',
179
+ 'aura.material.setColor',
180
+ 'aura.material.setTexture',
181
+ 'aura.material.setMetallic',
182
+ 'aura.material.setRoughness',
183
+ 'aura.material.setMetallicRoughness',
184
+ 'aura.material.reset',
185
+ 'aura.material.clone',
186
+ 'aura.material.unload',
187
+ ],
188
+ nativeChecks: [
189
+ { id: 'material.create', expression: "typeof aura.material?.create === 'function'" },
190
+ { id: 'material.setColor', expression: "typeof aura.material?.setColor === 'function'" },
191
+ { id: 'material.setTexture', expression: "typeof aura.material?.setTexture === 'function'" },
192
+ { id: 'material.setMetallic', expression: "typeof aura.material?.setMetallic === 'function'" },
193
+ { id: 'material.setRoughness', expression: "typeof aura.material?.setRoughness === 'function'" },
194
+ { id: 'material.setMetallicRoughness', expression: "typeof aura.material?.setMetallicRoughness === 'function'" },
195
+ { id: 'material.reset', expression: "typeof aura.material?.reset === 'function'" },
196
+ { id: 'material.clone', expression: "typeof aura.material?.clone === 'function'" },
197
+ { id: 'material.unload', expression: "typeof aura.material?.unload === 'function'" },
198
+ {
199
+ id: 'material.setTexture.invalidType.throws',
200
+ expression: "(() => { const handle = aura.material.create(); try { aura.material.setTexture(handle, 42); return false; } catch (error) { return error instanceof Error; } })()",
201
+ },
202
+ {
203
+ id: 'material.clone.invalidHandle.throws',
204
+ expression: "(() => { try { aura.material.clone(987654321); return false; } catch (error) { return error instanceof Error; } })()",
205
+ },
206
+ {
207
+ id: 'material.clone.texture-preserving.deterministic',
208
+ expression: "(() => { const runSample = () => { const base = aura.material.create({ texture: 'textures/clone-source.png', metallic: 0.25, roughness: 0.75 }); const cloneA = aura.material.clone(base); const cloneB = aura.material.clone(base); aura.material.setTexture(cloneA, null); aura.material.setMetallicRoughness(cloneB, 0.8, 0.2); aura.material.unload(cloneA); aura.material.unload(cloneB); aura.material.unload(base); return { base, cloneA, cloneB, distinct: base !== cloneA && base !== cloneB && cloneA !== cloneB }; }; const normalize = (sample) => ({ deltaBaseToCloneA: sample.cloneA - sample.base, deltaCloneAToCloneB: sample.cloneB - sample.cloneA, distinct: sample.distinct === true }); const first = runSample(); const second = runSample(); return JSON.stringify(normalize(first)) === JSON.stringify(normalize(second)) && first.distinct === true && second.distinct === true && first.base > 0 && second.base > 0; })()",
209
+ },
210
+ {
211
+ id: 'material.create.extended-pbr-options.accepted',
212
+ expression: "(() => { const handle = aura.material.create({ emissive: { r: 0.2, g: 0.1, b: 0.3 }, metallicRoughnessTexture: 'textures/clone-source.png', aoTexture: 'textures/clone-source.png', emissiveTexture: 'textures/clone-source.png', alphaMode: 'blend', alphaCutoff: 0.25, doubleSided: true, clearcoat: 0.4, clearcoatRoughness: 0.2, sheenColor: { r: 0.6, g: 0.3, b: 0.1 }, sheenRoughness: 0.5, occlusionStrength: 0.7 }); aura.material.unload(handle); return typeof handle === 'number' && handle > 0; })()",
213
+ },
214
+ {
215
+ id: 'material.create.masked-alpha.deterministic',
216
+ expression: "(() => { const runSample = () => { const maskedDefault = aura.material.create({ texture: 'textures/clone-source.png', alphaMode: 'mask' }); const maskedClamped = aura.material.create({ texture: 'textures/clone-source.png', alphaMode: 'mask', alphaCutoff: 2, doubleSided: true }); aura.material.unload(maskedClamped); aura.material.unload(maskedDefault); return { maskedDefault, maskedClamped, delta: maskedClamped - maskedDefault }; }; const first = runSample(); const second = runSample(); return JSON.stringify({ delta: first.delta }) === JSON.stringify({ delta: second.delta }) && first.maskedDefault > 0 && first.maskedClamped > first.maskedDefault && first.delta === 1; })()",
217
+ },
218
+ ],
219
+ source: `
220
+ aura.setup = function () {
221
+ const handle = aura.material.create({ metallic: 2, roughness: -1 });
222
+ aura.test.assert(typeof handle === 'number' && handle > 0, 'create should return numeric handle');
223
+
224
+ aura.material.setColor(handle, { r: 0.25, g: 0.5, b: 0.75, a: 1 });
225
+ aura.material.setMetallic(handle, 0.2);
226
+ aura.material.setRoughness(handle, 0.8);
227
+ aura.material.setMetallicRoughness(handle, 0.9, 0.1);
228
+ aura.material.setTexture(handle, null);
229
+ aura.material.reset(handle);
230
+
231
+ const clone = aura.material.clone(handle);
232
+ aura.test.assert(typeof clone === 'number' && clone !== handle, 'clone should return distinct numeric handle');
233
+ aura.material.unload(clone);
234
+ aura.material.unload(123456789); // silent no-op
235
+
236
+ const textured = aura.material.create({ texture: 'textures/clone-source.png', metallic: 0.4, roughness: 0.6 });
237
+ const texturedClone = aura.material.clone(textured);
238
+ aura.test.assert(typeof texturedClone === 'number' && texturedClone !== textured, 'textured clone should return distinct numeric handle');
239
+ aura.material.setTexture(texturedClone, null);
240
+ aura.material.unload(texturedClone);
241
+ aura.material.unload(textured);
242
+
243
+ let textureTypeError = false;
244
+ try {
245
+ aura.material.setTexture(handle, 123);
246
+ } catch (error) {
247
+ textureTypeError = true;
248
+ }
249
+ aura.test.assert(textureTypeError, 'setTexture should throw on non-string/non-null');
250
+
251
+ let cloneError = false;
252
+ try {
253
+ aura.material.clone(999999999);
254
+ } catch (error) {
255
+ cloneError = true;
256
+ }
257
+ aura.test.assert(cloneError, 'clone should throw for invalid handle');
258
+ };
259
+ `,
260
+ frames: 1,
261
+ },
262
+ {
263
+ id: 'storage-persistence-seed',
264
+ modes: ['native'],
265
+ namespaces: ['storage'],
266
+ functions: ['aura.storage.save', 'aura.storage.load'],
267
+ nativeChecks: [
268
+ {
269
+ id: 'storage.seed.persistedValueWritten',
270
+ expression: "(() => { const key = '__conformance_persist__'; aura.storage.save(key, { sentinel: 1337, marker: 'seed' }); const loaded = aura.storage.load(key); return !!loaded && loaded.sentinel === 1337 && loaded.marker === 'seed'; })()",
271
+ },
272
+ ],
273
+ // Allow one extra native frame so storage flush is deterministic before process exit.
274
+ nativeFrames: 2,
275
+ source: `
276
+ aura.setup = function () {};
277
+ `,
278
+ },
279
+ {
280
+ id: 'storage-persistence-verify',
281
+ modes: ['native'],
282
+ namespaces: ['storage'],
283
+ functions: ['aura.storage.load', 'aura.storage.keys', 'aura.storage.delete'],
284
+ nativeChecks: [
285
+ {
286
+ id: 'storage.verify.valueSurvivesProcessRestart',
287
+ expression: "(() => { const key = '__conformance_persist__'; const loaded = aura.storage.load(key); const listed = aura.storage.keys(); aura.storage.delete(key); return !!loaded && loaded.sentinel === 1337 && loaded.marker === 'seed' && Array.isArray(listed) && listed.includes(key) && aura.storage.load(key) === null; })()",
288
+ },
289
+ ],
290
+ nativeFrames: 1,
291
+ source: `
292
+ aura.setup = function () {};
293
+ `,
294
+ },
295
+ {
296
+ id: 'math-color-vec-collision-timer',
297
+ namespaces: ['math', 'color-vector', 'collision', 'timer'],
298
+ functions: [
299
+ 'aura.math.lerp',
300
+ 'aura.math.clamp',
301
+ 'aura.math.random',
302
+ 'aura.math.distance',
303
+ 'aura.math.angle',
304
+ 'aura.math.PI',
305
+ 'aura.math.TAU',
306
+ 'aura.rgb',
307
+ 'aura.rgba',
308
+ 'aura.Color.*',
309
+ 'aura.vec2.*',
310
+ 'aura.vec3.*',
311
+ 'aura.collision.*',
312
+ 'aura.timer.*',
313
+ ],
314
+ nativeChecks: [
315
+ { id: 'math.lerp', expression: "typeof aura.math?.lerp === 'function'" },
316
+ { id: 'math.clamp', expression: "typeof aura.math?.clamp === 'function'" },
317
+ { id: 'math.random', expression: "typeof aura.math?.random === 'function'" },
318
+ { id: 'math.distance', expression: "typeof aura.math?.distance === 'function'" },
319
+ { id: 'math.angle', expression: "typeof aura.math?.angle === 'function'" },
320
+ { id: 'math.PI', expression: "typeof aura.math?.PI === 'number'" },
321
+ { id: 'math.TAU', expression: "typeof aura.math?.TAU === 'number'" },
322
+ { id: 'rgb', expression: "typeof aura.rgb === 'function'" },
323
+ { id: 'rgba', expression: "typeof aura.rgba === 'function'" },
324
+ { id: 'Color.RED', expression: "typeof aura.Color?.RED === 'object'" },
325
+ { id: 'Color.TRANSPARENT', expression: "typeof aura.Color?.TRANSPARENT === 'object'" },
326
+ { id: 'vec2.constructor', expression: "typeof aura.vec2 === 'function'" },
327
+ {
328
+ id: 'vec2.add',
329
+ expression: "(() => { const v = aura.vec2.add(aura.vec2(3, 4), aura.vec2(2, 1)); return v.x === 5 && v.y === 5; })()",
330
+ },
331
+ {
332
+ id: 'vec2.sub',
333
+ expression: "(() => { const v = aura.vec2.sub(aura.vec2(3, 4), aura.vec2(2, 1)); return v.x === 1 && v.y === 3; })()",
334
+ },
335
+ {
336
+ id: 'vec2.scale',
337
+ expression: "(() => { const v = aura.vec2.scale(aura.vec2(3, 4), 2); return v.x === 6 && v.y === 8; })()",
338
+ },
339
+ { id: 'vec2.dot', expression: "aura.vec2.dot(aura.vec2(3, 4), aura.vec2(2, 1)) === 10" },
340
+ { id: 'vec2.length', expression: "aura.vec2.length(aura.vec2(3, 4)) === 5" },
341
+ {
342
+ id: 'vec2.normalize',
343
+ expression: "(() => { const v = aura.vec2.normalize(aura.vec2(3, 4)); return Math.abs(v.x - 0.6) < 1e-9 && Math.abs(v.y - 0.8) < 1e-9; })()",
344
+ },
345
+ {
346
+ id: 'vec2.distance',
347
+ expression: "Math.abs(aura.vec2.distance(aura.vec2(3, 4), aura.vec2(2, 1)) - Math.sqrt(10)) < 1e-9",
348
+ },
349
+ {
350
+ id: 'vec2.lerp',
351
+ expression: "(() => { const v = aura.vec2.lerp(aura.vec2(3, 4), aura.vec2(2, 1), 0.5); return v.x === 2.5 && v.y === 2.5; })()",
352
+ },
353
+ { id: 'vec3.constructor', expression: "typeof aura.vec3 === 'function'" },
354
+ {
355
+ id: 'vec3.add',
356
+ expression: "(() => { const v = aura.vec3.add(aura.vec3(1, 2, 3), aura.vec3(4, 5, 6)); return v.x === 5 && v.y === 7 && v.z === 9; })()",
357
+ },
358
+ {
359
+ id: 'vec3.sub',
360
+ expression: "(() => { const v = aura.vec3.sub(aura.vec3(4, 5, 6), aura.vec3(1, 2, 3)); return v.x === 3 && v.y === 3 && v.z === 3; })()",
361
+ },
362
+ {
363
+ id: 'vec3.scale',
364
+ expression: "(() => { const v = aura.vec3.scale(aura.vec3(1, 2, 3), 2); return v.x === 2 && v.y === 4 && v.z === 6; })()",
365
+ },
366
+ { id: 'vec3.dot', expression: "aura.vec3.dot(aura.vec3(1, 2, 3), aura.vec3(4, 5, 6)) === 32" },
367
+ {
368
+ id: 'vec3.cross',
369
+ expression: "(() => { const v = aura.vec3.cross(aura.vec3(1, 0, 0), aura.vec3(0, 1, 0)); return v.x === 0 && v.y === 0 && v.z === 1; })()",
370
+ },
371
+ { id: 'vec3.length', expression: "aura.vec3.length(aura.vec3(0, 3, 4)) === 5" },
372
+ {
373
+ id: 'vec3.normalize',
374
+ expression: "(() => { const v = aura.vec3.normalize(aura.vec3(0, 3, 4)); return Math.abs(v.x - 0) < 1e-9 && Math.abs(v.y - 0.6) < 1e-9 && Math.abs(v.z - 0.8) < 1e-9; })()",
375
+ },
376
+ {
377
+ id: 'vec3.distance',
378
+ expression: "Math.abs(aura.vec3.distance(aura.vec3(1, 2, 3), aura.vec3(4, 5, 6)) - Math.sqrt(27)) < 1e-9",
379
+ },
380
+ {
381
+ id: 'vec3.lerp',
382
+ expression: "(() => { const v = aura.vec3.lerp(aura.vec3(0, 0, 0), aura.vec3(2, 4, 6), 0.5); return v.x === 1 && v.y === 2 && v.z === 3; })()",
383
+ },
384
+ {
385
+ id: 'collision.rectRect',
386
+ expression: "aura.collision.rectRect({ x: 0, y: 0, w: 10, h: 10 }, { x: 5, y: 5, w: 10, h: 10 }) === true",
387
+ },
388
+ {
389
+ id: 'collision.rectPoint',
390
+ expression: "aura.collision.rectPoint({ x: 0, y: 0, w: 10, h: 10 }, { x: 2, y: 2 }) === true",
391
+ },
392
+ {
393
+ id: 'collision.circleCircle',
394
+ expression: "aura.collision.circleCircle({ x: 0, y: 0, radius: 4 }, { x: 6, y: 0, radius: 4 }) === true",
395
+ },
396
+ {
397
+ id: 'collision.circlePoint',
398
+ expression: "aura.collision.circlePoint({ x: 0, y: 0, radius: 4 }, { x: 0, y: 0 }) === true",
399
+ },
400
+ {
401
+ id: 'collision.circleRect',
402
+ expression: "aura.collision.circleRect({ x: 20, y: 20, radius: 2 }, { x: 0, y: 0, w: 10, h: 10 }) === false",
403
+ },
404
+ {
405
+ id: 'collision.rectPointBatch',
406
+ expression: "(() => { const hits = aura.collision.rectPointBatch({ x: 0, y: 0, w: 5, h: 5 }, [{ x: 1, y: 1 }, { x: 8, y: 8 }, { x: 4, y: 4 }]); return Array.isArray(hits) && hits.length === 3 && hits[0] === true && hits[1] === false && hits[2] === true; })()",
407
+ },
408
+ {
409
+ id: 'collision.circleRectBatch',
410
+ expression: "(() => { const hits = aura.collision.circleRectBatch({ x: 0, y: 0, radius: 4 }, [{ x: -2, y: -2, w: 2, h: 2 }, { x: 10, y: 10, w: 2, h: 2 }]); return Array.isArray(hits) && hits.length === 2 && hits[0] === true && hits[1] === false; })()",
411
+ },
412
+ {
413
+ id: 'collision.batch.invalid-input.safe-array',
414
+ expression: "Array.isArray(aura.collision.rectPointBatch({ x: 0, y: 0, w: 1, h: 1 }, null)) && Array.isArray(aura.collision.circleRectBatch({ x: 0, y: 0, radius: 1 }, 'bad'))",
415
+ },
416
+ { id: 'timer.after', expression: "typeof aura.timer?.after === 'function'" },
417
+ { id: 'timer.every', expression: "typeof aura.timer?.every === 'function'" },
418
+ { id: 'timer.cancel', expression: "typeof aura.timer?.cancel === 'function'" },
419
+ { id: 'timer.getDelta', expression: "typeof aura.timer?.getDelta === 'function'" },
420
+ { id: 'timer.getTime', expression: "typeof aura.timer?.getTime === 'function'" },
421
+ ],
422
+ frames: 1,
423
+ source: `
424
+ aura.setup = function () {
425
+ aura.test.equal(aura.math.clamp(11, 0, 10), 10, 'math.clamp should clamp high values');
426
+ aura.test.equal(aura.math.lerp(0, 10, 0.5), 5, 'math.lerp should interpolate');
427
+ const r = aura.math.random(1, 3);
428
+ aura.test.assert(Number.isFinite(r), 'math.random should be finite');
429
+ aura.test.assert(r >= 1 && r <= 3, 'math.random should be in range');
430
+ aura.test.equal(aura.math.distance(0, 0, 3, 4), 5, 'math.distance should be euclidean');
431
+ aura.test.equal(aura.math.angle(0, 0, 1, 0), 0, 'math.angle should measure from points');
432
+ aura.test.equal(aura.math.PI, Math.PI, 'math.PI should match');
433
+ aura.test.equal(aura.math.TAU, Math.PI * 2, 'math.TAU should match');
434
+
435
+ const c = aura.rgba(1, 0, 0, 0.5);
436
+ aura.test.equal(c.r, 1, 'aura.rgba should preserve r');
437
+ aura.test.equal(c.g, 0, 'aura.rgba should preserve g');
438
+ aura.test.equal(c.b, 0, 'aura.rgba should preserve b');
439
+ aura.test.equal(c.a, 0.5, 'aura.rgba should preserve a');
440
+ aura.test.equal(aura.Color.WHITE.a, 1, 'aura.Color.WHITE should exist');
441
+
442
+ const a = aura.vec2(3, 4);
443
+ const b = aura.vec2(2, 1);
444
+ const sum = aura.vec2.add(a, b);
445
+ aura.test.equal(sum.x, 5, 'vec2.add x');
446
+ aura.test.equal(sum.y, 5, 'vec2.add y');
447
+ const diff = aura.vec2.sub(a, b);
448
+ aura.test.equal(diff.x, 1, 'vec2.sub x');
449
+ aura.test.equal(diff.y, 3, 'vec2.sub y');
450
+ const scaled = aura.vec2.scale(a, 2);
451
+ aura.test.equal(scaled.x, 6, 'vec2.scale x');
452
+ aura.test.equal(scaled.y, 8, 'vec2.scale y');
453
+ aura.test.equal(aura.vec2.dot(a, b), 10, 'vec2.dot');
454
+ aura.test.equal(aura.vec2.length(a), 5, 'vec2.length');
455
+ const normalized = aura.vec2.normalize(a);
456
+ aura.test.assert(Math.abs(normalized.x - 0.6) < 1e-9, 'vec2.normalize x');
457
+ aura.test.assert(Math.abs(normalized.y - 0.8) < 1e-9, 'vec2.normalize y');
458
+ const distance = aura.vec2.distance(a, b);
459
+ aura.test.assert(Math.abs(distance - Math.sqrt(10)) < 1e-9, 'vec2.distance');
460
+ const lerped = aura.vec2.lerp(a, b, 0.5);
461
+ aura.test.equal(lerped.x, 2.5, 'vec2.lerp x');
462
+ aura.test.equal(lerped.y, 2.5, 'vec2.lerp y');
463
+
464
+ const v3a = aura.vec3(1, 2, 3);
465
+ const v3b = aura.vec3(4, 5, 6);
466
+ const v3sum = aura.vec3.add(v3a, v3b);
467
+ aura.test.equal(v3sum.x, 5, 'vec3.add x');
468
+ aura.test.equal(v3sum.y, 7, 'vec3.add y');
469
+ aura.test.equal(v3sum.z, 9, 'vec3.add z');
470
+ const v3sub = aura.vec3.sub(v3b, v3a);
471
+ aura.test.equal(v3sub.x, 3, 'vec3.sub x');
472
+ aura.test.equal(v3sub.y, 3, 'vec3.sub y');
473
+ aura.test.equal(v3sub.z, 3, 'vec3.sub z');
474
+ const v3scaled = aura.vec3.scale(v3a, 2);
475
+ aura.test.equal(v3scaled.x, 2, 'vec3.scale x');
476
+ aura.test.equal(v3scaled.y, 4, 'vec3.scale y');
477
+ aura.test.equal(v3scaled.z, 6, 'vec3.scale z');
478
+ aura.test.equal(aura.vec3.dot(v3a, v3b), 32, 'vec3.dot');
479
+ const cross = aura.vec3.cross(aura.vec3(1, 0, 0), aura.vec3(0, 1, 0));
480
+ aura.test.equal(cross.x, 0, 'vec3.cross x');
481
+ aura.test.equal(cross.y, 0, 'vec3.cross y');
482
+ aura.test.equal(cross.z, 1, 'vec3.cross z');
483
+ aura.test.equal(aura.vec3.length(aura.vec3(0, 3, 4)), 5, 'vec3.length');
484
+ const v3normalized = aura.vec3.normalize(aura.vec3(0, 3, 4));
485
+ aura.test.assert(Math.abs(v3normalized.y - 0.6) < 1e-9, 'vec3.normalize y');
486
+ aura.test.assert(Math.abs(v3normalized.z - 0.8) < 1e-9, 'vec3.normalize z');
487
+ aura.test.assert(
488
+ Math.abs(aura.vec3.distance(v3a, v3b) - Math.sqrt(27)) < 1e-9,
489
+ 'vec3.distance',
490
+ );
491
+ const v3lerped = aura.vec3.lerp(aura.vec3(0, 0, 0), aura.vec3(2, 4, 6), 0.5);
492
+ aura.test.equal(v3lerped.x, 1, 'vec3.lerp x');
493
+ aura.test.equal(v3lerped.y, 2, 'vec3.lerp y');
494
+ aura.test.equal(v3lerped.z, 3, 'vec3.lerp z');
495
+
496
+ aura.test.equal(
497
+ aura.collision.rectRect(
498
+ { x: 0, y: 0, w: 10, h: 10 },
499
+ { x: 5, y: 5, w: 10, h: 10 },
500
+ ),
501
+ true,
502
+ 'collision.rectRect overlap',
503
+ );
504
+ aura.test.equal(
505
+ aura.collision.rectPoint(
506
+ { x: 0, y: 0, w: 10, h: 10 },
507
+ { x: 2, y: 2 },
508
+ ),
509
+ true,
510
+ 'collision.rectPoint true',
511
+ );
512
+ aura.test.equal(
513
+ aura.collision.circleCircle(
514
+ { x: 0, y: 0, radius: 4 },
515
+ { x: 6, y: 0, radius: 4 },
516
+ ),
517
+ true,
518
+ 'collision.circleCircle overlap',
519
+ );
520
+ aura.test.equal(
521
+ aura.collision.circlePoint(
522
+ { x: 0, y: 0, radius: 4 },
523
+ { x: 0, y: 0 },
524
+ ),
525
+ true,
526
+ 'collision.circlePoint true',
527
+ );
528
+ aura.test.equal(
529
+ aura.collision.circleRect(
530
+ { x: 20, y: 20, radius: 2 },
531
+ { x: 0, y: 0, w: 10, h: 10 },
532
+ ),
533
+ false,
534
+ 'collision.circleRect false case',
535
+ );
536
+
537
+ let afterCount = 0;
538
+ let everyCount = 0;
539
+
540
+ aura.timer.after(0.05, () => {
541
+ afterCount += 1;
542
+ });
543
+
544
+ const token = aura.timer.every(0.05, () => {
545
+ everyCount += 1;
546
+ });
547
+ aura.timer.cancel(token);
548
+
549
+ aura.test.assert(Number.isFinite(aura.timer.getDelta()), 'timer.getDelta should be numeric');
550
+ aura.test.assert(Number.isFinite(aura.timer.getTime()), 'timer.getTime should be numeric');
551
+ aura.test.assert(afterCount >= 0 && afterCount <= 1, 'timer.after should not synchronously over-fire');
552
+ aura.test.assert(everyCount >= 0 && everyCount <= 1, 'timer.every should not synchronously over-fire');
553
+ };
554
+ `,
555
+ },
556
+ {
557
+ id: 'phaser-platformer-vertical-slice',
558
+ modes: ['shim', 'native'],
559
+ namespaces: ['gameplay', 'draw2d', 'collision', 'tilemap'],
560
+ functions: [
561
+ 'aura.update',
562
+ 'aura.draw',
563
+ 'aura.draw2d.clear',
564
+ 'aura.draw2d.rect',
565
+ 'aura.collision.rectRect',
566
+ 'aura.tilemap.import',
567
+ 'aura.tilemap.queryPoint',
568
+ 'aura.tilemap.setRegion',
569
+ 'aura.tilemap.removeRegion',
570
+ 'aura.tilemap.setLayerCollision',
571
+ 'aura.tilemap.setLayerVisibility',
572
+ 'aura.tilemap.draw',
573
+ 'aura.tilemap.unload',
574
+ ],
575
+ verticalSliceScenario: {
576
+ engine: 'phaser',
577
+ scenarioId: 'platformer',
578
+ scenarioName: 'Platformer movement/jump loop',
579
+ parityClaims: [
580
+ 'fixed-step horizontal movement stays deterministic',
581
+ 'jump apex/landing timing remains deterministic',
582
+ 'post-landing grounding lock is stable',
583
+ 'tilemap runtime edits and layer controls keep query/draw state deterministic',
584
+ ],
585
+ checks: [
586
+ 'phaser.platformer.fixed-step.motion',
587
+ 'phaser.platformer.jump.apex-and-landing',
588
+ 'phaser.platformer.ground-lock.stable',
589
+ 'phaser.platformer.tilemap-mutation-query.deterministic',
590
+ ],
591
+ expectedDeterministicState: {
592
+ finalX: 12,
593
+ finalY: 0,
594
+ maxJumpHeight: 9,
595
+ landedStep: 6,
596
+ tilemapHitsBefore: 1,
597
+ tilemapHitsAfterRemove: 0,
598
+ tilemapHitsAfterRestore: 1,
599
+ },
600
+ },
601
+ nativeChecks: [
602
+ {
603
+ id: 'phaser.platformer.surface.collision-available',
604
+ expression: "typeof aura.collision?.rectRect === 'function'",
605
+ },
606
+ {
607
+ id: 'phaser.platformer.fixed-step.motion',
608
+ expression: "(() => { const input = [1, 1, 1, 0, 0, -1, -1, 0]; const state = { x: 0, y: 0, vx: 0, vy: 0, grounded: true }; for (let i = 0; i < input.length; i += 1) { const axis = input[i]; if (axis > 0) state.vx = Math.min(state.vx + 2, 4); else if (axis < 0) state.vx = Math.max(state.vx - 2, -4); else if (state.vx > 0) state.vx -= 1; else if (state.vx < 0) state.vx += 1; if (i === 1 && state.grounded) { state.vy = 7; state.grounded = false; } if (!state.grounded) { state.vy -= 2; state.y += state.vy; if (state.y <= 0) { state.y = 0; state.vy = 0; state.grounded = true; } } state.x += state.vx; } return state.x === 12 && state.y === 0 && state.vx === -1; })()",
609
+ },
610
+ {
611
+ id: 'phaser.platformer.jump.apex-and-landing',
612
+ expression: "(() => { const input = [1, 1, 1, 0, 0, -1, -1, 0]; const state = { y: 0, vy: 0, grounded: true, maxJumpHeight: 0, landedStep: null }; for (let i = 0; i < input.length; i += 1) { if (i === 1 && state.grounded) { state.vy = 7; state.grounded = false; } if (!state.grounded) { state.vy -= 2; state.y += state.vy; if (state.y > state.maxJumpHeight) state.maxJumpHeight = state.y; if (state.y <= 0) { state.y = 0; state.vy = 0; state.grounded = true; if (state.landedStep == null && i > 1) state.landedStep = i; } } } return state.maxJumpHeight === 9 && state.landedStep === 6 && state.y === 0 && state.grounded === true; })()",
613
+ },
614
+ {
615
+ id: 'phaser.platformer.ground-lock.stable',
616
+ expression: "(() => { const input = [1, 1, 1, 0, 0, -1, -1, 0, 0, 0]; const state = { y: 0, vy: 0, grounded: true }; const tail = []; for (let i = 0; i < input.length; i += 1) { if (i === 1 && state.grounded) { state.vy = 7; state.grounded = false; } if (!state.grounded) { state.vy -= 2; state.y += state.vy; if (state.y <= 0) { state.y = 0; state.vy = 0; state.grounded = true; } } tail.push(state.y); } return tail.slice(-3).every((entry) => entry === 0); })()",
617
+ },
618
+ {
619
+ id: 'phaser.platformer.tilemap-mutation-query.deterministic',
620
+ expression: "(() => { const fixture = { width: 4, height: 2, tilewidth: 16, tileheight: 16, solidLayerNames: ['blockers'], layers: [ { name: 'ground', type: 'tilelayer', width: 4, height: 2, data: Array.from({ length: 8 }, () => 1) }, { name: 'blockers', type: 'tilelayer', width: 4, height: 2, data: [0, 0, 1, 0, 0, 0, 0, 0] } ], tilesets: [ { firstgid: 1, image: 'tiles.png', tilewidth: 16, tileheight: 16, tilecount: 1, columns: 1 } ] }; const mapId = aura.tilemap.import(fixture); const before = aura.tilemap.queryPoint(mapId, { x: 32.5, y: 0.5 }); aura.tilemap.removeRegion(mapId, 'blockers', { x: 2, y: 0, w: 1, h: 1 }); const removed = aura.tilemap.queryPoint(mapId, { x: 32.5, y: 0.5 }); aura.tilemap.setRegion(mapId, 'blockers', { x: 2, y: 0, w: 1, h: 1 }, 1); aura.tilemap.setLayerCollision(mapId, 'blockers', false); const muted = aura.tilemap.queryPoint(mapId, { x: 32.5, y: 0.5 }); aura.tilemap.setLayerCollision(mapId, 'blockers', true); const restored = aura.tilemap.queryPoint(mapId, { x: 32.5, y: 0.5 }); aura.tilemap.setLayerVisibility(mapId, 'blockers', false); const hidden = aura.tilemap.draw(mapId, { cull: false }); aura.tilemap.setLayerVisibility(mapId, 'blockers', true); const visible = aura.tilemap.draw(mapId, { cull: false }); aura.tilemap.unload(mapId); return Array.isArray(before?.hits) && before.hits.length === 1 && Array.isArray(removed?.hits) && removed.hits.length === 0 && Array.isArray(muted?.hits) && muted.hits.length === 0 && Array.isArray(restored?.hits) && restored.hits.length === 1 && hidden?.layerOrder?.join(',') === 'ground' && visible?.layerOrder?.join(',') === 'ground,blockers'; })()",
621
+ },
622
+ ],
623
+ frames: 8,
624
+ source: `
625
+ const __platformerInput = [1, 1, 1, 0, 0, -1, -1, 0];
626
+ const __platformer = {
627
+ frame: 0,
628
+ x: 0,
629
+ y: 0,
630
+ vx: 0,
631
+ vy: 0,
632
+ grounded: true,
633
+ maxJumpHeight: 0,
634
+ landedStep: null,
635
+ tilemapId: 0,
636
+ tilemapHitsBefore: -1,
637
+ tilemapHitsAfterRemove: -1,
638
+ tilemapHitsMuted: -1,
639
+ tilemapHitsAfterRestore: -1,
640
+ tilemapHiddenOrder: '',
641
+ tilemapVisibleOrder: '',
642
+ };
643
+
644
+ function __stepPlatformer(step) {
645
+ const axis = __platformerInput[step];
646
+ if (axis > 0) __platformer.vx = Math.min(__platformer.vx + 2, 4);
647
+ else if (axis < 0) __platformer.vx = Math.max(__platformer.vx - 2, -4);
648
+ else if (__platformer.vx > 0) __platformer.vx -= 1;
649
+ else if (__platformer.vx < 0) __platformer.vx += 1;
650
+
651
+ if (step === 1 && __platformer.grounded) {
652
+ __platformer.vy = 7;
653
+ __platformer.grounded = false;
654
+ }
655
+
656
+ if (!__platformer.grounded) {
657
+ __platformer.vy -= 2;
658
+ __platformer.y += __platformer.vy;
659
+ if (__platformer.y > __platformer.maxJumpHeight) __platformer.maxJumpHeight = __platformer.y;
660
+ if (__platformer.y <= 0) {
661
+ __platformer.y = 0;
662
+ __platformer.vy = 0;
663
+ __platformer.grounded = true;
664
+ if (__platformer.landedStep == null && step > 1) __platformer.landedStep = step;
665
+ }
666
+ }
667
+
668
+ __platformer.x += __platformer.vx;
669
+ }
670
+
671
+ function __stepTilemapMutation(step) {
672
+ if (__platformer.tilemapId <= 0) return;
673
+ if (step === 0) {
674
+ const before = aura.tilemap.queryPoint(__platformer.tilemapId, { x: 32.5, y: 0.5 });
675
+ __platformer.tilemapHitsBefore = Array.isArray(before?.hits) ? before.hits.length : -1;
676
+ }
677
+ if (step === 2) {
678
+ aura.tilemap.removeRegion(__platformer.tilemapId, 'blockers', { x: 2, y: 0, w: 1, h: 1 });
679
+ const removed = aura.tilemap.queryPoint(__platformer.tilemapId, { x: 32.5, y: 0.5 });
680
+ __platformer.tilemapHitsAfterRemove = Array.isArray(removed?.hits) ? removed.hits.length : -1;
681
+ }
682
+ if (step === 4) {
683
+ aura.tilemap.setRegion(__platformer.tilemapId, 'blockers', { x: 2, y: 0, w: 1, h: 1 }, 1);
684
+ aura.tilemap.setLayerCollision(__platformer.tilemapId, 'blockers', false);
685
+ const muted = aura.tilemap.queryPoint(__platformer.tilemapId, { x: 32.5, y: 0.5 });
686
+ __platformer.tilemapHitsMuted = Array.isArray(muted?.hits) ? muted.hits.length : -1;
687
+ aura.tilemap.setLayerCollision(__platformer.tilemapId, 'blockers', true);
688
+ const restored = aura.tilemap.queryPoint(__platformer.tilemapId, { x: 32.5, y: 0.5 });
689
+ __platformer.tilemapHitsAfterRestore = Array.isArray(restored?.hits) ? restored.hits.length : -1;
690
+ }
691
+ if (step === 5) {
692
+ aura.tilemap.setLayerVisibility(__platformer.tilemapId, 'blockers', false);
693
+ const hidden = aura.tilemap.draw(__platformer.tilemapId, { cull: false });
694
+ __platformer.tilemapHiddenOrder = hidden?.layerOrder?.join(',') || '';
695
+ }
696
+ if (step === 6) {
697
+ aura.tilemap.setLayerVisibility(__platformer.tilemapId, 'blockers', true);
698
+ const visible = aura.tilemap.draw(__platformer.tilemapId, { cull: false });
699
+ __platformer.tilemapVisibleOrder = visible?.layerOrder?.join(',') || '';
700
+ }
701
+ }
702
+
703
+ aura.setup = function () {
704
+ __platformer.tilemapId = aura.tilemap.import({
705
+ width: 4,
706
+ height: 2,
707
+ tilewidth: 16,
708
+ tileheight: 16,
709
+ solidLayerNames: ['blockers'],
710
+ layers: [
711
+ {
712
+ name: 'ground',
713
+ type: 'tilelayer',
714
+ width: 4,
715
+ height: 2,
716
+ data: Array.from({ length: 8 }, () => 1),
717
+ },
718
+ {
719
+ name: 'blockers',
720
+ type: 'tilelayer',
721
+ width: 4,
722
+ height: 2,
723
+ data: [0, 0, 1, 0, 0, 0, 0, 0],
724
+ },
725
+ ],
726
+ tilesets: [
727
+ { firstgid: 1, image: 'tiles.png', tilewidth: 16, tileheight: 16, tilecount: 1, columns: 1 },
728
+ ],
729
+ });
730
+ };
731
+
732
+ aura.update = function () {
733
+ if (__platformer.frame < __platformerInput.length) {
734
+ __stepPlatformer(__platformer.frame);
735
+ __stepTilemapMutation(__platformer.frame);
736
+ }
737
+ __platformer.frame += 1;
738
+ };
739
+
740
+ aura.draw = function () {
741
+ aura.draw2d.clear(8, 10, 16);
742
+ aura.draw2d.rect(__platformer.x + 200, 140 - (__platformer.y * 2), 12, 18, aura.colors.white);
743
+ aura.draw2d.rect(0, 140, 320, 6, aura.colors.green);
744
+
745
+ if (__platformer.frame === __platformerInput.length) {
746
+ aura.test.equal(__platformer.x, 12, 'platformer x progression should stay deterministic');
747
+ aura.test.equal(__platformer.y, 0, 'platformer should land exactly on ground');
748
+ aura.test.equal(__platformer.maxJumpHeight, 9, 'platformer jump apex should stay deterministic');
749
+ aura.test.equal(__platformer.landedStep, 6, 'platformer landing step should stay deterministic');
750
+ aura.test.equal(__platformer.tilemapHitsBefore, 1, 'platformer tilemap query should start with one blocker hit');
751
+ aura.test.equal(__platformer.tilemapHitsAfterRemove, 0, 'platformer tilemap query should reflect live tile removal');
752
+ aura.test.equal(__platformer.tilemapHitsMuted, 0, 'platformer tilemap collision toggle should mute blocker hits');
753
+ aura.test.equal(__platformer.tilemapHitsAfterRestore, 1, 'platformer tilemap query should restore after collision toggle');
754
+ aura.test.equal(__platformer.tilemapHiddenOrder, 'ground', 'platformer tilemap visibility toggle should affect draw order');
755
+ aura.test.equal(__platformer.tilemapVisibleOrder, 'ground,blockers', 'platformer tilemap visibility restore should recover draw order');
756
+ aura.test.equal(aura.tilemap.unload(__platformer.tilemapId), true, 'platformer tilemap should unload after deterministic assertions');
757
+ __platformer.tilemapId = 0;
758
+ }
759
+ };
760
+ `,
761
+ },
762
+ {
763
+ id: 'phaser-topdown-combat-vertical-slice',
764
+ modes: ['shim', 'native'],
765
+ namespaces: ['gameplay', 'draw2d', 'collision', 'tilemap', 'input'],
766
+ functions: [
767
+ 'aura.update',
768
+ 'aura.draw',
769
+ 'aura.draw2d.clear',
770
+ 'aura.draw2d.rect',
771
+ 'aura.collision.rectRect',
772
+ 'aura.tilemap.import',
773
+ 'aura.tilemap.queryPoint',
774
+ 'aura.tilemap.unload',
775
+ 'aura.input.isKeyDown',
776
+ ],
777
+ verticalSliceScenario: {
778
+ engine: 'phaser',
779
+ scenarioId: 'topdown-combat',
780
+ scenarioName: 'Topdown movement/combat loop',
781
+ parityClaims: [
782
+ 'topdown movement path remains deterministic through runtime tilemap queries',
783
+ 'projectile loop is deterministic through runtime collision hooks',
784
+ 'reason-coded tilemap guardrails remain stable in gameplay loop',
785
+ ],
786
+ checks: [
787
+ 'phaser.topdown.fixed-step.pathing',
788
+ 'phaser.topdown.projectile-loop.deterministic',
789
+ 'phaser.topdown.enemy-defeat.deterministic',
790
+ ],
791
+ expectedDeterministicState: {
792
+ playerX: 1,
793
+ playerY: 1,
794
+ enemyHp: 0,
795
+ blockedMoves: 1,
796
+ spawnedProjectiles: 2,
797
+ hitCount: 1,
798
+ },
799
+ },
800
+ nativeChecks: [
801
+ {
802
+ id: 'phaser.topdown.surface.draw2d-available',
803
+ expression: "typeof aura.draw2d?.rect === 'function' && typeof aura.collision?.rectRect === 'function' && typeof aura.tilemap?.import === 'function' && typeof aura.tilemap?.queryPoint === 'function' && typeof aura.input?.isKeyDown === 'function'",
804
+ },
805
+ {
806
+ id: 'phaser.topdown.fixed-step.pathing',
807
+ expression: "(() => { const runSample = () => { const fixture = { width: 5, height: 5, tilewidth: 1, tileheight: 1, solidLayerNames: ['walls'], layers: [ { name: 'ground', type: 'tilelayer', width: 5, height: 5, data: Array.from({ length: 25 }, () => 1) }, { name: 'walls', type: 'tilelayer', width: 5, height: 5, data: [0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] } ], tilesets: [ { firstgid: 1, image: 'tiles.png', tilewidth: 1, tileheight: 1, tilecount: 1, columns: 1 } ] }; const mapId = aura.tilemap.import(fixture); const invalidPoint = aura.tilemap.queryPoint(mapId, { x: 'bad', y: 0 }); const invalidHandle = aura.tilemap.queryPoint(999999, { x: 0, y: 0 }); const inputProbe = ['left', 'right', 'up', 'down'].every((key) => typeof aura.input.isKeyDown(key) === 'boolean'); const steps = [{ x: 1, y: 0 }, { x: 1, y: 0 }, { x: 0, y: 1 }, { x: -1, y: 0 }, { x: 0, y: 1 }]; const player = { x: 0, y: 0, w: 0.8, h: 0.8 }; let blockedMoves = 0; for (const step of steps) { const nextX = player.x + step.x; const nextY = player.y + step.y; const probe = aura.tilemap.queryPoint(mapId, { x: nextX + 0.5, y: nextY + 0.5 }); const blocked = Array.isArray(probe?.hits) && probe.hits.length > 0; if (blocked) { blockedMoves += 1; continue; } player.x = nextX; player.y = nextY; } const unloaded = aura.tilemap.unload(mapId); return { playerX: player.x, playerY: player.y, blockedMoves, invalidPoint: invalidPoint?.reasonCode || null, invalidHandle: invalidHandle?.reasonCode || null, inputProbe, unloaded }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.playerX === 1 && first.playerY === 1 && first.blockedMoves === 1 && first.invalidPoint === 'invalid_point_args' && first.invalidHandle === 'invalid_map_handle' && first.inputProbe === true && first.unloaded === true; })()",
808
+ },
809
+ {
810
+ id: 'phaser.topdown.projectile-loop.deterministic',
811
+ expression: "(() => { const runSample = () => { const enemy = { x: 4, y: 2, w: 1, h: 1, hp: 1 }; const projectiles = []; let spawned = 0; let hits = 0; for (let frame = 0; frame < 5; frame += 1) { if (frame === 0 || frame === 2) { projectiles.push({ x: 1, y: 2, w: 0.5, h: 0.5, vx: 1, alive: true }); spawned += 1; } for (const shot of projectiles) { if (!shot.alive) continue; shot.x += shot.vx; if (aura.collision.rectRect(shot.x, shot.y, shot.w, shot.h, enemy.x, enemy.y, enemy.w, enemy.h) && enemy.hp > 0) { enemy.hp -= 1; hits += 1; shot.alive = false; } } } const remaining = projectiles.filter((shot) => shot.alive && shot.x < 8).length; const farApart = aura.collision.rectRect(0, 0, 1, 1, 10, 10, 1, 1); const overlaps = aura.collision.rectRect(0, 0, 1, 1, 0.25, 0.25, 1, 1); return { spawned, hits, remaining, enemyHp: enemy.hp, farApart, overlaps }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.spawned === 2 && first.hits === 1 && first.remaining === 1 && first.enemyHp === 0 && first.farApart === false && first.overlaps === true; })()",
812
+ },
813
+ {
814
+ id: 'phaser.topdown.enemy-defeat.deterministic',
815
+ expression: "(() => { const runSample = () => { const enemy = { x: 4, y: 2, w: 1, h: 1, hp: 2 }; const projectiles = []; let spawned = 0; let hits = 0; let defeatFrame = null; for (let frame = 0; frame < 7; frame += 1) { if (frame === 0 || frame === 2 || frame === 4) { projectiles.push({ x: 1, y: 2, w: 0.5, h: 0.5, vx: 1, alive: true }); spawned += 1; } for (const shot of projectiles) { if (!shot.alive) continue; shot.x += shot.vx; if (aura.collision.rectRect(shot.x, shot.y, shot.w, shot.h, enemy.x, enemy.y, enemy.w, enemy.h) && enemy.hp > 0) { enemy.hp -= 1; hits += 1; shot.alive = false; if (enemy.hp === 0 && defeatFrame === null) defeatFrame = frame; } } } return { enemyHp: enemy.hp, spawned, hits, defeatFrame }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.enemyHp === 0 && first.spawned === 3 && first.hits === 2 && first.defeatFrame === 4; })()",
816
+ },
817
+ ],
818
+ frames: 7,
819
+ source: `
820
+ const __topdownInput = [
821
+ { x: 1, y: 0, fire: false },
822
+ { x: 1, y: 0, fire: true },
823
+ { x: 0, y: 1, fire: false },
824
+ { x: -1, y: 0, fire: false },
825
+ { x: 0, y: 1, fire: true },
826
+ { x: 0, y: 0, fire: false },
827
+ { x: 0, y: 0, fire: false },
828
+ ];
829
+ const __topdown = {
830
+ frame: 0,
831
+ player: { x: 0, y: 0, w: 0.8, h: 0.8 },
832
+ enemy: { x: 10, y: 0, hp: 1 },
833
+ projectiles: [],
834
+ spawned: 0,
835
+ hits: 0,
836
+ blockedMoves: 0,
837
+ mapId: 0,
838
+ invalidPointReason: null,
839
+ invalidHandleReason: null,
840
+ inputProbeOk: false,
841
+ };
842
+
843
+ function __createTopdownFixture() {
844
+ return {
845
+ width: 5,
846
+ height: 5,
847
+ tilewidth: 1,
848
+ tileheight: 1,
849
+ solidLayerNames: ['walls'],
850
+ layers: [
851
+ {
852
+ name: 'ground',
853
+ type: 'tilelayer',
854
+ width: 5,
855
+ height: 5,
856
+ data: Array.from({ length: 25 }, () => 1),
857
+ },
858
+ {
859
+ name: 'walls',
860
+ type: 'tilelayer',
861
+ width: 5,
862
+ height: 5,
863
+ data: [0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
864
+ },
865
+ ],
866
+ tilesets: [
867
+ { firstgid: 1, image: 'tiles.png', tilewidth: 1, tileheight: 1, tilecount: 1, columns: 1 },
868
+ ],
869
+ };
870
+ }
871
+
872
+ function __stepTopdown(step) {
873
+ const nextX = __topdown.player.x + step.x;
874
+ const nextY = __topdown.player.y + step.y;
875
+ const probe = aura.tilemap.queryPoint(__topdown.mapId, { x: nextX + 0.5, y: nextY + 0.5 });
876
+ const blocked = Array.isArray(probe?.hits) && probe.hits.length > 0;
877
+ if (blocked) {
878
+ __topdown.blockedMoves += 1;
879
+ } else {
880
+ __topdown.player.x = nextX;
881
+ __topdown.player.y = nextY;
882
+ }
883
+
884
+ if (step.fire) {
885
+ __topdown.projectiles.push({ x: __topdown.player.x + 0.2, y: __topdown.player.y + 0.2, w: 0.4, h: 0.4, vx: 2, vy: 0, alive: true });
886
+ __topdown.spawned += 1;
887
+ }
888
+
889
+ for (const shot of __topdown.projectiles) {
890
+ if (!shot.alive) continue;
891
+ shot.x += shot.vx;
892
+ shot.y += shot.vy;
893
+ if (
894
+ aura.collision.rectRect(
895
+ shot.x,
896
+ shot.y,
897
+ shot.w,
898
+ shot.h,
899
+ __topdown.enemy.x,
900
+ __topdown.enemy.y,
901
+ 1,
902
+ 1,
903
+ ) && __topdown.enemy.hp > 0
904
+ ) {
905
+ __topdown.enemy.hp -= 1;
906
+ __topdown.hits += 1;
907
+ shot.alive = false;
908
+ }
909
+ }
910
+ __topdown.projectiles = __topdown.projectiles.filter((shot) => shot.alive && shot.x < 12);
911
+ }
912
+
913
+ aura.setup = function () {
914
+ __topdown.mapId = aura.tilemap.import(__createTopdownFixture());
915
+ const invalidPoint = aura.tilemap.queryPoint(__topdown.mapId, { x: 'bad', y: 0 });
916
+ const invalidHandle = aura.tilemap.queryPoint(999999, { x: 0, y: 0 });
917
+ __topdown.invalidPointReason = invalidPoint?.reasonCode || null;
918
+ __topdown.invalidHandleReason = invalidHandle?.reasonCode || null;
919
+ __topdown.inputProbeOk = ['left', 'right', 'up', 'down']
920
+ .every((key) => typeof aura.input.isKeyDown(key) === 'boolean');
921
+ };
922
+
923
+ aura.update = function () {
924
+ if (__topdown.frame < __topdownInput.length) {
925
+ __stepTopdown(__topdownInput[__topdown.frame]);
926
+ }
927
+ __topdown.frame += 1;
928
+ };
929
+
930
+ aura.draw = function () {
931
+ aura.draw2d.clear(12, 12, 20);
932
+ aura.draw2d.rect(80 + (__topdown.player.x * 8), 60 + (__topdown.player.y * 8), 8, 8, aura.colors.white);
933
+ if (__topdown.enemy.hp > 0) {
934
+ aura.draw2d.rect(80 + (__topdown.enemy.x * 8), 60 + (__topdown.enemy.y * 8), 8, 8, aura.colors.red);
935
+ }
936
+ for (const shot of __topdown.projectiles) {
937
+ aura.draw2d.rect(80 + (shot.x * 8), 60 + (shot.y * 8), 3, 2, aura.colors.yellow);
938
+ }
939
+
940
+ if (__topdown.frame === __topdownInput.length) {
941
+ aura.test.equal(__topdown.player.x, 1, 'topdown player x should be deterministic');
942
+ aura.test.equal(__topdown.player.y, 1, 'topdown player y should be deterministic');
943
+ aura.test.equal(__topdown.blockedMoves, 1, 'topdown blocked movement count should be deterministic');
944
+ aura.test.equal(__topdown.spawned, 2, 'topdown projectile spawns should be deterministic');
945
+ aura.test.equal(__topdown.hits, 1, 'topdown hit count should be deterministic');
946
+ aura.test.equal(__topdown.enemy.hp, 0, 'topdown enemy should be defeated deterministically');
947
+ aura.test.equal(__topdown.invalidPointReason, 'invalid_point_args', 'topdown invalid point reason code should be deterministic');
948
+ aura.test.equal(__topdown.invalidHandleReason, 'invalid_map_handle', 'topdown invalid map reason code should be deterministic');
949
+ aura.test.equal(__topdown.inputProbeOk, true, 'topdown input hooks should remain callable');
950
+ aura.test.equal(aura.tilemap.unload(__topdown.mapId), true, 'topdown tilemap should unload after assertions');
951
+ __topdown.mapId = 0;
952
+ }
953
+ };
954
+ `,
955
+ },
956
+ {
957
+ id: 'phaser-arcade-collision-loop-vertical-slice',
958
+ modes: ['shim', 'native'],
959
+ namespaces: ['gameplay', 'draw2d', 'collision', 'tilemap'],
960
+ functions: [
961
+ 'aura.update',
962
+ 'aura.draw',
963
+ 'aura.draw2d.clear',
964
+ 'aura.draw2d.rect',
965
+ 'aura.collision.rectRect',
966
+ 'aura.tilemap.import',
967
+ 'aura.tilemap.queryPoint',
968
+ 'aura.tilemap.unload',
969
+ ],
970
+ verticalSliceScenario: {
971
+ engine: 'phaser',
972
+ scenarioId: 'arcade-collision-loop',
973
+ scenarioName: 'Arcade collision/collectible loop',
974
+ parityClaims: [
975
+ 'pickup resolution order is deterministic',
976
+ 'single-hit enemy damage loop is deterministic',
977
+ 'score/life deltas are deterministic',
978
+ ],
979
+ checks: [
980
+ 'phaser.arcade.pickup-score.deterministic',
981
+ 'phaser.arcade.enemy-collision.single-hit',
982
+ 'phaser.arcade.final-state.deterministic',
983
+ ],
984
+ expectedDeterministicState: {
985
+ score: 30,
986
+ lives: 2,
987
+ enemyHits: 1,
988
+ remainingPickups: 0,
989
+ hazardContacts: 2,
990
+ },
991
+ },
992
+ nativeChecks: [
993
+ {
994
+ id: 'phaser.arcade.surface.collision-available',
995
+ expression: "typeof aura.collision?.rectRect === 'function' && typeof aura.tilemap?.import === 'function' && typeof aura.tilemap?.queryPoint === 'function'",
996
+ },
997
+ {
998
+ id: 'phaser.arcade.pickup-score.deterministic',
999
+ expression: "(() => { const runSample = () => { const state = { player: { x: 0, y: 0, w: 2, h: 2 }, enemy: { x: 11, y: 0, w: 2, h: 2, vx: -1 }, pickups: [{ x: 3, y: 0, w: 1, h: 1, active: true }, { x: 7, y: 0, w: 1, h: 1, active: true }, { x: 11, y: 0, w: 1, h: 1, active: true }], score: 0, enemyHits: 0, lives: 3 }; for (let frame = 0; frame < 7; frame += 1) { state.player.x += 2; state.enemy.x += state.enemy.vx; for (const pickup of state.pickups) { if (pickup.active && aura.collision.rectRect(state.player.x, state.player.y, state.player.w, state.player.h, pickup.x, pickup.y, pickup.w, pickup.h)) { pickup.active = false; state.score += 10; } } if (aura.collision.rectRect(state.player.x, state.player.y, state.player.w, state.player.h, state.enemy.x, state.enemy.y, state.enemy.w, state.enemy.h)) { state.enemyHits += 1; if (state.enemyHits === 1) state.lives -= 1; } } return { score: state.score, inactivePickups: state.pickups.filter((pickup) => pickup.active === false).length, enemyHits: state.enemyHits, lives: state.lives }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.score === 30 && first.inactivePickups === 3 && first.enemyHits === 1 && first.lives === 2; })()",
1000
+ },
1001
+ {
1002
+ id: 'phaser.arcade.enemy-collision.single-hit',
1003
+ expression: "(() => { const runSample = () => { const state = { player: { x: 0, y: 0, w: 2, h: 2 }, enemy: { x: 11, y: 0, w: 2, h: 2, vx: -1 }, lives: 3, enemyHits: 0 }; for (let frame = 0; frame < 7; frame += 1) { state.player.x += 2; state.enemy.x += state.enemy.vx; if (aura.collision.rectRect(state.player.x, state.player.y, state.player.w, state.player.h, state.enemy.x, state.enemy.y, state.enemy.w, state.enemy.h)) { state.enemyHits += 1; if (state.enemyHits === 1) state.lives -= 1; } } const farApart = aura.collision.rectRect(0, 0, 1, 1, 9, 9, 1, 1); const overlaps = aura.collision.rectRect(0, 0, 2, 2, 1, 1, 2, 2); return { enemyHits: state.enemyHits, lives: state.lives, farApart, overlaps }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.enemyHits === 1 && first.lives === 2 && first.farApart === false && first.overlaps === true; })()",
1004
+ },
1005
+ {
1006
+ id: 'phaser.arcade.final-state.deterministic',
1007
+ expression: "(() => { const runSample = () => { const fixture = { width: 4, height: 1, tilewidth: 1, tileheight: 1, solidLayerNames: ['hazards'], layers: [ { name: 'ground', type: 'tilelayer', width: 4, height: 1, data: [1, 1, 1, 1] }, { name: 'hazards', type: 'tilelayer', width: 4, height: 1, data: [0, 0, 1, 0] } ], tilesets: [ { firstgid: 1, image: 'tiles.png', tilewidth: 1, tileheight: 1, tilecount: 1, columns: 1 } ] }; const mapId = aura.tilemap.import(fixture); const invalidPoint = aura.tilemap.queryPoint(mapId, { x: 'bad', y: 0 }); const invalidHandle = aura.tilemap.queryPoint(999999, { x: 0, y: 0 }); const state = { player: { x: 0, y: 0, w: 2, h: 2 }, enemy: { x: 11, y: 0, w: 2, h: 2, vx: -1 }, pickups: [{ x: 3, y: 0, w: 1, h: 1, active: true }, { x: 7, y: 0, w: 1, h: 1, active: true }, { x: 11, y: 0, w: 1, h: 1, active: true }], score: 0, enemyHits: 0, lives: 3, hazardContacts: 0 }; for (let frame = 0; frame < 7; frame += 1) { state.player.x += 2; state.enemy.x += state.enemy.vx; for (const pickup of state.pickups) { if (pickup.active && aura.collision.rectRect(state.player.x, state.player.y, state.player.w, state.player.h, pickup.x, pickup.y, pickup.w, pickup.h)) { pickup.active = false; state.score += 10; } } const hazard = aura.tilemap.queryPoint(mapId, { x: Math.min(3.5, (state.player.x / 4) + 0.5), y: 0.5 }); if (Array.isArray(hazard?.hits) && hazard.hits.length > 0) state.hazardContacts += 1; if (aura.collision.rectRect(state.player.x, state.player.y, state.player.w, state.player.h, state.enemy.x, state.enemy.y, state.enemy.w, state.enemy.h)) { state.enemyHits += 1; if (state.enemyHits === 1) state.lives -= 1; } } const unloaded = aura.tilemap.unload(mapId); return { playerX: state.player.x, enemyX: state.enemy.x, score: state.score, lives: state.lives, enemyHits: state.enemyHits, remainingPickups: state.pickups.filter((pickup) => pickup.active).length, hazardContacts: state.hazardContacts, invalidPoint: invalidPoint?.reasonCode || null, invalidHandle: invalidHandle?.reasonCode || null, unloaded }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.playerX === 14 && first.enemyX === 4 && first.score === 30 && first.lives === 2 && first.enemyHits === 1 && first.remainingPickups === 0 && first.hazardContacts === 2 && first.invalidPoint === 'invalid_point_args' && first.invalidHandle === 'invalid_map_handle' && first.unloaded === true; })()",
1008
+ },
1009
+ ],
1010
+ frames: 7,
1011
+ source: `
1012
+ const __arcade = {
1013
+ frame: 0,
1014
+ player: { x: 0, y: 0, w: 2, h: 2 },
1015
+ enemy: { x: 11, y: 0, w: 2, h: 2, vx: -1 },
1016
+ pickups: [
1017
+ { id: 1, x: 3, y: 0, w: 1, h: 1, active: true },
1018
+ { id: 2, x: 7, y: 0, w: 1, h: 1, active: true },
1019
+ { id: 3, x: 11, y: 0, w: 1, h: 1, active: true },
1020
+ ],
1021
+ score: 0,
1022
+ lives: 3,
1023
+ enemyHits: 0,
1024
+ hazardContacts: 0,
1025
+ mapId: 0,
1026
+ invalidPointReason: null,
1027
+ invalidHandleReason: null,
1028
+ };
1029
+
1030
+ function __createArcadeFixture() {
1031
+ return {
1032
+ width: 4,
1033
+ height: 1,
1034
+ tilewidth: 1,
1035
+ tileheight: 1,
1036
+ solidLayerNames: ['hazards'],
1037
+ layers: [
1038
+ {
1039
+ name: 'ground',
1040
+ type: 'tilelayer',
1041
+ width: 4,
1042
+ height: 1,
1043
+ data: [1, 1, 1, 1],
1044
+ },
1045
+ {
1046
+ name: 'hazards',
1047
+ type: 'tilelayer',
1048
+ width: 4,
1049
+ height: 1,
1050
+ data: [0, 0, 1, 0],
1051
+ },
1052
+ ],
1053
+ tilesets: [
1054
+ { firstgid: 1, image: 'tiles.png', tilewidth: 1, tileheight: 1, tilecount: 1, columns: 1 },
1055
+ ],
1056
+ };
1057
+ }
1058
+
1059
+ function __stepArcade() {
1060
+ __arcade.player.x += 2;
1061
+ __arcade.enemy.x += __arcade.enemy.vx;
1062
+
1063
+ for (const pickup of __arcade.pickups) {
1064
+ if (
1065
+ pickup.active
1066
+ && aura.collision.rectRect(
1067
+ __arcade.player.x,
1068
+ __arcade.player.y,
1069
+ __arcade.player.w,
1070
+ __arcade.player.h,
1071
+ pickup.x,
1072
+ pickup.y,
1073
+ pickup.w,
1074
+ pickup.h,
1075
+ )
1076
+ ) {
1077
+ pickup.active = false;
1078
+ __arcade.score += 10;
1079
+ }
1080
+ }
1081
+
1082
+ if (
1083
+ aura.collision.rectRect(
1084
+ __arcade.player.x,
1085
+ __arcade.player.y,
1086
+ __arcade.player.w,
1087
+ __arcade.player.h,
1088
+ __arcade.enemy.x,
1089
+ __arcade.enemy.y,
1090
+ __arcade.enemy.w,
1091
+ __arcade.enemy.h,
1092
+ )
1093
+ ) {
1094
+ __arcade.enemyHits += 1;
1095
+ if (__arcade.enemyHits === 1) {
1096
+ __arcade.lives -= 1;
1097
+ }
1098
+ }
1099
+
1100
+ const hazardProbe = aura.tilemap.queryPoint(
1101
+ __arcade.mapId,
1102
+ { x: Math.min(3.5, (__arcade.player.x / 4) + 0.5), y: 0.5 },
1103
+ );
1104
+ if (Array.isArray(hazardProbe?.hits) && hazardProbe.hits.length > 0) {
1105
+ __arcade.hazardContacts += 1;
1106
+ }
1107
+ }
1108
+
1109
+ aura.setup = function () {
1110
+ __arcade.mapId = aura.tilemap.import(__createArcadeFixture());
1111
+ const invalidPoint = aura.tilemap.queryPoint(__arcade.mapId, { x: 'bad', y: 0 });
1112
+ const invalidHandle = aura.tilemap.queryPoint(999999, { x: 0, y: 0 });
1113
+ __arcade.invalidPointReason = invalidPoint?.reasonCode || null;
1114
+ __arcade.invalidHandleReason = invalidHandle?.reasonCode || null;
1115
+ };
1116
+
1117
+ aura.update = function () {
1118
+ if (__arcade.frame < 7) {
1119
+ __stepArcade();
1120
+ }
1121
+ __arcade.frame += 1;
1122
+ };
1123
+
1124
+ aura.draw = function () {
1125
+ aura.draw2d.clear(6, 6, 12);
1126
+ aura.draw2d.rect(40 + (__arcade.player.x * 8), 80, 8, 8, aura.colors.white);
1127
+ aura.draw2d.rect(40 + (__arcade.enemy.x * 8), 80, 8, 8, aura.colors.red);
1128
+ for (const pickup of __arcade.pickups) {
1129
+ if (pickup.active) {
1130
+ aura.draw2d.rect(40 + (pickup.x * 8), 78, 4, 4, aura.colors.yellow);
1131
+ }
1132
+ }
1133
+
1134
+ if (__arcade.frame === 7) {
1135
+ aura.test.equal(__arcade.score, 30, 'arcade score should be deterministic');
1136
+ aura.test.equal(__arcade.lives, 2, 'arcade life decrement should be deterministic');
1137
+ aura.test.equal(__arcade.enemyHits, 1, 'arcade enemy collision count should be deterministic');
1138
+ aura.test.equal(__arcade.pickups.filter((pickup) => pickup.active).length, 0, 'arcade pickups should all resolve');
1139
+ aura.test.equal(__arcade.hazardContacts, 2, 'arcade tilemap hazard contacts should be deterministic');
1140
+ aura.test.equal(__arcade.invalidPointReason, 'invalid_point_args', 'arcade invalid point reason code should be deterministic');
1141
+ aura.test.equal(__arcade.invalidHandleReason, 'invalid_map_handle', 'arcade invalid map reason code should be deterministic');
1142
+ aura.test.equal(aura.tilemap.unload(__arcade.mapId), true, 'arcade tilemap should unload after assertions');
1143
+ __arcade.mapId = 0;
1144
+ }
1145
+ };
1146
+ `,
1147
+ },
1148
+ {
1149
+ id: 'draw2d-layout-widgets-runtime-native',
1150
+ modes: ['native'],
1151
+ namespaces: ['draw2d', 'ui'],
1152
+ functions: [
1153
+ 'aura.draw2d.clear',
1154
+ 'aura.ui.beginLayout',
1155
+ 'aura.ui.label',
1156
+ 'aura.ui.button',
1157
+ 'aura.ui.toggle',
1158
+ 'aura.ui.slider',
1159
+ 'aura.ui.moveFocus',
1160
+ 'aura.ui.activate',
1161
+ 'aura.ui.adjustValue',
1162
+ 'aura.ui.endLayout',
1163
+ 'aura.ui.getFocusState',
1164
+ 'aura.ui.getWidgetState',
1165
+ 'aura.ui.reset',
1166
+ ],
1167
+ nativeChecks: [
1168
+ {
1169
+ id: 'draw2d.layout-widgets.surface.methods',
1170
+ expression: "(() => ['beginLayout','label','button','toggle','slider','moveFocus','activate','adjustValue','endLayout','getFocusState','getWidgetState','reset','__inspectorStats'].every((name) => typeof aura.ui?.[name] === 'function') && typeof aura.draw2d?.clear === 'function')()",
1171
+ },
1172
+ {
1173
+ id: 'draw2d.layout-widgets.runtime.setup',
1174
+ expression: `(() => { try { globalThis.__draw2dLayoutWidgetsProbe = { frames: [], musicValue: false, volumeValue: 4, invalidFocusReason: aura.ui.moveFocus('sideways')?.reasonCode || null, invalidActivateReason: aura.ui.activate('')?.reasonCode || null, invalidAdjustReason: aura.ui.adjustValue('volume', 0)?.reasonCode || null, resetReason: null }; return globalThis.__draw2dLayoutWidgetsProbe.invalidFocusReason === 'invalid_focus_direction' && globalThis.__draw2dLayoutWidgetsProbe.invalidActivateReason === 'invalid_widget_target' && globalThis.__draw2dLayoutWidgetsProbe.invalidAdjustReason === 'invalid_widget_delta'; } catch (_) { return false; } })()`,
1175
+ },
1176
+ ],
1177
+ nativePostChecks: [
1178
+ {
1179
+ id: 'draw2d.layout-widgets.runtime.evidence',
1180
+ expression: `(() => { try { const probe = globalThis.__draw2dLayoutWidgetsProbe || {}; const frames = Array.isArray(probe.frames) ? probe.frames : []; const frame0 = frames[0] || {}; const frame1 = frames[1] || {}; const frame2 = frames[2] || {}; const frame3 = frames[3] || {}; const frame4 = frames[4] || {}; const frame5 = frames[5] || {}; return probe.invalidFocusReason === 'invalid_focus_direction' && probe.invalidActivateReason === 'invalid_widget_target' && probe.invalidAdjustReason === 'invalid_widget_delta' && probe.moveReason === 'ui_focus_move_requested' && probe.activateReason === 'ui_widget_activation_requested' && probe.moveReason2 === 'ui_focus_move_requested' && probe.adjustReason === 'ui_widget_adjust_requested' && probe.resetReason === 'ui_focus_reset' && frames.length === 6 && frame0.endReason === 'ui_focus_initialized' && frame0.focusedId === 'play' && frame0.focusedIndex === 0 && frame0.inspect?.focusedWidgetId === 'play' && frame1.endReason === 'ui_focus_advanced' && frame1.focusedId === 'music' && frame1.inspect?.focusedWidgetId === 'music' && frame2.endReason === 'ui_layout_committed' && frame2.musicActivated === true && frame2.musicToggled === true && frame2.musicValue === true && frame2.musicStateReason === 'ui_toggle_changed' && frame2.inspect?.activatedWidgetId === 'music' && Array.isArray(frame2.inspect?.changedWidgetIds) && frame2.inspect.changedWidgetIds.includes('music') && frame3.endReason === 'ui_focus_advanced' && frame3.focusedId === 'volume' && frame3.inspect?.focusedWidgetId === 'volume' && frame4.endReason === 'ui_layout_committed' && frame4.volumeValue === 6 && frame4.volumeStateReason === 'ui_slider_changed' && Array.isArray(frame4.inspect?.changedWidgetIds) && frame4.inspect.changedWidgetIds.includes('volume') && frame5.endReason === 'ui_focus_initialized' && frame5.focusedId === 'play' && frame5.focusedIndex === 0 && frame5.inspect?.focusedWidgetId === 'play'; } catch (_) { return false; } })()`,
1181
+ },
1182
+ ],
1183
+ nativeFrames: 6,
1184
+ source: `
1185
+ globalThis.__draw2dLayoutWidgetsProbe = {
1186
+ frames: [],
1187
+ musicValue: false,
1188
+ volumeValue: 4,
1189
+ invalidFocusReason: null,
1190
+ invalidActivateReason: null,
1191
+ invalidAdjustReason: null,
1192
+ resetReason: null,
1193
+ };
1194
+ `,
1195
+ nativeSource: `
1196
+ const __checks = [];
1197
+ let __reported = false;
1198
+
1199
+ function __toErrorString(value) {
1200
+ return String(value && value.message ? value.message : value);
1201
+ }
1202
+
1203
+ function __record(id, pass, detail, trace = null) {
1204
+ const row = { id, pass: !!pass, detail: detail || null };
1205
+ if (!row.pass && trace !== null && trace !== undefined) {
1206
+ row.trace = trace;
1207
+ }
1208
+ __checks.push(row);
1209
+ }
1210
+
1211
+ function __finish() {
1212
+ if (__reported) {
1213
+ return;
1214
+ }
1215
+ const __failedChecks = __checks.filter((check) => !check.pass);
1216
+ console.log('__AURA_CONFORMANCE_NATIVE__' + JSON.stringify({
1217
+ caseId: 'draw2d-layout-widgets-runtime-native',
1218
+ ok: __failedChecks.length === 0,
1219
+ checks: __checks,
1220
+ failed: __failedChecks.length,
1221
+ passed: __checks.length - __failedChecks.length,
1222
+ runtimeCacheDiagnostics: null,
1223
+ runtimeInspectorSnapshot: null,
1224
+ }));
1225
+ __reported = true;
1226
+ if (aura.window && typeof aura.window.close === 'function') {
1227
+ aura.window.close();
1228
+ }
1229
+ }
1230
+
1231
+ globalThis.__draw2dLayoutWidgetsProbe = {
1232
+ frames: [],
1233
+ musicValue: false,
1234
+ volumeValue: 4,
1235
+ invalidFocusReason: null,
1236
+ invalidActivateReason: null,
1237
+ invalidAdjustReason: null,
1238
+ resetReason: null,
1239
+ };
1240
+
1241
+ aura.setup = function () {
1242
+ try {
1243
+ const methodsOk = ['beginLayout', 'label', 'button', 'toggle', 'slider', 'moveFocus', 'activate', 'adjustValue', 'endLayout', 'getFocusState', 'getWidgetState', 'reset', '__inspectorStats']
1244
+ .every((name) => typeof aura.ui?.[name] === 'function')
1245
+ && typeof aura.draw2d?.clear === 'function';
1246
+ __record(
1247
+ 'draw2d.layout-widgets.surface.methods',
1248
+ methodsOk,
1249
+ methodsOk ? null : 'required_methods_missing',
1250
+ methodsOk ? null : {
1251
+ uiInspectorStats: typeof aura.ui?.__inspectorStats,
1252
+ draw2dClear: typeof aura.draw2d?.clear,
1253
+ },
1254
+ );
1255
+
1256
+ const probe = {
1257
+ frames: [],
1258
+ musicValue: false,
1259
+ volumeValue: 4,
1260
+ invalidFocusReason: aura.ui.moveFocus('sideways')?.reasonCode || null,
1261
+ invalidActivateReason: aura.ui.activate('')?.reasonCode || null,
1262
+ invalidAdjustReason: aura.ui.adjustValue('volume', 0)?.reasonCode || null,
1263
+ resetReason: null,
1264
+ };
1265
+ globalThis.__draw2dLayoutWidgetsProbe = probe;
1266
+ const setupOk = probe.invalidFocusReason === 'invalid_focus_direction'
1267
+ && probe.invalidActivateReason === 'invalid_widget_target'
1268
+ && probe.invalidAdjustReason === 'invalid_widget_delta';
1269
+ __record(
1270
+ 'draw2d.layout-widgets.runtime.setup',
1271
+ setupOk,
1272
+ setupOk ? null : 'draw2d_layout_widgets_setup_failed',
1273
+ setupOk ? null : { probe },
1274
+ );
1275
+
1276
+ aura.update = function () {};
1277
+ aura.draw = function () {
1278
+ const frameProbe = globalThis.__draw2dLayoutWidgetsProbe || {};
1279
+ const frameIndex = Array.isArray(frameProbe.frames) ? frameProbe.frames.length : 0;
1280
+
1281
+ if (frameIndex === 1) {
1282
+ frameProbe.moveReason = aura.ui.moveFocus('next')?.reasonCode || null;
1283
+ } else if (frameIndex === 2) {
1284
+ frameProbe.activateReason = aura.ui.activate()?.reasonCode || null;
1285
+ } else if (frameIndex === 3) {
1286
+ frameProbe.moveReason2 = aura.ui.moveFocus('next')?.reasonCode || null;
1287
+ } else if (frameIndex === 4) {
1288
+ frameProbe.adjustReason = aura.ui.adjustValue(1)?.reasonCode || null;
1289
+ } else if (frameIndex === 5) {
1290
+ frameProbe.resetReason = aura.ui.reset('menu')?.reasonCode || null;
1291
+ }
1292
+
1293
+ aura.draw2d.clear(6, 8, 12);
1294
+ const start = aura.ui.beginLayout({ id: 'menu', x: 8, y: 12, direction: 'vertical', gap: 4 });
1295
+ const title = aura.ui.label('title', { text: 'Main Menu', width: 120, height: 20 });
1296
+ const play = aura.ui.button('play', { label: 'Play', width: 120, height: 24 });
1297
+ const music = aura.ui.toggle('music', { label: 'Music', width: 120, height: 24, value: frameProbe.musicValue });
1298
+ const volume = aura.ui.slider('volume', { label: 'Volume', width: 120, height: 24, min: 0, max: 10, step: 2, value: frameProbe.volumeValue });
1299
+ const end = aura.ui.endLayout();
1300
+ const focus = aura.ui.getFocusState('menu');
1301
+ const playState = aura.ui.getWidgetState('play', 'menu');
1302
+ const musicState = aura.ui.getWidgetState('music', 'menu');
1303
+ const volumeState = aura.ui.getWidgetState('volume', 'menu');
1304
+ const inspect = aura.ui.__inspectorStats();
1305
+
1306
+ frameProbe.musicValue = musicState?.value ?? frameProbe.musicValue;
1307
+ frameProbe.volumeValue = volumeState?.value ?? frameProbe.volumeValue;
1308
+ frameProbe.frames.push({
1309
+ frameIndex,
1310
+ startReason: start?.reasonCode || null,
1311
+ titleReason: title?.reasonCode || null,
1312
+ playReason: play?.reasonCode || null,
1313
+ musicReason: music?.reasonCode || null,
1314
+ volumeReason: volume?.reasonCode || null,
1315
+ endReason: end?.reasonCode || null,
1316
+ focusedId: focus?.focusedId || null,
1317
+ focusedIndex: Number(focus?.focusedIndex ?? -1),
1318
+ playFocused: playState?.focused === true,
1319
+ musicFocused: musicState?.focused === true,
1320
+ musicActivated: musicState?.activated === true,
1321
+ musicToggled: musicState?.toggled === true,
1322
+ musicValue: musicState?.value ?? null,
1323
+ musicStateReason: musicState?.reasonCode || null,
1324
+ volumeFocused: volumeState?.focused === true,
1325
+ volumeValue: volumeState?.value ?? null,
1326
+ volumeStateReason: volumeState?.reasonCode || null,
1327
+ inspect,
1328
+ });
1329
+
1330
+ if (frameProbe.frames.length < 6) {
1331
+ return;
1332
+ }
1333
+
1334
+ const frames = frameProbe.frames;
1335
+ const frame0 = frames[0] || {};
1336
+ const frame1 = frames[1] || {};
1337
+ const frame2 = frames[2] || {};
1338
+ const frame3 = frames[3] || {};
1339
+ const frame4 = frames[4] || {};
1340
+ const frame5 = frames[5] || {};
1341
+ const evidenceOk = frameProbe.invalidFocusReason === 'invalid_focus_direction'
1342
+ && frameProbe.invalidActivateReason === 'invalid_widget_target'
1343
+ && frameProbe.invalidAdjustReason === 'invalid_widget_delta'
1344
+ && frameProbe.moveReason === 'ui_focus_move_requested'
1345
+ && frameProbe.activateReason === 'ui_widget_activation_requested'
1346
+ && frameProbe.moveReason2 === 'ui_focus_move_requested'
1347
+ && frameProbe.adjustReason === 'ui_widget_adjust_requested'
1348
+ && frameProbe.resetReason === 'ui_focus_reset'
1349
+ && frames.length === 6
1350
+ && frame0.startReason === 'ui_layout_started'
1351
+ && frame0.titleReason === 'ui_label_registered'
1352
+ && frame0.playReason === 'ui_button_registered'
1353
+ && frame0.musicReason === 'ui_toggle_registered'
1354
+ && frame0.volumeReason === 'ui_slider_registered'
1355
+ && frame0.endReason === 'ui_focus_initialized'
1356
+ && frame0.focusedId === 'play'
1357
+ && frame0.focusedIndex === 0
1358
+ && frame0.playFocused === true
1359
+ && frame0.musicValue === false
1360
+ && frame0.volumeValue === 4
1361
+ && frame0.inspect?.widgetCount === 4
1362
+ && frame0.inspect?.focusableCount === 3
1363
+ && frame0.inspect?.focusedWidgetId === 'play'
1364
+ && frame0.inspect?.lastReasonCode === 'ui_focus_initialized'
1365
+ && frame1.endReason === 'ui_focus_advanced'
1366
+ && frame1.focusedId === 'music'
1367
+ && frame1.focusedIndex === 1
1368
+ && frame1.musicFocused === true
1369
+ && frame1.inspect?.focusedWidgetId === 'music'
1370
+ && frame1.inspect?.lastReasonCode === 'ui_focus_advanced'
1371
+ && frame2.endReason === 'ui_layout_committed'
1372
+ && frame2.focusedId === 'music'
1373
+ && frame2.focusedIndex === 1
1374
+ && frame2.musicFocused === true
1375
+ && frame2.musicActivated === true
1376
+ && frame2.musicToggled === true
1377
+ && frame2.musicValue === true
1378
+ && frame2.musicStateReason === 'ui_toggle_changed'
1379
+ && frame2.inspect?.activatedWidgetId === 'music'
1380
+ && Array.isArray(frame2.inspect?.changedWidgetIds)
1381
+ && frame2.inspect.changedWidgetIds.includes('music')
1382
+ && frame2.inspect?.lastWidgetReasonCode === 'ui_toggle_changed'
1383
+ && frame3.endReason === 'ui_focus_advanced'
1384
+ && frame3.focusedId === 'volume'
1385
+ && frame3.focusedIndex === 2
1386
+ && frame3.volumeFocused === true
1387
+ && frame3.inspect?.focusedWidgetId === 'volume'
1388
+ && frame3.inspect?.lastReasonCode === 'ui_focus_advanced'
1389
+ && frame4.endReason === 'ui_layout_committed'
1390
+ && frame4.focusedId === 'volume'
1391
+ && frame4.focusedIndex === 2
1392
+ && frame4.volumeFocused === true
1393
+ && frame4.volumeValue === 6
1394
+ && frame4.volumeStateReason === 'ui_slider_changed'
1395
+ && Array.isArray(frame4.inspect?.changedWidgetIds)
1396
+ && frame4.inspect.changedWidgetIds.includes('volume')
1397
+ && frame4.inspect?.lastWidgetReasonCode === 'ui_slider_changed'
1398
+ && frame5.endReason === 'ui_focus_initialized'
1399
+ && frame5.focusedId === 'play'
1400
+ && frame5.focusedIndex === 0
1401
+ && frame5.playFocused === true
1402
+ && frame5.musicValue === true
1403
+ && frame5.volumeValue === 6
1404
+ && frame5.inspect?.focusedWidgetId === 'play'
1405
+ && frame5.inspect?.lastReasonCode === 'ui_focus_initialized';
1406
+ __record(
1407
+ 'draw2d.layout-widgets.runtime.evidence',
1408
+ evidenceOk,
1409
+ evidenceOk ? null : 'draw2d_layout_widgets_evidence_failed',
1410
+ evidenceOk ? null : { probe: frameProbe },
1411
+ );
1412
+ __finish();
1413
+ };
1414
+ } catch (__error) {
1415
+ __record('draw2d.layout-widgets.runtime.setup', false, __toErrorString(__error), {
1416
+ probe: globalThis.__draw2dLayoutWidgetsProbe || null,
1417
+ });
1418
+ __finish();
1419
+ }
1420
+ };
1421
+ `,
1422
+ },
1423
+ {
1424
+ id: 'draw2d-compositor-fx-runtime-native',
1425
+ modes: ['native'],
1426
+ namespaces: ['draw2d', 'debug'],
1427
+ functions: [
1428
+ 'aura.draw2d.clear',
1429
+ 'aura.draw2d.createRenderTarget',
1430
+ 'aura.draw2d.destroyRenderTarget',
1431
+ 'aura.draw2d.withRenderTargets',
1432
+ 'aura.draw2d.sprite',
1433
+ 'aura.draw2d.spriteFx',
1434
+ 'aura.draw2d.rectFill',
1435
+ 'aura.debug.inspectorStats',
1436
+ ],
1437
+ nativeChecks: [
1438
+ {
1439
+ id: 'draw2d.compositor-fx.surface.methods',
1440
+ expression: "(() => ['clear','createRenderTarget','destroyRenderTarget','withRenderTargets','sprite','spriteFx','rectFill'].every((name) => typeof aura.draw2d?.[name] === 'function') && typeof aura.debug?.inspectorStats === 'function')()",
1441
+ },
1442
+ {
1443
+ id: 'draw2d.compositor-fx.runtime.setup',
1444
+ expression: `(() => { try { const rtA = aura.draw2d.createRenderTarget(32, 16); const rtB = aura.draw2d.createRenderTarget(48, 24); globalThis.__draw2dCompositorFxProbe = { rtA, rtB, frames: [] }; return rtA?.ok === true && rtB?.ok === true && rtA?.type === 'renderTarget' && rtB?.type === 'renderTarget' && rtA?.__renderTarget === true && rtB?.__renderTarget === true && Number.isInteger(rtA?.handle) && Number.isInteger(rtB?.handle) && rtA.handle !== rtB.handle; } catch (_) { return false; } })()`,
1445
+ },
1446
+ ],
1447
+ nativePostChecks: [
1448
+ {
1449
+ id: 'draw2d.compositor-fx.runtime.evidence',
1450
+ expression: `(() => { try { const probe = globalThis.__draw2dCompositorFxProbe || {}; const frames = Array.isArray(probe.frames) ? probe.frames : []; const frame0 = frames[0] || {}; const frame1 = frames[1] || {}; const frame2 = frames[2] || {}; const destroyA = aura.draw2d.destroyRenderTarget(probe.rtA); const destroyB = aura.draw2d.destroyRenderTarget(probe.rtB); const missingDestroy = aura.draw2d.destroyRenderTarget(probe.rtB); return frames.length === 3 && frame0.duplicateReason === 'duplicate_render_target_stage' && frame0.invalidFxHandleReason === 'invalid_sprite_fx_source_handle' && frame0.missingShadowReason === 'missing_sprite_fx_effect' && frame0.graphReason === 'draw2d_render_targets_captured' && frame0.stageCount === 2 && frame0.commandCount === 5 && frame0.handlesLength === 2 && frame0.fxQueueReason === 'draw2d_sprite_fx_queued' && frame0.submittedFxDrawCount === 1 && frame0.pendingFxCommandCount === 1 && frame0.lastSubmittedFxCommandCount === 0 && frame0.lastExecutedFxCommandCount === 0 && frame0.lastReasonCode === 'draw2d_fx_idle' && frame0.lastOk === true && frame1.pendingFxCommandCount === 0 && frame1.lastSubmittedFxCommandCount === 1 && frame1.lastExecutedFxCommandCount === 1 && frame1.lastReasonCode === 'draw2d_fx_executed' && frame1.lastOk === true && frame2.pendingFxCommandCount === 0 && frame2.lastSubmittedFxCommandCount === 0 && frame2.lastExecutedFxCommandCount === 0 && frame2.lastReasonCode === 'draw2d_fx_idle' && frame2.lastOk === true && destroyA?.ok === true && destroyA?.reasonCode === 'draw2d_render_target_destroyed' && destroyB?.ok === true && destroyB?.reasonCode === 'draw2d_render_target_destroyed' && missingDestroy?.ok === false && missingDestroy?.reasonCode === 'missing_render_target'; } catch (_) { return false; } })()`,
1451
+ },
1452
+ ],
1453
+ nativeFrames: 3,
1454
+ source: `
1455
+ globalThis.__draw2dCompositorFxProbe = {
1456
+ rtA: null,
1457
+ rtB: null,
1458
+ frames: [],
1459
+ };
1460
+ `,
1461
+ nativeSource: `
1462
+ const __checks = [];
1463
+ let __reported = false;
1464
+
1465
+ function __toErrorString(value) {
1466
+ return String(value && value.message ? value.message : value);
1467
+ }
1468
+
1469
+ function __record(id, pass, detail, trace = null) {
1470
+ const row = { id, pass: !!pass, detail: detail || null };
1471
+ if (!row.pass && trace !== null && trace !== undefined) {
1472
+ row.trace = trace;
1473
+ }
1474
+ __checks.push(row);
1475
+ }
1476
+
1477
+ function __finish() {
1478
+ if (__reported) {
1479
+ return;
1480
+ }
1481
+ const __failedChecks = __checks.filter((check) => !check.pass);
1482
+ console.log('__AURA_CONFORMANCE_NATIVE__' + JSON.stringify({
1483
+ caseId: 'draw2d-compositor-fx-runtime-native',
1484
+ ok: __failedChecks.length === 0,
1485
+ checks: __checks,
1486
+ failed: __failedChecks.length,
1487
+ passed: __checks.length - __failedChecks.length,
1488
+ runtimeCacheDiagnostics: null,
1489
+ runtimeInspectorSnapshot: null,
1490
+ }));
1491
+ __reported = true;
1492
+ if (aura.window && typeof aura.window.close === 'function') {
1493
+ aura.window.close();
1494
+ }
1495
+ }
1496
+
1497
+ globalThis.__draw2dCompositorFxProbe = {
1498
+ rtA: null,
1499
+ rtB: null,
1500
+ frames: [],
1501
+ };
1502
+
1503
+ aura.setup = function () {
1504
+ try {
1505
+ const methodsOk = ['clear', 'createRenderTarget', 'destroyRenderTarget', 'withRenderTargets', 'sprite', 'spriteFx', 'rectFill']
1506
+ .every((name) => typeof aura.draw2d?.[name] === 'function')
1507
+ && typeof aura.debug?.inspectorStats === 'function';
1508
+ __record(
1509
+ 'draw2d.compositor-fx.surface.methods',
1510
+ methodsOk,
1511
+ methodsOk ? null : 'required_methods_missing',
1512
+ methodsOk ? null : {
1513
+ draw2d: {
1514
+ clear: typeof aura.draw2d?.clear,
1515
+ createRenderTarget: typeof aura.draw2d?.createRenderTarget,
1516
+ destroyRenderTarget: typeof aura.draw2d?.destroyRenderTarget,
1517
+ withRenderTargets: typeof aura.draw2d?.withRenderTargets,
1518
+ sprite: typeof aura.draw2d?.sprite,
1519
+ spriteFx: typeof aura.draw2d?.spriteFx,
1520
+ rectFill: typeof aura.draw2d?.rectFill,
1521
+ },
1522
+ debugInspectorStats: typeof aura.debug?.inspectorStats,
1523
+ },
1524
+ );
1525
+
1526
+ const rtA = aura.draw2d.createRenderTarget(32, 16);
1527
+ const rtB = aura.draw2d.createRenderTarget(48, 24);
1528
+ const probe = { rtA, rtB, frames: [] };
1529
+ globalThis.__draw2dCompositorFxProbe = probe;
1530
+ const setupOk = rtA?.ok === true
1531
+ && rtB?.ok === true
1532
+ && rtA?.type === 'renderTarget'
1533
+ && rtB?.type === 'renderTarget'
1534
+ && rtA?.__renderTarget === true
1535
+ && rtB?.__renderTarget === true
1536
+ && Number.isInteger(rtA?.handle)
1537
+ && Number.isInteger(rtB?.handle)
1538
+ && rtA.handle !== rtB.handle;
1539
+ __record(
1540
+ 'draw2d.compositor-fx.runtime.setup',
1541
+ setupOk,
1542
+ setupOk ? null : 'draw2d_compositor_fx_setup_failed',
1543
+ setupOk ? null : { probe },
1544
+ );
1545
+
1546
+ aura.update = function () {};
1547
+ aura.draw = function () {
1548
+ const frameProbe = globalThis.__draw2dCompositorFxProbe || {};
1549
+ const frameIndex = Array.isArray(frameProbe.frames) ? frameProbe.frames.length : 0;
1550
+ const white = aura.Color?.WHITE || aura.colors?.white || aura.rgba(1, 1, 1, 1);
1551
+
1552
+ aura.draw2d.clear(4, 6, 10);
1553
+ let duplicate = null;
1554
+ let invalidFxHandle = null;
1555
+ let missingShadow = null;
1556
+ let graph = null;
1557
+ let fxQueued = null;
1558
+
1559
+ if (frameIndex === 0) {
1560
+ duplicate = aura.draw2d.withRenderTargets([
1561
+ { target: frameProbe.rtA, draw: () => {} },
1562
+ { target: frameProbe.rtA, draw: () => {} },
1563
+ ]);
1564
+ invalidFxHandle = aura.draw2d.spriteFx({ type: 'renderTarget', handle: 9999 }, 1, 2, {
1565
+ shadow: { offsetX: 1, offsetY: 1 },
1566
+ });
1567
+ missingShadow = aura.draw2d.spriteFx('hero.png', 1, 2, {});
1568
+ graph = aura.draw2d.withRenderTargets([
1569
+ {
1570
+ target: frameProbe.rtA,
1571
+ draw: () => {
1572
+ aura.draw2d.clear(0, 0, 0, 0);
1573
+ aura.draw2d.rectFill(1, 2, 3, 4, white);
1574
+ },
1575
+ },
1576
+ {
1577
+ target: frameProbe.rtB,
1578
+ draw: () => {
1579
+ aura.draw2d.sprite(frameProbe.rtA, 0, 0, 16, 16);
1580
+ fxQueued = aura.draw2d.spriteFx(frameProbe.rtA, 8, 6, {
1581
+ width: 16,
1582
+ height: 12,
1583
+ shadow: { offsetX: 3, offsetY: 4 },
1584
+ });
1585
+ },
1586
+ },
1587
+ ]);
1588
+ }
1589
+
1590
+ aura.draw2d.sprite(frameProbe.rtB, 8, 9, 64, 32);
1591
+ const stats = aura.debug.inspectorStats() || {};
1592
+ const fx = stats.draw2dRuntime?.fx || {};
1593
+ frameProbe.frames.push({
1594
+ frameIndex,
1595
+ duplicateReason: duplicate?.reasonCode || null,
1596
+ invalidFxHandleReason: invalidFxHandle?.reasonCode || null,
1597
+ missingShadowReason: missingShadow?.reasonCode || null,
1598
+ graphReason: graph?.reasonCode || null,
1599
+ stageCount: Number(graph?.stageCount || 0),
1600
+ commandCount: Number(graph?.commandCount || 0),
1601
+ handlesLength: Array.isArray(graph?.handles) ? graph.handles.length : 0,
1602
+ fxQueueReason: fxQueued?.reasonCode || null,
1603
+ submittedFxDrawCount: Number(fxQueued?.submittedFxDrawCount || 0),
1604
+ pendingFxCommandCount: Number(fx.pendingFxCommandCount || 0),
1605
+ lastSubmittedFxCommandCount: Number(fx.lastSubmittedFxCommandCount || 0),
1606
+ lastExecutedFxCommandCount: Number(fx.lastExecutedFxCommandCount || 0),
1607
+ lastReasonCode: fx.lastReasonCode || null,
1608
+ lastOk: fx.lastOk === true,
1609
+ });
1610
+
1611
+ if (frameProbe.frames.length < 3) {
1612
+ return;
1613
+ }
1614
+
1615
+ const frames = frameProbe.frames;
1616
+ const frame0 = frames[0] || {};
1617
+ const frame1 = frames[1] || {};
1618
+ const frame2 = frames[2] || {};
1619
+ const destroyA = aura.draw2d.destroyRenderTarget(frameProbe.rtA);
1620
+ const destroyB = aura.draw2d.destroyRenderTarget(frameProbe.rtB);
1621
+ const missingDestroy = aura.draw2d.destroyRenderTarget(frameProbe.rtB);
1622
+ const evidenceOk = frame0.duplicateReason === 'duplicate_render_target_stage'
1623
+ && frame0.invalidFxHandleReason === 'invalid_sprite_fx_source_handle'
1624
+ && frame0.missingShadowReason === 'missing_sprite_fx_effect'
1625
+ && frame0.graphReason === 'draw2d_render_targets_captured'
1626
+ && frame0.stageCount === 2
1627
+ && frame0.commandCount === 5
1628
+ && frame0.handlesLength === 2
1629
+ && frame0.fxQueueReason === 'draw2d_sprite_fx_queued'
1630
+ && frame0.submittedFxDrawCount === 1
1631
+ && frame0.pendingFxCommandCount === 1
1632
+ && frame0.lastSubmittedFxCommandCount === 0
1633
+ && frame0.lastExecutedFxCommandCount === 0
1634
+ && frame0.lastReasonCode === 'draw2d_fx_idle'
1635
+ && frame0.lastOk === true
1636
+ && frame1.graphReason === null
1637
+ && frame1.pendingFxCommandCount === 0
1638
+ && frame1.lastSubmittedFxCommandCount === 1
1639
+ && frame1.lastExecutedFxCommandCount === 1
1640
+ && frame1.lastReasonCode === 'draw2d_fx_executed'
1641
+ && frame1.lastOk === true
1642
+ && frame2.graphReason === null
1643
+ && frame2.pendingFxCommandCount === 0
1644
+ && frame2.lastSubmittedFxCommandCount === 0
1645
+ && frame2.lastExecutedFxCommandCount === 0
1646
+ && frame2.lastReasonCode === 'draw2d_fx_idle'
1647
+ && frame2.lastOk === true
1648
+ && destroyA?.ok === true
1649
+ && destroyA?.reasonCode === 'draw2d_render_target_destroyed'
1650
+ && destroyB?.ok === true
1651
+ && destroyB?.reasonCode === 'draw2d_render_target_destroyed'
1652
+ && missingDestroy?.ok === false
1653
+ && missingDestroy?.reasonCode === 'missing_render_target';
1654
+ __record(
1655
+ 'draw2d.compositor-fx.runtime.evidence',
1656
+ evidenceOk,
1657
+ evidenceOk ? null : 'draw2d_compositor_fx_evidence_failed',
1658
+ evidenceOk ? null : { probe: frameProbe, destroyA, destroyB, missingDestroy },
1659
+ );
1660
+ __finish();
1661
+ };
1662
+ } catch (__error) {
1663
+ __record('draw2d.compositor-fx.runtime.setup', false, __toErrorString(__error), {
1664
+ probe: globalThis.__draw2dCompositorFxProbe || null,
1665
+ });
1666
+ __finish();
1667
+ }
1668
+ };
1669
+ `,
1670
+ },
1671
+ {
1672
+ id: 'draw2d-advanced-mask-runtime-native',
1673
+ modes: ['native'],
1674
+ namespaces: ['draw2d', 'debug'],
1675
+ functions: [
1676
+ 'aura.draw2d.clear',
1677
+ 'aura.draw2d.withMask',
1678
+ 'aura.draw2d.rectFill',
1679
+ 'aura.draw2d.circleFill',
1680
+ 'aura.draw2d.text',
1681
+ 'aura.debug.inspectorStats',
1682
+ ],
1683
+ nativeChecks: [
1684
+ {
1685
+ id: 'draw2d.advanced-mask.surface.methods',
1686
+ expression: "(() => ['clear','withMask','rectFill','circleFill','text'].every((name) => typeof aura.draw2d?.[name] === 'function') && typeof aura.debug?.inspectorStats === 'function')()",
1687
+ },
1688
+ {
1689
+ id: 'draw2d.advanced-mask.runtime.setup',
1690
+ expression: "(() => true)()",
1691
+ },
1692
+ ],
1693
+ nativePostChecks: [
1694
+ {
1695
+ id: 'draw2d.advanced-mask.runtime.evidence',
1696
+ expression: "(() => { try { const probe = globalThis.__draw2dAdvancedMaskProbe || {}; return Array.isArray(probe.frames) && probe.frames.length === 3; } catch (_) { return false; } })()",
1697
+ },
1698
+ ],
1699
+ nativeFrames: 3,
1700
+ source: `
1701
+ globalThis.__draw2dAdvancedMaskProbe = {
1702
+ frames: [],
1703
+ };
1704
+ `,
1705
+ nativeSource: `
1706
+ const __checks = [];
1707
+ let __reported = false;
1708
+
1709
+ function __toErrorString(value) {
1710
+ return String(value && value.message ? value.message : value);
1711
+ }
1712
+
1713
+ function __record(id, pass, detail, trace = null) {
1714
+ const row = { id, pass: !!pass, detail: detail || null };
1715
+ if (!row.pass && trace !== null && trace !== undefined) {
1716
+ row.trace = trace;
1717
+ }
1718
+ __checks.push(row);
1719
+ }
1720
+
1721
+ function __finish() {
1722
+ if (__reported) {
1723
+ return;
1724
+ }
1725
+ const __failedChecks = __checks.filter((check) => !check.pass);
1726
+ console.log('__AURA_CONFORMANCE_NATIVE__' + JSON.stringify({
1727
+ caseId: 'draw2d-advanced-mask-runtime-native',
1728
+ ok: __failedChecks.length === 0,
1729
+ checks: __checks,
1730
+ failed: __failedChecks.length,
1731
+ passed: __checks.length - __failedChecks.length,
1732
+ runtimeCacheDiagnostics: null,
1733
+ runtimeInspectorSnapshot: null,
1734
+ }));
1735
+ __reported = true;
1736
+ if (aura.window && typeof aura.window.close === 'function') {
1737
+ aura.window.close();
1738
+ }
1739
+ }
1740
+
1741
+ globalThis.__draw2dAdvancedMaskProbe = {
1742
+ frames: [],
1743
+ };
1744
+
1745
+ aura.setup = function () {
1746
+ try {
1747
+ const methodsOk = ['clear', 'withMask', 'rectFill', 'circleFill', 'text']
1748
+ .every((name) => typeof aura.draw2d?.[name] === 'function')
1749
+ && typeof aura.debug?.inspectorStats === 'function';
1750
+ __record('draw2d.advanced-mask.surface.methods', methodsOk, methodsOk ? null : 'required_methods_missing');
1751
+ __record('draw2d.advanced-mask.runtime.setup', true, null);
1752
+
1753
+ aura.update = function () {};
1754
+ aura.draw = function () {
1755
+ const probe = globalThis.__draw2dAdvancedMaskProbe || {};
1756
+ const frameIndex = Array.isArray(probe.frames) ? probe.frames.length : 0;
1757
+ const white = aura.Color?.WHITE || aura.colors?.white || aura.rgba(1, 1, 1, 1);
1758
+
1759
+ aura.draw2d.clear(6, 8, 12);
1760
+
1761
+ let invalidShape = null;
1762
+ let invalidFeather = null;
1763
+ let masked = null;
1764
+
1765
+ if (frameIndex === 0) {
1766
+ invalidShape = aura.draw2d.withMask({ type: 'analytic', shape: 'triangle' }, 0, 0, 8, 8, () => {});
1767
+ invalidFeather = aura.draw2d.withMask({ type: 'analytic', shape: 'circle', feather: -0.5 }, 0, 0, 8, 8, () => {});
1768
+ masked = aura.draw2d.withMask(
1769
+ { type: 'analytic', shape: 'circle', feather: 0.25 },
1770
+ 18,
1771
+ 14,
1772
+ 88,
1773
+ 88,
1774
+ () => {
1775
+ aura.draw2d.rectFill(14, 12, 96, 72, aura.rgba(0.18, 0.32, 0.55, 0.94));
1776
+ aura.draw2d.circleFill(62, 48, 18, aura.rgba(0.96, 0.82, 0.28, 0.92));
1777
+ aura.draw2d.text('MASK', 34, 40, { size: 12, color: white });
1778
+ },
1779
+ { invert: true },
1780
+ );
1781
+ }
1782
+
1783
+ const stats = aura.debug.inspectorStats() || {};
1784
+ const masking = stats.draw2dRuntime?.masking || {};
1785
+ probe.frames.push({
1786
+ frameIndex,
1787
+ invalidShapeReason: invalidShape?.reasonCode || null,
1788
+ invalidFeatherReason: invalidFeather?.reasonCode || null,
1789
+ maskedReason: masked?.reasonCode || null,
1790
+ maskedCommandCount: Number(masked?.commandCount || 0),
1791
+ maskKind: masked?.maskKind || null,
1792
+ maskShape: masked?.maskShape || null,
1793
+ maskFeather: Number(masked?.maskFeather || 0),
1794
+ pendingPassCount: Number(masking.pendingPassCount || 0),
1795
+ pendingAdvancedPassCount: Number(masking.pendingAdvancedPassCount || 0),
1796
+ lastSubmittedPassCount: Number(masking.lastSubmittedPassCount || 0),
1797
+ lastExecutedPassCount: Number(masking.lastExecutedPassCount || 0),
1798
+ lastSubmittedCommandCount: Number(masking.lastSubmittedCommandCount || 0),
1799
+ lastReasonCode: masking.lastReasonCode || null,
1800
+ lastOk: masking.lastOk === true,
1801
+ lastRequestedMaskKind: masking.lastRequestedMaskKind || null,
1802
+ lastRequestedMaskShape: masking.lastRequestedMaskShape || null,
1803
+ lastRequestedMaskFeather: Number(masking.lastRequestedMaskFeather || 0),
1804
+ });
1805
+
1806
+ if (probe.frames.length < 3) {
1807
+ return;
1808
+ }
1809
+
1810
+ const frames = probe.frames;
1811
+ const frame0 = frames[0] || {};
1812
+ const frame1 = frames[1] || {};
1813
+ const frame2 = frames[2] || {};
1814
+ const evidenceOk = frame0.invalidShapeReason === 'unsupported_mask_shape'
1815
+ && frame0.invalidFeatherReason === 'invalid_mask_feather'
1816
+ && frame0.maskedReason === 'draw2d_mask_captured'
1817
+ && frame0.maskedCommandCount === 3
1818
+ && frame0.maskKind === 'analytic'
1819
+ && frame0.maskShape === 'circle'
1820
+ && Math.abs(frame0.maskFeather - 0.25) < 1e-6
1821
+ && frame0.pendingPassCount === 1
1822
+ && frame0.pendingAdvancedPassCount === 1
1823
+ && frame0.lastSubmittedPassCount === 0
1824
+ && frame0.lastExecutedPassCount === 0
1825
+ && frame0.lastSubmittedCommandCount === 0
1826
+ && frame0.lastReasonCode === 'draw2d_mask_idle'
1827
+ && frame0.lastOk === true
1828
+ && frame0.lastRequestedMaskKind === 'analytic'
1829
+ && frame0.lastRequestedMaskShape === 'circle'
1830
+ && Math.abs(frame0.lastRequestedMaskFeather - 0.25) < 1e-6
1831
+ && frame1.maskedReason === null
1832
+ && frame1.pendingPassCount === 0
1833
+ && frame1.pendingAdvancedPassCount === 0
1834
+ && frame1.lastSubmittedPassCount === 1
1835
+ && frame1.lastExecutedPassCount === 1
1836
+ && frame1.lastSubmittedCommandCount === 3
1837
+ && frame1.lastReasonCode === 'draw2d_mask_executed'
1838
+ && frame1.lastOk === true
1839
+ && frame2.maskedReason === null
1840
+ && frame2.pendingPassCount === 0
1841
+ && frame2.pendingAdvancedPassCount === 0
1842
+ && frame2.lastSubmittedPassCount === 0
1843
+ && frame2.lastExecutedPassCount === 0
1844
+ && frame2.lastSubmittedCommandCount === 0
1845
+ && frame2.lastReasonCode === 'draw2d_mask_idle'
1846
+ && frame2.lastOk === true;
1847
+ __record(
1848
+ 'draw2d.advanced-mask.runtime.evidence',
1849
+ evidenceOk,
1850
+ evidenceOk ? null : 'draw2d_advanced_mask_evidence_failed',
1851
+ evidenceOk ? null : { probe },
1852
+ );
1853
+ __finish();
1854
+ };
1855
+ } catch (__error) {
1856
+ __record('draw2d.advanced-mask.runtime.setup', false, __toErrorString(__error), {
1857
+ probe: globalThis.__draw2dAdvancedMaskProbe || null,
1858
+ });
1859
+ __finish();
1860
+ }
1861
+ };
1862
+ `,
1863
+ },
1864
+ {
1865
+ id: 'draw2d-retained-ui-runtime-native',
1866
+ modes: ['native'],
1867
+ namespaces: ['ui', 'draw2d'],
1868
+ functions: [
1869
+ 'aura.draw2d.clear',
1870
+ 'aura.ui.beginContainer',
1871
+ 'aura.ui.region',
1872
+ 'aura.ui.selectOption',
1873
+ 'aura.ui.endContainer',
1874
+ 'aura.ui.getContainerState',
1875
+ 'aura.ui.getRegionState',
1876
+ 'aura.ui.getScrollState',
1877
+ 'aura.ui.scrollBy',
1878
+ 'aura.ui.getSelectionState',
1879
+ 'aura.ui.activate',
1880
+ ],
1881
+ nativeChecks: [
1882
+ {
1883
+ id: 'draw2d.retained-ui.surface.methods',
1884
+ expression: "(() => ['clear'].every((name) => typeof aura.draw2d?.[name] === 'function') && ['beginContainer','region','selectOption','endContainer','getContainerState','getRegionState','getScrollState','scrollBy','getSelectionState','activate'].every((name) => typeof aura.ui?.[name] === 'function'))()",
1885
+ },
1886
+ {
1887
+ id: 'draw2d.retained-ui.runtime.setup',
1888
+ expression: "(() => true)()",
1889
+ },
1890
+ ],
1891
+ nativePostChecks: [
1892
+ {
1893
+ id: 'draw2d.retained-ui.runtime.evidence',
1894
+ expression: "(() => { try { const probe = globalThis.__draw2dRetainedUiProbe || {}; return Array.isArray(probe.frames) && probe.frames.length === 4; } catch (_) { return false; } })()",
1895
+ },
1896
+ ],
1897
+ nativeFrames: 4,
1898
+ source: `
1899
+ globalThis.__draw2dRetainedUiProbe = {
1900
+ frames: [],
1901
+ selectedRegionId: null,
1902
+ };
1903
+ `,
1904
+ nativeSource: `
1905
+ const __checks = [];
1906
+ let __reported = false;
1907
+
1908
+ function __toErrorString(value) {
1909
+ return String(value && value.message ? value.message : value);
1910
+ }
1911
+
1912
+ function __record(id, pass, detail, trace = null) {
1913
+ const row = { id, pass: !!pass, detail: detail || null };
1914
+ if (!row.pass && trace !== null && trace !== undefined) {
1915
+ row.trace = trace;
1916
+ }
1917
+ __checks.push(row);
1918
+ }
1919
+
1920
+ function __finish() {
1921
+ if (__reported) {
1922
+ return;
1923
+ }
1924
+ const __failedChecks = __checks.filter((check) => !check.pass);
1925
+ console.log('__AURA_CONFORMANCE_NATIVE__' + JSON.stringify({
1926
+ caseId: 'draw2d-retained-ui-runtime-native',
1927
+ ok: __failedChecks.length === 0,
1928
+ checks: __checks,
1929
+ failed: __failedChecks.length,
1930
+ passed: __checks.length - __failedChecks.length,
1931
+ runtimeCacheDiagnostics: null,
1932
+ runtimeInspectorSnapshot: null,
1933
+ }));
1934
+ __reported = true;
1935
+ if (aura.window && typeof aura.window.close === 'function') {
1936
+ aura.window.close();
1937
+ }
1938
+ }
1939
+
1940
+ globalThis.__draw2dRetainedUiProbe = {
1941
+ frames: [],
1942
+ selectedRegionId: null,
1943
+ };
1944
+
1945
+ function __runUiFrame(frameIndex) {
1946
+ const probe = globalThis.__draw2dRetainedUiProbe || {};
1947
+ let scrollByResult = null;
1948
+ let activateResult = null;
1949
+
1950
+ if (frameIndex === 1) {
1951
+ scrollByResult = aura.ui.scrollBy('inventory', 0, 18);
1952
+ }
1953
+
1954
+ const begin = aura.ui.beginContainer({
1955
+ id: 'inventory',
1956
+ x: 18,
1957
+ y: 12,
1958
+ width: 84,
1959
+ height: 36,
1960
+ direction: 'vertical',
1961
+ gap: 4,
1962
+ padding: 2,
1963
+ });
1964
+ const header = aura.ui.region('header', { width: 76, height: 12 });
1965
+ const sword = aura.ui.selectOption('sword', {
1966
+ label: 'Sword',
1967
+ value: 'sword',
1968
+ width: 76,
1969
+ height: 12,
1970
+ selected: probe.selectedRegionId === 'sword',
1971
+ });
1972
+ const shield = aura.ui.selectOption('shield', {
1973
+ label: 'Shield',
1974
+ value: 'shield',
1975
+ width: 76,
1976
+ height: 12,
1977
+ selected: probe.selectedRegionId === 'shield',
1978
+ });
1979
+ const potion = aura.ui.selectOption('potion', {
1980
+ label: 'Potion',
1981
+ value: 'potion',
1982
+ width: 76,
1983
+ height: 12,
1984
+ selected: probe.selectedRegionId === 'potion',
1985
+ });
1986
+ if (frameIndex === 2) {
1987
+ activateResult = aura.ui.activate('shield');
1988
+ }
1989
+ const end = aura.ui.endContainer();
1990
+ const container = aura.ui.getContainerState('inventory');
1991
+ const headerState = aura.ui.getRegionState('header', 'inventory');
1992
+ const shieldState = aura.ui.getRegionState('shield', 'inventory');
1993
+ const scroll = aura.ui.getScrollState('inventory');
1994
+ const selection = aura.ui.getSelectionState('inventory');
1995
+
1996
+ probe.selectedRegionId = selection && selection.selectedRegionId
1997
+ ? selection.selectedRegionId
1998
+ : null;
1999
+
2000
+ return {
2001
+ begin,
2002
+ header,
2003
+ sword,
2004
+ shield,
2005
+ potion,
2006
+ end,
2007
+ container,
2008
+ headerState,
2009
+ shieldState,
2010
+ scroll,
2011
+ selection,
2012
+ scrollByResult,
2013
+ activateResult,
2014
+ };
2015
+ }
2016
+
2017
+ aura.setup = function () {
2018
+ try {
2019
+ const methodsOk = ['clear'].every((name) => typeof aura.draw2d?.[name] === 'function')
2020
+ && ['beginContainer', 'region', 'selectOption', 'endContainer', 'getContainerState', 'getRegionState', 'getScrollState', 'scrollBy', 'getSelectionState', 'activate']
2021
+ .every((name) => typeof aura.ui?.[name] === 'function');
2022
+ __record('draw2d.retained-ui.surface.methods', methodsOk, methodsOk ? null : 'required_methods_missing');
2023
+ __record('draw2d.retained-ui.runtime.setup', true, null);
2024
+
2025
+ aura.update = function () {};
2026
+ aura.draw = function () {
2027
+ const probe = globalThis.__draw2dRetainedUiProbe || {};
2028
+ const frameIndex = Array.isArray(probe.frames) ? probe.frames.length : 0;
2029
+
2030
+ aura.draw2d.clear(8, 10, 14);
2031
+ const uiState = __runUiFrame(frameIndex);
2032
+
2033
+ probe.frames.push({
2034
+ frameIndex,
2035
+ beginReason: uiState.begin?.reasonCode || null,
2036
+ endReason: uiState.end?.reasonCode || null,
2037
+ containerFocusedRegionId: uiState.container?.focusedRegionId || null,
2038
+ regionCount: Number(uiState.container?.regionCount || 0),
2039
+ optionCount: Number(uiState.container?.optionCount || 0),
2040
+ scrollY: Number(uiState.scroll?.scrollY || 0),
2041
+ maxScrollY: Number(uiState.scroll?.maxScrollY || 0),
2042
+ scrollReason: uiState.scroll?.lastReasonCode || null,
2043
+ scrollByReason: uiState.scrollByResult?.reasonCode || null,
2044
+ selectedRegionId: uiState.selection?.selectedRegionId || null,
2045
+ selectedValue: uiState.selection?.selectedValue || null,
2046
+ activatedRegionId: uiState.selection?.activatedRegionId || null,
2047
+ selectionReason: uiState.selection?.lastReasonCode || null,
2048
+ activateReason: uiState.activateResult?.reasonCode || null,
2049
+ headerFocused: uiState.headerState?.focused === true,
2050
+ shieldSelected: uiState.shieldState?.selected === true,
2051
+ shieldActivated: uiState.shieldState?.activated === true,
2052
+ });
2053
+
2054
+ if (probe.frames.length < 4) {
2055
+ return;
2056
+ }
2057
+
2058
+ const frames = probe.frames;
2059
+ const frame0 = frames[0] || {};
2060
+ const frame1 = frames[1] || {};
2061
+ const frame2 = frames[2] || {};
2062
+ const frame3 = frames[3] || {};
2063
+ const evidenceOk = frame0.beginReason === 'ui_container_started'
2064
+ && frame0.endReason === 'ui_container_focus_initialized'
2065
+ && frame0.containerFocusedRegionId === 'header'
2066
+ && frame0.regionCount === 4
2067
+ && frame0.optionCount === 3
2068
+ && frame0.scrollY === 0
2069
+ && frame0.maxScrollY > 0
2070
+ && frame0.selectedRegionId === null
2071
+ && frame0.selectionReason === 'ui_select_idle'
2072
+ && frame0.headerFocused === true
2073
+ && frame1.scrollByReason === 'ui_scroll_updated'
2074
+ && frame1.scrollY === 18
2075
+ && frame1.scrollReason === 'ui_scroll_updated'
2076
+ && frame1.selectedRegionId === null
2077
+ && frame2.activateReason === 'ui_widget_activation_requested'
2078
+ && frame2.selectedRegionId === 'shield'
2079
+ && frame2.selectedValue === 'shield'
2080
+ && frame2.activatedRegionId === 'shield'
2081
+ && frame2.selectionReason === 'ui_option_selected'
2082
+ && frame2.shieldSelected === true
2083
+ && frame2.shieldActivated === true
2084
+ && frame3.selectedRegionId === 'shield'
2085
+ && frame3.selectedValue === 'shield'
2086
+ && frame3.selectionReason === 'ui_select_idle'
2087
+ && frame3.shieldSelected === true;
2088
+ __record(
2089
+ 'draw2d.retained-ui.runtime.evidence',
2090
+ evidenceOk,
2091
+ evidenceOk ? null : 'draw2d_retained_ui_evidence_failed',
2092
+ evidenceOk ? null : { probe },
2093
+ );
2094
+ __finish();
2095
+ };
2096
+ } catch (__error) {
2097
+ __record('draw2d.retained-ui.runtime.setup', false, __toErrorString(__error), {
2098
+ probe: globalThis.__draw2dRetainedUiProbe || null,
2099
+ });
2100
+ __finish();
2101
+ }
2102
+ };
2103
+ `,
2104
+ },
2105
+ {
2106
+ id: 'draw2d-ui-dom-runtime-native',
2107
+ modes: ['native'],
2108
+ namespaces: ['ui', 'draw2d'],
2109
+ functions: [
2110
+ 'aura.draw2d.clear',
2111
+ 'aura.ui.setTheme',
2112
+ 'aura.ui.getTheme',
2113
+ 'aura.ui.beginView',
2114
+ 'aura.ui.endView',
2115
+ 'aura.ui.beginRow',
2116
+ 'aura.ui.endRow',
2117
+ 'aura.ui.beginColumn',
2118
+ 'aura.ui.endColumn',
2119
+ 'aura.ui.text',
2120
+ 'aura.ui.button',
2121
+ 'aura.ui.moveFocus',
2122
+ 'aura.ui.activate',
2123
+ 'aura.ui.getViewState',
2124
+ 'aura.ui.reset',
2125
+ 'aura.ui.__inspectorStats',
2126
+ ],
2127
+ nativeChecks: [
2128
+ {
2129
+ id: 'draw2d.ui-dom.surface.methods',
2130
+ expression: "(() => ['clear'].every((name) => typeof aura.draw2d?.[name] === 'function') && ['setTheme','getTheme','beginView','endView','beginRow','endRow','beginColumn','endColumn','text','button','moveFocus','activate','getViewState','reset','__inspectorStats'].every((name) => typeof aura.ui?.[name] === 'function'))()",
2131
+ },
2132
+ {
2133
+ id: 'draw2d.ui-dom.runtime.setup',
2134
+ expression: "(() => { try { globalThis.__draw2dUiDomProbe = { frames: [], invalidThemeReason: null, invalidViewReason: null, theme: null, moveReason: null, activateReason: null, resetReason: null }; return true; } catch (_) { return false; } })()",
2135
+ },
2136
+ ],
2137
+ nativePostChecks: [
2138
+ {
2139
+ id: 'draw2d.ui-dom.runtime.evidence',
2140
+ expression: "(() => { try { const probe = globalThis.__draw2dUiDomProbe || {}; const frames = Array.isArray(probe.frames) ? probe.frames : []; const frame0 = frames[0] || {}; const frame1 = frames[1] || {}; const frame2 = frames[2] || {}; const frame3 = frames[3] || {}; return probe.invalidThemeReason === 'invalid_ui_theme' && probe.invalidViewReason === 'invalid_view_options' && Number(probe.theme?.fontSize || 0) === 18 && Number(probe.theme?.buttonHeight || 0) === 34 && frames.length === 4 && frame0.viewNodeCount === 9 && frame0.focusedViewNodeId === 'start' && frame0.rowDirection === 'horizontal' && frame0.infoDirection === 'vertical' && frame0.actionsDirection === 'vertical' && frame1.moveReason === 'ui_focus_move_requested' && frame1.layoutReasonCode === 'ui_focus_advanced' && frame1.focusedViewNodeId === 'options' && frame2.activateReason === 'ui_widget_activation_requested' && frame2.optionsClicked === true && frame2.optionsReason === 'ui_button_activated' && frame2.clickedViewNodeId === 'options' && frame2.lastWidgetReasonCode === 'ui_button_activated' && frame3.resetReason === 'ui_focus_reset' && frame3.layoutReasonCode === 'ui_focus_initialized' && frame3.focusedViewNodeId === 'start'; } catch (_) { return false; } })()",
2141
+ },
2142
+ ],
2143
+ nativeFrames: 4,
2144
+ source: `
2145
+ globalThis.__draw2dUiDomProbe = {
2146
+ frames: [],
2147
+ invalidThemeReason: null,
2148
+ invalidViewReason: null,
2149
+ theme: null,
2150
+ moveReason: null,
2151
+ activateReason: null,
2152
+ resetReason: null,
2153
+ };
2154
+ `,
2155
+ nativeSource: `
2156
+ const __checks = [];
2157
+ let __reported = false;
2158
+
2159
+ function __toErrorString(value) {
2160
+ return String(value && value.message ? value.message : value);
2161
+ }
2162
+
2163
+ function __record(id, pass, detail, trace = null) {
2164
+ const row = { id, pass: !!pass, detail: detail || null };
2165
+ if (!row.pass && trace !== null && trace !== undefined) {
2166
+ row.trace = trace;
2167
+ }
2168
+ __checks.push(row);
2169
+ }
2170
+
2171
+ function __finish() {
2172
+ if (__reported) {
2173
+ return;
2174
+ }
2175
+ const __failedChecks = __checks.filter((check) => !check.pass);
2176
+ console.log('__AURA_CONFORMANCE_NATIVE__' + JSON.stringify({
2177
+ caseId: 'draw2d-ui-dom-runtime-native',
2178
+ ok: __failedChecks.length === 0,
2179
+ checks: __checks,
2180
+ failed: __failedChecks.length,
2181
+ passed: __checks.length - __failedChecks.length,
2182
+ runtimeCacheDiagnostics: null,
2183
+ runtimeInspectorSnapshot: null,
2184
+ }));
2185
+ __reported = true;
2186
+ if (aura.window && typeof aura.window.close === 'function') {
2187
+ aura.window.close();
2188
+ }
2189
+ }
2190
+
2191
+ globalThis.__draw2dUiDomProbe = {
2192
+ frames: [],
2193
+ invalidThemeReason: null,
2194
+ invalidViewReason: null,
2195
+ theme: null,
2196
+ moveReason: null,
2197
+ activateReason: null,
2198
+ resetReason: null,
2199
+ };
2200
+
2201
+ function __runUiFrame(frameIndex) {
2202
+ const begin = aura.ui.beginView({
2203
+ id: 'hud',
2204
+ x: 24,
2205
+ y: 20,
2206
+ width: 280,
2207
+ gap: 10,
2208
+ padding: 12,
2209
+ clip: true,
2210
+ background: '#101820',
2211
+ borderColor: '#4a6a88',
2212
+ });
2213
+ const title = aura.ui.text('title', {
2214
+ text: 'Command Deck',
2215
+ size: 18,
2216
+ color: '#f5f8ff',
2217
+ });
2218
+ const row = aura.ui.beginRow({ id: 'contentRow', gap: 12 });
2219
+ const infoCol = aura.ui.beginColumn({ id: 'infoCol', width: 136, gap: 4 });
2220
+ const statA = aura.ui.text('statA', { text: 'Crew Ready', color: '#9bc0e8' });
2221
+ const statB = aura.ui.text('statB', { text: 'UI DOM Proof', color: '#b8d5f4' });
2222
+ const endInfo = aura.ui.endColumn();
2223
+ const actionsCol = aura.ui.beginColumn({ id: 'actionsCol', width: 'fill', gap: 6 });
2224
+ const start = aura.ui.button('start', { label: 'Start Mission', width: 'fill' });
2225
+ const options = aura.ui.button('options', { label: 'Options', width: 'fill' });
2226
+ const endActions = aura.ui.endColumn();
2227
+ const endRow = aura.ui.endRow();
2228
+ const end = aura.ui.endView();
2229
+
2230
+ return {
2231
+ begin,
2232
+ title,
2233
+ row,
2234
+ infoCol,
2235
+ statA,
2236
+ statB,
2237
+ endInfo,
2238
+ actionsCol,
2239
+ start,
2240
+ options,
2241
+ endActions,
2242
+ endRow,
2243
+ end,
2244
+ root: aura.ui.getViewState('hud'),
2245
+ rowState: aura.ui.getViewState('contentRow'),
2246
+ infoState: aura.ui.getViewState('infoCol'),
2247
+ actionsState: aura.ui.getViewState('actionsCol'),
2248
+ startState: aura.ui.getViewState('start'),
2249
+ optionsState: aura.ui.getViewState('options'),
2250
+ inspect: aura.ui.__inspectorStats(),
2251
+ };
2252
+ }
2253
+
2254
+ aura.setup = function () {
2255
+ try {
2256
+ const methodsOk = ['clear'].every((name) => typeof aura.draw2d?.[name] === 'function')
2257
+ && ['setTheme', 'getTheme', 'beginView', 'endView', 'beginRow', 'endRow', 'beginColumn', 'endColumn', 'text', 'button', 'moveFocus', 'activate', 'getViewState', 'reset', '__inspectorStats']
2258
+ .every((name) => typeof aura.ui?.[name] === 'function');
2259
+ __record('draw2d.ui-dom.surface.methods', methodsOk, methodsOk ? null : 'required_methods_missing');
2260
+
2261
+ const themeResult = aura.ui.setTheme({
2262
+ gap: 8,
2263
+ padding: 12,
2264
+ fontSize: 18,
2265
+ buttonHeight: 34,
2266
+ borderWidth: 1,
2267
+ textColor: '#f5f8ff',
2268
+ panelBorderColor: '#4a6a88',
2269
+ buttonColor: '#213247',
2270
+ buttonHoverColor: '#335577',
2271
+ buttonFocusColor: '#245d9f',
2272
+ buttonActiveColor: '#1177dd',
2273
+ buttonTextColor: '#ffffff',
2274
+ });
2275
+
2276
+ const probe = globalThis.__draw2dUiDomProbe || {};
2277
+ probe.invalidThemeReason = aura.ui.setTheme('bad')?.reasonCode || null;
2278
+ probe.invalidViewReason = aura.ui.beginView('bad')?.reasonCode || null;
2279
+ probe.theme = aura.ui.getTheme();
2280
+
2281
+ const setupOk = themeResult?.ok === true
2282
+ && themeResult?.reasonCode === 'ui_theme_updated'
2283
+ && probe.invalidThemeReason === 'invalid_ui_theme'
2284
+ && probe.invalidViewReason === 'invalid_view_options'
2285
+ && Number(probe.theme?.fontSize || 0) === 18
2286
+ && Number(probe.theme?.buttonHeight || 0) === 34;
2287
+
2288
+ __record(
2289
+ 'draw2d.ui-dom.runtime.setup',
2290
+ setupOk,
2291
+ setupOk ? null : 'draw2d_ui_dom_setup_failed',
2292
+ setupOk ? null : { themeResult, probe },
2293
+ );
2294
+
2295
+ aura.update = function () {};
2296
+ aura.draw = function () {
2297
+ const probe = globalThis.__draw2dUiDomProbe || {};
2298
+ const frameIndex = Array.isArray(probe.frames) ? probe.frames.length : 0;
2299
+
2300
+ if (frameIndex === 1) {
2301
+ probe.moveReason = aura.ui.moveFocus('next')?.reasonCode || null;
2302
+ } else if (frameIndex === 2) {
2303
+ probe.activateReason = aura.ui.activate('options')?.reasonCode || null;
2304
+ } else if (frameIndex === 3) {
2305
+ probe.resetReason = aura.ui.reset('hud')?.reasonCode || null;
2306
+ }
2307
+
2308
+ aura.draw2d.clear(6, 8, 12);
2309
+ const uiState = __runUiFrame(frameIndex);
2310
+ probe.frames.push({
2311
+ frameIndex,
2312
+ moveReason: probe.moveReason || null,
2313
+ activateReason: probe.activateReason || null,
2314
+ resetReason: probe.resetReason || null,
2315
+ beginReason: uiState.begin?.reasonCode || null,
2316
+ titleReason: uiState.title?.reasonCode || null,
2317
+ rowReason: uiState.row?.reasonCode || null,
2318
+ infoReason: uiState.infoCol?.reasonCode || null,
2319
+ endInfoReason: uiState.endInfo?.reasonCode || null,
2320
+ actionsReason: uiState.actionsCol?.reasonCode || null,
2321
+ endActionsReason: uiState.endActions?.reasonCode || null,
2322
+ endRowReason: uiState.endRow?.reasonCode || null,
2323
+ endReason: uiState.end?.reasonCode || null,
2324
+ layoutReasonCode: uiState.end?.layoutReasonCode || null,
2325
+ rootKind: uiState.root?.kind || null,
2326
+ rowDirection: uiState.rowState?.direction || null,
2327
+ infoDirection: uiState.infoState?.direction || null,
2328
+ actionsDirection: uiState.actionsState?.direction || null,
2329
+ startFocused: uiState.startState?.focused === true,
2330
+ optionsFocused: uiState.optionsState?.focused === true,
2331
+ optionsClicked: uiState.optionsState?.clicked === true,
2332
+ optionsReason: uiState.optionsState?.reasonCode || null,
2333
+ focusedViewNodeId: uiState.inspect?.focusedViewNodeId || null,
2334
+ clickedViewNodeId: uiState.inspect?.clickedViewNodeId || null,
2335
+ viewNodeCount: Number(uiState.inspect?.viewNodeCount || 0),
2336
+ lastViewReasonCode: uiState.inspect?.lastViewReasonCode || null,
2337
+ lastWidgetReasonCode: uiState.inspect?.lastWidgetReasonCode || null,
2338
+ });
2339
+
2340
+ if (probe.frames.length < 4) {
2341
+ return;
2342
+ }
2343
+
2344
+ const frames = probe.frames;
2345
+ const frame0 = frames[0] || {};
2346
+ const frame1 = frames[1] || {};
2347
+ const frame2 = frames[2] || {};
2348
+ const frame3 = frames[3] || {};
2349
+ const evidenceOk = probe.invalidThemeReason === 'invalid_ui_theme'
2350
+ && probe.invalidViewReason === 'invalid_view_options'
2351
+ && Number(probe.theme?.fontSize || 0) === 18
2352
+ && Number(probe.theme?.buttonHeight || 0) === 34
2353
+ && frames.length === 4
2354
+ && frame0.beginReason === 'ui_view_started'
2355
+ && frame0.titleReason === 'ui_text_registered'
2356
+ && frame0.rowReason === 'ui_div_started'
2357
+ && frame0.infoReason === 'ui_div_started'
2358
+ && frame0.endInfoReason === 'ui_div_committed'
2359
+ && frame0.actionsReason === 'ui_div_started'
2360
+ && frame0.endActionsReason === 'ui_div_committed'
2361
+ && frame0.endRowReason === 'ui_div_committed'
2362
+ && frame0.endReason === 'ui_view_committed'
2363
+ && frame0.layoutReasonCode === 'ui_focus_initialized'
2364
+ && frame0.rootKind === 'view'
2365
+ && frame0.rowDirection === 'horizontal'
2366
+ && frame0.infoDirection === 'vertical'
2367
+ && frame0.actionsDirection === 'vertical'
2368
+ && frame0.startFocused === true
2369
+ && frame0.focusedViewNodeId === 'start'
2370
+ && frame0.viewNodeCount === 9
2371
+ && frame0.lastViewReasonCode === 'ui_focus_initialized'
2372
+ && frame1.moveReason === 'ui_focus_move_requested'
2373
+ && frame1.layoutReasonCode === 'ui_focus_advanced'
2374
+ && frame1.optionsFocused === true
2375
+ && frame1.focusedViewNodeId === 'options'
2376
+ && frame1.lastViewReasonCode === 'ui_focus_advanced'
2377
+ && frame2.activateReason === 'ui_widget_activation_requested'
2378
+ && frame2.layoutReasonCode === 'ui_layout_committed'
2379
+ && frame2.optionsFocused === true
2380
+ && frame2.optionsClicked === true
2381
+ && frame2.optionsReason === 'ui_button_activated'
2382
+ && frame2.clickedViewNodeId === 'options'
2383
+ && frame2.lastWidgetReasonCode === 'ui_button_activated'
2384
+ && frame3.resetReason === 'ui_focus_reset'
2385
+ && frame3.layoutReasonCode === 'ui_focus_initialized'
2386
+ && frame3.startFocused === true
2387
+ && frame3.focusedViewNodeId === 'start'
2388
+ && frame3.clickedViewNodeId === null;
2389
+
2390
+ __record(
2391
+ 'draw2d.ui-dom.runtime.evidence',
2392
+ evidenceOk,
2393
+ evidenceOk ? null : 'draw2d_ui_dom_evidence_failed',
2394
+ evidenceOk ? null : { probe },
2395
+ );
2396
+ __finish();
2397
+ };
2398
+ } catch (__error) {
2399
+ __record('draw2d.ui-dom.runtime.setup', false, __toErrorString(__error), {
2400
+ probe: globalThis.__draw2dUiDomProbe || null,
2401
+ });
2402
+ __finish();
2403
+ }
2404
+ };
2405
+ `,
2406
+ },
2407
+ {
2408
+ id: 'draw2d-ui-authored-widgets-runtime-native',
2409
+ modes: ['native'],
2410
+ namespaces: ['ui', 'draw2d'],
2411
+ functions: [
2412
+ 'aura.draw2d.clear',
2413
+ 'aura.ui.setTheme',
2414
+ 'aura.ui.getTheme',
2415
+ 'aura.ui.beginView',
2416
+ 'aura.ui.endView',
2417
+ 'aura.ui.beginColumn',
2418
+ 'aura.ui.endColumn',
2419
+ 'aura.ui.text',
2420
+ 'aura.ui.toggle',
2421
+ 'aura.ui.slider',
2422
+ 'aura.ui.button',
2423
+ 'aura.ui.moveFocus',
2424
+ 'aura.ui.activate',
2425
+ 'aura.ui.adjustValue',
2426
+ 'aura.ui.getViewState',
2427
+ 'aura.ui.reset',
2428
+ 'aura.ui.__inspectorStats',
2429
+ ],
2430
+ nativeChecks: [
2431
+ {
2432
+ id: 'draw2d.ui-authored-widgets.surface.methods',
2433
+ expression: "(() => ['clear'].every((name) => typeof aura.draw2d?.[name] === 'function') && ['setTheme','getTheme','beginView','endView','beginColumn','endColumn','text','toggle','slider','button','moveFocus','activate','adjustValue','getViewState','reset','__inspectorStats'].every((name) => typeof aura.ui?.[name] === 'function'))()",
2434
+ },
2435
+ {
2436
+ id: 'draw2d.ui-authored-widgets.runtime.setup',
2437
+ expression: "(() => { try { globalThis.__draw2dUiAuthoredWidgetsProbe = { frames: [], theme: null, invalidThemeReason: null, activateReason: null, moveReason: null, adjustReason: null, resetReason: null, musicValue: false, volumeValue: 4 }; return true; } catch (_) { return false; } })()",
2438
+ },
2439
+ ],
2440
+ nativePostChecks: [
2441
+ {
2442
+ id: 'draw2d.ui-authored-widgets.runtime.evidence',
2443
+ expression: "(() => { try { const probe = globalThis.__draw2dUiAuthoredWidgetsProbe || {}; const frames = Array.isArray(probe.frames) ? probe.frames : []; const frame0 = frames[0] || {}; const frame1 = frames[1] || {}; const frame2 = frames[2] || {}; const frame3 = frames[3] || {}; const frame4 = frames[4] || {}; return probe.invalidThemeReason === 'invalid_ui_theme' && Number(probe.theme?.fontSize || 0) === 16 && Number(probe.theme?.buttonHeight || 0) === 34 && frames.length === 5 && frame0.beginReason === 'ui_view_started' && frame0.endReason === 'ui_view_committed' && frame0.layoutReasonCode === 'ui_focus_initialized' && frame0.rootKind === 'view' && frame0.controlsDirection === 'vertical' && frame0.musicFocused === true && frame0.musicValue === false && frame0.volumeValue === 4 && frame0.focusedViewNodeId === 'music' && frame0.viewNodeCount === 6 && frame1.activateReason === 'ui_widget_activation_requested' && frame1.layoutReasonCode === 'ui_layout_committed' && frame1.musicFocused === true && frame1.musicActivated === true && frame1.musicClicked === true && frame1.musicToggled === true && frame1.musicValue === true && frame1.musicReason === 'ui_toggle_changed' && frame1.clickedViewNodeId === 'music' && frame1.lastWidgetReasonCode === 'ui_toggle_changed' && frame2.moveReason === 'ui_focus_move_requested' && frame2.layoutReasonCode === 'ui_focus_advanced' && frame2.volumeFocused === true && frame2.focusedViewNodeId === 'volume' && frame2.clickedViewNodeId === null && frame3.adjustReason === 'ui_widget_adjust_requested' && frame3.layoutReasonCode === 'ui_layout_committed' && frame3.volumeFocused === true && frame3.volumeChanged === true && frame3.volumeClicked === true && frame3.volumeValue === 6 && frame3.volumeReason === 'ui_slider_changed' && frame3.clickedViewNodeId === 'volume' && frame3.lastWidgetReasonCode === 'ui_slider_changed' && frame4.resetReason === 'ui_focus_reset' && frame4.layoutReasonCode === 'ui_focus_initialized' && frame4.musicFocused === true && frame4.musicValue === true && frame4.volumeValue === 6 && frame4.focusedViewNodeId === 'music' && frame4.clickedViewNodeId === null; } catch (_) { return false; } })()",
2444
+ },
2445
+ ],
2446
+ nativeFrames: 5,
2447
+ source: `
2448
+ globalThis.__draw2dUiAuthoredWidgetsProbe = {
2449
+ frames: [],
2450
+ theme: null,
2451
+ invalidThemeReason: null,
2452
+ activateReason: null,
2453
+ moveReason: null,
2454
+ adjustReason: null,
2455
+ resetReason: null,
2456
+ musicValue: false,
2457
+ volumeValue: 4,
2458
+ };
2459
+ `,
2460
+ nativeSource: `
2461
+ const __checks = [];
2462
+ let __reported = false;
2463
+
2464
+ function __toErrorString(value) {
2465
+ return String(value && value.message ? value.message : value);
2466
+ }
2467
+
2468
+ function __record(id, pass, detail, trace = null) {
2469
+ const row = { id, pass: !!pass, detail: detail || null };
2470
+ if (!row.pass && trace !== null && trace !== undefined) {
2471
+ row.trace = trace;
2472
+ }
2473
+ __checks.push(row);
2474
+ }
2475
+
2476
+ function __finish() {
2477
+ if (__reported) {
2478
+ return;
2479
+ }
2480
+ const __failedChecks = __checks.filter((check) => !check.pass);
2481
+ console.log('__AURA_CONFORMANCE_NATIVE__' + JSON.stringify({
2482
+ caseId: 'draw2d-ui-authored-widgets-runtime-native',
2483
+ ok: __failedChecks.length === 0,
2484
+ checks: __checks,
2485
+ failed: __failedChecks.length,
2486
+ passed: __checks.length - __failedChecks.length,
2487
+ runtimeCacheDiagnostics: null,
2488
+ runtimeInspectorSnapshot: null,
2489
+ }));
2490
+ __reported = true;
2491
+ if (aura.window && typeof aura.window.close === 'function') {
2492
+ aura.window.close();
2493
+ }
2494
+ }
2495
+
2496
+ globalThis.__draw2dUiAuthoredWidgetsProbe = {
2497
+ frames: [],
2498
+ theme: null,
2499
+ invalidThemeReason: null,
2500
+ activateReason: null,
2501
+ moveReason: null,
2502
+ adjustReason: null,
2503
+ resetReason: null,
2504
+ musicValue: false,
2505
+ volumeValue: 4,
2506
+ };
2507
+
2508
+ function __runWidgetFrame(frameProbe) {
2509
+ const begin = aura.ui.beginView({
2510
+ id: 'settings',
2511
+ x: 28,
2512
+ y: 22,
2513
+ width: 300,
2514
+ gap: 10,
2515
+ padding: 14,
2516
+ background: '#0d1826',
2517
+ borderColor: '#35506c',
2518
+ });
2519
+ const title = aura.ui.text('title', {
2520
+ text: 'Settings',
2521
+ size: 18,
2522
+ color: '#f3f7ff',
2523
+ });
2524
+ const controls = aura.ui.beginColumn({
2525
+ id: 'controls',
2526
+ gap: 8,
2527
+ });
2528
+ const music = aura.ui.toggle('music', {
2529
+ label: 'Music',
2530
+ width: 'fill',
2531
+ value: frameProbe.musicValue,
2532
+ });
2533
+ const volume = aura.ui.slider('volume', {
2534
+ label: 'Master Volume',
2535
+ width: 'fill',
2536
+ min: 0,
2537
+ max: 10,
2538
+ step: 2,
2539
+ value: frameProbe.volumeValue,
2540
+ });
2541
+ const apply = aura.ui.button('apply', {
2542
+ label: 'Apply',
2543
+ width: 'fill',
2544
+ });
2545
+ const endControls = aura.ui.endColumn();
2546
+ const end = aura.ui.endView();
2547
+
2548
+ return {
2549
+ begin,
2550
+ title,
2551
+ controls,
2552
+ music,
2553
+ volume,
2554
+ apply,
2555
+ endControls,
2556
+ end,
2557
+ root: aura.ui.getViewState('settings'),
2558
+ controlsState: aura.ui.getViewState('controls'),
2559
+ musicState: aura.ui.getViewState('music'),
2560
+ volumeState: aura.ui.getViewState('volume'),
2561
+ applyState: aura.ui.getViewState('apply'),
2562
+ inspect: aura.ui.__inspectorStats(),
2563
+ };
2564
+ }
2565
+
2566
+ aura.setup = function () {
2567
+ try {
2568
+ const methodsOk = ['clear'].every((name) => typeof aura.draw2d?.[name] === 'function')
2569
+ && ['setTheme', 'getTheme', 'beginView', 'endView', 'beginColumn', 'endColumn', 'text', 'toggle', 'slider', 'button', 'moveFocus', 'activate', 'adjustValue', 'getViewState', 'reset', '__inspectorStats']
2570
+ .every((name) => typeof aura.ui?.[name] === 'function');
2571
+ __record('draw2d.ui-authored-widgets.surface.methods', methodsOk, methodsOk ? null : 'required_methods_missing');
2572
+
2573
+ const themeResult = aura.ui.setTheme({
2574
+ gap: 8,
2575
+ padding: 12,
2576
+ fontSize: 16,
2577
+ buttonHeight: 34,
2578
+ borderWidth: 1,
2579
+ textColor: '#eef5ff',
2580
+ panelBorderColor: '#35506c',
2581
+ buttonColor: '#142334',
2582
+ buttonHoverColor: '#25415f',
2583
+ buttonFocusColor: '#1d5b96',
2584
+ buttonActiveColor: '#1f7fce',
2585
+ buttonTextColor: '#ffffff',
2586
+ });
2587
+
2588
+ const probe = globalThis.__draw2dUiAuthoredWidgetsProbe || {};
2589
+ probe.invalidThemeReason = aura.ui.setTheme('bad')?.reasonCode || null;
2590
+ probe.theme = aura.ui.getTheme();
2591
+
2592
+ const setupOk = themeResult?.ok === true
2593
+ && themeResult?.reasonCode === 'ui_theme_updated'
2594
+ && probe.invalidThemeReason === 'invalid_ui_theme'
2595
+ && Number(probe.theme?.fontSize || 0) === 16
2596
+ && Number(probe.theme?.buttonHeight || 0) === 34;
2597
+ __record(
2598
+ 'draw2d.ui-authored-widgets.runtime.setup',
2599
+ setupOk,
2600
+ setupOk ? null : 'draw2d_ui_authored_widgets_setup_failed',
2601
+ setupOk ? null : { themeResult, probe },
2602
+ );
2603
+
2604
+ aura.update = function () {};
2605
+ aura.draw = function () {
2606
+ const probe = globalThis.__draw2dUiAuthoredWidgetsProbe || {};
2607
+ const frameIndex = Array.isArray(probe.frames) ? probe.frames.length : 0;
2608
+
2609
+ if (frameIndex === 1) {
2610
+ probe.activateReason = aura.ui.activate()?.reasonCode || null;
2611
+ } else if (frameIndex === 2) {
2612
+ probe.moveReason = aura.ui.moveFocus('next')?.reasonCode || null;
2613
+ } else if (frameIndex === 3) {
2614
+ probe.adjustReason = aura.ui.adjustValue(1)?.reasonCode || null;
2615
+ } else if (frameIndex === 4) {
2616
+ probe.resetReason = aura.ui.reset('settings')?.reasonCode || null;
2617
+ }
2618
+
2619
+ aura.draw2d.clear(5, 8, 12);
2620
+ const uiState = __runWidgetFrame(probe);
2621
+ probe.musicValue = uiState.musicState?.value ?? probe.musicValue;
2622
+ probe.volumeValue = uiState.volumeState?.value ?? probe.volumeValue;
2623
+ probe.frames.push({
2624
+ frameIndex,
2625
+ activateReason: probe.activateReason || null,
2626
+ moveReason: probe.moveReason || null,
2627
+ adjustReason: probe.adjustReason || null,
2628
+ resetReason: probe.resetReason || null,
2629
+ beginReason: uiState.begin?.reasonCode || null,
2630
+ titleReason: uiState.title?.reasonCode || null,
2631
+ controlsReason: uiState.controls?.reasonCode || null,
2632
+ endControlsReason: uiState.endControls?.reasonCode || null,
2633
+ musicReasonRegistered: uiState.music?.reasonCode || null,
2634
+ volumeReasonRegistered: uiState.volume?.reasonCode || null,
2635
+ applyReasonRegistered: uiState.apply?.reasonCode || null,
2636
+ endReason: uiState.end?.reasonCode || null,
2637
+ layoutReasonCode: uiState.end?.layoutReasonCode || null,
2638
+ rootKind: uiState.root?.kind || null,
2639
+ controlsDirection: uiState.controlsState?.direction || null,
2640
+ musicFocused: uiState.musicState?.focused === true,
2641
+ musicActivated: uiState.musicState?.activated === true,
2642
+ musicClicked: uiState.musicState?.clicked === true,
2643
+ musicToggled: uiState.musicState?.toggled === true,
2644
+ musicValue: uiState.musicState?.value ?? null,
2645
+ musicReason: uiState.musicState?.reasonCode || null,
2646
+ volumeFocused: uiState.volumeState?.focused === true,
2647
+ volumeChanged: uiState.volumeState?.changed === true,
2648
+ volumeClicked: uiState.volumeState?.clicked === true,
2649
+ volumeValue: uiState.volumeState?.value ?? null,
2650
+ volumeReason: uiState.volumeState?.reasonCode || null,
2651
+ applyFocused: uiState.applyState?.focused === true,
2652
+ focusedViewNodeId: uiState.inspect?.focusedViewNodeId || null,
2653
+ clickedViewNodeId: uiState.inspect?.clickedViewNodeId || null,
2654
+ viewNodeCount: Number(uiState.inspect?.viewNodeCount || 0),
2655
+ lastViewReasonCode: uiState.inspect?.lastViewReasonCode || null,
2656
+ lastWidgetReasonCode: uiState.inspect?.lastWidgetReasonCode || null,
2657
+ });
2658
+
2659
+ if (probe.frames.length < 5) {
2660
+ return;
2661
+ }
2662
+
2663
+ const frames = probe.frames;
2664
+ const frame0 = frames[0] || {};
2665
+ const frame1 = frames[1] || {};
2666
+ const frame2 = frames[2] || {};
2667
+ const frame3 = frames[3] || {};
2668
+ const frame4 = frames[4] || {};
2669
+ const evidenceOk = probe.invalidThemeReason === 'invalid_ui_theme'
2670
+ && Number(probe.theme?.fontSize || 0) === 16
2671
+ && Number(probe.theme?.buttonHeight || 0) === 34
2672
+ && frames.length === 5
2673
+ && frame0.beginReason === 'ui_view_started'
2674
+ && frame0.titleReason === 'ui_text_registered'
2675
+ && frame0.controlsReason === 'ui_div_started'
2676
+ && frame0.endControlsReason === 'ui_div_committed'
2677
+ && frame0.musicReasonRegistered === 'ui_toggle_registered'
2678
+ && frame0.volumeReasonRegistered === 'ui_slider_registered'
2679
+ && frame0.applyReasonRegistered === 'ui_button_registered'
2680
+ && frame0.endReason === 'ui_view_committed'
2681
+ && frame0.layoutReasonCode === 'ui_focus_initialized'
2682
+ && frame0.rootKind === 'view'
2683
+ && frame0.controlsDirection === 'vertical'
2684
+ && frame0.musicFocused === true
2685
+ && frame0.musicValue === false
2686
+ && frame0.volumeValue === 4
2687
+ && frame0.focusedViewNodeId === 'music'
2688
+ && frame0.viewNodeCount === 6
2689
+ && frame1.activateReason === 'ui_widget_activation_requested'
2690
+ && frame1.layoutReasonCode === 'ui_layout_committed'
2691
+ && frame1.musicFocused === true
2692
+ && frame1.musicActivated === true
2693
+ && frame1.musicClicked === true
2694
+ && frame1.musicToggled === true
2695
+ && frame1.musicValue === true
2696
+ && frame1.musicReason === 'ui_toggle_changed'
2697
+ && frame1.clickedViewNodeId === 'music'
2698
+ && frame1.lastWidgetReasonCode === 'ui_toggle_changed'
2699
+ && frame2.moveReason === 'ui_focus_move_requested'
2700
+ && frame2.layoutReasonCode === 'ui_focus_advanced'
2701
+ && frame2.volumeFocused === true
2702
+ && frame2.focusedViewNodeId === 'volume'
2703
+ && frame2.clickedViewNodeId === null
2704
+ && frame3.adjustReason === 'ui_widget_adjust_requested'
2705
+ && frame3.layoutReasonCode === 'ui_layout_committed'
2706
+ && frame3.volumeFocused === true
2707
+ && frame3.volumeChanged === true
2708
+ && frame3.volumeClicked === true
2709
+ && frame3.volumeValue === 6
2710
+ && frame3.volumeReason === 'ui_slider_changed'
2711
+ && frame3.clickedViewNodeId === 'volume'
2712
+ && frame3.lastWidgetReasonCode === 'ui_slider_changed'
2713
+ && frame4.resetReason === 'ui_focus_reset'
2714
+ && frame4.layoutReasonCode === 'ui_focus_initialized'
2715
+ && frame4.musicFocused === true
2716
+ && frame4.musicValue === true
2717
+ && frame4.volumeValue === 6
2718
+ && frame4.focusedViewNodeId === 'music'
2719
+ && frame4.clickedViewNodeId === null;
2720
+
2721
+ __record(
2722
+ 'draw2d.ui-authored-widgets.runtime.evidence',
2723
+ evidenceOk,
2724
+ evidenceOk ? null : 'draw2d_ui_authored_widgets_evidence_failed',
2725
+ evidenceOk ? null : { probe },
2726
+ );
2727
+ __finish();
2728
+ };
2729
+ } catch (__error) {
2730
+ __record('draw2d.ui-authored-widgets.runtime.setup', false, __toErrorString(__error), {
2731
+ probe: globalThis.__draw2dUiAuthoredWidgetsProbe || null,
2732
+ });
2733
+ __finish();
2734
+ }
2735
+ };
2736
+ `,
2737
+ },
2738
+ {
2739
+ id: 'scene-flow-app-framework-runtime-native',
2740
+ modes: ['native'],
2741
+ namespaces: ['draw2d'],
2742
+ functions: [
2743
+ 'aura.draw2d.clear',
2744
+ 'aura.draw2d.rectFill',
2745
+ 'aura.draw2d.text',
2746
+ 'aura.rgba',
2747
+ ],
2748
+ nativeChecks: [
2749
+ {
2750
+ id: 'scene-flow.app-framework.runtime.setup',
2751
+ expression: "(() => { try { const probe = globalThis.__sceneFlowFrontierProbe || null; return probe?.schema === 'aurajs.scene-flow-frontier.v1'; } catch (_) { return false; } })()",
2752
+ debugExpression: 'globalThis.__sceneFlowFrontierProbe || null',
2753
+ },
2754
+ ],
2755
+ nativePostChecks: [
2756
+ {
2757
+ id: 'scene-flow.app-framework.runtime.evidence',
2758
+ expression: "(() => { try { const probe = globalThis.__sceneFlowFrontierProbe || {}; const frames = Array.isArray(probe.frames) ? probe.frames : []; const transitions = Array.isArray(probe.transitions) ? probe.transitions : []; const modalEvents = Array.isArray(probe.modalEvents) ? probe.modalEvents : []; const promptHistory = Array.isArray(probe.promptHistory) ? probe.promptHistory : []; const tags = transitions.map((row) => `${row.type}:${row.action}:${row.sceneId}`); const hasGameplay = frames.some((row) => row.activeSceneId === 'gameplay' && row.hudScreenId === 'hud'); const hasBriefing = frames.some((row) => row.activeSceneId === 'briefing' && row.stackDepth === 2); const hasPause = frames.some((row) => row.modalDepth === 1 && row.modalIds.includes('pause')); const hasSettings = frames.some((row) => row.modalDepth === 2 && row.modalIds.includes('pause') && row.modalIds.includes('settings')); const hasComplete = frames.some((row) => row.activeSceneId === 'complete' && row.objectiveReached === true); const promptReady = promptHistory.some((row) => row.triggerId === 'terminal' && row.ready === true); return probe.schema === 'aurajs.scene-flow-frontier.v1' && probe.objectiveReached === true && frames.length >= 5 && promptReady && hasGameplay && hasBriefing && hasPause && hasSettings && hasComplete && tags.includes('replace:enter:gameplay') && tags.includes('push:enter:briefing') && tags.includes('pop:resume:gameplay') && tags.includes('replace:enter:complete') && modalEvents.some((row) => row.action === 'push' && row.screenId === 'pause' && row.modalDepth === 1) && modalEvents.some((row) => row.action === 'push' && row.screenId === 'settings' && row.modalDepth === 2) && modalEvents.some((row) => row.action === 'pop' && row.screenId === 'settings' && row.modalDepth === 1) && modalEvents.some((row) => row.action === 'pop' && row.screenId === 'pause' && row.modalDepth === 0); } catch (_) { return false; } })()",
2759
+ debugExpression: 'globalThis.__sceneFlowFrontierProbe || null',
2760
+ },
2761
+ ],
2762
+ nativeFrames: 5,
2763
+ source: () => readConformanceSource('examples/scene-flow-frontier/src/main.js'),
2764
+ nativeSource: () => `
2765
+ ${readConformanceSource('examples/scene-flow-frontier/src/main.js')}
2766
+
2767
+ const __checks = [];
2768
+ let __reported = false;
2769
+
2770
+ function __toErrorString(value) {
2771
+ return String(value && value.message ? value.message : value);
2772
+ }
2773
+
2774
+ function __record(id, pass, detail, trace = null) {
2775
+ const row = { id, pass: !!pass, detail: detail || null };
2776
+ if (!row.pass && trace !== null && trace !== undefined) {
2777
+ row.trace = trace;
2778
+ }
2779
+ __checks.push(row);
2780
+ }
2781
+
2782
+ function __finish() {
2783
+ if (__reported) {
2784
+ return;
2785
+ }
2786
+ const __failedChecks = __checks.filter((check) => !check.pass);
2787
+ console.log('__AURA_CONFORMANCE_NATIVE__' + JSON.stringify({
2788
+ caseId: 'scene-flow-app-framework-runtime-native',
2789
+ ok: __failedChecks.length === 0,
2790
+ checks: __checks,
2791
+ failed: __failedChecks.length,
2792
+ passed: __checks.length - __failedChecks.length,
2793
+ runtimeCacheDiagnostics: null,
2794
+ runtimeInspectorSnapshot: null,
2795
+ }));
2796
+ __reported = true;
2797
+ if (aura.window && typeof aura.window.close === 'function') {
2798
+ aura.window.close();
2799
+ }
2800
+ }
2801
+
2802
+ aura.setup = function () {
2803
+ try {
2804
+ globalThis.__sceneFlowFrontierRuntime.setup();
2805
+ const probe = globalThis.__sceneFlowFrontierProbe || null;
2806
+ const runtime = globalThis.__sceneFlowFrontierRuntime || null;
2807
+ const setupOk = probe?.schema === 'aurajs.scene-flow-frontier.v1'
2808
+ && runtime
2809
+ && typeof runtime.update === 'function'
2810
+ && typeof runtime.draw === 'function';
2811
+ __record(
2812
+ 'scene-flow.app-framework.runtime.setup',
2813
+ setupOk,
2814
+ setupOk ? null : 'scene_flow_frontier_setup_failed',
2815
+ setupOk ? null : { probe, runtimeReady: !!runtime },
2816
+ );
2817
+ } catch (__error) {
2818
+ __record('scene-flow.app-framework.runtime.setup', false, __toErrorString(__error), {
2819
+ probe: globalThis.__sceneFlowFrontierProbe || null,
2820
+ });
2821
+ __finish();
2822
+ }
2823
+ };
2824
+
2825
+ aura.update = function (dt) {
2826
+ try {
2827
+ globalThis.__sceneFlowFrontierRuntime.update(dt);
2828
+ } catch (__error) {
2829
+ __record('scene-flow.app-framework.runtime.evidence', false, __toErrorString(__error), {
2830
+ probe: globalThis.__sceneFlowFrontierProbe || null,
2831
+ });
2832
+ __finish();
2833
+ }
2834
+ };
2835
+
2836
+ aura.draw = function () {
2837
+ if (__reported) {
2838
+ return;
2839
+ }
2840
+ try {
2841
+ globalThis.__sceneFlowFrontierRuntime.draw();
2842
+ const probe = globalThis.__sceneFlowFrontierProbe || {};
2843
+ const frames = Array.isArray(probe.frames) ? probe.frames : [];
2844
+ if (frames.length < 5) {
2845
+ return;
2846
+ }
2847
+ const transitions = Array.isArray(probe.transitions) ? probe.transitions : [];
2848
+ const modalEvents = Array.isArray(probe.modalEvents) ? probe.modalEvents : [];
2849
+ const promptHistory = Array.isArray(probe.promptHistory) ? probe.promptHistory : [];
2850
+ const tags = transitions.map((row) => \`\${row.type}:\${row.action}:\${row.sceneId}\`);
2851
+ const hasGameplay = frames.some((row) => row.activeSceneId === 'gameplay' && row.hudScreenId === 'hud');
2852
+ const hasBriefing = frames.some((row) => row.activeSceneId === 'briefing' && row.stackDepth === 2);
2853
+ const hasPause = frames.some((row) => row.modalDepth === 1 && row.modalIds.includes('pause'));
2854
+ const hasSettings = frames.some((row) => row.modalDepth === 2 && row.modalIds.includes('pause') && row.modalIds.includes('settings'));
2855
+ const hasComplete = frames.some((row) => row.activeSceneId === 'complete' && row.objectiveReached === true);
2856
+ const promptReady = promptHistory.some((row) => row.triggerId === 'terminal' && row.ready === true);
2857
+ const evidenceOk = probe.schema === 'aurajs.scene-flow-frontier.v1'
2858
+ && probe.objectiveReached === true
2859
+ && frames.length >= 5
2860
+ && promptReady
2861
+ && hasGameplay
2862
+ && hasBriefing
2863
+ && hasPause
2864
+ && hasSettings
2865
+ && hasComplete
2866
+ && tags.includes('replace:enter:gameplay')
2867
+ && tags.includes('push:enter:briefing')
2868
+ && tags.includes('pop:resume:gameplay')
2869
+ && tags.includes('replace:enter:complete')
2870
+ && modalEvents.some((row) => row.action === 'push' && row.screenId === 'pause' && row.modalDepth === 1)
2871
+ && modalEvents.some((row) => row.action === 'push' && row.screenId === 'settings' && row.modalDepth === 2)
2872
+ && modalEvents.some((row) => row.action === 'pop' && row.screenId === 'settings' && row.modalDepth === 1)
2873
+ && modalEvents.some((row) => row.action === 'pop' && row.screenId === 'pause' && row.modalDepth === 0);
2874
+ __record(
2875
+ 'scene-flow.app-framework.runtime.evidence',
2876
+ evidenceOk,
2877
+ evidenceOk ? null : 'scene_flow_frontier_evidence_failed',
2878
+ evidenceOk ? null : probe,
2879
+ );
2880
+ __finish();
2881
+ } catch (__error) {
2882
+ __record('scene-flow.app-framework.runtime.evidence', false, __toErrorString(__error), {
2883
+ probe: globalThis.__sceneFlowFrontierProbe || null,
2884
+ });
2885
+ __finish();
2886
+ }
2887
+ };
2888
+ `,
2889
+ },
2890
+ {
2891
+ id: 'starter-scene-flow-continuity-runtime-native',
2892
+ modes: ['native'],
2893
+ namespaces: ['draw2d'],
2894
+ functions: ['aura.draw2d.clear', 'aura.draw2d.rectFill', 'aura.draw2d.text', 'aura.rgba'],
2895
+ nativeChecks: [
2896
+ {
2897
+ id: 'starter.scene-flow.continuity.surface.methods',
2898
+ expression: "(() => ['clear','rectFill','text'].every((name) => typeof aura.draw2d?.[name] === 'function') && typeof aura.rgba === 'function')()",
2899
+ debugExpression: "(() => ({ hasDraw2d: !!aura.draw2d, hasRgba: typeof aura.rgba === 'function' }))()",
2900
+ },
2901
+ {
2902
+ id: 'starter.scene-flow.continuity.runtime.setup',
2903
+ expression: "(() => { try { const probe = globalThis.__starterSceneFlowContinuityProbe || null; return probe?.schema === 'aurajs.starter-scene-flow-continuity.v1'; } catch (_) { return false; } })()",
2904
+ debugExpression: 'globalThis.__starterSceneFlowContinuityProbe || null',
2905
+ },
2906
+ ],
2907
+ nativePostChecks: [
2908
+ {
2909
+ id: 'starter.scene-flow.continuity.runtime.evidence',
2910
+ expression: "(() => { try { const probe = globalThis.__starterSceneFlowContinuityProbe || {}; const captured = probe.captured || {}; const restored = probe.restored || {}; const continued = probe.continued || {}; const invalid = probe.invalid || {}; const frames = Array.isArray(probe.frames) ? probe.frames : []; return probe.schema === 'aurajs.starter-scene-flow-continuity.v1' && captured.sceneFlow?.schema === 'aurajs.scene-flow.v1' && captured.screenShell?.schema === 'aurajs.screen-shell.v1' && restored.sceneRestore?.ok === true && restored.screenRestore?.ok === true && restored.sceneMatch === true && restored.screenMatch === true && invalid.scene?.ok === false && invalid.scene?.reasonCode === 'scene_flow_unknown_scene' && invalid.screenShell?.ok === false && invalid.screenShell?.reasonCode === 'screen_shell_unknown_screen' && invalid.sceneStateStable === true && invalid.screenStateStable === true && continued.popScene?.ok === true && continued.popModal?.ok === true && continued.clearOverlay?.ok === true && continued.replaceScene?.ok === true && continued.setHud?.ok === true && continued.sceneFlow?.currentSceneId === 'complete' && continued.sceneFlow?.depth === 1 && continued.screenShell?.modalDepth === 0 && continued.screenShell?.overlay === null && continued.screenShell?.hud?.data?.status === 'restored-and-continued' && frames.length >= 3 && frames.some((row) => row.stage === 'captured' && row.sceneDepth === 2 && row.modalDepth === 1) && frames.some((row) => row.stage === 'restored' && row.sceneDepth === 2 && row.modalDepth === 1) && frames.some((row) => row.stage === 'continued' && row.sceneDepth === 1 && row.modalDepth === 0); } catch (_) { return false; } })()",
2911
+ debugExpression: 'globalThis.__starterSceneFlowContinuityProbe || null',
2912
+ },
2913
+ ],
2914
+ nativeFrames: 3,
2915
+ source: () => `globalThis.__starterSceneFlowContinuityProbe = { schema: 'aurajs.starter-scene-flow-continuity.v1', captured: null, restored: null, continued: null, invalid: null, frames: [] };`,
2916
+ nativeSource: () => `
2917
+ const __checks = [];
2918
+ let __reported = false;
2919
+ const __starterSceneFlowRuntime = (() => { ${STARTER_SCENE_FLOW_RUNTIME_SOURCE} return { createSceneFlow, SCENE_FLOW_SCHEMA }; })();
2920
+ const __starterScreenShellRuntime = (() => { ${STARTER_SCREEN_SHELL_RUNTIME_SOURCE} return { createScreenShell, SCREEN_SHELL_SCHEMA }; })();
2921
+ const __clone = (value) => (value == null ? value : JSON.parse(JSON.stringify(value)));
2922
+ const __same = (left, right) => JSON.stringify(left) === JSON.stringify(right);
2923
+ const __toErrorString = (value) => String(value && value.message ? value.message : value);
2924
+ function __record(id, pass, detail, trace = null) { const row = { id, pass: !!pass, detail: detail || null }; if (!row.pass && trace !== null && trace !== undefined) row.trace = trace; __checks.push(row); }
2925
+ function __finish() { if (__reported) return; const __failedChecks = __checks.filter((check) => !check.pass); console.log('__AURA_CONFORMANCE_NATIVE__' + JSON.stringify({ caseId: 'starter-scene-flow-continuity-runtime-native', ok: __failedChecks.length === 0, checks: __checks, failed: __failedChecks.length, passed: __checks.length - __failedChecks.length, runtimeCacheDiagnostics: null, runtimeInspectorSnapshot: null })); __reported = true; if (aura.window && typeof aura.window.close === 'function') aura.window.close(); }
2926
+ const __resolveScene = (sceneId) => ['title', 'gameplay', 'briefing', 'complete'].includes(sceneId) ? { id: sceneId } : null;
2927
+ const __resolveScreen = (screenId) => ['hud', 'overlay', 'pause'].includes(screenId) ? { id: screenId } : null;
2928
+ const __createSceneFlow = () => __starterSceneFlowRuntime.createSceneFlow({ resolveScene: __resolveScene });
2929
+ const __createScreenShell = () => __starterScreenShellRuntime.createScreenShell({ resolveScreen: __resolveScreen });
2930
+ function __runProof() {
2931
+ const probe = globalThis.__starterSceneFlowContinuityProbe = { schema: 'aurajs.starter-scene-flow-continuity.v1', captured: null, restored: null, continued: null, invalid: null, frames: [] };
2932
+ const sceneFlow = __createSceneFlow();
2933
+ const screenShell = __createScreenShell();
2934
+ sceneFlow.replace('gameplay', { checkpoint: 'alpha', coins: 3 });
2935
+ sceneFlow.push('briefing', { source: 'terminal', prompt: 'Press E to open briefing' });
2936
+ screenShell.setHud('hud', { title: 'Gameplay', status: 'captured' });
2937
+ screenShell.showOverlay('overlay', { promptText: 'Press E to continue' });
2938
+ screenShell.pushModal('pause', { reason: 'pause-menu' });
2939
+ const capturedSceneFlow = sceneFlow.getState();
2940
+ const capturedScreenShell = screenShell.getState();
2941
+ probe.captured = { sceneFlow: capturedSceneFlow, screenShell: capturedScreenShell };
2942
+ const restoredSceneFlow = __createSceneFlow();
2943
+ const restoredScreenShell = __createScreenShell();
2944
+ const sceneRestore = restoredSceneFlow.applyState(capturedSceneFlow);
2945
+ const screenRestore = restoredScreenShell.applyState(capturedScreenShell);
2946
+ const restoredSceneState = restoredSceneFlow.getState();
2947
+ const restoredScreenState = restoredScreenShell.getState();
2948
+ probe.restored = { sceneRestore, screenRestore, sceneFlow: restoredSceneState, screenShell: restoredScreenState, sceneMatch: __same(capturedSceneFlow, restoredSceneState), screenMatch: __same(capturedScreenShell, restoredScreenState) };
2949
+ const invalidSceneBefore = __clone(restoredSceneState);
2950
+ const invalidScreenBefore = __clone(restoredScreenState);
2951
+ const invalidScene = restoredSceneFlow.applyState({ schema: __starterSceneFlowRuntime.SCENE_FLOW_SCHEMA, stack: [{ sceneId: 'missing-scene', data: null, mountId: 99 }], mutationCount: restoredSceneState.mutationCount });
2952
+ const invalidScreenShell = restoredScreenShell.applyState({ schema: __starterScreenShellRuntime.SCREEN_SHELL_SCHEMA, hud: { screenId: 'missing-screen', data: null, mountId: 77 }, overlay: null, modals: [], mutationCount: restoredScreenState.mutationCount });
2953
+ probe.invalid = { scene: invalidScene, screenShell: invalidScreenShell, sceneStateStable: __same(invalidSceneBefore, restoredSceneFlow.getState()), screenStateStable: __same(invalidScreenBefore, restoredScreenShell.getState()) };
2954
+ const popScene = restoredSceneFlow.pop({ acknowledged: true });
2955
+ const popModal = restoredScreenShell.popModal({ resumed: true });
2956
+ const clearOverlay = restoredScreenShell.clearOverlay();
2957
+ const replaceScene = restoredSceneFlow.replace('complete', { summary: 'continued-from-restored-state' });
2958
+ const setHud = restoredScreenShell.setHud('hud', { title: 'Complete', status: 'restored-and-continued' });
2959
+ probe.continued = { popScene, popModal, clearOverlay, replaceScene, setHud, sceneFlow: restoredSceneFlow.getState(), screenShell: restoredScreenShell.getState() };
2960
+ }
2961
+ function __recordFrame(stage, detail) { const probe = globalThis.__starterSceneFlowContinuityProbe || null; if (!probe || !Array.isArray(probe.frames)) return; const sceneState = detail?.sceneFlow || null; const shellState = detail?.screenShell || null; probe.frames.push({ stage, sceneId: sceneState?.currentSceneId || null, sceneDepth: Number(sceneState?.depth || 0), modalDepth: Number(shellState?.modalDepth || 0), hudStatus: shellState?.hud?.data?.status || null, overlayPrompt: shellState?.overlay?.data?.promptText || null }); }
2962
+
2963
+ aura.setup = function () {
2964
+ try {
2965
+ const methodsOk = ['clear', 'rectFill', 'text'].every((name) => typeof aura.draw2d?.[name] === 'function') && typeof aura.rgba === 'function';
2966
+ __record('starter.scene-flow.continuity.surface.methods', methodsOk, methodsOk ? null : 'required_methods_missing');
2967
+ __runProof();
2968
+ const probe = globalThis.__starterSceneFlowContinuityProbe || null;
2969
+ const setupOk = probe?.schema === 'aurajs.starter-scene-flow-continuity.v1' && probe?.captured?.sceneFlow?.schema === __starterSceneFlowRuntime.SCENE_FLOW_SCHEMA && probe?.captured?.screenShell?.schema === __starterScreenShellRuntime.SCREEN_SHELL_SCHEMA && probe?.restored?.sceneRestore?.ok === true && probe?.restored?.screenRestore?.ok === true;
2970
+ __record('starter.scene-flow.continuity.runtime.setup', setupOk, setupOk ? null : 'starter_scene_flow_continuity_setup_failed', setupOk ? null : probe);
2971
+ } catch (__error) {
2972
+ __record('starter.scene-flow.continuity.runtime.setup', false, __toErrorString(__error), { probe: globalThis.__starterSceneFlowContinuityProbe || null });
2973
+ __finish();
2974
+ }
2975
+ };
2976
+
2977
+ aura.update = function () {};
2978
+
2979
+ aura.draw = function () {
2980
+ if (__reported) return;
2981
+ try {
2982
+ const probe = globalThis.__starterSceneFlowContinuityProbe || {};
2983
+ const frames = Array.isArray(probe.frames) ? probe.frames : [];
2984
+ const nextIndex = frames.length;
2985
+ const detail = nextIndex === 0 ? probe.captured : nextIndex === 1 ? probe.restored : probe.continued;
2986
+ const stage = nextIndex === 0 ? 'captured' : nextIndex === 1 ? 'restored' : 'continued';
2987
+ __recordFrame(stage, detail || null);
2988
+
2989
+ aura.draw2d.clear(aura.rgba(0.04, 0.06, 0.1, 1));
2990
+ aura.draw2d.rectFill(80, 88, 1120, 180, aura.rgba(0.05, 0.08, 0.13, 0.94));
2991
+ aura.draw2d.text('STARTER CONTINUITY ' + stage.toUpperCase() + ' scene=' + String(detail?.sceneFlow?.currentSceneId || 'none') + ' depth=' + String(detail?.sceneFlow?.depth || 0) + ' modals=' + String(detail?.screenShell?.modalDepth || 0), 120, 150, { size: 20, color: aura.rgba(0.95, 0.98, 1, 1) });
2992
+ aura.draw2d.text('hud=' + String(detail?.screenShell?.hud?.data?.status || 'none') + ' overlay=' + String(detail?.screenShell?.overlay?.data?.promptText || 'none'), 120, 190, { size: 16, color: aura.rgba(0.8, 0.88, 0.95, 1) });
2993
+ if (frames.length < 3) return;
2994
+ const evidenceOk = probe.schema === 'aurajs.starter-scene-flow-continuity.v1' && probe.captured?.sceneFlow?.schema === __starterSceneFlowRuntime.SCENE_FLOW_SCHEMA && probe.captured?.screenShell?.schema === __starterScreenShellRuntime.SCREEN_SHELL_SCHEMA && probe.restored?.sceneRestore?.ok === true && probe.restored?.screenRestore?.ok === true && probe.restored?.sceneMatch === true && probe.restored?.screenMatch === true && probe.invalid?.scene?.ok === false && probe.invalid?.scene?.reasonCode === 'scene_flow_unknown_scene' && probe.invalid?.screenShell?.ok === false && probe.invalid?.screenShell?.reasonCode === 'screen_shell_unknown_screen' && probe.invalid?.sceneStateStable === true && probe.invalid?.screenStateStable === true && probe.continued?.popScene?.ok === true && probe.continued?.popModal?.ok === true && probe.continued?.clearOverlay?.ok === true && probe.continued?.replaceScene?.ok === true && probe.continued?.setHud?.ok === true && probe.continued?.sceneFlow?.currentSceneId === 'complete' && probe.continued?.sceneFlow?.depth === 1 && probe.continued?.screenShell?.modalDepth === 0 && probe.continued?.screenShell?.overlay === null && probe.continued?.screenShell?.hud?.data?.status === 'restored-and-continued' && frames.some((row) => row.stage === 'captured' && row.sceneDepth === 2 && row.modalDepth === 1) && frames.some((row) => row.stage === 'restored' && row.sceneDepth === 2 && row.modalDepth === 1) && frames.some((row) => row.stage === 'continued' && row.sceneDepth === 1 && row.modalDepth === 0);
2995
+ __record('starter.scene-flow.continuity.runtime.evidence', evidenceOk, evidenceOk ? null : 'starter_scene_flow_continuity_evidence_failed', evidenceOk ? null : probe);
2996
+ __finish();
2997
+ } catch (__error) {
2998
+ __record('starter.scene-flow.continuity.runtime.evidence', false, __toErrorString(__error), { probe: globalThis.__starterSceneFlowContinuityProbe || null });
2999
+ __finish();
3000
+ }
3001
+ };
3002
+ `,
3003
+ },
3004
+ {
3005
+ id: 'draw2d-compositor-graph-runtime-native',
3006
+ modes: ['native'],
3007
+ namespaces: ['draw2d', 'debug'],
3008
+ functions: [
3009
+ 'aura.draw2d.clear',
3010
+ 'aura.draw2d.createRenderTarget',
3011
+ 'aura.draw2d.destroyRenderTarget',
3012
+ 'aura.draw2d.runCompositorGraph',
3013
+ 'aura.draw2d.exportRenderTarget',
3014
+ 'aura.draw2d.sprite',
3015
+ 'aura.draw2d.spriteFx',
3016
+ 'aura.draw2d.rectFill',
3017
+ 'aura.draw2d.text',
3018
+ 'aura.debug.inspectorStats',
3019
+ ],
3020
+ nativeChecks: [
3021
+ {
3022
+ id: 'draw2d.compositor-graph.surface.methods',
3023
+ expression: "(() => ['clear','createRenderTarget','destroyRenderTarget','runCompositorGraph','exportRenderTarget','sprite','spriteFx','rectFill','text'].every((name) => typeof aura.draw2d?.[name] === 'function') && typeof aura.debug?.inspectorStats === 'function')()",
3024
+ },
3025
+ {
3026
+ id: 'draw2d.compositor-graph.runtime.setup',
3027
+ expression: "(() => true)()",
3028
+ },
3029
+ ],
3030
+ nativePostChecks: [
3031
+ {
3032
+ id: 'draw2d.compositor-graph.runtime.evidence',
3033
+ expression: "(() => { try { const probe = globalThis.__draw2dCompositorGraphProbe || {}; return Array.isArray(probe.frames) && probe.frames.length === 3; } catch (_) { return false; } })()",
3034
+ },
3035
+ ],
3036
+ nativeFrames: 3,
3037
+ source: `
3038
+ globalThis.__draw2dCompositorGraphProbe = {
3039
+ panelTarget: null,
3040
+ fxTarget: null,
3041
+ finalTarget: null,
3042
+ frames: [],
3043
+ };
3044
+ `,
3045
+ nativeSource: `
3046
+ const __checks = [];
3047
+ let __reported = false;
3048
+
3049
+ function __toErrorString(value) {
3050
+ return String(value && value.message ? value.message : value);
3051
+ }
3052
+
3053
+ function __record(id, pass, detail, trace = null) {
3054
+ const row = { id, pass: !!pass, detail: detail || null };
3055
+ if (!row.pass && trace !== null && trace !== undefined) {
3056
+ row.trace = trace;
3057
+ }
3058
+ __checks.push(row);
3059
+ }
3060
+
3061
+ function __finish() {
3062
+ if (__reported) {
3063
+ return;
3064
+ }
3065
+ const __failedChecks = __checks.filter((check) => !check.pass);
3066
+ console.log('__AURA_CONFORMANCE_NATIVE__' + JSON.stringify({
3067
+ caseId: 'draw2d-compositor-graph-runtime-native',
3068
+ ok: __failedChecks.length === 0,
3069
+ checks: __checks,
3070
+ failed: __failedChecks.length,
3071
+ passed: __checks.length - __failedChecks.length,
3072
+ runtimeCacheDiagnostics: null,
3073
+ runtimeInspectorSnapshot: null,
3074
+ }));
3075
+ __reported = true;
3076
+ if (aura.window && typeof aura.window.close === 'function') {
3077
+ aura.window.close();
3078
+ }
3079
+ }
3080
+
3081
+ globalThis.__draw2dCompositorGraphProbe = {
3082
+ panelTarget: null,
3083
+ fxTarget: null,
3084
+ finalTarget: null,
3085
+ frames: [],
3086
+ };
3087
+
3088
+ aura.setup = function () {
3089
+ try {
3090
+ const methodsOk = ['clear', 'createRenderTarget', 'destroyRenderTarget', 'runCompositorGraph', 'exportRenderTarget', 'sprite', 'spriteFx', 'rectFill', 'text']
3091
+ .every((name) => typeof aura.draw2d?.[name] === 'function')
3092
+ && typeof aura.debug?.inspectorStats === 'function';
3093
+ __record('draw2d.compositor-graph.surface.methods', methodsOk, methodsOk ? null : 'required_methods_missing');
3094
+
3095
+ const panelTarget = aura.draw2d.createRenderTarget(112, 72);
3096
+ const fxTarget = aura.draw2d.createRenderTarget(144, 96);
3097
+ const finalTarget = aura.draw2d.createRenderTarget(176, 112);
3098
+ globalThis.__draw2dCompositorGraphProbe = {
3099
+ panelTarget,
3100
+ fxTarget,
3101
+ finalTarget,
3102
+ frames: [],
3103
+ };
3104
+
3105
+ const setupOk = panelTarget?.ok === true
3106
+ && fxTarget?.ok === true
3107
+ && finalTarget?.ok === true
3108
+ && Number.isInteger(panelTarget?.handle)
3109
+ && Number.isInteger(fxTarget?.handle)
3110
+ && Number.isInteger(finalTarget?.handle);
3111
+ __record(
3112
+ 'draw2d.compositor-graph.runtime.setup',
3113
+ setupOk,
3114
+ setupOk ? null : 'draw2d_compositor_graph_setup_failed',
3115
+ setupOk ? null : { panelTarget, fxTarget, finalTarget },
3116
+ );
3117
+
3118
+ aura.update = function () {};
3119
+ aura.draw = function () {
3120
+ const probe = globalThis.__draw2dCompositorGraphProbe || {};
3121
+ const frameIndex = Array.isArray(probe.frames) ? probe.frames.length : 0;
3122
+ const white = aura.Color?.WHITE || aura.colors?.white || aura.rgba(1, 1, 1, 1);
3123
+
3124
+ aura.draw2d.clear(5, 7, 11);
3125
+ let duplicateGraph = null;
3126
+ let validGraph = null;
3127
+ let invalidExport = null;
3128
+ let exportQueued = null;
3129
+ let invalidOutline = null;
3130
+ let outlineQueued = null;
3131
+
3132
+ if (frameIndex === 0) {
3133
+ duplicateGraph = aura.draw2d.runCompositorGraph('frontier-invalid', [
3134
+ { id: 'panel', target: probe.panelTarget, draw: () => {} },
3135
+ { id: 'panel', target: probe.fxTarget, draw: () => {} },
3136
+ ]);
3137
+ validGraph = aura.draw2d.runCompositorGraph('frontier-main', [
3138
+ {
3139
+ id: 'panel',
3140
+ target: probe.panelTarget,
3141
+ draw: () => {
3142
+ aura.draw2d.clear(0, 0, 0, 0);
3143
+ aura.draw2d.rectFill(0, 0, 112, 72, aura.rgba(0.15, 0.2, 0.3, 0.94));
3144
+ aura.draw2d.rectFill(10, 42, 72, 12, aura.rgba(0.22, 0.82, 1, 0.68));
3145
+ aura.draw2d.text('ENERGY 72', 12, 16, { size: 12, color: white });
3146
+ },
3147
+ },
3148
+ {
3149
+ id: 'fx',
3150
+ target: probe.fxTarget,
3151
+ draw: () => {
3152
+ aura.draw2d.clear(0, 0, 0, 0);
3153
+ aura.draw2d.sprite(probe.panelTarget, 0, 0, { width: 144, height: 96 });
3154
+ aura.draw2d.text('OUTLINE', 18, 62, { size: 11, color: white });
3155
+ },
3156
+ },
3157
+ {
3158
+ id: 'final',
3159
+ target: probe.finalTarget,
3160
+ draw: () => {
3161
+ aura.draw2d.clear(0, 0, 0, 0);
3162
+ aura.draw2d.sprite(probe.fxTarget, 0, 0, { width: 176, height: 112 });
3163
+ },
3164
+ },
3165
+ ]);
3166
+ if (Array.isArray(validGraph?.stages) && validGraph.stages.length === 3) {
3167
+ invalidExport = aura.draw2d.exportRenderTarget(validGraph.stages[2], 'frontier-export.jpg');
3168
+ exportQueued = aura.draw2d.exportRenderTarget(validGraph.stages[2], 'frontier-export.png');
3169
+ invalidOutline = aura.draw2d.spriteFx(validGraph.stages[1], 212, 28, {
3170
+ width: 54,
3171
+ height: 34,
3172
+ outline: { thickness: 0 },
3173
+ });
3174
+ outlineQueued = aura.draw2d.spriteFx(validGraph.stages[1], 212, 76, {
3175
+ width: 64,
3176
+ height: 40,
3177
+ outline: { thickness: 2, alpha: 0.8 },
3178
+ });
3179
+ aura.draw2d.sprite(validGraph.stages[2], 18, 18, { width: 176, height: 112 });
3180
+ }
3181
+ } else {
3182
+ aura.draw2d.sprite(probe.finalTarget, 18, 18, { width: 176, height: 112 });
3183
+ }
3184
+
3185
+ const stats = aura.debug.inspectorStats() || {};
3186
+ const compositor = stats.draw2dRuntime?.compositor || {};
3187
+ const fx = stats.draw2dRuntime?.fx || {};
3188
+ probe.frames.push({
3189
+ frameIndex,
3190
+ duplicateGraphReason: duplicateGraph?.reasonCode || null,
3191
+ graphReason: validGraph?.reasonCode || null,
3192
+ graphName: validGraph?.graphName || null,
3193
+ graphStageCount: Number(validGraph?.stageCount || 0),
3194
+ graphCommandCount: Number(validGraph?.commandCount || 0),
3195
+ stagesLength: Array.isArray(validGraph?.stages) ? validGraph.stages.length : 0,
3196
+ invalidExportReason: invalidExport?.reasonCode || null,
3197
+ exportQueuedReason: exportQueued?.reasonCode || null,
3198
+ exportQueuedPath: exportQueued?.path || null,
3199
+ invalidOutlineReason: invalidOutline?.reasonCode || null,
3200
+ outlineQueuedReason: outlineQueued?.reasonCode || null,
3201
+ submittedFxDrawCount: Number(outlineQueued?.submittedFxDrawCount || 0),
3202
+ knownGraphCount: Number(compositor.knownGraphCount || 0),
3203
+ knownStageCount: Number(compositor.knownStageCount || 0),
3204
+ lastGraphName: compositor.lastGraphName || null,
3205
+ lastGraphStageCount: Number(compositor.lastGraphStageCount || 0),
3206
+ lastGraphCommandCount: Number(compositor.lastGraphCommandCount || 0),
3207
+ lastGraphReasonCode: compositor.lastGraphReasonCode || null,
3208
+ lastGraphOk: compositor.lastGraphOk === true,
3209
+ pendingExportCount: Number(compositor.pendingExportCount || 0),
3210
+ lastSubmittedExportCount: Number(compositor.lastSubmittedExportCount || 0),
3211
+ lastExecutedExportCount: Number(compositor.lastExecutedExportCount || 0),
3212
+ lastExportReasonCode: compositor.lastExportReasonCode || null,
3213
+ lastExportOk: compositor.lastExportOk === true,
3214
+ pendingFxCommandCount: Number(fx.pendingFxCommandCount || 0),
3215
+ lastSubmittedFxCommandCount: Number(fx.lastSubmittedFxCommandCount || 0),
3216
+ lastExecutedFxCommandCount: Number(fx.lastExecutedFxCommandCount || 0),
3217
+ lastFxReasonCode: fx.lastReasonCode || null,
3218
+ lastFxOk: fx.lastOk === true,
3219
+ });
3220
+
3221
+ if (probe.frames.length < 3) {
3222
+ return;
3223
+ }
3224
+
3225
+ const frames = probe.frames;
3226
+ const frame0 = frames[0] || {};
3227
+ const frame1 = frames[1] || {};
3228
+ const frame2 = frames[2] || {};
3229
+ const destroyPanel = aura.draw2d.destroyRenderTarget(probe.panelTarget);
3230
+ const destroyFx = aura.draw2d.destroyRenderTarget(probe.fxTarget);
3231
+ const destroyFinal = aura.draw2d.destroyRenderTarget(probe.finalTarget);
3232
+ const missingDestroy = aura.draw2d.destroyRenderTarget(probe.finalTarget);
3233
+ const evidenceOk = frame0.duplicateGraphReason === 'duplicate_compositor_stage_id'
3234
+ && frame0.graphReason === 'draw2d_compositor_captured'
3235
+ && frame0.graphName === 'frontier-main'
3236
+ && frame0.graphStageCount === 3
3237
+ && frame0.graphCommandCount === 9
3238
+ && frame0.stagesLength === 3
3239
+ && frame0.invalidExportReason === 'unsupported_export_format'
3240
+ && frame0.exportQueuedReason === 'draw2d_render_target_export_queued'
3241
+ && frame0.exportQueuedPath === 'frontier-export.png'
3242
+ && frame0.invalidOutlineReason === 'invalid_sprite_fx_outline'
3243
+ && frame0.outlineQueuedReason === 'draw2d_sprite_fx_queued'
3244
+ && frame0.submittedFxDrawCount === 16
3245
+ && frame0.knownGraphCount === 1
3246
+ && frame0.knownStageCount === 3
3247
+ && frame0.lastGraphName === 'frontier-main'
3248
+ && frame0.lastGraphStageCount === 3
3249
+ && frame0.lastGraphCommandCount === 9
3250
+ && frame0.lastGraphReasonCode === 'draw2d_compositor_captured'
3251
+ && frame0.lastGraphOk === true
3252
+ && frame0.pendingExportCount === 1
3253
+ && frame0.lastSubmittedExportCount === 0
3254
+ && frame0.lastExecutedExportCount === 0
3255
+ && frame0.lastExportReasonCode === 'draw2d_export_idle'
3256
+ && frame0.lastExportOk === true
3257
+ && frame0.pendingFxCommandCount === 16
3258
+ && frame0.lastSubmittedFxCommandCount === 0
3259
+ && frame0.lastExecutedFxCommandCount === 0
3260
+ && frame0.lastFxReasonCode === 'draw2d_fx_idle'
3261
+ && frame0.lastFxOk === true
3262
+ && frame1.graphReason === null
3263
+ && frame1.pendingExportCount === 0
3264
+ && frame1.lastSubmittedExportCount === 1
3265
+ && frame1.lastExecutedExportCount === 1
3266
+ && frame1.lastExportReasonCode === 'draw2d_export_executed'
3267
+ && frame1.lastExportOk === true
3268
+ && frame1.pendingFxCommandCount === 0
3269
+ && frame1.lastSubmittedFxCommandCount === 16
3270
+ && frame1.lastExecutedFxCommandCount === 16
3271
+ && frame1.lastFxReasonCode === 'draw2d_fx_executed'
3272
+ && frame1.lastFxOk === true
3273
+ && frame2.graphReason === null
3274
+ && frame2.pendingExportCount === 0
3275
+ && frame2.lastSubmittedExportCount === 0
3276
+ && frame2.lastExecutedExportCount === 0
3277
+ && frame2.lastExportReasonCode === 'draw2d_export_idle'
3278
+ && frame2.lastExportOk === true
3279
+ && frame2.pendingFxCommandCount === 0
3280
+ && frame2.lastSubmittedFxCommandCount === 0
3281
+ && frame2.lastExecutedFxCommandCount === 0
3282
+ && frame2.lastFxReasonCode === 'draw2d_fx_idle'
3283
+ && frame2.lastFxOk === true
3284
+ && destroyPanel?.ok === true
3285
+ && destroyPanel?.reasonCode === 'draw2d_render_target_destroyed'
3286
+ && destroyFx?.ok === true
3287
+ && destroyFx?.reasonCode === 'draw2d_render_target_destroyed'
3288
+ && destroyFinal?.ok === true
3289
+ && destroyFinal?.reasonCode === 'draw2d_render_target_destroyed'
3290
+ && missingDestroy?.ok === false
3291
+ && missingDestroy?.reasonCode === 'missing_render_target';
3292
+ __record(
3293
+ 'draw2d.compositor-graph.runtime.evidence',
3294
+ evidenceOk,
3295
+ evidenceOk ? null : 'draw2d_compositor_graph_evidence_failed',
3296
+ evidenceOk ? null : { probe, destroyPanel, destroyFx, destroyFinal, missingDestroy },
3297
+ );
3298
+ __finish();
3299
+ };
3300
+ } catch (__error) {
3301
+ __record('draw2d.compositor-graph.runtime.setup', false, __toErrorString(__error), {
3302
+ probe: globalThis.__draw2dCompositorGraphProbe || null,
3303
+ });
3304
+ __finish();
3305
+ }
3306
+ };
3307
+ `,
3308
+ }
3309
+ ];