@ikijs/editor 0.3.0 → 0.4.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
@@ -1900,8 +1900,58 @@ var HAIR_FRONT_DEPTH = 0.1;
1900
1900
  var HAIR_BACK_DEPTH = -0.08;
1901
1901
  var NOD_TRAVEL = 30;
1902
1902
  var NOD_BEND = 0.5;
1903
- var HAIR_BACK_NOD_DEPTH = -0.07;
1903
+ var HAIR_BACK_NOD_DEPTH = -0.135;
1904
+ function headNodParallaxUnit(gridHalfHeight) {
1905
+ return gridHalfHeight * HEAD_CYLINDER_RADIUS_FACTOR * Math.sin(HEAD_TURN_MAX_DEG * NOD_BEND * (Math.PI / 180));
1906
+ }
1907
+ var FEATURE_DEPTH = {
1908
+ eye: 0.04,
1909
+ iris: 0.04,
1910
+ pupil: 0.04,
1911
+ highlight: 0.04,
1912
+ lash: 0.04,
1913
+ brow: 0.04,
1914
+ blush: 0.04,
1915
+ mouth: 0.04,
1916
+ mouth_open: 0.04,
1917
+ nose: 0.08
1918
+ };
1919
+ var HAIR_FRONT_NOD_DEPTH = FEATURE_DEPTH.brow;
1920
+ function roleFamily(role) {
1921
+ return role.replace(/_[LR]$/, "");
1922
+ }
1923
+ function featureParallaxBindings(role, options) {
1924
+ if (!options.hasNose) return [];
1925
+ const depth = FEATURE_DEPTH[roleFamily(role)];
1926
+ if (depth === void 0) return [];
1927
+ const bindings = [];
1928
+ const shiftX = depth * (options.parallaxUnit ?? 0);
1929
+ if (shiftX !== 0) {
1930
+ bindings.push({
1931
+ parameter: import_format3.StandardParameter.AngleX,
1932
+ channel: "translateX",
1933
+ from: -shiftX,
1934
+ to: shiftX
1935
+ });
1936
+ }
1937
+ const shiftY = depth * (options.parallaxUnitY ?? 0);
1938
+ if (shiftY !== 0) {
1939
+ bindings.push({
1940
+ parameter: import_format3.StandardParameter.AngleY,
1941
+ channel: "translateY",
1942
+ from: -shiftY,
1943
+ to: shiftY
1944
+ });
1945
+ }
1946
+ return bindings;
1947
+ }
1904
1948
  function bindingsForRole(spec, role, cropW, cropH, options = {}) {
1949
+ return [
1950
+ ...roleOwnBindings(spec, role, cropW, cropH, options),
1951
+ ...featureParallaxBindings(role, options)
1952
+ ];
1953
+ }
1954
+ function roleOwnBindings(spec, role, cropW, cropH, options) {
1905
1955
  const isEyeStack = EYE_STACK_PREFIXES.some((p) => role.startsWith(p));
1906
1956
  if (isEyeStack && spec.eyeSide !== void 0) {
1907
1957
  const isGazeRole = role.startsWith("iris_") || role.startsWith("pupil_") || role.startsWith("highlight_");
@@ -2015,7 +2065,8 @@ function bindingsForRole(spec, role, cropW, cropH, options = {}) {
2015
2065
  });
2016
2066
  }
2017
2067
  }
2018
- const shiftY = (isFront ? 0 : HAIR_BACK_NOD_DEPTH) * (options.parallaxUnitY ?? 0);
2068
+ const frontDepth = options.hasNose ? HAIR_FRONT_NOD_DEPTH : 0;
2069
+ const shiftY = (isFront ? frontDepth : HAIR_BACK_NOD_DEPTH) * (options.parallaxUnitY ?? 0);
2019
2070
  if (shiftY !== 0) {
2020
2071
  parallax.push({
2021
2072
  parameter: import_format3.StandardParameter.AngleY,
@@ -2060,14 +2111,18 @@ function bakeHairBackTurnWarp(mesh, parameter) {
2060
2111
  const radius = halfWidth * HAIR_BACK_BEND_RADIUS_FACTOR;
2061
2112
  const bulge = HAIR_BACK_FAR_BULGE * halfWidth;
2062
2113
  const DEG_TO_RAD = Math.PI / 180;
2063
- const keyforms = [-HEAD_TURN_MAX_DEG, 0, HEAD_TURN_MAX_DEG].map((deg) => {
2114
+ const keyforms = HEAD_TURN_STOPS.map((deg) => {
2064
2115
  const theta = deg * DEG_TO_RAD;
2065
2116
  const s = Math.sign(deg);
2117
+ const turnFraction = Math.abs(deg) / HEAD_TURN_MAX_DEG;
2118
+ const fullTheta = s * HEAD_TURN_MAX_DEG * DEG_TO_RAD;
2119
+ const bulgeAtStop = bulge * deg / HEAD_TURN_MAX_DEG;
2066
2120
  const offsets = [];
2067
2121
  for (let i = 0; i < mesh.vertices.length; i += 2) {
2068
2122
  const x = mesh.vertices[i];
2069
2123
  const far = Math.max(0, -s * x / halfWidth);
2070
- offsets.push(pinnedCylinderBend(x, radius, theta) - s * bulge * far, 0);
2124
+ const bend = far > 0 ? turnFraction * pinnedCylinderBend(x, radius, fullTheta) : pinnedCylinderBend(x, radius, theta);
2125
+ offsets.push(bend - bulgeAtStop * far, 0);
2071
2126
  }
2072
2127
  return { value: deg, offsets };
2073
2128
  });
@@ -2107,6 +2162,7 @@ function generateIkiFromLayerSet(layers, canvas) {
2107
2162
  validateLayerInputs(layers, canvas);
2108
2163
  const hasHair = layers.some((l) => l.role === "hair_front");
2109
2164
  const hasMouthOpen = layers.some((l) => l.role === "mouth_open");
2165
+ const hasNose = layers.some((l) => l.role === "nose");
2110
2166
  const bodyLayer = layers.find((l) => l.role === "body");
2111
2167
  const parameters = [
2112
2168
  {
@@ -2285,7 +2341,7 @@ function generateIkiFromLayerSet(layers, canvas) {
2285
2341
  const faceCenterY = faceTransform.y;
2286
2342
  const halfH = Math.max(faceCenterY - unionMinY, unionMaxY - faceCenterY);
2287
2343
  const parallaxUnit = headTurnParallaxUnit(halfW);
2288
- const parallaxUnitY = headTurnParallaxUnit(halfH);
2344
+ const parallaxUnitY = headNodParallaxUnit(halfH);
2289
2345
  const faceBottom = faceTransform.y - faceCropH / 2;
2290
2346
  const neckPivot = {
2291
2347
  x: faceCenterX,
@@ -2406,7 +2462,8 @@ function generateIkiFromLayerSet(layers, canvas) {
2406
2462
  const roleBindings = bindingsForRole(spec, role, cropW, cropH, {
2407
2463
  hasMouthOpen,
2408
2464
  parallaxUnit,
2409
- parallaxUnitY
2465
+ parallaxUnitY,
2466
+ hasNose
2410
2467
  });
2411
2468
  const deformerId = spec.deformer === "none" ? void 0 : spec.deformer;
2412
2469
  if (spec.mesh) {