@ikijs/editor 0.18.0 → 0.20.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.js CHANGED
@@ -62,6 +62,7 @@ __export(index_exports, {
62
62
  createLayerSetMeasurer: () => createLayerSetMeasurer,
63
63
  denseCoreOf: () => denseCoreOf,
64
64
  detectAlphaBbox: () => detectAlphaBbox,
65
+ forearmPoseGeometry: () => forearmPoseGeometry,
65
66
  foregroundSpan: () => foregroundSpan,
66
67
  generateIkiFromLayerSet: () => generateIkiFromLayerSet,
67
68
  headHalfOf: () => headHalfOf,
@@ -1641,7 +1642,13 @@ var ROW_RUN_ROLES = /* @__PURE__ */ new Set([
1641
1642
  "hair_back",
1642
1643
  "body",
1643
1644
  "arm_L",
1644
- "arm_R"
1645
+ "arm_R",
1646
+ "forearm_pose_L",
1647
+ "forearm_pose_R"
1648
+ ]);
1649
+ var REST_HIDDEN_ROLES = /* @__PURE__ */ new Set([
1650
+ "forearm_pose_L",
1651
+ "forearm_pose_R"
1645
1652
  ]);
1646
1653
  function createLayerSetMeasurer(canvas) {
1647
1654
  for (const field of ["width", "height"]) {
@@ -1672,6 +1679,7 @@ function createLayerSetMeasurer(canvas) {
1672
1679
  if (bbox === null) return null;
1673
1680
  const rowLeft = new Int32Array(canvasH).fill(canvasW);
1674
1681
  const rowRight = new Int32Array(canvasH).fill(-1);
1682
+ const hidden = REST_HIDDEN_ROLES.has(role);
1675
1683
  const rowRuns = ROW_RUN_ROLES.has(role) ? [] : void 0;
1676
1684
  for (let y = 0; y < canvasH; y++) {
1677
1685
  let runs;
@@ -1687,14 +1695,14 @@ function createLayerSetMeasurer(canvas) {
1687
1695
  runs.push(x);
1688
1696
  inRun = on;
1689
1697
  }
1690
- if (!on) continue;
1698
+ if (!on || hidden) continue;
1691
1699
  opaque[p] = 1;
1692
1700
  if (x < rowLeft[y]) rowLeft[y] = x;
1693
1701
  if (x > rowRight[y]) rowRight[y] = x;
1694
1702
  }
1695
1703
  if (runs !== void 0 && inRun) runs.push(canvasW);
1696
1704
  }
1697
- rowSpansByRole.push({ role, rowLeft, rowRight });
1705
+ if (!hidden) rowSpansByRole.push({ role, rowLeft, rowRight });
1698
1706
  const layer = {
1699
1707
  role,
1700
1708
  fileName,
@@ -2754,7 +2762,11 @@ function headOwnBreath(hasBody) {
2754
2762
  var ELBOW_AT = 0.42;
2755
2763
  var CAP_ROWS = [0.1, 0.3];
2756
2764
  var CAP_SEGMENTS = 12;
2757
- var ARM_RANGE = [-30, 150];
2765
+ var CAP_INSET = 3;
2766
+ var capInset = (i) => Math.round(CAP_INSET * Math.min(1, Math.min(i, CAP_SEGMENTS - i) / 2));
2767
+ var CAP_RIM = 0.25;
2768
+ var ARM_RANGE = [-8, 32];
2769
+ var ELBOW_RANGE = [-10, 90];
2758
2770
  var ARM_PARAMS = {
2759
2771
  arm_L: { arm: import_format5.StandardParameter.ArmLeft, elbow: import_format5.StandardParameter.ElbowLeft },
2760
2772
  arm_R: { arm: import_format5.StandardParameter.ArmRight, elbow: import_format5.StandardParameter.ElbowRight }
@@ -2762,49 +2774,67 @@ var ARM_PARAMS = {
2762
2774
  var ARM_IDS = {
2763
2775
  arm_L: {
2764
2776
  forearm: "forearm_L",
2777
+ cap: "elbow_L",
2765
2778
  armDeformer: "armDeformer_L",
2766
2779
  forearmDeformer: "forearmDeformer_L"
2767
2780
  },
2768
2781
  arm_R: {
2769
2782
  forearm: "forearm_R",
2783
+ cap: "elbow_R",
2770
2784
  armDeformer: "armDeformer_R",
2771
2785
  forearmDeformer: "forearmDeformer_R"
2772
2786
  }
2773
2787
  };
2774
- function armGeometry(layer, bodyAxisX) {
2788
+ function endPivot(layer, end) {
2775
2789
  const { bbox, canvasW, canvasH, rowRuns } = layer;
2776
- const b = boxOfLayer(layer);
2777
- const span = (k) => {
2790
+ const span = runSpan(layer);
2791
+ const from = (k) => end === "top" ? k : bbox.h - 1 - k;
2792
+ const painted = rowRuns?.flatMap((runs, k) => runs.length > 0 ? [k] : []) ?? [];
2793
+ const firstK = end === "top" ? painted[0] ?? 0 : painted.at(-1) ?? bbox.h - 1;
2794
+ const lo = Math.ceil(CAP_ROWS[0] * bbox.h);
2795
+ const hi = Math.max(lo, Math.floor(CAP_ROWS[1] * bbox.h));
2796
+ const widths = [];
2797
+ for (let k = lo; k <= hi; k++) {
2798
+ const [s2, e2] = span(from(k));
2799
+ widths.push(e2 - s2);
2800
+ }
2801
+ widths.sort((p, q) => p - q);
2802
+ const radius = widths[widths.length >> 1] / 2;
2803
+ const ks = end === "top" ? firstK + radius : firstK - radius;
2804
+ const [s, e] = span(Math.round(ks));
2805
+ return {
2806
+ point: {
2807
+ x: roundTo((s + e) / 2 - canvasW / 2, 0.01),
2808
+ y: roundTo(canvasH / 2 - (bbox.y + ks + 0.5), 0.01)
2809
+ },
2810
+ radius,
2811
+ row: ks
2812
+ };
2813
+ }
2814
+ function runSpan(layer) {
2815
+ const { bbox, rowRuns } = layer;
2816
+ return (k) => {
2778
2817
  const runs = rowRuns?.[k] ?? [];
2779
2818
  if (runs.length === 0) return [bbox.x, bbox.x + bbox.w];
2780
- let [s2, e2] = [runs[0], runs[1]];
2819
+ let [s, e] = [runs[0], runs[1]];
2781
2820
  for (let i = 2; i < runs.length; i += 2) {
2782
- if (runs[i + 1] - runs[i] > e2 - s2) [s2, e2] = [runs[i], runs[i + 1]];
2821
+ if (runs[i + 1] - runs[i] > e - s) [s, e] = [runs[i], runs[i + 1]];
2783
2822
  }
2784
- return [s2, e2];
2823
+ return [s, e];
2785
2824
  };
2825
+ }
2826
+ function armGeometry(layer, bodyAxisX) {
2827
+ const { bbox, canvasW, canvasH, rowRuns } = layer;
2828
+ const b = boxOfLayer(layer);
2829
+ const span = runSpan(layer);
2786
2830
  const centreX = (k) => {
2787
2831
  const [s2, e2] = span(k);
2788
2832
  return (s2 + e2) / 2 - canvasW / 2;
2789
2833
  };
2790
2834
  const rowY = (k) => canvasH / 2 - (bbox.y + k + 0.5);
2791
2835
  const painted = rowRuns?.flatMap((runs, k) => runs.length > 0 ? [k] : []) ?? [];
2792
- const first = painted[0] ?? 0;
2793
2836
  const last = painted.at(-1) ?? bbox.h - 1;
2794
- const lo = Math.ceil(CAP_ROWS[0] * bbox.h);
2795
- const hi = Math.max(lo, Math.floor(CAP_ROWS[1] * bbox.h));
2796
- const widths = [];
2797
- for (let k = lo; k <= hi; k++) {
2798
- const [s2, e2] = span(k);
2799
- widths.push(e2 - s2);
2800
- }
2801
- widths.sort((p, q) => p - q);
2802
- const ru = widths[widths.length >> 1] / 2;
2803
- const ks = first + ru;
2804
- const shoulder = {
2805
- x: roundTo(centreX(Math.round(ks)), 0.01),
2806
- y: roundTo(rowY(ks), 0.01)
2807
- };
2837
+ const { point: shoulder, radius: ru, row: ks } = endPivot(layer, "top");
2808
2838
  const ke = Math.round(ks + ELBOW_AT * (last - ks));
2809
2839
  if (ke <= ks) {
2810
2840
  throw new LayerGeometryError(
@@ -2819,11 +2849,30 @@ function armGeometry(layer, bodyAxisX) {
2819
2849
  b.x1 - elbow.x,
2820
2850
  b.y1 - elbow.y
2821
2851
  );
2852
+ const inside = (x, y) => {
2853
+ const k = Math.floor(y) - bbox.y;
2854
+ if (k < 0 || k >= bbox.h) return false;
2855
+ const [rs, re] = span(k);
2856
+ return rs < x && x < re;
2857
+ };
2858
+ const capRays = Array.from({ length: CAP_SEGMENTS + 1 }, (_, i) => {
2859
+ const a = Math.PI * i / CAP_SEGMENTS;
2860
+ let t = 1;
2861
+ while (t <= capRadius + CAP_INSET && inside(
2862
+ elbow.x + canvasW / 2 + t * Math.cos(a),
2863
+ canvasH / 2 - elbow.y - t * Math.sin(a)
2864
+ )) {
2865
+ t++;
2866
+ }
2867
+ return Math.min(capRadius, Math.max(1, t - capInset(i)));
2868
+ });
2822
2869
  return {
2823
2870
  shoulder,
2824
2871
  shoulderRadius: ru,
2825
2872
  elbow,
2826
2873
  capRadius,
2874
+ capRays,
2875
+ seamRun: [s - bbox.x, e - bbox.x],
2827
2876
  side: shoulder.x > bodyAxisX ? 1 : -1
2828
2877
  };
2829
2878
  }
@@ -2833,84 +2882,188 @@ function meshOf(vertices, indices) {
2833
2882
  );
2834
2883
  return { vertices, uvs, indices };
2835
2884
  }
2836
- function armParts(role, layer, g, order) {
2885
+ function armParts(role, layer, g, order, poseSwitch) {
2837
2886
  const b = boxOfLayer(layer);
2838
2887
  const lx = (x) => roundTo((x - cx(b)) / bw(b), 1e-5);
2839
2888
  const ly = (y) => roundTo((y - cy(b)) / bh(b), 1e-5);
2840
2889
  const seam = ly(g.elbow.y);
2841
- const band = (top, bottom) => [
2890
+ const band = (top2, bottom) => [
2842
2891
  -0.5,
2843
- top,
2892
+ top2,
2844
2893
  0.5,
2845
- top,
2894
+ top2,
2846
2895
  -0.5,
2847
2896
  bottom,
2848
2897
  0.5,
2849
2898
  bottom
2850
2899
  ];
2851
2900
  const quad = [2, 3, 0, 0, 3, 1];
2852
- const cap = [lx(g.elbow.x), seam];
2901
+ const rays = g.capRays.length;
2902
+ const top = (rays - 1) / 2;
2903
+ const at = (i, r) => {
2904
+ const a = Math.PI * i / (rays - 1);
2905
+ return [lx(g.elbow.x + r * Math.cos(a)), ly(g.elbow.y + r * Math.sin(a))];
2906
+ };
2907
+ const width = (i) => Math.min(CAP_RIM * g.capRadius, g.capRays[i] / 2);
2908
+ const ringRays = Array.from({ length: rays }, (_, i) => i);
2909
+ ringRays.splice(top, 0, top);
2910
+ const vertices = [lx(g.elbow.x), seam];
2911
+ for (let i = 0; i < rays; i++) {
2912
+ vertices.push(...at(i, g.capRays[i] - width(i)));
2913
+ }
2914
+ const ringInner = vertices.length / 2;
2915
+ for (const i of ringRays) vertices.push(...at(i, g.capRays[i] - width(i)));
2916
+ const ringOuter = vertices.length / 2;
2917
+ for (const i of ringRays) vertices.push(...at(i, g.capRays[i]));
2918
+ const { uvs } = meshOf(vertices, []);
2919
+ const col = (c) => roundTo(Math.min(Math.max(c + 0.5, 0.5), bw(b) - 0.5) / bw(b), 1e-5);
2920
+ const v = roundTo(0.5 - seam, 1e-5);
2921
+ ringRays.forEach((i, j) => {
2922
+ const right = j <= top;
2923
+ const outer = right ? g.seamRun[1] : g.seamRun[0] - 1;
2924
+ const step = right ? -width(i) : width(i);
2925
+ uvs[(ringInner + j) * 2] = col(outer + step);
2926
+ uvs[(ringInner + j) * 2 + 1] = v;
2927
+ uvs[(ringOuter + j) * 2] = col(outer);
2928
+ uvs[(ringOuter + j) * 2 + 1] = v;
2929
+ });
2853
2930
  const fan = [];
2854
- for (let i = 0; i <= CAP_SEGMENTS; i++) {
2855
- const a = Math.PI * i / CAP_SEGMENTS;
2856
- cap.push(
2857
- lx(g.elbow.x + g.capRadius * Math.cos(a)),
2858
- ly(g.elbow.y + g.capRadius * Math.sin(a))
2859
- );
2860
- if (i > 0) fan.push(4, 4 + i, 5 + i);
2861
- }
2862
- const part = (id, deformer, at, mesh) => ({
2931
+ for (let i = 0; i < rays - 1; i++) fan.push(0, 1 + i, 2 + i);
2932
+ const ring = [];
2933
+ for (let j = 0; j < ringRays.length - 1; j++) {
2934
+ if (j === top) continue;
2935
+ const [p, q] = [ringInner + j, ringOuter + j];
2936
+ ring.push(p, q, q + 1, p, q + 1, p + 1);
2937
+ }
2938
+ const part = (id, deformer, z, mesh, swaps = false) => ({
2863
2939
  id,
2864
2940
  color: [1, 1, 1, 1],
2865
2941
  width: bw(b),
2866
2942
  height: bh(b),
2867
2943
  transform: { x: cx(b), y: cy(b) },
2868
- order: at,
2944
+ order: z,
2869
2945
  deformer,
2870
- mesh
2946
+ mesh,
2947
+ ...swaps && poseSwitch !== void 0 ? {
2948
+ bindings: [
2949
+ {
2950
+ parameter: poseSwitch,
2951
+ channel: "opacity",
2952
+ from: 1,
2953
+ to: 0
2954
+ }
2955
+ ]
2956
+ } : {}
2871
2957
  });
2872
2958
  const ids = ARM_IDS[role];
2873
2959
  return [
2874
- part(role, ids.armDeformer, order, meshOf(band(0.5, seam), quad)),
2960
+ part(
2961
+ ids.cap,
2962
+ ids.forearmDeformer,
2963
+ order,
2964
+ {
2965
+ vertices,
2966
+ uvs,
2967
+ indices: [...fan, ...ring]
2968
+ },
2969
+ true
2970
+ ),
2971
+ part(role, ids.armDeformer, order + 1, meshOf(band(0.5, seam), quad)),
2875
2972
  part(
2876
2973
  ids.forearm,
2877
2974
  ids.forearmDeformer,
2878
- order + 1,
2879
- meshOf([...band(seam, -0.5), ...cap], [...quad, ...fan])
2975
+ order + 2,
2976
+ meshOf(band(seam, -0.5), quad),
2977
+ true
2880
2978
  )
2881
2979
  ];
2882
2980
  }
2981
+ var rotateBinding = (parameter, range, sign) => ({
2982
+ parameter,
2983
+ channel: "rotate",
2984
+ from: sign * range[0],
2985
+ to: sign * range[1]
2986
+ });
2883
2987
  function armDeformers(role, g) {
2884
2988
  const ids = ARM_IDS[role];
2885
2989
  const params = ARM_PARAMS[role];
2886
- const rotate = (parameter) => ({
2887
- parameter,
2888
- channel: "rotate",
2889
- from: g.side * ARM_RANGE[0],
2890
- to: g.side * ARM_RANGE[1]
2891
- });
2892
2990
  return [
2893
2991
  {
2894
2992
  id: ids.armDeformer,
2895
2993
  parent: BODY_WARP_ID,
2896
2994
  pivot: { ...g.shoulder },
2897
- bindings: [rotate(params.arm)]
2995
+ bindings: [rotateBinding(params.arm, ARM_RANGE, g.side)]
2898
2996
  },
2899
2997
  {
2900
2998
  id: ids.forearmDeformer,
2901
2999
  parent: ids.armDeformer,
2902
3000
  pivot: { ...g.elbow },
2903
- bindings: [rotate(params.elbow)]
3001
+ bindings: [rotateBinding(params.elbow, ELBOW_RANGE, -g.side)]
2904
3002
  }
2905
3003
  ];
2906
3004
  }
2907
3005
 
3006
+ // src/auto-rig/forearm-pose.ts
3007
+ var import_format6 = require("@ikijs/format");
3008
+ var ARM_OF_POSE = {
3009
+ forearm_pose_L: "arm_L",
3010
+ forearm_pose_R: "arm_R"
3011
+ };
3012
+ var POSE_OF_ARM = {
3013
+ arm_L: "forearm_pose_L",
3014
+ arm_R: "forearm_pose_R"
3015
+ };
3016
+ var POSE_PARAMS = {
3017
+ forearm_pose_L: { pose: import_format6.StandardParameter.ArmPoseLeft, angle: import_format6.StandardParameter.ArmPoseAngleLeft },
3018
+ forearm_pose_R: { pose: import_format6.StandardParameter.ArmPoseRight, angle: import_format6.StandardParameter.ArmPoseAngleRight }
3019
+ };
3020
+ var POSE_IDS = {
3021
+ forearm_pose_L: "armPoseDeformer_L",
3022
+ forearm_pose_R: "armPoseDeformer_R"
3023
+ };
3024
+ var POSE_ANGLE_RANGE = [-15, 15];
3025
+ function forearmPoseGeometry(layer) {
3026
+ const { point, radius } = endPivot(layer, "bottom");
3027
+ const first = layer.rowRuns?.findIndex((runs) => runs.length > 0) ?? -1;
3028
+ const k = first < 0 ? 0 : first;
3029
+ return {
3030
+ pivot: point,
3031
+ radius,
3032
+ top: roundTo(layer.canvasH / 2 - (layer.bbox.y + k + 0.5), 0.01)
3033
+ };
3034
+ }
3035
+ function forearmPosePart(role, layer, order) {
3036
+ const b = boxOfLayer(layer);
3037
+ return {
3038
+ id: role,
3039
+ color: [1, 1, 1, 1],
3040
+ width: bw(b),
3041
+ height: bh(b),
3042
+ transform: { x: cx(b), y: cy(b) },
3043
+ order,
3044
+ deformer: POSE_IDS[role],
3045
+ bindings: [
3046
+ { parameter: POSE_PARAMS[role].pose, channel: "opacity", from: 0, to: 1 }
3047
+ ]
3048
+ };
3049
+ }
3050
+ function forearmPoseDeformer(role, arm) {
3051
+ return {
3052
+ id: POSE_IDS[role],
3053
+ parent: ARM_IDS[ARM_OF_POSE[role]].armDeformer,
3054
+ pivot: { ...arm.elbow },
3055
+ bindings: [
3056
+ rotateBinding(POSE_PARAMS[role].angle, POSE_ANGLE_RANGE, -arm.side)
3057
+ ]
3058
+ };
3059
+ }
3060
+
2908
3061
  // src/auto-rig/roles.ts
2909
3062
  var ROLE_TABLE = [
2910
3063
  { role: "hair_back", family: "hair_back" },
2911
3064
  { role: "body", family: "body" },
2912
- { role: "arm_L", family: "arm", parts: ["arm_L", "forearm_L"] },
2913
- { role: "arm_R", family: "arm", parts: ["arm_R", "forearm_R"] },
3065
+ { role: "arm_L", family: "arm", parts: ["elbow_L", "arm_L", "forearm_L"] },
3066
+ { role: "arm_R", family: "arm", parts: ["elbow_R", "arm_R", "forearm_R"] },
2914
3067
  { role: "face", family: "face", required: true },
2915
3068
  { role: "blush_L", family: "face" },
2916
3069
  { role: "blush_R", family: "face" },
@@ -2931,7 +3084,10 @@ var ROLE_TABLE = [
2931
3084
  { role: "lash_R", family: "eye_R" },
2932
3085
  { role: "brow_L", family: "brow_L" },
2933
3086
  { role: "brow_R", family: "brow_R" },
2934
- { role: "hair_front", family: "hair_front" }
3087
+ { role: "hair_front", family: "hair_front" },
3088
+ // Drawn above the face and the hair: a raised hand passes them.
3089
+ { role: "forearm_pose_L", family: "forearm_pose" },
3090
+ { role: "forearm_pose_R", family: "forearm_pose" }
2935
3091
  ];
2936
3092
  var REQUIRED_ROLES = ROLE_TABLE.filter(
2937
3093
  (r) => r.required
@@ -2971,6 +3127,16 @@ function checkArmsHaveBody(roles) {
2971
3127
  );
2972
3128
  }
2973
3129
  }
3130
+ function checkPosesHaveArms(roles) {
3131
+ const has = new Set(roles);
3132
+ for (const side of ["L", "R"]) {
3133
+ if (has.has(`forearm_pose_${side}`) && !has.has(`arm_${side}`)) {
3134
+ throw new Error(
3135
+ `auto-rig: forearm_pose_${side} needs an arm_${side} layer (a pose forearm hangs from its arm's elbow)`
3136
+ );
3137
+ }
3138
+ }
3139
+ }
2974
3140
  function parseLayerRoles(fileNames) {
2975
3141
  const seen = /* @__PURE__ */ new Map();
2976
3142
  const out = [];
@@ -2997,36 +3163,37 @@ function parseLayerRoles(fileNames) {
2997
3163
  );
2998
3164
  }
2999
3165
  checkArmsHaveBody(seen.keys());
3166
+ checkPosesHaveArms(seen.keys());
3000
3167
  return out;
3001
3168
  }
3002
3169
 
3003
3170
  // src/auto-rig/generate.ts
3004
- var import_format8 = require("@ikijs/format");
3171
+ var import_format9 = require("@ikijs/format");
3005
3172
 
3006
3173
  // src/auto-rig/animations.ts
3007
- var import_format6 = require("@ikijs/format");
3174
+ var import_format7 = require("@ikijs/format");
3008
3175
  function browsY(y) {
3009
3176
  return [
3010
- { parameter: import_format6.StandardParameter.BrowLeftY, value: y, blend: "add" },
3011
- { parameter: import_format6.StandardParameter.BrowRightY, value: y, blend: "add" }
3177
+ { parameter: import_format7.StandardParameter.BrowLeftY, value: y, blend: "add" },
3178
+ { parameter: import_format7.StandardParameter.BrowRightY, value: y, blend: "add" }
3012
3179
  ];
3013
3180
  }
3014
3181
  function browsTilt(innerDown) {
3015
3182
  return [
3016
- { parameter: import_format6.StandardParameter.BrowLeftAngle, value: innerDown, blend: "add" },
3017
- { parameter: import_format6.StandardParameter.BrowRightAngle, value: -innerDown, blend: "add" }
3183
+ { parameter: import_format7.StandardParameter.BrowLeftAngle, value: innerDown, blend: "add" },
3184
+ { parameter: import_format7.StandardParameter.BrowRightAngle, value: -innerDown, blend: "add" }
3018
3185
  ];
3019
3186
  }
3020
3187
  function cheek(value) {
3021
- return { parameter: import_format6.StandardParameter.Cheek, value, blend: "add" };
3188
+ return { parameter: import_format7.StandardParameter.Cheek, value, blend: "add" };
3022
3189
  }
3023
- var BROWS = [import_format6.StandardParameter.BrowLeftY, import_format6.StandardParameter.BrowRightY, import_format6.StandardParameter.BrowLeftAngle, import_format6.StandardParameter.BrowRightAngle];
3190
+ var BROWS = [import_format7.StandardParameter.BrowLeftY, import_format7.StandardParameter.BrowRightY, import_format7.StandardParameter.BrowLeftAngle, import_format7.StandardParameter.BrowRightAngle];
3024
3191
  var EXPRESSIONS = [
3025
3192
  {
3026
3193
  id: "smile",
3027
3194
  description: "Smiling and pleased: warm, friendly, content. For greetings, thanks, agreement and gentle happiness.",
3028
3195
  parameters: [
3029
- { parameter: import_format6.StandardParameter.MouthForm, value: 1, blend: "add" },
3196
+ { parameter: import_format7.StandardParameter.MouthForm, value: 1, blend: "add" },
3030
3197
  ...browsY(0.25),
3031
3198
  cheek(0.4)
3032
3199
  ]
@@ -3035,10 +3202,10 @@ var EXPRESSIONS = [
3035
3202
  id: "laugh",
3036
3203
  description: "Laughing, eyes shut and mouth open: delighted, amused. For jokes, playfulness and big joy.",
3037
3204
  parameters: [
3038
- { parameter: import_format6.StandardParameter.EyeOpenLeft, value: 0, blend: "multiply" },
3039
- { parameter: import_format6.StandardParameter.EyeOpenRight, value: 0, blend: "multiply" },
3040
- { parameter: import_format6.StandardParameter.MouthForm, value: 1, blend: "add" },
3041
- { parameter: import_format6.StandardParameter.MouthOpen, value: 0.8, blend: "overwrite" },
3205
+ { parameter: import_format7.StandardParameter.EyeOpenLeft, value: 0, blend: "multiply" },
3206
+ { parameter: import_format7.StandardParameter.EyeOpenRight, value: 0, blend: "multiply" },
3207
+ { parameter: import_format7.StandardParameter.MouthForm, value: 1, blend: "add" },
3208
+ { parameter: import_format7.StandardParameter.MouthOpen, value: 0.8, blend: "overwrite" },
3042
3209
  ...browsY(0.4),
3043
3210
  cheek(0.65)
3044
3211
  ]
@@ -3050,7 +3217,7 @@ var EXPRESSIONS = [
3050
3217
  parameters: [
3051
3218
  ...browsY(-0.5),
3052
3219
  ...browsTilt(0.8),
3053
- { parameter: import_format6.StandardParameter.MouthForm, value: -0.9, blend: "add" }
3220
+ { parameter: import_format7.StandardParameter.MouthForm, value: -0.9, blend: "add" }
3054
3221
  ]
3055
3222
  },
3056
3223
  {
@@ -3060,7 +3227,7 @@ var EXPRESSIONS = [
3060
3227
  parameters: [
3061
3228
  ...browsY(0.35),
3062
3229
  ...browsTilt(-0.8),
3063
- { parameter: import_format6.StandardParameter.MouthForm, value: -0.8, blend: "add" }
3230
+ { parameter: import_format7.StandardParameter.MouthForm, value: -0.8, blend: "add" }
3064
3231
  ]
3065
3232
  },
3066
3233
  {
@@ -3068,18 +3235,18 @@ var EXPRESSIONS = [
3068
3235
  description: "Surprised, mouth dropped open: startled, amazed. For shock, sudden news or disbelief.",
3069
3236
  parameters: [
3070
3237
  ...browsY(0.8),
3071
- { parameter: import_format6.StandardParameter.MouthOpen, value: 0.9, blend: "overwrite" }
3238
+ { parameter: import_format7.StandardParameter.MouthOpen, value: 0.9, blend: "overwrite" }
3072
3239
  ]
3073
3240
  },
3074
3241
  {
3075
3242
  id: "shy",
3076
3243
  description: "Shy or embarrassed: bashful, flustered. For being praised, teased or caught off guard.",
3077
- needs: [import_format6.StandardParameter.Cheek],
3244
+ needs: [import_format7.StandardParameter.Cheek],
3078
3245
  parameters: [
3079
3246
  cheek(1),
3080
3247
  // Gaze down.
3081
- { parameter: import_format6.StandardParameter.EyeballY, value: -0.65, blend: "add" },
3082
- { parameter: import_format6.StandardParameter.MouthForm, value: 0.4, blend: "add" },
3248
+ { parameter: import_format7.StandardParameter.EyeballY, value: -0.65, blend: "add" },
3249
+ { parameter: import_format7.StandardParameter.MouthForm, value: 0.4, blend: "add" },
3083
3250
  ...browsTilt(-0.25)
3084
3251
  ]
3085
3252
  }
@@ -3092,14 +3259,14 @@ function defaultExpressions(declared) {
3092
3259
  parameters: e.parameters.filter((t) => declared.has(t.parameter))
3093
3260
  }));
3094
3261
  }
3095
- var DEFAULT_MOTIONS = {
3262
+ var HEAD_MOTIONS = {
3096
3263
  Nod: [
3097
3264
  {
3098
3265
  description: "Nods yes: agreement, acknowledgement, understanding.",
3099
3266
  duration: 1,
3100
3267
  curves: [
3101
3268
  {
3102
- parameter: import_format6.StandardParameter.AngleY,
3269
+ parameter: import_format7.StandardParameter.AngleY,
3103
3270
  keys: [
3104
3271
  [0, 0],
3105
3272
  [0.3, -18],
@@ -3120,7 +3287,7 @@ var DEFAULT_MOTIONS = {
3120
3287
  fadeIn: 0.15,
3121
3288
  curves: [
3122
3289
  {
3123
- parameter: import_format6.StandardParameter.AngleX,
3290
+ parameter: import_format7.StandardParameter.AngleX,
3124
3291
  keys: [
3125
3292
  [0, 0],
3126
3293
  [0.2, -18],
@@ -3139,7 +3306,7 @@ var DEFAULT_MOTIONS = {
3139
3306
  duration: 1.4,
3140
3307
  curves: [
3141
3308
  {
3142
- parameter: import_format6.StandardParameter.AngleZ,
3309
+ parameter: import_format7.StandardParameter.AngleZ,
3143
3310
  keys: [
3144
3311
  [0, 0],
3145
3312
  [0.35, 20],
@@ -3151,6 +3318,55 @@ var DEFAULT_MOTIONS = {
3151
3318
  }
3152
3319
  ]
3153
3320
  };
3321
+ var WAVE = {
3322
+ Wave: [
3323
+ {
3324
+ description: "Waves hello with the right hand: greeting, goodbye, getting attention.",
3325
+ duration: 2.2,
3326
+ fadeIn: 0.15,
3327
+ fadeOut: 0.15,
3328
+ curves: [
3329
+ {
3330
+ parameter: import_format7.StandardParameter.ArmPoseRight,
3331
+ interpolation: "linear",
3332
+ keys: [
3333
+ [0, 0],
3334
+ [0.15, 1],
3335
+ [2.05, 1],
3336
+ [2.2, 0]
3337
+ ]
3338
+ },
3339
+ {
3340
+ parameter: import_format7.StandardParameter.ArmRight,
3341
+ keys: [
3342
+ [0, 0],
3343
+ [0.4, 10],
3344
+ [1.8, 10],
3345
+ [2.2, 0]
3346
+ ]
3347
+ },
3348
+ {
3349
+ parameter: import_format7.StandardParameter.ArmPoseAngleRight,
3350
+ keys: [
3351
+ [0, 0],
3352
+ [0.5, 0],
3353
+ [0.7, 12],
3354
+ [1, -12],
3355
+ [1.3, 12],
3356
+ [1.7, 0],
3357
+ [2.2, 0]
3358
+ ]
3359
+ }
3360
+ ]
3361
+ }
3362
+ ]
3363
+ };
3364
+ function defaultMotions(declared) {
3365
+ const waves = [import_format7.StandardParameter.ArmRight, import_format7.StandardParameter.ArmPoseRight, import_format7.StandardParameter.ArmPoseAngleRight].every(
3366
+ (id) => declared.has(id)
3367
+ );
3368
+ return waves ? { ...HEAD_MOTIONS, ...WAVE } : HEAD_MOTIONS;
3369
+ }
3154
3370
 
3155
3371
  // src/auto-rig/checks.ts
3156
3372
  var finite = (v) => typeof v === "number" && Number.isFinite(v);
@@ -3256,6 +3472,7 @@ function checkLayers(layers, canvas) {
3256
3472
  throw new Error(`auto-rig: missing required role(s) ${missing.join(", ")}`);
3257
3473
  }
3258
3474
  checkArmsHaveBody(seen);
3475
+ checkPosesHaveArms(seen);
3259
3476
  }
3260
3477
  function checkHeadEdges(edges, byRole) {
3261
3478
  if (edges === void 0) return;
@@ -3373,7 +3590,7 @@ function checkStrandEdges(strand, irises, hair) {
3373
3590
  }
3374
3591
 
3375
3592
  // src/auto-rig/context.ts
3376
- var import_format7 = require("@ikijs/format");
3593
+ var import_format8 = require("@ikijs/format");
3377
3594
 
3378
3595
  // src/auto-rig/head.ts
3379
3596
  function outerEdge(runs, axisX, side) {
@@ -4405,6 +4622,7 @@ function familyField(m, family) {
4405
4622
  return hairField(m, m.hairBack, NOD.hairBack);
4406
4623
  case "body":
4407
4624
  case "arm":
4625
+ case "forearm_pose":
4408
4626
  return () => [0, 0];
4409
4627
  }
4410
4628
  }
@@ -4504,7 +4722,7 @@ function renderedLander(turn, parts, grids, from = /* @__PURE__ */ new Map()) {
4504
4722
  const family = roleSpec(role).family;
4505
4723
  const part = parts.find((p) => p.id === role);
4506
4724
  const g = grids.get(family);
4507
- const warp = part?.warps?.find((w) => w.parameter === import_format7.StandardParameter.AngleX);
4725
+ const warp = part?.warps?.find((w) => w.parameter === import_format8.StandardParameter.AngleX);
4508
4726
  if (part === void 0 || part.mesh === void 0 || !g && !warp) {
4509
4727
  return x + field(role)(x, y, ax, 0)[0];
4510
4728
  }
@@ -5240,6 +5458,7 @@ var WARP_ID = {
5240
5458
  };
5241
5459
  var isGridFamily = (f) => f in WARP_ID;
5242
5460
  var isArm = (spec) => spec.family === "arm";
5461
+ var isPose = (spec) => spec.family === "forearm_pose";
5243
5462
  var GRID_PAD = 6;
5244
5463
  function generateIkiFromLayerSet(layers, canvas, options = {}) {
5245
5464
  checkLayers(layers, canvas);
@@ -5308,11 +5527,22 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
5308
5527
  const layer = byRole.get(spec.role);
5309
5528
  if (layer === void 0) continue;
5310
5529
  if (isArm(spec)) {
5530
+ const pose = POSE_OF_ARM[spec.role];
5311
5531
  parts.push(
5312
- ...armParts(spec.role, layer, arms.get(spec.role), parts.length)
5532
+ ...armParts(
5533
+ spec.role,
5534
+ layer,
5535
+ arms.get(spec.role),
5536
+ parts.length,
5537
+ has(pose) ? POSE_PARAMS[pose].pose : void 0
5538
+ )
5313
5539
  );
5314
5540
  continue;
5315
5541
  }
5542
+ if (isPose(spec)) {
5543
+ parts.push(forearmPosePart(spec.role, layer, parts.length));
5544
+ continue;
5545
+ }
5316
5546
  const built = buildPart(
5317
5547
  spec,
5318
5548
  boxOfLayer(layer),
@@ -5365,7 +5595,7 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
5365
5595
  part.mesh = bodyWarp.mesh;
5366
5596
  continue;
5367
5597
  }
5368
- if (family === "arm") continue;
5598
+ if (family === "arm" || family === "forearm_pose") continue;
5369
5599
  part.deformer = "headDeformer";
5370
5600
  if (part.mesh === void 0) continue;
5371
5601
  const own = familyField(turn, family);
@@ -5377,17 +5607,17 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
5377
5607
  }
5378
5608
  const parameters = declareParameters(new Set(byRole.keys()));
5379
5609
  const model = {
5380
- version: import_format8.IKI_FORMAT_VERSION,
5610
+ version: import_format9.IKI_FORMAT_VERSION,
5381
5611
  name: "auto-rigged",
5382
5612
  canvas: { width: canvas.width, height: canvas.height },
5383
5613
  parameters,
5384
5614
  parts,
5385
- deformers: deformers(frame, grids, bodyWarp?.deformer, arms),
5615
+ deformers: deformers(frame, grids, bodyWarp?.deformer, arms, byRole),
5386
5616
  ...has("hair_front") ? { physics: hairPhysics() } : {},
5387
5617
  expressions: defaultExpressions(new Set(parameters.map((p) => p.id))),
5388
- motions: DEFAULT_MOTIONS
5618
+ motions: defaultMotions(new Set(parameters.map((p) => p.id)))
5389
5619
  };
5390
- const valid = (0, import_format8.parseIkiModel)(model);
5620
+ const valid = (0, import_format9.parseIkiModel)(model);
5391
5621
  if (hasNose && options.onTurnSolved) {
5392
5622
  options.onTurnSolved(
5393
5623
  turnReport(
@@ -5402,14 +5632,14 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
5402
5632
  function turnWarps(mesh, b, fieldOf) {
5403
5633
  return [
5404
5634
  localWarp(
5405
- import_format8.StandardParameter.AngleX,
5635
+ import_format9.StandardParameter.AngleX,
5406
5636
  mesh,
5407
5637
  b,
5408
5638
  X_STOPS,
5409
5639
  ([x, y], v, i) => v === 0 ? [0, 0] : [fieldOf(i)(x, y, v, 0)[0], 0]
5410
5640
  ),
5411
5641
  localWarp(
5412
- import_format8.StandardParameter.AngleY,
5642
+ import_format9.StandardParameter.AngleY,
5413
5643
  mesh,
5414
5644
  b,
5415
5645
  Y_STOPS,
@@ -5457,7 +5687,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
5457
5687
  }
5458
5688
  if (mesh !== void 0) part.mesh = mesh;
5459
5689
  const side = spec.role.endsWith("_L") ? "L" : "R";
5460
- const eyeOpen = side === "L" ? import_format8.StandardParameter.EyeOpenLeft : import_format8.StandardParameter.EyeOpenRight;
5690
+ const eyeOpen = side === "L" ? import_format9.StandardParameter.EyeOpenLeft : import_format9.StandardParameter.EyeOpenRight;
5461
5691
  const hh = frame.hh;
5462
5692
  switch (spec.role) {
5463
5693
  case "face":
@@ -5472,7 +5702,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
5472
5702
  headOwnRoll(byRole.has("body"))
5473
5703
  ),
5474
5704
  localWarp(
5475
- import_format8.StandardParameter.Breath,
5705
+ import_format9.StandardParameter.Breath,
5476
5706
  mesh,
5477
5707
  b,
5478
5708
  [0, 1],
@@ -5519,8 +5749,8 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
5519
5749
  if (byRole.has("mouth_open")) {
5520
5750
  warps.push(mouthWiden(mesh, b));
5521
5751
  bindings.push(
5522
- { parameter: import_format8.StandardParameter.MouthOpen, channel: "opacity", from: 1, to: 0 },
5523
- { parameter: import_format8.StandardParameter.MouthOpen, channel: "opacity", from: 1, to: 0 }
5752
+ { parameter: import_format9.StandardParameter.MouthOpen, channel: "opacity", from: 1, to: 0 },
5753
+ { parameter: import_format9.StandardParameter.MouthOpen, channel: "opacity", from: 1, to: 0 }
5524
5754
  );
5525
5755
  extra = [(AMPLITUDE.mouthOpenWidth - 1) * (bw(b) / 2), 0];
5526
5756
  } else {
@@ -5530,19 +5760,19 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
5530
5760
  );
5531
5761
  bindings.push(
5532
5762
  {
5533
- parameter: import_format8.StandardParameter.MouthOpen,
5763
+ parameter: import_format9.StandardParameter.MouthOpen,
5534
5764
  channel: "scaleY",
5535
5765
  from: 0,
5536
5766
  to: roundTo(grow, 0.01)
5537
5767
  },
5538
5768
  {
5539
- parameter: import_format8.StandardParameter.MouthOpen,
5769
+ parameter: import_format9.StandardParameter.MouthOpen,
5540
5770
  channel: "scaleX",
5541
5771
  from: 0,
5542
5772
  to: roundTo(AMPLITUDE.mouthOpenWidth - 1, 0.01)
5543
5773
  },
5544
5774
  {
5545
- parameter: import_format8.StandardParameter.MouthOpen,
5775
+ parameter: import_format9.StandardParameter.MouthOpen,
5546
5776
  channel: "translateY",
5547
5777
  from: 0,
5548
5778
  to: -roundTo(grow * bh(b) / 2, 0.01)
@@ -5554,7 +5784,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
5554
5784
  case "mouth_open":
5555
5785
  warps.push(mouthForm(mesh, b), mouthOpenGrow(mesh, b));
5556
5786
  bindings.push({
5557
- parameter: import_format8.StandardParameter.MouthOpen,
5787
+ parameter: import_format9.StandardParameter.MouthOpen,
5558
5788
  channel: "opacity",
5559
5789
  from: 0,
5560
5790
  to: 1
@@ -5564,7 +5794,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
5564
5794
  case "blush_L":
5565
5795
  case "blush_R":
5566
5796
  bindings.push({
5567
- parameter: import_format8.StandardParameter.Cheek,
5797
+ parameter: import_format9.StandardParameter.Cheek,
5568
5798
  channel: "opacity",
5569
5799
  from: AMPLITUDE.blushRest,
5570
5800
  to: 1
@@ -5575,8 +5805,8 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
5575
5805
  if (byRole.has("hair_front")) {
5576
5806
  const amp = style.sway * AMPLITUDE.sway * hh;
5577
5807
  warps.push(
5578
- hairSway(import_format8.StandardParameter.HairSwayX, mesh, b, amp),
5579
- hairSway(import_format8.StandardParameter.HairSwayZ, mesh, b, amp)
5808
+ hairSway(import_format9.StandardParameter.HairSwayX, mesh, b, amp),
5809
+ hairSway(import_format9.StandardParameter.HairSwayZ, mesh, b, amp)
5580
5810
  );
5581
5811
  }
5582
5812
  warps.push(tiltHang(mesh, b, pivot, hairHangWeight(frame.chinY, b.y0)));
@@ -5649,10 +5879,14 @@ function meshScale(role, frame) {
5649
5879
  return Infinity;
5650
5880
  }
5651
5881
  }
5652
- function deformers(frame, grids, bodyWarp, arms) {
5882
+ function deformers(frame, grids, bodyWarp, arms, byRole) {
5653
5883
  const out = [];
5654
5884
  if (bodyWarp !== void 0) out.push(bodyWarp);
5655
5885
  for (const [role, g] of arms) out.push(...armDeformers(role, g));
5886
+ for (const [role, arm] of arms) {
5887
+ const pose = POSE_OF_ARM[role];
5888
+ if (byRole.has(pose)) out.push(forearmPoseDeformer(pose, arm));
5889
+ }
5656
5890
  const hasBody = bodyWarp !== void 0;
5657
5891
  const roll = headOwnRoll(hasBody);
5658
5892
  out.push({
@@ -5661,9 +5895,9 @@ function deformers(frame, grids, bodyWarp, arms) {
5661
5895
  pivot: { x: roundTo(frame.axisX, 0.01), y: roundTo(frame.chinY, 0.01) },
5662
5896
  bindings: [
5663
5897
  // AngleZ is clockwise-positive (Live2D's); a rotation is CCW-positive.
5664
- { parameter: import_format8.StandardParameter.AngleZ, channel: "rotate", from: roll, to: -roll },
5898
+ { parameter: import_format9.StandardParameter.AngleZ, channel: "rotate", from: roll, to: -roll },
5665
5899
  {
5666
- parameter: import_format8.StandardParameter.Breath,
5900
+ parameter: import_format9.StandardParameter.Breath,
5667
5901
  channel: "translateY",
5668
5902
  from: 0,
5669
5903
  to: roundTo(headOwnBreath(hasBody) * frame.hh, 0.01)
@@ -5681,8 +5915,8 @@ function deformers(frame, grids, bodyWarp, arms) {
5681
5915
  points: g.lattice.points
5682
5916
  },
5683
5917
  warp2d: {
5684
- parameter: import_format8.StandardParameter.AngleX,
5685
- parameterY: import_format8.StandardParameter.AngleY,
5918
+ parameter: import_format9.StandardParameter.AngleX,
5919
+ parameterY: import_format9.StandardParameter.AngleY,
5686
5920
  valuesX: X_STOPS,
5687
5921
  valuesY: Y_STOPS,
5688
5922
  keyforms2d: g.keyforms.map((offsets) => ({ offsets }))
@@ -5695,16 +5929,16 @@ function hairPhysics() {
5695
5929
  return [
5696
5930
  {
5697
5931
  id: "hairSway",
5698
- input: { parameter: import_format8.StandardParameter.AngleX, weight: 1 },
5699
- output: { parameter: import_format8.StandardParameter.HairSwayX, scale: 5 },
5932
+ input: { parameter: import_format9.StandardParameter.AngleX, weight: 1 },
5933
+ output: { parameter: import_format9.StandardParameter.HairSwayX, scale: 5 },
5700
5934
  mass: 1,
5701
5935
  stiffness: 30,
5702
5936
  damping: 3
5703
5937
  },
5704
5938
  {
5705
5939
  id: "hairTilt",
5706
- input: { parameter: import_format8.StandardParameter.AngleZ, weight: 1 },
5707
- output: { parameter: import_format8.StandardParameter.HairSwayZ, scale: 8 },
5940
+ input: { parameter: import_format9.StandardParameter.AngleZ, weight: 1 },
5941
+ output: { parameter: import_format9.StandardParameter.HairSwayZ, scale: 8 },
5708
5942
  mass: 1,
5709
5943
  stiffness: 25,
5710
5944
  damping: 2.5
@@ -5714,46 +5948,55 @@ function hairPhysics() {
5714
5948
  function declareParameters(roles) {
5715
5949
  const out = [];
5716
5950
  const add = (id, name, min, max, def) => out.push({ id, name, min, max, default: def });
5717
- add(import_format8.StandardParameter.AngleX, "Head Angle", -30, 30, 0);
5718
- add(import_format8.StandardParameter.AngleY, "Head Angle Y", -30, 30, 0);
5719
- add(import_format8.StandardParameter.AngleZ, "Head Angle Z", -30, 30, 0);
5951
+ add(import_format9.StandardParameter.AngleX, "Head Angle", -30, 30, 0);
5952
+ add(import_format9.StandardParameter.AngleY, "Head Angle Y", -30, 30, 0);
5953
+ add(import_format9.StandardParameter.AngleZ, "Head Angle Z", -30, 30, 0);
5720
5954
  if (roles.has("body")) {
5721
- add(import_format8.StandardParameter.BodyAngleX, "Body Angle X", -10, 10, 0);
5722
- add(import_format8.StandardParameter.BodyAngleY, "Body Angle Y", -10, 10, 0);
5723
- add(import_format8.StandardParameter.BodyAngleZ, "Body Angle Z", -10, 10, 0);
5955
+ add(import_format9.StandardParameter.BodyAngleX, "Body Angle X", -10, 10, 0);
5956
+ add(import_format9.StandardParameter.BodyAngleY, "Body Angle Y", -10, 10, 0);
5957
+ add(import_format9.StandardParameter.BodyAngleZ, "Body Angle Z", -10, 10, 0);
5724
5958
  }
5959
+ const addPose = (side, pose, angle) => {
5960
+ add(pose, `Arm Pose ${side}`, 0, 1, 0);
5961
+ add(angle, `Arm Pose Angle ${side}`, ...POSE_ANGLE_RANGE, 0);
5962
+ };
5725
5963
  const [armMin, armMax] = ARM_RANGE;
5964
+ const [elbowMin, elbowMax] = ELBOW_RANGE;
5726
5965
  if (roles.has("arm_L")) {
5727
- add(import_format8.StandardParameter.ArmLeft, "Arm L", armMin, armMax, 0);
5728
- add(import_format8.StandardParameter.ElbowLeft, "Elbow L", armMin, armMax, 0);
5966
+ add(import_format9.StandardParameter.ArmLeft, "Arm L", armMin, armMax, 0);
5967
+ add(import_format9.StandardParameter.ElbowLeft, "Elbow L", elbowMin, elbowMax, 0);
5968
+ if (roles.has("forearm_pose_L"))
5969
+ addPose("L", import_format9.StandardParameter.ArmPoseLeft, import_format9.StandardParameter.ArmPoseAngleLeft);
5729
5970
  }
5730
5971
  if (roles.has("arm_R")) {
5731
- add(import_format8.StandardParameter.ArmRight, "Arm R", armMin, armMax, 0);
5732
- add(import_format8.StandardParameter.ElbowRight, "Elbow R", armMin, armMax, 0);
5972
+ add(import_format9.StandardParameter.ArmRight, "Arm R", armMin, armMax, 0);
5973
+ add(import_format9.StandardParameter.ElbowRight, "Elbow R", elbowMin, elbowMax, 0);
5974
+ if (roles.has("forearm_pose_R"))
5975
+ addPose("R", import_format9.StandardParameter.ArmPoseRight, import_format9.StandardParameter.ArmPoseAngleRight);
5733
5976
  }
5734
- add(import_format8.StandardParameter.EyeOpenLeft, "Eye L", 0, 1, 1);
5735
- add(import_format8.StandardParameter.EyeOpenRight, "Eye R", 0, 1, 1);
5977
+ add(import_format9.StandardParameter.EyeOpenLeft, "Eye L", 0, 1, 1);
5978
+ add(import_format9.StandardParameter.EyeOpenRight, "Eye R", 0, 1, 1);
5736
5979
  if ([...roles].some((r) => /^(iris|pupil|highlight)_/.test(r))) {
5737
- add(import_format8.StandardParameter.EyeballX, "Gaze X", -1, 1, 0);
5738
- add(import_format8.StandardParameter.EyeballY, "Gaze Y", -1, 1, 0);
5980
+ add(import_format9.StandardParameter.EyeballX, "Gaze X", -1, 1, 0);
5981
+ add(import_format9.StandardParameter.EyeballY, "Gaze Y", -1, 1, 0);
5739
5982
  }
5740
- add(import_format8.StandardParameter.MouthOpen, "Mouth Open", 0, 1, 0);
5741
- add(import_format8.StandardParameter.MouthForm, "Mouth Form", -1, 1, 0);
5983
+ add(import_format9.StandardParameter.MouthOpen, "Mouth Open", 0, 1, 0);
5984
+ add(import_format9.StandardParameter.MouthForm, "Mouth Form", -1, 1, 0);
5742
5985
  if (roles.has("brow_L")) {
5743
- add(import_format8.StandardParameter.BrowLeftY, "Brow L Y", -1, 1, 0);
5744
- add(import_format8.StandardParameter.BrowLeftAngle, "Brow L Angle", -1, 1, 0);
5986
+ add(import_format9.StandardParameter.BrowLeftY, "Brow L Y", -1, 1, 0);
5987
+ add(import_format9.StandardParameter.BrowLeftAngle, "Brow L Angle", -1, 1, 0);
5745
5988
  }
5746
5989
  if (roles.has("brow_R")) {
5747
- add(import_format8.StandardParameter.BrowRightY, "Brow R Y", -1, 1, 0);
5748
- add(import_format8.StandardParameter.BrowRightAngle, "Brow R Angle", -1, 1, 0);
5990
+ add(import_format9.StandardParameter.BrowRightY, "Brow R Y", -1, 1, 0);
5991
+ add(import_format9.StandardParameter.BrowRightAngle, "Brow R Angle", -1, 1, 0);
5749
5992
  }
5750
5993
  if (roles.has("blush_L") || roles.has("blush_R")) {
5751
- add(import_format8.StandardParameter.Cheek, "Cheek", 0, 1, 0);
5994
+ add(import_format9.StandardParameter.Cheek, "Cheek", 0, 1, 0);
5752
5995
  }
5753
- add(import_format8.StandardParameter.Breath, "Breath", 0, 1, 0);
5996
+ add(import_format9.StandardParameter.Breath, "Breath", 0, 1, 0);
5754
5997
  if (roles.has("hair_front")) {
5755
- add(import_format8.StandardParameter.HairSwayX, "Hair Sway X", -SWAY_RANGE, SWAY_RANGE, 0);
5756
- add(import_format8.StandardParameter.HairSwayZ, "Hair Sway Z", -SWAY_RANGE, SWAY_RANGE, 0);
5998
+ add(import_format9.StandardParameter.HairSwayX, "Hair Sway X", -SWAY_RANGE, SWAY_RANGE, 0);
5999
+ add(import_format9.StandardParameter.HairSwayZ, "Hair Sway Z", -SWAY_RANGE, SWAY_RANGE, 0);
5757
6000
  }
5758
6001
  return out;
5759
6002
  }
@@ -5801,6 +6044,7 @@ function declareParameters(roles) {
5801
6044
  createLayerSetMeasurer,
5802
6045
  denseCoreOf,
5803
6046
  detectAlphaBbox,
6047
+ forearmPoseGeometry,
5804
6048
  foregroundSpan,
5805
6049
  generateIkiFromLayerSet,
5806
6050
  headHalfOf,