@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/README.md +17 -15
- package/dist/index.d.mts +78 -3
- package/dist/index.d.ts +78 -3
- package/dist/index.js +378 -115
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +376 -113
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -36,6 +36,8 @@ __export(index_exports, {
|
|
|
36
36
|
LIP_INSIDE_ROLES: () => LIP_INSIDE_ROLES,
|
|
37
37
|
LIP_ROLES: () => LIP_ROLES,
|
|
38
38
|
LayerGeometryError: () => LayerGeometryError,
|
|
39
|
+
PatchError: () => PatchError,
|
|
40
|
+
SHUT_BY: () => SHUT_BY,
|
|
39
41
|
SPECK_CORE_FRACTION: () => SPECK_CORE_FRACTION,
|
|
40
42
|
SetDeformerBindings: () => SetDeformerBindings,
|
|
41
43
|
SetDeformerParent: () => SetDeformerParent,
|
|
@@ -1560,8 +1562,8 @@ function foregroundSpan(mask, width, height, rowLo, rowHi) {
|
|
|
1560
1562
|
}
|
|
1561
1563
|
return { left, right };
|
|
1562
1564
|
}
|
|
1563
|
-
function headHalfOf(
|
|
1564
|
-
return (
|
|
1565
|
+
function headHalfOf(span2) {
|
|
1566
|
+
return (span2.right - span2.left + 1) / 2;
|
|
1565
1567
|
}
|
|
1566
1568
|
var DARK_SHARE = 0.55;
|
|
1567
1569
|
function jawRowsOf(rgba, canvasW, bbox, rowLeft, rowRight) {
|
|
@@ -1571,9 +1573,9 @@ function jawRowsOf(rgba, canvasW, bbox, rowLeft, rowRight) {
|
|
|
1571
1573
|
let widest = bbox.y;
|
|
1572
1574
|
let widestSpan = -1;
|
|
1573
1575
|
for (let y = bbox.y; y < bbox.y + bbox.h; y++) {
|
|
1574
|
-
const
|
|
1575
|
-
if (
|
|
1576
|
-
widestSpan =
|
|
1576
|
+
const span2 = rowRight[y] - rowLeft[y];
|
|
1577
|
+
if (span2 >= widestSpan) {
|
|
1578
|
+
widestSpan = span2;
|
|
1577
1579
|
widest = y;
|
|
1578
1580
|
}
|
|
1579
1581
|
for (let x = bbox.x; x < bbox.x + bbox.w; x++) {
|
|
@@ -1742,14 +1744,14 @@ function createLayerSetMeasurer(canvas) {
|
|
|
1742
1744
|
}
|
|
1743
1745
|
function finish() {
|
|
1744
1746
|
const eyeRow = eyeBandRowOf(layerInputs);
|
|
1745
|
-
const
|
|
1747
|
+
const span2 = foregroundSpan(
|
|
1746
1748
|
opaque,
|
|
1747
1749
|
canvasW,
|
|
1748
1750
|
canvasH,
|
|
1749
1751
|
eyeRow - HEAD_BAND,
|
|
1750
1752
|
eyeRow + HEAD_BAND
|
|
1751
1753
|
);
|
|
1752
|
-
const headHalfWidth =
|
|
1754
|
+
const headHalfWidth = span2.right > span2.left ? headHalfOf(span2) : void 0;
|
|
1753
1755
|
const headHalfWidthApplied = headHalfWidth !== void 0 && headHalfWidth > facePlateHalfOf(layerInputs);
|
|
1754
1756
|
let headEdges;
|
|
1755
1757
|
if (headHalfWidthApplied) {
|
|
@@ -1777,9 +1779,9 @@ function createLayerSetMeasurer(canvas) {
|
|
|
1777
1779
|
const centre = iris.bbox.x + iris.bbox.w / 2;
|
|
1778
1780
|
const otherX = other.bbox.x + other.bbox.w / 2 - half;
|
|
1779
1781
|
const c = side < 0 ? Math.ceil(centre) - 1 : Math.floor(centre);
|
|
1780
|
-
const
|
|
1781
|
-
if (
|
|
1782
|
-
const minRun = STRAND_MIN_RUN_FRACTION * (
|
|
1782
|
+
const span3 = rowSpansByRole.find((s) => s.role === iris.role);
|
|
1783
|
+
if (span3.rowRight[r] < span3.rowLeft[r]) return void 0;
|
|
1784
|
+
const minRun = STRAND_MIN_RUN_FRACTION * (span3.rowRight[r] + 1 - span3.rowLeft[r]);
|
|
1783
1785
|
const strand = new Uint8Array(canvasW);
|
|
1784
1786
|
const runs = r >= hairTop && r < hairTop + hairRuns.length ? hairRuns[r - hairTop] : [];
|
|
1785
1787
|
for (let k = 0; k < runs.length; k += 2) {
|
|
@@ -1804,8 +1806,8 @@ function createLayerSetMeasurer(canvas) {
|
|
|
1804
1806
|
while (strandAt(x)) x += side;
|
|
1805
1807
|
return {
|
|
1806
1808
|
y: canvasH / 2 - (r + 0.5),
|
|
1807
|
-
irisOuter: (side < 0 ?
|
|
1808
|
-
irisInner: (side < 0 ?
|
|
1809
|
+
irisOuter: (side < 0 ? span3.rowLeft[r] : span3.rowRight[r] + 1) - half,
|
|
1810
|
+
irisInner: (side < 0 ? span3.rowRight[r] + 1 : span3.rowLeft[r]) - half,
|
|
1809
1811
|
runOuter: outerBoundary(x - side),
|
|
1810
1812
|
runFace
|
|
1811
1813
|
};
|
|
@@ -2209,6 +2211,12 @@ var DEFAULT_TURN_TARGETS = Object.freeze({
|
|
|
2209
2211
|
farEyeRatio: round2(TURN.eyeFarScale / TURN.eyeNearScale),
|
|
2210
2212
|
silhouetteRatio: 1
|
|
2211
2213
|
});
|
|
2214
|
+
var PatchError = class extends Error {
|
|
2215
|
+
constructor(message) {
|
|
2216
|
+
super(message);
|
|
2217
|
+
this.name = "PatchError";
|
|
2218
|
+
}
|
|
2219
|
+
};
|
|
2212
2220
|
|
|
2213
2221
|
// src/auto-rig/arms.ts
|
|
2214
2222
|
var import_format5 = require("@ikijs/format");
|
|
@@ -2834,7 +2842,7 @@ var ARM_IDS = {
|
|
|
2834
2842
|
};
|
|
2835
2843
|
function endPivot(layer, end) {
|
|
2836
2844
|
const { bbox, canvasW, canvasH, rowRuns } = layer;
|
|
2837
|
-
const
|
|
2845
|
+
const span2 = runSpan(layer);
|
|
2838
2846
|
const from = (k) => end === "top" ? k : bbox.h - 1 - k;
|
|
2839
2847
|
const painted = rowRuns?.flatMap((runs, k) => runs.length > 0 ? [k] : []) ?? [];
|
|
2840
2848
|
const firstK = end === "top" ? painted[0] ?? 0 : painted.at(-1) ?? bbox.h - 1;
|
|
@@ -2842,13 +2850,13 @@ function endPivot(layer, end) {
|
|
|
2842
2850
|
const hi = Math.max(lo, Math.floor(CAP_ROWS[1] * bbox.h));
|
|
2843
2851
|
const widths = [];
|
|
2844
2852
|
for (let k = lo; k <= hi; k++) {
|
|
2845
|
-
const [s2, e2] =
|
|
2853
|
+
const [s2, e2] = span2(from(k));
|
|
2846
2854
|
widths.push(e2 - s2);
|
|
2847
2855
|
}
|
|
2848
2856
|
widths.sort((p, q) => p - q);
|
|
2849
2857
|
const radius = widths[widths.length >> 1] / 2;
|
|
2850
2858
|
const ks = end === "top" ? firstK + radius : firstK - radius;
|
|
2851
|
-
const [s, e] =
|
|
2859
|
+
const [s, e] = span2(Math.round(ks));
|
|
2852
2860
|
return {
|
|
2853
2861
|
point: {
|
|
2854
2862
|
x: roundTo((s + e) / 2 - canvasW / 2, 0.01),
|
|
@@ -2873,9 +2881,9 @@ function runSpan(layer) {
|
|
|
2873
2881
|
function armGeometry(layer, bodyAxisX) {
|
|
2874
2882
|
const { bbox, canvasW, canvasH, rowRuns } = layer;
|
|
2875
2883
|
const b = boxOfLayer(layer);
|
|
2876
|
-
const
|
|
2884
|
+
const span2 = runSpan(layer);
|
|
2877
2885
|
const centreX = (k) => {
|
|
2878
|
-
const [s2, e2] =
|
|
2886
|
+
const [s2, e2] = span2(k);
|
|
2879
2887
|
return (s2 + e2) / 2 - canvasW / 2;
|
|
2880
2888
|
};
|
|
2881
2889
|
const rowY = (k) => canvasH / 2 - (bbox.y + k + 0.5);
|
|
@@ -2889,7 +2897,7 @@ function armGeometry(layer, bodyAxisX) {
|
|
|
2889
2897
|
);
|
|
2890
2898
|
}
|
|
2891
2899
|
const elbow = { x: roundTo(centreX(ke), 0.01), y: roundTo(rowY(ke), 0.01) };
|
|
2892
|
-
const [s, e] =
|
|
2900
|
+
const [s, e] = span2(ke);
|
|
2893
2901
|
const capRadius = Math.min(
|
|
2894
2902
|
(e - s) / 2 + 1,
|
|
2895
2903
|
elbow.x - b.x0,
|
|
@@ -2899,7 +2907,7 @@ function armGeometry(layer, bodyAxisX) {
|
|
|
2899
2907
|
const inside = (x, y) => {
|
|
2900
2908
|
const k = Math.floor(y) - bbox.y;
|
|
2901
2909
|
if (k < 0 || k >= bbox.h) return false;
|
|
2902
|
-
const [rs, re] =
|
|
2910
|
+
const [rs, re] = span2(k);
|
|
2903
2911
|
return rs < x && x < re;
|
|
2904
2912
|
};
|
|
2905
2913
|
const capRays = Array.from({ length: CAP_SEGMENTS + 1 }, (_, i) => {
|
|
@@ -3106,13 +3114,24 @@ function forearmPoseDeformer(role, arm) {
|
|
|
3106
3114
|
}
|
|
3107
3115
|
|
|
3108
3116
|
// src/auto-rig/mouth.ts
|
|
3109
|
-
var
|
|
3117
|
+
var import_format8 = require("@ikijs/format");
|
|
3110
3118
|
|
|
3111
3119
|
// src/auto-rig/roles.ts
|
|
3120
|
+
var import_format7 = require("@ikijs/format");
|
|
3112
3121
|
var LIP_ROLES = ["mouth_inner", "lip_lower", "lip_upper"];
|
|
3113
3122
|
var isLipRole = (role) => LIP_ROLES.includes(role);
|
|
3114
3123
|
var LIP_INSIDE_ROLES = ["mouth_tongue", "mouth_teeth"];
|
|
3115
3124
|
var isLipInsideRole = (role) => LIP_INSIDE_ROLES.includes(role);
|
|
3125
|
+
var SHUT_BY = new Map([
|
|
3126
|
+
["eye_L", import_format7.StandardParameter.EyeOpenLeft],
|
|
3127
|
+
["lash_lower_L", import_format7.StandardParameter.EyeOpenLeft],
|
|
3128
|
+
["eye_R", import_format7.StandardParameter.EyeOpenRight],
|
|
3129
|
+
["lash_lower_R", import_format7.StandardParameter.EyeOpenRight],
|
|
3130
|
+
...[...LIP_ROLES, ...LIP_INSIDE_ROLES].map((id) => [
|
|
3131
|
+
id,
|
|
3132
|
+
import_format7.StandardParameter.MouthOpen
|
|
3133
|
+
])
|
|
3134
|
+
]);
|
|
3116
3135
|
var ROLE_TABLE = [
|
|
3117
3136
|
{ role: "hair_back", family: "hair_back" },
|
|
3118
3137
|
{ role: "body", family: "body" },
|
|
@@ -3457,7 +3476,7 @@ function columnOfKnot(knot, opening) {
|
|
|
3457
3476
|
function mouthFoldWarp(role, mesh, xs, box, opening) {
|
|
3458
3477
|
const fold = mouthFold(role, opening);
|
|
3459
3478
|
return localWarp(
|
|
3460
|
-
|
|
3479
|
+
import_format8.StandardParameter.MouthOpen,
|
|
3461
3480
|
mesh,
|
|
3462
3481
|
box,
|
|
3463
3482
|
[0, 1],
|
|
@@ -3466,13 +3485,13 @@ function mouthFoldWarp(role, mesh, xs, box, opening) {
|
|
|
3466
3485
|
}
|
|
3467
3486
|
function mouthRestShift(byRole) {
|
|
3468
3487
|
const rig = buildMouthRig(byRole);
|
|
3469
|
-
const
|
|
3488
|
+
const fields2 = /* @__PURE__ */ new Map();
|
|
3470
3489
|
for (const role of ["lip_upper", "lip_lower"]) {
|
|
3471
3490
|
const box = boxOfLayer(byRole.get(role));
|
|
3472
3491
|
const { mesh, xs } = mouthMesh(box, rig.knots);
|
|
3473
3492
|
const warp = mouthFoldWarp(role, mesh, xs, box, rig.opening);
|
|
3474
3493
|
const offsets = warp.keyforms[0].offsets;
|
|
3475
|
-
|
|
3494
|
+
fields2.set(role, {
|
|
3476
3495
|
box,
|
|
3477
3496
|
xs,
|
|
3478
3497
|
rows: offsets.length / 2 / xs.length - 1,
|
|
@@ -3481,7 +3500,7 @@ function mouthRestShift(byRole) {
|
|
|
3481
3500
|
}
|
|
3482
3501
|
const { canvasW, canvasH } = byRole.get("lip_upper");
|
|
3483
3502
|
return (role, col, row) => {
|
|
3484
|
-
const { box, xs, rows, dy } =
|
|
3503
|
+
const { box, xs, rows, dy } = fields2.get(role);
|
|
3485
3504
|
const x = col + 0.5 - canvasW / 2;
|
|
3486
3505
|
const y = canvasH / 2 - (row + 0.5);
|
|
3487
3506
|
if (x < box.x0 || x > box.x1 || y < box.y0 || y > box.y1) return void 0;
|
|
@@ -3570,32 +3589,32 @@ function mouthAnchor(byRole) {
|
|
|
3570
3589
|
}
|
|
3571
3590
|
|
|
3572
3591
|
// src/auto-rig/generate.ts
|
|
3573
|
-
var
|
|
3592
|
+
var import_format12 = require("@ikijs/format");
|
|
3574
3593
|
|
|
3575
3594
|
// src/auto-rig/animations.ts
|
|
3576
|
-
var
|
|
3595
|
+
var import_format9 = require("@ikijs/format");
|
|
3577
3596
|
function browsY(y) {
|
|
3578
3597
|
return [
|
|
3579
|
-
{ parameter:
|
|
3580
|
-
{ parameter:
|
|
3598
|
+
{ parameter: import_format9.StandardParameter.BrowLeftY, value: y, blend: "add" },
|
|
3599
|
+
{ parameter: import_format9.StandardParameter.BrowRightY, value: y, blend: "add" }
|
|
3581
3600
|
];
|
|
3582
3601
|
}
|
|
3583
3602
|
function browsTilt(innerDown) {
|
|
3584
3603
|
return [
|
|
3585
|
-
{ parameter:
|
|
3586
|
-
{ parameter:
|
|
3604
|
+
{ parameter: import_format9.StandardParameter.BrowLeftAngle, value: innerDown, blend: "add" },
|
|
3605
|
+
{ parameter: import_format9.StandardParameter.BrowRightAngle, value: -innerDown, blend: "add" }
|
|
3587
3606
|
];
|
|
3588
3607
|
}
|
|
3589
3608
|
function cheek(value) {
|
|
3590
|
-
return { parameter:
|
|
3609
|
+
return { parameter: import_format9.StandardParameter.Cheek, value, blend: "add" };
|
|
3591
3610
|
}
|
|
3592
|
-
var BROWS = [
|
|
3611
|
+
var BROWS = [import_format9.StandardParameter.BrowLeftY, import_format9.StandardParameter.BrowRightY, import_format9.StandardParameter.BrowLeftAngle, import_format9.StandardParameter.BrowRightAngle];
|
|
3593
3612
|
var EXPRESSIONS = [
|
|
3594
3613
|
{
|
|
3595
3614
|
id: "smile",
|
|
3596
3615
|
description: "Smiling and pleased: warm, friendly, content. For greetings, thanks, agreement and gentle happiness.",
|
|
3597
3616
|
parameters: [
|
|
3598
|
-
{ parameter:
|
|
3617
|
+
{ parameter: import_format9.StandardParameter.MouthForm, value: 1, blend: "add" },
|
|
3599
3618
|
...browsY(0.25),
|
|
3600
3619
|
cheek(0.4)
|
|
3601
3620
|
]
|
|
@@ -3604,10 +3623,10 @@ var EXPRESSIONS = [
|
|
|
3604
3623
|
id: "laugh",
|
|
3605
3624
|
description: "Laughing, eyes shut and mouth open: delighted, amused. For jokes, playfulness and big joy.",
|
|
3606
3625
|
parameters: [
|
|
3607
|
-
{ parameter:
|
|
3608
|
-
{ parameter:
|
|
3609
|
-
{ parameter:
|
|
3610
|
-
{ parameter:
|
|
3626
|
+
{ parameter: import_format9.StandardParameter.EyeOpenLeft, value: 0, blend: "multiply" },
|
|
3627
|
+
{ parameter: import_format9.StandardParameter.EyeOpenRight, value: 0, blend: "multiply" },
|
|
3628
|
+
{ parameter: import_format9.StandardParameter.MouthForm, value: 1, blend: "add" },
|
|
3629
|
+
{ parameter: import_format9.StandardParameter.MouthOpen, value: 0.8, blend: "overwrite" },
|
|
3611
3630
|
...browsY(0.4),
|
|
3612
3631
|
cheek(0.65)
|
|
3613
3632
|
]
|
|
@@ -3619,7 +3638,7 @@ var EXPRESSIONS = [
|
|
|
3619
3638
|
parameters: [
|
|
3620
3639
|
...browsY(-0.5),
|
|
3621
3640
|
...browsTilt(0.8),
|
|
3622
|
-
{ parameter:
|
|
3641
|
+
{ parameter: import_format9.StandardParameter.MouthForm, value: -0.9, blend: "add" }
|
|
3623
3642
|
]
|
|
3624
3643
|
},
|
|
3625
3644
|
{
|
|
@@ -3629,7 +3648,7 @@ var EXPRESSIONS = [
|
|
|
3629
3648
|
parameters: [
|
|
3630
3649
|
...browsY(0.35),
|
|
3631
3650
|
...browsTilt(-0.8),
|
|
3632
|
-
{ parameter:
|
|
3651
|
+
{ parameter: import_format9.StandardParameter.MouthForm, value: -0.8, blend: "add" }
|
|
3633
3652
|
]
|
|
3634
3653
|
},
|
|
3635
3654
|
{
|
|
@@ -3637,18 +3656,18 @@ var EXPRESSIONS = [
|
|
|
3637
3656
|
description: "Surprised, mouth dropped open: startled, amazed. For shock, sudden news or disbelief.",
|
|
3638
3657
|
parameters: [
|
|
3639
3658
|
...browsY(0.8),
|
|
3640
|
-
{ parameter:
|
|
3659
|
+
{ parameter: import_format9.StandardParameter.MouthOpen, value: 0.9, blend: "overwrite" }
|
|
3641
3660
|
]
|
|
3642
3661
|
},
|
|
3643
3662
|
{
|
|
3644
3663
|
id: "shy",
|
|
3645
3664
|
description: "Shy or embarrassed: bashful, flustered. For being praised, teased or caught off guard.",
|
|
3646
|
-
needs: [
|
|
3665
|
+
needs: [import_format9.StandardParameter.Cheek],
|
|
3647
3666
|
parameters: [
|
|
3648
3667
|
cheek(1),
|
|
3649
3668
|
// Gaze down.
|
|
3650
|
-
{ parameter:
|
|
3651
|
-
{ parameter:
|
|
3669
|
+
{ parameter: import_format9.StandardParameter.EyeballY, value: -0.65, blend: "add" },
|
|
3670
|
+
{ parameter: import_format9.StandardParameter.MouthForm, value: 0.4, blend: "add" },
|
|
3652
3671
|
...browsTilt(-0.25)
|
|
3653
3672
|
]
|
|
3654
3673
|
}
|
|
@@ -3668,7 +3687,7 @@ var HEAD_MOTIONS = {
|
|
|
3668
3687
|
duration: 1,
|
|
3669
3688
|
curves: [
|
|
3670
3689
|
{
|
|
3671
|
-
parameter:
|
|
3690
|
+
parameter: import_format9.StandardParameter.AngleY,
|
|
3672
3691
|
keys: [
|
|
3673
3692
|
[0, 0],
|
|
3674
3693
|
[0.3, -18],
|
|
@@ -3689,7 +3708,7 @@ var HEAD_MOTIONS = {
|
|
|
3689
3708
|
fadeIn: 0.15,
|
|
3690
3709
|
curves: [
|
|
3691
3710
|
{
|
|
3692
|
-
parameter:
|
|
3711
|
+
parameter: import_format9.StandardParameter.AngleX,
|
|
3693
3712
|
keys: [
|
|
3694
3713
|
[0, 0],
|
|
3695
3714
|
[0.2, -18],
|
|
@@ -3708,7 +3727,7 @@ var HEAD_MOTIONS = {
|
|
|
3708
3727
|
duration: 1.4,
|
|
3709
3728
|
curves: [
|
|
3710
3729
|
{
|
|
3711
|
-
parameter:
|
|
3730
|
+
parameter: import_format9.StandardParameter.AngleZ,
|
|
3712
3731
|
keys: [
|
|
3713
3732
|
[0, 0],
|
|
3714
3733
|
[0.35, 20],
|
|
@@ -3729,7 +3748,7 @@ var WAVE = {
|
|
|
3729
3748
|
fadeOut: 0.15,
|
|
3730
3749
|
curves: [
|
|
3731
3750
|
{
|
|
3732
|
-
parameter:
|
|
3751
|
+
parameter: import_format9.StandardParameter.ArmPoseRight,
|
|
3733
3752
|
interpolation: "linear",
|
|
3734
3753
|
keys: [
|
|
3735
3754
|
[0, 0],
|
|
@@ -3739,7 +3758,7 @@ var WAVE = {
|
|
|
3739
3758
|
]
|
|
3740
3759
|
},
|
|
3741
3760
|
{
|
|
3742
|
-
parameter:
|
|
3761
|
+
parameter: import_format9.StandardParameter.ArmRight,
|
|
3743
3762
|
keys: [
|
|
3744
3763
|
[0, 0],
|
|
3745
3764
|
[0.4, 10],
|
|
@@ -3748,7 +3767,7 @@ var WAVE = {
|
|
|
3748
3767
|
]
|
|
3749
3768
|
},
|
|
3750
3769
|
{
|
|
3751
|
-
parameter:
|
|
3770
|
+
parameter: import_format9.StandardParameter.ArmPoseAngleRight,
|
|
3752
3771
|
keys: [
|
|
3753
3772
|
[0, 0],
|
|
3754
3773
|
[0.5, 0],
|
|
@@ -3764,7 +3783,7 @@ var WAVE = {
|
|
|
3764
3783
|
]
|
|
3765
3784
|
};
|
|
3766
3785
|
function defaultMotions(declared) {
|
|
3767
|
-
const waves = [
|
|
3786
|
+
const waves = [import_format9.StandardParameter.ArmRight, import_format9.StandardParameter.ArmPoseRight, import_format9.StandardParameter.ArmPoseAngleRight].every(
|
|
3768
3787
|
(id) => declared.has(id)
|
|
3769
3788
|
);
|
|
3770
3789
|
return waves ? { ...HEAD_MOTIONS, ...WAVE } : HEAD_MOTIONS;
|
|
@@ -4000,7 +4019,7 @@ function checkStrandEdges(strand, irises, hair) {
|
|
|
4000
4019
|
}
|
|
4001
4020
|
|
|
4002
4021
|
// src/auto-rig/context.ts
|
|
4003
|
-
var
|
|
4022
|
+
var import_format10 = require("@ikijs/format");
|
|
4004
4023
|
|
|
4005
4024
|
// src/auto-rig/head.ts
|
|
4006
4025
|
function outerEdge(runs, axisX, side) {
|
|
@@ -4109,14 +4128,14 @@ function buildHeadFrame(layers, opts) {
|
|
|
4109
4128
|
const rawRows = raw;
|
|
4110
4129
|
const earless = (chin) => {
|
|
4111
4130
|
const rowOf = (y) => Math.round(canvasH / 2 - y - faceLayer.bbox.y - 0.5);
|
|
4112
|
-
const
|
|
4131
|
+
const span2 = Math.max(1, eyeY - chin);
|
|
4113
4132
|
const found = findEars(
|
|
4114
4133
|
rawRows,
|
|
4115
4134
|
wMax,
|
|
4116
4135
|
Math.round(0.2 * rawRows.length),
|
|
4117
4136
|
Math.min(rawRows.length - 1, rowOf(chin)),
|
|
4118
|
-
Math.round(0.1 *
|
|
4119
|
-
Math.round(0.8 *
|
|
4137
|
+
Math.round(0.1 * span2),
|
|
4138
|
+
Math.round(0.8 * span2)
|
|
4120
4139
|
);
|
|
4121
4140
|
if (found === void 0) return profile;
|
|
4122
4141
|
const { top, bottom } = found;
|
|
@@ -4150,16 +4169,16 @@ function buildHeadFrame(layers, opts) {
|
|
|
4150
4169
|
}
|
|
4151
4170
|
}
|
|
4152
4171
|
if (neckRow >= 0 && n - neckRow >= 0.12 * n) {
|
|
4153
|
-
let
|
|
4172
|
+
let span2 = 0;
|
|
4154
4173
|
let waist = Infinity;
|
|
4155
4174
|
for (let r = neckRow; r < n; r++) {
|
|
4156
|
-
|
|
4175
|
+
span2 = Math.max(span2, profile[r]);
|
|
4157
4176
|
if (r < n - tail) waist = Math.min(waist, profile[r]);
|
|
4158
4177
|
}
|
|
4159
4178
|
neck = {
|
|
4160
4179
|
topY: rowY(neckRow),
|
|
4161
4180
|
half: profile[neckRow],
|
|
4162
|
-
span,
|
|
4181
|
+
span: span2,
|
|
4163
4182
|
waist: Math.min(waist, profile[neckRow])
|
|
4164
4183
|
};
|
|
4165
4184
|
}
|
|
@@ -4359,22 +4378,22 @@ function earField(m) {
|
|
|
4359
4378
|
const dy = face(x, y, 0, ay)[1];
|
|
4360
4379
|
const d = Math.abs(x - f.axisX);
|
|
4361
4380
|
const attach = ears.attachAt(y);
|
|
4362
|
-
const
|
|
4381
|
+
const span2 = Math.max(1, ears.outer - attach);
|
|
4363
4382
|
if (sideOf(m, x, s) === "far") {
|
|
4364
4383
|
const rim2 = TURN.earFar * m.face;
|
|
4365
4384
|
const root2 = earRoot(m, face, y, s);
|
|
4366
4385
|
const lead = Math.max(
|
|
4367
4386
|
0,
|
|
4368
|
-
Math.min((1 - m.earFarScale) *
|
|
4387
|
+
Math.min((1 - m.earFarScale) * span2, root2 - rim2)
|
|
4369
4388
|
);
|
|
4370
|
-
let along = rim2 + lead * (ears.outer - d) /
|
|
4389
|
+
let along = rim2 + lead * (ears.outer - d) / span2;
|
|
4371
4390
|
if (d < attach) along = Math.min(along, s * face(x, y, 30 * s, 0)[0]);
|
|
4372
4391
|
return [s * a * along, dy];
|
|
4373
4392
|
}
|
|
4374
4393
|
if (d <= attach) return [face(x, y, ax, 0)[0], dy];
|
|
4375
4394
|
const root = face(f.axisX + Math.sign(x - f.axisX) * attach, y, ax, 0)[0];
|
|
4376
4395
|
const rim = s * a * TURN.earNear * m.face;
|
|
4377
|
-
const t = Math.min(1, (d - attach) /
|
|
4396
|
+
const t = Math.min(1, (d - attach) / span2);
|
|
4378
4397
|
return [root + (rim - root) * t, dy];
|
|
4379
4398
|
};
|
|
4380
4399
|
}
|
|
@@ -5130,7 +5149,7 @@ function renderedLander(turn, parts, grids, from = /* @__PURE__ */ new Map()) {
|
|
|
5130
5149
|
const family = roleSpec(role).family;
|
|
5131
5150
|
const part = parts.find((p) => p.id === role);
|
|
5132
5151
|
const g = grids.get(family);
|
|
5133
|
-
const warp = part?.warps?.find((w) => w.parameter ===
|
|
5152
|
+
const warp = part?.warps?.find((w) => w.parameter === import_format10.StandardParameter.AngleX);
|
|
5134
5153
|
if (part === void 0 || part.mesh === void 0 || !g && !warp) {
|
|
5135
5154
|
return x + field(role)(x, y, ax, 0)[0];
|
|
5136
5155
|
}
|
|
@@ -5269,11 +5288,11 @@ function buildFaceMesh(frame, b, head, neckCells) {
|
|
|
5269
5288
|
const indices = [];
|
|
5270
5289
|
const neck = frame.neck;
|
|
5271
5290
|
if (neck !== void 0) {
|
|
5272
|
-
const
|
|
5273
|
-
const nc = cellsFor(2 *
|
|
5291
|
+
const span2 = neck.span + pad;
|
|
5292
|
+
const nc = cellsFor(2 * span2, neckCells.px, neckCells.min, neckCells.max);
|
|
5274
5293
|
const xs2 = columns(
|
|
5275
|
-
Math.max(b.x0, frame.axisX -
|
|
5276
|
-
Math.min(b.x1, frame.axisX +
|
|
5294
|
+
Math.max(b.x0, frame.axisX - span2),
|
|
5295
|
+
Math.min(b.x1, frame.axisX + span2),
|
|
5277
5296
|
nc
|
|
5278
5297
|
);
|
|
5279
5298
|
const sampleBelow = (x) => Math.max(
|
|
@@ -5409,6 +5428,9 @@ function buildFaceMesh(frame, b, head, neckCells) {
|
|
|
5409
5428
|
return { mesh: { vertices, uvs, indices }, region, headStart };
|
|
5410
5429
|
}
|
|
5411
5430
|
|
|
5431
|
+
// src/auto-rig/patches.ts
|
|
5432
|
+
var import_format11 = require("@ikijs/format");
|
|
5433
|
+
|
|
5412
5434
|
// src/auto-rig/solve.ts
|
|
5413
5435
|
var RANGES = {
|
|
5414
5436
|
// [lo, hi, lo exclusive]
|
|
@@ -5839,6 +5861,235 @@ function buildTurn(frame, landmarks, q) {
|
|
|
5839
5861
|
};
|
|
5840
5862
|
}
|
|
5841
5863
|
|
|
5864
|
+
// src/auto-rig/patches.ts
|
|
5865
|
+
var OP_KEYS = ["target", "at", "region", "by", "falloff", "why"];
|
|
5866
|
+
var REGION_KEYS = ["role", "x", "y"];
|
|
5867
|
+
var BY_KEYS = ["dx", "dy"];
|
|
5868
|
+
var ROLLS = /* @__PURE__ */ new Set([import_format11.StandardParameter.AngleZ, import_format11.StandardParameter.BodyAngleZ]);
|
|
5869
|
+
var REST_IS_ART = "rest is the drawn art, which no patch changes (change it with the layout or by regenerating the layer)";
|
|
5870
|
+
function applyPatches(patches, ctx) {
|
|
5871
|
+
if (!Array.isArray(patches)) {
|
|
5872
|
+
throw new PatchError(
|
|
5873
|
+
`patches must be an array, got ${patches === null ? "null" : typeof patches}`
|
|
5874
|
+
);
|
|
5875
|
+
}
|
|
5876
|
+
const sums = /* @__PURE__ */ new Map();
|
|
5877
|
+
const reports = patches.map((op, i) => replay(op, i, ctx, sums));
|
|
5878
|
+
for (const [offsets, s] of sums) {
|
|
5879
|
+
s.terms.forEach((t, k) => {
|
|
5880
|
+
if (t.length === 0) return;
|
|
5881
|
+
const d = t.sort((a, b) => a - b).reduce((a, b) => a + b, 0);
|
|
5882
|
+
offsets[k] = roundTo(offsets[k] + d / s.scale[k % 2], s.step);
|
|
5883
|
+
});
|
|
5884
|
+
}
|
|
5885
|
+
return reports;
|
|
5886
|
+
}
|
|
5887
|
+
function replay(op, i, ctx, sums) {
|
|
5888
|
+
const name = `patches[${i}]`;
|
|
5889
|
+
const o = fields(name, op, OP_KEYS);
|
|
5890
|
+
const target = text(`${name}.target`, o.target);
|
|
5891
|
+
const at = numbers(`${name}.at`, o.at);
|
|
5892
|
+
const region = fields(`${name}.region`, o.region, REGION_KEYS);
|
|
5893
|
+
const role = text(`${name}.region.role`, region.role);
|
|
5894
|
+
const x = span(`${name}.region.x`, region.x);
|
|
5895
|
+
const y = span(`${name}.region.y`, region.y);
|
|
5896
|
+
const by = fields(`${name}.by`, o.by, BY_KEYS);
|
|
5897
|
+
const dx = finite2(`${name}.by.dx`, by.dx);
|
|
5898
|
+
const dy = finite2(`${name}.by.dy`, by.dy);
|
|
5899
|
+
const falloff = o.falloff === void 0 ? 0 : finite2(`${name}.falloff`, o.falloff, 0);
|
|
5900
|
+
if (o.why !== void 0) text(`${name}.why`, o.why);
|
|
5901
|
+
const box = ctx.boxOf(role);
|
|
5902
|
+
if (box === void 0) {
|
|
5903
|
+
const roles = [...new Set(ctx.parts.map((p) => roleOfPart(p.id)))].filter(
|
|
5904
|
+
(r) => ctx.boxOf(r) !== void 0
|
|
5905
|
+
);
|
|
5906
|
+
throw new PatchError(
|
|
5907
|
+
`${name}.region.role "${role}" is not a layer of this set (roles: ${roles.join(", ")})`
|
|
5908
|
+
);
|
|
5909
|
+
}
|
|
5910
|
+
const stop = resolveStop(name, target, at, ctx);
|
|
5911
|
+
const { points } = stop;
|
|
5912
|
+
const weights = regionWeights(points, box, x, y, falloff * ctx.faceWidth);
|
|
5913
|
+
const hit = weights.flatMap((w, k) => w > 0 ? [k] : []);
|
|
5914
|
+
if (hit.length === 0) {
|
|
5915
|
+
const fx = points.map(([px]) => (px - box.x0) / bw(box));
|
|
5916
|
+
const fy = points.map(([, py]) => (box.y1 - py) / bh(box));
|
|
5917
|
+
const range = (v) => `[${roundTo(Math.min(...v), 0.01)}, ${roundTo(Math.max(...v), 0.01)}]`;
|
|
5918
|
+
throw new PatchError(
|
|
5919
|
+
`${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`
|
|
5920
|
+
);
|
|
5921
|
+
}
|
|
5922
|
+
let sum = sums.get(stop.offsets);
|
|
5923
|
+
if (sum === void 0) {
|
|
5924
|
+
sum = {
|
|
5925
|
+
terms: stop.offsets.map(() => []),
|
|
5926
|
+
scale: stop.scale,
|
|
5927
|
+
step: stop.step
|
|
5928
|
+
};
|
|
5929
|
+
sums.set(stop.offsets, sum);
|
|
5930
|
+
}
|
|
5931
|
+
const ddx = dx * ctx.faceWidth;
|
|
5932
|
+
const ddy = -dy * ctx.faceWidth;
|
|
5933
|
+
for (const k of hit) {
|
|
5934
|
+
sum.terms[2 * k].push(ddx * weights[k]);
|
|
5935
|
+
sum.terms[2 * k + 1].push(ddy * weights[k]);
|
|
5936
|
+
}
|
|
5937
|
+
const maxW = Math.max(...hit.map((k) => weights[k]));
|
|
5938
|
+
const report = {
|
|
5939
|
+
index: i,
|
|
5940
|
+
target,
|
|
5941
|
+
at,
|
|
5942
|
+
moved: hit.length,
|
|
5943
|
+
of: points.length,
|
|
5944
|
+
maxPx: roundTo(maxW * Math.hypot(dx, dy) * ctx.faceWidth, 0.1)
|
|
5945
|
+
};
|
|
5946
|
+
if (stop.stride !== void 0) {
|
|
5947
|
+
const { stride } = stop;
|
|
5948
|
+
const cols = hit.map((k) => k % stride);
|
|
5949
|
+
const rows = hit.map((k) => Math.floor(k / stride));
|
|
5950
|
+
report.cols = [Math.min(...cols), Math.max(...cols)];
|
|
5951
|
+
report.rows = [Math.min(...rows), Math.max(...rows)];
|
|
5952
|
+
}
|
|
5953
|
+
return report;
|
|
5954
|
+
}
|
|
5955
|
+
function resolveStop(name, target, at, ctx) {
|
|
5956
|
+
const grid = ctx.grids.get(target);
|
|
5957
|
+
if (grid !== void 0) {
|
|
5958
|
+
const l = grid.lattice.points;
|
|
5959
|
+
const points = [];
|
|
5960
|
+
for (let k = 0; k < l.length; k += 2) points.push([l[k], l[k + 1]]);
|
|
5961
|
+
return {
|
|
5962
|
+
offsets: gridStop(name, at, target, grid.keyforms),
|
|
5963
|
+
points,
|
|
5964
|
+
scale: [1, 1],
|
|
5965
|
+
step: 0.1,
|
|
5966
|
+
stride: grid.lattice.cols + 1
|
|
5967
|
+
};
|
|
5968
|
+
}
|
|
5969
|
+
const part = ctx.parts.find((p) => p.id === target);
|
|
5970
|
+
const b = ctx.boxOf(target);
|
|
5971
|
+
if (part?.mesh === void 0 || part.warps === void 0 || b === void 0) {
|
|
5972
|
+
const parts = ctx.parts.filter(
|
|
5973
|
+
(p) => p.mesh !== void 0 && p.warps !== void 0 && ctx.boxOf(p.id) !== void 0
|
|
5974
|
+
);
|
|
5975
|
+
throw new PatchError(
|
|
5976
|
+
`${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`
|
|
5977
|
+
);
|
|
5978
|
+
}
|
|
5979
|
+
return {
|
|
5980
|
+
offsets: partStop(name, at, part, part.warps, ctx),
|
|
5981
|
+
points: meshPoints(part.mesh, b),
|
|
5982
|
+
scale: [bw(b), bh(b)],
|
|
5983
|
+
step: 1e-4
|
|
5984
|
+
};
|
|
5985
|
+
}
|
|
5986
|
+
function gridStop(name, at, id, keyforms) {
|
|
5987
|
+
const i = X_STOPS.indexOf(at[import_format11.StandardParameter.AngleX]);
|
|
5988
|
+
const j = Y_STOPS.indexOf(at[import_format11.StandardParameter.AngleY]);
|
|
5989
|
+
if (Object.keys(at).length !== 2 || i < 0 || j < 0) {
|
|
5990
|
+
throw new PatchError(
|
|
5991
|
+
`${name}.at must name ${import_format11.StandardParameter.AngleX} in [${X_STOPS.join(", ")}] and ${import_format11.StandardParameter.AngleY} in [${Y_STOPS.join(", ")}] for the grid ${id}, got ${JSON.stringify(at)}`
|
|
5992
|
+
);
|
|
5993
|
+
}
|
|
5994
|
+
if (X_STOPS[i] === 0 && Y_STOPS[j] === 0) {
|
|
5995
|
+
throw new PatchError(
|
|
5996
|
+
`${name}.at ${import_format11.StandardParameter.AngleX}=0 ${import_format11.StandardParameter.AngleY}=0 is ${id}'s rest stop: ${REST_IS_ART}; patch a stop with ${import_format11.StandardParameter.AngleX} or ${import_format11.StandardParameter.AngleY} at \xB130 instead`
|
|
5997
|
+
);
|
|
5998
|
+
}
|
|
5999
|
+
return keyforms[j * X_STOPS.length + i];
|
|
6000
|
+
}
|
|
6001
|
+
function partStop(name, at, part, warps, ctx) {
|
|
6002
|
+
const keys = Object.keys(at);
|
|
6003
|
+
const [param] = keys;
|
|
6004
|
+
const value = at[param];
|
|
6005
|
+
const keyform = keys.length === 1 ? warps.filter((w) => w.parameter === param).flatMap((w) => w.keyforms).find((k) => k.value === value) : void 0;
|
|
6006
|
+
if (keyform === void 0) {
|
|
6007
|
+
throw new PatchError(
|
|
6008
|
+
`${name}.at must name one parameter at one of ${part.id}'s warp stops (${listStops(warps, () => true)}), got ${JSON.stringify(at)}`
|
|
6009
|
+
);
|
|
6010
|
+
}
|
|
6011
|
+
if (ROLLS.has(param)) {
|
|
6012
|
+
throw new PatchError(
|
|
6013
|
+
`${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`
|
|
6014
|
+
);
|
|
6015
|
+
}
|
|
6016
|
+
const isRest = (p, v) => v === ctx.parameters.find((q) => q.id === p)?.default;
|
|
6017
|
+
const isShut = (p, v) => SHUT_BY.get(part.id) === p && v === 0;
|
|
6018
|
+
if (!isRest(param, value) && !isShut(param, value)) return keyform.offsets;
|
|
6019
|
+
const open = listStops(warps, (p, v) => !isRest(p, v) && !isShut(p, v));
|
|
6020
|
+
const grid = part.deformer !== void 0 && ctx.grids.has(part.deformer) ? `its feature grid ${part.deformer} at a ${import_format11.StandardParameter.AngleX} \xD7 ${import_format11.StandardParameter.AngleY} stop` : "";
|
|
6021
|
+
const instead = [open && `another of its stops (${open})`, grid].filter((s) => s !== "").join(" or ");
|
|
6022
|
+
const hint = instead === "" ? "" : `; patch ${instead} instead`;
|
|
6023
|
+
throw new PatchError(
|
|
6024
|
+
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}`
|
|
6025
|
+
);
|
|
6026
|
+
}
|
|
6027
|
+
function listStops(warps, keep) {
|
|
6028
|
+
const stops = /* @__PURE__ */ new Map();
|
|
6029
|
+
for (const w of warps) {
|
|
6030
|
+
for (const k of w.keyforms) {
|
|
6031
|
+
if (!keep(w.parameter, k.value)) continue;
|
|
6032
|
+
const s = stops.get(w.parameter) ?? /* @__PURE__ */ new Set();
|
|
6033
|
+
s.add(k.value);
|
|
6034
|
+
stops.set(w.parameter, s);
|
|
6035
|
+
}
|
|
6036
|
+
}
|
|
6037
|
+
return [...stops].map(([p, s]) => `${p}@${[...s].sort((a, b) => a - b).join(",")}`).join(" ");
|
|
6038
|
+
}
|
|
6039
|
+
function regionWeights(points, box, x, y, fall) {
|
|
6040
|
+
const x0 = box.x0 + x[0] * bw(box);
|
|
6041
|
+
const x1 = box.x0 + x[1] * bw(box);
|
|
6042
|
+
const top = box.y1 - y[0] * bh(box);
|
|
6043
|
+
const bottom = box.y1 - y[1] * bh(box);
|
|
6044
|
+
return points.map(([px, py]) => {
|
|
6045
|
+
const d = Math.hypot(
|
|
6046
|
+
Math.max(x0 - px, 0, px - x1),
|
|
6047
|
+
Math.max(bottom - py, 0, py - top)
|
|
6048
|
+
);
|
|
6049
|
+
return d === 0 ? 1 : d < fall ? smoothstep(fall, 0, d) : 0;
|
|
6050
|
+
});
|
|
6051
|
+
}
|
|
6052
|
+
function asPatch(check) {
|
|
6053
|
+
try {
|
|
6054
|
+
return check();
|
|
6055
|
+
} catch (e) {
|
|
6056
|
+
throw e instanceof TurnTargetError ? new PatchError(e.message) : e;
|
|
6057
|
+
}
|
|
6058
|
+
}
|
|
6059
|
+
function fields(name, v, known) {
|
|
6060
|
+
if (v === void 0) throw new PatchError(`${name} is missing`);
|
|
6061
|
+
asPatch(() => checkedKeys(name, v, known));
|
|
6062
|
+
return v;
|
|
6063
|
+
}
|
|
6064
|
+
function numbers(name, v) {
|
|
6065
|
+
const o = fields(name, v, Object.keys(v ?? {}));
|
|
6066
|
+
return Object.fromEntries(
|
|
6067
|
+
Object.entries(o).map(([k, n]) => [k, finite2(`${name}.${k}`, n)])
|
|
6068
|
+
);
|
|
6069
|
+
}
|
|
6070
|
+
var finite2 = (name, v, lo = -Infinity) => asPatch(() => checkedNumber(name, v, lo, Infinity));
|
|
6071
|
+
function text(name, v) {
|
|
6072
|
+
if (typeof v !== "string") {
|
|
6073
|
+
throw new PatchError(`${name} must be a string, got ${String(v)}`);
|
|
6074
|
+
}
|
|
6075
|
+
return v;
|
|
6076
|
+
}
|
|
6077
|
+
function span(name, v) {
|
|
6078
|
+
if (!Array.isArray(v) || v.length !== 2) {
|
|
6079
|
+
throw new PatchError(
|
|
6080
|
+
`${name} must be [from, to], got ${JSON.stringify(v)}`
|
|
6081
|
+
);
|
|
6082
|
+
}
|
|
6083
|
+
const lo = finite2(`${name}[0]`, v[0]);
|
|
6084
|
+
const hi = finite2(`${name}[1]`, v[1]);
|
|
6085
|
+
if (lo > hi) {
|
|
6086
|
+
throw new PatchError(
|
|
6087
|
+
`${name} [${lo}, ${hi}] runs backwards: ${name}[0] must not exceed ${name}[1]`
|
|
6088
|
+
);
|
|
6089
|
+
}
|
|
6090
|
+
return [lo, hi];
|
|
6091
|
+
}
|
|
6092
|
+
|
|
5842
6093
|
// src/auto-rig/generate.ts
|
|
5843
6094
|
var MESH_CELLS = {
|
|
5844
6095
|
face: { px: 28, min: 4, max: 24 },
|
|
@@ -6016,8 +6267,17 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
6016
6267
|
];
|
|
6017
6268
|
}
|
|
6018
6269
|
const parameters = declareParameters(new Set(byRole.keys()));
|
|
6270
|
+
const reports = options.patches === void 0 ? void 0 : applyPatches(options.patches, {
|
|
6271
|
+
grids: new Map(
|
|
6272
|
+
[...grids].map(([family, g]) => [WARP_ID[family], g])
|
|
6273
|
+
),
|
|
6274
|
+
parts,
|
|
6275
|
+
boxOf: (role) => has(role) ? box(role) : void 0,
|
|
6276
|
+
faceWidth: byRole.get("face").cropW,
|
|
6277
|
+
parameters
|
|
6278
|
+
});
|
|
6019
6279
|
const model = {
|
|
6020
|
-
version:
|
|
6280
|
+
version: import_format12.IKI_FORMAT_VERSION,
|
|
6021
6281
|
name: "auto-rigged",
|
|
6022
6282
|
canvas: { width: canvas.width, height: canvas.height },
|
|
6023
6283
|
parameters,
|
|
@@ -6027,7 +6287,8 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
6027
6287
|
expressions: defaultExpressions(new Set(parameters.map((p) => p.id))),
|
|
6028
6288
|
motions: defaultMotions(new Set(parameters.map((p) => p.id)))
|
|
6029
6289
|
};
|
|
6030
|
-
const valid = (0,
|
|
6290
|
+
const valid = (0, import_format12.parseIkiModel)(model);
|
|
6291
|
+
if (reports !== void 0) options.onPatchesApplied?.(reports);
|
|
6031
6292
|
if (hasNose && options.onTurnSolved) {
|
|
6032
6293
|
options.onTurnSolved(
|
|
6033
6294
|
turnReport(
|
|
@@ -6042,14 +6303,14 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
6042
6303
|
function turnWarps(mesh, b, fieldOf) {
|
|
6043
6304
|
return [
|
|
6044
6305
|
localWarp(
|
|
6045
|
-
|
|
6306
|
+
import_format12.StandardParameter.AngleX,
|
|
6046
6307
|
mesh,
|
|
6047
6308
|
b,
|
|
6048
6309
|
X_STOPS,
|
|
6049
6310
|
([x, y], v, i) => v === 0 ? [0, 0] : [fieldOf(i)(x, y, v, 0)[0], 0]
|
|
6050
6311
|
),
|
|
6051
6312
|
localWarp(
|
|
6052
|
-
|
|
6313
|
+
import_format12.StandardParameter.AngleY,
|
|
6053
6314
|
mesh,
|
|
6054
6315
|
b,
|
|
6055
6316
|
Y_STOPS,
|
|
@@ -6100,7 +6361,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid, lips) {
|
|
|
6100
6361
|
}
|
|
6101
6362
|
if (mesh !== void 0) part.mesh = mesh;
|
|
6102
6363
|
const side = spec.role.endsWith("_L") ? "L" : "R";
|
|
6103
|
-
const eyeOpen = side === "L" ?
|
|
6364
|
+
const eyeOpen = side === "L" ? import_format12.StandardParameter.EyeOpenLeft : import_format12.StandardParameter.EyeOpenRight;
|
|
6104
6365
|
const hh = frame.hh;
|
|
6105
6366
|
switch (spec.role) {
|
|
6106
6367
|
case "face":
|
|
@@ -6115,7 +6376,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid, lips) {
|
|
|
6115
6376
|
headOwnRoll(byRole.has("body"))
|
|
6116
6377
|
),
|
|
6117
6378
|
localWarp(
|
|
6118
|
-
|
|
6379
|
+
import_format12.StandardParameter.Breath,
|
|
6119
6380
|
mesh,
|
|
6120
6381
|
b,
|
|
6121
6382
|
[0, 1],
|
|
@@ -6162,8 +6423,8 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid, lips) {
|
|
|
6162
6423
|
if (byRole.has("mouth_open")) {
|
|
6163
6424
|
warps.push(mouthWiden(mesh, b));
|
|
6164
6425
|
bindings.push(
|
|
6165
|
-
{ parameter:
|
|
6166
|
-
{ parameter:
|
|
6426
|
+
{ parameter: import_format12.StandardParameter.MouthOpen, channel: "opacity", from: 1, to: 0 },
|
|
6427
|
+
{ parameter: import_format12.StandardParameter.MouthOpen, channel: "opacity", from: 1, to: 0 }
|
|
6167
6428
|
);
|
|
6168
6429
|
extra = [(AMPLITUDE.mouthOpenWidth - 1) * (bw(b) / 2), 0];
|
|
6169
6430
|
} else {
|
|
@@ -6173,19 +6434,19 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid, lips) {
|
|
|
6173
6434
|
);
|
|
6174
6435
|
bindings.push(
|
|
6175
6436
|
{
|
|
6176
|
-
parameter:
|
|
6437
|
+
parameter: import_format12.StandardParameter.MouthOpen,
|
|
6177
6438
|
channel: "scaleY",
|
|
6178
6439
|
from: 0,
|
|
6179
6440
|
to: roundTo(grow, 0.01)
|
|
6180
6441
|
},
|
|
6181
6442
|
{
|
|
6182
|
-
parameter:
|
|
6443
|
+
parameter: import_format12.StandardParameter.MouthOpen,
|
|
6183
6444
|
channel: "scaleX",
|
|
6184
6445
|
from: 0,
|
|
6185
6446
|
to: roundTo(AMPLITUDE.mouthOpenWidth - 1, 0.01)
|
|
6186
6447
|
},
|
|
6187
6448
|
{
|
|
6188
|
-
parameter:
|
|
6449
|
+
parameter: import_format12.StandardParameter.MouthOpen,
|
|
6189
6450
|
channel: "translateY",
|
|
6190
6451
|
from: 0,
|
|
6191
6452
|
to: -roundTo(grow * bh(b) / 2, 0.01)
|
|
@@ -6197,7 +6458,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid, lips) {
|
|
|
6197
6458
|
case "mouth_open":
|
|
6198
6459
|
warps.push(mouthForm(mesh, b), mouthOpenGrow(mesh, b));
|
|
6199
6460
|
bindings.push({
|
|
6200
|
-
parameter:
|
|
6461
|
+
parameter: import_format12.StandardParameter.MouthOpen,
|
|
6201
6462
|
channel: "opacity",
|
|
6202
6463
|
from: 0,
|
|
6203
6464
|
to: 1
|
|
@@ -6219,7 +6480,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid, lips) {
|
|
|
6219
6480
|
case "blush_L":
|
|
6220
6481
|
case "blush_R":
|
|
6221
6482
|
bindings.push({
|
|
6222
|
-
parameter:
|
|
6483
|
+
parameter: import_format12.StandardParameter.Cheek,
|
|
6223
6484
|
channel: "opacity",
|
|
6224
6485
|
from: AMPLITUDE.blushRest,
|
|
6225
6486
|
to: 1
|
|
@@ -6230,8 +6491,8 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid, lips) {
|
|
|
6230
6491
|
if (byRole.has("hair_front")) {
|
|
6231
6492
|
const amp = style.sway * AMPLITUDE.sway * hh;
|
|
6232
6493
|
warps.push(
|
|
6233
|
-
hairSway(
|
|
6234
|
-
hairSway(
|
|
6494
|
+
hairSway(import_format12.StandardParameter.HairSwayX, mesh, b, amp),
|
|
6495
|
+
hairSway(import_format12.StandardParameter.HairSwayZ, mesh, b, amp)
|
|
6235
6496
|
);
|
|
6236
6497
|
}
|
|
6237
6498
|
warps.push(tiltHang(mesh, b, pivot, hairHangWeight(frame.chinY, b.y0)));
|
|
@@ -6297,9 +6558,9 @@ function deformers(frame, grids, bodyWarp, arms, byRole) {
|
|
|
6297
6558
|
pivot: { x: roundTo(frame.axisX, 0.01), y: roundTo(frame.chinY, 0.01) },
|
|
6298
6559
|
bindings: [
|
|
6299
6560
|
// AngleZ is clockwise-positive (Live2D's); a rotation is CCW-positive.
|
|
6300
|
-
{ parameter:
|
|
6561
|
+
{ parameter: import_format12.StandardParameter.AngleZ, channel: "rotate", from: roll, to: -roll },
|
|
6301
6562
|
{
|
|
6302
|
-
parameter:
|
|
6563
|
+
parameter: import_format12.StandardParameter.Breath,
|
|
6303
6564
|
channel: "translateY",
|
|
6304
6565
|
from: 0,
|
|
6305
6566
|
to: roundTo(headOwnBreath(hasBody) * frame.hh, 0.01)
|
|
@@ -6317,8 +6578,8 @@ function deformers(frame, grids, bodyWarp, arms, byRole) {
|
|
|
6317
6578
|
points: g.lattice.points
|
|
6318
6579
|
},
|
|
6319
6580
|
warp2d: {
|
|
6320
|
-
parameter:
|
|
6321
|
-
parameterY:
|
|
6581
|
+
parameter: import_format12.StandardParameter.AngleX,
|
|
6582
|
+
parameterY: import_format12.StandardParameter.AngleY,
|
|
6322
6583
|
valuesX: X_STOPS,
|
|
6323
6584
|
valuesY: Y_STOPS,
|
|
6324
6585
|
keyforms2d: g.keyforms.map((offsets) => ({ offsets }))
|
|
@@ -6331,16 +6592,16 @@ function hairPhysics() {
|
|
|
6331
6592
|
return [
|
|
6332
6593
|
{
|
|
6333
6594
|
id: "hairSway",
|
|
6334
|
-
input: { parameter:
|
|
6335
|
-
output: { parameter:
|
|
6595
|
+
input: { parameter: import_format12.StandardParameter.AngleX, weight: 1 },
|
|
6596
|
+
output: { parameter: import_format12.StandardParameter.HairSwayX, scale: 5 },
|
|
6336
6597
|
mass: 1,
|
|
6337
6598
|
stiffness: 30,
|
|
6338
6599
|
damping: 3
|
|
6339
6600
|
},
|
|
6340
6601
|
{
|
|
6341
6602
|
id: "hairTilt",
|
|
6342
|
-
input: { parameter:
|
|
6343
|
-
output: { parameter:
|
|
6603
|
+
input: { parameter: import_format12.StandardParameter.AngleZ, weight: 1 },
|
|
6604
|
+
output: { parameter: import_format12.StandardParameter.HairSwayZ, scale: 8 },
|
|
6344
6605
|
mass: 1,
|
|
6345
6606
|
stiffness: 25,
|
|
6346
6607
|
damping: 2.5
|
|
@@ -6350,13 +6611,13 @@ function hairPhysics() {
|
|
|
6350
6611
|
function declareParameters(roles) {
|
|
6351
6612
|
const out = [];
|
|
6352
6613
|
const add = (id, name, min, max, def) => out.push({ id, name, min, max, default: def });
|
|
6353
|
-
add(
|
|
6354
|
-
add(
|
|
6355
|
-
add(
|
|
6614
|
+
add(import_format12.StandardParameter.AngleX, "Head Angle", -30, 30, 0);
|
|
6615
|
+
add(import_format12.StandardParameter.AngleY, "Head Angle Y", -30, 30, 0);
|
|
6616
|
+
add(import_format12.StandardParameter.AngleZ, "Head Angle Z", -30, 30, 0);
|
|
6356
6617
|
if (roles.has("body")) {
|
|
6357
|
-
add(
|
|
6358
|
-
add(
|
|
6359
|
-
add(
|
|
6618
|
+
add(import_format12.StandardParameter.BodyAngleX, "Body Angle X", -10, 10, 0);
|
|
6619
|
+
add(import_format12.StandardParameter.BodyAngleY, "Body Angle Y", -10, 10, 0);
|
|
6620
|
+
add(import_format12.StandardParameter.BodyAngleZ, "Body Angle Z", -10, 10, 0);
|
|
6360
6621
|
}
|
|
6361
6622
|
const addPose = (side, pose, angle) => {
|
|
6362
6623
|
add(pose, `Arm Pose ${side}`, 0, 1, 0);
|
|
@@ -6365,40 +6626,40 @@ function declareParameters(roles) {
|
|
|
6365
6626
|
const [armMin, armMax] = ARM_RANGE;
|
|
6366
6627
|
const [elbowMin, elbowMax] = ELBOW_RANGE;
|
|
6367
6628
|
if (roles.has("arm_L")) {
|
|
6368
|
-
add(
|
|
6369
|
-
add(
|
|
6629
|
+
add(import_format12.StandardParameter.ArmLeft, "Arm L", armMin, armMax, 0);
|
|
6630
|
+
add(import_format12.StandardParameter.ElbowLeft, "Elbow L", elbowMin, elbowMax, 0);
|
|
6370
6631
|
if (roles.has("forearm_pose_L"))
|
|
6371
|
-
addPose("L",
|
|
6632
|
+
addPose("L", import_format12.StandardParameter.ArmPoseLeft, import_format12.StandardParameter.ArmPoseAngleLeft);
|
|
6372
6633
|
}
|
|
6373
6634
|
if (roles.has("arm_R")) {
|
|
6374
|
-
add(
|
|
6375
|
-
add(
|
|
6635
|
+
add(import_format12.StandardParameter.ArmRight, "Arm R", armMin, armMax, 0);
|
|
6636
|
+
add(import_format12.StandardParameter.ElbowRight, "Elbow R", elbowMin, elbowMax, 0);
|
|
6376
6637
|
if (roles.has("forearm_pose_R"))
|
|
6377
|
-
addPose("R",
|
|
6638
|
+
addPose("R", import_format12.StandardParameter.ArmPoseRight, import_format12.StandardParameter.ArmPoseAngleRight);
|
|
6378
6639
|
}
|
|
6379
|
-
add(
|
|
6380
|
-
add(
|
|
6640
|
+
add(import_format12.StandardParameter.EyeOpenLeft, "Eye L", 0, 1, 1);
|
|
6641
|
+
add(import_format12.StandardParameter.EyeOpenRight, "Eye R", 0, 1, 1);
|
|
6381
6642
|
if ([...roles].some((r) => /^(iris|pupil|highlight)_/.test(r))) {
|
|
6382
|
-
add(
|
|
6383
|
-
add(
|
|
6643
|
+
add(import_format12.StandardParameter.EyeballX, "Gaze X", -1, 1, 0);
|
|
6644
|
+
add(import_format12.StandardParameter.EyeballY, "Gaze Y", -1, 1, 0);
|
|
6384
6645
|
}
|
|
6385
|
-
add(
|
|
6386
|
-
add(
|
|
6646
|
+
add(import_format12.StandardParameter.MouthOpen, "Mouth Open", 0, 1, 0);
|
|
6647
|
+
add(import_format12.StandardParameter.MouthForm, "Mouth Form", -1, 1, 0);
|
|
6387
6648
|
if (roles.has("brow_L")) {
|
|
6388
|
-
add(
|
|
6389
|
-
add(
|
|
6649
|
+
add(import_format12.StandardParameter.BrowLeftY, "Brow L Y", -1, 1, 0);
|
|
6650
|
+
add(import_format12.StandardParameter.BrowLeftAngle, "Brow L Angle", -1, 1, 0);
|
|
6390
6651
|
}
|
|
6391
6652
|
if (roles.has("brow_R")) {
|
|
6392
|
-
add(
|
|
6393
|
-
add(
|
|
6653
|
+
add(import_format12.StandardParameter.BrowRightY, "Brow R Y", -1, 1, 0);
|
|
6654
|
+
add(import_format12.StandardParameter.BrowRightAngle, "Brow R Angle", -1, 1, 0);
|
|
6394
6655
|
}
|
|
6395
6656
|
if (roles.has("blush_L") || roles.has("blush_R")) {
|
|
6396
|
-
add(
|
|
6657
|
+
add(import_format12.StandardParameter.Cheek, "Cheek", 0, 1, 0);
|
|
6397
6658
|
}
|
|
6398
|
-
add(
|
|
6659
|
+
add(import_format12.StandardParameter.Breath, "Breath", 0, 1, 0);
|
|
6399
6660
|
if (roles.has("hair_front")) {
|
|
6400
|
-
add(
|
|
6401
|
-
add(
|
|
6661
|
+
add(import_format12.StandardParameter.HairSwayX, "Hair Sway X", -SWAY_RANGE, SWAY_RANGE, 0);
|
|
6662
|
+
add(import_format12.StandardParameter.HairSwayZ, "Hair Sway Z", -SWAY_RANGE, SWAY_RANGE, 0);
|
|
6402
6663
|
}
|
|
6403
6664
|
return out;
|
|
6404
6665
|
}
|
|
@@ -6420,6 +6681,8 @@ function declareParameters(roles) {
|
|
|
6420
6681
|
LIP_INSIDE_ROLES,
|
|
6421
6682
|
LIP_ROLES,
|
|
6422
6683
|
LayerGeometryError,
|
|
6684
|
+
PatchError,
|
|
6685
|
+
SHUT_BY,
|
|
6423
6686
|
SPECK_CORE_FRACTION,
|
|
6424
6687
|
SetDeformerBindings,
|
|
6425
6688
|
SetDeformerParent,
|