@kiberon-labs/behave-graph-scene 1.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 (50) hide show
  1. package/package.json +34 -0
  2. package/src/Abstractions/Drivers/DummyScene.ts +79 -0
  3. package/src/Abstractions/IScene.ts +18 -0
  4. package/src/GLTFJson.ts +34 -0
  5. package/src/Nodes/Actions/EaseSceneProperty.ts +162 -0
  6. package/src/Nodes/Actions/SetSceneProperty.ts +35 -0
  7. package/src/Nodes/Events/OnSceneNodeClick.ts +66 -0
  8. package/src/Nodes/Logic/ColorNodes.ts +121 -0
  9. package/src/Nodes/Logic/EulerNodes.ts +115 -0
  10. package/src/Nodes/Logic/Mat3Nodes.ts +202 -0
  11. package/src/Nodes/Logic/Mat4Nodes.ts +257 -0
  12. package/src/Nodes/Logic/QuatNodes.ts +178 -0
  13. package/src/Nodes/Logic/Vec2Nodes.ts +111 -0
  14. package/src/Nodes/Logic/Vec3Nodes.ts +121 -0
  15. package/src/Nodes/Logic/Vec4Nodes.ts +112 -0
  16. package/src/Nodes/Logic/VecElements.ts +34 -0
  17. package/src/Nodes/Queries/GetSceneProperty.ts +35 -0
  18. package/src/Values/ColorValue.ts +22 -0
  19. package/src/Values/EulerValue.ts +22 -0
  20. package/src/Values/Internal/Mat2.ts +214 -0
  21. package/src/Values/Internal/Mat3.ts +422 -0
  22. package/src/Values/Internal/Mat4.ts +831 -0
  23. package/src/Values/Internal/Vec2.ts +97 -0
  24. package/src/Values/Internal/Vec3.ts +244 -0
  25. package/src/Values/Internal/Vec4.ts +350 -0
  26. package/src/Values/Mat3Value.ts +20 -0
  27. package/src/Values/Mat4Value.ts +20 -0
  28. package/src/Values/QuatValue.ts +22 -0
  29. package/src/Values/Vec2Value.ts +14 -0
  30. package/src/Values/Vec3Value.ts +22 -0
  31. package/src/Values/Vec4Value.ts +21 -0
  32. package/src/buildScene.ts +479 -0
  33. package/src/index.ts +38 -0
  34. package/src/loadScene.ts +81 -0
  35. package/src/registerSceneProfile.ts +105 -0
  36. package/tests/graphs/logic/Color.json +53 -0
  37. package/tests/graphs/logic/Euler.json +53 -0
  38. package/tests/graphs/logic/Quaternion.json +56 -0
  39. package/tests/graphs/logic/Vector2.json +50 -0
  40. package/tests/graphs/logic/Vector3.json +53 -0
  41. package/tests/graphs/logic/Vector4.json +56 -0
  42. package/tests/readSceneGraphs.test.ts +57 -0
  43. package/tests/registerSceneProfile.test.ts +62 -0
  44. package/tests/tsconfig.json +11 -0
  45. package/tests/values/internal/Vec2.test.ts +74 -0
  46. package/tests/values/internal/Vec3.test.ts +83 -0
  47. package/tests/values/internal/Vec4.test.ts +91 -0
  48. package/tsconfig.json +55 -0
  49. package/tsdown.config.ts +13 -0
  50. package/vitest.config.ts +15 -0
@@ -0,0 +1,105 @@
1
+ import {
2
+ getCoreValuesMap,
3
+ getNodeDescriptions,
4
+ getStringConversionsForValueType,
5
+ memo
6
+ } from '@kiberon-labs/behave-graph';
7
+ import type {
8
+ IRegistry,
9
+ NodeDefinition,
10
+ ValueType,
11
+ ValueTypeMap
12
+ } from '@kiberon-labs/behave-graph';
13
+
14
+ import { SetSceneProperty } from './Nodes/Actions/SetSceneProperty.js';
15
+ import { OnSceneNodeClick } from './Nodes/Events/OnSceneNodeClick.js';
16
+ import * as ColorNodes from './Nodes/Logic/ColorNodes.js';
17
+ import * as EulerNodes from './Nodes/Logic/EulerNodes.js';
18
+ import * as Mat3Nodes from './Nodes/Logic/Mat3Nodes.js';
19
+ import * as Mat4Nodes from './Nodes/Logic/Mat4Nodes.js';
20
+ import * as QuatNodes from './Nodes/Logic/QuatNodes.js';
21
+ import * as Vec2Nodes from './Nodes/Logic/Vec2Nodes.js';
22
+ import * as Vec3Nodes from './Nodes/Logic/Vec3Nodes.js';
23
+ import * as Vec4Nodes from './Nodes/Logic/Vec4Nodes.js';
24
+ import { GetSceneProperty } from './Nodes/Queries/GetSceneProperty.js';
25
+ import { ColorValue } from './Values/ColorValue.js';
26
+ import { EulerValue } from './Values/EulerValue.js';
27
+ import { Mat3Value } from './Values/Mat3Value.js';
28
+ import { Mat4Value } from './Values/Mat4Value.js';
29
+ import { QuatValue } from './Values/QuatValue.js';
30
+ import { Vec2Value } from './Values/Vec2Value.js';
31
+ import { Vec3Value } from './Values/Vec3Value.js';
32
+ import { Vec4Value } from './Values/Vec4Value.js';
33
+
34
+ export const getSceneValuesMap = memo<ValueTypeMap>(() => {
35
+ const valueTypes = [
36
+ Vec2Value,
37
+ Vec3Value,
38
+ Vec4Value,
39
+ ColorValue,
40
+ EulerValue,
41
+ QuatValue,
42
+ Mat3Value,
43
+ Mat4Value
44
+ ];
45
+ const temp = Object.fromEntries(
46
+ valueTypes.map((valueType) => [valueType.name, valueType])
47
+ );
48
+ return temp;
49
+ });
50
+
51
+ export const getSceneStringConversions = (
52
+ values: Record<string, ValueType>
53
+ ): NodeDefinition[] =>
54
+ Object.keys(values).flatMap((valueTypeName) =>
55
+ getStringConversionsForValueType({ values, valueTypeName })
56
+ );
57
+
58
+ export const getSceneNodesMap = memo<Record<string, NodeDefinition>>(() => {
59
+ const allValueTypeNames = Object.keys({
60
+ ...getCoreValuesMap(),
61
+ ...getSceneValuesMap()
62
+ });
63
+
64
+ const nodeDefinitions = [
65
+ // pull in value type nodes
66
+ ...getNodeDescriptions(Vec2Nodes),
67
+ ...getNodeDescriptions(Vec3Nodes),
68
+ ...getNodeDescriptions(Vec4Nodes),
69
+ ...getNodeDescriptions(ColorNodes),
70
+ ...getNodeDescriptions(EulerNodes),
71
+ ...getNodeDescriptions(QuatNodes),
72
+ ...getNodeDescriptions(Mat3Nodes),
73
+ ...getNodeDescriptions(Mat4Nodes),
74
+
75
+ // events
76
+ OnSceneNodeClick,
77
+ // actions
78
+ ...SetSceneProperty(allValueTypeNames),
79
+ ...GetSceneProperty(allValueTypeNames),
80
+
81
+ ...getSceneStringConversions(getSceneValuesMap())
82
+ ];
83
+
84
+ return Object.fromEntries(
85
+ nodeDefinitions.map((nodeDefinition) => [
86
+ nodeDefinition.typeName,
87
+ nodeDefinition
88
+ ])
89
+ );
90
+ });
91
+
92
+ export const registerSceneProfile = (registry: IRegistry): IRegistry => {
93
+ const values = {
94
+ ...registry.values,
95
+ ...getCoreValuesMap(),
96
+ ...getSceneValuesMap()
97
+ };
98
+ return {
99
+ values,
100
+ nodes: { ...registry.nodes, ...getSceneNodesMap() },
101
+ dependencies: {
102
+ ...registry.dependencies
103
+ }
104
+ };
105
+ };
@@ -0,0 +1,53 @@
1
+ {
2
+ "nodes": [
3
+ {
4
+ "type": "lifecycle/onStart",
5
+ "id": "0",
6
+ "flows": {
7
+ "flow": {
8
+ "nodeId": "3",
9
+ "socket": "flow"
10
+ }
11
+ }
12
+ },
13
+ {
14
+ "type": "math/toColor/rgb",
15
+ "id": "1",
16
+ "parameters": {
17
+ "r": {
18
+ "value": 1
19
+ },
20
+ "g": {
21
+ "value": 0
22
+ },
23
+ "b": {
24
+ "value": 0
25
+ }
26
+ }
27
+ },
28
+ {
29
+ "type": "math/toString/color",
30
+ "id": "2",
31
+ "parameters": {
32
+ "a": {
33
+ "link": {
34
+ "nodeId": "1",
35
+ "socket": "result"
36
+ }
37
+ }
38
+ }
39
+ },
40
+ {
41
+ "type": "debug/log",
42
+ "id": "3",
43
+ "parameters": {
44
+ "text": {
45
+ "link": {
46
+ "nodeId": "2",
47
+ "socket": "result"
48
+ }
49
+ }
50
+ }
51
+ }
52
+ ]
53
+ }
@@ -0,0 +1,53 @@
1
+ {
2
+ "nodes": [
3
+ {
4
+ "type": "lifecycle/onStart",
5
+ "id": "0",
6
+ "flows": {
7
+ "flow": {
8
+ "nodeId": "3",
9
+ "socket": "flow"
10
+ }
11
+ }
12
+ },
13
+ {
14
+ "type": "math/toEuler/float",
15
+ "id": "1",
16
+ "parameters": {
17
+ "x": {
18
+ "value": 1
19
+ },
20
+ "y": {
21
+ "value": 0
22
+ },
23
+ "z": {
24
+ "value": 0
25
+ }
26
+ }
27
+ },
28
+ {
29
+ "type": "math/toString/euler",
30
+ "id": "2",
31
+ "parameters": {
32
+ "a": {
33
+ "link": {
34
+ "nodeId": "1",
35
+ "socket": "result"
36
+ }
37
+ }
38
+ }
39
+ },
40
+ {
41
+ "type": "debug/log",
42
+ "id": "3",
43
+ "parameters": {
44
+ "text": {
45
+ "link": {
46
+ "nodeId": "2",
47
+ "socket": "result"
48
+ }
49
+ }
50
+ }
51
+ }
52
+ ]
53
+ }
@@ -0,0 +1,56 @@
1
+ {
2
+ "nodes": [
3
+ {
4
+ "type": "lifecycle/onStart",
5
+ "id": "0",
6
+ "flows": {
7
+ "flow": {
8
+ "nodeId": "3",
9
+ "socket": "flow"
10
+ }
11
+ }
12
+ },
13
+ {
14
+ "type": "math/toQuat/float",
15
+ "id": "1",
16
+ "parameters": {
17
+ "x": {
18
+ "value": 1
19
+ },
20
+ "y": {
21
+ "value": 0
22
+ },
23
+ "z": {
24
+ "value": 0
25
+ },
26
+ "w": {
27
+ "value": 0
28
+ }
29
+ }
30
+ },
31
+ {
32
+ "type": "math/toString/quat",
33
+ "id": "2",
34
+ "parameters": {
35
+ "a": {
36
+ "link": {
37
+ "nodeId": "1",
38
+ "socket": "result"
39
+ }
40
+ }
41
+ }
42
+ },
43
+ {
44
+ "type": "debug/log",
45
+ "id": "3",
46
+ "parameters": {
47
+ "text": {
48
+ "link": {
49
+ "nodeId": "2",
50
+ "socket": "result"
51
+ }
52
+ }
53
+ }
54
+ }
55
+ ]
56
+ }
@@ -0,0 +1,50 @@
1
+ {
2
+ "nodes": [
3
+ {
4
+ "type": "lifecycle/onStart",
5
+ "id": "0",
6
+ "flows": {
7
+ "flow": {
8
+ "nodeId": "3",
9
+ "socket": "flow"
10
+ }
11
+ }
12
+ },
13
+ {
14
+ "type": "math/toVec2/float",
15
+ "id": "1",
16
+ "parameters": {
17
+ "x": {
18
+ "value": 1
19
+ },
20
+ "y": {
21
+ "value": 0
22
+ }
23
+ }
24
+ },
25
+ {
26
+ "type": "math/toString/vec2",
27
+ "id": "2",
28
+ "parameters": {
29
+ "a": {
30
+ "link": {
31
+ "nodeId": "1",
32
+ "socket": "result"
33
+ }
34
+ }
35
+ }
36
+ },
37
+ {
38
+ "type": "debug/log",
39
+ "id": "3",
40
+ "parameters": {
41
+ "text": {
42
+ "link": {
43
+ "nodeId": "2",
44
+ "socket": "result"
45
+ }
46
+ }
47
+ }
48
+ }
49
+ ]
50
+ }
@@ -0,0 +1,53 @@
1
+ {
2
+ "nodes": [
3
+ {
4
+ "type": "lifecycle/onStart",
5
+ "id": "0",
6
+ "flows": {
7
+ "flow": {
8
+ "nodeId": "3",
9
+ "socket": "flow"
10
+ }
11
+ }
12
+ },
13
+ {
14
+ "type": "math/toVec3/float",
15
+ "id": "1",
16
+ "parameters": {
17
+ "x": {
18
+ "value": 1
19
+ },
20
+ "y": {
21
+ "value": 0
22
+ },
23
+ "z": {
24
+ "value": 0
25
+ }
26
+ }
27
+ },
28
+ {
29
+ "type": "math/toString/vec3",
30
+ "id": "2",
31
+ "parameters": {
32
+ "a": {
33
+ "link": {
34
+ "nodeId": "1",
35
+ "socket": "result"
36
+ }
37
+ }
38
+ }
39
+ },
40
+ {
41
+ "type": "debug/log",
42
+ "id": "3",
43
+ "parameters": {
44
+ "text": {
45
+ "link": {
46
+ "nodeId": "2",
47
+ "socket": "result"
48
+ }
49
+ }
50
+ }
51
+ }
52
+ ]
53
+ }
@@ -0,0 +1,56 @@
1
+ {
2
+ "nodes": [
3
+ {
4
+ "type": "lifecycle/onStart",
5
+ "id": "0",
6
+ "flows": {
7
+ "flow": {
8
+ "nodeId": "3",
9
+ "socket": "flow"
10
+ }
11
+ }
12
+ },
13
+ {
14
+ "type": "math/toVec4/float",
15
+ "id": "1",
16
+ "parameters": {
17
+ "x": {
18
+ "value": 1
19
+ },
20
+ "y": {
21
+ "value": 0
22
+ },
23
+ "z": {
24
+ "value": 0
25
+ },
26
+ "w": {
27
+ "value": 0
28
+ }
29
+ }
30
+ },
31
+ {
32
+ "type": "math/toString/vec4",
33
+ "id": "2",
34
+ "parameters": {
35
+ "a": {
36
+ "link": {
37
+ "nodeId": "1",
38
+ "socket": "result"
39
+ }
40
+ }
41
+ }
42
+ },
43
+ {
44
+ "type": "debug/log",
45
+ "id": "3",
46
+ "parameters": {
47
+ "text": {
48
+ "link": {
49
+ "nodeId": "2",
50
+ "socket": "result"
51
+ }
52
+ }
53
+ }
54
+ }
55
+ ]
56
+ }
@@ -0,0 +1,57 @@
1
+ import * as colorJson from './graphs/logic/Color.json';
2
+ import * as eulerJson from './graphs/logic/Euler.json';
3
+ import * as quaternionJson from './graphs/logic/Quaternion.json';
4
+ import * as vector2Json from './graphs/logic/Vector2.json';
5
+ import * as vector3Json from './graphs/logic/Vector3.json';
6
+ import * as vector4Json from './graphs/logic/Vector4.json';
7
+ import {
8
+ readGraphFromJSON,
9
+ validateGraphLinks,
10
+ registerCoreProfile,
11
+ validateGraphAcyclic,
12
+ type IRegistry,
13
+ type GraphInstance,
14
+ type GraphJSON
15
+ } from '@kiberon-labs/behave-graph';
16
+ import { registerSceneProfile } from '@/registerSceneProfile.js';
17
+ import { describe, test, expect } from 'vitest';
18
+
19
+ let registry: IRegistry = {
20
+ nodes: {},
21
+ values: {},
22
+ dependencies: {}
23
+ };
24
+ registry = registerCoreProfile(registry);
25
+ registry = registerSceneProfile(registry);
26
+
27
+ const exampleMap: { [key: string]: any } = {
28
+ vector2Json,
29
+ vector3Json,
30
+ vector4Json,
31
+ quaternionJson,
32
+ colorJson,
33
+ eulerJson
34
+ };
35
+
36
+ for (const key in exampleMap) {
37
+ describe(`${key}`, () => {
38
+ const exampleJson = exampleMap[key] as GraphJSON;
39
+
40
+ let parsedGraphJson: GraphInstance | undefined;
41
+ test('parse json to graph', () => {
42
+ expect(() => {
43
+ parsedGraphJson = readGraphFromJSON({
44
+ graphJson: exampleJson,
45
+ registry
46
+ });
47
+ }).not.toThrow();
48
+ // await fs.writeFile('./examples/test.json', JSON.stringify(writeGraphToJSON(graph), null, ' '), { encoding: 'utf-8' });
49
+ if (parsedGraphJson !== undefined) {
50
+ expect(validateGraphLinks(parsedGraphJson.nodes)).toHaveLength(0);
51
+ expect(validateGraphAcyclic(parsedGraphJson.nodes)).toHaveLength(0);
52
+ } else {
53
+ expect(parsedGraphJson).toBeDefined();
54
+ }
55
+ });
56
+ });
57
+ }
@@ -0,0 +1,62 @@
1
+ import {
2
+ validateValueRegistry,
3
+ registerCoreProfile,
4
+ validateNodeRegistry,
5
+ type IRegistry
6
+ } from '@kiberon-labs/behave-graph';
7
+
8
+ import { registerSceneProfile } from '../src/registerSceneProfile.js';
9
+ import { describe, test, expect } from 'vitest';
10
+
11
+ describe('scene profile', () => {
12
+ let registry: IRegistry = {
13
+ nodes: {},
14
+ values: {},
15
+ dependencies: {
16
+ IScene: null
17
+ }
18
+ };
19
+ registry = registerCoreProfile(registry);
20
+ registry = registerSceneProfile(registry);
21
+
22
+ test('validate node registry', () => {
23
+ expect(validateNodeRegistry(registry)).toHaveLength(0);
24
+ });
25
+ test('validate value registry', () => {
26
+ expect(validateValueRegistry(registry.values)).toHaveLength(0);
27
+ });
28
+
29
+ const valueTypeNameToExampleValues: { [key: string]: any[] } = {
30
+ vec2: ['(0,0)', '1,0', '(100,-60.0)', { x: 0, y: 0 }, { x: -60, y: 100 }],
31
+ vec3: [
32
+ '(0,0,0)',
33
+ '1,0,0',
34
+ '100,-60.0,40',
35
+ { x: 0, y: 0, z: 1 },
36
+ { x: -60, y: 100, z: 0 }
37
+ ],
38
+ vec4: [
39
+ '(0,0,0,0)',
40
+ '1,0,0,0',
41
+ '(100,-60.0,40,-9e9)',
42
+ { x: 0, y: 0, z: 1, w: 2 },
43
+ { x: -60, y: 100, z: 0, w: -10 }
44
+ ]
45
+ };
46
+
47
+ for (const valueTypeName in valueTypeNameToExampleValues) {
48
+ test(`${valueTypeName} serialization/deserialization`, () => {
49
+ const valueType = registry.values[valueTypeName]!;
50
+
51
+ const exampleValues: any[] = valueTypeNameToExampleValues[valueTypeName]!;
52
+ exampleValues.forEach((exampleValue: any) => {
53
+ const deserializedValue = valueType.deserialize(exampleValue);
54
+ const serializedValue = valueType.serialize(deserializedValue);
55
+ const redeserializedValue = valueType.deserialize(serializedValue);
56
+ const reserializedValue = valueType.serialize(redeserializedValue);
57
+
58
+ expect(serializedValue).toStrictEqual(reserializedValue);
59
+ });
60
+ });
61
+ }
62
+ });
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "../tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": "../",
5
+ "lib": []
6
+ },
7
+ "include": [
8
+ "**/*.ts",
9
+ "**/*.json"
10
+ ]
11
+ }
@@ -0,0 +1,74 @@
1
+ import {
2
+ Vec2,
3
+ vec2Add,
4
+ vec2Dot,
5
+ vec2FromArray,
6
+ vec2Length,
7
+ vec2MultiplyByScalar,
8
+ vec2Negate,
9
+ vec2Normalize,
10
+ vec2Parse,
11
+ vec2Subtract,
12
+ vec2ToArray,
13
+ vec2ToString
14
+ } from '@/Values/Internal/Vec2.js';
15
+ import { describe, test, expect } from 'vitest';
16
+
17
+ describe('vec2 value type', () => {
18
+ test('constructor', () => {
19
+ const value = new Vec2(1, 2);
20
+ expect(value.x).toEqual(1);
21
+ expect(value.y).toEqual(2);
22
+ });
23
+ test('add', () => {
24
+ const value = vec2Add(new Vec2(1, 2), new Vec2(3, 4));
25
+ expect(value.x).toEqual(4);
26
+ expect(value.y).toEqual(6);
27
+ });
28
+ test('subtract', () => {
29
+ const value = vec2Subtract(new Vec2(1, 2), new Vec2(3, 8));
30
+ expect(value.x).toEqual(-2);
31
+ expect(value.y).toEqual(-6);
32
+ });
33
+ test('scale', () => {
34
+ const value = vec2MultiplyByScalar(new Vec2(1, 2), 2);
35
+ expect(value.x).toEqual(2);
36
+ expect(value.y).toEqual(4);
37
+ });
38
+ test('negate', () => {
39
+ const value = vec2Negate(new Vec2(1, 2));
40
+ expect(value.x).toEqual(-1);
41
+ expect(value.y).toEqual(-2);
42
+ });
43
+ test('length', () => {
44
+ const value = vec2Length(new Vec2(1, 2));
45
+ expect(value).toEqual(Math.sqrt(1 + 2 * 2));
46
+ });
47
+ test('normalize', () => {
48
+ const value = vec2Normalize(new Vec2(0, 2));
49
+ expect(value.x).toEqual(0);
50
+ expect(value.y).toEqual(1);
51
+ });
52
+ test('dot', () => {
53
+ const value = vec2Dot(new Vec2(0, 2), new Vec2(3, 4));
54
+ expect(value).toEqual(8);
55
+ });
56
+ test('fromArray', () => {
57
+ const value = vec2FromArray([1, 2, 3], 1);
58
+ expect(value.x).toEqual(2);
59
+ expect(value.y).toEqual(3);
60
+ });
61
+ test('fromArray', () => {
62
+ const array = [1, 2, 3];
63
+ vec2ToArray(new Vec2(6, 7), array, 1);
64
+ expect(array[1]).toEqual(6);
65
+ expect(array[2]).toEqual(7);
66
+ });
67
+ test('toString/parser', () => {
68
+ const v = new Vec2(10, 5.5);
69
+ const text = vec2ToString(v);
70
+ const v2 = vec2Parse(text);
71
+ expect(v.x).toEqual(v2.x);
72
+ expect(v.y).toEqual(v2.y);
73
+ });
74
+ });