@ikijs/editor 0.14.0 → 0.16.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 +6 -1
- package/dist/index.d.mts +9 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +236 -56
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +236 -54
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -60,7 +60,12 @@ leaves the document untouched.
|
|
|
60
60
|
`mouth`, plus optional `iris_*`, `brow_*`, `lash_*`, `lash_lower_*`, `hair_front`, `hair_back`,
|
|
61
61
|
…) into a rigged model that blinks, gazes, opens its mouth, turns its head over
|
|
62
62
|
a torso that breathes, and emotes with its brows — including a
|
|
63
|
-
hair-sway physics rig when a `hair_front` layer is present.
|
|
63
|
+
hair-sway physics rig when a `hair_front` layer is present. With a `blush_*`
|
|
64
|
+
layer it declares `ParamCheek`, which fades the blush from faint at rest to
|
|
65
|
+
as drawn. Every rigged model also declares the head motions Nod, Shake and
|
|
66
|
+
Tilt and up to six default expressions (smile, laugh, angry, sad, surprised,
|
|
67
|
+
shy; shy needs a blush, angry and sad need brows), each with a description a
|
|
68
|
+
host picks by (`AUTO-RIG.md`).
|
|
64
69
|
|
|
65
70
|
The rig turns the head by parallax, not a reshaped face, with values of our
|
|
66
71
|
own picked by eye (`auto-rig/profile.ts`, `AUTO-RIG.md`). The face plate
|
package/dist/index.d.mts
CHANGED
|
@@ -185,7 +185,8 @@ declare class SetDeformerBindings implements EditCommand {
|
|
|
185
185
|
/**
|
|
186
186
|
* Reparent a deformer (matrix or warp) under a new parent, or promote it to
|
|
187
187
|
* root (`newParentId === undefined`). Calls {@link validateDeformerReparent}
|
|
188
|
-
* FIRST so invalid reparents (cycles, warp
|
|
188
|
+
* FIRST so invalid reparents (cycles, warp-under-warp, a pivot outside the new
|
|
189
|
+
* warp parent's grid, unknown id) throw before any
|
|
189
190
|
* capture or mutation — a throwing apply leaves the model and undo stack
|
|
190
191
|
* untouched.
|
|
191
192
|
*
|
|
@@ -861,7 +862,9 @@ declare function parseLayerRoles(fileNames: string[]): {
|
|
|
861
862
|
* plate, the hair and the blush moved by per-vertex keyforms of their own —
|
|
862
863
|
* the plate as up to four islands of one drawing: a head that slides, a neck
|
|
863
864
|
* that stays and two ears that lag. Blink, gaze, brows, mouth, breath and
|
|
864
|
-
* hair sway are part warps and bindings under those.
|
|
865
|
+
* hair sway are part warps and bindings under those. The model also declares
|
|
866
|
+
* the default expressions and the Nod, Shake and Tilt motions
|
|
867
|
+
* (`animations.ts`).
|
|
865
868
|
*/
|
|
866
869
|
|
|
867
870
|
declare function generateIkiFromLayerSet(layers: LayerInput[], canvas: {
|
|
@@ -1179,8 +1182,10 @@ declare function uvRectFor(placement: AtlasPlacement, page: {
|
|
|
1179
1182
|
/**
|
|
1180
1183
|
* Validate that reparenting `deformerId` under `newParentId` keeps the deformer
|
|
1181
1184
|
* hierarchy valid. Pass `newParentId === undefined` to move to root (always legal).
|
|
1182
|
-
* Checks: existence, self-reference, undeclared parent, kind constraint (warp
|
|
1183
|
-
*
|
|
1185
|
+
* Checks: existence, self-reference, undeclared parent, kind constraint (a warp
|
|
1186
|
+
* deformer cannot be the parent of another warp deformer), a matrix deformer's
|
|
1187
|
+
* pivot inside its new warp parent's rest grid, and cycle detection via the
|
|
1188
|
+
* proposed edge.
|
|
1184
1189
|
*/
|
|
1185
1190
|
declare function validateDeformerReparent(deformers: IkiDeformer[], deformerId: string, newParentId: string | undefined): void;
|
|
1186
1191
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -185,7 +185,8 @@ declare class SetDeformerBindings implements EditCommand {
|
|
|
185
185
|
/**
|
|
186
186
|
* Reparent a deformer (matrix or warp) under a new parent, or promote it to
|
|
187
187
|
* root (`newParentId === undefined`). Calls {@link validateDeformerReparent}
|
|
188
|
-
* FIRST so invalid reparents (cycles, warp
|
|
188
|
+
* FIRST so invalid reparents (cycles, warp-under-warp, a pivot outside the new
|
|
189
|
+
* warp parent's grid, unknown id) throw before any
|
|
189
190
|
* capture or mutation — a throwing apply leaves the model and undo stack
|
|
190
191
|
* untouched.
|
|
191
192
|
*
|
|
@@ -861,7 +862,9 @@ declare function parseLayerRoles(fileNames: string[]): {
|
|
|
861
862
|
* plate, the hair and the blush moved by per-vertex keyforms of their own —
|
|
862
863
|
* the plate as up to four islands of one drawing: a head that slides, a neck
|
|
863
864
|
* that stays and two ears that lag. Blink, gaze, brows, mouth, breath and
|
|
864
|
-
* hair sway are part warps and bindings under those.
|
|
865
|
+
* hair sway are part warps and bindings under those. The model also declares
|
|
866
|
+
* the default expressions and the Nod, Shake and Tilt motions
|
|
867
|
+
* (`animations.ts`).
|
|
865
868
|
*/
|
|
866
869
|
|
|
867
870
|
declare function generateIkiFromLayerSet(layers: LayerInput[], canvas: {
|
|
@@ -1179,8 +1182,10 @@ declare function uvRectFor(placement: AtlasPlacement, page: {
|
|
|
1179
1182
|
/**
|
|
1180
1183
|
* Validate that reparenting `deformerId` under `newParentId` keeps the deformer
|
|
1181
1184
|
* hierarchy valid. Pass `newParentId === undefined` to move to root (always legal).
|
|
1182
|
-
* Checks: existence, self-reference, undeclared parent, kind constraint (warp
|
|
1183
|
-
*
|
|
1185
|
+
* Checks: existence, self-reference, undeclared parent, kind constraint (a warp
|
|
1186
|
+
* deformer cannot be the parent of another warp deformer), a matrix deformer's
|
|
1187
|
+
* pivot inside its new warp parent's rest grid, and cycle detection via the
|
|
1188
|
+
* proposed edge.
|
|
1184
1189
|
*/
|
|
1185
1190
|
declare function validateDeformerReparent(deformers: IkiDeformer[], deformerId: string, newParentId: string | undefined): void;
|
|
1186
1191
|
/**
|
package/dist/index.js
CHANGED
|
@@ -520,11 +520,24 @@ function validateDeformerReparent(deformers2, deformerId, newParentId) {
|
|
|
520
520
|
`deformers."${deformerId}".parent "${newParentId}" is not a declared deformer`
|
|
521
521
|
);
|
|
522
522
|
}
|
|
523
|
-
if (kindOf(parent) === "warp") {
|
|
523
|
+
if (kindOf(parent) === "warp" && kindOf(target) === "warp") {
|
|
524
524
|
throw new Error(
|
|
525
|
-
`deformers."${deformerId}".parent "${newParentId}" must be a matrix deformer (warp deformers cannot be
|
|
525
|
+
`deformers."${deformerId}".parent "${newParentId}" must be a matrix deformer (warp deformers cannot be nested under a warp deformer)`
|
|
526
526
|
);
|
|
527
527
|
}
|
|
528
|
+
if (parent.kind === "warp" && target.kind !== "warp") {
|
|
529
|
+
const { pivot } = target;
|
|
530
|
+
const { cols, rows, points } = parent.grid;
|
|
531
|
+
const xMin = points[0];
|
|
532
|
+
const xMax = points[2 * cols];
|
|
533
|
+
const yMax = points[1];
|
|
534
|
+
const yMin = points[rows * (cols + 1) * 2 + 1];
|
|
535
|
+
if (pivot.x < xMin || pivot.x > xMax || pivot.y < yMin || pivot.y > yMax) {
|
|
536
|
+
throw new Error(
|
|
537
|
+
`deformers."${deformerId}".pivot (${pivot.x}, ${pivot.y}) lies outside its warp parent "${newParentId}" rest grid x ${xMin}..${xMax}, y ${yMin}..${yMax}`
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
528
541
|
const parentOf = /* @__PURE__ */ new Map();
|
|
529
542
|
for (const d of deformers2) {
|
|
530
543
|
if (d.parent !== void 0) parentOf.set(d.id, d.parent);
|
|
@@ -1983,7 +1996,8 @@ var PROFILE_VALUES = {
|
|
|
1983
1996
|
mouthWiden: 1.2,
|
|
1984
1997
|
brow: 0.15,
|
|
1985
1998
|
breath: 0.03,
|
|
1986
|
-
sway: 0.08
|
|
1999
|
+
sway: 0.08,
|
|
2000
|
+
blushRest: 0.4
|
|
1987
2001
|
};
|
|
1988
2002
|
function deriveProfile(v) {
|
|
1989
2003
|
const farLead = v.lead * (1 - v.fore / 2);
|
|
@@ -2070,6 +2084,8 @@ function deriveProfile(v) {
|
|
|
2070
2084
|
breathHead: v.breath * 2 / 3,
|
|
2071
2085
|
/** Hair tip travel at full sway (±20), hh. */
|
|
2072
2086
|
sway: v.sway,
|
|
2087
|
+
/** The blush's opacity at Cheek 0; at Cheek 1 it is as drawn. */
|
|
2088
|
+
blushRest: v.blushRest,
|
|
2073
2089
|
/** The neck under the face reaches this far above the jaw, hh — what the
|
|
2074
2090
|
* chin uncovers as it slides off it: half again the chin's full-turn
|
|
2075
2091
|
* slide, to the next 0.05. */
|
|
@@ -2187,7 +2203,156 @@ function parseLayerRoles(fileNames) {
|
|
|
2187
2203
|
}
|
|
2188
2204
|
|
|
2189
2205
|
// src/auto-rig/generate.ts
|
|
2190
|
-
var
|
|
2206
|
+
var import_format6 = require("@ikijs/format");
|
|
2207
|
+
|
|
2208
|
+
// src/auto-rig/animations.ts
|
|
2209
|
+
var import_format3 = require("@ikijs/format");
|
|
2210
|
+
function browsY(y) {
|
|
2211
|
+
return [
|
|
2212
|
+
{ parameter: import_format3.StandardParameter.BrowLeftY, value: y, blend: "add" },
|
|
2213
|
+
{ parameter: import_format3.StandardParameter.BrowRightY, value: y, blend: "add" }
|
|
2214
|
+
];
|
|
2215
|
+
}
|
|
2216
|
+
function browsTilt(innerDown) {
|
|
2217
|
+
return [
|
|
2218
|
+
{ parameter: import_format3.StandardParameter.BrowLeftAngle, value: innerDown, blend: "add" },
|
|
2219
|
+
{ parameter: import_format3.StandardParameter.BrowRightAngle, value: -innerDown, blend: "add" }
|
|
2220
|
+
];
|
|
2221
|
+
}
|
|
2222
|
+
function cheek(value) {
|
|
2223
|
+
return { parameter: import_format3.StandardParameter.Cheek, value, blend: "add" };
|
|
2224
|
+
}
|
|
2225
|
+
var BROWS = [import_format3.StandardParameter.BrowLeftY, import_format3.StandardParameter.BrowRightY, import_format3.StandardParameter.BrowLeftAngle, import_format3.StandardParameter.BrowRightAngle];
|
|
2226
|
+
var EXPRESSIONS = [
|
|
2227
|
+
{
|
|
2228
|
+
id: "smile",
|
|
2229
|
+
description: "Smiling and pleased: warm, friendly, content. For greetings, thanks, agreement and gentle happiness.",
|
|
2230
|
+
parameters: [
|
|
2231
|
+
{ parameter: import_format3.StandardParameter.MouthForm, value: 1, blend: "add" },
|
|
2232
|
+
...browsY(0.25),
|
|
2233
|
+
cheek(0.4)
|
|
2234
|
+
]
|
|
2235
|
+
},
|
|
2236
|
+
{
|
|
2237
|
+
id: "laugh",
|
|
2238
|
+
description: "Laughing, eyes shut and mouth open: delighted, amused. For jokes, playfulness and big joy.",
|
|
2239
|
+
parameters: [
|
|
2240
|
+
{ parameter: import_format3.StandardParameter.EyeOpenLeft, value: 0, blend: "multiply" },
|
|
2241
|
+
{ parameter: import_format3.StandardParameter.EyeOpenRight, value: 0, blend: "multiply" },
|
|
2242
|
+
{ parameter: import_format3.StandardParameter.MouthForm, value: 1, blend: "add" },
|
|
2243
|
+
{ parameter: import_format3.StandardParameter.MouthOpen, value: 0.8, blend: "overwrite" },
|
|
2244
|
+
...browsY(0.4),
|
|
2245
|
+
cheek(0.65)
|
|
2246
|
+
]
|
|
2247
|
+
},
|
|
2248
|
+
{
|
|
2249
|
+
id: "angry",
|
|
2250
|
+
description: "Angry or annoyed, frowning. For irritation, frustration, indignation or scolding.",
|
|
2251
|
+
needs: BROWS,
|
|
2252
|
+
parameters: [
|
|
2253
|
+
...browsY(-0.5),
|
|
2254
|
+
...browsTilt(0.8),
|
|
2255
|
+
{ parameter: import_format3.StandardParameter.MouthForm, value: -0.9, blend: "add" }
|
|
2256
|
+
]
|
|
2257
|
+
},
|
|
2258
|
+
{
|
|
2259
|
+
id: "sad",
|
|
2260
|
+
description: "Sad or disappointed, downcast. For sorrow, regret, apology or sympathy.",
|
|
2261
|
+
needs: BROWS,
|
|
2262
|
+
parameters: [
|
|
2263
|
+
...browsY(0.35),
|
|
2264
|
+
...browsTilt(-0.8),
|
|
2265
|
+
{ parameter: import_format3.StandardParameter.MouthForm, value: -0.8, blend: "add" }
|
|
2266
|
+
]
|
|
2267
|
+
},
|
|
2268
|
+
{
|
|
2269
|
+
id: "surprised",
|
|
2270
|
+
description: "Surprised, mouth dropped open: startled, amazed. For shock, sudden news or disbelief.",
|
|
2271
|
+
parameters: [
|
|
2272
|
+
...browsY(0.8),
|
|
2273
|
+
{ parameter: import_format3.StandardParameter.MouthOpen, value: 0.9, blend: "overwrite" }
|
|
2274
|
+
]
|
|
2275
|
+
},
|
|
2276
|
+
{
|
|
2277
|
+
id: "shy",
|
|
2278
|
+
description: "Shy or embarrassed: bashful, flustered. For being praised, teased or caught off guard.",
|
|
2279
|
+
needs: [import_format3.StandardParameter.Cheek],
|
|
2280
|
+
parameters: [
|
|
2281
|
+
cheek(1),
|
|
2282
|
+
// Gaze down.
|
|
2283
|
+
{ parameter: import_format3.StandardParameter.EyeballY, value: -0.65, blend: "add" },
|
|
2284
|
+
{ parameter: import_format3.StandardParameter.MouthForm, value: 0.4, blend: "add" },
|
|
2285
|
+
...browsTilt(-0.25)
|
|
2286
|
+
]
|
|
2287
|
+
}
|
|
2288
|
+
];
|
|
2289
|
+
function defaultExpressions(declared) {
|
|
2290
|
+
return EXPRESSIONS.filter(
|
|
2291
|
+
(e) => e.needs === void 0 || e.needs.some((id) => declared.has(id))
|
|
2292
|
+
).map(({ needs: _needs, ...e }) => ({
|
|
2293
|
+
...e,
|
|
2294
|
+
parameters: e.parameters.filter((t) => declared.has(t.parameter))
|
|
2295
|
+
}));
|
|
2296
|
+
}
|
|
2297
|
+
var DEFAULT_MOTIONS = {
|
|
2298
|
+
Nod: [
|
|
2299
|
+
{
|
|
2300
|
+
description: "Nods yes: agreement, acknowledgement, understanding.",
|
|
2301
|
+
duration: 1,
|
|
2302
|
+
curves: [
|
|
2303
|
+
{
|
|
2304
|
+
parameter: import_format3.StandardParameter.AngleY,
|
|
2305
|
+
keys: [
|
|
2306
|
+
[0, 0],
|
|
2307
|
+
[0.3, -18],
|
|
2308
|
+
[0.6, 4],
|
|
2309
|
+
[0.8, -1],
|
|
2310
|
+
[1, 0]
|
|
2311
|
+
]
|
|
2312
|
+
}
|
|
2313
|
+
]
|
|
2314
|
+
}
|
|
2315
|
+
],
|
|
2316
|
+
Shake: [
|
|
2317
|
+
{
|
|
2318
|
+
description: "Shakes the head no: disagreement, refusal, disbelief.",
|
|
2319
|
+
duration: 1.2,
|
|
2320
|
+
// The first swing peaks at 0.2 s, which the default fade would still
|
|
2321
|
+
// be damping.
|
|
2322
|
+
fadeIn: 0.15,
|
|
2323
|
+
curves: [
|
|
2324
|
+
{
|
|
2325
|
+
parameter: import_format3.StandardParameter.AngleX,
|
|
2326
|
+
keys: [
|
|
2327
|
+
[0, 0],
|
|
2328
|
+
[0.2, -18],
|
|
2329
|
+
[0.45, 18],
|
|
2330
|
+
[0.7, -16],
|
|
2331
|
+
[0.95, 10],
|
|
2332
|
+
[1.2, 0]
|
|
2333
|
+
]
|
|
2334
|
+
}
|
|
2335
|
+
]
|
|
2336
|
+
}
|
|
2337
|
+
],
|
|
2338
|
+
Tilt: [
|
|
2339
|
+
{
|
|
2340
|
+
description: "Tilts the head to one side and back: curiosity, puzzlement, a question.",
|
|
2341
|
+
duration: 1.4,
|
|
2342
|
+
curves: [
|
|
2343
|
+
{
|
|
2344
|
+
parameter: import_format3.StandardParameter.AngleZ,
|
|
2345
|
+
keys: [
|
|
2346
|
+
[0, 0],
|
|
2347
|
+
[0.35, 20],
|
|
2348
|
+
[1, 20],
|
|
2349
|
+
[1.4, 0]
|
|
2350
|
+
]
|
|
2351
|
+
}
|
|
2352
|
+
]
|
|
2353
|
+
}
|
|
2354
|
+
]
|
|
2355
|
+
};
|
|
2191
2356
|
|
|
2192
2357
|
// src/auto-rig/layout.ts
|
|
2193
2358
|
function boxOfLayer(layer) {
|
|
@@ -2482,7 +2647,7 @@ function checkStrandEdges(strand, irises, hair) {
|
|
|
2482
2647
|
}
|
|
2483
2648
|
|
|
2484
2649
|
// src/auto-rig/context.ts
|
|
2485
|
-
var
|
|
2650
|
+
var import_format4 = require("@ikijs/format");
|
|
2486
2651
|
|
|
2487
2652
|
// src/auto-rig/grid.ts
|
|
2488
2653
|
var X_STOPS = [-30, 0, 30];
|
|
@@ -3698,7 +3863,7 @@ function renderedLander(turn, parts, grids, from = /* @__PURE__ */ new Map()) {
|
|
|
3698
3863
|
const family = roleSpec(role).family;
|
|
3699
3864
|
const part = parts.find((p) => p.id === role);
|
|
3700
3865
|
const g = grids.get(family);
|
|
3701
|
-
const warp = part?.warps?.find((w) => w.parameter ===
|
|
3866
|
+
const warp = part?.warps?.find((w) => w.parameter === import_format4.StandardParameter.AngleX);
|
|
3702
3867
|
if (part === void 0 || part.mesh === void 0 || !g && !warp) {
|
|
3703
3868
|
return x + field(role)(x, y, ax, 0)[0];
|
|
3704
3869
|
}
|
|
@@ -4408,7 +4573,7 @@ function buildTurn(frame, landmarks, q) {
|
|
|
4408
4573
|
}
|
|
4409
4574
|
|
|
4410
4575
|
// src/auto-rig/drivers.ts
|
|
4411
|
-
var
|
|
4576
|
+
var import_format5 = require("@ikijs/format");
|
|
4412
4577
|
var SWAY_RANGE = 20;
|
|
4413
4578
|
var SWAY_CURVE = 1.4;
|
|
4414
4579
|
var HAIR_HANG = 0.35;
|
|
@@ -4486,13 +4651,13 @@ function gazeBindings(irisW, share = 1) {
|
|
|
4486
4651
|
const gy = AMPLITUDE.gazeY * irisW * share;
|
|
4487
4652
|
return [
|
|
4488
4653
|
{
|
|
4489
|
-
parameter:
|
|
4654
|
+
parameter: import_format5.StandardParameter.EyeballX,
|
|
4490
4655
|
channel: "translateX",
|
|
4491
4656
|
from: -round1(gx),
|
|
4492
4657
|
to: round1(gx)
|
|
4493
4658
|
},
|
|
4494
4659
|
{
|
|
4495
|
-
parameter:
|
|
4660
|
+
parameter: import_format5.StandardParameter.EyeballY,
|
|
4496
4661
|
channel: "translateY",
|
|
4497
4662
|
from: -round1(gy),
|
|
4498
4663
|
to: round1(gy)
|
|
@@ -4506,8 +4671,8 @@ function browReach(hh) {
|
|
|
4506
4671
|
return AMPLITUDE.brow * hh;
|
|
4507
4672
|
}
|
|
4508
4673
|
function browBindings(side, reach) {
|
|
4509
|
-
const y = side === "L" ?
|
|
4510
|
-
const a = side === "L" ?
|
|
4674
|
+
const y = side === "L" ? import_format5.StandardParameter.BrowLeftY : import_format5.StandardParameter.BrowRightY;
|
|
4675
|
+
const a = side === "L" ? import_format5.StandardParameter.BrowLeftAngle : import_format5.StandardParameter.BrowRightAngle;
|
|
4511
4676
|
return [
|
|
4512
4677
|
{
|
|
4513
4678
|
parameter: y,
|
|
@@ -4523,7 +4688,7 @@ function mouthForm(mesh, box) {
|
|
|
4523
4688
|
const a = 0.3 * bh(box);
|
|
4524
4689
|
const c = cx(box);
|
|
4525
4690
|
const half = bw(box) / 2;
|
|
4526
|
-
return localWarp(
|
|
4691
|
+
return localWarp(import_format5.StandardParameter.MouthForm, mesh, box, [-1, 0, 1], ([x], v) => {
|
|
4527
4692
|
if (v === 0) return [0, 0];
|
|
4528
4693
|
const u = (x - c) / half;
|
|
4529
4694
|
const widen = v > 0 ? 0.05 : 0.03;
|
|
@@ -4533,7 +4698,7 @@ function mouthForm(mesh, box) {
|
|
|
4533
4698
|
function mouthOpenGrow(mesh, box) {
|
|
4534
4699
|
const c = cx(box);
|
|
4535
4700
|
return localWarp(
|
|
4536
|
-
|
|
4701
|
+
import_format5.StandardParameter.MouthOpen,
|
|
4537
4702
|
mesh,
|
|
4538
4703
|
box,
|
|
4539
4704
|
[0, 1],
|
|
@@ -4542,7 +4707,7 @@ function mouthOpenGrow(mesh, box) {
|
|
|
4542
4707
|
}
|
|
4543
4708
|
function mouthWiden(mesh, box) {
|
|
4544
4709
|
const c = cx(box);
|
|
4545
|
-
return localWarp(
|
|
4710
|
+
return localWarp(import_format5.StandardParameter.MouthOpen, mesh, box, [0, 1], ([x], v) => [
|
|
4546
4711
|
v * (AMPLITUDE.mouthOpenWidth - 1) * (x - c),
|
|
4547
4712
|
0
|
|
4548
4713
|
]);
|
|
@@ -4560,7 +4725,7 @@ function hairSway(param, mesh, box, amp) {
|
|
|
4560
4725
|
);
|
|
4561
4726
|
}
|
|
4562
4727
|
function tiltHang(mesh, box, pivot, weight) {
|
|
4563
|
-
return localWarp(
|
|
4728
|
+
return localWarp(import_format5.StandardParameter.AngleZ, mesh, box, Z_STOPS, ([x, y], v, i) => {
|
|
4564
4729
|
const g = weight(y, i);
|
|
4565
4730
|
if (g === 0 || v === 0) return [0, 0];
|
|
4566
4731
|
const a = -g * rollOf(v);
|
|
@@ -4713,16 +4878,19 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
4713
4878
|
...part.warps ?? []
|
|
4714
4879
|
];
|
|
4715
4880
|
}
|
|
4881
|
+
const parameters = declareParameters(new Set(byRole.keys()));
|
|
4716
4882
|
const model = {
|
|
4717
|
-
version:
|
|
4883
|
+
version: import_format6.IKI_FORMAT_VERSION,
|
|
4718
4884
|
name: "auto-rigged",
|
|
4719
4885
|
canvas: { width: canvas.width, height: canvas.height },
|
|
4720
|
-
parameters
|
|
4886
|
+
parameters,
|
|
4721
4887
|
parts,
|
|
4722
4888
|
deformers: deformers(frame, grids, has("body") ? box("body") : void 0),
|
|
4723
|
-
...has("hair_front") ? { physics: hairPhysics() } : {}
|
|
4889
|
+
...has("hair_front") ? { physics: hairPhysics() } : {},
|
|
4890
|
+
expressions: defaultExpressions(new Set(parameters.map((p) => p.id))),
|
|
4891
|
+
motions: DEFAULT_MOTIONS
|
|
4724
4892
|
};
|
|
4725
|
-
const valid = (0,
|
|
4893
|
+
const valid = (0, import_format6.parseIkiModel)(model);
|
|
4726
4894
|
if (hasNose && options.onTurnSolved) {
|
|
4727
4895
|
options.onTurnSolved(
|
|
4728
4896
|
turnReport(
|
|
@@ -4737,14 +4905,14 @@ function generateIkiFromLayerSet(layers, canvas, options = {}) {
|
|
|
4737
4905
|
function turnWarps(mesh, b, fieldOf) {
|
|
4738
4906
|
return [
|
|
4739
4907
|
localWarp(
|
|
4740
|
-
|
|
4908
|
+
import_format6.StandardParameter.AngleX,
|
|
4741
4909
|
mesh,
|
|
4742
4910
|
b,
|
|
4743
4911
|
X_STOPS,
|
|
4744
4912
|
([x, y], v, i) => v === 0 ? [0, 0] : [fieldOf(i)(x, y, v, 0)[0], 0]
|
|
4745
4913
|
),
|
|
4746
4914
|
localWarp(
|
|
4747
|
-
|
|
4915
|
+
import_format6.StandardParameter.AngleY,
|
|
4748
4916
|
mesh,
|
|
4749
4917
|
b,
|
|
4750
4918
|
Y_STOPS,
|
|
@@ -4792,7 +4960,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
4792
4960
|
}
|
|
4793
4961
|
if (mesh !== void 0) part.mesh = mesh;
|
|
4794
4962
|
const side = spec.role.endsWith("_L") ? "L" : "R";
|
|
4795
|
-
const eyeOpen = side === "L" ?
|
|
4963
|
+
const eyeOpen = side === "L" ? import_format6.StandardParameter.EyeOpenLeft : import_format6.StandardParameter.EyeOpenRight;
|
|
4796
4964
|
const hh = frame.hh;
|
|
4797
4965
|
switch (spec.role) {
|
|
4798
4966
|
case "face":
|
|
@@ -4801,7 +4969,7 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
4801
4969
|
warps.push(
|
|
4802
4970
|
tiltHang(mesh, b, pivot, (_y, i) => isNeck[i] ? 1 : 0),
|
|
4803
4971
|
localWarp(
|
|
4804
|
-
|
|
4972
|
+
import_format6.StandardParameter.Breath,
|
|
4805
4973
|
mesh,
|
|
4806
4974
|
b,
|
|
4807
4975
|
[0, 1],
|
|
@@ -4848,8 +5016,8 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
4848
5016
|
if (byRole.has("mouth_open")) {
|
|
4849
5017
|
warps.push(mouthWiden(mesh, b));
|
|
4850
5018
|
bindings.push(
|
|
4851
|
-
{ parameter:
|
|
4852
|
-
{ parameter:
|
|
5019
|
+
{ parameter: import_format6.StandardParameter.MouthOpen, channel: "opacity", from: 1, to: 0 },
|
|
5020
|
+
{ parameter: import_format6.StandardParameter.MouthOpen, channel: "opacity", from: 1, to: 0 }
|
|
4853
5021
|
);
|
|
4854
5022
|
extra = [(AMPLITUDE.mouthOpenWidth - 1) * (bw(b) / 2), 0];
|
|
4855
5023
|
} else {
|
|
@@ -4859,19 +5027,19 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
4859
5027
|
);
|
|
4860
5028
|
bindings.push(
|
|
4861
5029
|
{
|
|
4862
|
-
parameter:
|
|
5030
|
+
parameter: import_format6.StandardParameter.MouthOpen,
|
|
4863
5031
|
channel: "scaleY",
|
|
4864
5032
|
from: 0,
|
|
4865
5033
|
to: roundTo(grow, 0.01)
|
|
4866
5034
|
},
|
|
4867
5035
|
{
|
|
4868
|
-
parameter:
|
|
5036
|
+
parameter: import_format6.StandardParameter.MouthOpen,
|
|
4869
5037
|
channel: "scaleX",
|
|
4870
5038
|
from: 0,
|
|
4871
5039
|
to: roundTo(AMPLITUDE.mouthOpenWidth - 1, 0.01)
|
|
4872
5040
|
},
|
|
4873
5041
|
{
|
|
4874
|
-
parameter:
|
|
5042
|
+
parameter: import_format6.StandardParameter.MouthOpen,
|
|
4875
5043
|
channel: "translateY",
|
|
4876
5044
|
from: 0,
|
|
4877
5045
|
to: -roundTo(grow * bh(b) / 2, 0.01)
|
|
@@ -4883,20 +5051,29 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
|
|
|
4883
5051
|
case "mouth_open":
|
|
4884
5052
|
warps.push(mouthForm(mesh, b), mouthOpenGrow(mesh, b));
|
|
4885
5053
|
bindings.push({
|
|
4886
|
-
parameter:
|
|
5054
|
+
parameter: import_format6.StandardParameter.MouthOpen,
|
|
4887
5055
|
channel: "opacity",
|
|
4888
5056
|
from: 0,
|
|
4889
5057
|
to: 1
|
|
4890
5058
|
});
|
|
4891
5059
|
extra = [(AMPLITUDE.mouthOpenWidth - 1) * (bw(b) / 2), 0];
|
|
4892
5060
|
break;
|
|
5061
|
+
case "blush_L":
|
|
5062
|
+
case "blush_R":
|
|
5063
|
+
bindings.push({
|
|
5064
|
+
parameter: import_format6.StandardParameter.Cheek,
|
|
5065
|
+
channel: "opacity",
|
|
5066
|
+
from: AMPLITUDE.blushRest,
|
|
5067
|
+
to: 1
|
|
5068
|
+
});
|
|
5069
|
+
break;
|
|
4893
5070
|
case "hair_front":
|
|
4894
5071
|
case "hair_back":
|
|
4895
5072
|
if (byRole.has("hair_front")) {
|
|
4896
5073
|
const amp = style.sway * AMPLITUDE.sway * hh;
|
|
4897
5074
|
warps.push(
|
|
4898
|
-
hairSway(
|
|
4899
|
-
hairSway(
|
|
5075
|
+
hairSway(import_format6.StandardParameter.HairSwayX, mesh, b, amp),
|
|
5076
|
+
hairSway(import_format6.StandardParameter.HairSwayZ, mesh, b, amp)
|
|
4900
5077
|
);
|
|
4901
5078
|
}
|
|
4902
5079
|
warps.push(tiltHang(mesh, b, pivot, hairHangWeight(frame.chinY, b.y0)));
|
|
@@ -4977,7 +5154,7 @@ function deformers(frame, grids, body) {
|
|
|
4977
5154
|
pivot: { x: roundTo(cx(body), 0.01), y: roundTo(body.y1, 0.01) },
|
|
4978
5155
|
bindings: [
|
|
4979
5156
|
{
|
|
4980
|
-
parameter:
|
|
5157
|
+
parameter: import_format6.StandardParameter.Breath,
|
|
4981
5158
|
channel: "translateY",
|
|
4982
5159
|
from: 0,
|
|
4983
5160
|
to: roundTo(AMPLITUDE.breathBody * frame.hh, 0.01)
|
|
@@ -4990,9 +5167,9 @@ function deformers(frame, grids, body) {
|
|
|
4990
5167
|
pivot: { x: roundTo(frame.axisX, 0.01), y: roundTo(frame.chinY, 0.01) },
|
|
4991
5168
|
bindings: [
|
|
4992
5169
|
// AngleZ is clockwise-positive (Live2D's); a rotation is CCW-positive.
|
|
4993
|
-
{ parameter:
|
|
5170
|
+
{ parameter: import_format6.StandardParameter.AngleZ, channel: "rotate", from: ROLL_DEG, to: -ROLL_DEG },
|
|
4994
5171
|
{
|
|
4995
|
-
parameter:
|
|
5172
|
+
parameter: import_format6.StandardParameter.Breath,
|
|
4996
5173
|
channel: "translateY",
|
|
4997
5174
|
from: 0,
|
|
4998
5175
|
to: roundTo(AMPLITUDE.breathHead * frame.hh, 0.01)
|
|
@@ -5010,8 +5187,8 @@ function deformers(frame, grids, body) {
|
|
|
5010
5187
|
points: g.lattice.points
|
|
5011
5188
|
},
|
|
5012
5189
|
warp2d: {
|
|
5013
|
-
parameter:
|
|
5014
|
-
parameterY:
|
|
5190
|
+
parameter: import_format6.StandardParameter.AngleX,
|
|
5191
|
+
parameterY: import_format6.StandardParameter.AngleY,
|
|
5015
5192
|
valuesX: X_STOPS,
|
|
5016
5193
|
valuesY: Y_STOPS,
|
|
5017
5194
|
keyforms2d: g.keyforms.map((offsets) => ({ offsets }))
|
|
@@ -5024,16 +5201,16 @@ function hairPhysics() {
|
|
|
5024
5201
|
return [
|
|
5025
5202
|
{
|
|
5026
5203
|
id: "hairSway",
|
|
5027
|
-
input: { parameter:
|
|
5028
|
-
output: { parameter:
|
|
5204
|
+
input: { parameter: import_format6.StandardParameter.AngleX, weight: 1 },
|
|
5205
|
+
output: { parameter: import_format6.StandardParameter.HairSwayX, scale: 5 },
|
|
5029
5206
|
mass: 1,
|
|
5030
5207
|
stiffness: 30,
|
|
5031
5208
|
damping: 3
|
|
5032
5209
|
},
|
|
5033
5210
|
{
|
|
5034
5211
|
id: "hairTilt",
|
|
5035
|
-
input: { parameter:
|
|
5036
|
-
output: { parameter:
|
|
5212
|
+
input: { parameter: import_format6.StandardParameter.AngleZ, weight: 1 },
|
|
5213
|
+
output: { parameter: import_format6.StandardParameter.HairSwayZ, scale: 8 },
|
|
5037
5214
|
mass: 1,
|
|
5038
5215
|
stiffness: 25,
|
|
5039
5216
|
damping: 2.5
|
|
@@ -5043,29 +5220,32 @@ function hairPhysics() {
|
|
|
5043
5220
|
function declareParameters(roles) {
|
|
5044
5221
|
const out = [];
|
|
5045
5222
|
const add = (id, name, min, max, def) => out.push({ id, name, min, max, default: def });
|
|
5046
|
-
add(
|
|
5047
|
-
add(
|
|
5048
|
-
add(
|
|
5049
|
-
add(
|
|
5050
|
-
add(
|
|
5223
|
+
add(import_format6.StandardParameter.AngleX, "Head Angle", -30, 30, 0);
|
|
5224
|
+
add(import_format6.StandardParameter.AngleY, "Head Angle Y", -30, 30, 0);
|
|
5225
|
+
add(import_format6.StandardParameter.AngleZ, "Head Angle Z", -30, 30, 0);
|
|
5226
|
+
add(import_format6.StandardParameter.EyeOpenLeft, "Eye L", 0, 1, 1);
|
|
5227
|
+
add(import_format6.StandardParameter.EyeOpenRight, "Eye R", 0, 1, 1);
|
|
5051
5228
|
if ([...roles].some((r) => /^(iris|pupil|highlight)_/.test(r))) {
|
|
5052
|
-
add(
|
|
5053
|
-
add(
|
|
5229
|
+
add(import_format6.StandardParameter.EyeballX, "Gaze X", -1, 1, 0);
|
|
5230
|
+
add(import_format6.StandardParameter.EyeballY, "Gaze Y", -1, 1, 0);
|
|
5054
5231
|
}
|
|
5055
|
-
add(
|
|
5056
|
-
add(
|
|
5232
|
+
add(import_format6.StandardParameter.MouthOpen, "Mouth Open", 0, 1, 0);
|
|
5233
|
+
add(import_format6.StandardParameter.MouthForm, "Mouth Form", -1, 1, 0);
|
|
5057
5234
|
if (roles.has("brow_L")) {
|
|
5058
|
-
add(
|
|
5059
|
-
add(
|
|
5235
|
+
add(import_format6.StandardParameter.BrowLeftY, "Brow L Y", -1, 1, 0);
|
|
5236
|
+
add(import_format6.StandardParameter.BrowLeftAngle, "Brow L Angle", -1, 1, 0);
|
|
5060
5237
|
}
|
|
5061
5238
|
if (roles.has("brow_R")) {
|
|
5062
|
-
add(
|
|
5063
|
-
add(
|
|
5239
|
+
add(import_format6.StandardParameter.BrowRightY, "Brow R Y", -1, 1, 0);
|
|
5240
|
+
add(import_format6.StandardParameter.BrowRightAngle, "Brow R Angle", -1, 1, 0);
|
|
5241
|
+
}
|
|
5242
|
+
if (roles.has("blush_L") || roles.has("blush_R")) {
|
|
5243
|
+
add(import_format6.StandardParameter.Cheek, "Cheek", 0, 1, 0);
|
|
5064
5244
|
}
|
|
5065
|
-
add(
|
|
5245
|
+
add(import_format6.StandardParameter.Breath, "Breath", 0, 1, 0);
|
|
5066
5246
|
if (roles.has("hair_front")) {
|
|
5067
|
-
add(
|
|
5068
|
-
add(
|
|
5247
|
+
add(import_format6.StandardParameter.HairSwayX, "Hair Sway X", -SWAY_RANGE, SWAY_RANGE, 0);
|
|
5248
|
+
add(import_format6.StandardParameter.HairSwayZ, "Hair Sway Z", -SWAY_RANGE, SWAY_RANGE, 0);
|
|
5069
5249
|
}
|
|
5070
5250
|
return out;
|
|
5071
5251
|
}
|