@aura3d/scripting 1.0.6

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 (139) hide show
  1. package/README.md +16 -0
  2. package/dist/AdaptiveDifficultyFixtures.d.ts +58 -0
  3. package/dist/AdaptiveDifficultyFixtures.d.ts.map +1 -0
  4. package/dist/AdaptiveDifficultyFixtures.js +228 -0
  5. package/dist/AdaptiveDifficultyFixtures.js.map +1 -0
  6. package/dist/AnalyticsPrivacyFixtures.d.ts +63 -0
  7. package/dist/AnalyticsPrivacyFixtures.d.ts.map +1 -0
  8. package/dist/AnalyticsPrivacyFixtures.js +120 -0
  9. package/dist/AnalyticsPrivacyFixtures.js.map +1 -0
  10. package/dist/Behavior.d.ts +10 -0
  11. package/dist/Behavior.d.ts.map +1 -0
  12. package/dist/Behavior.js +2 -0
  13. package/dist/Behavior.js.map +1 -0
  14. package/dist/BehaviorHost.d.ts +17 -0
  15. package/dist/BehaviorHost.d.ts.map +1 -0
  16. package/dist/BehaviorHost.js +39 -0
  17. package/dist/BehaviorHost.js.map +1 -0
  18. package/dist/BehaviorRegistry.d.ts +8 -0
  19. package/dist/BehaviorRegistry.d.ts.map +1 -0
  20. package/dist/BehaviorRegistry.js +17 -0
  21. package/dist/BehaviorRegistry.js.map +1 -0
  22. package/dist/BehaviorSystem.d.ts +26 -0
  23. package/dist/BehaviorSystem.d.ts.map +1 -0
  24. package/dist/BehaviorSystem.js +76 -0
  25. package/dist/BehaviorSystem.js.map +1 -0
  26. package/dist/BehaviorTree.d.ts +75 -0
  27. package/dist/BehaviorTree.d.ts.map +1 -0
  28. package/dist/BehaviorTree.js +204 -0
  29. package/dist/BehaviorTree.js.map +1 -0
  30. package/dist/CloudServiceFixtures.d.ts +81 -0
  31. package/dist/CloudServiceFixtures.d.ts.map +1 -0
  32. package/dist/CloudServiceFixtures.js +144 -0
  33. package/dist/CloudServiceFixtures.js.map +1 -0
  34. package/dist/CulturalBehaviorFixtures.d.ts +75 -0
  35. package/dist/CulturalBehaviorFixtures.d.ts.map +1 -0
  36. package/dist/CulturalBehaviorFixtures.js +180 -0
  37. package/dist/CulturalBehaviorFixtures.js.map +1 -0
  38. package/dist/DecisionTree.d.ts +42 -0
  39. package/dist/DecisionTree.d.ts.map +1 -0
  40. package/dist/DecisionTree.js +125 -0
  41. package/dist/DecisionTree.js.map +1 -0
  42. package/dist/GOAP.d.ts +51 -0
  43. package/dist/GOAP.d.ts.map +1 -0
  44. package/dist/GOAP.js +105 -0
  45. package/dist/GOAP.js.map +1 -0
  46. package/dist/HTN.d.ts +58 -0
  47. package/dist/HTN.d.ts.map +1 -0
  48. package/dist/HTN.js +115 -0
  49. package/dist/HTN.js.map +1 -0
  50. package/dist/LearningAgentFixtures.d.ts +60 -0
  51. package/dist/LearningAgentFixtures.d.ts.map +1 -0
  52. package/dist/LearningAgentFixtures.js +122 -0
  53. package/dist/LearningAgentFixtures.js.map +1 -0
  54. package/dist/NetworkReplicationFixtures.d.ts +82 -0
  55. package/dist/NetworkReplicationFixtures.d.ts.map +1 -0
  56. package/dist/NetworkReplicationFixtures.js +330 -0
  57. package/dist/NetworkReplicationFixtures.js.map +1 -0
  58. package/dist/Perception.d.ts +58 -0
  59. package/dist/Perception.d.ts.map +1 -0
  60. package/dist/Perception.js +111 -0
  61. package/dist/Perception.js.map +1 -0
  62. package/dist/PlayerBehaviorTelemetryFixtures.d.ts +74 -0
  63. package/dist/PlayerBehaviorTelemetryFixtures.d.ts.map +1 -0
  64. package/dist/PlayerBehaviorTelemetryFixtures.js +189 -0
  65. package/dist/PlayerBehaviorTelemetryFixtures.js.map +1 -0
  66. package/dist/ProceduralContentAdaptationFixtures.d.ts +52 -0
  67. package/dist/ProceduralContentAdaptationFixtures.d.ts.map +1 -0
  68. package/dist/ProceduralContentAdaptationFixtures.js +149 -0
  69. package/dist/ProceduralContentAdaptationFixtures.js.map +1 -0
  70. package/dist/ScriptContext.d.ts +18 -0
  71. package/dist/ScriptContext.d.ts.map +1 -0
  72. package/dist/ScriptContext.js +21 -0
  73. package/dist/ScriptContext.js.map +1 -0
  74. package/dist/StateMachine.d.ts +52 -0
  75. package/dist/StateMachine.d.ts.map +1 -0
  76. package/dist/StateMachine.js +117 -0
  77. package/dist/StateMachine.js.map +1 -0
  78. package/dist/UtilityAI.d.ts +55 -0
  79. package/dist/UtilityAI.d.ts.map +1 -0
  80. package/dist/UtilityAI.js +113 -0
  81. package/dist/UtilityAI.js.map +1 -0
  82. package/dist/VisualGraph.d.ts +20 -0
  83. package/dist/VisualGraph.d.ts.map +1 -0
  84. package/dist/VisualGraph.js +191 -0
  85. package/dist/VisualGraph.js.map +1 -0
  86. package/dist/VisualGraphContext.d.ts +123 -0
  87. package/dist/VisualGraphContext.d.ts.map +1 -0
  88. package/dist/VisualGraphContext.js +2 -0
  89. package/dist/VisualGraphContext.js.map +1 -0
  90. package/dist/VisualGraphExecutor.d.ts +16 -0
  91. package/dist/VisualGraphExecutor.d.ts.map +1 -0
  92. package/dist/VisualGraphExecutor.js +571 -0
  93. package/dist/VisualGraphExecutor.js.map +1 -0
  94. package/dist/VisualNode.d.ts +17 -0
  95. package/dist/VisualNode.d.ts.map +1 -0
  96. package/dist/VisualNode.js +24 -0
  97. package/dist/VisualNode.js.map +1 -0
  98. package/dist/VisualNodeCatalog.d.ts +14 -0
  99. package/dist/VisualNodeCatalog.d.ts.map +1 -0
  100. package/dist/VisualNodeCatalog.js +142 -0
  101. package/dist/VisualNodeCatalog.js.map +1 -0
  102. package/dist/WeaponSystem.d.ts +228 -0
  103. package/dist/WeaponSystem.d.ts.map +1 -0
  104. package/dist/WeaponSystem.js +530 -0
  105. package/dist/WeaponSystem.js.map +1 -0
  106. package/dist/index.d.ts +51 -0
  107. package/dist/index.d.ts.map +1 -0
  108. package/dist/index.js +25 -0
  109. package/dist/index.js.map +1 -0
  110. package/package.json +13 -0
  111. package/src/AdaptiveDifficultyFixtures.ts +324 -0
  112. package/src/AnalyticsPrivacyFixtures.ts +182 -0
  113. package/src/Behavior.ts +11 -0
  114. package/src/BehaviorHost.ts +51 -0
  115. package/src/BehaviorRegistry.ts +22 -0
  116. package/src/BehaviorSystem.ts +103 -0
  117. package/src/BehaviorTree.ts +234 -0
  118. package/src/CloudServiceFixtures.ts +225 -0
  119. package/src/CulturalBehaviorFixtures.ts +262 -0
  120. package/src/DecisionTree.ts +162 -0
  121. package/src/GOAP.ts +150 -0
  122. package/src/HTN.ts +178 -0
  123. package/src/LearningAgentFixtures.ts +184 -0
  124. package/src/NetworkReplicationFixtures.ts +440 -0
  125. package/src/Perception.ts +163 -0
  126. package/src/PlayerBehaviorTelemetryFixtures.ts +257 -0
  127. package/src/ProceduralContentAdaptationFixtures.ts +205 -0
  128. package/src/ScriptContext.ts +34 -0
  129. package/src/StateMachine.ts +138 -0
  130. package/src/UtilityAI.ts +158 -0
  131. package/src/VisualGraph.ts +236 -0
  132. package/src/VisualGraphContext.ts +138 -0
  133. package/src/VisualGraphExecutor.ts +663 -0
  134. package/src/VisualNode.ts +44 -0
  135. package/src/VisualNodeCatalog.ts +195 -0
  136. package/src/WeaponSystem.ts +793 -0
  137. package/src/index.ts +175 -0
  138. package/tests/scripting.test.ts +229 -0
  139. package/tsconfig.json +7 -0
package/src/index.ts ADDED
@@ -0,0 +1,175 @@
1
+ export type { Behavior, BehaviorPhase } from "./Behavior";
2
+ export {
3
+ BehaviorAction,
4
+ BehaviorCondition,
5
+ BehaviorSelector,
6
+ BehaviorSequence,
7
+ BehaviorTree,
8
+ BehaviorTreeNode,
9
+ Blackboard
10
+ } from "./BehaviorTree";
11
+ export type {
12
+ BehaviorTreeContext,
13
+ BehaviorTreeStatus,
14
+ BehaviorTreeTickResult,
15
+ BlackboardChange,
16
+ BlackboardValue
17
+ } from "./BehaviorTree";
18
+ export { PerceptionSensor } from "./Perception";
19
+ export type {
20
+ PerceptionHit,
21
+ PerceptionMemory,
22
+ PerceptionPoint,
23
+ PerceptionSensorOptions,
24
+ PerceptionSnapshot,
25
+ PerceptionTarget
26
+ } from "./Perception";
27
+ export { UtilityAI, UtilityAction, UtilityConsideration } from "./UtilityAI";
28
+ export type {
29
+ UtilityActionOptions,
30
+ UtilityActionScore,
31
+ UtilityConsiderationOptions,
32
+ UtilityContext,
33
+ UtilityCurve,
34
+ UtilityScoring
35
+ } from "./UtilityAI";
36
+ export { State, StateMachine } from "./StateMachine";
37
+ export type { StateMachineSnapshot, StateTransition, StateTransitionCondition } from "./StateMachine";
38
+ export { GOAPAction, GOAPPlanner, WorldState } from "./GOAP";
39
+ export type { GOAPActionOptions, GOAPPlan, GOAPPlannerOptions, GOAPStateShape, GOAPValue } from "./GOAP";
40
+ export { HTNPlanner, HTNTask } from "./HTN";
41
+ export type { HTNCompoundTaskOptions, HTNPlan, HTNPlannerOptions, HTNPrimitiveTaskOptions, HTNTaskMethod, HTNTaskResult, HTNTaskType } from "./HTN";
42
+ export { DecisionTree } from "./DecisionTree";
43
+ export type { DecisionAction, DecisionCondition, DecisionTreeContext, DecisionTreeDecision, DecisionTreeNode, DecisionTreeNodeType, DecisionTreeStats } from "./DecisionTree";
44
+ export { sampleAdaptiveDifficultyFixture } from "./AdaptiveDifficultyFixtures";
45
+ export type {
46
+ AdaptiveDifficultyAdjustment,
47
+ AdaptiveDifficultyChangeType,
48
+ AdaptiveDifficultyFixture,
49
+ AdaptiveDifficultyFixtureOptions,
50
+ AdaptiveDifficultyMetricSummary,
51
+ AdaptiveDifficultyMetricType,
52
+ AdaptiveDifficultyStrategy,
53
+ AdaptiveDifficultyTriggeredRule
54
+ } from "./AdaptiveDifficultyFixtures";
55
+ export { sampleAnalyticsPrivacyFixture } from "./AnalyticsPrivacyFixtures";
56
+ export type {
57
+ AnalyticsConsentCategory,
58
+ AnalyticsPrivacyFixture,
59
+ AnalyticsPrivacyFixtureOptions,
60
+ AnalyticsProviderMode
61
+ } from "./AnalyticsPrivacyFixtures";
62
+ export { sampleCulturalBehaviorFixture } from "./CulturalBehaviorFixtures";
63
+ export type {
64
+ CulturalBehaviorFixture,
65
+ CulturalBehaviorFixtureOptions,
66
+ CulturalCommunicationStyle,
67
+ CulturalEntityFixture,
68
+ CulturalPersonalSpace,
69
+ CulturalRelationship,
70
+ CultureDescriptor,
71
+ ProxemicZone
72
+ } from "./CulturalBehaviorFixtures";
73
+ export { sampleCloudServiceFixture } from "./CloudServiceFixtures";
74
+ export type { CloudFixtureServiceStatus, CloudServiceFixture, CloudServiceFixtureOptions } from "./CloudServiceFixtures";
75
+ export { sampleLearningAgentFixture } from "./LearningAgentFixtures";
76
+ export type { LearningAgentFixture, LearningAgentFixtureOptions } from "./LearningAgentFixtures";
77
+ export { sampleNetworkReplicationFixture } from "./NetworkReplicationFixtures";
78
+ export type {
79
+ NetworkDeltaSummary,
80
+ NetworkEntityState,
81
+ NetworkInputFrame,
82
+ NetworkInterestSummary,
83
+ NetworkInterpolationSummary,
84
+ NetworkPredictionSummary,
85
+ NetworkReplicationFixture,
86
+ NetworkReplicationFixtureOptions,
87
+ NetworkReplicationMode
88
+ } from "./NetworkReplicationFixtures";
89
+ export { samplePlayerBehaviorTelemetryFixture } from "./PlayerBehaviorTelemetryFixtures";
90
+ export type {
91
+ PlayerBehaviorPatternTelemetry,
92
+ PlayerBehaviorTelemetryFixture,
93
+ PlayerBehaviorTelemetryOptions,
94
+ PlayerEngagementLevel,
95
+ PlayerEventCategory,
96
+ PlayerEventSeverity,
97
+ PlayerPlaystyle,
98
+ PlayerSkillAssessmentTelemetry,
99
+ PlayerSkillLevel
100
+ } from "./PlayerBehaviorTelemetryFixtures";
101
+ export { sampleProceduralContentAdaptationFixture } from "./ProceduralContentAdaptationFixtures";
102
+ export type {
103
+ AdaptiveAiStrategy,
104
+ GeneratedContentDifficulty,
105
+ GeneratedContentTelemetry,
106
+ GeneratedContentType,
107
+ ProceduralContentAdaptationFixture,
108
+ ProceduralContentAdaptationOptions
109
+ } from "./ProceduralContentAdaptationFixtures";
110
+ export { sampleFpsEnemyTactics, sampleFpsHudOverlay, sampleFpsLevelLayout, sampleFpsWeaponCycle, samplePowerUpEffect, sampleSpaceShooterWave, sampleWeaponBurst } from "./WeaponSystem";
111
+ export type {
112
+ FpsEnemyTacticalState,
113
+ FpsEnemyTacticsInput,
114
+ FpsEnemyTacticsSample,
115
+ FpsFiringMode,
116
+ FpsHudOverlayInput,
117
+ FpsHudOverlaySample,
118
+ FpsLevelCorridor,
119
+ FpsLevelLayoutInput,
120
+ FpsLevelLayoutSample,
121
+ FpsLevelPickup,
122
+ FpsLevelPoint,
123
+ FpsLevelRoom,
124
+ FpsPickupType,
125
+ FpsWeaponCycleInput,
126
+ FpsWeaponCycleSample,
127
+ FpsWeaponType,
128
+ PowerUpEffectInput,
129
+ PowerUpEffectSample,
130
+ SpaceShooterEnemyType,
131
+ SpaceShooterFormation,
132
+ SpaceShooterPowerUpType,
133
+ SpaceShooterSpawn,
134
+ SpaceShooterWaveInput,
135
+ SpaceShooterWaveSample,
136
+ WeaponBurst,
137
+ WeaponBurstInput,
138
+ WeaponKind,
139
+ WeaponProjectile
140
+ } from "./WeaponSystem";
141
+ export { BehaviorHost } from "./BehaviorHost";
142
+ export type { BehaviorHostOptions } from "./BehaviorHost";
143
+ export { BehaviorRegistry } from "./BehaviorRegistry";
144
+ export type { BehaviorFactory } from "./BehaviorRegistry";
145
+ export { BehaviorSystem } from "./BehaviorSystem";
146
+ export type { BehaviorError, BehaviorSystemUpdateOptions } from "./BehaviorSystem";
147
+ export { ScriptContext } from "./ScriptContext";
148
+ export type { ScriptContextOptions } from "./ScriptContext";
149
+ export { deserializeGraph, serializeGraph, validateGraph } from "./VisualGraph";
150
+ export type { SerializedVisualGraph, VisualEdge, VisualGraph } from "./VisualGraph";
151
+ export { VisualGraphExecutor } from "./VisualGraphExecutor";
152
+ export type { VisualExecutionResult } from "./VisualGraphExecutor";
153
+ export type {
154
+ VisualAnimationControllerState,
155
+ VisualAnimationEvent,
156
+ VisualCameraState,
157
+ VisualCollisionEvent,
158
+ VisualCombatEvent,
159
+ VisualGraphDiagnostic,
160
+ VisualGraphExecutionContext,
161
+ VisualGraphSideEffect,
162
+ VisualGraphValidationOptions,
163
+ VisualInputSet,
164
+ VisualInputSnapshot,
165
+ VisualOverlapResult,
166
+ VisualPhysicsBodyState,
167
+ VisualRaycastHit,
168
+ VisualRuntimeNodeState,
169
+ VisualStateCollection,
170
+ VisualVector3
171
+ } from "./VisualGraphContext";
172
+ export { createVisualNode, getVisualNodeDefinition, listVisualNodeDefinitions } from "./VisualNodeCatalog";
173
+ export type { VisualNodeCategory, VisualNodeDefinition } from "./VisualNodeCatalog";
174
+ export { validateNode } from "./VisualNode";
175
+ export type { VisualNode, VisualPort, VisualPortDirection, VisualPortType } from "./VisualNode";
@@ -0,0 +1,229 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import {
4
+ BehaviorHost,
5
+ BehaviorSystem,
6
+ createVisualNode,
7
+ listVisualNodeDefinitions,
8
+ validateGraph,
9
+ VisualGraphExecutor,
10
+ type VisualGraphExecutionContext
11
+ } from "../src/index";
12
+
13
+ test("BehaviorSystem runs start before update and fixed phase separately", async () => {
14
+ const calls: string[] = [];
15
+ const host = new BehaviorHost();
16
+ host.attach({
17
+ onStart: () => calls.push("start"),
18
+ onFixedUpdate: () => calls.push("fixed"),
19
+ onUpdate: () => calls.push("update")
20
+ });
21
+
22
+ const system = new BehaviorSystem();
23
+ system.registerHost(host);
24
+ await system.fixedUpdate({ fixedDeltaSeconds: 1 / 60 });
25
+ await system.update({ deltaSeconds: 1 / 30 });
26
+ await system.update({ deltaSeconds: 1 / 30 });
27
+
28
+ assert.deepEqual(calls, ["fixed", "start", "update", "update"]);
29
+ });
30
+
31
+ test("Visual graph validates ports and executes simple constants plus add", () => {
32
+ const graph = {
33
+ nodes: [
34
+ { id: "a", kind: "const", data: { value: 2 }, ports: [{ id: "out", direction: "output", type: "number" }] },
35
+ { id: "b", kind: "const", data: { value: 3 }, ports: [{ id: "out", direction: "output", type: "number" }] },
36
+ { id: "sum", kind: "add", ports: [{ id: "in", direction: "input", type: "number" }] }
37
+ ],
38
+ edges: [
39
+ { fromNode: "a", fromPort: "out", toNode: "sum", toPort: "in" },
40
+ { fromNode: "b", fromPort: "out", toNode: "sum", toPort: "in" }
41
+ ]
42
+ } as const;
43
+
44
+ assert.deepEqual(validateGraph(graph), []);
45
+ assert.equal(new VisualGraphExecutor().execute(graph).values.get("sum"), 5);
46
+ });
47
+
48
+ test("Visual graph executes catalog math and logic nodes", () => {
49
+ const graph = {
50
+ nodes: [
51
+ createVisualNode("const", "a", { value: 12 }),
52
+ createVisualNode("const", "b", { value: 5 }),
53
+ createVisualNode("subtract", "delta"),
54
+ createVisualNode("lessEqual", "bounded", { b: 7 })
55
+ ],
56
+ edges: [
57
+ { fromNode: "a", fromPort: "out", toNode: "delta", toPort: "a" },
58
+ { fromNode: "b", fromPort: "out", toNode: "delta", toPort: "b" },
59
+ { fromNode: "delta", fromPort: "out", toNode: "bounded", toPort: "a" }
60
+ ]
61
+ };
62
+
63
+ const result = new VisualGraphExecutor().execute(graph);
64
+
65
+ assert.equal(result.values.get("delta"), 7);
66
+ assert.equal(result.values.get("bounded"), true);
67
+ });
68
+
69
+ test("Visual graph executes bounded flow-control catalog nodes", () => {
70
+ const graph = {
71
+ nodes: [
72
+ createVisualNode("branch", "branch", { condition: false }),
73
+ createVisualNode("forRange", "loop", { startIndex: 1, endIndex: 4 }),
74
+ createVisualNode("gate", "gate", { startClosed: true })
75
+ ],
76
+ edges: []
77
+ };
78
+
79
+ const result = new VisualGraphExecutor().execute(graph);
80
+
81
+ assert.equal(result.values.get("branch.selected"), "false");
82
+ assert.equal(result.values.get("branch.false"), true);
83
+ assert.deepEqual(result.values.get("loop.indices"), [1, 2, 3]);
84
+ assert.equal(result.values.get("gate.isOpen"), false);
85
+ assert.equal(result.values.get("gate.out"), false);
86
+ assert.ok(result.blockedClaims.includes("Unreal Blueprint parity"));
87
+ });
88
+
89
+ test("Visual node catalog exposes Aura3D 1.0.5 runtime-facing node families", () => {
90
+ const definitions = listVisualNodeDefinitions();
91
+ const byCategory = new Map(definitions.map((definition) => [definition.kind, definition.category]));
92
+
93
+ for (const [kind, category] of Object.entries({
94
+ onFrame: "runtime",
95
+ translate: "runtime",
96
+ pressed: "input",
97
+ combo: "input",
98
+ restartClip: "animation",
99
+ onAnimationEvent: "animation",
100
+ setVelocity: "physics",
101
+ onCollisionEnter: "physics",
102
+ openHitbox: "combat",
103
+ onHit: "combat",
104
+ follow: "camera",
105
+ captureSnapshot: "evidence",
106
+ assertState: "evidence"
107
+ })) {
108
+ assert.equal(byCategory.get(kind), category);
109
+ }
110
+ });
111
+
112
+ test("Visual graph validation catches missing inputs and invalid deterministic context references", () => {
113
+ const context: VisualGraphExecutionContext = {
114
+ runtimeNodes: [{ id: "player" }],
115
+ animationControllers: [{ id: "playerAnim", clips: ["Idle", "LightPunch"], morphTargets: ["AA", "FV"] }],
116
+ physicsBodies: [{ id: "playerBody" }]
117
+ };
118
+
119
+ const missingInputGraph = {
120
+ nodes: [createVisualNode("getNode", "missing-node-id")],
121
+ edges: []
122
+ };
123
+
124
+ assert.ok(validateGraph(missingInputGraph).some((error) => error.includes("Missing required input")));
125
+
126
+ const invalidGraph = {
127
+ nodes: [
128
+ createVisualNode("getNode", "bad-runtime-node", { nodeId: "ghost" }),
129
+ createVisualNode("playClip", "bad-clip", { controllerId: "playerAnim", clip: "Uppercut" }),
130
+ createVisualNode("setMorphTarget", "bad-morph", { controllerId: "playerAnim", morphTarget: "ZZ", weight: 1 }),
131
+ createVisualNode("setVelocity", "bad-body", { bodyId: "ghostBody", velocity: { x: 1, y: 0, z: 0 } })
132
+ ],
133
+ edges: []
134
+ };
135
+
136
+ const errors = validateGraph(invalidGraph, { context, strictReferences: true });
137
+
138
+ assert.ok(errors.some((error) => error.includes("Unknown runtime node id")));
139
+ assert.ok(errors.some((error) => error.includes("Unknown animation clip")));
140
+ assert.ok(errors.some((error) => error.includes("Unknown morph target")));
141
+ assert.ok(errors.some((error) => error.includes("Unknown physics body id")));
142
+
143
+ const cycleGraph = {
144
+ nodes: [createVisualNode("add", "a"), createVisualNode("add", "b")],
145
+ edges: [
146
+ { fromNode: "a", fromPort: "out", toNode: "b", toPort: "in" },
147
+ { fromNode: "b", fromPort: "out", toNode: "a", toPort: "in" }
148
+ ]
149
+ };
150
+
151
+ assert.ok(validateGraph(cycleGraph).some((error) => error.includes("Visual graph cycle detected")));
152
+ });
153
+
154
+ test("Visual graph executes deterministic runtime input animation physics combat camera and evidence hooks", () => {
155
+ const context: VisualGraphExecutionContext = {
156
+ frame: 12,
157
+ time: 0.2,
158
+ dt: 1 / 60,
159
+ runtimeNodes: [{ id: "player", position: { x: 1, y: 0, z: 0 }, visible: true }],
160
+ input: {
161
+ pressed: ["attack"],
162
+ held: { right: true },
163
+ buffered: ["dash"],
164
+ combos: ["light-light"],
165
+ axes: { moveX: 1 }
166
+ },
167
+ animationControllers: [
168
+ {
169
+ id: "playerAnim",
170
+ currentClip: "Idle",
171
+ clipTime: 0.24,
172
+ clips: ["Idle", "LightPunch"],
173
+ morphTargets: ["AA"],
174
+ events: [{ type: "hitbox.open", controllerId: "playerAnim", clip: "LightPunch", time: 0.12, payload: { hitboxId: "player.light" } }]
175
+ }
176
+ ],
177
+ physicsBodies: [{ id: "playerBody", velocity: { x: 0, y: 0, z: 0 }, grounded: true }],
178
+ collisionEvents: [{ type: "enter", bodyId: "playerBody", otherBodyId: "dummyBody" }],
179
+ combatEvents: [{ type: "hit", actorId: "player", targetId: "dummy", hitboxId: "player.light", amount: 8 }],
180
+ camera: { id: "mainCamera", position: { x: 0, y: 2, z: 5 } },
181
+ evidence: { proofId: "visual-scripting-runtime" }
182
+ };
183
+
184
+ const graph = {
185
+ nodes: [
186
+ createVisualNode("onFrame", "frame"),
187
+ createVisualNode("pressed", "attack-pressed", { action: "attack" }),
188
+ createVisualNode("axis", "move-axis", { axis: "moveX" }),
189
+ createVisualNode("translate", "move", { nodeId: "player", delta: { x: 0.25, y: 0, z: 0 } }),
190
+ createVisualNode("restartClip", "attack-clip", { controllerId: "playerAnim", clip: "LightPunch" }),
191
+ createVisualNode("onAnimationEvent", "hitbox-event", { controllerId: "playerAnim", eventType: "hitbox.open", clip: "LightPunch" }),
192
+ createVisualNode("openHitbox", "open-hitbox", { hitboxId: "player.light", ownerId: "player", damage: 8 }),
193
+ createVisualNode("setMorphTarget", "mouth-aa", { controllerId: "playerAnim", morphTarget: "AA", weight: 0.7 }),
194
+ createVisualNode("setVelocity", "velocity", { bodyId: "playerBody", velocity: { x: 3, y: 0, z: 0 } }),
195
+ createVisualNode("onCollisionEnter", "collision", { bodyId: "playerBody", otherBodyId: "dummyBody" }),
196
+ createVisualNode("onHit", "hit", { actorId: "player", hitboxId: "player.light" }),
197
+ createVisualNode("follow", "camera-follow", { targetId: "player", stiffness: 0.85 }),
198
+ createVisualNode("captureSnapshot", "snapshot", { label: "visual-scripting-runtime" }),
199
+ createVisualNode("assertState", "assert-attack", { actual: true, expected: true })
200
+ ],
201
+ edges: []
202
+ };
203
+
204
+ assert.deepEqual(validateGraph(graph, { context }), []);
205
+
206
+ const result = new VisualGraphExecutor(context).execute(graph);
207
+ const second = new VisualGraphExecutor(context).execute(graph);
208
+
209
+ assert.equal(result.values.get("attack-pressed"), true);
210
+ assert.equal(result.values.get("move-axis"), 1);
211
+ assert.equal(result.values.get("hitbox-event.fired"), true);
212
+ assert.equal(result.values.get("collision.collided"), true);
213
+ assert.equal(result.values.get("hit.hit"), true);
214
+ assert.equal(result.values.get("assert-attack.passed"), true);
215
+
216
+ assert.deepEqual((result.values.get("move.command") as { position: unknown }).position, { x: 1.25, y: 0, z: 0 });
217
+ assert.deepEqual(result.sideEffects.map((effect) => effect.kind), [
218
+ "runtime.translate",
219
+ "animation.restartClip",
220
+ "combat.openHitbox",
221
+ "animation.setMorphTarget",
222
+ "physics.setVelocity",
223
+ "camera.follow",
224
+ "evidence.captureSnapshot",
225
+ "evidence.assertState"
226
+ ]);
227
+ assert.deepEqual(result.sideEffects, second.sideEffects);
228
+ assert.deepEqual(result.diagnostics, []);
229
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "noEmit": true
5
+ },
6
+ "include": ["src/**/*.ts"]
7
+ }