@babylonjs/loaders 9.26.2 → 9.27.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 (33) hide show
  1. package/glTF/2.0/Extensions/EXT_texture_avif.pure.js +1 -1
  2. package/glTF/2.0/Extensions/EXT_texture_avif.pure.js.map +1 -1
  3. package/glTF/2.0/Extensions/EXT_texture_webp.pure.js +1 -1
  4. package/glTF/2.0/Extensions/EXT_texture_webp.pure.js.map +1 -1
  5. package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.d.ts +33 -0
  6. package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js +166 -37
  7. package/glTF/2.0/Extensions/KHR_interactivity/declarationMapper.js.map +1 -1
  8. package/glTF/2.0/Extensions/KHR_interactivity/index.d.ts +1 -0
  9. package/glTF/2.0/Extensions/KHR_interactivity/index.js +1 -0
  10. package/glTF/2.0/Extensions/KHR_interactivity/index.js.map +1 -1
  11. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphExporter.d.ts +243 -0
  12. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphExporter.js +2335 -0
  13. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphExporter.js.map +1 -0
  14. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphModel.d.ts +82 -1
  15. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphModel.js +180 -34
  16. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphModel.js.map +1 -1
  17. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.d.ts +14 -2
  18. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js +220 -34
  19. package/glTF/2.0/Extensions/KHR_interactivity/interactivityGraphParser.js.map +1 -1
  20. package/glTF/2.0/Extensions/KHR_interactivity/pure.d.ts +1 -0
  21. package/glTF/2.0/Extensions/KHR_interactivity/pure.js +1 -0
  22. package/glTF/2.0/Extensions/KHR_interactivity/pure.js.map +1 -1
  23. package/glTF/2.0/Extensions/KHR_interactivity.pure.d.ts +4 -0
  24. package/glTF/2.0/Extensions/KHR_interactivity.pure.js +6 -2
  25. package/glTF/2.0/Extensions/KHR_interactivity.pure.js.map +1 -1
  26. package/glTF/2.0/Extensions/KHR_texture_basisu.pure.js +1 -1
  27. package/glTF/2.0/Extensions/KHR_texture_basisu.pure.js.map +1 -1
  28. package/glTF/2.0/glTFLoader.pure.d.ts +2 -1
  29. package/glTF/2.0/glTFLoader.pure.js +41 -4
  30. package/glTF/2.0/glTFLoader.pure.js.map +1 -1
  31. package/glTF/2.0/glTFLoaderInterfaces.d.ts +9 -0
  32. package/glTF/2.0/glTFLoaderInterfaces.js.map +1 -1
  33. package/package.json +3 -3
@@ -1,12 +1,81 @@
1
- import { getMappingForDeclaration, getNoOpMappingForDeclaration, ParseDebugLogTemplate } from "./declarationMapper.js";
1
+ import { getMappingForDeclaration, getNoOpMappingForDeclaration, HasDefaultInteractivityFlowInput, NormalizeInteractivityEventDataConfiguration, ParseDebugLogTemplate, } from "./declarationMapper.js";
2
2
  import { Logger } from "@babylonjs/core/Misc/logger.js";
3
3
  import { RandomGUID } from "@babylonjs/core/Misc/guid.js";
4
- import { CloneKHRInteractivityGraph, CreateEffectiveKHRInteractivityGraph, gltfTypeToBabylonType } from "./interactivityGraphModel.js";
4
+ import { _CreateKHRInteractivityRuntimeValueSnapshot, CloneKHRInteractivityGraph, CreateEffectiveKHRInteractivityGraph, gltfTypeToBabylonType, KHR_INTERACTIVITY_SPECIFICATION_COMMIT, } from "./interactivityGraphModel.js";
5
5
  import { DelayReferencePrefix, EventReferencePrefix } from "./interactivityReferences.js";
6
6
  export { gltfTypeToBabylonType } from "./interactivityGraphModel.js";
7
7
  function _GetOwnMapping(mapping, key) {
8
8
  return mapping && Object.prototype.hasOwnProperty.call(mapping, key) ? mapping[key] : undefined;
9
9
  }
10
+ function _CloneMetadataValue(value) {
11
+ if (Array.isArray(value)) {
12
+ return value.map((entry) => _CloneMetadataValue(entry));
13
+ }
14
+ if (value !== null && typeof value === "object") {
15
+ const clone = {};
16
+ for (const [key, entry] of Object.entries(value)) {
17
+ Object.defineProperty(clone, key, {
18
+ configurable: true,
19
+ enumerable: true,
20
+ value: _CloneMetadataValue(entry),
21
+ writable: true,
22
+ });
23
+ }
24
+ return clone;
25
+ }
26
+ return value;
27
+ }
28
+ function _IsSerializableConfigurationValue(value) {
29
+ return (value === null ||
30
+ ["string", "number", "boolean"].includes(typeof value) ||
31
+ (Array.isArray(value) && value.every(_IsSerializableConfigurationValue)) ||
32
+ (typeof value === "object" && Object.values(value).every(_IsSerializableConfigurationValue)));
33
+ }
34
+ /**
35
+ * Captures import-time defaults for unconnected runtime inputs that have no authored KHR socket.
36
+ * @param flowGraph the fully parsed FlowGraph
37
+ * @internal
38
+ */
39
+ // eslint-disable-next-line @typescript-eslint/naming-convention
40
+ export function _CaptureKHRInteractivityRuntimeInputDefaults(flowGraph) {
41
+ for (const block of flowGraph.getAllBlocks()) {
42
+ const provenance = block.metadata?.khrInteractivity;
43
+ if (!provenance) {
44
+ continue;
45
+ }
46
+ if (Object.prototype.hasOwnProperty.call(provenance.generatedConfiguration ?? {}, "eventData")) {
47
+ provenance.generatedConfigurationRuntime || (provenance.generatedConfigurationRuntime = {});
48
+ if (!Object.prototype.hasOwnProperty.call(provenance.generatedConfigurationRuntime, "eventData")) {
49
+ Object.defineProperty(provenance.generatedConfigurationRuntime, "eventData", {
50
+ configurable: true,
51
+ enumerable: true,
52
+ value: _CreateKHRInteractivityRuntimeValueSnapshot(NormalizeInteractivityEventDataConfiguration(block.config?.eventData)),
53
+ writable: true,
54
+ });
55
+ }
56
+ }
57
+ for (const input of block.dataInputs) {
58
+ if (input.isConnected()) {
59
+ continue;
60
+ }
61
+ const socketProvenance = input.metadata?.khrInteractivity;
62
+ if (socketProvenance) {
63
+ socketProvenance.runtimeValueSnapshot ?? (socketProvenance.runtimeValueSnapshot = _CreateKHRInteractivityRuntimeValueSnapshot(input._defaultValue));
64
+ continue;
65
+ }
66
+ if (provenance.generatedInputDefaults && Object.prototype.hasOwnProperty.call(provenance.generatedInputDefaults, input.name)) {
67
+ continue;
68
+ }
69
+ provenance.generatedInputDefaults || (provenance.generatedInputDefaults = {});
70
+ Object.defineProperty(provenance.generatedInputDefaults, input.name, {
71
+ configurable: true,
72
+ enumerable: true,
73
+ value: _CreateKHRInteractivityRuntimeValueSnapshot(input._defaultValue),
74
+ writable: true,
75
+ });
76
+ }
77
+ }
78
+ }
10
79
  /**
11
80
  * Parses a KHR_interactivity graph definition (the raw glTF JSON object) into
12
81
  * the serialized FlowGraph form consumed by {@link ParseFlowGraphAsync}.
@@ -16,7 +85,7 @@ function _GetOwnMapping(mapping, key) {
16
85
  * {@link serializeToFlowGraph}.
17
86
  */
18
87
  export class InteractivityGraphToFlowGraphParser {
19
- constructor(interactivityGraph, _gltf, _animationTargetFps = 60, _graphIndex = 0, _supportedExtensions, _declarationModels) {
88
+ constructor(interactivityGraph, _gltf, _animationTargetFps = 60, _graphIndex = 0, _supportedExtensions, _declarationModels, canonicalGraph) {
20
89
  this._gltf = _gltf;
21
90
  this._animationTargetFps = _animationTargetFps;
22
91
  this._graphIndex = _graphIndex;
@@ -39,6 +108,7 @@ export class InteractivityGraphToFlowGraphParser {
39
108
  * the last block) is not disturbed, then concatenated into the serialized graph.
40
109
  */
41
110
  this._insertedBlocks = [];
111
+ this._canonicalGraph = CloneKHRInteractivityGraph(canonicalGraph ?? interactivityGraph);
42
112
  this._interactivityGraph = this._declarationModels
43
113
  ? CreateEffectiveKHRInteractivityGraph(interactivityGraph, this._declarationModels, this._gltf.nodes?.length ?? 0)
44
114
  : CloneKHRInteractivityGraph(interactivityGraph);
@@ -53,20 +123,6 @@ export class InteractivityGraphToFlowGraphParser {
53
123
  get _strictValidation() {
54
124
  return !!this._declarationModels;
55
125
  }
56
- _hasDefaultFlowInput(operation) {
57
- if (operation === "flow/waitAll") {
58
- return false;
59
- }
60
- return (operation.startsWith("flow/") ||
61
- operation.startsWith("animation/") ||
62
- operation === "pointer/set" ||
63
- operation === "pointer/interpolate" ||
64
- operation === "variable/set" ||
65
- operation === "variable/interpolate" ||
66
- operation === "event/send" ||
67
- operation === "event/stopPropagation" ||
68
- operation === "flow/log:BABYLON");
69
- }
70
126
  _getAllowedDynamicValueSockets(operation, node, direction) {
71
127
  if ((operation === "debug/log" || operation === "flow/log:BABYLON") && direction === "input") {
72
128
  const message = node.configuration?.[operation === "debug/log" ? "message" : "messageTemplate"]?.value?.[0];
@@ -339,6 +395,16 @@ export class InteractivityGraphToFlowGraphParser {
339
395
  this._nodes.push({ blocks, fullOperationName: mapping.fullOperationName });
340
396
  }
341
397
  }
398
+ _createBlockProvenance(nodeIndex, declarationIndex, operation, role) {
399
+ return {
400
+ graphIndex: this._graphIndex,
401
+ nodeIndex,
402
+ declarationIndex,
403
+ operation,
404
+ role,
405
+ sourcePath: `/extensions/KHR_interactivity/graphs/${this._graphIndex}/nodes/${nodeIndex}`,
406
+ };
407
+ }
342
408
  _getEmptyBlock(className, type, nodeIndex, declarationIndex, role) {
343
409
  return {
344
410
  uniqueId: RandomGUID(),
@@ -352,17 +418,24 @@ export class InteractivityGraphToFlowGraphParser {
352
418
  metadata: nodeIndex === undefined
353
419
  ? {}
354
420
  : {
355
- khrInteractivity: {
356
- graphIndex: this._graphIndex,
357
- nodeIndex,
358
- declarationIndex,
359
- operation: type,
360
- role: role ?? 0,
361
- sourcePath: `/extensions/KHR_interactivity/graphs/${this._graphIndex}/nodes/${nodeIndex}`,
362
- },
421
+ khrInteractivity: this._createBlockProvenance(nodeIndex, declarationIndex, type, role ?? 0),
363
422
  },
364
423
  };
365
424
  }
425
+ _setSocketProvenance(connection, nodeIndex, declarationIndex, operation, role, kind, direction, socket) {
426
+ connection.metadata = {
427
+ ...(connection.metadata ?? {}),
428
+ khrInteractivity: {
429
+ ...this._createBlockProvenance(nodeIndex, declarationIndex, operation, role),
430
+ kind,
431
+ direction,
432
+ socket,
433
+ },
434
+ };
435
+ }
436
+ _getBlockRole(blocks, block) {
437
+ return block.metadata?.khrInteractivity?.role ?? blocks.indexOf(block);
438
+ }
366
439
  _createUnsupportedExtensionBlock(node, nodeIndex, mapping) {
367
440
  const block = this._getEmptyBlock("KHR_interactivity/FlowGraphUnsupportedInteractivityBlock", mapping.fullOperationName, nodeIndex, node.declaration, 0);
368
441
  const inputFlowSockets = new Set();
@@ -386,16 +459,24 @@ export class InteractivityGraphToFlowGraphParser {
386
459
  outputFlowSockets: Object.keys(node.flows ?? {}).sort(),
387
460
  };
388
461
  for (const socket of block.config.inputValueSockets) {
389
- block.dataInputs.push(this._createNewSocketConnection(socket.name));
462
+ const connection = this._createNewSocketConnection(socket.name);
463
+ this._setSocketProvenance(connection, nodeIndex, node.declaration, mapping.fullOperationName, 0, "value", "input", socket.name);
464
+ block.dataInputs.push(connection);
390
465
  }
391
466
  for (const socket of block.config.outputValueSockets) {
392
- block.dataOutputs.push(this._createNewSocketConnection(socket.name, true));
467
+ const connection = this._createNewSocketConnection(socket.name, true);
468
+ this._setSocketProvenance(connection, nodeIndex, node.declaration, mapping.fullOperationName, 0, "value", "output", socket.name);
469
+ block.dataOutputs.push(connection);
393
470
  }
394
471
  for (const socket of block.config.inputFlowSockets) {
395
- block.signalInputs.push(this._createNewSocketConnection(socket));
472
+ const connection = this._createNewSocketConnection(socket);
473
+ this._setSocketProvenance(connection, nodeIndex, node.declaration, mapping.fullOperationName, 0, "flow", "input", socket);
474
+ block.signalInputs.push(connection);
396
475
  }
397
476
  for (const socket of block.config.outputFlowSockets) {
398
- block.signalOutputs.push(this._createNewSocketConnection(socket, true));
477
+ const connection = this._createNewSocketConnection(socket, true);
478
+ this._setSocketProvenance(connection, nodeIndex, node.declaration, mapping.fullOperationName, 0, "flow", "output", socket);
479
+ block.signalOutputs.push(connection);
399
480
  }
400
481
  return block;
401
482
  }
@@ -516,6 +597,7 @@ export class InteractivityGraphToFlowGraphParser {
516
597
  if (!block.signalOutputs.includes(socketOut)) {
517
598
  block.signalOutputs.push(socketOut);
518
599
  }
600
+ this._setSocketProvenance(socketOut, i, gltfNode.declaration, flowGraphBlocks.fullOperationName, this._getBlockRole(flowGraphBlocks.blocks, block), "flow", "output", flowKey);
519
601
  // get the mapper for the input node - in case it mapped to multiple blocks
520
602
  const inputMapper = this._mappings[this._interactivityGraph.nodes[inputNodeId].declaration]?.flowGraphMapping;
521
603
  if (!inputMapper) {
@@ -541,7 +623,7 @@ export class InteractivityGraphToFlowGraphParser {
541
623
  if (this._strictValidation && allowedDynamicInputs && !allowedDynamicInputs.has(flow.socket ?? "in")) {
542
624
  flowInMapping = undefined;
543
625
  }
544
- if (!flowInMapping && (flow.socket ?? "in") === "in" && this._hasDefaultFlowInput(nodeIn.fullOperationName)) {
626
+ if (!flowInMapping && (flow.socket ?? "in") === "in" && HasDefaultInteractivityFlowInput(nodeIn.fullOperationName)) {
545
627
  flowInMapping = { name: "in" };
546
628
  }
547
629
  if (!flowInMapping && !this._isUnsupportedExtensionBlock(nodeIn.blocks[0])) {
@@ -557,6 +639,7 @@ export class InteractivityGraphToFlowGraphParser {
557
639
  socketIn = this._createNewSocketConnection(nodeInSocketName);
558
640
  inputBlock.signalInputs.push(socketIn);
559
641
  }
642
+ this._setSocketProvenance(socketIn, inputNodeId, this._interactivityGraph.nodes[inputNodeId].declaration, nodeIn.fullOperationName, this._getBlockRole(nodeIn.blocks, inputBlock), "flow", "input", flow.socket ?? "in");
560
643
  // connect the sockets
561
644
  socketIn.connectedPointIds.push(socketOut.uniqueId);
562
645
  socketOut.connectedPointIds.push(socketIn.uniqueId);
@@ -593,6 +676,9 @@ export class InteractivityGraphToFlowGraphParser {
593
676
  if (!block.dataInputs.includes(socketIn)) {
594
677
  block.dataInputs.push(socketIn);
595
678
  }
679
+ this._setSocketProvenance(socketIn, i, gltfNode.declaration, flowGraphBlocks.fullOperationName, this._getBlockRole(flowGraphBlocks.blocks, block), "value", "input", valueKey);
680
+ const socketProvenance = socketIn.metadata.khrInteractivity;
681
+ socketProvenance.sourceValue = _CloneMetadataValue(this._canonicalGraph.nodes?.[i]?.values?.[valueKey] ?? value);
596
682
  // Captured before the connected branch below shadows `valueMapping`. When set and the
597
683
  // value is supplied by a connection, the seconds→frames `dataTransformer` cannot run
598
684
  // (it is parse-time only), so the raw connected value is scaled by a runtime multiply.
@@ -600,6 +686,8 @@ export class InteractivityGraphToFlowGraphParser {
600
686
  if (value.value !== undefined) {
601
687
  const convertedValue = this._parseVariable(value, valueMapping && valueMapping.dataTransformer);
602
688
  context._connectionValues[socketIn.uniqueId] = convertedValue;
689
+ socketIn.defaultValue = convertedValue;
690
+ socketProvenance.runtimeValue = _CloneMetadataValue(convertedValue.value);
603
691
  }
604
692
  else if (typeof value.node !== "undefined") {
605
693
  const nodeOutId = value.node;
@@ -654,9 +742,10 @@ export class InteractivityGraphToFlowGraphParser {
654
742
  socketOut = this._createNewSocketConnection(socketOutName, true);
655
743
  outBlock.dataOutputs.push(socketOut);
656
744
  }
745
+ this._setSocketProvenance(socketOut, nodeOutId, this._interactivityGraph.nodes[nodeOutId].declaration, nodeOut.fullOperationName, this._getBlockRole(nodeOut.blocks, outBlock), "value", "output", nodeOutSocketName);
657
746
  // connect the sockets
658
747
  if (convertConnectedTimeToFrames) {
659
- this._connectWithSecondsToFramesConversion(context, socketOut, socketIn, i, gltfNode.declaration);
748
+ this._connectWithSecondsToFramesConversion(context, socketOut, socketIn, i, gltfNode.declaration, flowGraphBlocks.fullOperationName);
660
749
  }
661
750
  else {
662
751
  socketIn.connectedPointIds.push(socketOut.uniqueId);
@@ -685,6 +774,93 @@ export class InteractivityGraphToFlowGraphParser {
685
774
  }
686
775
  flowGraphBlocks.blocks = outputMapper.flowGraphMapping.extraProcessor(gltfNode, declaration, outputMapper.flowGraphMapping, this, flowGraphBlocks.blocks, context, this._gltf);
687
776
  }
777
+ this._ensureMappedSocketProvenance(i, gltfNode, flowGraphBlocks.blocks, outputMapper);
778
+ }
779
+ }
780
+ _ensureMappedSocketProvenance(nodeIndex, node, blocks, mapping) {
781
+ const ensureConnections = (socketMappings, kind, direction) => {
782
+ for (const [sourceName, property] of Object.entries(socketMappings ?? {})) {
783
+ if ((sourceName.startsWith("[") && sourceName.endsWith("]")) || (this._strictValidation && property.compatibilityOnly)) {
784
+ continue;
785
+ }
786
+ const block = (property.toBlock && blocks.find((candidate) => candidate.className === property.toBlock)) || blocks[0];
787
+ if (!block) {
788
+ continue;
789
+ }
790
+ const connections = kind === "value" ? (direction === "input" ? block.dataInputs : block.dataOutputs) : direction === "input" ? block.signalInputs : block.signalOutputs;
791
+ let connection = connections.find((candidate) => candidate.name === property.name);
792
+ if (!connection) {
793
+ connection = this._createNewSocketConnection(property.name, direction === "output");
794
+ connections.push(connection);
795
+ }
796
+ this._setSocketProvenance(connection, nodeIndex, node.declaration, mapping.fullOperationName, this._getBlockRole(blocks, block), kind, direction, sourceName);
797
+ }
798
+ };
799
+ ensureConnections(mapping.flowGraphMapping.outputs?.values, "value", "output");
800
+ ensureConnections(mapping.flowGraphMapping.inputs?.flows, "flow", "input");
801
+ ensureConnections(mapping.flowGraphMapping.outputs?.flows, "flow", "output");
802
+ if (HasDefaultInteractivityFlowInput(mapping.fullOperationName)) {
803
+ const block = blocks[0];
804
+ if (block) {
805
+ let connection = block.signalInputs.find((candidate) => candidate.name === "in");
806
+ if (!connection) {
807
+ connection = this._createNewSocketConnection("in");
808
+ block.signalInputs.push(connection);
809
+ }
810
+ this._setSocketProvenance(connection, nodeIndex, node.declaration, mapping.fullOperationName, this._getBlockRole(blocks, block), "flow", "input", "in");
811
+ }
812
+ }
813
+ for (const [sourceKey, property] of Object.entries(mapping.flowGraphMapping.configuration ?? {})) {
814
+ const block = (property.toBlock && blocks.find((candidate) => candidate.className === property.toBlock)) || blocks[0];
815
+ const provenance = block?.metadata?.khrInteractivity;
816
+ if (!block || !provenance) {
817
+ continue;
818
+ }
819
+ const serializedRuntimeValue = block.config?.[property.name];
820
+ const runtimeValue = serializedRuntimeValue !== null && typeof serializedRuntimeValue === "object" && Object.prototype.hasOwnProperty.call(serializedRuntimeValue, "value")
821
+ ? serializedRuntimeValue.value
822
+ : serializedRuntimeValue;
823
+ provenance.configuration || (provenance.configuration = {});
824
+ const configurationProvenance = {
825
+ sourceValue: _CloneMetadataValue(this._canonicalGraph.nodes?.[nodeIndex]?.configuration?.[sourceKey]?.value),
826
+ runtimeValue: _CloneMetadataValue(runtimeValue),
827
+ };
828
+ Object.defineProperty(provenance.configuration, sourceKey, {
829
+ configurable: true,
830
+ enumerable: true,
831
+ value: configurationProvenance,
832
+ writable: true,
833
+ });
834
+ }
835
+ for (const block of blocks) {
836
+ const provenance = block.metadata?.khrInteractivity;
837
+ if (!provenance) {
838
+ continue;
839
+ }
840
+ const mappedConfigurationNames = new Set(Object.values(mapping.flowGraphMapping.configuration ?? {})
841
+ .filter((property) => (property.toBlock ? block.className === property.toBlock : provenance.role === 0))
842
+ .map((property) => property.name));
843
+ const ignoredConfigurationNames = new Set(["glTF"]);
844
+ for (const [key, value] of Object.entries(block.config ?? {})) {
845
+ if (mappedConfigurationNames.has(key) || ignoredConfigurationNames.has(key)) {
846
+ continue;
847
+ }
848
+ const normalizedValue = key === "eventData"
849
+ ? NormalizeInteractivityEventDataConfiguration(value)
850
+ : value !== null && typeof value === "object" && Object.prototype.hasOwnProperty.call(value, "value")
851
+ ? value.value
852
+ : value;
853
+ if (!_IsSerializableConfigurationValue(normalizedValue)) {
854
+ continue;
855
+ }
856
+ provenance.generatedConfiguration || (provenance.generatedConfiguration = {});
857
+ Object.defineProperty(provenance.generatedConfiguration, key, {
858
+ configurable: true,
859
+ enumerable: true,
860
+ value: _CloneMetadataValue(normalizedValue),
861
+ writable: true,
862
+ });
863
+ }
688
864
  }
689
865
  }
690
866
  _createNewSocketConnection(name, isOutput) {
@@ -709,9 +885,10 @@ export class InteractivityGraphToFlowGraphParser {
709
885
  * @param downstreamInput the data input socket that expects the time in frames
710
886
  * @param nodeIndex source node receiving the converted value
711
887
  * @param declarationIndex source declaration used by the receiving node
888
+ * @param operation owning KHR operation
712
889
  */
713
- _connectWithSecondsToFramesConversion(context, upstreamOutput, downstreamInput, nodeIndex, declarationIndex) {
714
- const multiplyBlock = this._getEmptyBlock("FlowGraphMultiplyBlock" /* FlowGraphBlockNames.Multiply */, "FlowGraphMultiplyBlock" /* FlowGraphBlockNames.Multiply */, nodeIndex, declarationIndex, -1);
890
+ _connectWithSecondsToFramesConversion(context, upstreamOutput, downstreamInput, nodeIndex, declarationIndex, operation) {
891
+ const multiplyBlock = this._getEmptyBlock("FlowGraphMultiplyBlock" /* FlowGraphBlockNames.Multiply */, operation, nodeIndex, declarationIndex, -1);
715
892
  // Scalar (float) multiply; matches how the `math/mul` mapping configures the block.
716
893
  multiplyBlock.config = { type: "number" /* FlowGraphTypes.Number */ };
717
894
  const inputA = this._createNewSocketConnection("a");
@@ -720,7 +897,9 @@ export class InteractivityGraphToFlowGraphParser {
720
897
  multiplyBlock.dataInputs.push(inputA, inputB);
721
898
  multiplyBlock.dataOutputs.push(output);
722
899
  // The second factor is the constant animation target fps.
723
- context._connectionValues[inputB.uniqueId] = { type: "number" /* FlowGraphTypes.Number */, value: [this._animationTargetFps] };
900
+ const frameRateValue = { type: "number" /* FlowGraphTypes.Number */, value: [this._animationTargetFps] };
901
+ context._connectionValues[inputB.uniqueId] = frameRateValue;
902
+ inputB.defaultValue = frameRateValue;
724
903
  // upstream time output -> multiply.a
725
904
  inputA.connectedPointIds.push(upstreamOutput.uniqueId);
726
905
  upstreamOutput.connectedPointIds.push(inputA.uniqueId);
@@ -776,6 +955,13 @@ export class InteractivityGraphToFlowGraphParser {
776
955
  const allBlocks = this._nodes.reduce((acc, val) => acc.concat(val.blocks), []).concat(this._insertedBlocks);
777
956
  return {
778
957
  name: this._interactivityGraph.name ?? `Graph ${this._graphIndex + 1}`,
958
+ metadata: {
959
+ khrInteractivity: {
960
+ graphIndex: this._graphIndex,
961
+ specificationCommit: KHR_INTERACTIVITY_SPECIFICATION_COMMIT,
962
+ source: CloneKHRInteractivityGraph(this._canonicalGraph),
963
+ },
964
+ },
779
965
  rightHanded: true,
780
966
  allBlocks,
781
967
  executionContexts: [context],