@aura3d/engine 1.0.3 → 1.0.5

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 (198) hide show
  1. package/README.md +309 -7
  2. package/dist/animation/AnimationClipEvents.d.ts +57 -0
  3. package/dist/animation/AnimationClipEvents.d.ts.map +1 -0
  4. package/dist/animation/AnimationClipEvents.js +171 -0
  5. package/dist/animation/AnimationClipEvents.js.map +1 -0
  6. package/dist/animation/AnimationClipRegistry.d.ts +76 -0
  7. package/dist/animation/AnimationClipRegistry.d.ts.map +1 -0
  8. package/dist/animation/AnimationClipRegistry.js +130 -0
  9. package/dist/animation/AnimationClipRegistry.js.map +1 -0
  10. package/dist/animation/AnimationController.d.ts +168 -0
  11. package/dist/animation/AnimationController.d.ts.map +1 -0
  12. package/dist/animation/AnimationController.js +619 -0
  13. package/dist/animation/AnimationController.js.map +1 -0
  14. package/dist/animation/HumanoidRetargeting.d.ts +76 -0
  15. package/dist/animation/HumanoidRetargeting.d.ts.map +1 -0
  16. package/dist/animation/HumanoidRetargeting.js +331 -0
  17. package/dist/animation/HumanoidRetargeting.js.map +1 -0
  18. package/dist/animation/browser-index.d.ts +18 -0
  19. package/dist/animation/browser-index.d.ts.map +1 -1
  20. package/dist/animation/browser-index.js +13 -0
  21. package/dist/animation/browser-index.js.map +1 -1
  22. package/dist/animation/index.d.ts +16 -1
  23. package/dist/animation/index.d.ts.map +1 -1
  24. package/dist/animation/index.js +11 -1
  25. package/dist/animation/index.js.map +1 -1
  26. package/dist/animation/threejs-compatibility/AnimationDiagnostics.d.ts.map +1 -1
  27. package/dist/animation/threejs-compatibility/AnimationDiagnostics.js +3 -5
  28. package/dist/animation/threejs-compatibility/AnimationDiagnostics.js.map +1 -1
  29. package/dist/assets/GLTFAnimationRuntime.js +1 -1
  30. package/dist/assets/GLTFLoader.js +1 -1
  31. package/dist/aura3d-cli/cli.js +194 -8
  32. package/dist/aura3d-cli/cli.js.map +1 -1
  33. package/dist/aura3d-cli/index.d.ts +280 -3
  34. package/dist/aura3d-cli/index.d.ts.map +1 -1
  35. package/dist/aura3d-cli/index.js +886 -4
  36. package/dist/aura3d-cli/index.js.map +1 -1
  37. package/dist/aura3d-cli/pull-bridge.d.ts +95 -0
  38. package/dist/aura3d-cli/pull-bridge.d.ts.map +1 -0
  39. package/dist/aura3d-cli/pull-bridge.js +247 -0
  40. package/dist/aura3d-cli/pull-bridge.js.map +1 -0
  41. package/dist/create-aura3d/index.d.ts +1 -1
  42. package/dist/create-aura3d/index.d.ts.map +1 -1
  43. package/dist/create-aura3d/index.js +9 -2
  44. package/dist/create-aura3d/index.js.map +1 -1
  45. package/dist/editor-runtime/ProjectSerializer.d.ts +74 -1
  46. package/dist/editor-runtime/ProjectSerializer.d.ts.map +1 -1
  47. package/dist/editor-runtime/ProjectSerializer.js +123 -6
  48. package/dist/editor-runtime/ProjectSerializer.js.map +1 -1
  49. package/dist/editor-runtime/TimelineModel.d.ts +18 -0
  50. package/dist/editor-runtime/TimelineModel.d.ts.map +1 -1
  51. package/dist/editor-runtime/TimelineModel.js +67 -3
  52. package/dist/editor-runtime/TimelineModel.js.map +1 -1
  53. package/dist/editor-runtime/TimelineRuntimeBridge.d.ts +98 -0
  54. package/dist/editor-runtime/TimelineRuntimeBridge.d.ts.map +1 -0
  55. package/dist/editor-runtime/TimelineRuntimeBridge.js +186 -0
  56. package/dist/editor-runtime/TimelineRuntimeBridge.js.map +1 -0
  57. package/dist/editor-runtime/index.d.ts +3 -1
  58. package/dist/editor-runtime/index.d.ts.map +1 -1
  59. package/dist/editor-runtime/index.js +1 -0
  60. package/dist/editor-runtime/index.js.map +1 -1
  61. package/dist/engine/agent-api/AnimationController.d.ts +607 -0
  62. package/dist/engine/agent-api/AnimationController.d.ts.map +1 -0
  63. package/dist/engine/agent-api/AnimationController.js +2192 -0
  64. package/dist/engine/agent-api/AnimationController.js.map +1 -0
  65. package/dist/engine/agent-api/AssetEvidence.d.ts +88 -0
  66. package/dist/engine/agent-api/AssetEvidence.d.ts.map +1 -0
  67. package/dist/engine/agent-api/AssetEvidence.js +157 -0
  68. package/dist/engine/agent-api/AssetEvidence.js.map +1 -0
  69. package/dist/engine/agent-api/AuraAppHandle.d.ts +55 -0
  70. package/dist/engine/agent-api/AuraAppHandle.d.ts.map +1 -0
  71. package/dist/engine/agent-api/AuraAppHandle.js +15 -0
  72. package/dist/engine/agent-api/AuraAppHandle.js.map +1 -0
  73. package/dist/engine/agent-api/AuraVoiceBridge.d.ts +96 -0
  74. package/dist/engine/agent-api/AuraVoiceBridge.d.ts.map +1 -0
  75. package/dist/engine/agent-api/AuraVoiceBridge.js +370 -0
  76. package/dist/engine/agent-api/AuraVoiceBridge.js.map +1 -0
  77. package/dist/engine/agent-api/CartoonDirector.d.ts +95 -0
  78. package/dist/engine/agent-api/CartoonDirector.d.ts.map +1 -0
  79. package/dist/engine/agent-api/CartoonDirector.js +342 -0
  80. package/dist/engine/agent-api/CartoonDirector.js.map +1 -0
  81. package/dist/engine/agent-api/CartoonPerformance.d.ts +149 -0
  82. package/dist/engine/agent-api/CartoonPerformance.d.ts.map +1 -0
  83. package/dist/engine/agent-api/CartoonPerformance.js +317 -0
  84. package/dist/engine/agent-api/CartoonPerformance.js.map +1 -0
  85. package/dist/engine/agent-api/CartoonRenderQueue.d.ts +132 -0
  86. package/dist/engine/agent-api/CartoonRenderQueue.d.ts.map +1 -0
  87. package/dist/engine/agent-api/CartoonRenderQueue.js +385 -0
  88. package/dist/engine/agent-api/CartoonRenderQueue.js.map +1 -0
  89. package/dist/engine/agent-api/CharacterAssembly.d.ts +126 -0
  90. package/dist/engine/agent-api/CharacterAssembly.d.ts.map +1 -0
  91. package/dist/engine/agent-api/CharacterAssembly.js +280 -0
  92. package/dist/engine/agent-api/CharacterAssembly.js.map +1 -0
  93. package/dist/engine/agent-api/DialoguePerformance.d.ts +150 -0
  94. package/dist/engine/agent-api/DialoguePerformance.d.ts.map +1 -0
  95. package/dist/engine/agent-api/DialoguePerformance.js +335 -0
  96. package/dist/engine/agent-api/DialoguePerformance.js.map +1 -0
  97. package/dist/engine/agent-api/FrameLoop.d.ts +70 -0
  98. package/dist/engine/agent-api/FrameLoop.d.ts.map +1 -0
  99. package/dist/engine/agent-api/FrameLoop.js +165 -0
  100. package/dist/engine/agent-api/FrameLoop.js.map +1 -0
  101. package/dist/engine/agent-api/GameAssetValidation.d.ts +279 -0
  102. package/dist/engine/agent-api/GameAssetValidation.d.ts.map +1 -0
  103. package/dist/engine/agent-api/GameAssetValidation.js +719 -0
  104. package/dist/engine/agent-api/GameAssetValidation.js.map +1 -0
  105. package/dist/engine/agent-api/GameEvidence.d.ts +148 -0
  106. package/dist/engine/agent-api/GameEvidence.d.ts.map +1 -0
  107. package/dist/engine/agent-api/GameEvidence.js +269 -0
  108. package/dist/engine/agent-api/GameEvidence.js.map +1 -0
  109. package/dist/engine/agent-api/GameRuntime.d.ts +931 -0
  110. package/dist/engine/agent-api/GameRuntime.d.ts.map +1 -0
  111. package/dist/engine/agent-api/GameRuntime.js +2229 -0
  112. package/dist/engine/agent-api/GameRuntime.js.map +1 -0
  113. package/dist/engine/agent-api/GameSceneBridge.d.ts +54 -0
  114. package/dist/engine/agent-api/GameSceneBridge.d.ts.map +1 -0
  115. package/dist/engine/agent-api/GameSceneBridge.js +110 -0
  116. package/dist/engine/agent-api/GameSceneBridge.js.map +1 -0
  117. package/dist/engine/agent-api/PromptAnimationContract.d.ts +278 -0
  118. package/dist/engine/agent-api/PromptAnimationContract.d.ts.map +1 -0
  119. package/dist/engine/agent-api/PromptAnimationContract.js +238 -0
  120. package/dist/engine/agent-api/PromptAnimationContract.js.map +1 -0
  121. package/dist/engine/agent-api/PromptAnimationEvidence.d.ts +183 -0
  122. package/dist/engine/agent-api/PromptAnimationEvidence.d.ts.map +1 -0
  123. package/dist/engine/agent-api/PromptAnimationEvidence.js +454 -0
  124. package/dist/engine/agent-api/PromptAnimationEvidence.js.map +1 -0
  125. package/dist/engine/agent-api/RuntimeNodeHandle.d.ts +100 -0
  126. package/dist/engine/agent-api/RuntimeNodeHandle.d.ts.map +1 -0
  127. package/dist/engine/agent-api/RuntimeNodeHandle.js +36 -0
  128. package/dist/engine/agent-api/RuntimeNodeHandle.js.map +1 -0
  129. package/dist/engine/agent-api/ShotTimeline.d.ts +179 -0
  130. package/dist/engine/agent-api/ShotTimeline.d.ts.map +1 -0
  131. package/dist/engine/agent-api/ShotTimeline.js +264 -0
  132. package/dist/engine/agent-api/ShotTimeline.js.map +1 -0
  133. package/dist/engine/agent-api/VisemeController.d.ts +89 -0
  134. package/dist/engine/agent-api/VisemeController.d.ts.map +1 -0
  135. package/dist/engine/agent-api/VisemeController.js +207 -0
  136. package/dist/engine/agent-api/VisemeController.js.map +1 -0
  137. package/dist/engine/agent-api/game-kits/fighting.d.ts +123 -0
  138. package/dist/engine/agent-api/game-kits/fighting.d.ts.map +1 -0
  139. package/dist/engine/agent-api/game-kits/fighting.js +483 -0
  140. package/dist/engine/agent-api/game-kits/fighting.js.map +1 -0
  141. package/dist/engine/agent-api/game-kits/index.d.ts +15 -0
  142. package/dist/engine/agent-api/game-kits/index.d.ts.map +1 -0
  143. package/dist/engine/agent-api/game-kits/index.js +6 -0
  144. package/dist/engine/agent-api/game-kits/index.js.map +1 -0
  145. package/dist/engine/agent-api/humanoid-walk-runtime.d.ts +1 -0
  146. package/dist/engine/agent-api/humanoid-walk-runtime.d.ts.map +1 -1
  147. package/dist/engine/agent-api/index.d.ts +487 -1
  148. package/dist/engine/agent-api/index.d.ts.map +1 -1
  149. package/dist/engine/agent-api/index.js +740 -6
  150. package/dist/engine/agent-api/index.js.map +1 -1
  151. package/dist/engine/agent-api/product-viewer-runtime.d.ts.map +1 -1
  152. package/dist/index.d.ts +1 -0
  153. package/dist/index.js +1 -0
  154. package/dist/physics/CollisionVolumes.d.ts +57 -0
  155. package/dist/physics/CollisionVolumes.d.ts.map +1 -0
  156. package/dist/physics/CollisionVolumes.js +159 -0
  157. package/dist/physics/CollisionVolumes.js.map +1 -0
  158. package/dist/physics/HitboxWorld.d.ts +229 -0
  159. package/dist/physics/HitboxWorld.d.ts.map +1 -0
  160. package/dist/physics/HitboxWorld.js +640 -0
  161. package/dist/physics/HitboxWorld.js.map +1 -0
  162. package/dist/physics/KinematicBody.d.ts +157 -0
  163. package/dist/physics/KinematicBody.d.ts.map +1 -0
  164. package/dist/physics/KinematicBody.js +405 -0
  165. package/dist/physics/KinematicBody.js.map +1 -0
  166. package/dist/physics/KinematicWorld.d.ts +58 -0
  167. package/dist/physics/KinematicWorld.d.ts.map +1 -0
  168. package/dist/physics/KinematicWorld.js +246 -0
  169. package/dist/physics/KinematicWorld.js.map +1 -0
  170. package/dist/physics/index.d.ts +4 -0
  171. package/dist/physics/index.d.ts.map +1 -1
  172. package/dist/physics/index.js +4 -0
  173. package/dist/physics/index.js.map +1 -1
  174. package/dist/rendering/ForwardPass.js +2 -2
  175. package/dist/rendering/ShaderLibrary.js +2 -2
  176. package/dist/rendering/SkinnedLitMaterial.js +3 -3
  177. package/dist/rendering/SkinnedUnlitMaterial.js +3 -3
  178. package/dist/scene/Renderable.js +2 -2
  179. package/dist/scripting/VisualGraph.d.ts +2 -1
  180. package/dist/scripting/VisualGraph.d.ts.map +1 -1
  181. package/dist/scripting/VisualGraph.js +118 -1
  182. package/dist/scripting/VisualGraph.js.map +1 -1
  183. package/dist/scripting/VisualGraphContext.d.ts +123 -0
  184. package/dist/scripting/VisualGraphContext.d.ts.map +1 -0
  185. package/dist/scripting/VisualGraphContext.js +2 -0
  186. package/dist/scripting/VisualGraphContext.js.map +1 -0
  187. package/dist/scripting/VisualGraphExecutor.d.ts +6 -1
  188. package/dist/scripting/VisualGraphExecutor.d.ts.map +1 -1
  189. package/dist/scripting/VisualGraphExecutor.js +364 -7
  190. package/dist/scripting/VisualGraphExecutor.js.map +1 -1
  191. package/dist/scripting/VisualNodeCatalog.d.ts +1 -1
  192. package/dist/scripting/VisualNodeCatalog.d.ts.map +1 -1
  193. package/dist/scripting/VisualNodeCatalog.js +61 -1
  194. package/dist/scripting/VisualNodeCatalog.js.map +1 -1
  195. package/dist/scripting/index.d.ts +1 -0
  196. package/dist/scripting/index.d.ts.map +1 -1
  197. package/dist/scripting/index.js.map +1 -1
  198. package/package.json +192 -118
@@ -1,5 +1,42 @@
1
1
  import { PhysicsDebugDraw, PhysicsStepper, PhysicsWorld, ScenePhysicsBridge, Shape as PhysicsShapeFactory } from "../../physics/index.js";
2
+ import { createFrameLoop } from "./FrameLoop.js";
3
+ import { createCombatWorld, createGameCameraDirector, createGameEffects, applyGameCombatEventsToRuntime, createGameAccessibilityFocus, createGameAccessibilityLabel, createGameAccessibilityRuntimeSettings, createGameHighContrastSource, createGameHudBindings, createGameHudComboBinding, createGameHudDebugToggleBinding, createGameHudHealthBinding, createGameHudMeterBinding, createGameHudRoundBinding, createGameHudSnapshot, createGameHudTimerBinding, createGameBoxCollider, createGameCapsuleCollider, createGameColliderDebugGeometry, createGameCombatDebugGeometry, createGameDebugOverlayData, createGameDebugSceneNodes, createGameHitboxDebugGeometry, createGameFighting2DRules, createGameInput, createGameInputReplay, createGameInputReplayDriver, createGameJumpAssist, createGameKinematicBody, createGamePauseControlsSource, createGameRectCollider, createGameReducedFlashSource, createGameReducedMotionSource, createGameSphereCollider, createGameTouchControlLayout, gameColliderAabb, gameColliders, gameEffectPresets, gameGuardboxes, gameHitboxes, gameHurtboxes, gameInputReplayEventsAt, gamePushboxes, gameTriggerVolumes } from "./GameRuntime.js";
4
+ import { collectGameRuntimeEvidence as collectGameRuntimeEvidenceV105 } from "./GameEvidence.js";
5
+ import { calculateRuntimeNodeBounds } from "./RuntimeNodeHandle.js";
6
+ import { createRuntimeNodeSpec } from "./GameSceneBridge.js";
7
+ import { createFightingGameKit, fighting as fightingGameKit } from "./game-kits/fighting.js";
8
+ import { createPromptAnimationEpisodePlan, createPromptAnimationStoryBible, definePromptAnimationStoryboard } from "./PromptAnimationContract.js";
9
+ import { applyShotPlaybackFrame, createShotPlaybackPlan, createShotTimeline, installShotPlayback, sampleShotPlaybackPlan } from "./ShotTimeline.js";
10
+ import { captionCueAtTime, createCaptionTimingProof, deriveCaptionTrackFromDialogue } from "./DialoguePerformance.js";
11
+ import { createAuraVoiceVisemeTrack, createGlbBlendshapeVisemeCue, createPrimitiveMouthVisemeCues, sampleVisemeTrack } from "./VisemeController.js";
12
+ import { createAuraVoiceBridgePackage, createAuraVoiceDubRerenderProof, createAuraVoiceRerenderPlan, sampleAuraVoiceBridgeAtTime } from "./AuraVoiceBridge.js";
13
+ import { createCartoonDirectorPlan } from "./CartoonDirector.js";
14
+ import { createCartoonPerformance } from "./CartoonPerformance.js";
15
+ import { createCartoonRenderOutputPackageMetadata, createCartoonRenderQueue } from "./CartoonRenderQueue.js";
16
+ import { collectPromptAnimationEvidence } from "./PromptAnimationEvidence.js";
2
17
  export { Engine } from "../../core/index.js";
18
+ export { asAuraAppHandle, isAuraAppHandle } from "./AuraAppHandle.js";
19
+ export { FrameLoop, createFrameLoop } from "./FrameLoop.js";
20
+ export { createCombatWorld, createGameCameraDirector, createGameEffects, applyGameCombatEventsToRuntime, createGameAccessibilityFocus, createGameAccessibilityLabel, createGameAccessibilityRuntimeSettings, createGameHighContrastSource, createGameHudBindings, createGameHudComboBinding, createGameHudDebugToggleBinding, createGameHudHealthBinding, createGameHudMeterBinding, createGameHudRoundBinding, createGameHudSnapshot, createGameHudTimerBinding, createGameBoxCollider, createGameCapsuleCollider, createGameColliderDebugGeometry, createGameCombatDebugGeometry, createGameDebugOverlayData, createGameDebugSceneNodes, createGameHitboxDebugGeometry, createGameInput, createGameInputReplay, createGameInputReplayDriver, createGameJumpAssist, createGameKinematicBody, createGamePauseControlsSource, createGameRectCollider, createGameReducedFlashSource, createGameReducedMotionSource, createGameSphereCollider, createGameTouchControlLayout, gameColliderAabb, gameColliders, gameInputReplayEventsAt, createGameLoopPlan } from "./GameRuntime.js";
21
+ export { collectGameSceneRuntimeNodes, createGameSceneBridge, createRuntimeNodeSpec } from "./GameSceneBridge.js";
22
+ export { calculateRuntimeNodeBounds, createRuntimeNodeEffectAttachment, runtimeNodeHasTag } from "./RuntimeNodeHandle.js";
23
+ export { createFightingGameKit, fighting, fighterRuntimeNode } from "./game-kits/fighting.js";
24
+ export { gameKits } from "./game-kits/index.js";
25
+ export * from "./GameAssetValidation.js";
26
+ export * from "./CharacterAssembly.js";
27
+ export * from "./AssetEvidence.js";
28
+ export * from "./AnimationController.js";
29
+ export { gameAssetValidation, quaterniusGameReadyFighterValidationContract, validateQuaterniusGameReadyFighterAsset } from "./GameAssetValidation.js";
30
+ export { createAnimationController } from "./AnimationController.js";
31
+ export * from "./PromptAnimationContract.js";
32
+ export * from "./AuraVoiceBridge.js";
33
+ export * from "./ShotTimeline.js";
34
+ export * from "./DialoguePerformance.js";
35
+ export * from "./VisemeController.js";
36
+ export * from "./PromptAnimationEvidence.js";
37
+ export * from "./CartoonDirector.js";
38
+ export * from "./CartoonPerformance.js";
39
+ export * from "./CartoonRenderQueue.js";
3
40
  const auraAssetRefBrand = Symbol("AuraAssetRef");
4
41
  export function defineAuraAssets(definitions) {
5
42
  const refs = {};
@@ -45,6 +82,9 @@ export class AuraNodeBuilder {
45
82
  physics(spec) {
46
83
  return this.with({ physics: spec });
47
84
  }
85
+ runtime(spec) {
86
+ return this.with({ runtime: { mutable: true, ...spec } });
87
+ }
48
88
  toJSON() {
49
89
  return this.value;
50
90
  }
@@ -2876,6 +2916,8 @@ export const games = {
2876
2916
  miniGolfCourse: () => prefabs.miniGolfCourse(),
2877
2917
  createMiniGolfState: () => createMiniGolfStateController(),
2878
2918
  miniGolfPointerShot: miniGolfPointerShotFromDrag,
2919
+ fighting: fightingGameKit,
2920
+ createFightingGameKit,
2879
2921
  miniGolfScene: () => scene()
2880
2922
  .background("#12321d")
2881
2923
  .addMany(prefabs.miniGolfHole())
@@ -2883,6 +2925,321 @@ export const games = {
2883
2925
  .camera(camera.follow({ targetNode: "white physics golf ball", distance: 4.2 }))
2884
2926
  .timeline(timeline.loop({ seconds: 8 }))
2885
2927
  };
2928
+ export function collectGameRuntimeEvidence(app, options = {}) {
2929
+ return collectGameRuntimeEvidenceV105(app, options);
2930
+ }
2931
+ function createGameInputController(options) {
2932
+ const actions = options.actions;
2933
+ const axes = options.axes ?? {};
2934
+ const bufferMs = options.bufferMs ?? 120;
2935
+ const activeBindings = new Set();
2936
+ const activeActionOverrides = new Set();
2937
+ const previousHeld = new Map();
2938
+ const currentHeld = new Map();
2939
+ const pressedEdges = new Set();
2940
+ const releasedEdges = new Set();
2941
+ const lastPressedAt = new Map();
2942
+ const replayEvents = [];
2943
+ let frame = 0;
2944
+ let time = 0;
2945
+ let latestSnapshot = {
2946
+ kind: "aura-game-input-snapshot",
2947
+ frame,
2948
+ time,
2949
+ activeBindings: [],
2950
+ actions: {}
2951
+ };
2952
+ const resolveHeld = (action) => {
2953
+ if (activeActionOverrides.has(action))
2954
+ return true;
2955
+ const bindings = actions[action] ?? [];
2956
+ return bindings.some((binding) => activeBindings.has(binding));
2957
+ };
2958
+ const record = (type, binding) => {
2959
+ replayEvents.push({ frame, time, type, binding });
2960
+ };
2961
+ const pressBinding = (binding, shouldRecord = true) => {
2962
+ activeBindings.add(binding);
2963
+ if (actions[binding])
2964
+ activeActionOverrides.add(binding);
2965
+ if (shouldRecord)
2966
+ record("press", binding);
2967
+ };
2968
+ const releaseBinding = (binding, shouldRecord = true) => {
2969
+ activeBindings.delete(binding);
2970
+ activeActionOverrides.delete(binding);
2971
+ if (shouldRecord)
2972
+ record("release", binding);
2973
+ };
2974
+ const toSnapshot = () => {
2975
+ const actionStates = {};
2976
+ const nowMs = time * 1000;
2977
+ for (const action of Object.keys(actions)) {
2978
+ const held = currentHeld.get(action) ?? false;
2979
+ actionStates[action] = {
2980
+ pressed: pressedEdges.has(action),
2981
+ held,
2982
+ released: releasedEdges.has(action),
2983
+ buffered: pressedEdges.has(action) || nowMs - (lastPressedAt.get(action) ?? Number.NEGATIVE_INFINITY) <= bufferMs,
2984
+ value: held ? 1 : 0
2985
+ };
2986
+ }
2987
+ return {
2988
+ kind: "aura-game-input-snapshot",
2989
+ frame,
2990
+ time,
2991
+ activeBindings: [...activeBindings].sort(),
2992
+ actions: actionStates
2993
+ };
2994
+ };
2995
+ const update = (dt = 1 / 60) => {
2996
+ frame += 1;
2997
+ time += Math.max(0, dt);
2998
+ pressedEdges.clear();
2999
+ releasedEdges.clear();
3000
+ for (const action of Object.keys(actions)) {
3001
+ const held = resolveHeld(action);
3002
+ const wasHeld = previousHeld.get(action) ?? false;
3003
+ currentHeld.set(action, held);
3004
+ if (held && !wasHeld) {
3005
+ pressedEdges.add(action);
3006
+ lastPressedAt.set(action, time * 1000);
3007
+ }
3008
+ if (!held && wasHeld)
3009
+ releasedEdges.add(action);
3010
+ previousHeld.set(action, held);
3011
+ }
3012
+ latestSnapshot = toSnapshot();
3013
+ return latestSnapshot;
3014
+ };
3015
+ const target = options.target ?? (typeof window !== "undefined" ? window : undefined);
3016
+ const onKeyDown = (event) => {
3017
+ const keyboard = event;
3018
+ if (keyboard.repeat)
3019
+ return;
3020
+ if (keyboard.code)
3021
+ pressBinding(keyboard.code);
3022
+ if (keyboard.key && keyboard.key !== keyboard.code)
3023
+ pressBinding(keyboard.key);
3024
+ };
3025
+ const onKeyUp = (event) => {
3026
+ const keyboard = event;
3027
+ if (keyboard.code)
3028
+ releaseBinding(keyboard.code);
3029
+ if (keyboard.key && keyboard.key !== keyboard.code)
3030
+ releaseBinding(keyboard.key);
3031
+ };
3032
+ if (options.autoListen !== false && target?.addEventListener) {
3033
+ target.addEventListener("keydown", onKeyDown);
3034
+ target.addEventListener("keyup", onKeyUp);
3035
+ }
3036
+ return {
3037
+ kind: "aura-game-input-plan",
3038
+ actions,
3039
+ axes,
3040
+ bufferMs,
3041
+ update,
3042
+ snapshot() {
3043
+ return latestSnapshot;
3044
+ },
3045
+ pressed(action) {
3046
+ return pressedEdges.has(action);
3047
+ },
3048
+ held(action) {
3049
+ return currentHeld.get(action) ?? resolveHeld(action);
3050
+ },
3051
+ released(action) {
3052
+ return releasedEdges.has(action);
3053
+ },
3054
+ buffered(action, windowMs = bufferMs) {
3055
+ return pressedEdges.has(action) || time * 1000 - (lastPressedAt.get(action) ?? Number.NEGATIVE_INFINITY) <= windowMs;
3056
+ },
3057
+ axis(name, negativeAction, positiveAction) {
3058
+ const binding = axes[name];
3059
+ const negative = negativeAction ?? binding?.negative;
3060
+ const positive = positiveAction ?? binding?.positive;
3061
+ if (!negative && !positive)
3062
+ return this.held(name) ? 1 : 0;
3063
+ return (positive && this.held(positive) ? 1 : 0) - (negative && this.held(negative) ? 1 : 0);
3064
+ },
3065
+ press(binding) {
3066
+ pressBinding(binding);
3067
+ },
3068
+ release(binding) {
3069
+ releaseBinding(binding);
3070
+ },
3071
+ setAction(action, held) {
3072
+ if (held) {
3073
+ activeActionOverrides.add(action);
3074
+ record("press", action);
3075
+ }
3076
+ else {
3077
+ activeActionOverrides.delete(action);
3078
+ record("release", action);
3079
+ }
3080
+ },
3081
+ recorded() {
3082
+ return [...replayEvents];
3083
+ },
3084
+ replay(events) {
3085
+ activeBindings.clear();
3086
+ activeActionOverrides.clear();
3087
+ for (const event of events) {
3088
+ if (event.type === "press")
3089
+ pressBinding(event.binding, false);
3090
+ else
3091
+ releaseBinding(event.binding, false);
3092
+ }
3093
+ return update(0);
3094
+ },
3095
+ clearReplay() {
3096
+ replayEvents.length = 0;
3097
+ },
3098
+ dispose() {
3099
+ if (target?.removeEventListener) {
3100
+ target.removeEventListener("keydown", onKeyDown);
3101
+ target.removeEventListener("keyup", onKeyUp);
3102
+ }
3103
+ activeBindings.clear();
3104
+ activeActionOverrides.clear();
3105
+ previousHeld.clear();
3106
+ currentHeld.clear();
3107
+ pressedEdges.clear();
3108
+ releasedEdges.clear();
3109
+ }
3110
+ };
3111
+ }
3112
+ export function createAuraGameRules(options = {}) {
3113
+ return {
3114
+ kind: "aura-game-rules",
3115
+ gravity: options.gravity ?? 24,
3116
+ roundSeconds: options.roundSeconds ?? 90,
3117
+ maxHealth: options.maxHealth ?? 100,
3118
+ maxGuard: options.maxGuard ?? 100,
3119
+ maxMeter: options.maxMeter ?? 100,
3120
+ stageBounds: options.stageBounds ?? {
3121
+ minX: -4.5,
3122
+ maxX: 4.5
3123
+ }
3124
+ };
3125
+ }
3126
+ export const gameRules = Object.assign(createAuraGameRules, {
3127
+ fighting2D: createGameFighting2DRules
3128
+ });
3129
+ export function createAuraGameRuntime(options = {}) {
3130
+ return {
3131
+ kind: "aura-game-runtime",
3132
+ loop: {
3133
+ kind: "aura-game-loop-plan",
3134
+ fixedDt: options.loop?.fixedDt ?? 1 / 60,
3135
+ maxSubSteps: options.loop?.maxSubSteps ?? 5,
3136
+ timeScale: options.loop?.timeScale ?? 1
3137
+ },
3138
+ rules: createAuraGameRules(options.rules),
3139
+ input: options.input ? createGameInput(options.input) : undefined,
3140
+ combat: createCombatWorld(),
3141
+ camera: createGameCameraDirector({
3142
+ stageBounds: {
3143
+ minX: options.rules?.stageBounds?.minX ?? -4.5,
3144
+ maxX: options.rules?.stageBounds?.maxX ?? 4.5
3145
+ }
3146
+ }),
3147
+ effects: createGameEffects({ poolSize: options.effectPoolSize }),
3148
+ bodies: []
3149
+ };
3150
+ }
3151
+ export const game = {
3152
+ createRuntime: createAuraGameRuntime,
3153
+ rules: gameRules,
3154
+ loop: (options = {}) => ({
3155
+ kind: "aura-game-loop-plan",
3156
+ fixedDt: options.fixedDt ?? 1 / 60,
3157
+ maxSubSteps: options.maxSubSteps ?? 5,
3158
+ timeScale: options.timeScale ?? 1
3159
+ }),
3160
+ frameLoop: createFrameLoop,
3161
+ runtimeNode: createRuntimeNodeSpec,
3162
+ input: createGameInput,
3163
+ inputReplay: createGameInputReplay,
3164
+ inputReplayDriver: createGameInputReplayDriver,
3165
+ inputReplayEventsAt: gameInputReplayEventsAt,
3166
+ touchControls: createGameTouchControlLayout,
3167
+ kinematicBody: createGameKinematicBody,
3168
+ jumpAssist: createGameJumpAssist,
3169
+ collider: {
3170
+ box: createGameBoxCollider,
3171
+ sphere: createGameSphereCollider,
3172
+ capsule: createGameCapsuleCollider,
3173
+ rect: createGameRectCollider,
3174
+ aabb: gameColliderAabb,
3175
+ factories: gameColliders
3176
+ },
3177
+ hitbox: gameHitboxes,
3178
+ hurtbox: gameHurtboxes,
3179
+ guardbox: gameGuardboxes,
3180
+ pushbox: gamePushboxes,
3181
+ trigger: gameTriggerVolumes,
3182
+ combatWorld: createCombatWorld,
3183
+ combatEvents: applyGameCombatEventsToRuntime,
3184
+ cameraDirector: createGameCameraDirector,
3185
+ effects: createGameEffects,
3186
+ effectPresets: gameEffectPresets,
3187
+ debug: {
3188
+ colliders: createGameColliderDebugGeometry,
3189
+ hitboxes: createGameHitboxDebugGeometry,
3190
+ combat: createGameCombatDebugGeometry,
3191
+ overlay: createGameDebugOverlayData,
3192
+ sceneNodes: createGameDebugSceneNodes
3193
+ },
3194
+ hud: {
3195
+ health: createGameHudHealthBinding,
3196
+ meter: createGameHudMeterBinding,
3197
+ timer: createGameHudTimerBinding,
3198
+ combo: createGameHudComboBinding,
3199
+ round: createGameHudRoundBinding,
3200
+ debugToggle: createGameHudDebugToggleBinding,
3201
+ bindings: createGameHudBindings,
3202
+ snapshot: createGameHudSnapshot
3203
+ },
3204
+ accessibility: {
3205
+ label: createGameAccessibilityLabel,
3206
+ focus: createGameAccessibilityFocus,
3207
+ reducedMotion: createGameReducedMotionSource,
3208
+ reducedFlash: createGameReducedFlashSource,
3209
+ highContrast: createGameHighContrastSource,
3210
+ pauseControls: createGamePauseControlsSource,
3211
+ settings: createGameAccessibilityRuntimeSettings
3212
+ },
3213
+ fighting: createFightingGameKit,
3214
+ evidence: collectGameRuntimeEvidence
3215
+ };
3216
+ export const cartoon = {
3217
+ episodePlan: createPromptAnimationEpisodePlan,
3218
+ storyBible: createPromptAnimationStoryBible,
3219
+ storyboard: definePromptAnimationStoryboard,
3220
+ shotTimeline: createShotTimeline,
3221
+ shotPlaybackPlan: createShotPlaybackPlan,
3222
+ sampleShotPlaybackPlan,
3223
+ applyShotPlaybackFrame,
3224
+ installShotPlayback,
3225
+ captionsFromDialogue: deriveCaptionTrackFromDialogue,
3226
+ captionCueAtTime,
3227
+ captionTimingProof: createCaptionTimingProof,
3228
+ visemeTrack: createAuraVoiceVisemeTrack,
3229
+ primitiveMouthVisemes: createPrimitiveMouthVisemeCues,
3230
+ glbBlendshapeViseme: createGlbBlendshapeVisemeCue,
3231
+ sampleVisemeTrack,
3232
+ auraVoiceBridgePackage: createAuraVoiceBridgePackage,
3233
+ sampleAuraVoiceBridgeAtTime,
3234
+ auraVoiceRerenderPlan: createAuraVoiceRerenderPlan,
3235
+ auraVoiceDubRerenderProof: createAuraVoiceDubRerenderProof,
3236
+ director: createCartoonDirectorPlan,
3237
+ performance: createCartoonPerformance,
3238
+ renderQueue: createCartoonRenderQueue,
3239
+ renderOutputPackage: createCartoonRenderOutputPackageMetadata,
3240
+ evidence: collectPromptAnimationEvidence
3241
+ };
3242
+ export const animationStudio = cartoon;
2886
3243
  function collectParticleBudgetDiagnostics(nodes) {
2887
3244
  const flattened = groups.flatten(nodes);
2888
3245
  const particleEffects = flattened.filter((node) => node.kind === "effect" && node.effect === "particles");
@@ -3500,6 +3857,7 @@ export const character = {
3500
3857
  lowPolyHumanoid: (options = {}) => createLowPolyHumanoid(options),
3501
3858
  authoredHumanoid: (options = {}) => createAuthoredLowPolyHumanoid(options),
3502
3859
  primitiveHumanoid: (options = {}) => createHierarchicalPrimitiveHumanoid(options),
3860
+ performance: createCartoonPerformance,
3503
3861
  importedRigRuntime: async (options) => {
3504
3862
  markAuraLazySystemRequested("character-rig", "character.importedRigRuntime");
3505
3863
  const started = performanceNow();
@@ -4278,17 +4636,46 @@ export const sceneKits = {
4278
4636
  humanoidWalk: (options = {}) => makeSceneKit("humanoidWalk", options),
4279
4637
  productViewer: (asset, options = {}) => makeSceneKit("productViewer", { ...options, asset })
4280
4638
  };
4639
+ export function promptSubjectIsResolved(s) {
4640
+ return "asset" in s;
4641
+ }
4642
+ export async function resolvePromptPlanSubject(plan, resolver) {
4643
+ if (promptSubjectIsResolved(plan.subject)) {
4644
+ return plan;
4645
+ }
4646
+ const intent = plan.subject;
4647
+ const result = await resolver.resolve({ text: intent.intent, constraints: intent.constraints });
4648
+ if (!result) {
4649
+ throw new Error(`No auto-pullable asset matched the prompt-plan intent "${intent.intent}". ` +
4650
+ "Refine the intent or constraints (maxTriangles/license/animated), or provide a concrete typed asset " +
4651
+ "(e.g. a file via `assets add` / a typed asset ref) before compiling.");
4652
+ }
4653
+ const resolvedSubject = {
4654
+ asset: result.asset,
4655
+ ...(intent.label !== undefined ? { label: intent.label } : {})
4656
+ };
4657
+ return { ...plan, subject: resolvedSubject };
4658
+ }
4281
4659
  export function definePromptPlan(plan) {
4282
4660
  return plan;
4283
4661
  }
4662
+ function requireResolvedPromptSubject(plan) {
4663
+ if (!promptSubjectIsResolved(plan.subject)) {
4664
+ throw new Error(`Cannot compile a prompt plan whose subject is still an unresolved intent ("${plan.subject.intent}"). ` +
4665
+ "Resolve the prompt-plan subject first via resolvePromptPlanSubject(...) or the CLI `assets search`; " +
4666
+ "compile needs a concrete typed asset.");
4667
+ }
4668
+ return plan.subject;
4669
+ }
4284
4670
  export function compilePromptPlan(plan) {
4285
- const sceneBuilder = promptRecipes[plan.sceneType](plan.subject.asset, plan);
4671
+ const subject = requireResolvedPromptSubject(plan);
4672
+ const sceneBuilder = promptRecipes[plan.sceneType](subject.asset, plan);
4286
4673
  return {
4287
4674
  scene: sceneBuilder,
4288
4675
  report: {
4289
4676
  schema: "aura3d-prompt-plan-report/1.0",
4290
4677
  sceneType: plan.sceneType,
4291
- subjectAssetId: plan.subject.asset.id,
4678
+ subjectAssetId: subject.asset.id,
4292
4679
  recipe: plan.sceneType,
4293
4680
  cameraPreset: plan.camera?.preset ?? defaultCameraPreset(plan.sceneType),
4294
4681
  lightingPreset: plan.lighting?.preset ?? defaultLightingPreset(plan.sceneType),
@@ -4485,6 +4872,10 @@ function repairHintsForPromptPlan(plan) {
4485
4872
  function promptPlanWarnings(plan) {
4486
4873
  const warnings = [];
4487
4874
  const acceptanceCriteria = plan.acceptanceCriteria.map((item) => item.trim()).filter(Boolean);
4875
+ if (!promptSubjectIsResolved(plan.subject)) {
4876
+ warnings.push(`PromptPlan subject is still an unresolved intent ("${plan.subject.intent}"); resolve it via resolvePromptPlanSubject(...) ` +
4877
+ "or the CLI `assets search` to a concrete typed asset before compiling.");
4878
+ }
4488
4879
  if (!plan.subject.label?.trim()) {
4489
4880
  warnings.push("PromptPlan subject is missing a human-readable label; add one so reports and diagnostics describe the visible subject.");
4490
4881
  }
@@ -4522,6 +4913,217 @@ export class AuraRuntimeError extends Error {
4522
4913
  this.code = code;
4523
4914
  }
4524
4915
  }
4916
+ function createAuraRuntimeNodeRegistry(snapshot) {
4917
+ let handles = new Map();
4918
+ const registry = {
4919
+ get(id) {
4920
+ return handles.get(id);
4921
+ },
4922
+ require(id) {
4923
+ const handle = handles.get(id);
4924
+ if (!handle) {
4925
+ throw new AuraRuntimeError("missing-asset", `Aura3D runtime node "${id}" was not found. Suggested fix: add .runtime({ id: "${id}" }) to the model, primitive, group, or label you want to mutate.`);
4926
+ }
4927
+ return handle;
4928
+ },
4929
+ has(id) {
4930
+ return handles.has(id);
4931
+ },
4932
+ ids() {
4933
+ return [...handles.keys()];
4934
+ },
4935
+ all() {
4936
+ return [...handles.values()];
4937
+ },
4938
+ reset(nextSnapshot) {
4939
+ handles = collectRuntimeNodeHandles(nextSnapshot);
4940
+ }
4941
+ };
4942
+ registry.reset(snapshot);
4943
+ return registry;
4944
+ }
4945
+ function collectRuntimeNodeHandles(snapshot) {
4946
+ const next = new Map();
4947
+ for (const node of snapshot.nodes) {
4948
+ const runtime = "runtime" in node ? node.runtime : undefined;
4949
+ if (!runtime?.id)
4950
+ continue;
4951
+ next.set(runtime.id, createRuntimeNodeHandle(node, runtime));
4952
+ }
4953
+ return next;
4954
+ }
4955
+ function createRuntimeNodeHandle(node, runtime) {
4956
+ const tags = runtime.tags ?? [];
4957
+ const attachedEffects = [];
4958
+ const morphTargetWeights = new Map();
4959
+ let animationBinding;
4960
+ let animationPose;
4961
+ let animationPoseBinding;
4962
+ const getVisible = () => node.kind === "model" ? node.visible !== false : node.visible !== false;
4963
+ const getBounds = () => calculateRuntimeNodeBounds({
4964
+ position: node.position,
4965
+ scale: node.scale,
4966
+ size: "size" in node ? node.size : undefined
4967
+ });
4968
+ return {
4969
+ id: runtime.id,
4970
+ kind: node.kind,
4971
+ name: "name" in node ? node.name : undefined,
4972
+ tags,
4973
+ get position() {
4974
+ return node.position ?? [0, 0, 0];
4975
+ },
4976
+ set position(next) {
4977
+ node.position = next;
4978
+ },
4979
+ get rotation() {
4980
+ return node.rotation ?? [0, 0, 0];
4981
+ },
4982
+ set rotation(next) {
4983
+ node.rotation = next;
4984
+ },
4985
+ get scale() {
4986
+ return node.scale ?? 1;
4987
+ },
4988
+ set scale(next) {
4989
+ node.scale = next;
4990
+ },
4991
+ get visible() {
4992
+ return getVisible();
4993
+ },
4994
+ set visible(next) {
4995
+ node.visible = next;
4996
+ },
4997
+ setPosition(x, y, z) {
4998
+ node.position = [x, y, z];
4999
+ return this;
5000
+ },
5001
+ translate(x, y, z) {
5002
+ const current = node.position ?? [0, 0, 0];
5003
+ node.position = [current[0] + x, current[1] + y, current[2] + z];
5004
+ return this;
5005
+ },
5006
+ setRotation(x, y, z) {
5007
+ node.rotation = [x, y, z];
5008
+ return this;
5009
+ },
5010
+ setScale(scale) {
5011
+ node.scale = scale;
5012
+ return this;
5013
+ },
5014
+ setVisible(visible) {
5015
+ node.visible = visible;
5016
+ return this;
5017
+ },
5018
+ setMaterial(nextMaterial) {
5019
+ node.material = nextMaterial;
5020
+ return this;
5021
+ },
5022
+ play(clip, options = {}) {
5023
+ node.animation = { ...options, clip };
5024
+ return this;
5025
+ },
5026
+ setAnimation(animation) {
5027
+ node.animation = animation;
5028
+ return this;
5029
+ },
5030
+ setAnimationBinding(binding) {
5031
+ animationBinding = binding;
5032
+ return this;
5033
+ },
5034
+ setAnimationPose(pose, metadata) {
5035
+ animationPose = pose ? cloneRuntimeAnimationPose(pose) : undefined;
5036
+ animationPoseBinding = pose ? metadata : undefined;
5037
+ if (pose?.morphTargets) {
5038
+ for (const [name, weight] of Object.entries(pose.morphTargets)) {
5039
+ const normalizedName = name.trim();
5040
+ if (normalizedName) {
5041
+ morphTargetWeights.set(normalizedName, sanitizeRuntimeMorphWeight(weight));
5042
+ }
5043
+ }
5044
+ }
5045
+ return this;
5046
+ },
5047
+ animationPose() {
5048
+ return animationPose ? cloneRuntimeAnimationPose(animationPose) : undefined;
5049
+ },
5050
+ setMorphTarget(name, weight) {
5051
+ const normalizedName = name.trim();
5052
+ if (!normalizedName) {
5053
+ throw new AuraRuntimeError("missing-asset", "Aura3D morph target name is required.");
5054
+ }
5055
+ morphTargetWeights.set(normalizedName, sanitizeRuntimeMorphWeight(weight));
5056
+ return this;
5057
+ },
5058
+ setMorphTargets(weights) {
5059
+ morphTargetWeights.clear();
5060
+ for (const [name, weight] of Object.entries(weights)) {
5061
+ const normalizedName = name.trim();
5062
+ if (normalizedName) {
5063
+ morphTargetWeights.set(normalizedName, sanitizeRuntimeMorphWeight(weight));
5064
+ }
5065
+ }
5066
+ return this;
5067
+ },
5068
+ morphTargets() {
5069
+ return Object.fromEntries(morphTargetWeights.entries());
5070
+ },
5071
+ bounds() {
5072
+ return getBounds();
5073
+ },
5074
+ attachEffect(effect) {
5075
+ attachedEffects.push(effect);
5076
+ return this;
5077
+ },
5078
+ effects() {
5079
+ return [...attachedEffects];
5080
+ },
5081
+ snapshot() {
5082
+ return {
5083
+ id: runtime.id,
5084
+ kind: node.kind,
5085
+ name: "name" in node ? node.name : undefined,
5086
+ tags,
5087
+ position: node.position ?? [0, 0, 0],
5088
+ rotation: node.rotation ?? [0, 0, 0],
5089
+ scale: node.scale ?? 1,
5090
+ visible: getVisible(),
5091
+ animation: node.animation,
5092
+ animationBinding,
5093
+ animationPose: animationPose ? cloneRuntimeAnimationPose(animationPose) : undefined,
5094
+ animationPoseBinding,
5095
+ morphTargets: Object.fromEntries(morphTargetWeights.entries()),
5096
+ bounds: getBounds(),
5097
+ effects: [...attachedEffects]
5098
+ };
5099
+ }
5100
+ };
5101
+ }
5102
+ function cloneRuntimeAnimationPose(pose) {
5103
+ return {
5104
+ bones: Object.fromEntries(Object.entries(pose.bones ?? {}).map(([bone, transform]) => [
5105
+ bone,
5106
+ {
5107
+ position: transform.position ? { ...transform.position } : undefined,
5108
+ rotation: transform.rotation ? { ...transform.rotation } : undefined,
5109
+ scale: transform.scale ? { ...transform.scale } : undefined
5110
+ }
5111
+ ])),
5112
+ morphTargets: pose.morphTargets ? { ...pose.morphTargets } : undefined,
5113
+ rootMotion: pose.rootMotion
5114
+ ? {
5115
+ translation: pose.rootMotion.translation ? { ...pose.rootMotion.translation } : undefined,
5116
+ rotation: pose.rootMotion.rotation ? { ...pose.rootMotion.rotation } : undefined
5117
+ }
5118
+ : undefined,
5119
+ metadata: pose.metadata ? { ...pose.metadata } : undefined
5120
+ };
5121
+ }
5122
+ function sanitizeRuntimeMorphWeight(weight) {
5123
+ if (!Number.isFinite(weight))
5124
+ return 0;
5125
+ return Math.max(0, Math.min(1, weight));
5126
+ }
4525
5127
  export function createAuraApp(target, options) {
4526
5128
  let snapshot = normalizeSceneSnapshot(options.scene);
4527
5129
  let renderSnapshot = flattenSceneSnapshot(snapshot);
@@ -4537,6 +5139,32 @@ export function createAuraApp(target, options) {
4537
5139
  let lastTime = 0;
4538
5140
  let mountRevision = 0;
4539
5141
  let canvasRuntimePhysics;
5142
+ const runtimeNodes = createAuraRuntimeNodeRegistry(renderSnapshot);
5143
+ const frameCallbacks = new Set();
5144
+ let runtimePaused = options.autoStart === false;
5145
+ let runtimeFrame = 0;
5146
+ let runtimeTime = 0;
5147
+ const runtimeFixedDt = 1 / 60;
5148
+ let runtimeAlpha = 0;
5149
+ const ownedInputControllers = new Set();
5150
+ const runRuntimeFrame = (dt, source) => {
5151
+ runtimeFrame += 1;
5152
+ runtimeTime += dt;
5153
+ runtimeAlpha = runtimeFixedDt > 0 ? Math.max(0, Math.min(1, (dt % runtimeFixedDt) / runtimeFixedDt)) : 0;
5154
+ const frame = {
5155
+ dt,
5156
+ fixedDt: runtimeFixedDt,
5157
+ time: runtimeTime,
5158
+ frame: runtimeFrame,
5159
+ alpha: runtimeAlpha,
5160
+ paused: runtimePaused,
5161
+ source,
5162
+ substep: 1,
5163
+ substeps: 1
5164
+ };
5165
+ for (const callback of [...frameCallbacks])
5166
+ callback(frame);
5167
+ };
4540
5168
  const shouldUseProductionRendererForCurrentScene = () => Boolean(canvas && renderSnapshot.nodes.some(isWebGLRenderableNode) && typeof window !== "undefined");
4541
5169
  const resetDiagnosticsForCurrentScene = (backend) => {
4542
5170
  const fresh = createInitialDiagnostics(renderSnapshot);
@@ -4557,7 +5185,11 @@ export function createAuraApp(target, options) {
4557
5185
  return;
4558
5186
  const delta = lastTime > 0 ? Math.max(1, time - lastTime) : 16.67;
4559
5187
  lastTime = time;
4560
- canvasRuntimePhysics?.step(delta / 1000);
5188
+ const dt = delta / 1000;
5189
+ if (!runtimePaused) {
5190
+ runRuntimeFrame(dt, "raf");
5191
+ canvasRuntimePhysics?.step(dt);
5192
+ }
4561
5193
  diagnosticsState.evidence = collectAuraSceneEvidence(renderSnapshot);
4562
5194
  diagnosticsState.fps = Math.round(1000 / delta);
4563
5195
  diagnosticsState.drawCalls = renderSceneToCanvas(canvas, renderSnapshot, time);
@@ -4584,7 +5216,7 @@ export function createAuraApp(target, options) {
4584
5216
  overlay?.update();
4585
5217
  const revision = ++mountRevision;
4586
5218
  if (shouldUseProductionRenderer && canvas) {
4587
- void startProductionRender(canvas, renderSnapshot, diagnosticsState, options, overlay)
5219
+ void startProductionRender(canvas, renderSnapshot, diagnosticsState, options, overlay, runRuntimeFrame, () => runtimePaused)
4588
5220
  .then((controller) => {
4589
5221
  if (disposed || revision !== mountRevision) {
4590
5222
  controller.dispose();
@@ -4618,11 +5250,71 @@ export function createAuraApp(target, options) {
4618
5250
  setScene(nextScene) {
4619
5251
  snapshot = normalizeSceneSnapshot(nextScene);
4620
5252
  renderSnapshot = flattenSceneSnapshot(snapshot);
5253
+ runtimeNodes.reset(renderSnapshot);
4621
5254
  mountCurrentScene();
4622
5255
  },
5256
+ nodes: runtimeNodes,
5257
+ get runtime() {
5258
+ return {
5259
+ paused: runtimePaused,
5260
+ frame: runtimeFrame,
5261
+ time: runtimeTime,
5262
+ fixedDt: runtimeFixedDt,
5263
+ alpha: runtimeAlpha
5264
+ };
5265
+ },
5266
+ onFrame(callback) {
5267
+ frameCallbacks.add(callback);
5268
+ return () => {
5269
+ frameCallbacks.delete(callback);
5270
+ };
5271
+ },
5272
+ offFrame(callback) {
5273
+ frameCallbacks.delete(callback);
5274
+ },
5275
+ input(inputOptions) {
5276
+ const controller = createGameInput(inputOptions);
5277
+ ownedInputControllers.add(controller);
5278
+ return controller;
5279
+ },
5280
+ pause() {
5281
+ runtimePaused = true;
5282
+ },
5283
+ resume() {
5284
+ runtimePaused = false;
5285
+ if (!animationHandle && !productionController && options.autoStart !== false && typeof requestAnimationFrame !== "undefined") {
5286
+ animationHandle = requestAnimationFrame(render);
5287
+ }
5288
+ },
5289
+ step(dt = 1 / 60) {
5290
+ const seconds = Math.max(0, dt);
5291
+ runRuntimeFrame(seconds, "manual");
5292
+ canvasRuntimePhysics?.step(seconds);
5293
+ const previousPaused = runtimePaused;
5294
+ runtimePaused = true;
5295
+ if (productionController) {
5296
+ productionController.render(performanceNow());
5297
+ }
5298
+ else {
5299
+ render(performanceNow());
5300
+ }
5301
+ runtimePaused = previousPaused;
5302
+ },
4623
5303
  diagnostics() {
4624
5304
  return snapshotDiagnostics(diagnosticsState);
4625
5305
  },
5306
+ evidence(evidenceOptions = {}) {
5307
+ return collectGameRuntimeEvidenceV105({
5308
+ runtime: {
5309
+ paused: runtimePaused,
5310
+ frame: runtimeFrame,
5311
+ time: runtimeTime,
5312
+ fixedDt: runtimeFixedDt,
5313
+ alpha: runtimeAlpha
5314
+ },
5315
+ nodes: runtimeNodes
5316
+ }, evidenceOptions);
5317
+ },
4626
5318
  screenshot() {
4627
5319
  return captureAuraScreenshot(canvas);
4628
5320
  },
@@ -4630,6 +5322,9 @@ export function createAuraApp(target, options) {
4630
5322
  disposed = true;
4631
5323
  if (animationHandle && typeof cancelAnimationFrame !== "undefined")
4632
5324
  cancelAnimationFrame(animationHandle);
5325
+ for (const controller of ownedInputControllers)
5326
+ controller.dispose();
5327
+ ownedInputControllers.clear();
4633
5328
  productionController?.dispose();
4634
5329
  overlay?.dispose();
4635
5330
  }
@@ -4653,6 +5348,10 @@ export function collectAuraSceneEvidence(sceneValue) {
4653
5348
  const assetProvenance = snapshot.nodes
4654
5349
  .filter((node) => node.kind === "model")
4655
5350
  .map((node) => createAssetProvenance(node.asset));
5351
+ const runtimeNodeIds = snapshot.nodes
5352
+ .map((node) => "runtime" in node ? node.runtime?.id : undefined)
5353
+ .filter((id) => Boolean(id));
5354
+ const expectsGameRuntime = runtimeNodeIds.length > 0 || interactionNodes.some((node) => node.mode === "keyboard" || node.mode === "drag-vector" || node.mode === "click-impulse");
4656
5355
  return {
4657
5356
  physics: {
4658
5357
  worldAttached: Boolean(snapshot.physics),
@@ -4690,6 +5389,31 @@ export function collectAuraSceneEvidence(sceneValue) {
4690
5389
  collisionAvoidance: labelNodes.filter((node) => node.collisionAvoidance === true).length
4691
5390
  },
4692
5391
  performance: createPerformanceEvidence(snapshot),
5392
+ gameRuntime: collectGameRuntimeEvidenceV105({
5393
+ runtime: {
5394
+ frame: 0,
5395
+ time: 0,
5396
+ paused: true
5397
+ },
5398
+ nodes: {
5399
+ ids: () => runtimeNodeIds
5400
+ }
5401
+ }, {
5402
+ animation: {
5403
+ controllers: animatedNodes.length,
5404
+ activeClips: clips,
5405
+ eventCount: 0
5406
+ },
5407
+ assets: {
5408
+ typedAssets: assetProvenance.filter((asset) => asset.source === "typed-aura-assets-manifest").length,
5409
+ missingAssets: []
5410
+ },
5411
+ source: {
5412
+ mode: "scene-source",
5413
+ expectsGame: expectsGameRuntime,
5414
+ label: "collectAuraSceneEvidence"
5415
+ }
5416
+ }),
4693
5417
  rendering: createRendererDiagnosticReport(snapshot),
4694
5418
  assets: assetProvenance
4695
5419
  };
@@ -4810,7 +5534,7 @@ function isRenderableModelNode(node) {
4810
5534
  function isWebGLRenderableNode(node) {
4811
5535
  return isRenderableModelNode(node) || node.kind === "primitive";
4812
5536
  }
4813
- async function startProductionRender(canvas, snapshot, diagnosticsState, options, overlay) {
5537
+ async function startProductionRender(canvas, snapshot, diagnosticsState, options, overlay, beforeRender, isPaused = () => false) {
4814
5538
  const renderableNode = snapshot.nodes.find(isWebGLRenderableNode);
4815
5539
  if (!renderableNode) {
4816
5540
  throw new AuraRuntimeError("missing-asset", "Aura3D production rendering requires at least one typed model asset or primitive. Suggested fix: add model(assets.product), primitives.box(), primitives.sphere(), primitives.cylinder(), or primitives.plane().");
@@ -4820,9 +5544,14 @@ async function startProductionRender(canvas, snapshot, diagnosticsState, options
4820
5544
  const continuousRender = shouldContinuouslyRender(snapshot);
4821
5545
  let disposed = false;
4822
5546
  let animationHandle = 0;
5547
+ let lastTime = 0;
4823
5548
  const renderFrame = (time = performanceNow()) => {
4824
5549
  if (disposed)
4825
5550
  return;
5551
+ const delta = lastTime > 0 ? Math.max(1, time - lastTime) : 16.67;
5552
+ lastTime = time;
5553
+ if (!isPaused())
5554
+ beforeRender?.(delta / 1000, "raf");
4826
5555
  const drawCalls = renderer.render(time);
4827
5556
  diagnosticsState.backend = "webgl2";
4828
5557
  diagnosticsState.fps = diagnosticsState.fps || 60;
@@ -4837,6 +5566,9 @@ async function startProductionRender(canvas, snapshot, diagnosticsState, options
4837
5566
  };
4838
5567
  renderFrame();
4839
5568
  return {
5569
+ render(time = performanceNow()) {
5570
+ renderFrame(time);
5571
+ },
4840
5572
  dispose() {
4841
5573
  disposed = true;
4842
5574
  if (animationHandle && typeof cancelAnimationFrame !== "undefined")
@@ -4851,6 +5583,8 @@ function shouldContinuouslyRender(snapshot) {
4851
5583
  if (snapshot.camera.mode === "dolly" || snapshot.camera.mode === "follow" || snapshot.camera.mode === "path" || snapshot.camera.mode === "flythrough")
4852
5584
  return true;
4853
5585
  return snapshot.nodes.some((node) => {
5586
+ if ("runtime" in node && node.runtime?.mutable !== false)
5587
+ return true;
4854
5588
  if ((node.kind === "model" || node.kind === "primitive") && node.animation)
4855
5589
  return true;
4856
5590
  if (node.kind !== "effect")
@@ -6179,7 +6913,7 @@ function normalizeSceneSnapshot(value) {
6179
6913
  }
6180
6914
  function resolveCanvas(target) {
6181
6915
  if (!target) {
6182
- throw new AuraRuntimeError("missing-canvas", "Aura3D could not mount because the app target was null or undefined. Suggested fix: pass a selector like createAuraApp(\"#app\", ...) or check document.querySelector before mounting.");
6916
+ return undefined;
6183
6917
  }
6184
6918
  if (typeof target === "string") {
6185
6919
  if (typeof document === "undefined") {