@babylonjs/loaders 9.19.1 → 9.20.1

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 (52) hide show
  1. package/SPLAT/gaussianSplattingStream.d.ts +170 -1
  2. package/SPLAT/gaussianSplattingStream.js +516 -40
  3. package/SPLAT/gaussianSplattingStream.js.map +1 -1
  4. package/SPLAT/gaussianSplattingWorkBuffer.d.ts +163 -4
  5. package/SPLAT/gaussianSplattingWorkBuffer.js +683 -35
  6. package/SPLAT/gaussianSplattingWorkBuffer.js.map +1 -1
  7. package/SPLAT/gaussianSplattingWorkBufferShaders.d.ts +70 -2
  8. package/SPLAT/gaussianSplattingWorkBufferShaders.js +465 -4
  9. package/SPLAT/gaussianSplattingWorkBufferShaders.js.map +1 -1
  10. package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.d.ts +16 -1
  11. package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js +232 -25
  12. package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js.map +1 -1
  13. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.d.ts +52 -2
  14. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js +108 -7
  15. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js.map +1 -1
  16. package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.d.ts +37 -0
  17. package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.js +69 -0
  18. package/glTF/2.0/Extensions/KHR_interactivity/interactivityHostResolver.js.map +1 -0
  19. package/glTF/2.0/Extensions/KHR_interactivity/interactivityReferences.d.ts +44 -0
  20. package/glTF/2.0/Extensions/KHR_interactivity/interactivityReferences.js +51 -0
  21. package/glTF/2.0/Extensions/KHR_interactivity/interactivityReferences.js.map +1 -0
  22. package/glTF/2.0/Extensions/KHR_interactivity.pure.d.ts +1 -0
  23. package/glTF/2.0/Extensions/KHR_interactivity.pure.js +143 -12
  24. package/glTF/2.0/Extensions/KHR_interactivity.pure.js.map +1 -1
  25. package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js +6 -0
  26. package/glTF/2.0/Extensions/KHR_node_hoverability.pure.js.map +1 -1
  27. package/glTF/2.0/Extensions/KHR_node_selectability.pure.js +4 -0
  28. package/glTF/2.0/Extensions/KHR_node_selectability.pure.js.map +1 -1
  29. package/glTF/2.0/Extensions/KHR_node_visibility.pure.js +11 -0
  30. package/glTF/2.0/Extensions/KHR_node_visibility.pure.js.map +1 -1
  31. package/glTF/2.0/Extensions/babylonScenePathToObjectConverter.d.ts +126 -0
  32. package/glTF/2.0/Extensions/babylonScenePathToObjectConverter.js +251 -0
  33. package/glTF/2.0/Extensions/babylonScenePathToObjectConverter.js.map +1 -0
  34. package/glTF/2.0/Extensions/compositePathToObjectConverter.d.ts +51 -0
  35. package/glTF/2.0/Extensions/compositePathToObjectConverter.js +51 -0
  36. package/glTF/2.0/Extensions/compositePathToObjectConverter.js.map +1 -0
  37. package/glTF/2.0/Extensions/gltfPathToObjectConverter.js +69 -7
  38. package/glTF/2.0/Extensions/gltfPathToObjectConverter.js.map +1 -1
  39. package/glTF/2.0/Extensions/interactivityAssetPathToObjectConverter.d.ts +41 -0
  40. package/glTF/2.0/Extensions/interactivityAssetPathToObjectConverter.js +108 -0
  41. package/glTF/2.0/Extensions/interactivityAssetPathToObjectConverter.js.map +1 -0
  42. package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.d.ts +28 -0
  43. package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.js +71 -0
  44. package/glTF/2.0/Extensions/interactivityRefPathToObjectConverter.js.map +1 -0
  45. package/glTF/2.0/Extensions/objectModelMapping.d.ts +118 -30
  46. package/glTF/2.0/Extensions/objectModelMapping.js +472 -70
  47. package/glTF/2.0/Extensions/objectModelMapping.js.map +1 -1
  48. package/glTF/2.0/Extensions/transmissionHelper.js +4 -0
  49. package/glTF/2.0/Extensions/transmissionHelper.js.map +1 -1
  50. package/glTF/2.0/glTFLoader.pure.js +2 -1
  51. package/glTF/2.0/glTFLoader.pure.js.map +1 -1
  52. package/package.json +3 -3
@@ -1,5 +1,12 @@
1
1
  import { Logger } from "@babylonjs/core/Misc/logger.js";
2
2
  import { getAnimationTypeByFlowGraphType } from "@babylonjs/core/FlowGraph/flowGraphRichTypes.js";
3
+ // Per-block runaway-loop guard for KHR_interactivity for-loops. Interactivity assets may run large
4
+ // finite loops (e.g. the math/random Monte Carlo conformance asset iterates 10k times), so this is
5
+ // set above the FlowGraphForLoopBlock process-wide default while staying low enough that the guard is
6
+ // still meaningful — every iteration runs a full synchronous sub-graph, so a much larger value (and
7
+ // especially nested loops) could lock the main thread before the guard trips. Applied per for-loop
8
+ // block via the flow/for extraProcessor rather than by mutating the shared static.
9
+ const InteractivityForLoopMaxIterations = 20000;
3
10
  export function getMappingForFullOperationName(fullOperationName) {
4
11
  const [op, extension] = fullOperationName.split(":");
5
12
  return getMappingForDeclaration({ op, extension });
@@ -77,6 +84,10 @@ const gltfToFlowGraphMapping = {
77
84
  "event/onStart": {
78
85
  blocks: ["FlowGraphSceneReadyEventBlock" /* FlowGraphBlockNames.SceneReadyEvent */],
79
86
  outputs: {
87
+ values: {
88
+ // KHR_interactivity `ref event` output (the event reference).
89
+ event: { name: "event" },
90
+ },
80
91
  flows: {
81
92
  out: { name: "done" },
82
93
  },
@@ -88,6 +99,8 @@ const gltfToFlowGraphMapping = {
88
99
  outputs: {
89
100
  values: {
90
101
  timeSinceLastTick: { name: "deltaTime", gltfType: "number" /*, dataTransformer: (time: number) => time / 1000*/ },
102
+ // KHR_interactivity `ref event` output (the event reference).
103
+ event: { name: "event" },
91
104
  },
92
105
  flows: {
93
106
  out: { name: "done" },
@@ -118,6 +131,10 @@ const gltfToFlowGraphMapping = {
118
131
  "event/receive": {
119
132
  blocks: ["FlowGraphReceiveCustomEventBlock" /* FlowGraphBlockNames.ReceiveCustomEvent */],
120
133
  outputs: {
134
+ values: {
135
+ // KHR_interactivity `ref event` output (the event reference).
136
+ event: { name: "event" },
137
+ },
121
138
  flows: {
122
139
  out: { name: "done" },
123
140
  },
@@ -163,8 +180,26 @@ const gltfToFlowGraphMapping = {
163
180
  return serializedObjects;
164
181
  },
165
182
  },
183
+ "event/stopPropagation": {
184
+ blocks: ["FlowGraphStopEventPropagationBlock" /* FlowGraphBlockNames.StopEventPropagation */],
185
+ inputs: {
186
+ values: {
187
+ event: { name: "event" },
188
+ stopImmediate: { name: "stopImmediate" },
189
+ },
190
+ flows: {
191
+ in: { name: "in" },
192
+ },
193
+ },
194
+ outputs: {
195
+ flows: {
196
+ out: { name: "out" },
197
+ },
198
+ },
199
+ },
166
200
  "math/E": getSimpleInputMapping("FlowGraphEBlock" /* FlowGraphBlockNames.E */),
167
201
  "math/Pi": getSimpleInputMapping("FlowGraphPIBlock" /* FlowGraphBlockNames.PI */),
202
+ "math/Tau": getSimpleInputMapping("FlowGraphTauBlock" /* FlowGraphBlockNames.Tau */),
168
203
  "math/Inf": getSimpleInputMapping("FlowGraphInfBlock" /* FlowGraphBlockNames.Inf */),
169
204
  "math/NaN": getSimpleInputMapping("FlowGraphNaNBlock" /* FlowGraphBlockNames.NaN */),
170
205
  "math/abs": getSimpleInputMapping("FlowGraphAbsBlock" /* FlowGraphBlockNames.Abs */),
@@ -235,7 +270,57 @@ const gltfToFlowGraphMapping = {
235
270
  "math/clamp": getSimpleInputMapping("FlowGraphClampBlock" /* FlowGraphBlockNames.Clamp */, ["a", "b", "c"]),
236
271
  "math/saturate": getSimpleInputMapping("FlowGraphSaturateBlock" /* FlowGraphBlockNames.Saturate */),
237
272
  "math/mix": getSimpleInputMapping("FlowGraphMathInterpolationBlock" /* FlowGraphBlockNames.MathInterpolation */, ["a", "b", "c"]),
273
+ // Smooth-step (Hermite interpolation): edges a/b and value c.
274
+ "math/smoothStep": getSimpleInputMapping("FlowGraphSmoothStepBlock" /* FlowGraphBlockNames.SmoothStep */, ["a", "b", "c"]),
275
+ // Linear sRGB <-> OkLCh (Oklab polar form). Scalar r/g/b inputs map to l/c/h
276
+ // outputs (hue in radians) and vice-versa.
277
+ "math/rgbToOkLCh": {
278
+ blocks: ["FlowGraphRGBToOkLChBlock" /* FlowGraphBlockNames.RGBToOkLCh */],
279
+ inputs: {
280
+ values: {
281
+ r: { name: "r", gltfType: "number" },
282
+ g: { name: "g", gltfType: "number" },
283
+ b: { name: "b", gltfType: "number" },
284
+ },
285
+ },
286
+ outputs: {
287
+ values: {
288
+ l: { name: "l" },
289
+ c: { name: "c" },
290
+ h: { name: "h" },
291
+ },
292
+ },
293
+ },
294
+ "math/rgbFromOkLCh": {
295
+ blocks: ["FlowGraphRGBFromOkLChBlock" /* FlowGraphBlockNames.RGBFromOkLCh */],
296
+ inputs: {
297
+ values: {
298
+ l: { name: "l", gltfType: "number" },
299
+ c: { name: "c", gltfType: "number" },
300
+ h: { name: "h", gltfType: "number" },
301
+ },
302
+ },
303
+ outputs: {
304
+ values: {
305
+ r: { name: "r" },
306
+ g: { name: "g" },
307
+ b: { name: "b" },
308
+ },
309
+ },
310
+ },
311
+ // Quaternion spherical-linear interpolation. Inputs are two unit
312
+ // quaternions and an unclamped float coefficient.
313
+ "math/quatSlerp": getSimpleInputMapping("FlowGraphMathSlerpBlock" /* FlowGraphBlockNames.MathSlerp */, ["a", "b", "c"]),
314
+ // Vector spherical-linear interpolation (float2/float3). Inputs are two
315
+ // vectors and an unclamped float coefficient.
316
+ "math/slerp": getSimpleInputMapping("FlowGraphVectorSlerpBlock" /* FlowGraphBlockNames.VectorSlerp */, ["a", "b", "c"]),
238
317
  "math/eq": getSimpleInputMapping("FlowGraphEqualityBlock" /* FlowGraphBlockNames.Equality */, ["a", "b"]),
318
+ // Reference equality. The spec defines `ref/eq` as: true if both refs are
319
+ // null, true if both refer to the same object (regardless of whether it
320
+ // exists), false otherwise. FlowGraphEqualityBlock falls through to a
321
+ // strict `===` comparison for non-vector/matrix/numeric types, which
322
+ // already produces the spec-defined behaviour for Babylon object refs.
323
+ "ref/eq": getSimpleInputMapping("FlowGraphEqualityBlock" /* FlowGraphBlockNames.Equality */, ["a", "b"]),
239
324
  "math/lt": getSimpleInputMapping("FlowGraphLessThanBlock" /* FlowGraphBlockNames.LessThan */, ["a", "b"]),
240
325
  "math/le": getSimpleInputMapping("FlowGraphLessThanOrEqualBlock" /* FlowGraphBlockNames.LessThanOrEqual */, ["a", "b"]),
241
326
  "math/gt": getSimpleInputMapping("FlowGraphGreaterThanBlock" /* FlowGraphBlockNames.GreaterThan */, ["a", "b"]),
@@ -469,6 +554,16 @@ const gltfToFlowGraphMapping = {
469
554
  scale: { name: "scaling" },
470
555
  },
471
556
  },
557
+ extraProcessor(_gltfBlock, _declaration, _mapping, _parser, serializedObjects) {
558
+ var _a;
559
+ // KHR_interactivity step 4 of the matDecompose algorithm requires a non-decomposable matrix to still
560
+ // report the extracted translation and the raw column lengths, instead of the type defaults the
561
+ // FlowGraph block emits by default. The block has no `isValid` output in glTF, so the caller can only
562
+ // observe those values.
563
+ (_a = serializedObjects[0]).config || (_a.config = {});
564
+ serializedObjects[0].config.keepDegenerateComponents = true;
565
+ return serializedObjects;
566
+ },
472
567
  },
473
568
  "math/quatConjugate": getSimpleInputMapping("FlowGraphConjugateBlock" /* FlowGraphBlockNames.Conjugate */, ["a"]),
474
569
  "math/quatMul": {
@@ -508,6 +603,40 @@ const gltfToFlowGraphMapping = {
508
603
  },
509
604
  "math/quatToAxisAngle": getSimpleInputMapping("FlowGraphAxisAngleFromQuaternionBlock" /* FlowGraphBlockNames.AxisAngleFromQuaternion */, ["a"]),
510
605
  "math/quatFromDirections": getSimpleInputMapping("FlowGraphQuaternionFromDirectionsBlock" /* FlowGraphBlockNames.QuaternionFromDirections */, ["a", "b"]),
606
+ "math/quatFromUpForward": {
607
+ blocks: ["FlowGraphQuaternionFromUpForwardBlock" /* FlowGraphBlockNames.QuaternionFromUpForward */],
608
+ inputs: {
609
+ values: {
610
+ up: { name: "a", gltfType: "float3" },
611
+ forward: { name: "b", gltfType: "float3" },
612
+ },
613
+ },
614
+ outputs: {
615
+ values: {
616
+ value: { name: "value" },
617
+ },
618
+ },
619
+ },
620
+ // Tait–Bryan intrinsic Euler angles (x/y/z, in radians) to a rotation quaternion. The rotation
621
+ // order is selected by the `order` configuration string (default `yxz`).
622
+ "math/quatFromAngles": {
623
+ blocks: ["FlowGraphQuaternionFromAnglesBlock" /* FlowGraphBlockNames.QuaternionFromAngles */],
624
+ configuration: {
625
+ order: { name: "order", defaultValue: ["yxz"] },
626
+ },
627
+ inputs: {
628
+ values: {
629
+ x: { name: "a", gltfType: "number" },
630
+ y: { name: "b", gltfType: "number" },
631
+ z: { name: "c", gltfType: "number" },
632
+ },
633
+ },
634
+ outputs: {
635
+ values: {
636
+ value: { name: "value" },
637
+ },
638
+ },
639
+ },
511
640
  "math/combine2x2": {
512
641
  blocks: ["FlowGraphCombineMatrix2DBlock" /* FlowGraphBlockNames.CombineMatrix2D */],
513
642
  inputs: {
@@ -523,13 +652,6 @@ const gltfToFlowGraphMapping = {
523
652
  value: { name: "value" },
524
653
  },
525
654
  },
526
- extraProcessor(_gltfBlock, _declaration, _mapping, _parser, serializedObjects) {
527
- var _a;
528
- // configure it to work the way glTF specifies
529
- (_a = serializedObjects[0]).config || (_a.config = {});
530
- serializedObjects[0].config.inputIsColumnMajor = true;
531
- return serializedObjects;
532
- },
533
655
  },
534
656
  "math/extract2x2": {
535
657
  blocks: ["FlowGraphExtractMatrix2DBlock" /* FlowGraphBlockNames.ExtractMatrix2D */],
@@ -567,13 +689,6 @@ const gltfToFlowGraphMapping = {
567
689
  value: { name: "value" },
568
690
  },
569
691
  },
570
- extraProcessor(_gltfBlock, _declaration, _mapping, _parser, serializedObjects) {
571
- var _a;
572
- // configure it to work the way glTF specifies
573
- (_a = serializedObjects[0]).config || (_a.config = {});
574
- serializedObjects[0].config.inputIsColumnMajor = true;
575
- return serializedObjects;
576
- },
577
692
  },
578
693
  "math/extract3x3": {
579
694
  blocks: ["FlowGraphExtractMatrix3DBlock" /* FlowGraphBlockNames.ExtractMatrix3D */],
@@ -623,13 +738,6 @@ const gltfToFlowGraphMapping = {
623
738
  value: { name: "value" },
624
739
  },
625
740
  },
626
- extraProcessor(_gltfBlock, _declaration, _mapping, _parser, serializedObjects) {
627
- var _a;
628
- // configure it to work the way glTF specifies
629
- (_a = serializedObjects[0]).config || (_a.config = {});
630
- serializedObjects[0].config.inputIsColumnMajor = true;
631
- return serializedObjects;
632
- },
633
741
  },
634
742
  "math/extract4x4": {
635
743
  blocks: ["FlowGraphExtractMatrixBlock" /* FlowGraphBlockNames.ExtractMatrix */],
@@ -866,6 +974,11 @@ const gltfToFlowGraphMapping = {
866
974
  const serializedObject = serializedObjects[0];
867
975
  serializedObject.config || (serializedObject.config = {});
868
976
  serializedObject.config.incrementIndexWhenLoopDone = true;
977
+ // KHR_interactivity assets may run large finite loops (e.g. the math/random Monte Carlo
978
+ // conformance asset iterates 10k times), well above the block's conservative default guard.
979
+ // Raise the cap for interactivity for-loops only, per block, instead of mutating the
980
+ // process-wide FlowGraphForLoopBlock.MaxLoopIterations that every other FlowGraph relies on.
981
+ serializedObject.config.maxLoopIterations = InteractivityForLoopMaxIterations;
869
982
  return serializedObjects;
870
983
  },
871
984
  },
@@ -938,10 +1051,22 @@ const gltfToFlowGraphMapping = {
938
1051
  flows: {
939
1052
  err: { name: "error" },
940
1053
  },
1054
+ values: {
1055
+ // New spec renames this output to `lastDelay` (ref). Internally we still produce a
1056
+ // FlowGraphInteger; the index is unique per delay so it acts as the opaque handle.
1057
+ lastDelay: { name: "lastDelayIndex" },
1058
+ },
941
1059
  },
942
1060
  },
943
1061
  "flow/cancelDelay": {
944
1062
  blocks: ["FlowGraphCancelDelayBlock" /* FlowGraphBlockNames.CancelDelay */],
1063
+ inputs: {
1064
+ values: {
1065
+ // New spec renames this input to `delay` (ref). The underlying block reads an int
1066
+ // from `delayIndex`; when a ref-string flows in we coerce it via the path converter.
1067
+ delay: { name: "delayIndex" },
1068
+ },
1069
+ },
945
1070
  },
946
1071
  "variable/get": {
947
1072
  blocks: ["FlowGraphGetVariableBlock" /* FlowGraphBlockNames.GetVariable */],
@@ -1088,6 +1213,7 @@ const gltfToFlowGraphMapping = {
1088
1213
  },
1089
1214
  "pointer/get": {
1090
1215
  blocks: ["FlowGraphGetPropertyBlock" /* FlowGraphBlockNames.GetProperty */, "FlowGraphJsonPointerParserBlock" /* FlowGraphBlockNames.JsonPointerParser */],
1216
+ validation: ValidateJsonPointerTemplate,
1091
1217
  configuration: {
1092
1218
  pointer: { name: "jsonPointer", toBlock: "FlowGraphJsonPointerParserBlock" /* FlowGraphBlockNames.JsonPointerParser */ },
1093
1219
  },
@@ -1132,6 +1258,7 @@ const gltfToFlowGraphMapping = {
1132
1258
  },
1133
1259
  "pointer/set": {
1134
1260
  blocks: ["FlowGraphSetPropertyBlock" /* FlowGraphBlockNames.SetProperty */, "FlowGraphJsonPointerParserBlock" /* FlowGraphBlockNames.JsonPointerParser */],
1261
+ validation: ValidateJsonPointerTemplate,
1135
1262
  configuration: {
1136
1263
  pointer: { name: "jsonPointer", toBlock: "FlowGraphJsonPointerParserBlock" /* FlowGraphBlockNames.JsonPointerParser */ },
1137
1264
  },
@@ -1184,6 +1311,7 @@ const gltfToFlowGraphMapping = {
1184
1311
  "pointer/interpolate": {
1185
1312
  // interpolate, parse the pointer and play the animation generated. 3 blocks!
1186
1313
  blocks: ["FlowGraphInterpolationBlock" /* FlowGraphBlockNames.ValueInterpolation */, "FlowGraphJsonPointerParserBlock" /* FlowGraphBlockNames.JsonPointerParser */, "FlowGraphPlayAnimationBlock" /* FlowGraphBlockNames.PlayAnimation */, "FlowGraphBezierCurveEasing" /* FlowGraphBlockNames.BezierCurveEasing */],
1314
+ validation: ValidateJsonPointerTemplate,
1187
1315
  configuration: {
1188
1316
  pointer: { name: "jsonPointer", toBlock: "FlowGraphJsonPointerParserBlock" /* FlowGraphBlockNames.JsonPointerParser */ },
1189
1317
  },
@@ -1280,8 +1408,18 @@ const gltfToFlowGraphMapping = {
1280
1408
  values: {
1281
1409
  animation: { name: "index", gltfType: "number", toBlock: "FlowGraphArrayIndexBlock" /* FlowGraphBlockNames.ArrayIndex */ },
1282
1410
  speed: { name: "speed", gltfType: "number" },
1283
- startTime: { name: "from", gltfType: "number", dataTransformer: (time, parser) => [time[0] * parser._animationTargetFps] },
1284
- endTime: { name: "to", gltfType: "number", dataTransformer: (time, parser) => [time[0] * parser._animationTargetFps] },
1411
+ startTime: {
1412
+ name: "from",
1413
+ gltfType: "number",
1414
+ convertConnectedTimeToFrames: true,
1415
+ dataTransformer: (time, parser) => [time[0] * parser._animationTargetFps],
1416
+ },
1417
+ endTime: {
1418
+ name: "to",
1419
+ gltfType: "number",
1420
+ convertConnectedTimeToFrames: true,
1421
+ dataTransformer: (time, parser) => [time[0] * parser._animationTargetFps],
1422
+ },
1285
1423
  },
1286
1424
  },
1287
1425
  outputs: {
@@ -1355,7 +1493,12 @@ const gltfToFlowGraphMapping = {
1355
1493
  inputs: {
1356
1494
  values: {
1357
1495
  animation: { name: "index", gltfType: "number", toBlock: "FlowGraphArrayIndexBlock" /* FlowGraphBlockNames.ArrayIndex */ },
1358
- stopTime: { name: "stopAtFrame", gltfType: "number", dataTransformer: (time, parser) => [time[0] * parser._animationTargetFps] },
1496
+ stopTime: {
1497
+ name: "stopAtFrame",
1498
+ gltfType: "number",
1499
+ convertConnectedTimeToFrames: true,
1500
+ dataTransformer: (time, parser) => [time[0] * parser._animationTargetFps],
1501
+ },
1359
1502
  },
1360
1503
  },
1361
1504
  outputs: {
@@ -1491,6 +1634,70 @@ function ValidateTypes(gltfBlock) {
1491
1634
  }
1492
1635
  return { valid: true };
1493
1636
  }
1637
+ /**
1638
+ * Returns whether a literal path segment has an odd number of consecutive occurrences of any bracket character.
1639
+ * Brackets used literally inside a path segment must be doubled, so an odd run means the segment is malformed.
1640
+ * @param segment the literal path segment
1641
+ * @returns true when the segment contains an odd run of brackets
1642
+ */
1643
+ function HasOddBracketRun(segment) {
1644
+ for (let index = 0; index < segment.length; index++) {
1645
+ const character = segment[index];
1646
+ if ("[]{}".indexOf(character) === -1) {
1647
+ continue;
1648
+ }
1649
+ let runLength = 1;
1650
+ while (segment[index + runLength] === character) {
1651
+ runLength++;
1652
+ }
1653
+ if (runLength % 2 !== 0) {
1654
+ return true;
1655
+ }
1656
+ index += runLength - 1;
1657
+ }
1658
+ return false;
1659
+ }
1660
+ /**
1661
+ * Validates the `pointer` configuration value of a `pointer/*` operation, following the JSON Pointer Template
1662
+ * Parsing steps of the KHR_interactivity specification. A template parameter must span an entire path segment, so
1663
+ * a template such as `/materials/{materialRef}pbrMetallicRoughness/...` is a syntax error, and the specification
1664
+ * requires the whole behavior graph to be rejected.
1665
+ * @param gltfBlock the glTF interactivity node
1666
+ * @returns the validation result
1667
+ */
1668
+ function ValidateJsonPointerTemplate(gltfBlock) {
1669
+ const pointer = gltfBlock.configuration?.pointer?.value?.[0];
1670
+ if (typeof pointer !== "string") {
1671
+ return { valid: false, error: "A pointer operation requires a string `pointer` configuration value" };
1672
+ }
1673
+ // A JSON Pointer (RFC 6901) is either empty or a sequence of `/`-prefixed reference tokens.
1674
+ if (pointer.length !== 0 && pointer[0] !== "/") {
1675
+ return { valid: false, error: `The JSON Pointer Template "${pointer}" is not a syntactically valid JSON Pointer` };
1676
+ }
1677
+ const invalid = (reason) => ({ valid: false, error: `The JSON Pointer Template "${pointer}" is invalid: ${reason}` });
1678
+ const socketIds = new Set();
1679
+ for (const segment of pointer.split("/")) {
1680
+ const isIntegerParameter = segment[0] === "[" && segment[1] !== "[";
1681
+ const isReferenceParameter = segment[0] === "{" && segment[1] !== "{";
1682
+ if (!isIntegerParameter && !isReferenceParameter) {
1683
+ if (HasOddBracketRun(segment)) {
1684
+ return invalid(`the path segment "${segment}" contains an odd number of consecutive brackets`);
1685
+ }
1686
+ continue;
1687
+ }
1688
+ const closingBracket = isIntegerParameter ? "]" : "}";
1689
+ const body = segment.substring(1, segment.length - 1);
1690
+ if (segment.length < 3 || segment[segment.length - 1] !== closingBracket || /[[{]/.test(body) || /[\]}]/.test(body)) {
1691
+ return invalid(`the template parameter path segment "${segment}" is malformed`);
1692
+ }
1693
+ const socketId = body.replace(/~1/g, "/").replace(/~0/g, "~");
1694
+ if (socketIds.has(socketId)) {
1695
+ return invalid(`the template parameter "${socketId}" is used more than once`);
1696
+ }
1697
+ socketIds.add(socketId);
1698
+ }
1699
+ return { valid: true };
1700
+ }
1494
1701
  export function getAllSupportedNativeNodeTypes() {
1495
1702
  return Object.keys(gltfToFlowGraphMapping);
1496
1703
  }
@@ -1660,7 +1867,7 @@ export function getAllSupportedNativeNodeTypes() {
1660
1867
  - Effective JSON Pointer Generation (`pointer/set`) [FlowGraphBlockNames.SetProperty, FlowGraphBlockNames.JsonPointerParser]
1661
1868
  - Pointer Get (`pointer/get`) [FlowGraphBlockNames.GetProperty, FlowGraphBlockNames.JsonPointerParser]
1662
1869
  - Pointer Set (`pointer/set`) [FlowGraphBlockNames.SetProperty, FlowGraphBlockNames.JsonPointerParser]
1663
- - Pointer Interpolate (`pointer/interpolate`) [FlowGraphBlockNames.ValueInterpolation, FlowGraphBlockNames.JsonPointerParser, FlowGraphBlockNames.PlayAnimation, FlowGraphBlockNames.Easing]
1870
+ - Pointer Interpolate (`pointer/interpolate`) [FlowGraphBlockNames.ValueInterpolation, FlowGraphBlockNames.JsonPointerParser, FlowGraphBlockNames.PlayAnimation, FlowGraphBlockNames.BezierCurveEasing]
1664
1871
 
1665
1872
  ### Animation Control Nodes
1666
1873
  1. **Animation Play** (`animation/start`) FlowGraphBlockNames.PlayAnimation