@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.
package/dist/index.cjs CHANGED
@@ -33,9 +33,7 @@ __export(index_exports, {
33
33
  bindingTargetFromInput: () => bindingTargetFromInput,
34
34
  bindingToDefinition: () => bindingToDefinition,
35
35
  buildCanonicalBindingExpression: () => buildCanonicalBindingExpression,
36
- buildDefaultSlotExpression: () => buildDefaultSlotExpression,
37
36
  buildMachineReport: () => buildMachineReport,
38
- buildPiecewiseRemapExpression: () => buildPiecewiseRemapExpression,
39
37
  buildRigGraphSpec: () => buildRigGraphSpec,
40
38
  collectExpressionReferences: () => collectExpressionReferences,
41
39
  compileIrGraph: () => compileIrGraph,
@@ -43,7 +41,6 @@ __export(index_exports, {
43
41
  createDefaultBindings: () => createDefaultBindings,
44
42
  createDefaultInputValues: () => createDefaultInputValues,
45
43
  createDefaultParentBinding: () => createDefaultParentBinding,
46
- createDefaultRemap: () => createDefaultRemap,
47
44
  createExpressionVariableTable: () => createExpressionVariableTable,
48
45
  createIrGraphBuilder: () => createIrGraphBuilder,
49
46
  createLegacyIrGraph: () => createLegacyIrGraph,
@@ -53,20 +50,19 @@ __export(index_exports, {
53
50
  mapExpression: () => mapExpression,
54
51
  parseControlExpression: () => parseControlExpression,
55
52
  reconcileBindings: () => reconcileBindings,
56
- remapValue: () => remapValue,
57
53
  removeBindingSlot: () => removeBindingSlot,
58
54
  toIrBindingSummary: () => toIrBindingSummary,
59
55
  updateBindingExpression: () => updateBindingExpression,
60
56
  updateBindingSlotAlias: () => updateBindingSlotAlias,
61
- updateBindingSlotRemap: () => updateBindingSlotRemap,
62
57
  updateBindingSlotValueType: () => updateBindingSlotValueType,
63
58
  updateBindingWithInput: () => updateBindingWithInput
64
59
  });
65
60
  module.exports = __toCommonJS(index_exports);
66
61
 
67
62
  // src/graphBuilder.ts
68
- var import_utils2 = require("@vizij/utils");
69
- var import_utils3 = require("@vizij/utils");
63
+ var import_utils4 = require("@vizij/utils");
64
+ var import_utils5 = require("@vizij/utils");
65
+ var import_metadata2 = require("@vizij/node-graph-wasm/metadata");
70
66
 
71
67
  // src/state.ts
72
68
  var import_utils = require("@vizij/utils");
@@ -108,9 +104,6 @@ function bindingTargetFromInput(input) {
108
104
  valueType: "scalar"
109
105
  };
110
106
  }
111
- var DEFAULT_INPUT_RANGE = { min: -1, max: 1 };
112
- var DEFAULT_INPUT_ANCHOR = 0;
113
- var EPSILON = 1e-6;
114
107
  var LEGACY_SLOT_PATTERN = /^slot_(\d+)$/i;
115
108
  var ALIAS_SANITIZE_PATTERN = /[^A-Za-z0-9_]+/g;
116
109
  var PRIMARY_SLOT_ID = "s1";
@@ -186,131 +179,11 @@ function rewriteLegacyExpression(expression, replacements) {
186
179
  return `s${digits}`;
187
180
  });
188
181
  }
189
- function clamp(value, min, max) {
190
- return Math.min(max, Math.max(min, value));
191
- }
192
- function isFiniteNumber(value) {
193
- return typeof value === "number" && Number.isFinite(value);
194
- }
195
- function deriveOutputDefaults(target) {
196
- const { min, max } = target.range;
197
- const anchor = clamp(target.defaultValue, min, max);
198
- return {
199
- outLow: min,
200
- outAnchor: anchor,
201
- outHigh: max
202
- };
203
- }
204
- function deriveInputDefaults() {
205
- return {
206
- inLow: DEFAULT_INPUT_RANGE.min,
207
- inAnchor: DEFAULT_INPUT_ANCHOR,
208
- inHigh: DEFAULT_INPUT_RANGE.max
209
- };
210
- }
211
- function migrateLegacyRemap(legacy, target) {
212
- const inputDefaults = deriveInputDefaults();
213
- const outputDefaults = deriveOutputDefaults(target);
214
- const defaults = {
215
- inLow: inputDefaults.inLow,
216
- inAnchor: inputDefaults.inAnchor,
217
- inHigh: inputDefaults.inHigh,
218
- outLow: outputDefaults.outLow,
219
- outAnchor: outputDefaults.outAnchor,
220
- outHigh: outputDefaults.outHigh
221
- };
222
- if ("inLow" in legacy && "inHigh" in legacy && "outLow" in legacy && "outHigh" in legacy) {
223
- const inLow2 = isFiniteNumber(legacy.inLow) ? legacy.inLow : defaults.inLow;
224
- const inAnchor2 = isFiniteNumber(legacy.inAnchor) ? legacy.inAnchor : defaults.inAnchor;
225
- const inHigh2 = isFiniteNumber(legacy.inHigh) ? legacy.inHigh : defaults.inHigh;
226
- let outLow = isFiniteNumber(legacy.outLow) ? legacy.outLow : defaults.outLow;
227
- let outHigh = isFiniteNumber(legacy.outHigh) ? legacy.outHigh : defaults.outHigh;
228
- if (outLow > outHigh) {
229
- const low = outHigh;
230
- const high = outLow;
231
- outLow = low;
232
- outHigh = high;
233
- }
234
- const outAnchor2 = clamp(
235
- isFiniteNumber(legacy.outAnchor) ? legacy.outAnchor : defaults.outAnchor,
236
- outLow,
237
- outHigh
238
- );
239
- return {
240
- inLow: inLow2,
241
- inAnchor: inAnchor2,
242
- inHigh: inHigh2,
243
- outLow,
244
- outAnchor: outAnchor2,
245
- outHigh
246
- };
247
- }
248
- const legacyTyped = legacy;
249
- const inLow = isFiniteNumber(legacyTyped.inMin) ? legacyTyped.inMin : defaults.inLow;
250
- const inHigh = isFiniteNumber(legacyTyped.inMax) ? legacyTyped.inMax : defaults.inHigh;
251
- const inAnchor = (inLow + inHigh) / 2;
252
- const legacyOutMid = isFiniteNumber(legacyTyped.outMin) && isFiniteNumber(legacyTyped.outMax) ? (legacyTyped.outMin + legacyTyped.outMax) / 2 : defaults.outAnchor;
253
- const outAnchor = clamp(legacyOutMid, defaults.outLow, defaults.outHigh);
254
- return {
255
- inLow,
256
- inAnchor,
257
- inHigh,
258
- outLow: defaults.outLow,
259
- outAnchor,
260
- outHigh: defaults.outHigh
261
- };
262
- }
263
- function normalizeRemap(remap, target) {
264
- if (!remap) {
265
- return createDefaultRemap(target);
266
- }
267
- return migrateLegacyRemap(remap, target);
268
- }
269
- function cloneRemap(remap) {
270
- return (0, import_utils.cloneRemapSettings)(remap);
271
- }
272
182
  function cloneBindingMetadata(metadata) {
273
183
  if (!metadata) {
274
184
  return void 0;
275
185
  }
276
- return JSON.parse(JSON.stringify(metadata));
277
- }
278
- function sanitizeRemap(remap, target) {
279
- const normalized = normalizeRemap(remap, target);
280
- const outputDefaults = deriveOutputDefaults(target);
281
- if (!Number.isFinite(normalized.outLow)) {
282
- normalized.outLow = outputDefaults.outLow;
283
- }
284
- if (!Number.isFinite(normalized.outHigh)) {
285
- normalized.outHigh = outputDefaults.outHigh;
286
- }
287
- if (!Number.isFinite(normalized.outAnchor)) {
288
- normalized.outAnchor = outputDefaults.outAnchor;
289
- }
290
- if (normalized.outLow > normalized.outHigh) {
291
- const low = normalized.outHigh;
292
- const high = normalized.outLow;
293
- normalized.outLow = low;
294
- normalized.outHigh = high;
295
- }
296
- normalized.outAnchor = clamp(
297
- normalized.outAnchor,
298
- normalized.outLow,
299
- normalized.outHigh
300
- );
301
- return normalized;
302
- }
303
- function createDefaultRemap(target) {
304
- const inputDefaults = deriveInputDefaults();
305
- const outputDefaults = deriveOutputDefaults(target);
306
- return {
307
- inLow: inputDefaults.inLow,
308
- inAnchor: inputDefaults.inAnchor,
309
- inHigh: inputDefaults.inHigh,
310
- outLow: outputDefaults.outLow,
311
- outAnchor: outputDefaults.outAnchor,
312
- outHigh: outputDefaults.outHigh
313
- };
186
+ return (0, import_utils.cloneDeepSafe)(metadata);
314
187
  }
315
188
  function createDefaultBindings(components) {
316
189
  const bindings = {};
@@ -320,21 +193,18 @@ function createDefaultBindings(components) {
320
193
  return bindings;
321
194
  }
322
195
  function createDefaultBinding(component) {
323
- const remap = createDefaultRemap(component);
324
196
  const valueType = getTargetValueType(component);
325
197
  const slots = [
326
198
  {
327
199
  id: PRIMARY_SLOT_ID,
328
200
  alias: PRIMARY_SLOT_ALIAS,
329
201
  inputId: null,
330
- remap: cloneRemap(remap),
331
202
  valueType
332
203
  }
333
204
  ];
334
205
  return {
335
206
  targetId: component.id,
336
207
  inputId: null,
337
- remap,
338
208
  slots,
339
209
  expression: buildCanonicalExpressionFromSlots(slots)
340
210
  };
@@ -360,7 +230,6 @@ function createDefaultParentBinding(component) {
360
230
  };
361
231
  }
362
232
  function ensurePrimarySlot(binding, target) {
363
- const normalizedBindingRemap = sanitizeRemap(binding.remap, target);
364
233
  const targetValueType = getTargetValueType(target);
365
234
  const aliasReplacements = /* @__PURE__ */ new Map();
366
235
  const sourceSlots = Array.isArray(binding.slots) && binding.slots.length > 0 ? binding.slots : [
@@ -368,7 +237,6 @@ function ensurePrimarySlot(binding, target) {
368
237
  id: PRIMARY_SLOT_ID,
369
238
  alias: PRIMARY_SLOT_ALIAS,
370
239
  inputId: binding.inputId ?? null,
371
- remap: cloneRemap(normalizedBindingRemap),
372
240
  valueType: targetValueType
373
241
  }
374
242
  ];
@@ -383,8 +251,6 @@ function ensurePrimarySlot(binding, target) {
383
251
  if (replaced && replaced !== normalizedAlias) {
384
252
  aliasReplacements.set(replaced, normalizedAlias);
385
253
  }
386
- const slotRemapSource = slot.remap ?? (index === 0 ? normalizedBindingRemap : createDefaultRemap(target));
387
- const normalizedSlotRemap = sanitizeRemap(slotRemapSource, target);
388
254
  const inputId = slot.inputId !== void 0 && slot.inputId !== null ? slot.inputId : index === 0 ? binding.inputId ?? null : null;
389
255
  const slotValueType = sanitizeSlotValueType(
390
256
  slot.valueType,
@@ -394,13 +260,11 @@ function ensurePrimarySlot(binding, target) {
394
260
  id: normalizedId,
395
261
  alias: normalizedAlias,
396
262
  inputId,
397
- remap: cloneRemap(normalizedSlotRemap),
398
263
  valueType: slotValueType
399
264
  };
400
265
  }
401
266
  );
402
267
  const primary = normalizedSlots[0];
403
- const primaryRemap = sanitizeRemap(primary.remap, target);
404
268
  const primaryInputId = primary.inputId === import_utils.SELF_BINDING_ID ? import_utils.SELF_BINDING_ID : primary.inputId ?? binding.inputId ?? null;
405
269
  const primaryAlias = primaryInputId === import_utils.SELF_BINDING_ID ? "self" : primary.alias || PRIMARY_SLOT_ALIAS;
406
270
  normalizedSlots[0] = {
@@ -408,16 +272,13 @@ function ensurePrimarySlot(binding, target) {
408
272
  id: primary.id || PRIMARY_SLOT_ID,
409
273
  alias: primaryAlias,
410
274
  inputId: primaryInputId,
411
- remap: cloneRemap(primaryRemap),
412
275
  valueType: sanitizeSlotValueType(primary.valueType, targetValueType)
413
276
  };
414
277
  normalizedSlots.slice(1).forEach((slot, index) => {
415
- const slotRemap = sanitizeRemap(slot.remap, target);
416
278
  normalizedSlots[index + 1] = {
417
279
  ...slot,
418
280
  id: slot.id || defaultSlotId(index + 1),
419
281
  alias: slot.alias || defaultSlotId(index + 1),
420
- remap: cloneRemap(slotRemap),
421
282
  valueType: sanitizeSlotValueType(slot.valueType, targetValueType)
422
283
  };
423
284
  });
@@ -432,7 +293,6 @@ function ensurePrimarySlot(binding, target) {
432
293
  const normalizedBinding = {
433
294
  ...binding,
434
295
  inputId: normalizedSlots[0].inputId ?? null,
435
- remap: cloneRemap(primaryRemap),
436
296
  slots: normalizedSlots,
437
297
  expression
438
298
  };
@@ -459,14 +319,13 @@ function addBindingSlot(binding, target) {
459
319
  const nextIndex = base.slots.length + 1;
460
320
  const slotId = defaultSlotId(nextIndex - 1);
461
321
  const alias = slotId;
462
- const remap = createDefaultRemap(target);
463
322
  const nextSlots = [
464
323
  ...base.slots,
465
324
  {
466
325
  id: slotId,
467
326
  alias,
468
327
  inputId: null,
469
- remap: cloneRemap(remap)
328
+ valueType: getTargetValueType(target)
470
329
  }
471
330
  ];
472
331
  return ensurePrimarySlot(
@@ -580,50 +439,6 @@ function updateBindingExpression(binding, target, expression) {
580
439
  expression: trimmed.length > 0 ? trimmed : canonicalExpression
581
440
  };
582
441
  }
583
- function updateBindingSlotRemap(binding, target, slotId, field, value) {
584
- const base = ensurePrimarySlot(binding, target);
585
- const existingExpression = typeof base.expression === "string" ? base.expression.trim() : "";
586
- const canonicalBefore = buildCanonicalExpressionFromSlots(base.slots);
587
- const expressionWasDefault = expressionMatchesAliasOnly(existingExpression, base.slots) || expressionsEquivalent(existingExpression, canonicalBefore);
588
- const nextSlots = base.slots.map((slot) => {
589
- if (slot.id !== slotId) {
590
- return slot;
591
- }
592
- const updatedRemap = {
593
- ...slot.remap,
594
- [field]: value
595
- };
596
- const sanitized = sanitizeRemap(updatedRemap, target);
597
- return {
598
- ...slot,
599
- remap: cloneRemap(sanitized)
600
- };
601
- });
602
- const updated = ensurePrimarySlot(
603
- {
604
- ...base,
605
- slots: nextSlots
606
- },
607
- target
608
- );
609
- if (updated.slots[0]?.id === slotId) {
610
- updated.remap = {
611
- ...updated.remap,
612
- [field]: value
613
- };
614
- }
615
- if (!expressionWasDefault) {
616
- return updated;
617
- }
618
- const canonicalAfter = buildCanonicalExpressionFromSlots(updated.slots);
619
- if (expressionsEquivalent(updated.expression ?? "", canonicalAfter)) {
620
- return updated;
621
- }
622
- return {
623
- ...updated,
624
- expression: canonicalAfter
625
- };
626
- }
627
442
  function updateBindingWithInput(binding, target, input, slotId = PRIMARY_SLOT_ID) {
628
443
  const base = ensurePrimarySlot(binding, target);
629
444
  const existingExpression = typeof base.expression === "string" ? base.expression.trim() : "";
@@ -631,39 +446,27 @@ function updateBindingWithInput(binding, target, input, slotId = PRIMARY_SLOT_ID
631
446
  const expressionWasDefault = expressionMatchesAliasOnly(existingExpression, base.slots) || expressionsEquivalent(existingExpression, canonicalBefore);
632
447
  const slotIndex = base.slots.findIndex((slot) => slot.id === slotId);
633
448
  const effectiveIndex = slotIndex >= 0 ? slotIndex : base.slots.length;
634
- const slots = base.slots.map((slot) => ({
635
- ...slot,
636
- remap: cloneRemap(slot.remap)
637
- }));
449
+ const slots = base.slots.map((slot) => ({ ...slot }));
638
450
  if (slotIndex === -1) {
639
451
  const alias = slotId === PRIMARY_SLOT_ID && slots.length === 0 ? PRIMARY_SLOT_ALIAS : slotId;
640
452
  slots.push({
641
453
  id: slotId,
642
454
  alias,
643
455
  inputId: null,
644
- remap: cloneRemap(createDefaultRemap(target))
456
+ valueType: getTargetValueType(target)
645
457
  });
646
458
  }
647
459
  const currentSlot = slots[effectiveIndex];
648
460
  let nextBinding;
649
461
  if (!input) {
650
- const normalizedSlotRemap = sanitizeRemap(currentSlot.remap, target);
651
- const updatedRemap = {
652
- ...normalizedSlotRemap,
653
- inLow: DEFAULT_INPUT_RANGE.min,
654
- inAnchor: DEFAULT_INPUT_ANCHOR,
655
- inHigh: DEFAULT_INPUT_RANGE.max
656
- };
657
462
  slots[effectiveIndex] = {
658
463
  ...currentSlot,
659
- inputId: null,
660
- remap: cloneRemap(updatedRemap)
464
+ inputId: null
661
465
  };
662
466
  if (effectiveIndex === 0) {
663
467
  nextBinding = {
664
468
  ...base,
665
469
  inputId: null,
666
- remap: cloneRemap(updatedRemap),
667
470
  slots
668
471
  };
669
472
  } else {
@@ -673,24 +476,14 @@ function updateBindingWithInput(binding, target, input, slotId = PRIMARY_SLOT_ID
673
476
  };
674
477
  }
675
478
  } else {
676
- const normalizedRemap = sanitizeRemap(currentSlot.remap, target);
677
- const updatedRemap = {
678
- ...normalizedRemap,
679
- inLow: input.range.min,
680
- inAnchor: clamp(input.defaultValue, input.range.min, input.range.max),
681
- inHigh: input.range.max,
682
- ...deriveOutputDefaults(target)
683
- };
684
479
  slots[effectiveIndex] = {
685
480
  ...currentSlot,
686
- inputId: input.id,
687
- remap: cloneRemap(updatedRemap)
481
+ inputId: input.id
688
482
  };
689
483
  if (effectiveIndex === 0) {
690
484
  nextBinding = {
691
485
  ...base,
692
486
  inputId: input.id,
693
- remap: cloneRemap(updatedRemap),
694
487
  slots
695
488
  };
696
489
  } else {
@@ -712,26 +505,6 @@ function updateBindingWithInput(binding, target, input, slotId = PRIMARY_SLOT_ID
712
505
  expression: canonicalAfter
713
506
  };
714
507
  }
715
- function remapValue(value, remap) {
716
- const { inLow, inAnchor, inHigh, outLow, outAnchor, outHigh } = remap;
717
- if (Number.isNaN(value)) {
718
- return outAnchor;
719
- }
720
- if (value <= inAnchor) {
721
- const span2 = inAnchor - inLow;
722
- if (Math.abs(span2) < EPSILON) {
723
- return outLow;
724
- }
725
- const t2 = (value - inLow) / span2;
726
- return outLow + t2 * (outAnchor - outLow);
727
- }
728
- const span = inHigh - inAnchor;
729
- if (Math.abs(span) < EPSILON) {
730
- return outHigh;
731
- }
732
- const t = (value - inAnchor) / span;
733
- return outAnchor + t * (outHigh - outAnchor);
734
- }
735
508
  function reconcileBindings(previous, components) {
736
509
  const next = {};
737
510
  components.forEach((component) => {
@@ -749,12 +522,10 @@ function reconcileBindings(previous, components) {
749
522
  if (replaced && replaced !== normalizedAlias) {
750
523
  aliasReplacements.set(replaced, normalizedAlias);
751
524
  }
752
- const slotRemap = sanitizeRemap(slot.remap, component);
753
525
  return {
754
526
  ...slot,
755
527
  id: normalizedId,
756
- alias: normalizedAlias,
757
- remap: cloneRemap(slotRemap)
528
+ alias: normalizedAlias
758
529
  };
759
530
  });
760
531
  const primary = slots[0];
@@ -764,7 +535,6 @@ function reconcileBindings(previous, components) {
764
535
  ...ensured,
765
536
  targetId: component.id,
766
537
  inputId: primary.inputId ?? null,
767
- remap: cloneRemap(primary.remap),
768
538
  slots,
769
539
  expression
770
540
  };
@@ -777,11 +547,7 @@ function reconcileBindings(previous, components) {
777
547
  function bindingToDefinition(binding) {
778
548
  const definition = {
779
549
  inputId: binding.inputId ?? null,
780
- remap: cloneRemap(binding.remap),
781
- slots: binding.slots.map((slot) => ({
782
- ...slot,
783
- remap: cloneRemap(slot.remap)
784
- })),
550
+ slots: binding.slots.map((slot) => ({ ...slot })),
785
551
  expression: binding.expression,
786
552
  metadata: cloneBindingMetadata(binding.metadata)
787
553
  };
@@ -794,46 +560,12 @@ function bindingFromDefinition(target, definition) {
794
560
  const binding = {
795
561
  targetId: target.id,
796
562
  inputId: definition.inputId ?? null,
797
- remap: cloneRemap(definition.remap),
798
- slots: definition.slots.map((slot) => ({
799
- ...slot,
800
- remap: cloneRemap(slot.remap)
801
- })),
563
+ slots: definition.slots.map((slot) => ({ ...slot })),
802
564
  expression: definition.expression,
803
565
  metadata: cloneBindingMetadata(definition.metadata)
804
566
  };
805
567
  return ensureBindingStructure(binding, target);
806
568
  }
807
- function sanitizeLiteral(value) {
808
- if (!Number.isFinite(value)) {
809
- return 0;
810
- }
811
- if (Object.is(value, -0)) {
812
- return 0;
813
- }
814
- return value;
815
- }
816
- function formatVectorLiteral(values) {
817
- return `vec(${values.map((value) => sanitizeLiteral(value)).join(", ")})`;
818
- }
819
- function buildPiecewiseRemapExpression(alias, remap) {
820
- const sanitizedAlias = alias && alias.trim().length > 0 ? alias.trim() : PRIMARY_SLOT_ALIAS;
821
- const inputBreakpoints = [remap.inLow, remap.inAnchor, remap.inHigh];
822
- const outputBreakpoints = [remap.outLow, remap.outAnchor, remap.outHigh];
823
- return `piecewise_remap(${sanitizedAlias}, ${formatVectorLiteral(
824
- inputBreakpoints
825
- )}, ${formatVectorLiteral(outputBreakpoints)})`;
826
- }
827
- function isSelfAlias(alias) {
828
- return alias.trim().toLowerCase() === "self";
829
- }
830
- function buildDefaultSlotExpression(alias, inputId, remap) {
831
- const sanitizedAlias = alias && alias.trim().length > 0 ? alias.trim() : PRIMARY_SLOT_ALIAS;
832
- if (inputId === import_utils.SELF_BINDING_ID || isSelfAlias(sanitizedAlias)) {
833
- return sanitizedAlias;
834
- }
835
- return buildPiecewiseRemapExpression(sanitizedAlias, remap);
836
- }
837
569
  function normalizeSlotAliasForExpression(slot, index) {
838
570
  if (slot.alias && slot.alias.trim().length > 0) {
839
571
  return slot.alias.trim();
@@ -850,16 +582,7 @@ function buildAliasOnlyExpression(slots) {
850
582
  return slots.map((slot, index) => normalizeSlotAliasForExpression(slot, index)).join(" + ");
851
583
  }
852
584
  function buildCanonicalExpressionFromSlots(slots) {
853
- if (!slots.length) {
854
- return PRIMARY_SLOT_ALIAS;
855
- }
856
- return slots.map(
857
- (slot, index) => buildDefaultSlotExpression(
858
- normalizeSlotAliasForExpression(slot, index),
859
- slot.inputId ?? null,
860
- slot.remap
861
- )
862
- ).join(" + ");
585
+ return buildAliasOnlyExpression(slots);
863
586
  }
864
587
  function expressionsEquivalent(left, right) {
865
588
  return left.trim() === right.trim();
@@ -1970,9 +1693,7 @@ var DefaultExpressionVariableTable = class {
1970
1693
  targetId: options.targetId,
1971
1694
  animatableId: options.animatableId,
1972
1695
  component: options.component,
1973
- valueType: options.valueType,
1974
- remap: options.remap,
1975
- autoRemap: options.autoRemap
1696
+ valueType: options.valueType
1976
1697
  }
1977
1698
  });
1978
1699
  }
@@ -2069,9 +1790,6 @@ var RESERVED_EXPRESSION_VARIABLES = [
2069
1790
  ];
2070
1791
  var EXPRESSION_FUNCTION_VOCABULARY = SCALAR_FUNCTION_VOCABULARY;
2071
1792
 
2072
- // src/graphBuilder.ts
2073
- var import_metadata2 = require("@vizij/node-graph-wasm/metadata");
2074
-
2075
1793
  // src/ir/builder.ts
2076
1794
  var graphSequence = 0;
2077
1795
  function generateGraphId(faceId) {
@@ -2158,12 +1876,12 @@ function createLegacyIrGraph(payload) {
2158
1876
  function toIrBindingSummary(summaries) {
2159
1877
  return summaries.map((summary) => ({
2160
1878
  ...summary,
2161
- remap: { ...summary.remap },
2162
1879
  issues: summary.issues ? [...summary.issues] : void 0
2163
1880
  }));
2164
1881
  }
2165
1882
 
2166
1883
  // src/ir/compiler.ts
1884
+ var import_utils2 = require("@vizij/utils");
2167
1885
  function compileIrGraph(graph, options = {}) {
2168
1886
  const preferLegacy = options.preferLegacySpec === true;
2169
1887
  const legacySpec = graph.legacy?.spec;
@@ -2248,7 +1966,7 @@ function cloneJsonLike(value) {
2248
1966
  if (value === void 0 || value === null) {
2249
1967
  return value;
2250
1968
  }
2251
- return JSON.parse(JSON.stringify(value));
1969
+ return (0, import_utils2.cloneDeepSafe)(value);
2252
1970
  }
2253
1971
  function inlineSingleUseConstants(spec) {
2254
1972
  const nodes = spec.nodes ?? [];
@@ -2287,8 +2005,9 @@ function inlineSingleUseConstants(spec) {
2287
2005
  }
2288
2006
 
2289
2007
  // src/bindingMetadata.ts
2008
+ var import_utils3 = require("@vizij/utils");
2290
2009
  function cloneOperand(entry) {
2291
- return JSON.parse(JSON.stringify(entry));
2010
+ return (0, import_utils3.cloneDeepSafe)(entry);
2292
2011
  }
2293
2012
  function describeSlot(entry) {
2294
2013
  const metadata = entry.metadata;
@@ -2330,17 +2049,17 @@ function describeReference(node, variables) {
2330
2049
  function stringifyExpression(node) {
2331
2050
  switch (node.type) {
2332
2051
  case "Literal":
2333
- return Number.isFinite(node.value) ? `${node.value}` : "0";
2052
+ return Number.isFinite(node.value) ? `${node.value} ` : "0";
2334
2053
  case "VectorLiteral":
2335
2054
  return `vec(${node.values.join(", ")})`;
2336
2055
  case "Reference":
2337
2056
  return node.name;
2338
2057
  case "Unary":
2339
- return `${node.operator}${stringifyExpression(node.operand)}`;
2058
+ return `${node.operator}${stringifyExpression(node.operand)} `;
2340
2059
  case "Binary":
2341
- return `${stringifyExpression(node.left)} ${node.operator} ${stringifyExpression(node.right)}`;
2060
+ return `${stringifyExpression(node.left)} ${node.operator} ${stringifyExpression(node.right)} `;
2342
2061
  case "Function":
2343
- return `${node.name}(${node.args.map(stringifyExpression).join(", ")})`;
2062
+ return `${node.name} (${node.args.map(stringifyExpression).join(", ")})`;
2344
2063
  default:
2345
2064
  return "";
2346
2065
  }
@@ -2405,6 +2124,61 @@ function buildBindingMetadataFromExpression(node, variables) {
2405
2124
  }
2406
2125
 
2407
2126
  // src/graphBuilder.ts
2127
+ function resolveBindingSlotInputId(bindingInputId, inputsById) {
2128
+ if (!bindingInputId || bindingInputId === import_utils5.SELF_BINDING_ID) {
2129
+ return bindingInputId;
2130
+ }
2131
+ const resolvedInputId = (0, import_utils4.resolveStandardRigInputId)(bindingInputId, inputsById);
2132
+ if (inputsById.has(resolvedInputId)) {
2133
+ return resolvedInputId;
2134
+ }
2135
+ return bindingInputId;
2136
+ }
2137
+ function isRigElementAliasInput(inputId, inputsById) {
2138
+ const input = inputsById.get(inputId);
2139
+ if (!input?.path) {
2140
+ return false;
2141
+ }
2142
+ return (0, import_utils4.isRigElementStandardInputPath)(input.path);
2143
+ }
2144
+ function isHigherOrderRigBindingInput(inputId, inputsById) {
2145
+ const input = inputsById.get(inputId);
2146
+ if (!input?.path) {
2147
+ return false;
2148
+ }
2149
+ if (isRigElementAliasInput(inputId, inputsById)) {
2150
+ return false;
2151
+ }
2152
+ return true;
2153
+ }
2154
+ function bindingReferencesRigElementInput(binding, inputsById) {
2155
+ const candidateInputIds = /* @__PURE__ */ new Set();
2156
+ if (binding.inputId && binding.inputId !== import_utils5.SELF_BINDING_ID) {
2157
+ candidateInputIds.add(binding.inputId);
2158
+ }
2159
+ binding.slots.forEach((slot) => {
2160
+ if (slot.inputId && slot.inputId !== import_utils5.SELF_BINDING_ID) {
2161
+ candidateInputIds.add(slot.inputId);
2162
+ }
2163
+ });
2164
+ for (const candidateInputId of candidateInputIds) {
2165
+ if ((0, import_utils4.isRigElementStandardInputPath)(candidateInputId)) {
2166
+ return true;
2167
+ }
2168
+ const resolvedCandidateId = resolveBindingSlotInputId(
2169
+ candidateInputId,
2170
+ inputsById
2171
+ );
2172
+ if (!resolvedCandidateId || resolvedCandidateId === import_utils5.SELF_BINDING_ID) {
2173
+ continue;
2174
+ }
2175
+ const resolvedInput = inputsById.get(resolvedCandidateId);
2176
+ if (resolvedInput && (0, import_utils4.isRigElementStandardInputPath)(resolvedInput.path)) {
2177
+ return true;
2178
+ }
2179
+ }
2180
+ return false;
2181
+ }
2408
2182
  function evaluateBinding({
2409
2183
  binding,
2410
2184
  target,
@@ -2413,9 +2187,18 @@ function evaluateBinding({
2413
2187
  component,
2414
2188
  safeId,
2415
2189
  context,
2416
- selfNodeId
2190
+ selfNodeId,
2191
+ enforceRigBoundaryRules = false
2417
2192
  }) {
2418
- const { nodes, edges, ensureInputNode, bindingIssues, summaryBindings } = context;
2193
+ const {
2194
+ nodes,
2195
+ edges,
2196
+ ensureInputNode,
2197
+ bindingIssues,
2198
+ summaryBindings,
2199
+ inputsById,
2200
+ inputBindings
2201
+ } = context;
2419
2202
  const exprContext = {
2420
2203
  componentSafeId: safeId,
2421
2204
  nodes,
@@ -2424,7 +2207,6 @@ function evaluateBinding({
2424
2207
  counter: 0,
2425
2208
  reservedNodes: /* @__PURE__ */ new Map(),
2426
2209
  nodeValueTypes: /* @__PURE__ */ new Map(),
2427
- slotRemapNodes: /* @__PURE__ */ new Map(),
2428
2210
  graphReservedNodes: context.graphReservedNodes,
2429
2211
  generateReservedNodeId: context.generateReservedNodeId
2430
2212
  };
@@ -2440,9 +2222,13 @@ function evaluateBinding({
2440
2222
  const fallbackAlias = `s${index + 1}`;
2441
2223
  const alias = aliasBase.length > 0 ? aliasBase : fallbackAlias;
2442
2224
  const slotId = slot.id && slot.id.length > 0 ? slot.id : alias;
2225
+ const resolvedSlotInputId = resolveBindingSlotInputId(
2226
+ slot.inputId,
2227
+ inputsById
2228
+ );
2443
2229
  const slotValueType = slot.valueType === "vector" ? "vector" : "scalar";
2444
2230
  let slotOutputId;
2445
- if (slot.inputId === import_utils3.SELF_BINDING_ID) {
2231
+ if (slot.inputId === import_utils5.SELF_BINDING_ID) {
2446
2232
  if (selfNodeId) {
2447
2233
  slotOutputId = selfNodeId;
2448
2234
  hasActiveSlot = true;
@@ -2455,19 +2241,30 @@ function evaluateBinding({
2455
2241
  expressionIssues.push("Self reference unavailable for this input.");
2456
2242
  slotOutputId = getConstantNodeId(exprContext, target.defaultValue);
2457
2243
  }
2458
- } else if (slot.inputId) {
2459
- const inputNode = ensureInputNode(slot.inputId);
2460
- if (inputNode) {
2461
- slotOutputId = inputNode.nodeId;
2462
- hasActiveSlot = true;
2463
- setNodeValueType(
2464
- exprContext,
2465
- slotOutputId,
2466
- slotValueType === "vector" ? "vector" : "scalar"
2244
+ } else if (resolvedSlotInputId) {
2245
+ const inputId = resolvedSlotInputId;
2246
+ const sourceBinding = inputBindings[inputId];
2247
+ const allowedHigherOrderViaRigElementSource = sourceBinding !== void 0 && bindingReferencesRigElementInput(sourceBinding, inputsById);
2248
+ if (enforceRigBoundaryRules && isHigherOrderRigBindingInput(inputId, inputsById) && !allowedHigherOrderViaRigElementSource && inputId !== import_utils5.SELF_BINDING_ID) {
2249
+ expressionIssues.push(
2250
+ `Input "${inputId}" is a higher-order rig input and cannot directly drive animatable "${target.id}".`
2467
2251
  );
2468
- } else {
2469
- expressionIssues.push(`Missing standard input "${slot.inputId}".`);
2470
2252
  slotOutputId = getConstantNodeId(exprContext, 0);
2253
+ hasActiveSlot = true;
2254
+ } else {
2255
+ const inputNode = ensureInputNode(inputId);
2256
+ if (inputNode) {
2257
+ slotOutputId = inputNode.nodeId;
2258
+ hasActiveSlot = true;
2259
+ setNodeValueType(
2260
+ exprContext,
2261
+ slotOutputId,
2262
+ slotValueType === "vector" ? "vector" : "scalar"
2263
+ );
2264
+ } else {
2265
+ expressionIssues.push(`Missing standard input "${inputId}".`);
2266
+ slotOutputId = getConstantNodeId(exprContext, 0);
2267
+ }
2471
2268
  }
2472
2269
  } else {
2473
2270
  slotOutputId = getConstantNodeId(exprContext, 0);
@@ -2477,13 +2274,11 @@ function evaluateBinding({
2477
2274
  nodeId: slotOutputId,
2478
2275
  slotId,
2479
2276
  slotAlias: alias,
2480
- inputId: slot.inputId ?? null,
2277
+ inputId: resolvedSlotInputId ?? null,
2481
2278
  targetId,
2482
2279
  animatableId,
2483
2280
  component,
2484
- valueType: slotValueType,
2485
- remap: { ...slot.remap },
2486
- autoRemap: slot.inputId !== import_utils3.SELF_BINDING_ID && slotValueType === "scalar"
2281
+ valueType: slotValueType
2487
2282
  });
2488
2283
  setNodeValueType(
2489
2284
  exprContext,
@@ -2496,8 +2291,7 @@ function evaluateBinding({
2496
2291
  component,
2497
2292
  slotId,
2498
2293
  slotAlias: alias,
2499
- inputId: slot.inputId ?? null,
2500
- remap: { ...slot.remap },
2294
+ inputId: resolvedSlotInputId ?? null,
2501
2295
  expression: trimmedExpression,
2502
2296
  valueType: slotValueType,
2503
2297
  nodeId: slotOutputId,
@@ -2516,9 +2310,7 @@ function evaluateBinding({
2516
2310
  targetId,
2517
2311
  animatableId,
2518
2312
  component,
2519
- valueType: targetValueType,
2520
- remap: createDefaultRemap(target),
2521
- autoRemap: false
2313
+ valueType: targetValueType
2522
2314
  });
2523
2315
  setNodeValueType(
2524
2316
  exprContext,
@@ -2532,7 +2324,6 @@ function evaluateBinding({
2532
2324
  slotId: PRIMARY_SLOT_ID,
2533
2325
  slotAlias: alias,
2534
2326
  inputId: null,
2535
- remap: createDefaultRemap(target),
2536
2327
  expression: trimmedExpression,
2537
2328
  valueType: targetValueType,
2538
2329
  nodeId: constantId,
@@ -2647,6 +2438,20 @@ function buildRigInputPath(faceId, inputPath) {
2647
2438
  const suffix = trimmed ? `/${trimmed}` : "";
2648
2439
  return `rig/${faceId}${suffix}`;
2649
2440
  }
2441
+ function buildPoseControlInputPath(faceId, inputId) {
2442
+ return `rig/${faceId}/pose/control/${inputId}`;
2443
+ }
2444
+ function isPoseWeightInputPath(path) {
2445
+ const normalized = (0, import_utils4.normalizeStandardRigInputPath)(path);
2446
+ return normalized.startsWith("/poses/") && normalized.endsWith(".weight");
2447
+ }
2448
+ function isPoseControlPath(path) {
2449
+ const normalized = (0, import_utils4.normalizeStandardRigInputPath)(path);
2450
+ return normalized.startsWith("/pose/control/");
2451
+ }
2452
+ function resolveInputComposeMode(mode) {
2453
+ return mode === "average" ? "average" : "add";
2454
+ }
2650
2455
  function getComponentOrder(animatable) {
2651
2456
  switch (animatable.type) {
2652
2457
  case "vector2":
@@ -2729,73 +2534,6 @@ function ensureOperandValueType(context, operandId, expected, functionName, inpu
2729
2534
  `Function "${functionName}" expects ${expectation} input for "${inputId}", but the expression produced ${actual}.`
2730
2535
  );
2731
2536
  }
2732
- function resolveSlotReferenceNode(entry, fallbackNodeId, context) {
2733
- if (entry.kind !== "slot") {
2734
- return fallbackNodeId;
2735
- }
2736
- const metadata = entry.metadata;
2737
- if (!metadata || metadata.autoRemap === false || !metadata.remap) {
2738
- return fallbackNodeId;
2739
- }
2740
- if (metadata.valueType !== "scalar") {
2741
- return fallbackNodeId;
2742
- }
2743
- if (isIdentityRemap(metadata.remap)) {
2744
- return fallbackNodeId;
2745
- }
2746
- const cacheKey = metadata.slotId ?? entry.name;
2747
- const existing = context.slotRemapNodes.get(cacheKey);
2748
- if (existing) {
2749
- return existing;
2750
- }
2751
- const remapNodeId = createSlotRemapNode(
2752
- context,
2753
- fallbackNodeId,
2754
- metadata.remap,
2755
- metadata.slotAlias ?? cacheKey
2756
- );
2757
- context.slotRemapNodes.set(cacheKey, remapNodeId);
2758
- return remapNodeId;
2759
- }
2760
- function createSlotRemapNode(context, sourceNodeId, remap, slotKey) {
2761
- const safeSlotKey = sanitizeNodeId(slotKey || "slot");
2762
- const nodeId = `slot_remap_${safeSlotKey}_${context.counter++}`;
2763
- context.nodes.push({
2764
- id: nodeId,
2765
- type: "centered_remap",
2766
- inputDefaults: {
2767
- in_low: remap.inLow,
2768
- in_anchor: remap.inAnchor,
2769
- in_high: remap.inHigh,
2770
- out_low: remap.outLow,
2771
- out_anchor: remap.outAnchor,
2772
- out_high: remap.outHigh
2773
- }
2774
- });
2775
- context.edges.push({
2776
- from: { nodeId: sourceNodeId },
2777
- to: { nodeId, portId: "in" }
2778
- });
2779
- setNodeValueType(context, nodeId, "scalar");
2780
- return nodeId;
2781
- }
2782
- function isIdentityRemap(remap) {
2783
- return nearlyEqual(remap.inLow, remap.outLow) && nearlyEqual(remap.inAnchor, remap.outAnchor) && nearlyEqual(remap.inHigh, remap.outHigh);
2784
- }
2785
- function nearlyEqual(a, b, epsilon = 1e-4) {
2786
- return Math.abs(a - b) <= epsilon;
2787
- }
2788
- var REMAP_FUNCTION_NODE_TYPES = /* @__PURE__ */ new Set([
2789
- "piecewise_remap",
2790
- "centered_remap",
2791
- "remap"
2792
- ]);
2793
- function shouldSkipAutoRemapForArgument(nodeType, index) {
2794
- if (!REMAP_FUNCTION_NODE_TYPES.has(nodeType)) {
2795
- return false;
2796
- }
2797
- return index === 0;
2798
- }
2799
2537
  function getConstantNodeId(context, value) {
2800
2538
  const key = Number.isFinite(value) ? value.toString() : "NaN";
2801
2539
  const existing = context.constants.get(key);
@@ -3254,8 +2992,7 @@ var BINARY_FUNCTION_OPERATOR_MAP = {
3254
2992
  "&&": "and",
3255
2993
  "||": "or"
3256
2994
  };
3257
- function materializeExpression(node, context, variables, issues, options) {
3258
- const autoRemap = options?.autoRemap !== false;
2995
+ function materializeExpression(node, context, variables, issues) {
3259
2996
  switch (node.type) {
3260
2997
  case "Literal": {
3261
2998
  return getConstantNodeId(context, node.value);
@@ -3270,10 +3007,7 @@ function materializeExpression(node, context, variables, issues, options) {
3270
3007
  return getConstantNodeId(context, 0);
3271
3008
  }
3272
3009
  const mappedId = entry.nodeId ?? getConstantNodeId(context, 0);
3273
- if (!autoRemap || entry.kind !== "slot") {
3274
- return mappedId;
3275
- }
3276
- return resolveSlotReferenceNode(entry, mappedId, context);
3010
+ return mappedId;
3277
3011
  }
3278
3012
  case "Unary": {
3279
3013
  const operandId = materializeExpression(
@@ -3411,13 +3145,7 @@ function materializeExpression(node, context, variables, issues, options) {
3411
3145
  );
3412
3146
  const operandNodes = argNodes.slice(0, operandLimit);
3413
3147
  const operands = operandNodes.map(
3414
- (arg, index) => materializeExpression(
3415
- arg,
3416
- context,
3417
- variables,
3418
- issues,
3419
- shouldSkipAutoRemapForArgument(definition.nodeType, index) ? { autoRemap: false } : void 0
3420
- )
3148
+ (arg, _index) => materializeExpression(arg, context, variables, issues)
3421
3149
  );
3422
3150
  const paramArgStart = operandLimit;
3423
3151
  const paramArgNodes = paramArgCount > 0 ? argNodes.slice(paramArgStart, paramArgStart + paramArgCount) : [];
@@ -3446,7 +3174,9 @@ function buildRigGraphSpec({
3446
3174
  bindings,
3447
3175
  inputsById,
3448
3176
  inputBindings,
3449
- inputMetadata
3177
+ inputMetadata,
3178
+ inputComposeModesById,
3179
+ pipelineV1
3450
3180
  }) {
3451
3181
  const metadataByInputId = inputMetadata ?? /* @__PURE__ */ new Map();
3452
3182
  const irBuilder = createIrGraphBuilder({
@@ -3469,8 +3199,634 @@ function buildRigGraphSpec({
3469
3199
  const computedInputs = /* @__PURE__ */ new Set();
3470
3200
  const summaryBindings = [];
3471
3201
  const bindingIssues = /* @__PURE__ */ new Map();
3202
+ const stagedPipelineByInputId = /* @__PURE__ */ new Map();
3472
3203
  const animatableEntries = /* @__PURE__ */ new Map();
3473
3204
  const outputs = /* @__PURE__ */ new Set();
3205
+ const composeModeByInputId = /* @__PURE__ */ new Map();
3206
+ Object.entries(inputComposeModesById ?? {}).forEach(([inputId, mode]) => {
3207
+ if (!inputsById.has(inputId)) {
3208
+ return;
3209
+ }
3210
+ composeModeByInputId.set(inputId, resolveInputComposeMode(mode));
3211
+ });
3212
+ const shouldComposeInputWithPoseControl = (input) => {
3213
+ if (!composeModeByInputId.has(input.id)) {
3214
+ return false;
3215
+ }
3216
+ if (isPoseWeightInputPath(input.path)) {
3217
+ return false;
3218
+ }
3219
+ if (isPoseControlPath(input.path)) {
3220
+ return false;
3221
+ }
3222
+ return true;
3223
+ };
3224
+ const buildNormalizedAdditiveBlendNodeId = ({
3225
+ nodeIdPrefix,
3226
+ sourceNodeIds,
3227
+ baseline
3228
+ }) => {
3229
+ if (sourceNodeIds.length === 0) {
3230
+ const fallbackNodeId = `${nodeIdPrefix}_baseline`;
3231
+ nodes.push({
3232
+ id: fallbackNodeId,
3233
+ type: "constant",
3234
+ params: {
3235
+ value: baseline
3236
+ }
3237
+ });
3238
+ return fallbackNodeId;
3239
+ }
3240
+ if (sourceNodeIds.length === 1) {
3241
+ return sourceNodeIds[0];
3242
+ }
3243
+ const addNodeId = `${nodeIdPrefix}_add`;
3244
+ nodes.push({
3245
+ id: addNodeId,
3246
+ type: "add"
3247
+ });
3248
+ sourceNodeIds.forEach((sourceNodeId, index) => {
3249
+ edges.push({
3250
+ from: { nodeId: sourceNodeId },
3251
+ to: { nodeId: addNodeId, portId: `operand_${index + 1}` }
3252
+ });
3253
+ });
3254
+ const normalizedNodeId = `${nodeIdPrefix}_normalized_add`;
3255
+ nodes.push({
3256
+ id: normalizedNodeId,
3257
+ type: "subtract",
3258
+ inputDefaults: {
3259
+ rhs: (sourceNodeIds.length - 1) * baseline
3260
+ }
3261
+ });
3262
+ edges.push({
3263
+ from: { nodeId: addNodeId },
3264
+ to: { nodeId: normalizedNodeId, portId: "lhs" }
3265
+ });
3266
+ return normalizedNodeId;
3267
+ };
3268
+ const splitTopLevelCommaSeparated = (value) => {
3269
+ const segments = [];
3270
+ let depthParen = 0;
3271
+ let depthBracket = 0;
3272
+ let start = 0;
3273
+ for (let index = 0; index < value.length; index += 1) {
3274
+ const char = value[index];
3275
+ if (char === "(") {
3276
+ depthParen += 1;
3277
+ continue;
3278
+ }
3279
+ if (char === ")") {
3280
+ depthParen = Math.max(0, depthParen - 1);
3281
+ continue;
3282
+ }
3283
+ if (char === "[") {
3284
+ depthBracket += 1;
3285
+ continue;
3286
+ }
3287
+ if (char === "]") {
3288
+ depthBracket = Math.max(0, depthBracket - 1);
3289
+ continue;
3290
+ }
3291
+ if (char === "," && depthParen === 0 && depthBracket === 0) {
3292
+ segments.push(value.slice(start, index));
3293
+ start = index + 1;
3294
+ }
3295
+ }
3296
+ segments.push(value.slice(start));
3297
+ return segments;
3298
+ };
3299
+ const stripTopLevelAssignment = (value) => {
3300
+ let depthParen = 0;
3301
+ let depthBracket = 0;
3302
+ for (let index = 0; index < value.length; index += 1) {
3303
+ const char = value[index];
3304
+ if (char === "(") {
3305
+ depthParen += 1;
3306
+ continue;
3307
+ }
3308
+ if (char === ")") {
3309
+ depthParen = Math.max(0, depthParen - 1);
3310
+ continue;
3311
+ }
3312
+ if (char === "[") {
3313
+ depthBracket += 1;
3314
+ continue;
3315
+ }
3316
+ if (char === "]") {
3317
+ depthBracket = Math.max(0, depthBracket - 1);
3318
+ continue;
3319
+ }
3320
+ if (char !== "=" || depthParen !== 0 || depthBracket !== 0) {
3321
+ continue;
3322
+ }
3323
+ const previous = value[index - 1];
3324
+ const next = value[index + 1];
3325
+ if (previous === "=" || next === "=") {
3326
+ continue;
3327
+ }
3328
+ return value.slice(index + 1).trim();
3329
+ }
3330
+ return value.trim();
3331
+ };
3332
+ const isNormalizedAdditiveFunctionName = (value) => {
3333
+ const normalized = value.trim().toLowerCase();
3334
+ return normalized === "normalizedadditive" || normalized === "normalizedaddative" || normalized === "noramalizedadditive" || normalized === "noramalizedaddative";
3335
+ };
3336
+ const buildNormalizedAdditiveExpression = (value) => {
3337
+ const args = splitTopLevelCommaSeparated(value).map(
3338
+ (entry) => entry.trim()
3339
+ );
3340
+ if (args.length === 0) {
3341
+ return "default";
3342
+ }
3343
+ const parentTerms = [];
3344
+ let baselineExpression = "default";
3345
+ const firstArg = args[0];
3346
+ if (firstArg && firstArg.startsWith("[") && firstArg.endsWith("]")) {
3347
+ const inner = firstArg.slice(1, -1).trim();
3348
+ if (inner.length > 0) {
3349
+ splitTopLevelCommaSeparated(inner).forEach((entry) => {
3350
+ const term = entry.trim();
3351
+ if (term.length > 0) {
3352
+ parentTerms.push(term);
3353
+ }
3354
+ });
3355
+ }
3356
+ args.slice(1).forEach((entry) => {
3357
+ const baselineMatch = entry.match(/^baseline\s*=\s*(.+)$/i);
3358
+ if (baselineMatch?.[1]) {
3359
+ baselineExpression = baselineMatch[1].trim();
3360
+ return;
3361
+ }
3362
+ const term = entry.trim();
3363
+ if (term.length > 0) {
3364
+ parentTerms.push(term);
3365
+ }
3366
+ });
3367
+ } else {
3368
+ args.forEach((entry) => {
3369
+ const baselineMatch = entry.match(/^baseline\s*=\s*(.+)$/i);
3370
+ if (baselineMatch?.[1]) {
3371
+ baselineExpression = baselineMatch[1].trim();
3372
+ return;
3373
+ }
3374
+ const term = entry.trim();
3375
+ if (term.length > 0) {
3376
+ parentTerms.push(term);
3377
+ }
3378
+ });
3379
+ }
3380
+ if (parentTerms.length === 0) {
3381
+ return `(${baselineExpression})`;
3382
+ }
3383
+ if (parentTerms.length === 1) {
3384
+ return `(${parentTerms[0]})`;
3385
+ }
3386
+ return `((${parentTerms.join(" + ")}) - (${parentTerms.length - 1}) * (${baselineExpression}))`;
3387
+ };
3388
+ const rewriteNormalizedAdditiveCalls = (value) => {
3389
+ let cursor = 0;
3390
+ let rewritten = "";
3391
+ while (cursor < value.length) {
3392
+ const remaining = value.slice(cursor);
3393
+ const match = remaining.match(
3394
+ /(normalizedadditive|normalizedaddative|noramalizedadditive|noramalizedaddative)\s*\(/i
3395
+ );
3396
+ if (!match || match.index === void 0) {
3397
+ rewritten += remaining;
3398
+ break;
3399
+ }
3400
+ const matchStart = cursor + match.index;
3401
+ const functionName = match[1] ?? "";
3402
+ const openParenIndex = value.indexOf(
3403
+ "(",
3404
+ matchStart + functionName.length
3405
+ );
3406
+ if (openParenIndex < 0) {
3407
+ rewritten += value.slice(cursor);
3408
+ break;
3409
+ }
3410
+ rewritten += value.slice(cursor, matchStart);
3411
+ let depth = 1;
3412
+ let closeParenIndex = openParenIndex + 1;
3413
+ while (closeParenIndex < value.length && depth > 0) {
3414
+ const char = value[closeParenIndex];
3415
+ if (char === "(") {
3416
+ depth += 1;
3417
+ } else if (char === ")") {
3418
+ depth -= 1;
3419
+ }
3420
+ closeParenIndex += 1;
3421
+ }
3422
+ if (depth !== 0) {
3423
+ rewritten += value.slice(matchStart);
3424
+ break;
3425
+ }
3426
+ const argsContent = value.slice(openParenIndex + 1, closeParenIndex - 1);
3427
+ if (isNormalizedAdditiveFunctionName(functionName)) {
3428
+ rewritten += buildNormalizedAdditiveExpression(argsContent);
3429
+ } else {
3430
+ rewritten += value.slice(matchStart, closeParenIndex);
3431
+ }
3432
+ cursor = closeParenIndex;
3433
+ }
3434
+ return rewritten;
3435
+ };
3436
+ const normalizeStagedFormulaExpression = (expression) => {
3437
+ const rhs = stripTopLevelAssignment(expression);
3438
+ return rewriteNormalizedAdditiveCalls(rhs);
3439
+ };
3440
+ const normalizeFormulaSignature = (expression) => normalizeStagedFormulaExpression(expression).replace(/\s+/g, "").toLowerCase();
3441
+ const buildDefaultParentTransformNodeId = (params) => {
3442
+ let transformedNodeId = params.sourceNodeId;
3443
+ if (params.scale !== 1) {
3444
+ const scaledNodeId = `input_parent_scale_${params.nodeSuffix}`;
3445
+ nodes.push({
3446
+ id: scaledNodeId,
3447
+ type: "multiply",
3448
+ inputDefaults: {
3449
+ operand_2: params.scale
3450
+ }
3451
+ });
3452
+ edges.push({
3453
+ from: { nodeId: transformedNodeId },
3454
+ to: { nodeId: scaledNodeId, portId: "operand_1" }
3455
+ });
3456
+ transformedNodeId = scaledNodeId;
3457
+ }
3458
+ if (params.offset !== 0) {
3459
+ const offsetNodeId = `input_parent_offset_${params.nodeSuffix}`;
3460
+ nodes.push({
3461
+ id: offsetNodeId,
3462
+ type: "add",
3463
+ inputDefaults: {
3464
+ operand_2: params.offset
3465
+ }
3466
+ });
3467
+ edges.push({
3468
+ from: { nodeId: transformedNodeId },
3469
+ to: { nodeId: offsetNodeId, portId: "operand_1" }
3470
+ });
3471
+ transformedNodeId = offsetNodeId;
3472
+ }
3473
+ return transformedNodeId;
3474
+ };
3475
+ const buildStagedFormulaNodeId = (params) => {
3476
+ const normalizedExpression = normalizeStagedFormulaExpression(
3477
+ params.expression
3478
+ );
3479
+ if (!normalizedExpression) {
3480
+ return params.fallbackNodeId;
3481
+ }
3482
+ const parseResult = parseControlExpression(normalizedExpression);
3483
+ const issues = [];
3484
+ if (!parseResult.node) {
3485
+ parseResult.errors.forEach((error) => {
3486
+ issues.push(
3487
+ `${params.issuePrefix}: ${error.message} (index ${error.index}).`
3488
+ );
3489
+ });
3490
+ }
3491
+ if (!parseResult.node || issues.length > 0) {
3492
+ const issueSet = bindingIssues.get(params.inputId) ?? /* @__PURE__ */ new Set();
3493
+ issues.forEach((issue) => issueSet.add(issue));
3494
+ if (issues.length > 0) {
3495
+ bindingIssues.set(params.inputId, issueSet);
3496
+ }
3497
+ return params.fallbackNodeId;
3498
+ }
3499
+ const exprContext = {
3500
+ componentSafeId: params.componentSafeId,
3501
+ nodes,
3502
+ edges,
3503
+ constants: /* @__PURE__ */ new Map(),
3504
+ counter: 1,
3505
+ reservedNodes: /* @__PURE__ */ new Map(),
3506
+ nodeValueTypes: /* @__PURE__ */ new Map(),
3507
+ graphReservedNodes,
3508
+ generateReservedNodeId
3509
+ };
3510
+ const variableTable = createExpressionVariableTable();
3511
+ const registerVariableName = (name, nodeId2) => {
3512
+ const trimmed = name.trim();
3513
+ if (!trimmed) {
3514
+ return;
3515
+ }
3516
+ variableTable.registerReservedVariable({
3517
+ name: trimmed,
3518
+ nodeId: nodeId2,
3519
+ description: "Staged pipeline formula variable"
3520
+ });
3521
+ const lower = trimmed.toLowerCase();
3522
+ if (lower !== trimmed) {
3523
+ variableTable.registerReservedVariable({
3524
+ name: lower,
3525
+ nodeId: nodeId2,
3526
+ description: "Staged pipeline formula variable"
3527
+ });
3528
+ }
3529
+ };
3530
+ Object.entries(params.variables).forEach(([name, variable]) => {
3531
+ const nodeId2 = variable.nodeId ?? (typeof variable.value === "number" && Number.isFinite(variable.value) ? getConstantNodeId(exprContext, variable.value) : null);
3532
+ if (!nodeId2) {
3533
+ return;
3534
+ }
3535
+ registerVariableName(name, nodeId2);
3536
+ });
3537
+ const references = collectExpressionReferences(parseResult.node);
3538
+ const missingVariables = variableTable.missing(references);
3539
+ if (missingVariables.length > 0) {
3540
+ const issueSet = bindingIssues.get(params.inputId) ?? /* @__PURE__ */ new Set();
3541
+ missingVariables.forEach((entry) => {
3542
+ issueSet.add(
3543
+ `${params.issuePrefix}: unknown formula variable "${entry.name}".`
3544
+ );
3545
+ });
3546
+ bindingIssues.set(params.inputId, issueSet);
3547
+ return params.fallbackNodeId;
3548
+ }
3549
+ validateLiteralParamArguments(parseResult.node, issues);
3550
+ const nodeId = materializeExpression(
3551
+ parseResult.node,
3552
+ exprContext,
3553
+ variableTable,
3554
+ issues
3555
+ );
3556
+ if (issues.length > 0) {
3557
+ const issueSet = bindingIssues.get(params.inputId) ?? /* @__PURE__ */ new Set();
3558
+ issues.forEach(
3559
+ (issue) => issueSet.add(`${params.issuePrefix}: ${issue}`)
3560
+ );
3561
+ bindingIssues.set(params.inputId, issueSet);
3562
+ return params.fallbackNodeId;
3563
+ }
3564
+ return nodeId;
3565
+ };
3566
+ const buildLegacyEffectiveInputNodeId = (input, directNodeId) => {
3567
+ if (!shouldComposeInputWithPoseControl(input)) {
3568
+ return directNodeId;
3569
+ }
3570
+ const safeInputId = sanitizeNodeId(input.id);
3571
+ const composeBaseline = Number.isFinite(input.defaultValue) ? input.defaultValue : 0;
3572
+ const poseControlNodeId = `input_pose_control_${safeInputId}`;
3573
+ nodes.push({
3574
+ id: poseControlNodeId,
3575
+ type: "input",
3576
+ params: {
3577
+ path: buildPoseControlInputPath(faceId, input.id),
3578
+ value: { float: composeBaseline }
3579
+ }
3580
+ });
3581
+ const composeAddNodeId = `input_compose_add_${safeInputId}`;
3582
+ nodes.push({
3583
+ id: composeAddNodeId,
3584
+ type: "add"
3585
+ });
3586
+ edges.push(
3587
+ {
3588
+ from: { nodeId: directNodeId },
3589
+ to: { nodeId: composeAddNodeId, portId: "operand_1" }
3590
+ },
3591
+ {
3592
+ from: { nodeId: poseControlNodeId },
3593
+ to: { nodeId: composeAddNodeId, portId: "operand_2" }
3594
+ }
3595
+ );
3596
+ const composeMode = composeModeByInputId.get(input.id) ?? "add";
3597
+ let composeOutputNodeId = composeAddNodeId;
3598
+ if (composeMode === "average") {
3599
+ composeOutputNodeId = `input_compose_average_${safeInputId}`;
3600
+ nodes.push({
3601
+ id: composeOutputNodeId,
3602
+ type: "divide",
3603
+ inputDefaults: { rhs: 2 }
3604
+ });
3605
+ edges.push({
3606
+ from: { nodeId: composeAddNodeId },
3607
+ to: { nodeId: composeOutputNodeId, portId: "lhs" }
3608
+ });
3609
+ } else {
3610
+ composeOutputNodeId = `input_compose_normalized_add_${safeInputId}`;
3611
+ nodes.push({
3612
+ id: composeOutputNodeId,
3613
+ type: "subtract",
3614
+ inputDefaults: { rhs: composeBaseline }
3615
+ });
3616
+ edges.push({
3617
+ from: { nodeId: composeAddNodeId },
3618
+ to: { nodeId: composeOutputNodeId, portId: "lhs" }
3619
+ });
3620
+ }
3621
+ const minValue = Number.isFinite(input.range.min) ? input.range.min : -1;
3622
+ const maxValue = Number.isFinite(input.range.max) ? input.range.max : 1;
3623
+ const clampNodeId = `input_effective_${safeInputId}`;
3624
+ nodes.push({
3625
+ id: clampNodeId,
3626
+ type: "clamp",
3627
+ inputDefaults: { min: minValue, max: maxValue }
3628
+ });
3629
+ edges.push({
3630
+ from: { nodeId: composeOutputNodeId },
3631
+ to: { nodeId: clampNodeId, portId: "in" }
3632
+ });
3633
+ return clampNodeId;
3634
+ };
3635
+ const buildStagedEffectiveInputNodeId = (input, stagedConfig) => {
3636
+ const safeInputId = sanitizeNodeId(input.id);
3637
+ const composeBaseline = Number.isFinite(input.defaultValue) ? input.defaultValue : 0;
3638
+ const parentContributionNodes = [];
3639
+ const parentNodeIdByAlias = /* @__PURE__ */ new Map();
3640
+ stagedConfig.parents.forEach((parent, index) => {
3641
+ if (!parent.enabled) {
3642
+ return;
3643
+ }
3644
+ const resolvedParentInputId = (0, import_utils4.resolveStandardRigInputId)(
3645
+ parent.inputId,
3646
+ inputsById
3647
+ );
3648
+ const parentInput = ensureInputNode(resolvedParentInputId);
3649
+ if (!parentInput) {
3650
+ const issueSet = bindingIssues.get(input.id) ?? /* @__PURE__ */ new Set();
3651
+ issueSet.add(
3652
+ `Staged parent "${resolvedParentInputId}" missing for "${input.id}".`
3653
+ );
3654
+ bindingIssues.set(input.id, issueSet);
3655
+ return;
3656
+ }
3657
+ const nodeSuffix = `${safeInputId}_${index + 1}`;
3658
+ const fallbackParentNodeId = buildDefaultParentTransformNodeId({
3659
+ sourceNodeId: parentInput.nodeId,
3660
+ nodeSuffix,
3661
+ scale: parent.scale,
3662
+ offset: parent.offset
3663
+ });
3664
+ const defaultParentFormulaExpression = `${parent.alias} = parent * scale + offset`;
3665
+ const parentFormulaNodeId = normalizeFormulaSignature(parent.expression) === normalizeFormulaSignature(defaultParentFormulaExpression) ? fallbackParentNodeId : buildStagedFormulaNodeId({
3666
+ expression: parent.expression,
3667
+ fallbackNodeId: fallbackParentNodeId,
3668
+ componentSafeId: `staged_parent_${nodeSuffix}`,
3669
+ inputId: input.id,
3670
+ issuePrefix: `Parent formula "${parent.alias}"`,
3671
+ variables: {
3672
+ parent: { nodeId: parentInput.nodeId },
3673
+ scale: { value: parent.scale },
3674
+ offset: { value: parent.offset },
3675
+ default: { value: composeBaseline },
3676
+ baseline: { value: composeBaseline }
3677
+ }
3678
+ });
3679
+ parentContributionNodes.push(parentFormulaNodeId);
3680
+ parentNodeIdByAlias.set(parent.alias, parentFormulaNodeId);
3681
+ const normalizedAlias = parent.alias.toLowerCase();
3682
+ if (normalizedAlias !== parent.alias) {
3683
+ parentNodeIdByAlias.set(normalizedAlias, parentFormulaNodeId);
3684
+ }
3685
+ });
3686
+ const parentContributionNodeId = parentContributionNodes.length > 0 ? (() => {
3687
+ const defaultParentContributionNodeId = buildNormalizedAdditiveBlendNodeId({
3688
+ nodeIdPrefix: `input_parent_blend_${safeInputId}`,
3689
+ sourceNodeIds: parentContributionNodes,
3690
+ baseline: composeBaseline
3691
+ });
3692
+ const defaultParentContributionExpression = `parentContribution = normalizedAdditive([${stagedConfig.parents.filter((entry) => entry.enabled).map((entry) => entry.alias).join(", ")}], baseline=default)`;
3693
+ if (normalizeFormulaSignature(stagedConfig.parentBlend.expression) === normalizeFormulaSignature(defaultParentContributionExpression)) {
3694
+ return defaultParentContributionNodeId;
3695
+ }
3696
+ return buildStagedFormulaNodeId({
3697
+ expression: stagedConfig.parentBlend.expression,
3698
+ fallbackNodeId: defaultParentContributionNodeId,
3699
+ componentSafeId: `staged_parent_contribution_${safeInputId}`,
3700
+ inputId: input.id,
3701
+ issuePrefix: "Parent contribution formula",
3702
+ variables: {
3703
+ ...Object.fromEntries(
3704
+ Array.from(parentNodeIdByAlias.entries()).map(
3705
+ ([alias, nodeId]) => [alias, { nodeId }]
3706
+ )
3707
+ ),
3708
+ default: { value: composeBaseline },
3709
+ baseline: { value: composeBaseline }
3710
+ }
3711
+ });
3712
+ })() : null;
3713
+ let poseContributionNodeId = null;
3714
+ const hasPoseContribution = stagedConfig.poseSource.targetIds.length > 0 || shouldComposeInputWithPoseControl(input);
3715
+ if (hasPoseContribution) {
3716
+ poseContributionNodeId = `input_pose_control_${safeInputId}`;
3717
+ nodes.push({
3718
+ id: poseContributionNodeId,
3719
+ type: "input",
3720
+ params: {
3721
+ path: buildPoseControlInputPath(faceId, input.id),
3722
+ value: { float: composeBaseline }
3723
+ }
3724
+ });
3725
+ }
3726
+ const sourceBranchNodeIds = [];
3727
+ if (parentContributionNodeId) {
3728
+ sourceBranchNodeIds.push(parentContributionNodeId);
3729
+ }
3730
+ if (poseContributionNodeId) {
3731
+ sourceBranchNodeIds.push(poseContributionNodeId);
3732
+ }
3733
+ if (stagedConfig.directInput.enabled) {
3734
+ const directNodeId = `input_direct_${safeInputId}`;
3735
+ nodes.push({
3736
+ id: directNodeId,
3737
+ type: "input",
3738
+ params: {
3739
+ path: stagedConfig.directInput.valuePath,
3740
+ value: { float: composeBaseline }
3741
+ }
3742
+ });
3743
+ sourceBranchNodeIds.push(directNodeId);
3744
+ }
3745
+ const sourceBlendNodeId = buildNormalizedAdditiveBlendNodeId({
3746
+ nodeIdPrefix: `input_source_blend_${safeInputId}`,
3747
+ sourceNodeIds: sourceBranchNodeIds,
3748
+ baseline: composeBaseline
3749
+ });
3750
+ const overrideEnabledNodeId = `input_override_enabled_${safeInputId}`;
3751
+ nodes.push({
3752
+ id: overrideEnabledNodeId,
3753
+ type: "input",
3754
+ params: {
3755
+ path: stagedConfig.override.enabledPath,
3756
+ value: { float: stagedConfig.override.enabledDefault ? 1 : 0 }
3757
+ }
3758
+ });
3759
+ const overrideValueNodeId = `input_override_value_${safeInputId}`;
3760
+ nodes.push({
3761
+ id: overrideValueNodeId,
3762
+ type: "input",
3763
+ params: {
3764
+ path: stagedConfig.override.valuePath,
3765
+ value: { float: stagedConfig.override.valueDefault }
3766
+ }
3767
+ });
3768
+ const overrideDeltaNodeId = `input_override_delta_${safeInputId}`;
3769
+ nodes.push({
3770
+ id: overrideDeltaNodeId,
3771
+ type: "subtract"
3772
+ });
3773
+ edges.push(
3774
+ {
3775
+ from: { nodeId: overrideValueNodeId },
3776
+ to: { nodeId: overrideDeltaNodeId, portId: "lhs" }
3777
+ },
3778
+ {
3779
+ from: { nodeId: sourceBlendNodeId },
3780
+ to: { nodeId: overrideDeltaNodeId, portId: "rhs" }
3781
+ }
3782
+ );
3783
+ const overrideScaleNodeId = `input_override_scale_${safeInputId}`;
3784
+ nodes.push({
3785
+ id: overrideScaleNodeId,
3786
+ type: "multiply"
3787
+ });
3788
+ edges.push(
3789
+ {
3790
+ from: { nodeId: overrideEnabledNodeId },
3791
+ to: { nodeId: overrideScaleNodeId, portId: "operand_1" }
3792
+ },
3793
+ {
3794
+ from: { nodeId: overrideDeltaNodeId },
3795
+ to: { nodeId: overrideScaleNodeId, portId: "operand_2" }
3796
+ }
3797
+ );
3798
+ const overrideSelectedNodeId = `input_override_selected_${safeInputId}`;
3799
+ nodes.push({
3800
+ id: overrideSelectedNodeId,
3801
+ type: "add"
3802
+ });
3803
+ edges.push(
3804
+ {
3805
+ from: { nodeId: sourceBlendNodeId },
3806
+ to: { nodeId: overrideSelectedNodeId, portId: "operand_1" }
3807
+ },
3808
+ {
3809
+ from: { nodeId: overrideScaleNodeId },
3810
+ to: { nodeId: overrideSelectedNodeId, portId: "operand_2" }
3811
+ }
3812
+ );
3813
+ if (!stagedConfig.clamp.enabled) {
3814
+ return overrideSelectedNodeId;
3815
+ }
3816
+ const minValue = Number.isFinite(input.range.min) ? input.range.min : -1;
3817
+ const maxValue = Number.isFinite(input.range.max) ? input.range.max : 1;
3818
+ const clampNodeId = `input_effective_${safeInputId}`;
3819
+ nodes.push({
3820
+ id: clampNodeId,
3821
+ type: "clamp",
3822
+ inputDefaults: { min: minValue, max: maxValue }
3823
+ });
3824
+ edges.push({
3825
+ from: { nodeId: overrideSelectedNodeId },
3826
+ to: { nodeId: clampNodeId, portId: "in" }
3827
+ });
3828
+ return clampNodeId;
3829
+ };
3474
3830
  const ensureInputNode = (inputId) => {
3475
3831
  const existing = inputNodes.get(inputId);
3476
3832
  if (existing) {
@@ -3482,7 +3838,8 @@ function buildRigGraphSpec({
3482
3838
  }
3483
3839
  const defaultValue = Number.isFinite(input.defaultValue) ? input.defaultValue : 0;
3484
3840
  const inputBindingRaw = inputBindings[inputId];
3485
- if (inputBindingRaw) {
3841
+ const isStagedInput = (0, import_utils4.hasRigPipelineV1InputConfig)(pipelineV1, inputId);
3842
+ if (isStagedInput || inputBindingRaw) {
3486
3843
  if (buildingDerived.has(inputId)) {
3487
3844
  const issueSet = bindingIssues.get(inputId) ?? /* @__PURE__ */ new Set();
3488
3845
  issueSet.add("Derived input cycle detected.");
@@ -3491,9 +3848,24 @@ function buildRigGraphSpec({
3491
3848
  }
3492
3849
  buildingDerived.add(inputId);
3493
3850
  try {
3851
+ if (isStagedInput) {
3852
+ const stagedConfig = (0, import_utils4.resolveRigPipelineV1InputConfig)({
3853
+ faceId,
3854
+ input,
3855
+ pipelineV1
3856
+ });
3857
+ stagedPipelineByInputId.set(input.id, stagedConfig);
3858
+ computedInputs.add(inputId);
3859
+ const record3 = {
3860
+ nodeId: buildStagedEffectiveInputNodeId(input, stagedConfig),
3861
+ input
3862
+ };
3863
+ inputNodes.set(inputId, record3);
3864
+ return record3;
3865
+ }
3494
3866
  const target = bindingTargetFromInput(input);
3495
3867
  const binding = ensureBindingStructure(inputBindingRaw, target);
3496
- const requiresSelf = binding.inputId === import_utils3.SELF_BINDING_ID || binding.slots.some((slot) => slot.inputId === import_utils3.SELF_BINDING_ID);
3868
+ const requiresSelf = binding.inputId === import_utils5.SELF_BINDING_ID || binding.slots.some((slot) => slot.inputId === import_utils5.SELF_BINDING_ID);
3497
3869
  let selfNodeId;
3498
3870
  if (requiresSelf) {
3499
3871
  const sliderNodeId = `input_raw_${sanitizeNodeId(inputId)}`;
@@ -3514,7 +3886,10 @@ function buildRigGraphSpec({
3514
3886
  animatableId: inputId,
3515
3887
  component: void 0,
3516
3888
  safeId: sanitizeNodeId(inputId),
3889
+ enforceRigBoundaryRules: false,
3517
3890
  context: {
3891
+ inputsById,
3892
+ inputBindings,
3518
3893
  nodes,
3519
3894
  edges,
3520
3895
  ensureInputNode,
@@ -3534,12 +3909,18 @@ function buildRigGraphSpec({
3534
3909
  value: input.defaultValue
3535
3910
  }
3536
3911
  });
3537
- const record3 = { nodeId: constNodeId, input };
3912
+ const record3 = {
3913
+ nodeId: buildLegacyEffectiveInputNodeId(input, constNodeId),
3914
+ input
3915
+ };
3538
3916
  inputNodes.set(inputId, record3);
3539
3917
  return record3;
3540
3918
  }
3541
3919
  computedInputs.add(inputId);
3542
- const record2 = { nodeId: valueNodeId, input };
3920
+ const record2 = {
3921
+ nodeId: buildLegacyEffectiveInputNodeId(input, valueNodeId),
3922
+ input
3923
+ };
3543
3924
  inputNodes.set(inputId, record2);
3544
3925
  return record2;
3545
3926
  } finally {
@@ -3555,7 +3936,10 @@ function buildRigGraphSpec({
3555
3936
  value: { float: defaultValue }
3556
3937
  }
3557
3938
  });
3558
- const record = { nodeId, input };
3939
+ const record = {
3940
+ nodeId: buildLegacyEffectiveInputNodeId(input, nodeId),
3941
+ input
3942
+ };
3559
3943
  inputNodes.set(inputId, record);
3560
3944
  return record;
3561
3945
  };
@@ -3596,7 +3980,10 @@ function buildRigGraphSpec({
3596
3980
  animatableId: component.animatableId,
3597
3981
  component: component.component,
3598
3982
  safeId: component.safeId,
3983
+ enforceRigBoundaryRules: true,
3599
3984
  context: {
3985
+ inputsById,
3986
+ inputBindings,
3600
3987
  nodes,
3601
3988
  edges,
3602
3989
  ensureInputNode,
@@ -3619,7 +4006,6 @@ function buildRigGraphSpec({
3619
4006
  slotId: PRIMARY_SLOT_ID,
3620
4007
  slotAlias: PRIMARY_SLOT_ALIAS,
3621
4008
  inputId: null,
3622
- remap: createDefaultRemap(target),
3623
4009
  expression: PRIMARY_SLOT_ALIAS,
3624
4010
  valueType: target.valueType === "vector" ? "vector" : "scalar",
3625
4011
  issues: ["Binding not found."],
@@ -3674,7 +4060,7 @@ function buildRigGraphSpec({
3674
4060
  let sourceId = entry.values.get(componentKey);
3675
4061
  if (!sourceId) {
3676
4062
  const componentDefault = entry.defaults.get(componentKey) ?? extractComponentDefault(
3677
- (0, import_utils2.buildAnimatableValue)(entry.animatable, void 0),
4063
+ (0, import_utils4.buildAnimatableValue)(entry.animatable, void 0),
3678
4064
  componentKey
3679
4065
  );
3680
4066
  const constNodeId = `const_${safeId}_${componentKey}`;
@@ -3745,6 +4131,61 @@ function buildRigGraphSpec({
3745
4131
  const filteredSummaryBindings = summaryBindings.filter(
3746
4132
  (binding) => outputs.has(binding.animatableId) || computedInputs.has(binding.animatableId)
3747
4133
  );
4134
+ const pipelineV1ByInputId = stagedPipelineByInputId.size > 0 ? Object.fromEntries(
4135
+ Array.from(stagedPipelineByInputId.entries()).map(
4136
+ ([inputId, stagedConfig]) => [
4137
+ inputId,
4138
+ {
4139
+ inputId: stagedConfig.inputId,
4140
+ parents: stagedConfig.parents.map((parent) => ({
4141
+ linkId: parent.linkId,
4142
+ inputId: parent.inputId,
4143
+ alias: parent.alias,
4144
+ scale: parent.scale,
4145
+ offset: parent.offset,
4146
+ enabled: parent.enabled,
4147
+ expression: parent.expression
4148
+ })),
4149
+ children: stagedConfig.children.map((child) => ({
4150
+ linkId: child.linkId,
4151
+ childInputId: child.childInputId
4152
+ })),
4153
+ parentBlend: {
4154
+ mode: stagedConfig.parentBlend.mode,
4155
+ expression: stagedConfig.parentBlend.expression
4156
+ },
4157
+ poseSource: {
4158
+ targetIds: [...stagedConfig.poseSource.targetIds]
4159
+ },
4160
+ directInput: {
4161
+ enabled: stagedConfig.directInput.enabled,
4162
+ valuePath: stagedConfig.directInput.valuePath
4163
+ },
4164
+ sourceBlend: {
4165
+ mode: stagedConfig.sourceBlend.mode
4166
+ },
4167
+ sourceFallback: {
4168
+ whenNoSources: stagedConfig.sourceFallback.whenNoSources
4169
+ },
4170
+ clamp: {
4171
+ enabled: stagedConfig.clamp.enabled
4172
+ },
4173
+ override: {
4174
+ enabledDefault: stagedConfig.override.enabledDefault,
4175
+ valueDefault: stagedConfig.override.valueDefault,
4176
+ enabledPath: stagedConfig.override.enabledPath,
4177
+ valuePath: stagedConfig.override.valuePath
4178
+ }
4179
+ }
4180
+ ]
4181
+ )
4182
+ ) : void 0;
4183
+ const hasPipelineLinks = pipelineV1?.links && typeof pipelineV1.links === "object" && Object.keys(pipelineV1.links).length > 0;
4184
+ const pipelineV1Metadata = pipelineV1ByInputId || hasPipelineLinks ? {
4185
+ version: import_utils4.RIG_PIPELINE_V1_VERSION,
4186
+ ...pipelineV1ByInputId ? { byInputId: pipelineV1ByInputId } : {},
4187
+ ...hasPipelineLinks ? { links: cloneJsonLike2(pipelineV1?.links) } : {}
4188
+ } : void 0;
3748
4189
  const vizijMetadata = {
3749
4190
  vizij: {
3750
4191
  faceId,
@@ -3777,12 +4218,12 @@ function buildRigGraphSpec({
3777
4218
  }),
3778
4219
  bindings: filteredSummaryBindings.map((binding) => ({
3779
4220
  ...binding,
3780
- remap: { ...binding.remap },
3781
4221
  expression: binding.expression,
3782
4222
  valueType: binding.valueType,
3783
4223
  issues: binding.issues ? [...binding.issues] : void 0,
3784
4224
  metadata: binding.metadata ? cloneJsonLike2(binding.metadata) : void 0
3785
- }))
4225
+ })),
4226
+ ...pipelineV1Metadata ? { pipelineV1: pipelineV1Metadata } : {}
3786
4227
  }
3787
4228
  };
3788
4229
  const issuesByTarget = {};
@@ -3812,7 +4253,6 @@ function buildRigGraphSpec({
3812
4253
  bindings: toIrBindingSummary(
3813
4254
  filteredSummaryBindings.map((binding) => ({
3814
4255
  ...binding,
3815
- remap: { ...binding.remap },
3816
4256
  issues: binding.issues ? [...binding.issues] : void 0
3817
4257
  }))
3818
4258
  )
@@ -3931,7 +4371,7 @@ function cloneJsonLike2(value) {
3931
4371
  if (value === void 0 || value === null) {
3932
4372
  return value;
3933
4373
  }
3934
- return JSON.parse(JSON.stringify(value));
4374
+ return (0, import_utils4.cloneDeepSafe)(value);
3935
4375
  }
3936
4376
  function validateRemapDefaults(nodes) {
3937
4377
  const issues = [];
@@ -3959,15 +4399,8 @@ function validateRemapDefaults(nodes) {
3959
4399
 
3960
4400
  // src/ir/inspection.ts
3961
4401
  var import_metadata3 = require("@vizij/node-graph-wasm/metadata");
4402
+ var import_utils6 = require("@vizij/utils");
3962
4403
  var MACHINE_REPORT_VERSION = 1;
3963
- var REMAP_KEYS = [
3964
- "inLow",
3965
- "inAnchor",
3966
- "inHigh",
3967
- "outLow",
3968
- "outAnchor",
3969
- "outHigh"
3970
- ];
3971
4404
  var DEFAULT_DIFF_LIMIT = 50;
3972
4405
  function buildMachineReport(result) {
3973
4406
  return {
@@ -4008,7 +4441,6 @@ function normalizeGraphBindingSummaries(bindings) {
4008
4441
  slotId: binding.slotId,
4009
4442
  slotAlias: binding.slotAlias,
4010
4443
  inputId: binding.inputId ?? null,
4011
- remap: normalizeRemap2(binding.remap),
4012
4444
  expression: binding.expression,
4013
4445
  valueType: binding.valueType,
4014
4446
  nodeId: binding.nodeId,
@@ -4023,7 +4455,7 @@ function cloneBindingMetadata2(metadata) {
4023
4455
  if (!metadata) {
4024
4456
  return void 0;
4025
4457
  }
4026
- return JSON.parse(JSON.stringify(metadata));
4458
+ return (0, import_utils6.cloneDeepSafe)(metadata);
4027
4459
  }
4028
4460
  function normalizeIssues(issues) {
4029
4461
  const byTargetEntries = Object.entries(issues.byTarget ?? {}).map(
@@ -4107,7 +4539,6 @@ function normalizeIrGraphSummary(summary) {
4107
4539
  function normalizeIrBindingSummaries(bindings) {
4108
4540
  const normalized = bindings.map((binding) => ({
4109
4541
  ...binding,
4110
- remap: sortPlainObject(binding.remap),
4111
4542
  issues: normalizeStringArray(binding.issues)
4112
4543
  }));
4113
4544
  normalized.sort((a, b) => bindingSortKey(a).localeCompare(bindingSortKey(b)));
@@ -4188,6 +4619,9 @@ function normalizeRegistryVariadicSpec(spec) {
4188
4619
  if (typeof spec.max === "number") {
4189
4620
  normalized.max = spec.max;
4190
4621
  }
4622
+ if (spec.keyed) {
4623
+ normalized.keyed = true;
4624
+ }
4191
4625
  return normalized;
4192
4626
  }
4193
4627
  function normalizeRegistryParamSpec(param) {
@@ -4210,13 +4644,6 @@ function normalizeRegistryParamSpec(param) {
4210
4644
  }
4211
4645
  return normalized;
4212
4646
  }
4213
- function normalizeRemap2(remap) {
4214
- const normalized = {};
4215
- REMAP_KEYS.forEach((key) => {
4216
- normalized[key] = remap[key];
4217
- });
4218
- return normalized;
4219
- }
4220
4647
  function normalizeStringArray(values) {
4221
4648
  if (!values || values.length === 0) {
4222
4649
  return void 0;
@@ -4368,9 +4795,7 @@ function normalizeDiffLimit(limit) {
4368
4795
  bindingTargetFromInput,
4369
4796
  bindingToDefinition,
4370
4797
  buildCanonicalBindingExpression,
4371
- buildDefaultSlotExpression,
4372
4798
  buildMachineReport,
4373
- buildPiecewiseRemapExpression,
4374
4799
  buildRigGraphSpec,
4375
4800
  collectExpressionReferences,
4376
4801
  compileIrGraph,
@@ -4378,7 +4803,6 @@ function normalizeDiffLimit(limit) {
4378
4803
  createDefaultBindings,
4379
4804
  createDefaultInputValues,
4380
4805
  createDefaultParentBinding,
4381
- createDefaultRemap,
4382
4806
  createExpressionVariableTable,
4383
4807
  createIrGraphBuilder,
4384
4808
  createLegacyIrGraph,
@@ -4388,12 +4812,10 @@ function normalizeDiffLimit(limit) {
4388
4812
  mapExpression,
4389
4813
  parseControlExpression,
4390
4814
  reconcileBindings,
4391
- remapValue,
4392
4815
  removeBindingSlot,
4393
4816
  toIrBindingSummary,
4394
4817
  updateBindingExpression,
4395
4818
  updateBindingSlotAlias,
4396
- updateBindingSlotRemap,
4397
4819
  updateBindingSlotValueType,
4398
4820
  updateBindingWithInput
4399
4821
  });