@ikijs/editor 0.12.2 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1890,14 +1890,155 @@ function createDefaultWarpDeformer(model) {
1890
1890
  };
1891
1891
  }
1892
1892
 
1893
+ // src/auto-rig/profile.ts
1894
+ var PROFILE_VALUES = {
1895
+ slide: 0.12,
1896
+ lead: 0.1,
1897
+ noseDepth: 2,
1898
+ hairFollow: 1,
1899
+ fore: 0.2,
1900
+ backShare: 0.1,
1901
+ earFar: 0.5,
1902
+ nodDown: 0.18,
1903
+ nodUp: 0.1,
1904
+ nodLead: 0.06,
1905
+ chinShare: 0.75,
1906
+ rollDeg: 14,
1907
+ gaze: 0.2,
1908
+ blink: 0.6,
1909
+ mouthOpen: 0.8,
1910
+ mouthWiden: 1.2,
1911
+ brow: 0.15,
1912
+ breath: 0.03,
1913
+ sway: 0.08
1914
+ };
1915
+ function deriveProfile(v) {
1916
+ const farLead = v.lead * (1 - v.fore / 2);
1917
+ const nearLead = v.lead * (1 + v.fore / 2);
1918
+ const turn = {
1919
+ /** The face plate's translation. */
1920
+ face: v.slide,
1921
+ /** The chin tip's lead over the plate. */
1922
+ chinLead: v.lead,
1923
+ /** The plate's width at full turn: eye and cheek rows, then the jaw. The
1924
+ * plate translates; it does not narrow. */
1925
+ widthUpper: 1,
1926
+ widthJaw: 1,
1927
+ eyeFar: v.slide + farLead,
1928
+ eyeNear: v.slide + nearLead,
1929
+ /** Each eye's width at full turn, about its own centre. */
1930
+ eyeFarScale: 1 - v.fore,
1931
+ eyeNearScale: 1 + v.fore / 2,
1932
+ browFar: v.slide + farLead,
1933
+ browNear: v.slide + nearLead,
1934
+ nose: v.slide + v.noseDepth * v.lead,
1935
+ mouth: v.slide + v.lead,
1936
+ mouthWidth: 1,
1937
+ /** The mouth's far corner rises (its near end drops) by this much: it
1938
+ * stays level. */
1939
+ mouthTiltDeg: 0,
1940
+ /** The front hair (bangs and side locks) rides the face at this share of
1941
+ * its translation. */
1942
+ hairFollow: v.hairFollow,
1943
+ /** The head's outline at the eye row holds: where the front hair draws
1944
+ * it, its outer edge follows the face this much on a row where no back
1945
+ * hair paints behind that edge. Where back hair does, the edge rides
1946
+ * further, as far as that back hair stays behind it through the turn and
1947
+ * the nod, up to the face's follow there (`hairFollow`; over the far
1948
+ * eye's rows, as far as that eye's outer corner goes). On the cap (the
1949
+ * rows above the eyes) it follows less where the turn would otherwise
1950
+ * carry it further outside its back hair than the nod alone does. */
1951
+ outlineFollow: 0,
1952
+ /** The back hair's slight counter-motion. */
1953
+ hairBack: -v.backShare * v.slide,
1954
+ /** The ears lag the plate: the far one's outer edge moves this share of
1955
+ * its slide; the near one rides the head. */
1956
+ earFar: v.earFar,
1957
+ earNear: 1,
1958
+ /** The far ear's width at full turn, about its outer edge, where the head
1959
+ * leaves it room; less where it does not. */
1960
+ earFarScale: 1 - v.fore
1961
+ };
1962
+ const mid = v.nodDown * (1 + v.chinShare) / 2;
1963
+ const feature = (depth) => ({
1964
+ up: -(v.nodUp + depth * v.nodLead),
1965
+ down: mid + depth * v.nodLead
1966
+ });
1967
+ const nod = {
1968
+ faceTop: { up: -v.nodUp, down: v.nodDown },
1969
+ chin: { up: -v.nodUp, down: v.chinShare * v.nodDown },
1970
+ eye: feature(1),
1971
+ /** Eye height at the extreme, about the eye's centre: it holds. */
1972
+ eyeHeight: { up: 1, down: 1 },
1973
+ brow: feature(1),
1974
+ nose: feature(v.noseDepth),
1975
+ mouth: feature(1),
1976
+ hairFront: { up: -v.hairFollow * v.nodUp, down: v.hairFollow * v.nodDown },
1977
+ /** The front hair's cap top: half the plate's rise looking up; looking
1978
+ * down the plate's top, which the rig slides only as far as the back
1979
+ * hair covers the crown behind it. */
1980
+ hairFrontTop: { up: -v.nodUp / 2, down: v.nodDown },
1981
+ hairBack: { up: -v.backShare * v.nodUp, down: v.backShare * v.nodDown }
1982
+ };
1983
+ const amplitude = {
1984
+ /** Iris travel, in iris widths. */
1985
+ gazeX: v.gaze,
1986
+ gazeY: v.gaze / 2,
1987
+ /** How far the upper lid comes down, over the eye's height. */
1988
+ blink: v.blink,
1989
+ /** A single mouth drawing opens to this height over its rest width. */
1990
+ mouthOpenHeight: v.mouthOpen,
1991
+ /** The mouth widens this much open. */
1992
+ mouthOpenWidth: v.mouthWiden,
1993
+ /** Brow raise / lower, hh. */
1994
+ brow: v.brow,
1995
+ /** Breath lifts the shoulders and the head, hh. */
1996
+ breathBody: v.breath,
1997
+ breathHead: v.breath * 2 / 3,
1998
+ /** Hair tip travel at full sway (±20), hh. */
1999
+ sway: v.sway,
2000
+ /** The neck under the face reaches this far above the jaw, hh — what the
2001
+ * chin uncovers as it slides off it: half again the chin's full-turn
2002
+ * slide, to the next 0.05. */
2003
+ hiddenNeck: Math.ceil(30 * (v.slide + v.lead) - 1e-9) / 20
2004
+ };
2005
+ return { TURN: turn, NOD: nod, ROLL_DEG: v.rollDeg, AMPLITUDE: amplitude };
2006
+ }
2007
+ var { TURN, NOD, ROLL_DEG, AMPLITUDE } = deriveProfile(PROFILE_VALUES);
2008
+ var STYLE_KNOBS = [
2009
+ "turn",
2010
+ "featureLead",
2011
+ "hairFollow",
2012
+ "outlineFollow",
2013
+ "blink",
2014
+ "sway"
2015
+ ];
2016
+ function resolveStyle(style, check) {
2017
+ const s = style ?? {};
2018
+ const get = (key, def, lo, hi) => s[key] === void 0 ? def : check(`style.${key}`, s[key], lo, hi);
2019
+ return {
2020
+ turn: get("turn", 1, 0, 3),
2021
+ featureLead: get("featureLead", 1, 0, 3),
2022
+ hairFollow: get("hairFollow", TURN.hairFollow, 0, 2),
2023
+ outlineFollow: get("outlineFollow", TURN.outlineFollow, 0, 2),
2024
+ blink: get("blink", AMPLITUDE.blink, 0.1, 1),
2025
+ sway: get("sway", 1, 0, 5)
2026
+ };
2027
+ }
2028
+
1893
2029
  // src/auto-rig/types.ts
2030
+ var round2 = (v) => Math.round(v * 100) / 100;
1894
2031
  var TurnTargetError = class extends Error {
1895
2032
  constructor(message) {
1896
2033
  super(message);
1897
2034
  this.name = "TurnTargetError";
1898
2035
  }
1899
2036
  };
1900
- var DEFAULT_TURN_TARGETS = Object.freeze({ eyeShift: 0.22, farEyeRatio: 0.78, silhouetteRatio: 1 });
2037
+ var DEFAULT_TURN_TARGETS = Object.freeze({
2038
+ eyeShift: round2((TURN.eyeFar + TURN.eyeNear) / 2 - TURN.hairBack),
2039
+ farEyeRatio: round2(TURN.eyeFarScale / TURN.eyeNearScale),
2040
+ silhouetteRatio: 1
2041
+ });
1901
2042
 
1902
2043
  // src/auto-rig/roles.ts
1903
2044
  var ROLE_TABLE = [
@@ -1917,6 +2058,8 @@ var ROLE_TABLE = [
1917
2058
  { role: "pupil_R", family: "eye_R" },
1918
2059
  { role: "highlight_L", family: "eye_L" },
1919
2060
  { role: "highlight_R", family: "eye_R" },
2061
+ { role: "lash_lower_L", family: "eye_L" },
2062
+ { role: "lash_lower_R", family: "eye_R" },
1920
2063
  { role: "lash_L", family: "eye_L" },
1921
2064
  { role: "lash_R", family: "eye_R" },
1922
2065
  { role: "brow_L", family: "brow_L" },
@@ -2358,117 +2501,6 @@ function land(l, offsets, x, y) {
2358
2501
  return [topX + (botX - topX) * t, topY + (botY - topY) * t];
2359
2502
  }
2360
2503
 
2361
- // src/auto-rig/profile.ts
2362
- var HH_PER_EYE_TO_CHIN = 1.017;
2363
- var TURN = {
2364
- /** The face plate's translation (its cheek edges, 0.118 / 0.126). */
2365
- face: 0.118,
2366
- /** The chin tip's lead over the plate (it moves 0.194). */
2367
- chinLead: 0.076,
2368
- /** The plate's width at full turn: eye and cheek rows, then the jaw. */
2369
- widthUpper: 0.985,
2370
- widthJaw: 0.96,
2371
- eyeFar: 0.192,
2372
- eyeNear: 0.23,
2373
- /** Each eye's width at full turn, about its own centre. */
2374
- eyeFarScale: 0.85,
2375
- eyeNearScale: 1.085,
2376
- browFar: 0.213,
2377
- browNear: 0.243,
2378
- nose: 0.301,
2379
- mouth: 0.213,
2380
- mouthWidth: 0.975,
2381
- /** The mouth's far corner rises (its near end drops) by this much. */
2382
- mouthTiltDeg: 4.4,
2383
- /** The front hair (bangs and side locks) rides the face at this share of
2384
- * its translation (bangs 1.18×, side locks at the eye row ≈ 1.0×). */
2385
- hairFollow: 1.1,
2386
- /** The head's outline at the eye row holds (−0.014 / −0.004 hh): where the
2387
- * front hair draws it, its outer edge follows the face this much on a row
2388
- * where no back hair paints behind that edge. Where back hair does, the
2389
- * edge rides further, as far as that back hair stays behind it through
2390
- * the turn and the nod, up to the face's follow there (`hairFollow`;
2391
- * over the far eye's rows, as far as that eye's outer corner goes). On
2392
- * the cap (the rows above the eyes) it follows less where the turn would
2393
- * otherwise carry it further outside its back hair than the nod alone
2394
- * does. */
2395
- outlineFollow: 0,
2396
- /** The back hair's slight counter-motion. */
2397
- hairBack: -0.027,
2398
- /** The ears lag the plate: the far one's outer edge moves this share of
2399
- * its slide, the near one this at its widest reach, its root riding the
2400
- * head (the samples' parallax ratios, 0.44 and 0.87). */
2401
- earFar: 0.44,
2402
- earNear: 0.87,
2403
- /** The far ear's width at full turn, about its outer edge, where the head
2404
- * leaves it room (the samples' median: Haru 0.81 / 0.91, Hiyori 0.90 /
2405
- * 0.85, Mao 0.77 / 0.79; none fades); less where it does not. */
2406
- earFarScale: 0.83
2407
- };
2408
- var NOD = {
2409
- faceTop: { up: -0.081, down: 0.178 },
2410
- chin: { up: -0.0875, down: 0.109 },
2411
- eye: { up: -0.167, down: 0.202 },
2412
- /** Eye height at the extreme, about the eye's centre. */
2413
- eyeHeight: { up: 0.994, down: 0.96 },
2414
- brow: { up: -0.167, down: 0.223 },
2415
- nose: { up: -0.207, down: 0.193 },
2416
- mouth: { up: -0.172, down: 0.177 },
2417
- hairFront: { up: -0.11, down: 0.189 },
2418
- /** The front hair's cap top. The samples' cap top moves 1.215× their face's
2419
- * centroid looking down (Mao 1.236, Haru 1.626, Hiyori 1.194, Natori
2420
- * 0.730) and 0.415× looking up (0.385, 0.430, 0.400, 0.487); each ratio
2421
- * times the plate's own nod halfway between its top and the chin (0.1435
2422
- * down, 0.084 up). Looking down, the rig slides it only as far as the
2423
- * back hair covers the crown behind it. */
2424
- hairFrontTop: { up: -0.035, down: 0.174 },
2425
- hairBack: { up: -0.011, down: 0.025 }
2426
- };
2427
- var ROLL_DEG = 10;
2428
- var AMPLITUDE = {
2429
- /** Iris travel, in iris widths (X 0.045 hh, Y 0.031 hh on the samples). */
2430
- gazeX: 0.17,
2431
- gazeY: 0.11,
2432
- /** How far the upper lid comes down, over the eye's height (Haru 0.30,
2433
- * Mao 0.58, Hiyori 0.67). */
2434
- blink: 0.58,
2435
- /** A single mouth drawing opens to this height over its rest width. */
2436
- mouthOpenHeight: 0.77,
2437
- /** The mouth widens this much open. */
2438
- mouthOpenWidth: 1.15,
2439
- /** Brow raise / lower, hh. */
2440
- brow: 0.089,
2441
- /** Breath lifts the shoulders and the head, hh. */
2442
- breathBody: 0.025,
2443
- breathHead: 0.016,
2444
- /** Hair tip travel at full sway (±20), hh (the keyform ranges at ±1 have a
2445
- * median of 0.05–0.06 hh). */
2446
- sway: 0.06,
2447
- /** The neck under the face reaches this far above the jaw, hh — what the
2448
- * chin uncovers as it slides off it. */
2449
- hiddenNeck: 0.3
2450
- };
2451
- var STYLE_KNOBS = [
2452
- "turn",
2453
- "featureLead",
2454
- "hairFollow",
2455
- "outlineFollow",
2456
- "blink",
2457
- "sway"
2458
- ];
2459
- function resolveStyle(style, check) {
2460
- const s = style ?? {};
2461
- const get = (key, def, lo, hi) => s[key] === void 0 ? def : check(`style.${key}`, s[key], lo, hi);
2462
- return {
2463
- turn: get("turn", 1, 0, 3),
2464
- featureLead: get("featureLead", 1, 0, 3),
2465
- hairFollow: get("hairFollow", TURN.hairFollow, 0, 2),
2466
- outlineFollow: get("outlineFollow", TURN.outlineFollow, 0, 2),
2467
- blink: get("blink", AMPLITUDE.blink, 0.1, 1),
2468
- sway: get("sway", 1, 0, 5)
2469
- };
2470
- }
2471
-
2472
2504
  // src/auto-rig/head.ts
2473
2505
  function outerEdge(runs, axisX, side) {
2474
2506
  if (runs.length === 0) return void 0;
@@ -2681,7 +2713,7 @@ function buildHeadFrame(layers, opts) {
2681
2713
  return face.y1;
2682
2714
  };
2683
2715
  const chin = chinY;
2684
- const shade = JAW_SHADE * HH_PER_EYE_TO_CHIN * Math.max(1, eyeY - chin);
2716
+ const shade = JAW_SHADE * Math.max(1, eyeY - chin);
2685
2717
  const reach = opts.chinSlide === void 0 ? nk.waist : clamp(
2686
2718
  nk.waist - opts.chinSlide - CUT_MARGIN - (CUT_LOW + 1),
2687
2719
  0,
@@ -2730,7 +2762,7 @@ function buildHeadFrame(layers, opts) {
2730
2762
  }
2731
2763
  }
2732
2764
  }
2733
- const hh = HH_PER_EYE_TO_CHIN * Math.max(1, eyeY - chinY);
2765
+ const hh = Math.max(1, eyeY - chinY);
2734
2766
  const headHalf = opts.headHalfWidth;
2735
2767
  const hairShell = headHalf !== void 0;
2736
2768
  let shellLeft = axisX - plateHalf;
@@ -4361,12 +4393,12 @@ function motionReach(warps, mesh, box, extra = [0, 0]) {
4361
4393
  }
4362
4394
  return out;
4363
4395
  }
4364
- function blinkFold(param, mesh, eye, travel) {
4396
+ function blinkFold(param, mesh, box, travel, eye = box) {
4365
4397
  const yc = eye.y1 - travel * bh(eye);
4366
4398
  return localWarp(
4367
4399
  param,
4368
4400
  mesh,
4369
- eye,
4401
+ box,
4370
4402
  [0, 1],
4371
4403
  ([, y], v) => v === 1 ? [0, 0] : [0, yc - y]
4372
4404
  );
@@ -4715,6 +4747,10 @@ function buildPart(spec, b, order, frame, byRole, style, frontGrid) {
4715
4747
  case "eye_R":
4716
4748
  warps.push(blinkFold(eyeOpen, mesh, b, style.blink));
4717
4749
  break;
4750
+ case "lash_lower_L":
4751
+ case "lash_lower_R":
4752
+ warps.push(blinkFold(eyeOpen, mesh, b, style.blink, box(`eye_${side}`)));
4753
+ break;
4718
4754
  case "lash_L":
4719
4755
  case "lash_R":
4720
4756
  warps.push(lashFold(eyeOpen, mesh, b, box(`eye_${side}`), style.blink));