@vizij/node-graph-authoring 0.0.5 → 0.1.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.
@@ -1,7 +1,7 @@
1
1
  // src/state.ts
2
2
  import {
3
- cloneRemapSettings,
4
- SELF_BINDING_ID
3
+ SELF_BINDING_ID,
4
+ cloneDeepSafe
5
5
  } from "@vizij/utils";
6
6
  var VECTOR_ANIMATABLE_TYPES = /* @__PURE__ */ new Set(["vector2", "vector3", "euler", "rgb"]);
7
7
  function deriveComponentValueType(component) {
@@ -41,9 +41,6 @@ function bindingTargetFromInput(input) {
41
41
  valueType: "scalar"
42
42
  };
43
43
  }
44
- var DEFAULT_INPUT_RANGE = { min: -1, max: 1 };
45
- var DEFAULT_INPUT_ANCHOR = 0;
46
- var EPSILON = 1e-6;
47
44
  var LEGACY_SLOT_PATTERN = /^slot_(\d+)$/i;
48
45
  var ALIAS_SANITIZE_PATTERN = /[^A-Za-z0-9_]+/g;
49
46
  var PRIMARY_SLOT_ID = "s1";
@@ -119,131 +116,11 @@ function rewriteLegacyExpression(expression, replacements) {
119
116
  return `s${digits}`;
120
117
  });
121
118
  }
122
- function clamp(value, min, max) {
123
- return Math.min(max, Math.max(min, value));
124
- }
125
- function isFiniteNumber(value) {
126
- return typeof value === "number" && Number.isFinite(value);
127
- }
128
- function deriveOutputDefaults(target) {
129
- const { min, max } = target.range;
130
- const anchor = clamp(target.defaultValue, min, max);
131
- return {
132
- outLow: min,
133
- outAnchor: anchor,
134
- outHigh: max
135
- };
136
- }
137
- function deriveInputDefaults() {
138
- return {
139
- inLow: DEFAULT_INPUT_RANGE.min,
140
- inAnchor: DEFAULT_INPUT_ANCHOR,
141
- inHigh: DEFAULT_INPUT_RANGE.max
142
- };
143
- }
144
- function migrateLegacyRemap(legacy, target) {
145
- const inputDefaults = deriveInputDefaults();
146
- const outputDefaults = deriveOutputDefaults(target);
147
- const defaults = {
148
- inLow: inputDefaults.inLow,
149
- inAnchor: inputDefaults.inAnchor,
150
- inHigh: inputDefaults.inHigh,
151
- outLow: outputDefaults.outLow,
152
- outAnchor: outputDefaults.outAnchor,
153
- outHigh: outputDefaults.outHigh
154
- };
155
- if ("inLow" in legacy && "inHigh" in legacy && "outLow" in legacy && "outHigh" in legacy) {
156
- const inLow2 = isFiniteNumber(legacy.inLow) ? legacy.inLow : defaults.inLow;
157
- const inAnchor2 = isFiniteNumber(legacy.inAnchor) ? legacy.inAnchor : defaults.inAnchor;
158
- const inHigh2 = isFiniteNumber(legacy.inHigh) ? legacy.inHigh : defaults.inHigh;
159
- let outLow = isFiniteNumber(legacy.outLow) ? legacy.outLow : defaults.outLow;
160
- let outHigh = isFiniteNumber(legacy.outHigh) ? legacy.outHigh : defaults.outHigh;
161
- if (outLow > outHigh) {
162
- const low = outHigh;
163
- const high = outLow;
164
- outLow = low;
165
- outHigh = high;
166
- }
167
- const outAnchor2 = clamp(
168
- isFiniteNumber(legacy.outAnchor) ? legacy.outAnchor : defaults.outAnchor,
169
- outLow,
170
- outHigh
171
- );
172
- return {
173
- inLow: inLow2,
174
- inAnchor: inAnchor2,
175
- inHigh: inHigh2,
176
- outLow,
177
- outAnchor: outAnchor2,
178
- outHigh
179
- };
180
- }
181
- const legacyTyped = legacy;
182
- const inLow = isFiniteNumber(legacyTyped.inMin) ? legacyTyped.inMin : defaults.inLow;
183
- const inHigh = isFiniteNumber(legacyTyped.inMax) ? legacyTyped.inMax : defaults.inHigh;
184
- const inAnchor = (inLow + inHigh) / 2;
185
- const legacyOutMid = isFiniteNumber(legacyTyped.outMin) && isFiniteNumber(legacyTyped.outMax) ? (legacyTyped.outMin + legacyTyped.outMax) / 2 : defaults.outAnchor;
186
- const outAnchor = clamp(legacyOutMid, defaults.outLow, defaults.outHigh);
187
- return {
188
- inLow,
189
- inAnchor,
190
- inHigh,
191
- outLow: defaults.outLow,
192
- outAnchor,
193
- outHigh: defaults.outHigh
194
- };
195
- }
196
- function normalizeRemap(remap, target) {
197
- if (!remap) {
198
- return createDefaultRemap(target);
199
- }
200
- return migrateLegacyRemap(remap, target);
201
- }
202
- function cloneRemap(remap) {
203
- return cloneRemapSettings(remap);
204
- }
205
119
  function cloneBindingMetadata(metadata) {
206
120
  if (!metadata) {
207
121
  return void 0;
208
122
  }
209
- return JSON.parse(JSON.stringify(metadata));
210
- }
211
- function sanitizeRemap(remap, target) {
212
- const normalized = normalizeRemap(remap, target);
213
- const outputDefaults = deriveOutputDefaults(target);
214
- if (!Number.isFinite(normalized.outLow)) {
215
- normalized.outLow = outputDefaults.outLow;
216
- }
217
- if (!Number.isFinite(normalized.outHigh)) {
218
- normalized.outHigh = outputDefaults.outHigh;
219
- }
220
- if (!Number.isFinite(normalized.outAnchor)) {
221
- normalized.outAnchor = outputDefaults.outAnchor;
222
- }
223
- if (normalized.outLow > normalized.outHigh) {
224
- const low = normalized.outHigh;
225
- const high = normalized.outLow;
226
- normalized.outLow = low;
227
- normalized.outHigh = high;
228
- }
229
- normalized.outAnchor = clamp(
230
- normalized.outAnchor,
231
- normalized.outLow,
232
- normalized.outHigh
233
- );
234
- return normalized;
235
- }
236
- function createDefaultRemap(target) {
237
- const inputDefaults = deriveInputDefaults();
238
- const outputDefaults = deriveOutputDefaults(target);
239
- return {
240
- inLow: inputDefaults.inLow,
241
- inAnchor: inputDefaults.inAnchor,
242
- inHigh: inputDefaults.inHigh,
243
- outLow: outputDefaults.outLow,
244
- outAnchor: outputDefaults.outAnchor,
245
- outHigh: outputDefaults.outHigh
246
- };
123
+ return cloneDeepSafe(metadata);
247
124
  }
248
125
  function createDefaultBindings(components) {
249
126
  const bindings = {};
@@ -253,21 +130,18 @@ function createDefaultBindings(components) {
253
130
  return bindings;
254
131
  }
255
132
  function createDefaultBinding(component) {
256
- const remap = createDefaultRemap(component);
257
133
  const valueType = getTargetValueType(component);
258
134
  const slots = [
259
135
  {
260
136
  id: PRIMARY_SLOT_ID,
261
137
  alias: PRIMARY_SLOT_ALIAS,
262
138
  inputId: null,
263
- remap: cloneRemap(remap),
264
139
  valueType
265
140
  }
266
141
  ];
267
142
  return {
268
143
  targetId: component.id,
269
144
  inputId: null,
270
- remap,
271
145
  slots,
272
146
  expression: buildCanonicalExpressionFromSlots(slots)
273
147
  };
@@ -293,7 +167,6 @@ function createDefaultParentBinding(component) {
293
167
  };
294
168
  }
295
169
  function ensurePrimarySlot(binding, target) {
296
- const normalizedBindingRemap = sanitizeRemap(binding.remap, target);
297
170
  const targetValueType = getTargetValueType(target);
298
171
  const aliasReplacements = /* @__PURE__ */ new Map();
299
172
  const sourceSlots = Array.isArray(binding.slots) && binding.slots.length > 0 ? binding.slots : [
@@ -301,7 +174,6 @@ function ensurePrimarySlot(binding, target) {
301
174
  id: PRIMARY_SLOT_ID,
302
175
  alias: PRIMARY_SLOT_ALIAS,
303
176
  inputId: binding.inputId ?? null,
304
- remap: cloneRemap(normalizedBindingRemap),
305
177
  valueType: targetValueType
306
178
  }
307
179
  ];
@@ -316,8 +188,6 @@ function ensurePrimarySlot(binding, target) {
316
188
  if (replaced && replaced !== normalizedAlias) {
317
189
  aliasReplacements.set(replaced, normalizedAlias);
318
190
  }
319
- const slotRemapSource = slot.remap ?? (index === 0 ? normalizedBindingRemap : createDefaultRemap(target));
320
- const normalizedSlotRemap = sanitizeRemap(slotRemapSource, target);
321
191
  const inputId = slot.inputId !== void 0 && slot.inputId !== null ? slot.inputId : index === 0 ? binding.inputId ?? null : null;
322
192
  const slotValueType = sanitizeSlotValueType(
323
193
  slot.valueType,
@@ -327,13 +197,11 @@ function ensurePrimarySlot(binding, target) {
327
197
  id: normalizedId,
328
198
  alias: normalizedAlias,
329
199
  inputId,
330
- remap: cloneRemap(normalizedSlotRemap),
331
200
  valueType: slotValueType
332
201
  };
333
202
  }
334
203
  );
335
204
  const primary = normalizedSlots[0];
336
- const primaryRemap = sanitizeRemap(primary.remap, target);
337
205
  const primaryInputId = primary.inputId === SELF_BINDING_ID ? SELF_BINDING_ID : primary.inputId ?? binding.inputId ?? null;
338
206
  const primaryAlias = primaryInputId === SELF_BINDING_ID ? "self" : primary.alias || PRIMARY_SLOT_ALIAS;
339
207
  normalizedSlots[0] = {
@@ -341,16 +209,13 @@ function ensurePrimarySlot(binding, target) {
341
209
  id: primary.id || PRIMARY_SLOT_ID,
342
210
  alias: primaryAlias,
343
211
  inputId: primaryInputId,
344
- remap: cloneRemap(primaryRemap),
345
212
  valueType: sanitizeSlotValueType(primary.valueType, targetValueType)
346
213
  };
347
214
  normalizedSlots.slice(1).forEach((slot, index) => {
348
- const slotRemap = sanitizeRemap(slot.remap, target);
349
215
  normalizedSlots[index + 1] = {
350
216
  ...slot,
351
217
  id: slot.id || defaultSlotId(index + 1),
352
218
  alias: slot.alias || defaultSlotId(index + 1),
353
- remap: cloneRemap(slotRemap),
354
219
  valueType: sanitizeSlotValueType(slot.valueType, targetValueType)
355
220
  };
356
221
  });
@@ -365,7 +230,6 @@ function ensurePrimarySlot(binding, target) {
365
230
  const normalizedBinding = {
366
231
  ...binding,
367
232
  inputId: normalizedSlots[0].inputId ?? null,
368
- remap: cloneRemap(primaryRemap),
369
233
  slots: normalizedSlots,
370
234
  expression
371
235
  };
@@ -392,14 +256,13 @@ function addBindingSlot(binding, target) {
392
256
  const nextIndex = base.slots.length + 1;
393
257
  const slotId = defaultSlotId(nextIndex - 1);
394
258
  const alias = slotId;
395
- const remap = createDefaultRemap(target);
396
259
  const nextSlots = [
397
260
  ...base.slots,
398
261
  {
399
262
  id: slotId,
400
263
  alias,
401
264
  inputId: null,
402
- remap: cloneRemap(remap)
265
+ valueType: getTargetValueType(target)
403
266
  }
404
267
  ];
405
268
  return ensurePrimarySlot(
@@ -513,50 +376,6 @@ function updateBindingExpression(binding, target, expression) {
513
376
  expression: trimmed.length > 0 ? trimmed : canonicalExpression
514
377
  };
515
378
  }
516
- function updateBindingSlotRemap(binding, target, slotId, field, value) {
517
- const base = ensurePrimarySlot(binding, target);
518
- const existingExpression = typeof base.expression === "string" ? base.expression.trim() : "";
519
- const canonicalBefore = buildCanonicalExpressionFromSlots(base.slots);
520
- const expressionWasDefault = expressionMatchesAliasOnly(existingExpression, base.slots) || expressionsEquivalent(existingExpression, canonicalBefore);
521
- const nextSlots = base.slots.map((slot) => {
522
- if (slot.id !== slotId) {
523
- return slot;
524
- }
525
- const updatedRemap = {
526
- ...slot.remap,
527
- [field]: value
528
- };
529
- const sanitized = sanitizeRemap(updatedRemap, target);
530
- return {
531
- ...slot,
532
- remap: cloneRemap(sanitized)
533
- };
534
- });
535
- const updated = ensurePrimarySlot(
536
- {
537
- ...base,
538
- slots: nextSlots
539
- },
540
- target
541
- );
542
- if (updated.slots[0]?.id === slotId) {
543
- updated.remap = {
544
- ...updated.remap,
545
- [field]: value
546
- };
547
- }
548
- if (!expressionWasDefault) {
549
- return updated;
550
- }
551
- const canonicalAfter = buildCanonicalExpressionFromSlots(updated.slots);
552
- if (expressionsEquivalent(updated.expression ?? "", canonicalAfter)) {
553
- return updated;
554
- }
555
- return {
556
- ...updated,
557
- expression: canonicalAfter
558
- };
559
- }
560
379
  function updateBindingWithInput(binding, target, input, slotId = PRIMARY_SLOT_ID) {
561
380
  const base = ensurePrimarySlot(binding, target);
562
381
  const existingExpression = typeof base.expression === "string" ? base.expression.trim() : "";
@@ -564,39 +383,27 @@ function updateBindingWithInput(binding, target, input, slotId = PRIMARY_SLOT_ID
564
383
  const expressionWasDefault = expressionMatchesAliasOnly(existingExpression, base.slots) || expressionsEquivalent(existingExpression, canonicalBefore);
565
384
  const slotIndex = base.slots.findIndex((slot) => slot.id === slotId);
566
385
  const effectiveIndex = slotIndex >= 0 ? slotIndex : base.slots.length;
567
- const slots = base.slots.map((slot) => ({
568
- ...slot,
569
- remap: cloneRemap(slot.remap)
570
- }));
386
+ const slots = base.slots.map((slot) => ({ ...slot }));
571
387
  if (slotIndex === -1) {
572
388
  const alias = slotId === PRIMARY_SLOT_ID && slots.length === 0 ? PRIMARY_SLOT_ALIAS : slotId;
573
389
  slots.push({
574
390
  id: slotId,
575
391
  alias,
576
392
  inputId: null,
577
- remap: cloneRemap(createDefaultRemap(target))
393
+ valueType: getTargetValueType(target)
578
394
  });
579
395
  }
580
396
  const currentSlot = slots[effectiveIndex];
581
397
  let nextBinding;
582
398
  if (!input) {
583
- const normalizedSlotRemap = sanitizeRemap(currentSlot.remap, target);
584
- const updatedRemap = {
585
- ...normalizedSlotRemap,
586
- inLow: DEFAULT_INPUT_RANGE.min,
587
- inAnchor: DEFAULT_INPUT_ANCHOR,
588
- inHigh: DEFAULT_INPUT_RANGE.max
589
- };
590
399
  slots[effectiveIndex] = {
591
400
  ...currentSlot,
592
- inputId: null,
593
- remap: cloneRemap(updatedRemap)
401
+ inputId: null
594
402
  };
595
403
  if (effectiveIndex === 0) {
596
404
  nextBinding = {
597
405
  ...base,
598
406
  inputId: null,
599
- remap: cloneRemap(updatedRemap),
600
407
  slots
601
408
  };
602
409
  } else {
@@ -606,24 +413,14 @@ function updateBindingWithInput(binding, target, input, slotId = PRIMARY_SLOT_ID
606
413
  };
607
414
  }
608
415
  } else {
609
- const normalizedRemap = sanitizeRemap(currentSlot.remap, target);
610
- const updatedRemap = {
611
- ...normalizedRemap,
612
- inLow: input.range.min,
613
- inAnchor: clamp(input.defaultValue, input.range.min, input.range.max),
614
- inHigh: input.range.max,
615
- ...deriveOutputDefaults(target)
616
- };
617
416
  slots[effectiveIndex] = {
618
417
  ...currentSlot,
619
- inputId: input.id,
620
- remap: cloneRemap(updatedRemap)
418
+ inputId: input.id
621
419
  };
622
420
  if (effectiveIndex === 0) {
623
421
  nextBinding = {
624
422
  ...base,
625
423
  inputId: input.id,
626
- remap: cloneRemap(updatedRemap),
627
424
  slots
628
425
  };
629
426
  } else {
@@ -645,26 +442,6 @@ function updateBindingWithInput(binding, target, input, slotId = PRIMARY_SLOT_ID
645
442
  expression: canonicalAfter
646
443
  };
647
444
  }
648
- function remapValue(value, remap) {
649
- const { inLow, inAnchor, inHigh, outLow, outAnchor, outHigh } = remap;
650
- if (Number.isNaN(value)) {
651
- return outAnchor;
652
- }
653
- if (value <= inAnchor) {
654
- const span2 = inAnchor - inLow;
655
- if (Math.abs(span2) < EPSILON) {
656
- return outLow;
657
- }
658
- const t2 = (value - inLow) / span2;
659
- return outLow + t2 * (outAnchor - outLow);
660
- }
661
- const span = inHigh - inAnchor;
662
- if (Math.abs(span) < EPSILON) {
663
- return outHigh;
664
- }
665
- const t = (value - inAnchor) / span;
666
- return outAnchor + t * (outHigh - outAnchor);
667
- }
668
445
  function reconcileBindings(previous, components) {
669
446
  const next = {};
670
447
  components.forEach((component) => {
@@ -682,12 +459,10 @@ function reconcileBindings(previous, components) {
682
459
  if (replaced && replaced !== normalizedAlias) {
683
460
  aliasReplacements.set(replaced, normalizedAlias);
684
461
  }
685
- const slotRemap = sanitizeRemap(slot.remap, component);
686
462
  return {
687
463
  ...slot,
688
464
  id: normalizedId,
689
- alias: normalizedAlias,
690
- remap: cloneRemap(slotRemap)
465
+ alias: normalizedAlias
691
466
  };
692
467
  });
693
468
  const primary = slots[0];
@@ -697,7 +472,6 @@ function reconcileBindings(previous, components) {
697
472
  ...ensured,
698
473
  targetId: component.id,
699
474
  inputId: primary.inputId ?? null,
700
- remap: cloneRemap(primary.remap),
701
475
  slots,
702
476
  expression
703
477
  };
@@ -710,11 +484,7 @@ function reconcileBindings(previous, components) {
710
484
  function bindingToDefinition(binding) {
711
485
  const definition = {
712
486
  inputId: binding.inputId ?? null,
713
- remap: cloneRemap(binding.remap),
714
- slots: binding.slots.map((slot) => ({
715
- ...slot,
716
- remap: cloneRemap(slot.remap)
717
- })),
487
+ slots: binding.slots.map((slot) => ({ ...slot })),
718
488
  expression: binding.expression,
719
489
  metadata: cloneBindingMetadata(binding.metadata)
720
490
  };
@@ -727,46 +497,12 @@ function bindingFromDefinition(target, definition) {
727
497
  const binding = {
728
498
  targetId: target.id,
729
499
  inputId: definition.inputId ?? null,
730
- remap: cloneRemap(definition.remap),
731
- slots: definition.slots.map((slot) => ({
732
- ...slot,
733
- remap: cloneRemap(slot.remap)
734
- })),
500
+ slots: definition.slots.map((slot) => ({ ...slot })),
735
501
  expression: definition.expression,
736
502
  metadata: cloneBindingMetadata(definition.metadata)
737
503
  };
738
504
  return ensureBindingStructure(binding, target);
739
505
  }
740
- function sanitizeLiteral(value) {
741
- if (!Number.isFinite(value)) {
742
- return 0;
743
- }
744
- if (Object.is(value, -0)) {
745
- return 0;
746
- }
747
- return value;
748
- }
749
- function formatVectorLiteral(values) {
750
- return `vec(${values.map((value) => sanitizeLiteral(value)).join(", ")})`;
751
- }
752
- function buildPiecewiseRemapExpression(alias, remap) {
753
- const sanitizedAlias = alias && alias.trim().length > 0 ? alias.trim() : PRIMARY_SLOT_ALIAS;
754
- const inputBreakpoints = [remap.inLow, remap.inAnchor, remap.inHigh];
755
- const outputBreakpoints = [remap.outLow, remap.outAnchor, remap.outHigh];
756
- return `piecewise_remap(${sanitizedAlias}, ${formatVectorLiteral(
757
- inputBreakpoints
758
- )}, ${formatVectorLiteral(outputBreakpoints)})`;
759
- }
760
- function isSelfAlias(alias) {
761
- return alias.trim().toLowerCase() === "self";
762
- }
763
- function buildDefaultSlotExpression(alias, inputId, remap) {
764
- const sanitizedAlias = alias && alias.trim().length > 0 ? alias.trim() : PRIMARY_SLOT_ALIAS;
765
- if (inputId === SELF_BINDING_ID || isSelfAlias(sanitizedAlias)) {
766
- return sanitizedAlias;
767
- }
768
- return buildPiecewiseRemapExpression(sanitizedAlias, remap);
769
- }
770
506
  function normalizeSlotAliasForExpression(slot, index) {
771
507
  if (slot.alias && slot.alias.trim().length > 0) {
772
508
  return slot.alias.trim();
@@ -783,16 +519,7 @@ function buildAliasOnlyExpression(slots) {
783
519
  return slots.map((slot, index) => normalizeSlotAliasForExpression(slot, index)).join(" + ");
784
520
  }
785
521
  function buildCanonicalExpressionFromSlots(slots) {
786
- if (!slots.length) {
787
- return PRIMARY_SLOT_ALIAS;
788
- }
789
- return slots.map(
790
- (slot, index) => buildDefaultSlotExpression(
791
- normalizeSlotAliasForExpression(slot, index),
792
- slot.inputId ?? null,
793
- slot.remap
794
- )
795
- ).join(" + ");
522
+ return buildAliasOnlyExpression(slots);
796
523
  }
797
524
  function expressionsEquivalent(left, right) {
798
525
  return left.trim() === right.trim();
@@ -1903,9 +1630,7 @@ var DefaultExpressionVariableTable = class {
1903
1630
  targetId: options.targetId,
1904
1631
  animatableId: options.animatableId,
1905
1632
  component: options.component,
1906
- valueType: options.valueType,
1907
- remap: options.remap,
1908
- autoRemap: options.autoRemap
1633
+ valueType: options.valueType
1909
1634
  }
1910
1635
  });
1911
1636
  }
@@ -2088,12 +1813,12 @@ function createLegacyIrGraph(payload) {
2088
1813
  function toIrBindingSummary(summaries) {
2089
1814
  return summaries.map((summary) => ({
2090
1815
  ...summary,
2091
- remap: { ...summary.remap },
2092
1816
  issues: summary.issues ? [...summary.issues] : void 0
2093
1817
  }));
2094
1818
  }
2095
1819
 
2096
1820
  // src/ir/compiler.ts
1821
+ import { cloneDeepSafe as cloneDeepSafe2 } from "@vizij/utils";
2097
1822
  function compileIrGraph(graph, options = {}) {
2098
1823
  const preferLegacy = options.preferLegacySpec === true;
2099
1824
  const legacySpec = graph.legacy?.spec;
@@ -2178,7 +1903,7 @@ function cloneJsonLike(value) {
2178
1903
  if (value === void 0 || value === null) {
2179
1904
  return value;
2180
1905
  }
2181
- return JSON.parse(JSON.stringify(value));
1906
+ return cloneDeepSafe2(value);
2182
1907
  }
2183
1908
  function inlineSingleUseConstants(spec) {
2184
1909
  const nodes = spec.nodes ?? [];
@@ -2217,13 +1942,25 @@ function inlineSingleUseConstants(spec) {
2217
1942
  }
2218
1943
 
2219
1944
  // src/graphBuilder.ts
2220
- import { buildAnimatableValue } from "@vizij/utils";
1945
+ import {
1946
+ RIG_PIPELINE_V1_VERSION,
1947
+ buildAnimatableValue,
1948
+ cloneDeepSafe as cloneDeepSafe4,
1949
+ hasRigPipelineV1InputConfig,
1950
+ isRigElementStandardInputPath,
1951
+ normalizeStandardRigInputPath,
1952
+ resolveRigPipelineV1InputConfig,
1953
+ resolveStandardRigInputId
1954
+ } from "@vizij/utils";
2221
1955
  import { SELF_BINDING_ID as SELF_BINDING_ID2 } from "@vizij/utils";
2222
1956
  import { nodeRegistryVersion } from "@vizij/node-graph-wasm/metadata";
2223
1957
 
2224
1958
  // src/bindingMetadata.ts
1959
+ import {
1960
+ cloneDeepSafe as cloneDeepSafe3
1961
+ } from "@vizij/utils";
2225
1962
  function cloneOperand(entry) {
2226
- return JSON.parse(JSON.stringify(entry));
1963
+ return cloneDeepSafe3(entry);
2227
1964
  }
2228
1965
  function describeSlot(entry) {
2229
1966
  const metadata = entry.metadata;
@@ -2265,17 +2002,17 @@ function describeReference(node, variables) {
2265
2002
  function stringifyExpression(node) {
2266
2003
  switch (node.type) {
2267
2004
  case "Literal":
2268
- return Number.isFinite(node.value) ? `${node.value}` : "0";
2005
+ return Number.isFinite(node.value) ? `${node.value} ` : "0";
2269
2006
  case "VectorLiteral":
2270
2007
  return `vec(${node.values.join(", ")})`;
2271
2008
  case "Reference":
2272
2009
  return node.name;
2273
2010
  case "Unary":
2274
- return `${node.operator}${stringifyExpression(node.operand)}`;
2011
+ return `${node.operator}${stringifyExpression(node.operand)} `;
2275
2012
  case "Binary":
2276
- return `${stringifyExpression(node.left)} ${node.operator} ${stringifyExpression(node.right)}`;
2013
+ return `${stringifyExpression(node.left)} ${node.operator} ${stringifyExpression(node.right)} `;
2277
2014
  case "Function":
2278
- return `${node.name}(${node.args.map(stringifyExpression).join(", ")})`;
2015
+ return `${node.name} (${node.args.map(stringifyExpression).join(", ")})`;
2279
2016
  default:
2280
2017
  return "";
2281
2018
  }
@@ -2340,6 +2077,61 @@ function buildBindingMetadataFromExpression(node, variables) {
2340
2077
  }
2341
2078
 
2342
2079
  // src/graphBuilder.ts
2080
+ function resolveBindingSlotInputId(bindingInputId, inputsById) {
2081
+ if (!bindingInputId || bindingInputId === SELF_BINDING_ID2) {
2082
+ return bindingInputId;
2083
+ }
2084
+ const resolvedInputId = resolveStandardRigInputId(bindingInputId, inputsById);
2085
+ if (inputsById.has(resolvedInputId)) {
2086
+ return resolvedInputId;
2087
+ }
2088
+ return bindingInputId;
2089
+ }
2090
+ function isRigElementAliasInput(inputId, inputsById) {
2091
+ const input = inputsById.get(inputId);
2092
+ if (!input?.path) {
2093
+ return false;
2094
+ }
2095
+ return isRigElementStandardInputPath(input.path);
2096
+ }
2097
+ function isHigherOrderRigBindingInput(inputId, inputsById) {
2098
+ const input = inputsById.get(inputId);
2099
+ if (!input?.path) {
2100
+ return false;
2101
+ }
2102
+ if (isRigElementAliasInput(inputId, inputsById)) {
2103
+ return false;
2104
+ }
2105
+ return true;
2106
+ }
2107
+ function bindingReferencesRigElementInput(binding, inputsById) {
2108
+ const candidateInputIds = /* @__PURE__ */ new Set();
2109
+ if (binding.inputId && binding.inputId !== SELF_BINDING_ID2) {
2110
+ candidateInputIds.add(binding.inputId);
2111
+ }
2112
+ binding.slots.forEach((slot) => {
2113
+ if (slot.inputId && slot.inputId !== SELF_BINDING_ID2) {
2114
+ candidateInputIds.add(slot.inputId);
2115
+ }
2116
+ });
2117
+ for (const candidateInputId of candidateInputIds) {
2118
+ if (isRigElementStandardInputPath(candidateInputId)) {
2119
+ return true;
2120
+ }
2121
+ const resolvedCandidateId = resolveBindingSlotInputId(
2122
+ candidateInputId,
2123
+ inputsById
2124
+ );
2125
+ if (!resolvedCandidateId || resolvedCandidateId === SELF_BINDING_ID2) {
2126
+ continue;
2127
+ }
2128
+ const resolvedInput = inputsById.get(resolvedCandidateId);
2129
+ if (resolvedInput && isRigElementStandardInputPath(resolvedInput.path)) {
2130
+ return true;
2131
+ }
2132
+ }
2133
+ return false;
2134
+ }
2343
2135
  function evaluateBinding({
2344
2136
  binding,
2345
2137
  target,
@@ -2348,9 +2140,18 @@ function evaluateBinding({
2348
2140
  component,
2349
2141
  safeId,
2350
2142
  context,
2351
- selfNodeId
2143
+ selfNodeId,
2144
+ enforceRigBoundaryRules = false
2352
2145
  }) {
2353
- const { nodes, edges, ensureInputNode, bindingIssues, summaryBindings } = context;
2146
+ const {
2147
+ nodes,
2148
+ edges,
2149
+ ensureInputNode,
2150
+ bindingIssues,
2151
+ summaryBindings,
2152
+ inputsById,
2153
+ inputBindings
2154
+ } = context;
2354
2155
  const exprContext = {
2355
2156
  componentSafeId: safeId,
2356
2157
  nodes,
@@ -2359,7 +2160,6 @@ function evaluateBinding({
2359
2160
  counter: 0,
2360
2161
  reservedNodes: /* @__PURE__ */ new Map(),
2361
2162
  nodeValueTypes: /* @__PURE__ */ new Map(),
2362
- slotRemapNodes: /* @__PURE__ */ new Map(),
2363
2163
  graphReservedNodes: context.graphReservedNodes,
2364
2164
  generateReservedNodeId: context.generateReservedNodeId
2365
2165
  };
@@ -2375,6 +2175,10 @@ function evaluateBinding({
2375
2175
  const fallbackAlias = `s${index + 1}`;
2376
2176
  const alias = aliasBase.length > 0 ? aliasBase : fallbackAlias;
2377
2177
  const slotId = slot.id && slot.id.length > 0 ? slot.id : alias;
2178
+ const resolvedSlotInputId = resolveBindingSlotInputId(
2179
+ slot.inputId,
2180
+ inputsById
2181
+ );
2378
2182
  const slotValueType = slot.valueType === "vector" ? "vector" : "scalar";
2379
2183
  let slotOutputId;
2380
2184
  if (slot.inputId === SELF_BINDING_ID2) {
@@ -2390,19 +2194,30 @@ function evaluateBinding({
2390
2194
  expressionIssues.push("Self reference unavailable for this input.");
2391
2195
  slotOutputId = getConstantNodeId(exprContext, target.defaultValue);
2392
2196
  }
2393
- } else if (slot.inputId) {
2394
- const inputNode = ensureInputNode(slot.inputId);
2395
- if (inputNode) {
2396
- slotOutputId = inputNode.nodeId;
2397
- hasActiveSlot = true;
2398
- setNodeValueType(
2399
- exprContext,
2400
- slotOutputId,
2401
- slotValueType === "vector" ? "vector" : "scalar"
2197
+ } else if (resolvedSlotInputId) {
2198
+ const inputId = resolvedSlotInputId;
2199
+ const sourceBinding = inputBindings[inputId];
2200
+ const allowedHigherOrderViaRigElementSource = sourceBinding !== void 0 && bindingReferencesRigElementInput(sourceBinding, inputsById);
2201
+ if (enforceRigBoundaryRules && isHigherOrderRigBindingInput(inputId, inputsById) && !allowedHigherOrderViaRigElementSource && inputId !== SELF_BINDING_ID2) {
2202
+ expressionIssues.push(
2203
+ `Input "${inputId}" is a higher-order rig input and cannot directly drive animatable "${target.id}".`
2402
2204
  );
2403
- } else {
2404
- expressionIssues.push(`Missing standard input "${slot.inputId}".`);
2405
2205
  slotOutputId = getConstantNodeId(exprContext, 0);
2206
+ hasActiveSlot = true;
2207
+ } else {
2208
+ const inputNode = ensureInputNode(inputId);
2209
+ if (inputNode) {
2210
+ slotOutputId = inputNode.nodeId;
2211
+ hasActiveSlot = true;
2212
+ setNodeValueType(
2213
+ exprContext,
2214
+ slotOutputId,
2215
+ slotValueType === "vector" ? "vector" : "scalar"
2216
+ );
2217
+ } else {
2218
+ expressionIssues.push(`Missing standard input "${inputId}".`);
2219
+ slotOutputId = getConstantNodeId(exprContext, 0);
2220
+ }
2406
2221
  }
2407
2222
  } else {
2408
2223
  slotOutputId = getConstantNodeId(exprContext, 0);
@@ -2412,13 +2227,11 @@ function evaluateBinding({
2412
2227
  nodeId: slotOutputId,
2413
2228
  slotId,
2414
2229
  slotAlias: alias,
2415
- inputId: slot.inputId ?? null,
2230
+ inputId: resolvedSlotInputId ?? null,
2416
2231
  targetId,
2417
2232
  animatableId,
2418
2233
  component,
2419
- valueType: slotValueType,
2420
- remap: { ...slot.remap },
2421
- autoRemap: slot.inputId !== SELF_BINDING_ID2 && slotValueType === "scalar"
2234
+ valueType: slotValueType
2422
2235
  });
2423
2236
  setNodeValueType(
2424
2237
  exprContext,
@@ -2431,8 +2244,7 @@ function evaluateBinding({
2431
2244
  component,
2432
2245
  slotId,
2433
2246
  slotAlias: alias,
2434
- inputId: slot.inputId ?? null,
2435
- remap: { ...slot.remap },
2247
+ inputId: resolvedSlotInputId ?? null,
2436
2248
  expression: trimmedExpression,
2437
2249
  valueType: slotValueType,
2438
2250
  nodeId: slotOutputId,
@@ -2451,9 +2263,7 @@ function evaluateBinding({
2451
2263
  targetId,
2452
2264
  animatableId,
2453
2265
  component,
2454
- valueType: targetValueType,
2455
- remap: createDefaultRemap(target),
2456
- autoRemap: false
2266
+ valueType: targetValueType
2457
2267
  });
2458
2268
  setNodeValueType(
2459
2269
  exprContext,
@@ -2467,7 +2277,6 @@ function evaluateBinding({
2467
2277
  slotId: PRIMARY_SLOT_ID,
2468
2278
  slotAlias: alias,
2469
2279
  inputId: null,
2470
- remap: createDefaultRemap(target),
2471
2280
  expression: trimmedExpression,
2472
2281
  valueType: targetValueType,
2473
2282
  nodeId: constantId,
@@ -2582,6 +2391,20 @@ function buildRigInputPath(faceId, inputPath) {
2582
2391
  const suffix = trimmed ? `/${trimmed}` : "";
2583
2392
  return `rig/${faceId}${suffix}`;
2584
2393
  }
2394
+ function buildPoseControlInputPath(faceId, inputId) {
2395
+ return `rig/${faceId}/pose/control/${inputId}`;
2396
+ }
2397
+ function isPoseWeightInputPath(path) {
2398
+ const normalized = normalizeStandardRigInputPath(path);
2399
+ return normalized.startsWith("/poses/") && normalized.endsWith(".weight");
2400
+ }
2401
+ function isPoseControlPath(path) {
2402
+ const normalized = normalizeStandardRigInputPath(path);
2403
+ return normalized.startsWith("/pose/control/");
2404
+ }
2405
+ function resolveInputComposeMode(mode) {
2406
+ return mode === "average" ? "average" : "add";
2407
+ }
2585
2408
  function getComponentOrder(animatable) {
2586
2409
  switch (animatable.type) {
2587
2410
  case "vector2":
@@ -2664,73 +2487,6 @@ function ensureOperandValueType(context, operandId, expected, functionName, inpu
2664
2487
  `Function "${functionName}" expects ${expectation} input for "${inputId}", but the expression produced ${actual}.`
2665
2488
  );
2666
2489
  }
2667
- function resolveSlotReferenceNode(entry, fallbackNodeId, context) {
2668
- if (entry.kind !== "slot") {
2669
- return fallbackNodeId;
2670
- }
2671
- const metadata = entry.metadata;
2672
- if (!metadata || metadata.autoRemap === false || !metadata.remap) {
2673
- return fallbackNodeId;
2674
- }
2675
- if (metadata.valueType !== "scalar") {
2676
- return fallbackNodeId;
2677
- }
2678
- if (isIdentityRemap(metadata.remap)) {
2679
- return fallbackNodeId;
2680
- }
2681
- const cacheKey = metadata.slotId ?? entry.name;
2682
- const existing = context.slotRemapNodes.get(cacheKey);
2683
- if (existing) {
2684
- return existing;
2685
- }
2686
- const remapNodeId = createSlotRemapNode(
2687
- context,
2688
- fallbackNodeId,
2689
- metadata.remap,
2690
- metadata.slotAlias ?? cacheKey
2691
- );
2692
- context.slotRemapNodes.set(cacheKey, remapNodeId);
2693
- return remapNodeId;
2694
- }
2695
- function createSlotRemapNode(context, sourceNodeId, remap, slotKey) {
2696
- const safeSlotKey = sanitizeNodeId(slotKey || "slot");
2697
- const nodeId = `slot_remap_${safeSlotKey}_${context.counter++}`;
2698
- context.nodes.push({
2699
- id: nodeId,
2700
- type: "centered_remap",
2701
- inputDefaults: {
2702
- in_low: remap.inLow,
2703
- in_anchor: remap.inAnchor,
2704
- in_high: remap.inHigh,
2705
- out_low: remap.outLow,
2706
- out_anchor: remap.outAnchor,
2707
- out_high: remap.outHigh
2708
- }
2709
- });
2710
- context.edges.push({
2711
- from: { nodeId: sourceNodeId },
2712
- to: { nodeId, portId: "in" }
2713
- });
2714
- setNodeValueType(context, nodeId, "scalar");
2715
- return nodeId;
2716
- }
2717
- function isIdentityRemap(remap) {
2718
- return nearlyEqual(remap.inLow, remap.outLow) && nearlyEqual(remap.inAnchor, remap.outAnchor) && nearlyEqual(remap.inHigh, remap.outHigh);
2719
- }
2720
- function nearlyEqual(a, b, epsilon = 1e-4) {
2721
- return Math.abs(a - b) <= epsilon;
2722
- }
2723
- var REMAP_FUNCTION_NODE_TYPES = /* @__PURE__ */ new Set([
2724
- "piecewise_remap",
2725
- "centered_remap",
2726
- "remap"
2727
- ]);
2728
- function shouldSkipAutoRemapForArgument(nodeType, index) {
2729
- if (!REMAP_FUNCTION_NODE_TYPES.has(nodeType)) {
2730
- return false;
2731
- }
2732
- return index === 0;
2733
- }
2734
2490
  function getConstantNodeId(context, value) {
2735
2491
  const key = Number.isFinite(value) ? value.toString() : "NaN";
2736
2492
  const existing = context.constants.get(key);
@@ -3189,8 +2945,7 @@ var BINARY_FUNCTION_OPERATOR_MAP = {
3189
2945
  "&&": "and",
3190
2946
  "||": "or"
3191
2947
  };
3192
- function materializeExpression(node, context, variables, issues, options) {
3193
- const autoRemap = options?.autoRemap !== false;
2948
+ function materializeExpression(node, context, variables, issues) {
3194
2949
  switch (node.type) {
3195
2950
  case "Literal": {
3196
2951
  return getConstantNodeId(context, node.value);
@@ -3205,10 +2960,7 @@ function materializeExpression(node, context, variables, issues, options) {
3205
2960
  return getConstantNodeId(context, 0);
3206
2961
  }
3207
2962
  const mappedId = entry.nodeId ?? getConstantNodeId(context, 0);
3208
- if (!autoRemap || entry.kind !== "slot") {
3209
- return mappedId;
3210
- }
3211
- return resolveSlotReferenceNode(entry, mappedId, context);
2963
+ return mappedId;
3212
2964
  }
3213
2965
  case "Unary": {
3214
2966
  const operandId = materializeExpression(
@@ -3346,13 +3098,7 @@ function materializeExpression(node, context, variables, issues, options) {
3346
3098
  );
3347
3099
  const operandNodes = argNodes.slice(0, operandLimit);
3348
3100
  const operands = operandNodes.map(
3349
- (arg, index) => materializeExpression(
3350
- arg,
3351
- context,
3352
- variables,
3353
- issues,
3354
- shouldSkipAutoRemapForArgument(definition.nodeType, index) ? { autoRemap: false } : void 0
3355
- )
3101
+ (arg, _index) => materializeExpression(arg, context, variables, issues)
3356
3102
  );
3357
3103
  const paramArgStart = operandLimit;
3358
3104
  const paramArgNodes = paramArgCount > 0 ? argNodes.slice(paramArgStart, paramArgStart + paramArgCount) : [];
@@ -3381,7 +3127,9 @@ function buildRigGraphSpec({
3381
3127
  bindings,
3382
3128
  inputsById,
3383
3129
  inputBindings,
3384
- inputMetadata
3130
+ inputMetadata,
3131
+ inputComposeModesById,
3132
+ pipelineV1
3385
3133
  }) {
3386
3134
  const metadataByInputId = inputMetadata ?? /* @__PURE__ */ new Map();
3387
3135
  const irBuilder = createIrGraphBuilder({
@@ -3404,8 +3152,634 @@ function buildRigGraphSpec({
3404
3152
  const computedInputs = /* @__PURE__ */ new Set();
3405
3153
  const summaryBindings = [];
3406
3154
  const bindingIssues = /* @__PURE__ */ new Map();
3155
+ const stagedPipelineByInputId = /* @__PURE__ */ new Map();
3407
3156
  const animatableEntries = /* @__PURE__ */ new Map();
3408
3157
  const outputs = /* @__PURE__ */ new Set();
3158
+ const composeModeByInputId = /* @__PURE__ */ new Map();
3159
+ Object.entries(inputComposeModesById ?? {}).forEach(([inputId, mode]) => {
3160
+ if (!inputsById.has(inputId)) {
3161
+ return;
3162
+ }
3163
+ composeModeByInputId.set(inputId, resolveInputComposeMode(mode));
3164
+ });
3165
+ const shouldComposeInputWithPoseControl = (input) => {
3166
+ if (!composeModeByInputId.has(input.id)) {
3167
+ return false;
3168
+ }
3169
+ if (isPoseWeightInputPath(input.path)) {
3170
+ return false;
3171
+ }
3172
+ if (isPoseControlPath(input.path)) {
3173
+ return false;
3174
+ }
3175
+ return true;
3176
+ };
3177
+ const buildNormalizedAdditiveBlendNodeId = ({
3178
+ nodeIdPrefix,
3179
+ sourceNodeIds,
3180
+ baseline
3181
+ }) => {
3182
+ if (sourceNodeIds.length === 0) {
3183
+ const fallbackNodeId = `${nodeIdPrefix}_baseline`;
3184
+ nodes.push({
3185
+ id: fallbackNodeId,
3186
+ type: "constant",
3187
+ params: {
3188
+ value: baseline
3189
+ }
3190
+ });
3191
+ return fallbackNodeId;
3192
+ }
3193
+ if (sourceNodeIds.length === 1) {
3194
+ return sourceNodeIds[0];
3195
+ }
3196
+ const addNodeId = `${nodeIdPrefix}_add`;
3197
+ nodes.push({
3198
+ id: addNodeId,
3199
+ type: "add"
3200
+ });
3201
+ sourceNodeIds.forEach((sourceNodeId, index) => {
3202
+ edges.push({
3203
+ from: { nodeId: sourceNodeId },
3204
+ to: { nodeId: addNodeId, portId: `operand_${index + 1}` }
3205
+ });
3206
+ });
3207
+ const normalizedNodeId = `${nodeIdPrefix}_normalized_add`;
3208
+ nodes.push({
3209
+ id: normalizedNodeId,
3210
+ type: "subtract",
3211
+ inputDefaults: {
3212
+ rhs: (sourceNodeIds.length - 1) * baseline
3213
+ }
3214
+ });
3215
+ edges.push({
3216
+ from: { nodeId: addNodeId },
3217
+ to: { nodeId: normalizedNodeId, portId: "lhs" }
3218
+ });
3219
+ return normalizedNodeId;
3220
+ };
3221
+ const splitTopLevelCommaSeparated = (value) => {
3222
+ const segments = [];
3223
+ let depthParen = 0;
3224
+ let depthBracket = 0;
3225
+ let start = 0;
3226
+ for (let index = 0; index < value.length; index += 1) {
3227
+ const char = value[index];
3228
+ if (char === "(") {
3229
+ depthParen += 1;
3230
+ continue;
3231
+ }
3232
+ if (char === ")") {
3233
+ depthParen = Math.max(0, depthParen - 1);
3234
+ continue;
3235
+ }
3236
+ if (char === "[") {
3237
+ depthBracket += 1;
3238
+ continue;
3239
+ }
3240
+ if (char === "]") {
3241
+ depthBracket = Math.max(0, depthBracket - 1);
3242
+ continue;
3243
+ }
3244
+ if (char === "," && depthParen === 0 && depthBracket === 0) {
3245
+ segments.push(value.slice(start, index));
3246
+ start = index + 1;
3247
+ }
3248
+ }
3249
+ segments.push(value.slice(start));
3250
+ return segments;
3251
+ };
3252
+ const stripTopLevelAssignment = (value) => {
3253
+ let depthParen = 0;
3254
+ let depthBracket = 0;
3255
+ for (let index = 0; index < value.length; index += 1) {
3256
+ const char = value[index];
3257
+ if (char === "(") {
3258
+ depthParen += 1;
3259
+ continue;
3260
+ }
3261
+ if (char === ")") {
3262
+ depthParen = Math.max(0, depthParen - 1);
3263
+ continue;
3264
+ }
3265
+ if (char === "[") {
3266
+ depthBracket += 1;
3267
+ continue;
3268
+ }
3269
+ if (char === "]") {
3270
+ depthBracket = Math.max(0, depthBracket - 1);
3271
+ continue;
3272
+ }
3273
+ if (char !== "=" || depthParen !== 0 || depthBracket !== 0) {
3274
+ continue;
3275
+ }
3276
+ const previous = value[index - 1];
3277
+ const next = value[index + 1];
3278
+ if (previous === "=" || next === "=") {
3279
+ continue;
3280
+ }
3281
+ return value.slice(index + 1).trim();
3282
+ }
3283
+ return value.trim();
3284
+ };
3285
+ const isNormalizedAdditiveFunctionName = (value) => {
3286
+ const normalized = value.trim().toLowerCase();
3287
+ return normalized === "normalizedadditive" || normalized === "normalizedaddative" || normalized === "noramalizedadditive" || normalized === "noramalizedaddative";
3288
+ };
3289
+ const buildNormalizedAdditiveExpression = (value) => {
3290
+ const args = splitTopLevelCommaSeparated(value).map(
3291
+ (entry) => entry.trim()
3292
+ );
3293
+ if (args.length === 0) {
3294
+ return "default";
3295
+ }
3296
+ const parentTerms = [];
3297
+ let baselineExpression = "default";
3298
+ const firstArg = args[0];
3299
+ if (firstArg && firstArg.startsWith("[") && firstArg.endsWith("]")) {
3300
+ const inner = firstArg.slice(1, -1).trim();
3301
+ if (inner.length > 0) {
3302
+ splitTopLevelCommaSeparated(inner).forEach((entry) => {
3303
+ const term = entry.trim();
3304
+ if (term.length > 0) {
3305
+ parentTerms.push(term);
3306
+ }
3307
+ });
3308
+ }
3309
+ args.slice(1).forEach((entry) => {
3310
+ const baselineMatch = entry.match(/^baseline\s*=\s*(.+)$/i);
3311
+ if (baselineMatch?.[1]) {
3312
+ baselineExpression = baselineMatch[1].trim();
3313
+ return;
3314
+ }
3315
+ const term = entry.trim();
3316
+ if (term.length > 0) {
3317
+ parentTerms.push(term);
3318
+ }
3319
+ });
3320
+ } else {
3321
+ args.forEach((entry) => {
3322
+ const baselineMatch = entry.match(/^baseline\s*=\s*(.+)$/i);
3323
+ if (baselineMatch?.[1]) {
3324
+ baselineExpression = baselineMatch[1].trim();
3325
+ return;
3326
+ }
3327
+ const term = entry.trim();
3328
+ if (term.length > 0) {
3329
+ parentTerms.push(term);
3330
+ }
3331
+ });
3332
+ }
3333
+ if (parentTerms.length === 0) {
3334
+ return `(${baselineExpression})`;
3335
+ }
3336
+ if (parentTerms.length === 1) {
3337
+ return `(${parentTerms[0]})`;
3338
+ }
3339
+ return `((${parentTerms.join(" + ")}) - (${parentTerms.length - 1}) * (${baselineExpression}))`;
3340
+ };
3341
+ const rewriteNormalizedAdditiveCalls = (value) => {
3342
+ let cursor = 0;
3343
+ let rewritten = "";
3344
+ while (cursor < value.length) {
3345
+ const remaining = value.slice(cursor);
3346
+ const match = remaining.match(
3347
+ /(normalizedadditive|normalizedaddative|noramalizedadditive|noramalizedaddative)\s*\(/i
3348
+ );
3349
+ if (!match || match.index === void 0) {
3350
+ rewritten += remaining;
3351
+ break;
3352
+ }
3353
+ const matchStart = cursor + match.index;
3354
+ const functionName = match[1] ?? "";
3355
+ const openParenIndex = value.indexOf(
3356
+ "(",
3357
+ matchStart + functionName.length
3358
+ );
3359
+ if (openParenIndex < 0) {
3360
+ rewritten += value.slice(cursor);
3361
+ break;
3362
+ }
3363
+ rewritten += value.slice(cursor, matchStart);
3364
+ let depth = 1;
3365
+ let closeParenIndex = openParenIndex + 1;
3366
+ while (closeParenIndex < value.length && depth > 0) {
3367
+ const char = value[closeParenIndex];
3368
+ if (char === "(") {
3369
+ depth += 1;
3370
+ } else if (char === ")") {
3371
+ depth -= 1;
3372
+ }
3373
+ closeParenIndex += 1;
3374
+ }
3375
+ if (depth !== 0) {
3376
+ rewritten += value.slice(matchStart);
3377
+ break;
3378
+ }
3379
+ const argsContent = value.slice(openParenIndex + 1, closeParenIndex - 1);
3380
+ if (isNormalizedAdditiveFunctionName(functionName)) {
3381
+ rewritten += buildNormalizedAdditiveExpression(argsContent);
3382
+ } else {
3383
+ rewritten += value.slice(matchStart, closeParenIndex);
3384
+ }
3385
+ cursor = closeParenIndex;
3386
+ }
3387
+ return rewritten;
3388
+ };
3389
+ const normalizeStagedFormulaExpression = (expression) => {
3390
+ const rhs = stripTopLevelAssignment(expression);
3391
+ return rewriteNormalizedAdditiveCalls(rhs);
3392
+ };
3393
+ const normalizeFormulaSignature = (expression) => normalizeStagedFormulaExpression(expression).replace(/\s+/g, "").toLowerCase();
3394
+ const buildDefaultParentTransformNodeId = (params) => {
3395
+ let transformedNodeId = params.sourceNodeId;
3396
+ if (params.scale !== 1) {
3397
+ const scaledNodeId = `input_parent_scale_${params.nodeSuffix}`;
3398
+ nodes.push({
3399
+ id: scaledNodeId,
3400
+ type: "multiply",
3401
+ inputDefaults: {
3402
+ operand_2: params.scale
3403
+ }
3404
+ });
3405
+ edges.push({
3406
+ from: { nodeId: transformedNodeId },
3407
+ to: { nodeId: scaledNodeId, portId: "operand_1" }
3408
+ });
3409
+ transformedNodeId = scaledNodeId;
3410
+ }
3411
+ if (params.offset !== 0) {
3412
+ const offsetNodeId = `input_parent_offset_${params.nodeSuffix}`;
3413
+ nodes.push({
3414
+ id: offsetNodeId,
3415
+ type: "add",
3416
+ inputDefaults: {
3417
+ operand_2: params.offset
3418
+ }
3419
+ });
3420
+ edges.push({
3421
+ from: { nodeId: transformedNodeId },
3422
+ to: { nodeId: offsetNodeId, portId: "operand_1" }
3423
+ });
3424
+ transformedNodeId = offsetNodeId;
3425
+ }
3426
+ return transformedNodeId;
3427
+ };
3428
+ const buildStagedFormulaNodeId = (params) => {
3429
+ const normalizedExpression = normalizeStagedFormulaExpression(
3430
+ params.expression
3431
+ );
3432
+ if (!normalizedExpression) {
3433
+ return params.fallbackNodeId;
3434
+ }
3435
+ const parseResult = parseControlExpression(normalizedExpression);
3436
+ const issues = [];
3437
+ if (!parseResult.node) {
3438
+ parseResult.errors.forEach((error) => {
3439
+ issues.push(
3440
+ `${params.issuePrefix}: ${error.message} (index ${error.index}).`
3441
+ );
3442
+ });
3443
+ }
3444
+ if (!parseResult.node || issues.length > 0) {
3445
+ const issueSet = bindingIssues.get(params.inputId) ?? /* @__PURE__ */ new Set();
3446
+ issues.forEach((issue) => issueSet.add(issue));
3447
+ if (issues.length > 0) {
3448
+ bindingIssues.set(params.inputId, issueSet);
3449
+ }
3450
+ return params.fallbackNodeId;
3451
+ }
3452
+ const exprContext = {
3453
+ componentSafeId: params.componentSafeId,
3454
+ nodes,
3455
+ edges,
3456
+ constants: /* @__PURE__ */ new Map(),
3457
+ counter: 1,
3458
+ reservedNodes: /* @__PURE__ */ new Map(),
3459
+ nodeValueTypes: /* @__PURE__ */ new Map(),
3460
+ graphReservedNodes,
3461
+ generateReservedNodeId
3462
+ };
3463
+ const variableTable = createExpressionVariableTable();
3464
+ const registerVariableName = (name, nodeId2) => {
3465
+ const trimmed = name.trim();
3466
+ if (!trimmed) {
3467
+ return;
3468
+ }
3469
+ variableTable.registerReservedVariable({
3470
+ name: trimmed,
3471
+ nodeId: nodeId2,
3472
+ description: "Staged pipeline formula variable"
3473
+ });
3474
+ const lower = trimmed.toLowerCase();
3475
+ if (lower !== trimmed) {
3476
+ variableTable.registerReservedVariable({
3477
+ name: lower,
3478
+ nodeId: nodeId2,
3479
+ description: "Staged pipeline formula variable"
3480
+ });
3481
+ }
3482
+ };
3483
+ Object.entries(params.variables).forEach(([name, variable]) => {
3484
+ const nodeId2 = variable.nodeId ?? (typeof variable.value === "number" && Number.isFinite(variable.value) ? getConstantNodeId(exprContext, variable.value) : null);
3485
+ if (!nodeId2) {
3486
+ return;
3487
+ }
3488
+ registerVariableName(name, nodeId2);
3489
+ });
3490
+ const references = collectExpressionReferences(parseResult.node);
3491
+ const missingVariables = variableTable.missing(references);
3492
+ if (missingVariables.length > 0) {
3493
+ const issueSet = bindingIssues.get(params.inputId) ?? /* @__PURE__ */ new Set();
3494
+ missingVariables.forEach((entry) => {
3495
+ issueSet.add(
3496
+ `${params.issuePrefix}: unknown formula variable "${entry.name}".`
3497
+ );
3498
+ });
3499
+ bindingIssues.set(params.inputId, issueSet);
3500
+ return params.fallbackNodeId;
3501
+ }
3502
+ validateLiteralParamArguments(parseResult.node, issues);
3503
+ const nodeId = materializeExpression(
3504
+ parseResult.node,
3505
+ exprContext,
3506
+ variableTable,
3507
+ issues
3508
+ );
3509
+ if (issues.length > 0) {
3510
+ const issueSet = bindingIssues.get(params.inputId) ?? /* @__PURE__ */ new Set();
3511
+ issues.forEach(
3512
+ (issue) => issueSet.add(`${params.issuePrefix}: ${issue}`)
3513
+ );
3514
+ bindingIssues.set(params.inputId, issueSet);
3515
+ return params.fallbackNodeId;
3516
+ }
3517
+ return nodeId;
3518
+ };
3519
+ const buildLegacyEffectiveInputNodeId = (input, directNodeId) => {
3520
+ if (!shouldComposeInputWithPoseControl(input)) {
3521
+ return directNodeId;
3522
+ }
3523
+ const safeInputId = sanitizeNodeId(input.id);
3524
+ const composeBaseline = Number.isFinite(input.defaultValue) ? input.defaultValue : 0;
3525
+ const poseControlNodeId = `input_pose_control_${safeInputId}`;
3526
+ nodes.push({
3527
+ id: poseControlNodeId,
3528
+ type: "input",
3529
+ params: {
3530
+ path: buildPoseControlInputPath(faceId, input.id),
3531
+ value: { float: composeBaseline }
3532
+ }
3533
+ });
3534
+ const composeAddNodeId = `input_compose_add_${safeInputId}`;
3535
+ nodes.push({
3536
+ id: composeAddNodeId,
3537
+ type: "add"
3538
+ });
3539
+ edges.push(
3540
+ {
3541
+ from: { nodeId: directNodeId },
3542
+ to: { nodeId: composeAddNodeId, portId: "operand_1" }
3543
+ },
3544
+ {
3545
+ from: { nodeId: poseControlNodeId },
3546
+ to: { nodeId: composeAddNodeId, portId: "operand_2" }
3547
+ }
3548
+ );
3549
+ const composeMode = composeModeByInputId.get(input.id) ?? "add";
3550
+ let composeOutputNodeId = composeAddNodeId;
3551
+ if (composeMode === "average") {
3552
+ composeOutputNodeId = `input_compose_average_${safeInputId}`;
3553
+ nodes.push({
3554
+ id: composeOutputNodeId,
3555
+ type: "divide",
3556
+ inputDefaults: { rhs: 2 }
3557
+ });
3558
+ edges.push({
3559
+ from: { nodeId: composeAddNodeId },
3560
+ to: { nodeId: composeOutputNodeId, portId: "lhs" }
3561
+ });
3562
+ } else {
3563
+ composeOutputNodeId = `input_compose_normalized_add_${safeInputId}`;
3564
+ nodes.push({
3565
+ id: composeOutputNodeId,
3566
+ type: "subtract",
3567
+ inputDefaults: { rhs: composeBaseline }
3568
+ });
3569
+ edges.push({
3570
+ from: { nodeId: composeAddNodeId },
3571
+ to: { nodeId: composeOutputNodeId, portId: "lhs" }
3572
+ });
3573
+ }
3574
+ const minValue = Number.isFinite(input.range.min) ? input.range.min : -1;
3575
+ const maxValue = Number.isFinite(input.range.max) ? input.range.max : 1;
3576
+ const clampNodeId = `input_effective_${safeInputId}`;
3577
+ nodes.push({
3578
+ id: clampNodeId,
3579
+ type: "clamp",
3580
+ inputDefaults: { min: minValue, max: maxValue }
3581
+ });
3582
+ edges.push({
3583
+ from: { nodeId: composeOutputNodeId },
3584
+ to: { nodeId: clampNodeId, portId: "in" }
3585
+ });
3586
+ return clampNodeId;
3587
+ };
3588
+ const buildStagedEffectiveInputNodeId = (input, stagedConfig) => {
3589
+ const safeInputId = sanitizeNodeId(input.id);
3590
+ const composeBaseline = Number.isFinite(input.defaultValue) ? input.defaultValue : 0;
3591
+ const parentContributionNodes = [];
3592
+ const parentNodeIdByAlias = /* @__PURE__ */ new Map();
3593
+ stagedConfig.parents.forEach((parent, index) => {
3594
+ if (!parent.enabled) {
3595
+ return;
3596
+ }
3597
+ const resolvedParentInputId = resolveStandardRigInputId(
3598
+ parent.inputId,
3599
+ inputsById
3600
+ );
3601
+ const parentInput = ensureInputNode(resolvedParentInputId);
3602
+ if (!parentInput) {
3603
+ const issueSet = bindingIssues.get(input.id) ?? /* @__PURE__ */ new Set();
3604
+ issueSet.add(
3605
+ `Staged parent "${resolvedParentInputId}" missing for "${input.id}".`
3606
+ );
3607
+ bindingIssues.set(input.id, issueSet);
3608
+ return;
3609
+ }
3610
+ const nodeSuffix = `${safeInputId}_${index + 1}`;
3611
+ const fallbackParentNodeId = buildDefaultParentTransformNodeId({
3612
+ sourceNodeId: parentInput.nodeId,
3613
+ nodeSuffix,
3614
+ scale: parent.scale,
3615
+ offset: parent.offset
3616
+ });
3617
+ const defaultParentFormulaExpression = `${parent.alias} = parent * scale + offset`;
3618
+ const parentFormulaNodeId = normalizeFormulaSignature(parent.expression) === normalizeFormulaSignature(defaultParentFormulaExpression) ? fallbackParentNodeId : buildStagedFormulaNodeId({
3619
+ expression: parent.expression,
3620
+ fallbackNodeId: fallbackParentNodeId,
3621
+ componentSafeId: `staged_parent_${nodeSuffix}`,
3622
+ inputId: input.id,
3623
+ issuePrefix: `Parent formula "${parent.alias}"`,
3624
+ variables: {
3625
+ parent: { nodeId: parentInput.nodeId },
3626
+ scale: { value: parent.scale },
3627
+ offset: { value: parent.offset },
3628
+ default: { value: composeBaseline },
3629
+ baseline: { value: composeBaseline }
3630
+ }
3631
+ });
3632
+ parentContributionNodes.push(parentFormulaNodeId);
3633
+ parentNodeIdByAlias.set(parent.alias, parentFormulaNodeId);
3634
+ const normalizedAlias = parent.alias.toLowerCase();
3635
+ if (normalizedAlias !== parent.alias) {
3636
+ parentNodeIdByAlias.set(normalizedAlias, parentFormulaNodeId);
3637
+ }
3638
+ });
3639
+ const parentContributionNodeId = parentContributionNodes.length > 0 ? (() => {
3640
+ const defaultParentContributionNodeId = buildNormalizedAdditiveBlendNodeId({
3641
+ nodeIdPrefix: `input_parent_blend_${safeInputId}`,
3642
+ sourceNodeIds: parentContributionNodes,
3643
+ baseline: composeBaseline
3644
+ });
3645
+ const defaultParentContributionExpression = `parentContribution = normalizedAdditive([${stagedConfig.parents.filter((entry) => entry.enabled).map((entry) => entry.alias).join(", ")}], baseline=default)`;
3646
+ if (normalizeFormulaSignature(stagedConfig.parentBlend.expression) === normalizeFormulaSignature(defaultParentContributionExpression)) {
3647
+ return defaultParentContributionNodeId;
3648
+ }
3649
+ return buildStagedFormulaNodeId({
3650
+ expression: stagedConfig.parentBlend.expression,
3651
+ fallbackNodeId: defaultParentContributionNodeId,
3652
+ componentSafeId: `staged_parent_contribution_${safeInputId}`,
3653
+ inputId: input.id,
3654
+ issuePrefix: "Parent contribution formula",
3655
+ variables: {
3656
+ ...Object.fromEntries(
3657
+ Array.from(parentNodeIdByAlias.entries()).map(
3658
+ ([alias, nodeId]) => [alias, { nodeId }]
3659
+ )
3660
+ ),
3661
+ default: { value: composeBaseline },
3662
+ baseline: { value: composeBaseline }
3663
+ }
3664
+ });
3665
+ })() : null;
3666
+ let poseContributionNodeId = null;
3667
+ const hasPoseContribution = stagedConfig.poseSource.targetIds.length > 0 || shouldComposeInputWithPoseControl(input);
3668
+ if (hasPoseContribution) {
3669
+ poseContributionNodeId = `input_pose_control_${safeInputId}`;
3670
+ nodes.push({
3671
+ id: poseContributionNodeId,
3672
+ type: "input",
3673
+ params: {
3674
+ path: buildPoseControlInputPath(faceId, input.id),
3675
+ value: { float: composeBaseline }
3676
+ }
3677
+ });
3678
+ }
3679
+ const sourceBranchNodeIds = [];
3680
+ if (parentContributionNodeId) {
3681
+ sourceBranchNodeIds.push(parentContributionNodeId);
3682
+ }
3683
+ if (poseContributionNodeId) {
3684
+ sourceBranchNodeIds.push(poseContributionNodeId);
3685
+ }
3686
+ if (stagedConfig.directInput.enabled) {
3687
+ const directNodeId = `input_direct_${safeInputId}`;
3688
+ nodes.push({
3689
+ id: directNodeId,
3690
+ type: "input",
3691
+ params: {
3692
+ path: stagedConfig.directInput.valuePath,
3693
+ value: { float: composeBaseline }
3694
+ }
3695
+ });
3696
+ sourceBranchNodeIds.push(directNodeId);
3697
+ }
3698
+ const sourceBlendNodeId = buildNormalizedAdditiveBlendNodeId({
3699
+ nodeIdPrefix: `input_source_blend_${safeInputId}`,
3700
+ sourceNodeIds: sourceBranchNodeIds,
3701
+ baseline: composeBaseline
3702
+ });
3703
+ const overrideEnabledNodeId = `input_override_enabled_${safeInputId}`;
3704
+ nodes.push({
3705
+ id: overrideEnabledNodeId,
3706
+ type: "input",
3707
+ params: {
3708
+ path: stagedConfig.override.enabledPath,
3709
+ value: { float: stagedConfig.override.enabledDefault ? 1 : 0 }
3710
+ }
3711
+ });
3712
+ const overrideValueNodeId = `input_override_value_${safeInputId}`;
3713
+ nodes.push({
3714
+ id: overrideValueNodeId,
3715
+ type: "input",
3716
+ params: {
3717
+ path: stagedConfig.override.valuePath,
3718
+ value: { float: stagedConfig.override.valueDefault }
3719
+ }
3720
+ });
3721
+ const overrideDeltaNodeId = `input_override_delta_${safeInputId}`;
3722
+ nodes.push({
3723
+ id: overrideDeltaNodeId,
3724
+ type: "subtract"
3725
+ });
3726
+ edges.push(
3727
+ {
3728
+ from: { nodeId: overrideValueNodeId },
3729
+ to: { nodeId: overrideDeltaNodeId, portId: "lhs" }
3730
+ },
3731
+ {
3732
+ from: { nodeId: sourceBlendNodeId },
3733
+ to: { nodeId: overrideDeltaNodeId, portId: "rhs" }
3734
+ }
3735
+ );
3736
+ const overrideScaleNodeId = `input_override_scale_${safeInputId}`;
3737
+ nodes.push({
3738
+ id: overrideScaleNodeId,
3739
+ type: "multiply"
3740
+ });
3741
+ edges.push(
3742
+ {
3743
+ from: { nodeId: overrideEnabledNodeId },
3744
+ to: { nodeId: overrideScaleNodeId, portId: "operand_1" }
3745
+ },
3746
+ {
3747
+ from: { nodeId: overrideDeltaNodeId },
3748
+ to: { nodeId: overrideScaleNodeId, portId: "operand_2" }
3749
+ }
3750
+ );
3751
+ const overrideSelectedNodeId = `input_override_selected_${safeInputId}`;
3752
+ nodes.push({
3753
+ id: overrideSelectedNodeId,
3754
+ type: "add"
3755
+ });
3756
+ edges.push(
3757
+ {
3758
+ from: { nodeId: sourceBlendNodeId },
3759
+ to: { nodeId: overrideSelectedNodeId, portId: "operand_1" }
3760
+ },
3761
+ {
3762
+ from: { nodeId: overrideScaleNodeId },
3763
+ to: { nodeId: overrideSelectedNodeId, portId: "operand_2" }
3764
+ }
3765
+ );
3766
+ if (!stagedConfig.clamp.enabled) {
3767
+ return overrideSelectedNodeId;
3768
+ }
3769
+ const minValue = Number.isFinite(input.range.min) ? input.range.min : -1;
3770
+ const maxValue = Number.isFinite(input.range.max) ? input.range.max : 1;
3771
+ const clampNodeId = `input_effective_${safeInputId}`;
3772
+ nodes.push({
3773
+ id: clampNodeId,
3774
+ type: "clamp",
3775
+ inputDefaults: { min: minValue, max: maxValue }
3776
+ });
3777
+ edges.push({
3778
+ from: { nodeId: overrideSelectedNodeId },
3779
+ to: { nodeId: clampNodeId, portId: "in" }
3780
+ });
3781
+ return clampNodeId;
3782
+ };
3409
3783
  const ensureInputNode = (inputId) => {
3410
3784
  const existing = inputNodes.get(inputId);
3411
3785
  if (existing) {
@@ -3417,7 +3791,8 @@ function buildRigGraphSpec({
3417
3791
  }
3418
3792
  const defaultValue = Number.isFinite(input.defaultValue) ? input.defaultValue : 0;
3419
3793
  const inputBindingRaw = inputBindings[inputId];
3420
- if (inputBindingRaw) {
3794
+ const isStagedInput = hasRigPipelineV1InputConfig(pipelineV1, inputId);
3795
+ if (isStagedInput || inputBindingRaw) {
3421
3796
  if (buildingDerived.has(inputId)) {
3422
3797
  const issueSet = bindingIssues.get(inputId) ?? /* @__PURE__ */ new Set();
3423
3798
  issueSet.add("Derived input cycle detected.");
@@ -3426,6 +3801,21 @@ function buildRigGraphSpec({
3426
3801
  }
3427
3802
  buildingDerived.add(inputId);
3428
3803
  try {
3804
+ if (isStagedInput) {
3805
+ const stagedConfig = resolveRigPipelineV1InputConfig({
3806
+ faceId,
3807
+ input,
3808
+ pipelineV1
3809
+ });
3810
+ stagedPipelineByInputId.set(input.id, stagedConfig);
3811
+ computedInputs.add(inputId);
3812
+ const record3 = {
3813
+ nodeId: buildStagedEffectiveInputNodeId(input, stagedConfig),
3814
+ input
3815
+ };
3816
+ inputNodes.set(inputId, record3);
3817
+ return record3;
3818
+ }
3429
3819
  const target = bindingTargetFromInput(input);
3430
3820
  const binding = ensureBindingStructure(inputBindingRaw, target);
3431
3821
  const requiresSelf = binding.inputId === SELF_BINDING_ID2 || binding.slots.some((slot) => slot.inputId === SELF_BINDING_ID2);
@@ -3449,7 +3839,10 @@ function buildRigGraphSpec({
3449
3839
  animatableId: inputId,
3450
3840
  component: void 0,
3451
3841
  safeId: sanitizeNodeId(inputId),
3842
+ enforceRigBoundaryRules: false,
3452
3843
  context: {
3844
+ inputsById,
3845
+ inputBindings,
3453
3846
  nodes,
3454
3847
  edges,
3455
3848
  ensureInputNode,
@@ -3469,12 +3862,18 @@ function buildRigGraphSpec({
3469
3862
  value: input.defaultValue
3470
3863
  }
3471
3864
  });
3472
- const record3 = { nodeId: constNodeId, input };
3865
+ const record3 = {
3866
+ nodeId: buildLegacyEffectiveInputNodeId(input, constNodeId),
3867
+ input
3868
+ };
3473
3869
  inputNodes.set(inputId, record3);
3474
3870
  return record3;
3475
3871
  }
3476
3872
  computedInputs.add(inputId);
3477
- const record2 = { nodeId: valueNodeId, input };
3873
+ const record2 = {
3874
+ nodeId: buildLegacyEffectiveInputNodeId(input, valueNodeId),
3875
+ input
3876
+ };
3478
3877
  inputNodes.set(inputId, record2);
3479
3878
  return record2;
3480
3879
  } finally {
@@ -3490,7 +3889,10 @@ function buildRigGraphSpec({
3490
3889
  value: { float: defaultValue }
3491
3890
  }
3492
3891
  });
3493
- const record = { nodeId, input };
3892
+ const record = {
3893
+ nodeId: buildLegacyEffectiveInputNodeId(input, nodeId),
3894
+ input
3895
+ };
3494
3896
  inputNodes.set(inputId, record);
3495
3897
  return record;
3496
3898
  };
@@ -3531,7 +3933,10 @@ function buildRigGraphSpec({
3531
3933
  animatableId: component.animatableId,
3532
3934
  component: component.component,
3533
3935
  safeId: component.safeId,
3936
+ enforceRigBoundaryRules: true,
3534
3937
  context: {
3938
+ inputsById,
3939
+ inputBindings,
3535
3940
  nodes,
3536
3941
  edges,
3537
3942
  ensureInputNode,
@@ -3554,7 +3959,6 @@ function buildRigGraphSpec({
3554
3959
  slotId: PRIMARY_SLOT_ID,
3555
3960
  slotAlias: PRIMARY_SLOT_ALIAS,
3556
3961
  inputId: null,
3557
- remap: createDefaultRemap(target),
3558
3962
  expression: PRIMARY_SLOT_ALIAS,
3559
3963
  valueType: target.valueType === "vector" ? "vector" : "scalar",
3560
3964
  issues: ["Binding not found."],
@@ -3680,6 +4084,61 @@ function buildRigGraphSpec({
3680
4084
  const filteredSummaryBindings = summaryBindings.filter(
3681
4085
  (binding) => outputs.has(binding.animatableId) || computedInputs.has(binding.animatableId)
3682
4086
  );
4087
+ const pipelineV1ByInputId = stagedPipelineByInputId.size > 0 ? Object.fromEntries(
4088
+ Array.from(stagedPipelineByInputId.entries()).map(
4089
+ ([inputId, stagedConfig]) => [
4090
+ inputId,
4091
+ {
4092
+ inputId: stagedConfig.inputId,
4093
+ parents: stagedConfig.parents.map((parent) => ({
4094
+ linkId: parent.linkId,
4095
+ inputId: parent.inputId,
4096
+ alias: parent.alias,
4097
+ scale: parent.scale,
4098
+ offset: parent.offset,
4099
+ enabled: parent.enabled,
4100
+ expression: parent.expression
4101
+ })),
4102
+ children: stagedConfig.children.map((child) => ({
4103
+ linkId: child.linkId,
4104
+ childInputId: child.childInputId
4105
+ })),
4106
+ parentBlend: {
4107
+ mode: stagedConfig.parentBlend.mode,
4108
+ expression: stagedConfig.parentBlend.expression
4109
+ },
4110
+ poseSource: {
4111
+ targetIds: [...stagedConfig.poseSource.targetIds]
4112
+ },
4113
+ directInput: {
4114
+ enabled: stagedConfig.directInput.enabled,
4115
+ valuePath: stagedConfig.directInput.valuePath
4116
+ },
4117
+ sourceBlend: {
4118
+ mode: stagedConfig.sourceBlend.mode
4119
+ },
4120
+ sourceFallback: {
4121
+ whenNoSources: stagedConfig.sourceFallback.whenNoSources
4122
+ },
4123
+ clamp: {
4124
+ enabled: stagedConfig.clamp.enabled
4125
+ },
4126
+ override: {
4127
+ enabledDefault: stagedConfig.override.enabledDefault,
4128
+ valueDefault: stagedConfig.override.valueDefault,
4129
+ enabledPath: stagedConfig.override.enabledPath,
4130
+ valuePath: stagedConfig.override.valuePath
4131
+ }
4132
+ }
4133
+ ]
4134
+ )
4135
+ ) : void 0;
4136
+ const hasPipelineLinks = pipelineV1?.links && typeof pipelineV1.links === "object" && Object.keys(pipelineV1.links).length > 0;
4137
+ const pipelineV1Metadata = pipelineV1ByInputId || hasPipelineLinks ? {
4138
+ version: RIG_PIPELINE_V1_VERSION,
4139
+ ...pipelineV1ByInputId ? { byInputId: pipelineV1ByInputId } : {},
4140
+ ...hasPipelineLinks ? { links: cloneJsonLike2(pipelineV1?.links) } : {}
4141
+ } : void 0;
3683
4142
  const vizijMetadata = {
3684
4143
  vizij: {
3685
4144
  faceId,
@@ -3712,12 +4171,12 @@ function buildRigGraphSpec({
3712
4171
  }),
3713
4172
  bindings: filteredSummaryBindings.map((binding) => ({
3714
4173
  ...binding,
3715
- remap: { ...binding.remap },
3716
4174
  expression: binding.expression,
3717
4175
  valueType: binding.valueType,
3718
4176
  issues: binding.issues ? [...binding.issues] : void 0,
3719
4177
  metadata: binding.metadata ? cloneJsonLike2(binding.metadata) : void 0
3720
- }))
4178
+ })),
4179
+ ...pipelineV1Metadata ? { pipelineV1: pipelineV1Metadata } : {}
3721
4180
  }
3722
4181
  };
3723
4182
  const issuesByTarget = {};
@@ -3747,7 +4206,6 @@ function buildRigGraphSpec({
3747
4206
  bindings: toIrBindingSummary(
3748
4207
  filteredSummaryBindings.map((binding) => ({
3749
4208
  ...binding,
3750
- remap: { ...binding.remap },
3751
4209
  issues: binding.issues ? [...binding.issues] : void 0
3752
4210
  }))
3753
4211
  )
@@ -3866,7 +4324,7 @@ function cloneJsonLike2(value) {
3866
4324
  if (value === void 0 || value === null) {
3867
4325
  return value;
3868
4326
  }
3869
- return JSON.parse(JSON.stringify(value));
4327
+ return cloneDeepSafe4(value);
3870
4328
  }
3871
4329
  function validateRemapDefaults(nodes) {
3872
4330
  const issues = [];
@@ -3894,15 +4352,8 @@ function validateRemapDefaults(nodes) {
3894
4352
 
3895
4353
  // src/ir/inspection.ts
3896
4354
  import { findNodeSignature } from "@vizij/node-graph-wasm/metadata";
4355
+ import { cloneDeepSafe as cloneDeepSafe5 } from "@vizij/utils";
3897
4356
  var MACHINE_REPORT_VERSION = 1;
3898
- var REMAP_KEYS = [
3899
- "inLow",
3900
- "inAnchor",
3901
- "inHigh",
3902
- "outLow",
3903
- "outAnchor",
3904
- "outHigh"
3905
- ];
3906
4357
  var DEFAULT_DIFF_LIMIT = 50;
3907
4358
  function buildMachineReport(result) {
3908
4359
  return {
@@ -3943,7 +4394,6 @@ function normalizeGraphBindingSummaries(bindings) {
3943
4394
  slotId: binding.slotId,
3944
4395
  slotAlias: binding.slotAlias,
3945
4396
  inputId: binding.inputId ?? null,
3946
- remap: normalizeRemap2(binding.remap),
3947
4397
  expression: binding.expression,
3948
4398
  valueType: binding.valueType,
3949
4399
  nodeId: binding.nodeId,
@@ -3958,7 +4408,7 @@ function cloneBindingMetadata2(metadata) {
3958
4408
  if (!metadata) {
3959
4409
  return void 0;
3960
4410
  }
3961
- return JSON.parse(JSON.stringify(metadata));
4411
+ return cloneDeepSafe5(metadata);
3962
4412
  }
3963
4413
  function normalizeIssues(issues) {
3964
4414
  const byTargetEntries = Object.entries(issues.byTarget ?? {}).map(
@@ -4042,7 +4492,6 @@ function normalizeIrGraphSummary(summary) {
4042
4492
  function normalizeIrBindingSummaries(bindings) {
4043
4493
  const normalized = bindings.map((binding) => ({
4044
4494
  ...binding,
4045
- remap: sortPlainObject(binding.remap),
4046
4495
  issues: normalizeStringArray(binding.issues)
4047
4496
  }));
4048
4497
  normalized.sort((a, b) => bindingSortKey(a).localeCompare(bindingSortKey(b)));
@@ -4123,6 +4572,9 @@ function normalizeRegistryVariadicSpec(spec) {
4123
4572
  if (typeof spec.max === "number") {
4124
4573
  normalized.max = spec.max;
4125
4574
  }
4575
+ if (spec.keyed) {
4576
+ normalized.keyed = true;
4577
+ }
4126
4578
  return normalized;
4127
4579
  }
4128
4580
  function normalizeRegistryParamSpec(param) {
@@ -4145,13 +4597,6 @@ function normalizeRegistryParamSpec(param) {
4145
4597
  }
4146
4598
  return normalized;
4147
4599
  }
4148
- function normalizeRemap2(remap) {
4149
- const normalized = {};
4150
- REMAP_KEYS.forEach((key) => {
4151
- normalized[key] = remap[key];
4152
- });
4153
- return normalized;
4154
- }
4155
4600
  function normalizeStringArray(values) {
4156
4601
  if (!values || values.length === 0) {
4157
4602
  return void 0;
@@ -4294,7 +4739,6 @@ export {
4294
4739
  bindingTargetFromInput,
4295
4740
  PRIMARY_SLOT_ID,
4296
4741
  PRIMARY_SLOT_ALIAS,
4297
- createDefaultRemap,
4298
4742
  createDefaultBindings,
4299
4743
  createDefaultBinding,
4300
4744
  createDefaultParentBinding,
@@ -4306,14 +4750,10 @@ export {
4306
4750
  updateBindingSlotAlias,
4307
4751
  updateBindingSlotValueType,
4308
4752
  updateBindingExpression,
4309
- updateBindingSlotRemap,
4310
4753
  updateBindingWithInput,
4311
- remapValue,
4312
4754
  reconcileBindings,
4313
4755
  bindingToDefinition,
4314
4756
  bindingFromDefinition,
4315
- buildPiecewiseRemapExpression,
4316
- buildDefaultSlotExpression,
4317
4757
  buildCanonicalBindingExpression,
4318
4758
  parseControlExpression,
4319
4759
  collectExpressionReferences,