@kiberon-labs/behave-graph-scene 1.0.1 → 2.0.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 (214) hide show
  1. package/.storybook/main.ts +18 -0
  2. package/.storybook/preview.ts +16 -0
  3. package/.storybook/vscode.css +822 -0
  4. package/.turbo/turbo-build.log +4 -3
  5. package/CHANGELOG.md +84 -0
  6. package/README.md +1 -1
  7. package/dist/Abstractions/Drivers/DummyScene.d.ts +47 -3
  8. package/dist/Abstractions/Drivers/DummyScene.d.ts.map +1 -1
  9. package/dist/Abstractions/Drivers/DummyScene.js +57 -0
  10. package/dist/Abstractions/Drivers/DummyScene.js.map +1 -1
  11. package/dist/Abstractions/IScene.d.ts +63 -4
  12. package/dist/Abstractions/IScene.d.ts.map +1 -1
  13. package/dist/Abstractions/IScene.js +19 -0
  14. package/dist/Abstractions/IScene.js.map +1 -0
  15. package/dist/Nodes/Actions/AddLight.d.ts +21 -0
  16. package/dist/Nodes/Actions/AddLight.d.ts.map +1 -0
  17. package/dist/Nodes/Actions/AddLight.js +38 -0
  18. package/dist/Nodes/Actions/AddLight.js.map +1 -0
  19. package/dist/Nodes/Actions/CloneMesh.d.ts +16 -0
  20. package/dist/Nodes/Actions/CloneMesh.d.ts.map +1 -0
  21. package/dist/Nodes/Actions/CloneMesh.js +28 -0
  22. package/dist/Nodes/Actions/CloneMesh.js.map +1 -0
  23. package/dist/Nodes/Actions/CreateMesh.d.ts +22 -0
  24. package/dist/Nodes/Actions/CreateMesh.d.ts.map +1 -0
  25. package/dist/Nodes/Actions/CreateMesh.js +44 -0
  26. package/dist/Nodes/Actions/CreateMesh.js.map +1 -0
  27. package/dist/Nodes/Actions/DeleteMesh.d.ts +15 -0
  28. package/dist/Nodes/Actions/DeleteMesh.d.ts.map +1 -0
  29. package/dist/Nodes/Actions/DeleteMesh.js +27 -0
  30. package/dist/Nodes/Actions/DeleteMesh.js.map +1 -0
  31. package/dist/Nodes/Actions/EaseSceneProperty.d.ts +1 -1
  32. package/dist/Nodes/Actions/EaseSceneProperty.d.ts.map +1 -1
  33. package/dist/Nodes/Actions/EaseSceneProperty.js +2 -2
  34. package/dist/Nodes/Actions/EaseSceneProperty.js.map +1 -1
  35. package/dist/Nodes/Actions/LookAt.d.ts +16 -0
  36. package/dist/Nodes/Actions/LookAt.d.ts.map +1 -0
  37. package/dist/Nodes/Actions/LookAt.js +35 -0
  38. package/dist/Nodes/Actions/LookAt.js.map +1 -0
  39. package/dist/Nodes/Actions/MoveTowards.d.ts +21 -0
  40. package/dist/Nodes/Actions/MoveTowards.d.ts.map +1 -0
  41. package/dist/Nodes/Actions/MoveTowards.js +46 -0
  42. package/dist/Nodes/Actions/MoveTowards.js.map +1 -0
  43. package/dist/Nodes/Actions/RemoveLight.d.ts +15 -0
  44. package/dist/Nodes/Actions/RemoveLight.d.ts.map +1 -0
  45. package/dist/Nodes/Actions/RemoveLight.js +27 -0
  46. package/dist/Nodes/Actions/RemoveLight.js.map +1 -0
  47. package/dist/Nodes/Actions/SetLightProperty.d.ts +25 -0
  48. package/dist/Nodes/Actions/SetLightProperty.d.ts.map +1 -0
  49. package/dist/Nodes/Actions/SetLightProperty.js +64 -0
  50. package/dist/Nodes/Actions/SetLightProperty.js.map +1 -0
  51. package/dist/Nodes/Actions/SetMaterialProperty.d.ts +25 -0
  52. package/dist/Nodes/Actions/SetMaterialProperty.d.ts.map +1 -0
  53. package/dist/Nodes/Actions/SetMaterialProperty.js +69 -0
  54. package/dist/Nodes/Actions/SetMaterialProperty.js.map +1 -0
  55. package/dist/Nodes/Actions/SetMeshPosition.d.ts +18 -0
  56. package/dist/Nodes/Actions/SetMeshPosition.d.ts.map +1 -0
  57. package/dist/Nodes/Actions/SetMeshPosition.js +34 -0
  58. package/dist/Nodes/Actions/SetMeshPosition.js.map +1 -0
  59. package/dist/Nodes/Actions/SetMeshVisible.d.ts +16 -0
  60. package/dist/Nodes/Actions/SetMeshVisible.d.ts.map +1 -0
  61. package/dist/Nodes/Actions/SetMeshVisible.js +28 -0
  62. package/dist/Nodes/Actions/SetMeshVisible.js.map +1 -0
  63. package/dist/Nodes/Actions/SetSceneProperty.d.ts +12 -1
  64. package/dist/Nodes/Actions/SetSceneProperty.d.ts.map +1 -1
  65. package/dist/Nodes/Actions/SetSceneProperty.js +1 -1
  66. package/dist/Nodes/Actions/SetSceneProperty.js.map +1 -1
  67. package/dist/Nodes/Events/OnAnyMeshClicked.d.ts +13 -0
  68. package/dist/Nodes/Events/OnAnyMeshClicked.d.ts.map +1 -0
  69. package/dist/Nodes/Events/OnAnyMeshClicked.js +34 -0
  70. package/dist/Nodes/Events/OnAnyMeshClicked.js.map +1 -0
  71. package/dist/Nodes/Events/OnSceneChanged.d.ts +12 -0
  72. package/dist/Nodes/Events/OnSceneChanged.d.ts.map +1 -0
  73. package/dist/Nodes/Events/OnSceneChanged.js +28 -0
  74. package/dist/Nodes/Events/OnSceneChanged.js.map +1 -0
  75. package/dist/Nodes/Events/OnSceneNodeClick.d.ts +14 -1
  76. package/dist/Nodes/Events/OnSceneNodeClick.d.ts.map +1 -1
  77. package/dist/Nodes/Events/OnSceneNodeClick.js +1 -1
  78. package/dist/Nodes/Events/OnSceneNodeClick.js.map +1 -1
  79. package/dist/Nodes/Logic/ColorNodes.d.ts +17 -13
  80. package/dist/Nodes/Logic/ColorNodes.d.ts.map +1 -1
  81. package/dist/Nodes/Logic/EulerNodes.d.ts +16 -12
  82. package/dist/Nodes/Logic/EulerNodes.d.ts.map +1 -1
  83. package/dist/Nodes/Logic/Mat3Nodes.d.ts +26 -23
  84. package/dist/Nodes/Logic/Mat3Nodes.d.ts.map +1 -1
  85. package/dist/Nodes/Logic/Mat3Nodes.js +0 -14
  86. package/dist/Nodes/Logic/Mat3Nodes.js.map +1 -1
  87. package/dist/Nodes/Logic/Mat4Nodes.d.ts +32 -28
  88. package/dist/Nodes/Logic/Mat4Nodes.d.ts.map +1 -1
  89. package/dist/Nodes/Logic/QuatNodes.d.ts +22 -18
  90. package/dist/Nodes/Logic/QuatNodes.d.ts.map +1 -1
  91. package/dist/Nodes/Logic/Vec2Nodes.d.ts +16 -12
  92. package/dist/Nodes/Logic/Vec2Nodes.d.ts.map +1 -1
  93. package/dist/Nodes/Logic/Vec3Nodes.d.ts +17 -13
  94. package/dist/Nodes/Logic/Vec3Nodes.d.ts.map +1 -1
  95. package/dist/Nodes/Logic/Vec4Nodes.d.ts +16 -12
  96. package/dist/Nodes/Logic/Vec4Nodes.d.ts.map +1 -1
  97. package/dist/Nodes/Queries/GetDistanceBetween.d.ts +18 -0
  98. package/dist/Nodes/Queries/GetDistanceBetween.d.ts.map +1 -0
  99. package/dist/Nodes/Queries/GetDistanceBetween.js +30 -0
  100. package/dist/Nodes/Queries/GetDistanceBetween.js.map +1 -0
  101. package/dist/Nodes/Queries/GetLightProperty.d.ts +23 -0
  102. package/dist/Nodes/Queries/GetLightProperty.d.ts.map +1 -0
  103. package/dist/Nodes/Queries/GetLightProperty.js +68 -0
  104. package/dist/Nodes/Queries/GetLightProperty.js.map +1 -0
  105. package/dist/Nodes/Queries/GetMaterialProperty.d.ts +23 -0
  106. package/dist/Nodes/Queries/GetMaterialProperty.d.ts.map +1 -0
  107. package/dist/Nodes/Queries/GetMaterialProperty.js +69 -0
  108. package/dist/Nodes/Queries/GetMaterialProperty.js.map +1 -0
  109. package/dist/Nodes/Queries/GetMeshPosition.d.ts +16 -0
  110. package/dist/Nodes/Queries/GetMeshPosition.d.ts.map +1 -0
  111. package/dist/Nodes/Queries/GetMeshPosition.js +29 -0
  112. package/dist/Nodes/Queries/GetMeshPosition.js.map +1 -0
  113. package/dist/Nodes/Queries/GetSceneProperty.d.ts +10 -1
  114. package/dist/Nodes/Queries/GetSceneProperty.d.ts.map +1 -1
  115. package/dist/Nodes/Queries/GetSceneProperty.js +2 -2
  116. package/dist/Nodes/Queries/GetSceneProperty.js.map +1 -1
  117. package/dist/Values/Internal/Mat3.d.ts +1 -1
  118. package/dist/Values/Internal/Mat3.d.ts.map +1 -1
  119. package/dist/Values/Internal/Mat3.js +1 -3
  120. package/dist/Values/Internal/Mat3.js.map +1 -1
  121. package/dist/Values/Internal/Mat4.d.ts.map +1 -1
  122. package/dist/Values/Internal/Mat4.js +1 -3
  123. package/dist/Values/Internal/Mat4.js.map +1 -1
  124. package/dist/Values/Internal/Vec3.d.ts +1 -1
  125. package/dist/Values/Internal/Vec3.d.ts.map +1 -1
  126. package/dist/Values/Internal/Vec3.js +0 -2
  127. package/dist/Values/Internal/Vec3.js.map +1 -1
  128. package/dist/Values/Internal/Vec4.d.ts.map +1 -1
  129. package/dist/Values/Internal/Vec4.js +0 -1
  130. package/dist/Values/Internal/Vec4.js.map +1 -1
  131. package/dist/_virtual/rolldown_runtime.js +23 -1
  132. package/dist/behave-graph.manifest.json +6082 -0
  133. package/dist/buildScene.d.ts.map +1 -1
  134. package/dist/buildScene.js +24 -3
  135. package/dist/buildScene.js.map +1 -1
  136. package/dist/index.d.ts +29 -3
  137. package/dist/index.d.ts.map +1 -0
  138. package/dist/index.js +22 -4
  139. package/dist/manifest.source.d.ts +7 -0
  140. package/dist/manifest.source.d.ts.map +1 -0
  141. package/dist/manifest.source.js +54 -0
  142. package/dist/manifest.source.js.map +1 -0
  143. package/dist/node_modules/.pnpm/react@19.2.3/node_modules/react/cjs/react-jsx-runtime.development.js +207 -0
  144. package/dist/node_modules/.pnpm/react@19.2.3/node_modules/react/cjs/react-jsx-runtime.development.js.map +1 -0
  145. package/dist/node_modules/.pnpm/react@19.2.3/node_modules/react/cjs/react-jsx-runtime.production.js +40 -0
  146. package/dist/node_modules/.pnpm/react@19.2.3/node_modules/react/cjs/react-jsx-runtime.production.js.map +1 -0
  147. package/dist/node_modules/.pnpm/react@19.2.3/node_modules/react/cjs/react.development.js +766 -0
  148. package/dist/node_modules/.pnpm/react@19.2.3/node_modules/react/cjs/react.development.js.map +1 -0
  149. package/dist/node_modules/.pnpm/react@19.2.3/node_modules/react/cjs/react.production.js +367 -0
  150. package/dist/node_modules/.pnpm/react@19.2.3/node_modules/react/cjs/react.production.js.map +1 -0
  151. package/dist/node_modules/.pnpm/react@19.2.3/node_modules/react/index.js +15 -0
  152. package/dist/node_modules/.pnpm/react@19.2.3/node_modules/react/index.js.map +1 -0
  153. package/dist/node_modules/.pnpm/react@19.2.3/node_modules/react/jsx-runtime.js +15 -0
  154. package/dist/node_modules/.pnpm/react@19.2.3/node_modules/react/jsx-runtime.js.map +1 -0
  155. package/dist/packages/nodes/scene/package.js +7 -0
  156. package/dist/packages/nodes/scene/package.js.map +1 -0
  157. package/dist/registerSceneProfile.d.ts +3 -3
  158. package/dist/registerSceneProfile.d.ts.map +1 -1
  159. package/dist/registerSceneProfile.js +35 -1
  160. package/dist/registerSceneProfile.js.map +1 -1
  161. package/dist/ui/controls/vec3.d.ts +9 -0
  162. package/dist/ui/controls/vec3.d.ts.map +1 -0
  163. package/dist/ui/controls/vec3.js +99 -0
  164. package/dist/ui/controls/vec3.js.map +1 -0
  165. package/package.json +28 -9
  166. package/src/Abstractions/Drivers/DummyScene.ts +110 -2
  167. package/src/Abstractions/IScene.ts +74 -3
  168. package/src/Nodes/Actions/AddLight.ts +46 -0
  169. package/src/Nodes/Actions/CloneMesh.ts +31 -0
  170. package/src/Nodes/Actions/CreateMesh.ts +47 -0
  171. package/src/Nodes/Actions/DeleteMesh.ts +29 -0
  172. package/src/Nodes/Actions/EaseSceneProperty.ts +6 -2
  173. package/src/Nodes/Actions/LookAt.ts +34 -0
  174. package/src/Nodes/Actions/MoveTowards.ts +55 -0
  175. package/src/Nodes/Actions/RemoveLight.ts +29 -0
  176. package/src/Nodes/Actions/SetLightProperty.ts +60 -0
  177. package/src/Nodes/Actions/SetMaterialProperty.ts +62 -0
  178. package/src/Nodes/Actions/SetMeshPosition.ts +37 -0
  179. package/src/Nodes/Actions/SetMeshVisible.ts +31 -0
  180. package/src/Nodes/Actions/SetSceneProperty.ts +3 -5
  181. package/src/Nodes/Events/OnAnyMeshClicked.ts +48 -0
  182. package/src/Nodes/Events/OnSceneChanged.ts +43 -0
  183. package/src/Nodes/Events/OnSceneNodeClick.ts +3 -3
  184. package/src/Nodes/Logic/Mat3Nodes.ts +0 -10
  185. package/src/Nodes/Queries/GetDistanceBetween.ts +37 -0
  186. package/src/Nodes/Queries/GetLightProperty.ts +53 -0
  187. package/src/Nodes/Queries/GetMaterialProperty.ts +55 -0
  188. package/src/Nodes/Queries/GetMeshPosition.ts +32 -0
  189. package/src/Nodes/Queries/GetSceneProperty.ts +4 -5
  190. package/src/Values/Internal/Mat3.ts +3 -3
  191. package/src/Values/Internal/Mat4.ts +5 -4
  192. package/src/Values/Internal/Vec3.ts +5 -4
  193. package/src/Values/Internal/Vec4.ts +3 -2
  194. package/src/buildScene.ts +36 -2
  195. package/src/index.ts +26 -2
  196. package/src/manifest.source.ts +61 -0
  197. package/src/registerSceneProfile.ts +41 -4
  198. package/src/ui/controls/vec3.tsx +69 -0
  199. package/stories/click.stories.tsx +112 -0
  200. package/stories/components/DemoScene.ts +610 -0
  201. package/stories/components/SceneViewer.tsx +204 -0
  202. package/stories/components/SceneViewerPanel.tsx +41 -0
  203. package/stories/data/clickDemo.json +94 -0
  204. package/stories/data/rotate.json +402 -0
  205. package/stories/index.stories.tsx +90 -0
  206. package/stories/plugin/sceneViewerPlugin.tsx +88 -0
  207. package/tests/manifest.test.ts +65 -0
  208. package/tests/readSceneGraphs.test.ts +8 -1
  209. package/tests/registerSceneProfile.test.ts +6 -5
  210. package/tsconfig.json +18 -11
  211. package/tsdown.config.ts +5 -1
  212. package/vite.config.js +7 -0
  213. package/src/Values/Internal/Mat2.ts +0 -214
  214. package/src/loadScene.ts +0 -81
@@ -0,0 +1,55 @@
1
+ import {
2
+ makeFunctionNodeDefinition,
3
+ NodeCategory
4
+ } from '@kiberon-labs/behave-graph';
5
+
6
+ const materialPropertyChoices = [
7
+ { text: 'color', value: 'color' },
8
+ { text: 'opacity', value: 'opacity' },
9
+ { text: 'visible', value: 'visible' },
10
+ { text: 'wireframe', value: 'wireframe' }
11
+ ];
12
+
13
+ export const GetMaterialProperty = makeFunctionNodeDefinition({
14
+ typeName: 'scene/getMaterialProperty',
15
+ category: NodeCategory.Query,
16
+ label: 'Get Material Property',
17
+ in: {
18
+ meshName: (_, graphApi) => {
19
+ const scene = graphApi.getDependency('IScene');
20
+ return {
21
+ valueType: 'string',
22
+ choices: scene?.getMeshNames()
23
+ };
24
+ },
25
+ property: (_) => ({
26
+ valueType: 'string',
27
+ choices: materialPropertyChoices
28
+ })
29
+ },
30
+ out: {
31
+ floatValue: 'float',
32
+ booleanValue: 'boolean',
33
+ colorValue: 'color'
34
+ },
35
+ exec: ({ graph, read, write }) => {
36
+ const scene = graph.getDependency('IScene');
37
+ const meshName = read<string>('meshName');
38
+ const property = read<string>('property');
39
+
40
+ const value = scene?.getMaterialProperty(meshName, property);
41
+
42
+ switch (property) {
43
+ case 'color':
44
+ write('colorValue', value ?? { r: 0, g: 0, b: 0 });
45
+ break;
46
+ case 'opacity':
47
+ write('floatValue', (value as number) ?? 1);
48
+ break;
49
+ case 'visible':
50
+ case 'wireframe':
51
+ write('booleanValue', (value as boolean) ?? false);
52
+ break;
53
+ }
54
+ }
55
+ });
@@ -0,0 +1,32 @@
1
+ import {
2
+ makeFunctionNodeDefinition,
3
+ NodeCategory
4
+ } from '@kiberon-labs/behave-graph';
5
+
6
+ // Get the world-space position of a mesh.
7
+ export const GetMeshPosition = makeFunctionNodeDefinition({
8
+ typeName: 'scene/getMeshPosition',
9
+ category: NodeCategory.Query,
10
+ label: 'Get Mesh Position',
11
+ in: {
12
+ meshName: (_, graphApi) => {
13
+ const scene = graphApi.getDependency('IScene');
14
+ return {
15
+ valueType: 'string',
16
+ choices: scene?.getMeshNames()
17
+ };
18
+ }
19
+ },
20
+ out: {
21
+ x: 'float',
22
+ y: 'float',
23
+ z: 'float'
24
+ },
25
+ exec: ({ graph, read, write }) => {
26
+ const scene = graph.getDependency('IScene');
27
+ const pos = scene?.getMeshPosition(read<string>('meshName'));
28
+ write('x', pos?.x ?? 0);
29
+ write('y', pos?.y ?? 0);
30
+ write('z', pos?.z ?? 0);
31
+ }
32
+ });
@@ -2,21 +2,20 @@ import {
2
2
  makeFunctionNodeDefinition,
3
3
  NodeCategory
4
4
  } from '@kiberon-labs/behave-graph';
5
- import type { IScene } from '../../Abstractions/IScene.js';
6
5
 
7
6
  export const GetSceneProperty = (valueTypeNames: string[]) =>
8
7
  valueTypeNames.map((valueTypeName) =>
9
8
  makeFunctionNodeDefinition({
10
9
  typeName: `scene/get/${valueTypeName}`,
11
10
  category: NodeCategory.Query,
12
- label: `Scene set ${valueTypeName}`,
11
+ label: `Scene get ${valueTypeName}`,
13
12
  in: {
14
13
  jsonPath: (_, graphApi) => {
15
- const scene = graphApi.getDependency<IScene>('IScene');
14
+ const scene = graphApi.getDependency('IScene');
16
15
 
17
16
  return {
18
17
  valueType: 'string',
19
- choices: scene?.getProperties()
18
+ choices: scene?.getProperties(valueTypeName)
20
19
  };
21
20
  }
22
21
  },
@@ -24,7 +23,7 @@ export const GetSceneProperty = (valueTypeNames: string[]) =>
24
23
  value: valueTypeName
25
24
  },
26
25
  exec: ({ graph, read, write }) => {
27
- const scene = graph.getDependency<IScene>('IScene');
26
+ const scene = graph.getDependency('IScene');
28
27
  const propertyValue = scene?.getProperty(
29
28
  read('jsonPath'),
30
29
  valueTypeName
@@ -5,10 +5,10 @@ import {
5
5
  toSafeString
6
6
  } from '@kiberon-labs/behave-graph';
7
7
 
8
- import { Mat4 } from './Mat4.js';
8
+ import type { Mat4 } from './Mat4.js';
9
9
  import { Vec2 } from './Vec2.js';
10
10
  import { Vec3 } from './Vec3.js';
11
- import { Vec4 } from './Vec4.js';
11
+ import type { Vec4 } from './Vec4.js';
12
12
 
13
13
  // uses OpenGL matrix layout where each column is specified subsequently in order from left to right.
14
14
  // ( x, y, 1 ) x [ 0 3 6 ] = ( x', y', 1 )
@@ -80,7 +80,7 @@ export function mat3SetRow3(
80
80
  result = new Mat3()
81
81
  ): Mat3 {
82
82
  const re = result.set(m.elements).elements;
83
- re[rowIndex + NUM_COLUMNS * 0] = row.x;
83
+ re[rowIndex] = row.x;
84
84
  re[rowIndex + NUM_COLUMNS * 1] = row.y;
85
85
  re[rowIndex + NUM_COLUMNS * 2] = row.z;
86
86
  return result;
@@ -5,8 +5,9 @@ import {
5
5
  toSafeString
6
6
  } from '@kiberon-labs/behave-graph';
7
7
 
8
- import { eulerToMat3, Mat3, quatToMat3 } from './Mat3.js';
9
- import { Vec2 } from './Vec2.js';
8
+ import type { Mat3 } from './Mat3.js';
9
+ import { eulerToMat3, quatToMat3 } from './Mat3.js';
10
+ import type { Vec2 } from './Vec2.js';
10
11
  import {
11
12
  Vec3,
12
13
  vec3Cross,
@@ -15,7 +16,7 @@ import {
15
16
  vec3Normalize,
16
17
  vec3Subtract
17
18
  } from './Vec3.js';
18
- import { Vec4 } from './Vec4.js';
19
+ import type { Vec4 } from './Vec4.js';
19
20
 
20
21
  // uses OpenGL matrix layout where each column is specified subsequently in order from left to right.
21
22
  // ( x, y, z, 1 ) x [ 0 4 8 12] = ( x', y', z', 1 )
@@ -99,7 +100,7 @@ export function mat4SetRow4(
99
100
  ): Mat4 {
100
101
  const re = result.set(m.elements).elements;
101
102
  const base = Number(rowIndex);
102
- re[base + NUM_COLUMNS * 0] = row.x;
103
+ re[base] = row.x;
103
104
  re[base + NUM_COLUMNS * 1] = row.y;
104
105
  re[base + NUM_COLUMNS * 2] = row.z;
105
106
  re[base + NUM_COLUMNS * 3] = row.w;
@@ -6,11 +6,12 @@ import {
6
6
  toSafeString
7
7
  } from '@kiberon-labs/behave-graph';
8
8
 
9
- import { Mat3, mat4ToMat3, quatToMat3 } from './Mat3.js';
10
- import { Mat4 } from './Mat4.js';
11
- import { Vec4 } from './Vec4.js';
9
+ import type { Mat3 } from './Mat3.js';
10
+ import { mat4ToMat3, quatToMat3 } from './Mat3.js';
11
+ import type { Mat4 } from './Mat4.js';
12
+ import type { Vec4 } from './Vec4.js';
12
13
 
13
- export type Vec3JSON = number[];
14
+ export type Vec3JSON = [number, number, number];
14
15
 
15
16
  export class Vec3 {
16
17
  public x: number;
@@ -5,8 +5,9 @@ import {
5
5
  toSafeString
6
6
  } from '@kiberon-labs/behave-graph';
7
7
 
8
- import { Mat3, mat4ToMat3 } from './Mat3.js';
9
- import { Mat4 } from './Mat4.js';
8
+ import type { Mat3 } from './Mat3.js';
9
+ import { mat4ToMat3 } from './Mat3.js';
10
+ import type { Mat4 } from './Mat4.js';
10
11
  import { Vec3 } from './Vec3.js';
11
12
 
12
13
  export type Vec4JSON = number[];
package/src/buildScene.ts CHANGED
@@ -172,7 +172,6 @@ function applyNodeModifier(property: string, objectRef: Object3D, value: any) {
172
172
  }
173
173
  case 'scale': {
174
174
  const v = value as Vec3;
175
- console.log(v.x);
176
175
  objectRef.scale.set(v.x, v.y, v.z);
177
176
  break;
178
177
  }
@@ -464,6 +463,18 @@ export const buildScene = ({
464
463
  onSceneChanged.removeListener(listener);
465
464
  };
466
465
 
466
+ // This scene is backed by a loaded glTF model and exposes it through the
467
+ // json-path property API (getProperty/setProperty/...). The procedural
468
+ // mesh/light/material API (added to IScene for scene backends like the demo
469
+ // scene) is not supported here, so those operations fail loudly rather than
470
+ // silently doing the wrong thing. Name-enumeration getters return empty so
471
+ // generic choice UIs degrade gracefully instead of throwing.
472
+ const notSupported = (op: string): never => {
473
+ throw new Error(
474
+ `The glTF-backed scene does not support "${op}". Use a scene backend that implements the procedural mesh/light API (e.g. the demo scene) for that operation.`
475
+ );
476
+ };
477
+
467
478
  const scene: IScene = {
468
479
  getProperty,
469
480
  setProperty,
@@ -472,7 +483,30 @@ export const buildScene = ({
472
483
  addOnClickedListener,
473
484
  removeOnClickedListener,
474
485
  addOnSceneChangedListener,
475
- removeOnSceneChangedListener
486
+ removeOnSceneChangedListener,
487
+
488
+ // --- procedural mesh/light/material API: unsupported on a glTF scene ---
489
+ createMesh: () => notSupported('createMesh'),
490
+ deleteMesh: () => notSupported('deleteMesh'),
491
+ getMeshNames: () => [],
492
+ addLight: () => notSupported('addLight'),
493
+ removeLight: () => notSupported('removeLight'),
494
+ setLightProperty: () => notSupported('setLightProperty'),
495
+ getLightProperty: () => notSupported('getLightProperty'),
496
+ getLightNames: () => [],
497
+ setMaterialProperty: () => notSupported('setMaterialProperty'),
498
+ getMaterialProperty: () => notSupported('getMaterialProperty'),
499
+ addOnAnyMeshClickedListener: () =>
500
+ notSupported('addOnAnyMeshClickedListener'),
501
+ removeOnAnyMeshClickedListener: () =>
502
+ notSupported('removeOnAnyMeshClickedListener'),
503
+ getMeshPosition: () => notSupported('getMeshPosition'),
504
+ setMeshPosition: () => notSupported('setMeshPosition'),
505
+ getDistanceBetween: () => notSupported('getDistanceBetween'),
506
+ lookAt: () => notSupported('lookAt'),
507
+ moveTowards: () => notSupported('moveTowards'),
508
+ cloneMesh: () => notSupported('cloneMesh'),
509
+ setMeshVisible: () => notSupported('setMeshVisible')
476
510
  };
477
511
 
478
512
  return scene;
package/src/index.ts CHANGED
@@ -1,4 +1,11 @@
1
- // scene profile
1
+ import type { IScene } from './Abstractions/IScene.js';
2
+
3
+ declare module '@kiberon-labs/behave-graph' {
4
+ interface Dependencies {
5
+ IScene: IScene;
6
+ }
7
+ }
8
+
2
9
  export * from './Abstractions/IScene.js';
3
10
  export * from './Abstractions/Drivers/DummyScene.js';
4
11
 
@@ -17,9 +24,22 @@ export * from './Values/Vec3Value.js';
17
24
  export * from './Values/Vec4Value.js';
18
25
  export * from './Values/QuatValue.js';
19
26
 
20
- export * from './Nodes/Actions/SetSceneProperty.js';
27
+ export * from './Nodes/Actions/AddLight.js';
28
+ export * from './Nodes/Actions/CloneMesh.js';
29
+ export * from './Nodes/Actions/CreateMesh.js';
30
+ export * from './Nodes/Actions/DeleteMesh.js';
21
31
  export * from './Nodes/Actions/EaseSceneProperty.js';
32
+ export * from './Nodes/Actions/LookAt.js';
33
+ export * from './Nodes/Actions/MoveTowards.js';
34
+ export * from './Nodes/Actions/RemoveLight.js';
35
+ export * from './Nodes/Actions/SetLightProperty.js';
36
+ export * from './Nodes/Actions/SetMaterialProperty.js';
37
+ export * from './Nodes/Actions/SetMeshPosition.js';
38
+ export * from './Nodes/Actions/SetMeshVisible.js';
39
+ export * from './Nodes/Actions/SetSceneProperty.js';
22
40
 
41
+ export * from './Nodes/Events/OnAnyMeshClicked.js';
42
+ export * from './Nodes/Events/OnSceneChanged.js';
23
43
  export * from './Nodes/Events/OnSceneNodeClick.js';
24
44
 
25
45
  export * as ColorNodes from './Nodes/Logic/ColorNodes.js';
@@ -32,6 +52,10 @@ export * as Vec4Nodes from './Nodes/Logic/Vec4Nodes.js';
32
52
  export * as QuatNodes from './Nodes/Logic/QuatNodes.js';
33
53
  export * from './Nodes/Logic/VecElements.js';
34
54
 
55
+ export * from './Nodes/Queries/GetDistanceBetween.js';
56
+ export * from './Nodes/Queries/GetLightProperty.js';
57
+ export * from './Nodes/Queries/GetMaterialProperty.js';
58
+ export * from './Nodes/Queries/GetMeshPosition.js';
35
59
  export * from './Nodes/Queries/GetSceneProperty.js';
36
60
 
37
61
  export * from './registerSceneProfile.js';
@@ -0,0 +1,61 @@
1
+ import {
2
+ ContributionKind,
3
+ PackageCategory,
4
+ defineManifestSource,
5
+ type ContributionSpec,
6
+ type Dependencies
7
+ } from '@kiberon-labs/behave-graph';
8
+ import { getSceneNodesMap, getSceneValuesMap } from './registerSceneProfile.js';
9
+ import { DummyScene } from './Abstractions/Drivers/DummyScene.js';
10
+ import pkg from '../package.json' with { type: 'json' };
11
+
12
+ /**
13
+ * Build-time manifest source for the scene package.
14
+ *
15
+ * The registry projects scene's own nodes + value types into static specs
16
+ * (instantiation only — nodes are never run, no IScene driver needed). The
17
+ * executable profile (`registerSceneProfile`) lives behind the `runtime` entry,
18
+ * loaded only by a runner. Contributions point into the built `dist`: the vec3
19
+ * input control, plus each scene value type so a trusted host can swap the
20
+ * editor's pass-through implementations for the real serializers.
21
+ */
22
+
23
+ // (file, export, valueType name) for each scene value type.
24
+ const valueTypeContributions: ContributionSpec[] = [
25
+ ['Vec2Value', 'vec2'],
26
+ ['Vec3Value', 'vec3'],
27
+ ['Vec4Value', 'vec4'],
28
+ ['ColorValue', 'color'],
29
+ ['EulerValue', 'euler'],
30
+ ['QuatValue', 'quat'],
31
+ ['Mat3Value', 'mat3'],
32
+ ['Mat4Value', 'mat4']
33
+ ].map(([exportName, valueType]) => ({
34
+ id: `${valueType}-value`,
35
+ kind: ContributionKind.ValueType,
36
+ export: `./Values/${exportName}.js#${exportName}`,
37
+ bind: { valueType }
38
+ }));
39
+
40
+ export default defineManifestSource({
41
+ package: { name: pkg.name, version: pkg.version },
42
+ registry: () => ({
43
+ nodes: getSceneNodesMap(),
44
+ values: getSceneValuesMap(),
45
+ // The DummyScene driver satisfies IScene-dependent nodes during spec
46
+ // generation (it never runs them); the real driver is host-provided at run
47
+ // time. Without it, scene-property nodes log "IScene not registered".
48
+ dependencies: { IScene: new DummyScene() } as unknown as Dependencies
49
+ }),
50
+ runtime: './index.js',
51
+ categories: [PackageCategory.Effect],
52
+ contributions: [
53
+ {
54
+ id: 'vec3-control',
55
+ kind: ContributionKind.Control,
56
+ export: './ui/controls/vec3.js#Vec3Control',
57
+ bind: { controlName: 'vec3' }
58
+ },
59
+ ...valueTypeContributions
60
+ ]
61
+ });
@@ -11,7 +11,20 @@ import type {
11
11
  ValueTypeMap
12
12
  } from '@kiberon-labs/behave-graph';
13
13
 
14
+ import { AddLight } from './Nodes/Actions/AddLight.js';
15
+ import { CloneMesh } from './Nodes/Actions/CloneMesh.js';
16
+ import { CreateMesh } from './Nodes/Actions/CreateMesh.js';
17
+ import { DeleteMesh } from './Nodes/Actions/DeleteMesh.js';
18
+ import { LookAt } from './Nodes/Actions/LookAt.js';
19
+ import { MoveTowards } from './Nodes/Actions/MoveTowards.js';
20
+ import { RemoveLight } from './Nodes/Actions/RemoveLight.js';
21
+ import { SetLightProperty } from './Nodes/Actions/SetLightProperty.js';
22
+ import { SetMaterialProperty } from './Nodes/Actions/SetMaterialProperty.js';
23
+ import { SetMeshPosition } from './Nodes/Actions/SetMeshPosition.js';
24
+ import { SetMeshVisible } from './Nodes/Actions/SetMeshVisible.js';
14
25
  import { SetSceneProperty } from './Nodes/Actions/SetSceneProperty.js';
26
+ import { OnAnyMeshClicked } from './Nodes/Events/OnAnyMeshClicked.js';
27
+ import { OnSceneChanged } from './Nodes/Events/OnSceneChanged.js';
15
28
  import { OnSceneNodeClick } from './Nodes/Events/OnSceneNodeClick.js';
16
29
  import * as ColorNodes from './Nodes/Logic/ColorNodes.js';
17
30
  import * as EulerNodes from './Nodes/Logic/EulerNodes.js';
@@ -21,6 +34,10 @@ import * as QuatNodes from './Nodes/Logic/QuatNodes.js';
21
34
  import * as Vec2Nodes from './Nodes/Logic/Vec2Nodes.js';
22
35
  import * as Vec3Nodes from './Nodes/Logic/Vec3Nodes.js';
23
36
  import * as Vec4Nodes from './Nodes/Logic/Vec4Nodes.js';
37
+ import { GetDistanceBetween } from './Nodes/Queries/GetDistanceBetween.js';
38
+ import { GetLightProperty } from './Nodes/Queries/GetLightProperty.js';
39
+ import { GetMaterialProperty } from './Nodes/Queries/GetMaterialProperty.js';
40
+ import { GetMeshPosition } from './Nodes/Queries/GetMeshPosition.js';
24
41
  import { GetSceneProperty } from './Nodes/Queries/GetSceneProperty.js';
25
42
  import { ColorValue } from './Values/ColorValue.js';
26
43
  import { EulerValue } from './Values/EulerValue.js';
@@ -74,9 +91,31 @@ export const getSceneNodesMap = memo<Record<string, NodeDefinition>>(() => {
74
91
 
75
92
  // events
76
93
  OnSceneNodeClick,
77
- // actions
94
+ OnSceneChanged,
95
+ OnAnyMeshClicked,
96
+ // actions - property
78
97
  ...SetSceneProperty(allValueTypeNames),
98
+ // actions - mesh lifecycle
99
+ CreateMesh,
100
+ DeleteMesh,
101
+ CloneMesh,
102
+ // actions - spatial
103
+ MoveTowards,
104
+ LookAt,
105
+ SetMeshPosition,
106
+ SetMeshVisible,
107
+ // actions - lighting
108
+ AddLight,
109
+ RemoveLight,
110
+ SetLightProperty,
111
+ // actions - material
112
+ SetMaterialProperty,
113
+ // queries
79
114
  ...GetSceneProperty(allValueTypeNames),
115
+ GetLightProperty,
116
+ GetMaterialProperty,
117
+ GetMeshPosition,
118
+ GetDistanceBetween,
80
119
 
81
120
  ...getSceneStringConversions(getSceneValuesMap())
82
121
  ];
@@ -98,8 +137,6 @@ export const registerSceneProfile = (registry: IRegistry): IRegistry => {
98
137
  return {
99
138
  values,
100
139
  nodes: { ...registry.nodes, ...getSceneNodesMap() },
101
- dependencies: {
102
- ...registry.dependencies
103
- }
140
+ dependencies: registry.dependencies
104
141
  };
105
142
  };
@@ -0,0 +1,69 @@
1
+ import React from 'react';
2
+
3
+ import { VscodeTextfield } from '@vscode-elements/react-elements';
4
+ import type { ControlProps } from '@kiberon-labs/behave-graph-flow';
5
+ import type { Vec3JSON } from '@/Values/Internal/Vec3';
6
+
7
+ // The @vscode-elements/react-elements typings surface the underlying custom
8
+ // element's DOM events, so its `onChange` hands back a plain `Event`. Pull the
9
+ // value out via the input target (same hack the flow number control uses).
10
+ const readNumber = (e: Event): number | undefined => {
11
+ const stringValue = (e as unknown as React.ChangeEvent<HTMLInputElement>)
12
+ .currentTarget.value;
13
+ const num = parseFloat(stringValue);
14
+ return isNaN(num) ? undefined : num;
15
+ };
16
+
17
+ export const Vec3Control: React.FC<ControlProps<Vec3JSON>> = ({
18
+ value,
19
+ onChange
20
+ }) => {
21
+ const vec = value ?? [0, 0, 0];
22
+
23
+ const handleChangeX = (e: Event) => {
24
+ const num = readNumber(e);
25
+ if (num !== undefined) onChange([num, vec[1], vec[2]]);
26
+ };
27
+
28
+ const handleChangeY = (e: Event) => {
29
+ const num = readNumber(e);
30
+ if (num !== undefined) onChange([vec[0], num, vec[2]]);
31
+ };
32
+
33
+ const handleChangeZ = (e: Event) => {
34
+ const num = readNumber(e);
35
+ if (num !== undefined) onChange([vec[0], vec[1], num]);
36
+ };
37
+
38
+ return (
39
+ <div style={{ display: 'flex', gap: '4px', alignItems: 'center' }}>
40
+ <label style={{ fontSize: '11px', opacity: 0.7, minWidth: '12px' }}>
41
+ X
42
+ </label>
43
+ <VscodeTextfield
44
+ type="number"
45
+ value={vec[0].toString()}
46
+ onChange={handleChangeX}
47
+ style={{ flex: 1 }}
48
+ />
49
+ <label style={{ fontSize: '11px', opacity: 0.7, minWidth: '12px' }}>
50
+ Y
51
+ </label>
52
+ <VscodeTextfield
53
+ type="number"
54
+ value={vec[1].toString()}
55
+ onChange={handleChangeY}
56
+ style={{ flex: 1 }}
57
+ />
58
+ <label style={{ fontSize: '11px', opacity: 0.7, minWidth: '12px' }}>
59
+ Z
60
+ </label>
61
+ <VscodeTextfield
62
+ type="number"
63
+ value={vec[2].toString()}
64
+ onChange={handleChangeZ}
65
+ style={{ flex: 1 }}
66
+ />
67
+ </div>
68
+ );
69
+ };
@@ -0,0 +1,112 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import {
3
+ kitchenSinkPlugin,
4
+ GraphProvider,
5
+ LayoutController,
6
+ localGraphRunnerPlugin,
7
+ System,
8
+ SystemProvider,
9
+ type UIGraphJSON
10
+ } from '@kiberon-labs/behave-graph-flow';
11
+ import {
12
+ DefaultLogger,
13
+ ManualLifecycleEventEmitter,
14
+ registerCoreProfile
15
+ } from '@kiberon-labs/behave-graph';
16
+ import { registerSceneProfile } from '@/registerSceneProfile';
17
+ import { DemoScene } from './components/DemoScene';
18
+ import { sceneViewerPlugin } from './plugin/sceneViewerPlugin';
19
+ import { Vec3Control } from '@/ui/controls/vec3';
20
+ import clickDemoGraph from './data/clickDemo.json';
21
+
22
+ const meta: Meta<typeof LayoutController> = {
23
+ component: LayoutController,
24
+ title: 'Apex/default',
25
+ decorators: [(Story) => <Story />],
26
+ parameters: {
27
+ layout: 'fullscreen'
28
+ }
29
+ };
30
+
31
+ export default meta;
32
+
33
+ type Story = StoryObj<typeof meta>;
34
+
35
+ // Create a demo scene instance
36
+ const demoScene = new DemoScene();
37
+
38
+ // Create the old-style registry for node definitions
39
+ const coreRegistry = registerSceneProfile(
40
+ registerCoreProfile({
41
+ nodes: {},
42
+ values: {},
43
+ dependencies: {
44
+ IScene: demoScene,
45
+ ILifecycleEventEmitter: new ManualLifecycleEventEmitter(),
46
+ ILogger: new DefaultLogger()
47
+ }
48
+ })
49
+ );
50
+
51
+ // --- Click Demo story: preloads a graph with OnAnyMeshClicked → DebugLog ---
52
+
53
+ const clickDemoScene = new DemoScene();
54
+
55
+ const clickRegistry = registerSceneProfile(
56
+ registerCoreProfile({
57
+ nodes: {},
58
+ values: {},
59
+ dependencies: {
60
+ IScene: clickDemoScene,
61
+ ILifecycleEventEmitter: new ManualLifecycleEventEmitter(),
62
+ ILogger: new DefaultLogger()
63
+ }
64
+ })
65
+ );
66
+
67
+ const clickNodeRegistry = {
68
+ values: clickRegistry.values,
69
+ specs: []
70
+ };
71
+
72
+ const clickSys = new System(clickNodeRegistry);
73
+ const clickSession = clickSys.createSession('graph');
74
+
75
+ clickSys.controlStore.getState().registerControl('color', Vec3Control);
76
+ clickSys.controlStore.getState().registerControl('vec3', Vec3Control);
77
+ clickSys.controlStore.getState().registerControl('euler', Vec3Control);
78
+
79
+ clickSys.registerPlugin(kitchenSinkPlugin);
80
+ clickSys.registerPlugin(localGraphRunnerPlugin, {
81
+ registry: clickRegistry,
82
+ tickStrategy: async () => {
83
+ await new Promise((resolve) => requestAnimationFrame(resolve));
84
+ }
85
+ });
86
+ clickSys.registerPlugin(sceneViewerPlugin, {
87
+ scene: clickDemoScene,
88
+ addMenuItem: true
89
+ });
90
+
91
+ // Preload the click demo graph so the OnAnyMeshClicked event node is present.
92
+ // clickDemo.json is a full UIGraphJSON (UI state + inner flow), so deserialize
93
+ // the UI state and load the inner behave graph , the same path the menubar's
94
+ // "Load Graph" uses , rather than passing it straight to setGraph.
95
+ const clickDemoUiGraph = clickDemoGraph as unknown as UIGraphJSON;
96
+ clickSession.graph.deseralize(clickDemoUiGraph);
97
+ clickSession.flowStore
98
+ .getState()
99
+ .setGraph(clickDemoUiGraph.flow, { skipLayout: true });
100
+
101
+ export const ClickDemo: Story = {
102
+ render: () => {
103
+ return (
104
+ <SystemProvider value={clickSys}>
105
+ <GraphProvider value={clickSession}>
106
+ <LayoutController />
107
+ </GraphProvider>
108
+ </SystemProvider>
109
+ );
110
+ },
111
+ args: {}
112
+ };