@ikijs/editor 0.24.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1476,8 +1476,8 @@ function foregroundSpan(mask, width, height, rowLo, rowHi) {
1476
1476
  }
1477
1477
  return { left, right };
1478
1478
  }
1479
- function headHalfOf(span) {
1480
- return (span.right - span.left + 1) / 2;
1479
+ function headHalfOf(span2) {
1480
+ return (span2.right - span2.left + 1) / 2;
1481
1481
  }
1482
1482
  var DARK_SHARE = 0.55;
1483
1483
  function jawRowsOf(rgba, canvasW, bbox, rowLeft, rowRight) {
@@ -1487,9 +1487,9 @@ function jawRowsOf(rgba, canvasW, bbox, rowLeft, rowRight) {
1487
1487
  let widest = bbox.y;
1488
1488
  let widestSpan = -1;
1489
1489
  for (let y = bbox.y; y < bbox.y + bbox.h; y++) {
1490
- const span = rowRight[y] - rowLeft[y];
1491
- if (span >= widestSpan) {
1492
- widestSpan = span;
1490
+ const span2 = rowRight[y] - rowLeft[y];
1491
+ if (span2 >= widestSpan) {
1492
+ widestSpan = span2;
1493
1493
  widest = y;
1494
1494
  }
1495
1495
  for (let x = bbox.x; x < bbox.x + bbox.w; x++) {
@@ -1658,14 +1658,14 @@ function createLayerSetMeasurer(canvas) {
1658
1658
  }
1659
1659
  function finish() {
1660
1660
  const eyeRow = eyeBandRowOf(layerInputs);
1661
- const span = foregroundSpan(
1661
+ const span2 = foregroundSpan(
1662
1662
  opaque,
1663
1663
  canvasW,
1664
1664
  canvasH,
1665
1665
  eyeRow - HEAD_BAND,
1666
1666
  eyeRow + HEAD_BAND
1667
1667
  );
1668
- const headHalfWidth = span.right > span.left ? headHalfOf(span) : void 0;
1668
+ const headHalfWidth = span2.right > span2.left ? headHalfOf(span2) : void 0;
1669
1669
  const headHalfWidthApplied = headHalfWidth !== void 0 && headHalfWidth > facePlateHalfOf(layerInputs);
1670
1670
  let headEdges;
1671
1671
  if (headHalfWidthApplied) {
@@ -1693,9 +1693,9 @@ function createLayerSetMeasurer(canvas) {
1693
1693
  const centre = iris.bbox.x + iris.bbox.w / 2;
1694
1694
  const otherX = other.bbox.x + other.bbox.w / 2 - half;
1695
1695
  const c = side < 0 ? Math.ceil(centre) - 1 : Math.floor(centre);
1696
- const span2 = rowSpansByRole.find((s) => s.role === iris.role);
1697
- if (span2.rowRight[r] < span2.rowLeft[r]) return void 0;
1698
- const minRun = STRAND_MIN_RUN_FRACTION * (span2.rowRight[r] + 1 - span2.rowLeft[r]);
1696
+ const span3 = rowSpansByRole.find((s) => s.role === iris.role);
1697
+ if (span3.rowRight[r] < span3.rowLeft[r]) return void 0;
1698
+ const minRun = STRAND_MIN_RUN_FRACTION * (span3.rowRight[r] + 1 - span3.rowLeft[r]);
1699
1699
  const strand = new Uint8Array(canvasW);
1700
1700
  const runs = r >= hairTop && r < hairTop + hairRuns.length ? hairRuns[r - hairTop] : [];
1701
1701
  for (let k = 0; k < runs.length; k += 2) {
@@ -1720,8 +1720,8 @@ function createLayerSetMeasurer(canvas) {
1720
1720
  while (strandAt(x)) x += side;
1721
1721
  return {
1722
1722
  y: canvasH / 2 - (r + 0.5),
1723
- irisOuter: (side < 0 ? span2.rowLeft[r] : span2.rowRight[r] + 1) - half,
1724
- irisInner: (side < 0 ? span2.rowRight[r] + 1 : span2.rowLeft[r]) - half,
1723
+ irisOuter: (side < 0 ? span3.rowLeft[r] : span3.rowRight[r] + 1) - half,
1724
+ irisInner: (side < 0 ? span3.rowRight[r] + 1 : span3.rowLeft[r]) - half,
1725
1725
  runOuter: outerBoundary(x - side),
1726
1726
  runFace
1727
1727
  };
@@ -2125,6 +2125,12 @@ var DEFAULT_TURN_TARGETS = Object.freeze({
2125
2125
  farEyeRatio: round2(TURN.eyeFarScale / TURN.eyeNearScale),
2126
2126
  silhouetteRatio: 1
2127
2127
  });
2128
+ var PatchError = class extends Error {
2129
+ constructor(message) {
2130
+ super(message);
2131
+ this.name = "PatchError";
2132
+ }
2133
+ };
2128
2134
 
2129
2135
  // src/auto-rig/arms.ts
2130
2136
  import {
@@ -2756,7 +2762,7 @@ var ARM_IDS = {
2756
2762
  };
2757
2763
  function endPivot(layer, end) {
2758
2764
  const { bbox, canvasW, canvasH, rowRuns } = layer;
2759
- const span = runSpan(layer);
2765
+ const span2 = runSpan(layer);
2760
2766
  const from = (k) => end === "top" ? k : bbox.h - 1 - k;
2761
2767
  const painted = rowRuns?.flatMap((runs, k) => runs.length > 0 ? [k] : []) ?? [];
2762
2768
  const firstK = end === "top" ? painted[0] ?? 0 : painted.at(-1) ?? bbox.h - 1;
@@ -2764,13 +2770,13 @@ function endPivot(layer, end) {
2764
2770
  const hi = Math.max(lo, Math.floor(CAP_ROWS[1] * bbox.h));
2765
2771
  const widths = [];
2766
2772
  for (let k = lo; k <= hi; k++) {
2767
- const [s2, e2] = span(from(k));
2773
+ const [s2, e2] = span2(from(k));
2768
2774
  widths.push(e2 - s2);
2769
2775
  }
2770
2776
  widths.sort((p, q) => p - q);
2771
2777
  const radius = widths[widths.length >> 1] / 2;
2772
2778
  const ks = end === "top" ? firstK + radius : firstK - radius;
2773
- const [s, e] = span(Math.round(ks));
2779
+ const [s, e] = span2(Math.round(ks));
2774
2780
  return {
2775
2781
  point: {
2776
2782
  x: roundTo((s + e) / 2 - canvasW / 2, 0.01),
@@ -2795,9 +2801,9 @@ function runSpan(layer) {
2795
2801
  function armGeometry(layer, bodyAxisX) {
2796
2802
  const { bbox, canvasW, canvasH, rowRuns } = layer;
2797
2803
  const b = boxOfLayer(layer);
2798
- const span = runSpan(layer);
2804
+ const span2 = runSpan(layer);
2799
2805
  const centreX = (k) => {
2800
- const [s2, e2] = span(k);
2806
+ const [s2, e2] = span2(k);
2801
2807
  return (s2 + e2) / 2 - canvasW / 2;
2802
2808
  };
2803
2809
  const rowY = (k) => canvasH / 2 - (bbox.y + k + 0.5);
@@ -2811,7 +2817,7 @@ function armGeometry(layer, bodyAxisX) {
2811
2817
  );
2812
2818
  }
2813
2819
  const elbow = { x: roundTo(centreX(ke), 0.01), y: roundTo(rowY(ke), 0.01) };
2814
- const [s, e] = span(ke);
2820
+ const [s, e] = span2(ke);
2815
2821
  const capRadius = Math.min(
2816
2822
  (e - s) / 2 + 1,
2817
2823
  elbow.x - b.x0,
@@ -2821,7 +2827,7 @@ function armGeometry(layer, bodyAxisX) {
2821
2827
  const inside = (x, y) => {
2822
2828
  const k = Math.floor(y) - bbox.y;
2823
2829
  if (k < 0 || k >= bbox.h) return false;
2824
- const [rs, re] = span(k);
2830
+ const [rs, re] = span2(k);
2825
2831
  return rs < x && x < re;
2826
2832
  };
2827
2833
  const capRays = Array.from({ length: CAP_SEGMENTS + 1 }, (_, i) => {
@@ -3031,14 +3037,25 @@ function forearmPoseDeformer(role, arm) {
3031
3037
 
3032
3038
  // src/auto-rig/mouth.ts
3033
3039
  import {
3034
- StandardParameter as P5
3040
+ StandardParameter as P6
3035
3041
  } from "@ikijs/format";
3036
3042
 
3037
3043
  // src/auto-rig/roles.ts
3044
+ import { StandardParameter as P5 } from "@ikijs/format";
3038
3045
  var LIP_ROLES = ["mouth_inner", "lip_lower", "lip_upper"];
3039
3046
  var isLipRole = (role) => LIP_ROLES.includes(role);
3040
3047
  var LIP_INSIDE_ROLES = ["mouth_tongue", "mouth_teeth"];
3041
3048
  var isLipInsideRole = (role) => LIP_INSIDE_ROLES.includes(role);
3049
+ var SHUT_BY = new Map([
3050
+ ["eye_L", P5.EyeOpenLeft],
3051
+ ["lash_lower_L", P5.EyeOpenLeft],
3052
+ ["eye_R", P5.EyeOpenRight],
3053
+ ["lash_lower_R", P5.EyeOpenRight],
3054
+ ...[...LIP_ROLES, ...LIP_INSIDE_ROLES].map((id) => [
3055
+ id,
3056
+ P5.MouthOpen
3057
+ ])
3058
+ ]);
3042
3059
  var ROLE_TABLE = [
3043
3060
  { role: "hair_back", family: "hair_back" },
3044
3061
  { role: "body", family: "body" },
@@ -3383,7 +3400,7 @@ function columnOfKnot(knot, opening) {
3383
3400
  function mouthFoldWarp(role, mesh, xs, box, opening) {
3384
3401
  const fold = mouthFold(role, opening);
3385
3402
  return localWarp(
3386
- P5.MouthOpen,
3403
+ P6.MouthOpen,
3387
3404
  mesh,
3388
3405
  box,
3389
3406
  [0, 1],
@@ -3392,13 +3409,13 @@ function mouthFoldWarp(role, mesh, xs, box, opening) {
3392
3409
  }
3393
3410
  function mouthRestShift(byRole) {
3394
3411
  const rig = buildMouthRig(byRole);
3395
- const fields = /* @__PURE__ */ new Map();
3412
+ const fields2 = /* @__PURE__ */ new Map();
3396
3413
  for (const role of ["lip_upper", "lip_lower"]) {
3397
3414
  const box = boxOfLayer(byRole.get(role));
3398
3415
  const { mesh, xs } = mouthMesh(box, rig.knots);
3399
3416
  const warp = mouthFoldWarp(role, mesh, xs, box, rig.opening);
3400
3417
  const offsets = warp.keyforms[0].offsets;
3401
- fields.set(role, {
3418
+ fields2.set(role, {
3402
3419
  box,
3403
3420
  xs,
3404
3421
  rows: offsets.length / 2 / xs.length - 1,
@@ -3407,7 +3424,7 @@ function mouthRestShift(byRole) {
3407
3424
  }
3408
3425
  const { canvasW, canvasH } = byRole.get("lip_upper");
3409
3426
  return (role, col, row) => {
3410
- const { box, xs, rows, dy } = fields.get(role);
3427
+ const { box, xs, rows, dy } = fields2.get(role);
3411
3428
  const x = col + 0.5 - canvasW / 2;
3412
3429
  const y = canvasH / 2 - (row + 0.5);
3413
3430
  if (x < box.x0 || x > box.x1 || y < box.y0 || y > box.y1) return void 0;
@@ -3498,36 +3515,36 @@ function mouthAnchor(byRole) {
3498
3515
  // src/auto-rig/generate.ts
3499
3516
  import {
3500
3517
  IKI_FORMAT_VERSION as IKI_FORMAT_VERSION2,
3501
- StandardParameter as P8,
3518
+ StandardParameter as P10,
3502
3519
  parseIkiModel as parseIkiModel3
3503
3520
  } from "@ikijs/format";
3504
3521
 
3505
3522
  // src/auto-rig/animations.ts
3506
3523
  import {
3507
- StandardParameter as P6
3524
+ StandardParameter as P7
3508
3525
  } from "@ikijs/format";
3509
3526
  function browsY(y) {
3510
3527
  return [
3511
- { parameter: P6.BrowLeftY, value: y, blend: "add" },
3512
- { parameter: P6.BrowRightY, value: y, blend: "add" }
3528
+ { parameter: P7.BrowLeftY, value: y, blend: "add" },
3529
+ { parameter: P7.BrowRightY, value: y, blend: "add" }
3513
3530
  ];
3514
3531
  }
3515
3532
  function browsTilt(innerDown) {
3516
3533
  return [
3517
- { parameter: P6.BrowLeftAngle, value: innerDown, blend: "add" },
3518
- { parameter: P6.BrowRightAngle, value: -innerDown, blend: "add" }
3534
+ { parameter: P7.BrowLeftAngle, value: innerDown, blend: "add" },
3535
+ { parameter: P7.BrowRightAngle, value: -innerDown, blend: "add" }
3519
3536
  ];
3520
3537
  }
3521
3538
  function cheek(value) {
3522
- return { parameter: P6.Cheek, value, blend: "add" };
3539
+ return { parameter: P7.Cheek, value, blend: "add" };
3523
3540
  }
3524
- var BROWS = [P6.BrowLeftY, P6.BrowRightY, P6.BrowLeftAngle, P6.BrowRightAngle];
3541
+ var BROWS = [P7.BrowLeftY, P7.BrowRightY, P7.BrowLeftAngle, P7.BrowRightAngle];
3525
3542
  var EXPRESSIONS = [
3526
3543
  {
3527
3544
  id: "smile",
3528
3545
  description: "Smiling and pleased: warm, friendly, content. For greetings, thanks, agreement and gentle happiness.",
3529
3546
  parameters: [
3530
- { parameter: P6.MouthForm, value: 1, blend: "add" },
3547
+ { parameter: P7.MouthForm, value: 1, blend: "add" },
3531
3548
  ...browsY(0.25),
3532
3549
  cheek(0.4)
3533
3550
  ]
@@ -3536,10 +3553,10 @@ var EXPRESSIONS = [
3536
3553
  id: "laugh",
3537
3554
  description: "Laughing, eyes shut and mouth open: delighted, amused. For jokes, playfulness and big joy.",
3538
3555
  parameters: [
3539
- { parameter: P6.EyeOpenLeft, value: 0, blend: "multiply" },
3540
- { parameter: P6.EyeOpenRight, value: 0, blend: "multiply" },
3541
- { parameter: P6.MouthForm, value: 1, blend: "add" },
3542
- { parameter: P6.MouthOpen, value: 0.8, blend: "overwrite" },
3556
+ { parameter: P7.EyeOpenLeft, value: 0, blend: "multiply" },
3557
+ { parameter: P7.EyeOpenRight, value: 0, blend: "multiply" },
3558
+ { parameter: P7.MouthForm, value: 1, blend: "add" },
3559
+ { parameter: P7.MouthOpen, value: 0.8, blend: "overwrite" },
3543
3560
  ...browsY(0.4),
3544
3561
  cheek(0.65)
3545
3562
  ]
@@ -3551,7 +3568,7 @@ var EXPRESSIONS = [
3551
3568
  parameters: [
3552
3569
  ...browsY(-0.5),
3553
3570
  ...browsTilt(0.8),
3554
- { parameter: P6.MouthForm, value: -0.9, blend: "add" }
3571
+ { parameter: P7.MouthForm, value: -0.9, blend: "add" }
3555
3572
  ]
3556
3573
  },
3557
3574
  {
@@ -3561,7 +3578,7 @@ var EXPRESSIONS = [
3561
3578
  parameters: [
3562
3579
  ...browsY(0.35),
3563
3580
  ...browsTilt(-0.8),
3564
- { parameter: P6.MouthForm, value: -0.8, blend: "add" }
3581
+ { parameter: P7.MouthForm, value: -0.8, blend: "add" }
3565
3582
  ]
3566
3583
  },
3567
3584
  {
@@ -3569,18 +3586,18 @@ var EXPRESSIONS = [
3569
3586
  description: "Surprised, mouth dropped open: startled, amazed. For shock, sudden news or disbelief.",
3570
3587
  parameters: [
3571
3588
  ...browsY(0.8),
3572
- { parameter: P6.MouthOpen, value: 0.9, blend: "overwrite" }
3589
+ { parameter: P7.MouthOpen, value: 0.9, blend: "overwrite" }
3573
3590
  ]
3574
3591
  },
3575
3592
  {
3576
3593
  id: "shy",
3577
3594
  description: "Shy or embarrassed: bashful, flustered. For being praised, teased or caught off guard.",
3578
- needs: [P6.Cheek],
3595
+ needs: [P7.Cheek],
3579
3596
  parameters: [
3580
3597
  cheek(1),
3581
3598
  // Gaze down.
3582
- { parameter: P6.EyeballY, value: -0.65, blend: "add" },
3583
- { parameter: P6.MouthForm, value: 0.4, blend: "add" },
3599
+ { parameter: P7.EyeballY, value: -0.65, blend: "add" },
3600
+ { parameter: P7.MouthForm, value: 0.4, blend: "add" },
3584
3601
  ...browsTilt(-0.25)
3585
3602
  ]
3586
3603
  }
@@ -3600,7 +3617,7 @@ var HEAD_MOTIONS = {
3600
3617
  duration: 1,
3601
3618
  curves: [
3602
3619
  {
3603
- parameter: P6.AngleY,
3620
+ parameter: P7.AngleY,
3604
3621
  keys: [
3605
3622
  [0, 0],
3606
3623
  [0.3, -18],
@@ -3621,7 +3638,7 @@ var HEAD_MOTIONS = {
3621
3638
  fadeIn: 0.15,
3622
3639
  curves: [
3623
3640
  {
3624
- parameter: P6.AngleX,
3641
+ parameter: P7.AngleX,
3625
3642
  keys: [
3626
3643
  [0, 0],
3627
3644
  [0.2, -18],
@@ -3640,7 +3657,7 @@ var HEAD_MOTIONS = {
3640
3657
  duration: 1.4,
3641
3658
  curves: [
3642
3659
  {
3643
- parameter: P6.AngleZ,
3660
+ parameter: P7.AngleZ,
3644
3661
  keys: [
3645
3662
  [0, 0],
3646
3663
  [0.35, 20],
@@ -3661,7 +3678,7 @@ var WAVE = {
3661
3678
  fadeOut: 0.15,
3662
3679
  curves: [
3663
3680
  {
3664
- parameter: P6.ArmPoseRight,
3681
+ parameter: P7.ArmPoseRight,
3665
3682
  interpolation: "linear",
3666
3683
  keys: [
3667
3684
  [0, 0],
@@ -3671,7 +3688,7 @@ var WAVE = {
3671
3688
  ]
3672
3689
  },
3673
3690
  {
3674
- parameter: P6.ArmRight,
3691
+ parameter: P7.ArmRight,
3675
3692
  keys: [
3676
3693
  [0, 0],
3677
3694
  [0.4, 10],
@@ -3680,7 +3697,7 @@ var WAVE = {
3680
3697
  ]
3681
3698
  },
3682
3699
  {
3683
- parameter: P6.ArmPoseAngleRight,
3700
+ parameter: P7.ArmPoseAngleRight,
3684
3701
  keys: [
3685
3702
  [0, 0],
3686
3703
  [0.5, 0],
@@ -3696,7 +3713,7 @@ var WAVE = {
3696
3713
  ]
3697
3714
  };
3698
3715
  function defaultMotions(declared) {
3699
- const waves = [P6.ArmRight, P6.ArmPoseRight, P6.ArmPoseAngleRight].every(
3716
+ const waves = [P7.ArmRight, P7.ArmPoseRight, P7.ArmPoseAngleRight].every(
3700
3717
  (id) => declared.has(id)
3701
3718
  );
3702
3719
  return waves ? { ...HEAD_MOTIONS, ...WAVE } : HEAD_MOTIONS;
@@ -3932,7 +3949,7 @@ function checkStrandEdges(strand, irises, hair) {
3932
3949
  }
3933
3950
 
3934
3951
  // src/auto-rig/context.ts
3935
- import { StandardParameter as P7 } from "@ikijs/format";
3952
+ import { StandardParameter as P8 } from "@ikijs/format";
3936
3953
 
3937
3954
  // src/auto-rig/head.ts
3938
3955
  function outerEdge(runs, axisX, side) {
@@ -4041,14 +4058,14 @@ function buildHeadFrame(layers, opts) {
4041
4058
  const rawRows = raw;
4042
4059
  const earless = (chin) => {
4043
4060
  const rowOf = (y) => Math.round(canvasH / 2 - y - faceLayer.bbox.y - 0.5);
4044
- const span = Math.max(1, eyeY - chin);
4061
+ const span2 = Math.max(1, eyeY - chin);
4045
4062
  const found = findEars(
4046
4063
  rawRows,
4047
4064
  wMax,
4048
4065
  Math.round(0.2 * rawRows.length),
4049
4066
  Math.min(rawRows.length - 1, rowOf(chin)),
4050
- Math.round(0.1 * span),
4051
- Math.round(0.8 * span)
4067
+ Math.round(0.1 * span2),
4068
+ Math.round(0.8 * span2)
4052
4069
  );
4053
4070
  if (found === void 0) return profile;
4054
4071
  const { top, bottom } = found;
@@ -4082,16 +4099,16 @@ function buildHeadFrame(layers, opts) {
4082
4099
  }
4083
4100
  }
4084
4101
  if (neckRow >= 0 && n - neckRow >= 0.12 * n) {
4085
- let span = 0;
4102
+ let span2 = 0;
4086
4103
  let waist = Infinity;
4087
4104
  for (let r = neckRow; r < n; r++) {
4088
- span = Math.max(span, profile[r]);
4105
+ span2 = Math.max(span2, profile[r]);
4089
4106
  if (r < n - tail) waist = Math.min(waist, profile[r]);
4090
4107
  }
4091
4108
  neck = {
4092
4109
  topY: rowY(neckRow),
4093
4110
  half: profile[neckRow],
4094
- span,
4111
+ span: span2,
4095
4112
  waist: Math.min(waist, profile[neckRow])
4096
4113
  };
4097
4114
  }
@@ -4291,22 +4308,22 @@ function earField(m) {
4291
4308
  const dy = face(x, y, 0, ay)[1];
4292
4309
  const d = Math.abs(x - f.axisX);
4293
4310
  const attach = ears.attachAt(y);
4294
- const span = Math.max(1, ears.outer - attach);
4311
+ const span2 = Math.max(1, ears.outer - attach);
4295
4312
  if (sideOf(m, x, s) === "far") {
4296
4313
  const rim2 = TURN.earFar * m.face;
4297
4314
  const root2 = earRoot(m, face, y, s);
4298
4315
  const lead = Math.max(
4299
4316
  0,
4300
- Math.min((1 - m.earFarScale) * span, root2 - rim2)
4317
+ Math.min((1 - m.earFarScale) * span2, root2 - rim2)
4301
4318
  );
4302
- let along = rim2 + lead * (ears.outer - d) / span;
4319
+ let along = rim2 + lead * (ears.outer - d) / span2;
4303
4320
  if (d < attach) along = Math.min(along, s * face(x, y, 30 * s, 0)[0]);
4304
4321
  return [s * a * along, dy];
4305
4322
  }
4306
4323
  if (d <= attach) return [face(x, y, ax, 0)[0], dy];
4307
4324
  const root = face(f.axisX + Math.sign(x - f.axisX) * attach, y, ax, 0)[0];
4308
4325
  const rim = s * a * TURN.earNear * m.face;
4309
- const t = Math.min(1, (d - attach) / span);
4326
+ const t = Math.min(1, (d - attach) / span2);
4310
4327
  return [root + (rim - root) * t, dy];
4311
4328
  };
4312
4329
  }
@@ -5062,7 +5079,7 @@ function renderedLander(turn, parts, grids, from = /* @__PURE__ */ new Map()) {
5062
5079
  const family = roleSpec(role).family;
5063
5080
  const part = parts.find((p) => p.id === role);
5064
5081
  const g = grids.get(family);
5065
- const warp = part?.warps?.find((w) => w.parameter === P7.AngleX);
5082
+ const warp = part?.warps?.find((w) => w.parameter === P8.AngleX);
5066
5083
  if (part === void 0 || part.mesh === void 0 || !g && !warp) {
5067
5084
  return x + field(role)(x, y, ax, 0)[0];
5068
5085
  }
@@ -5201,11 +5218,11 @@ function buildFaceMesh(frame, b, head, neckCells) {
5201
5218
  const indices = [];
5202
5219
  const neck = frame.neck;
5203
5220
  if (neck !== void 0) {
5204
- const span = neck.span + pad;
5205
- const nc = cellsFor(2 * span, neckCells.px, neckCells.min, neckCells.max);
5221
+ const span2 = neck.span + pad;
5222
+ const nc = cellsFor(2 * span2, neckCells.px, neckCells.min, neckCells.max);
5206
5223
  const xs2 = columns(
5207
- Math.max(b.x0, frame.axisX - span),
5208
- Math.min(b.x1, frame.axisX + span),
5224
+ Math.max(b.x0, frame.axisX - span2),
5225
+ Math.min(b.x1, frame.axisX + span2),
5209
5226
  nc
5210
5227
  );
5211
5228
  const sampleBelow = (x) => Math.max(
@@ -5341,6 +5358,11 @@ function buildFaceMesh(frame, b, head, neckCells) {
5341
5358
  return { mesh: { vertices, uvs, indices }, region, headStart };
5342
5359
  }
5343
5360
 
5361
+ // src/auto-rig/patches.ts
5362
+ import {
5363
+ StandardParameter as P9
5364
+ } from "@ikijs/format";
5365
+
5344
5366
  // src/auto-rig/solve.ts
5345
5367
  var RANGES = {
5346
5368
  // [lo, hi, lo exclusive]
@@ -5771,6 +5793,235 @@ function buildTurn(frame, landmarks, q) {
5771
5793
  };
5772
5794
  }
5773
5795
 
5796
+ // src/auto-rig/patches.ts
5797
+ var OP_KEYS = ["target", "at", "region", "by", "falloff", "why"];
5798
+ var REGION_KEYS = ["role", "x", "y"];
5799
+ var BY_KEYS = ["dx", "dy"];
5800
+ var ROLLS = /* @__PURE__ */ new Set([P9.AngleZ, P9.BodyAngleZ]);
5801
+ var REST_IS_ART = "rest is the drawn art, which no patch changes (change it with the layout or by regenerating the layer)";
5802
+ function applyPatches(patches, ctx) {
5803
+ if (!Array.isArray(patches)) {
5804
+ throw new PatchError(
5805
+ `patches must be an array, got ${patches === null ? "null" : typeof patches}`
5806
+ );
5807
+ }
5808
+ const sums = /* @__PURE__ */ new Map();
5809
+ const reports = patches.map((op, i) => replay(op, i, ctx, sums));
5810
+ for (const [offsets, s] of sums) {
5811
+ s.terms.forEach((t, k) => {
5812
+ if (t.length === 0) return;
5813
+ const d = t.sort((a, b) => a - b).reduce((a, b) => a + b, 0);
5814
+ offsets[k] = roundTo(offsets[k] + d / s.scale[k % 2], s.step);
5815
+ });
5816
+ }
5817
+ return reports;
5818
+ }
5819
+ function replay(op, i, ctx, sums) {
5820
+ const name = `patches[${i}]`;
5821
+ const o = fields(name, op, OP_KEYS);
5822
+ const target = text(`${name}.target`, o.target);
5823
+ const at = numbers(`${name}.at`, o.at);
5824
+ const region = fields(`${name}.region`, o.region, REGION_KEYS);
5825
+ const role = text(`${name}.region.role`, region.role);
5826
+ const x = span(`${name}.region.x`, region.x);
5827
+ const y = span(`${name}.region.y`, region.y);
5828
+ const by = fields(`${name}.by`, o.by, BY_KEYS);
5829
+ const dx = finite2(`${name}.by.dx`, by.dx);
5830
+ const dy = finite2(`${name}.by.dy`, by.dy);
5831
+ const falloff = o.falloff === void 0 ? 0 : finite2(`${name}.falloff`, o.falloff, 0);
5832
+ if (o.why !== void 0) text(`${name}.why`, o.why);
5833
+ const box = ctx.boxOf(role);
5834
+ if (box === void 0) {
5835
+ const roles = [...new Set(ctx.parts.map((p) => roleOfPart(p.id)))].filter(
5836
+ (r) => ctx.boxOf(r) !== void 0
5837
+ );
5838
+ throw new PatchError(
5839
+ `${name}.region.role "${role}" is not a layer of this set (roles: ${roles.join(", ")})`
5840
+ );
5841
+ }
5842
+ const stop = resolveStop(name, target, at, ctx);
5843
+ const { points } = stop;
5844
+ const weights = regionWeights(points, box, x, y, falloff * ctx.faceWidth);
5845
+ const hit = weights.flatMap((w, k) => w > 0 ? [k] : []);
5846
+ if (hit.length === 0) {
5847
+ const fx = points.map(([px]) => (px - box.x0) / bw(box));
5848
+ const fy = points.map(([, py]) => (box.y1 - py) / bh(box));
5849
+ const range = (v) => `[${roundTo(Math.min(...v), 0.01)}, ${roundTo(Math.max(...v), 0.01)}]`;
5850
+ throw new PatchError(
5851
+ `${name}.region (falloff ${falloff}) catches none of ${target}'s ${points.length} points; at rest they span x ${range(fx)}, y ${range(fy)} of ${role}'s box`
5852
+ );
5853
+ }
5854
+ let sum = sums.get(stop.offsets);
5855
+ if (sum === void 0) {
5856
+ sum = {
5857
+ terms: stop.offsets.map(() => []),
5858
+ scale: stop.scale,
5859
+ step: stop.step
5860
+ };
5861
+ sums.set(stop.offsets, sum);
5862
+ }
5863
+ const ddx = dx * ctx.faceWidth;
5864
+ const ddy = -dy * ctx.faceWidth;
5865
+ for (const k of hit) {
5866
+ sum.terms[2 * k].push(ddx * weights[k]);
5867
+ sum.terms[2 * k + 1].push(ddy * weights[k]);
5868
+ }
5869
+ const maxW = Math.max(...hit.map((k) => weights[k]));
5870
+ const report = {
5871
+ index: i,
5872
+ target,
5873
+ at,
5874
+ moved: hit.length,
5875
+ of: points.length,
5876
+ maxPx: roundTo(maxW * Math.hypot(dx, dy) * ctx.faceWidth, 0.1)
5877
+ };
5878
+ if (stop.stride !== void 0) {
5879
+ const { stride } = stop;
5880
+ const cols = hit.map((k) => k % stride);
5881
+ const rows = hit.map((k) => Math.floor(k / stride));
5882
+ report.cols = [Math.min(...cols), Math.max(...cols)];
5883
+ report.rows = [Math.min(...rows), Math.max(...rows)];
5884
+ }
5885
+ return report;
5886
+ }
5887
+ function resolveStop(name, target, at, ctx) {
5888
+ const grid = ctx.grids.get(target);
5889
+ if (grid !== void 0) {
5890
+ const l = grid.lattice.points;
5891
+ const points = [];
5892
+ for (let k = 0; k < l.length; k += 2) points.push([l[k], l[k + 1]]);
5893
+ return {
5894
+ offsets: gridStop(name, at, target, grid.keyforms),
5895
+ points,
5896
+ scale: [1, 1],
5897
+ step: 0.1,
5898
+ stride: grid.lattice.cols + 1
5899
+ };
5900
+ }
5901
+ const part = ctx.parts.find((p) => p.id === target);
5902
+ const b = ctx.boxOf(target);
5903
+ if (part?.mesh === void 0 || part.warps === void 0 || b === void 0) {
5904
+ const parts = ctx.parts.filter(
5905
+ (p) => p.mesh !== void 0 && p.warps !== void 0 && ctx.boxOf(p.id) !== void 0
5906
+ );
5907
+ throw new PatchError(
5908
+ `${name}.target "${target}" is neither a feature grid (${[...ctx.grids.keys()].join(", ")}) nor a mesh part with warps (${parts.map((p) => p.id).join(", ")}); bodyWarp and the matrix deformers are not patchable`
5909
+ );
5910
+ }
5911
+ return {
5912
+ offsets: partStop(name, at, part, part.warps, ctx),
5913
+ points: meshPoints(part.mesh, b),
5914
+ scale: [bw(b), bh(b)],
5915
+ step: 1e-4
5916
+ };
5917
+ }
5918
+ function gridStop(name, at, id, keyforms) {
5919
+ const i = X_STOPS.indexOf(at[P9.AngleX]);
5920
+ const j = Y_STOPS.indexOf(at[P9.AngleY]);
5921
+ if (Object.keys(at).length !== 2 || i < 0 || j < 0) {
5922
+ throw new PatchError(
5923
+ `${name}.at must name ${P9.AngleX} in [${X_STOPS.join(", ")}] and ${P9.AngleY} in [${Y_STOPS.join(", ")}] for the grid ${id}, got ${JSON.stringify(at)}`
5924
+ );
5925
+ }
5926
+ if (X_STOPS[i] === 0 && Y_STOPS[j] === 0) {
5927
+ throw new PatchError(
5928
+ `${name}.at ${P9.AngleX}=0 ${P9.AngleY}=0 is ${id}'s rest stop: ${REST_IS_ART}; patch a stop with ${P9.AngleX} or ${P9.AngleY} at \xB130 instead`
5929
+ );
5930
+ }
5931
+ return keyforms[j * X_STOPS.length + i];
5932
+ }
5933
+ function partStop(name, at, part, warps, ctx) {
5934
+ const keys = Object.keys(at);
5935
+ const [param] = keys;
5936
+ const value = at[param];
5937
+ const keyform = keys.length === 1 ? warps.filter((w) => w.parameter === param).flatMap((w) => w.keyforms).find((k) => k.value === value) : void 0;
5938
+ if (keyform === void 0) {
5939
+ throw new PatchError(
5940
+ `${name}.at must name one parameter at one of ${part.id}'s warp stops (${listStops(warps, () => true)}), got ${JSON.stringify(at)}`
5941
+ );
5942
+ }
5943
+ if (ROLLS.has(param)) {
5944
+ throw new PatchError(
5945
+ `${name}.at ${param}: that parameter rolls ${part.id}'s deformer chain, so a displacement at its stop is not on screen axes; patch another of its stops (${listStops(warps, (p) => !ROLLS.has(p))}) or its feature grid instead`
5946
+ );
5947
+ }
5948
+ const isRest = (p, v) => v === ctx.parameters.find((q) => q.id === p)?.default;
5949
+ const isShut = (p, v) => SHUT_BY.get(part.id) === p && v === 0;
5950
+ if (!isRest(param, value) && !isShut(param, value)) return keyform.offsets;
5951
+ const open = listStops(warps, (p, v) => !isRest(p, v) && !isShut(p, v));
5952
+ const grid = part.deformer !== void 0 && ctx.grids.has(part.deformer) ? `its feature grid ${part.deformer} at a ${P9.AngleX} \xD7 ${P9.AngleY} stop` : "";
5953
+ const instead = [open && `another of its stops (${open})`, grid].filter((s) => s !== "").join(" or ");
5954
+ const hint = instead === "" ? "" : `; patch ${instead} instead`;
5955
+ throw new PatchError(
5956
+ isRest(param, value) ? `${name}.at ${param}=${value} is that parameter's default, ${part.id}'s rest stop: ${REST_IS_ART}${hint}` : `${name}.at ${param}=0 is where the rig shuts ${part.id} on purpose, a closure the fold check exempts, so a fold a patch made there would never be reported${hint}`
5957
+ );
5958
+ }
5959
+ function listStops(warps, keep) {
5960
+ const stops = /* @__PURE__ */ new Map();
5961
+ for (const w of warps) {
5962
+ for (const k of w.keyforms) {
5963
+ if (!keep(w.parameter, k.value)) continue;
5964
+ const s = stops.get(w.parameter) ?? /* @__PURE__ */ new Set();
5965
+ s.add(k.value);
5966
+ stops.set(w.parameter, s);
5967
+ }
5968
+ }
5969
+ return [...stops].map(([p, s]) => `${p}@${[...s].sort((a, b) => a - b).join(",")}`).join(" ");
5970
+ }
5971
+ function regionWeights(points, box, x, y, fall) {
5972
+ const x0 = box.x0 + x[0] * bw(box);
5973
+ const x1 = box.x0 + x[1] * bw(box);
5974
+ const top = box.y1 - y[0] * bh(box);
5975
+ const bottom = box.y1 - y[1] * bh(box);
5976
+ return points.map(([px, py]) => {
5977
+ const d = Math.hypot(
5978
+ Math.max(x0 - px, 0, px - x1),
5979
+ Math.max(bottom - py, 0, py - top)
5980
+ );
5981
+ return d === 0 ? 1 : d < fall ? smoothstep(fall, 0, d) : 0;
5982
+ });
5983
+ }
5984
+ function asPatch(check) {
5985
+ try {
5986
+ return check();
5987
+ } catch (e) {
5988
+ throw e instanceof TurnTargetError ? new PatchError(e.message) : e;
5989
+ }
5990
+ }
5991
+ function fields(name, v, known) {
5992
+ if (v === void 0) throw new PatchError(`${name} is missing`);
5993
+ asPatch(() => checkedKeys(name, v, known));
5994
+ return v;
5995
+ }
5996
+ function numbers(name, v) {
5997
+ const o = fields(name, v, Object.keys(v ?? {}));
5998
+ return Object.fromEntries(
5999
+ Object.entries(o).map(([k, n]) => [k, finite2(`${name}.${k}`, n)])
6000
+ );
6001
+ }
6002
+ var finite2 = (name, v, lo = -Infinity) => asPatch(() => checkedNumber(name, v, lo, Infinity));
6003
+ function text(name, v) {
6004
+ if (typeof v !== "string") {
6005
+ throw new PatchError(`${name} must be a string, got ${String(v)}`);
6006
+ }
6007
+ return v;
6008
+ }
6009
+ function span(name, v) {
6010
+ if (!Array.isArray(v) || v.length !== 2) {
6011
+ throw new PatchError(
6012
+ `${name} must be [from, to], got ${JSON.stringify(v)}`
6013
+ );
6014
+ }
6015
+ const lo = finite2(`${name}[0]`, v[0]);
6016
+ const hi = finite2(`${name}[1]`, v[1]);
6017
+ if (lo > hi) {
6018
+ throw new PatchError(
6019
+ `${name} [${lo}, ${hi}] runs backwards: ${name}[0] must not exceed ${name}[1]`
6020
+ );
6021
+ }
6022
+ return [lo, hi];
6023
+ }
6024
+
5774
6025
  // src/auto-rig/generate.ts
5775
6026
  var MESH_CELLS = {
5776
6027
  face: { px: 28, min: 4, max: 24 },
@@ -5948,6 +6199,15 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
5948
6199
  ];
5949
6200
  }
5950
6201
  const parameters = declareParameters(new Set(byRole.keys()));
6202
+ const reports = options.patches === void 0 ? void 0 : applyPatches(options.patches, {
6203
+ grids: new Map(
6204
+ [...grids].map(([family, g]) => [WARP_ID[family], g])
6205
+ ),
6206
+ parts,
6207
+ boxOf: (role) => has(role) ? box(role) : void 0,
6208
+ faceWidth: byRole.get("face").cropW,
6209
+ parameters
6210
+ });
5951
6211
  const model = {
5952
6212
  version: IKI_FORMAT_VERSION2,
5953
6213
  name: "auto-rigged",
@@ -5960,6 +6220,7 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
5960
6220
  motions: defaultMotions(new Set(parameters.map((p) => p.id)))
5961
6221
  };
5962
6222
  const valid = parseIkiModel3(model);
6223
+ if (reports !== void 0) options.onPatchesApplied?.(reports);
5963
6224
  if (hasNose && options.onTurnSolved) {
5964
6225
  options.onTurnSolved(
5965
6226
  turnReport(
@@ -5974,14 +6235,14 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
5974
6235
  function turnWarps(mesh, b, fieldOf) {
5975
6236
  return [
5976
6237
  localWarp(
5977
- P8.AngleX,
6238
+ P10.AngleX,
5978
6239
  mesh,
5979
6240
  b,
5980
6241
  X_STOPS,
5981
6242
  ([x, y], v, i) => v === 0 ? [0, 0] : [fieldOf(i)(x, y, v, 0)[0], 0]
5982
6243
  ),
5983
6244
  localWarp(
5984
- P8.AngleY,
6245
+ P10.AngleY,
5985
6246
  mesh,
5986
6247
  b,
5987
6248
  Y_STOPS,
@@ -6032,7 +6293,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid, lips) {
6032
6293
  }
6033
6294
  if (mesh !== void 0) part.mesh = mesh;
6034
6295
  const side = spec.role.endsWith("_L") ? "L" : "R";
6035
- const eyeOpen = side === "L" ? P8.EyeOpenLeft : P8.EyeOpenRight;
6296
+ const eyeOpen = side === "L" ? P10.EyeOpenLeft : P10.EyeOpenRight;
6036
6297
  const hh = frame.hh;
6037
6298
  switch (spec.role) {
6038
6299
  case "face":
@@ -6047,7 +6308,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid, lips) {
6047
6308
  headOwnRoll(byRole.has("body"))
6048
6309
  ),
6049
6310
  localWarp(
6050
- P8.Breath,
6311
+ P10.Breath,
6051
6312
  mesh,
6052
6313
  b,
6053
6314
  [0, 1],
@@ -6094,8 +6355,8 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid, lips) {
6094
6355
  if (byRole.has("mouth_open")) {
6095
6356
  warps.push(mouthWiden(mesh, b));
6096
6357
  bindings.push(
6097
- { parameter: P8.MouthOpen, channel: "opacity", from: 1, to: 0 },
6098
- { parameter: P8.MouthOpen, channel: "opacity", from: 1, to: 0 }
6358
+ { parameter: P10.MouthOpen, channel: "opacity", from: 1, to: 0 },
6359
+ { parameter: P10.MouthOpen, channel: "opacity", from: 1, to: 0 }
6099
6360
  );
6100
6361
  extra = [(AMPLITUDE.mouthOpenWidth - 1) * (bw(b) / 2), 0];
6101
6362
  } else {
@@ -6105,19 +6366,19 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid, lips) {
6105
6366
  );
6106
6367
  bindings.push(
6107
6368
  {
6108
- parameter: P8.MouthOpen,
6369
+ parameter: P10.MouthOpen,
6109
6370
  channel: "scaleY",
6110
6371
  from: 0,
6111
6372
  to: roundTo(grow, 0.01)
6112
6373
  },
6113
6374
  {
6114
- parameter: P8.MouthOpen,
6375
+ parameter: P10.MouthOpen,
6115
6376
  channel: "scaleX",
6116
6377
  from: 0,
6117
6378
  to: roundTo(AMPLITUDE.mouthOpenWidth - 1, 0.01)
6118
6379
  },
6119
6380
  {
6120
- parameter: P8.MouthOpen,
6381
+ parameter: P10.MouthOpen,
6121
6382
  channel: "translateY",
6122
6383
  from: 0,
6123
6384
  to: -roundTo(grow * bh(b) / 2, 0.01)
@@ -6129,7 +6390,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid, lips) {
6129
6390
  case "mouth_open":
6130
6391
  warps.push(mouthForm(mesh, b), mouthOpenGrow(mesh, b));
6131
6392
  bindings.push({
6132
- parameter: P8.MouthOpen,
6393
+ parameter: P10.MouthOpen,
6133
6394
  channel: "opacity",
6134
6395
  from: 0,
6135
6396
  to: 1
@@ -6151,7 +6412,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid, lips) {
6151
6412
  case "blush_L":
6152
6413
  case "blush_R":
6153
6414
  bindings.push({
6154
- parameter: P8.Cheek,
6415
+ parameter: P10.Cheek,
6155
6416
  channel: "opacity",
6156
6417
  from: AMPLITUDE.blushRest,
6157
6418
  to: 1
@@ -6162,8 +6423,8 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid, lips) {
6162
6423
  if (byRole.has("hair_front")) {
6163
6424
  const amp = style.sway * AMPLITUDE.sway * hh;
6164
6425
  warps.push(
6165
- hairSway(P8.HairSwayX, mesh, b, amp),
6166
- hairSway(P8.HairSwayZ, mesh, b, amp)
6426
+ hairSway(P10.HairSwayX, mesh, b, amp),
6427
+ hairSway(P10.HairSwayZ, mesh, b, amp)
6167
6428
  );
6168
6429
  }
6169
6430
  warps.push(tiltHang(mesh, b, pivot, hairHangWeight(frame.chinY, b.y0)));
@@ -6229,9 +6490,9 @@ function deformers(frame, grids, bodyWarp, arms, byRole) {
6229
6490
  pivot: { x: roundTo(frame.axisX, 0.01), y: roundTo(frame.chinY, 0.01) },
6230
6491
  bindings: [
6231
6492
  // AngleZ is clockwise-positive (Live2D's); a rotation is CCW-positive.
6232
- { parameter: P8.AngleZ, channel: "rotate", from: roll, to: -roll },
6493
+ { parameter: P10.AngleZ, channel: "rotate", from: roll, to: -roll },
6233
6494
  {
6234
- parameter: P8.Breath,
6495
+ parameter: P10.Breath,
6235
6496
  channel: "translateY",
6236
6497
  from: 0,
6237
6498
  to: roundTo(headOwnBreath(hasBody) * frame.hh, 0.01)
@@ -6249,8 +6510,8 @@ function deformers(frame, grids, bodyWarp, arms, byRole) {
6249
6510
  points: g.lattice.points
6250
6511
  },
6251
6512
  warp2d: {
6252
- parameter: P8.AngleX,
6253
- parameterY: P8.AngleY,
6513
+ parameter: P10.AngleX,
6514
+ parameterY: P10.AngleY,
6254
6515
  valuesX: X_STOPS,
6255
6516
  valuesY: Y_STOPS,
6256
6517
  keyforms2d: g.keyforms.map((offsets) => ({ offsets }))
@@ -6263,16 +6524,16 @@ function hairPhysics() {
6263
6524
  return [
6264
6525
  {
6265
6526
  id: "hairSway",
6266
- input: { parameter: P8.AngleX, weight: 1 },
6267
- output: { parameter: P8.HairSwayX, scale: 5 },
6527
+ input: { parameter: P10.AngleX, weight: 1 },
6528
+ output: { parameter: P10.HairSwayX, scale: 5 },
6268
6529
  mass: 1,
6269
6530
  stiffness: 30,
6270
6531
  damping: 3
6271
6532
  },
6272
6533
  {
6273
6534
  id: "hairTilt",
6274
- input: { parameter: P8.AngleZ, weight: 1 },
6275
- output: { parameter: P8.HairSwayZ, scale: 8 },
6535
+ input: { parameter: P10.AngleZ, weight: 1 },
6536
+ output: { parameter: P10.HairSwayZ, scale: 8 },
6276
6537
  mass: 1,
6277
6538
  stiffness: 25,
6278
6539
  damping: 2.5
@@ -6282,13 +6543,13 @@ function hairPhysics() {
6282
6543
  function declareParameters(roles) {
6283
6544
  const out = [];
6284
6545
  const add = (id, name, min, max, def) => out.push({ id, name, min, max, default: def });
6285
- add(P8.AngleX, "Head Angle", -30, 30, 0);
6286
- add(P8.AngleY, "Head Angle Y", -30, 30, 0);
6287
- add(P8.AngleZ, "Head Angle Z", -30, 30, 0);
6546
+ add(P10.AngleX, "Head Angle", -30, 30, 0);
6547
+ add(P10.AngleY, "Head Angle Y", -30, 30, 0);
6548
+ add(P10.AngleZ, "Head Angle Z", -30, 30, 0);
6288
6549
  if (roles.has("body")) {
6289
- add(P8.BodyAngleX, "Body Angle X", -10, 10, 0);
6290
- add(P8.BodyAngleY, "Body Angle Y", -10, 10, 0);
6291
- add(P8.BodyAngleZ, "Body Angle Z", -10, 10, 0);
6550
+ add(P10.BodyAngleX, "Body Angle X", -10, 10, 0);
6551
+ add(P10.BodyAngleY, "Body Angle Y", -10, 10, 0);
6552
+ add(P10.BodyAngleZ, "Body Angle Z", -10, 10, 0);
6292
6553
  }
6293
6554
  const addPose = (side, pose, angle) => {
6294
6555
  add(pose, `Arm Pose ${side}`, 0, 1, 0);
@@ -6297,40 +6558,40 @@ function declareParameters(roles) {
6297
6558
  const [armMin, armMax] = ARM_RANGE;
6298
6559
  const [elbowMin, elbowMax] = ELBOW_RANGE;
6299
6560
  if (roles.has("arm_L")) {
6300
- add(P8.ArmLeft, "Arm L", armMin, armMax, 0);
6301
- add(P8.ElbowLeft, "Elbow L", elbowMin, elbowMax, 0);
6561
+ add(P10.ArmLeft, "Arm L", armMin, armMax, 0);
6562
+ add(P10.ElbowLeft, "Elbow L", elbowMin, elbowMax, 0);
6302
6563
  if (roles.has("forearm_pose_L"))
6303
- addPose("L", P8.ArmPoseLeft, P8.ArmPoseAngleLeft);
6564
+ addPose("L", P10.ArmPoseLeft, P10.ArmPoseAngleLeft);
6304
6565
  }
6305
6566
  if (roles.has("arm_R")) {
6306
- add(P8.ArmRight, "Arm R", armMin, armMax, 0);
6307
- add(P8.ElbowRight, "Elbow R", elbowMin, elbowMax, 0);
6567
+ add(P10.ArmRight, "Arm R", armMin, armMax, 0);
6568
+ add(P10.ElbowRight, "Elbow R", elbowMin, elbowMax, 0);
6308
6569
  if (roles.has("forearm_pose_R"))
6309
- addPose("R", P8.ArmPoseRight, P8.ArmPoseAngleRight);
6570
+ addPose("R", P10.ArmPoseRight, P10.ArmPoseAngleRight);
6310
6571
  }
6311
- add(P8.EyeOpenLeft, "Eye L", 0, 1, 1);
6312
- add(P8.EyeOpenRight, "Eye R", 0, 1, 1);
6572
+ add(P10.EyeOpenLeft, "Eye L", 0, 1, 1);
6573
+ add(P10.EyeOpenRight, "Eye R", 0, 1, 1);
6313
6574
  if ([...roles].some((r) => /^(iris|pupil|highlight)_/.test(r))) {
6314
- add(P8.EyeballX, "Gaze X", -1, 1, 0);
6315
- add(P8.EyeballY, "Gaze Y", -1, 1, 0);
6575
+ add(P10.EyeballX, "Gaze X", -1, 1, 0);
6576
+ add(P10.EyeballY, "Gaze Y", -1, 1, 0);
6316
6577
  }
6317
- add(P8.MouthOpen, "Mouth Open", 0, 1, 0);
6318
- add(P8.MouthForm, "Mouth Form", -1, 1, 0);
6578
+ add(P10.MouthOpen, "Mouth Open", 0, 1, 0);
6579
+ add(P10.MouthForm, "Mouth Form", -1, 1, 0);
6319
6580
  if (roles.has("brow_L")) {
6320
- add(P8.BrowLeftY, "Brow L Y", -1, 1, 0);
6321
- add(P8.BrowLeftAngle, "Brow L Angle", -1, 1, 0);
6581
+ add(P10.BrowLeftY, "Brow L Y", -1, 1, 0);
6582
+ add(P10.BrowLeftAngle, "Brow L Angle", -1, 1, 0);
6322
6583
  }
6323
6584
  if (roles.has("brow_R")) {
6324
- add(P8.BrowRightY, "Brow R Y", -1, 1, 0);
6325
- add(P8.BrowRightAngle, "Brow R Angle", -1, 1, 0);
6585
+ add(P10.BrowRightY, "Brow R Y", -1, 1, 0);
6586
+ add(P10.BrowRightAngle, "Brow R Angle", -1, 1, 0);
6326
6587
  }
6327
6588
  if (roles.has("blush_L") || roles.has("blush_R")) {
6328
- add(P8.Cheek, "Cheek", 0, 1, 0);
6589
+ add(P10.Cheek, "Cheek", 0, 1, 0);
6329
6590
  }
6330
- add(P8.Breath, "Breath", 0, 1, 0);
6591
+ add(P10.Breath, "Breath", 0, 1, 0);
6331
6592
  if (roles.has("hair_front")) {
6332
- add(P8.HairSwayX, "Hair Sway X", -SWAY_RANGE, SWAY_RANGE, 0);
6333
- add(P8.HairSwayZ, "Hair Sway Z", -SWAY_RANGE, SWAY_RANGE, 0);
6593
+ add(P10.HairSwayX, "Hair Sway X", -SWAY_RANGE, SWAY_RANGE, 0);
6594
+ add(P10.HairSwayZ, "Hair Sway Z", -SWAY_RANGE, SWAY_RANGE, 0);
6334
6595
  }
6335
6596
  return out;
6336
6597
  }
@@ -6351,6 +6612,8 @@ export {
6351
6612
  LIP_INSIDE_ROLES,
6352
6613
  LIP_ROLES,
6353
6614
  LayerGeometryError,
6615
+ PatchError,
6616
+ SHUT_BY,
6354
6617
  SPECK_CORE_FRACTION,
6355
6618
  SetDeformerBindings,
6356
6619
  SetDeformerParent,