@ikijs/editor 0.5.0 → 0.6.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 CHANGED
@@ -92,7 +92,10 @@ is still the furthest out after it turns.
92
92
  It takes **already-decoded** layer geometry (`LayerInput`), never pixels, which
93
93
  is what keeps this package free of any image dependency: the editor app
94
94
  decodes with canvas, `@ikijs/mcp` decodes with `sharp`, and both feed the same
95
- pure function.
95
+ pure function — including the optional `rowHalfWidths` (one entry per crop row,
96
+ half that row's opaque span in canvas px), which `@ikijs/mcp` measures for the
97
+ face so the plate turns on a radius that varies by row; absent, it turns on one
98
+ constant radius.
96
99
 
97
100
  `*_L` / `*_R` are the **character's** sides — `eye_L` is the character's left
98
101
  eye, which appears on the viewer's right.
package/dist/index.d.mts CHANGED
@@ -875,6 +875,19 @@ interface LayerInput {
875
875
  cropW: number;
876
876
  /** Cropped image height = bbox.h. */
877
877
  cropH: number;
878
+ /**
879
+ * The layer's painted half-width on every CROP row, top → bottom, one entry
880
+ * per row (`cropH` of them): half the row's opaque span in canvas px under
881
+ * the same alpha ≥ 128 rule the head's `headEdges` are measured with
882
+ * (`@ikijs/mcp`'s `measure-turn`), 0 for a row with no opaque pixel.
883
+ * Optional, and only the FACE's is read: it gives the face plate a
884
+ * row-dependent turn radius and a chin swing (`faceRowProfile`,
885
+ * `turnSurface`); absent — as the editor's own import leaves it — the plate
886
+ * turns on one radius on every row. Validated before anything reads it: an
887
+ * array of length `cropH` whose every entry is a finite number in
888
+ * [0, cropW / 2], the most an inclusive span inside the crop can be.
889
+ */
890
+ rowHalfWidths?: number[];
878
891
  }
879
892
  /**
880
893
  * Map an array of raw filenames to canonical `{ role, fileName }` pairs.
@@ -983,16 +996,23 @@ interface TurnSolveReport {
983
996
  *
984
997
  * - Validate all inputs before deriving anything.
985
998
  * - Place parts at source-derived positions (bboxToTransform, unshifted).
986
- * - Emit the standard parameters (same ids/ranges as sample-model.ts), plus a
987
- * conditional HairSwayX descriptor + hair-sway physics rig when a hair_front
988
- * layer is present.
999
+ * - Emit the standard parameters (STANDARD_PARAMETERS), plus a conditional
1000
+ * HairSwayX/Z pair + hair-sway physics rigs when a hair_front layer is
1001
+ * present.
1002
+ * - Size every turn group's grid to its own members and the virtual lattice
1003
+ * to those grids, then solve the turn on them (turnSetup, solveTurnModel):
1004
+ * one surface — radius, travel, the head-level nod radius — that every
1005
+ * bake below samples.
989
1006
  * - Build headDeformer (matrix, neck pivot, nod/tilt/breath bindings — the
990
- * turn translates nothing rigidly; its travel is in the face warp),
1007
+ * turn translates nothing rigidly; its travel is in the group grids), one
1008
+ * warp deformer per turn group present — `faceWarp` for the plate,
1009
+ * `eyeWarp_L/R`, `mouthWarp`, `noseWarp`, `browWarp_L/R`, `blushWarp_L/R`
1010
+ * — each a warp2d over its own grid baked from that surface with the
1011
+ * family's solved depth as keyform geometry (bakeTurnGroupWarp2D), and
991
1012
  * bodyDeformer when a body layer is present (matrix, torso-base pivot,
992
- * AngleX follow + Breath follow), and faceWarp (warp, FACE_GRID_CELLS²,
993
- * baked cylinder warp center-relative on faceCenterX).
1013
+ * AngleX follow + Breath follow).
994
1014
  * - Mesh parts (spec.mesh===true) → width:1, height:1, pixel grid mesh sized by
995
- * meshCellsFor + role bindings.
1015
+ * meshCellsFor + role bindings, each face-family part on its group's warp.
996
1016
  * - Static parts (spec.mesh===false) → width:cropW, height:cropH, no mesh.
997
1017
  * - Part ids equal the role string (deterministic, no crypto.randomUUID).
998
1018
  * - Return parseIkiModel(structuredClone(model)) — every caller gets a
package/dist/index.d.ts CHANGED
@@ -875,6 +875,19 @@ interface LayerInput {
875
875
  cropW: number;
876
876
  /** Cropped image height = bbox.h. */
877
877
  cropH: number;
878
+ /**
879
+ * The layer's painted half-width on every CROP row, top → bottom, one entry
880
+ * per row (`cropH` of them): half the row's opaque span in canvas px under
881
+ * the same alpha ≥ 128 rule the head's `headEdges` are measured with
882
+ * (`@ikijs/mcp`'s `measure-turn`), 0 for a row with no opaque pixel.
883
+ * Optional, and only the FACE's is read: it gives the face plate a
884
+ * row-dependent turn radius and a chin swing (`faceRowProfile`,
885
+ * `turnSurface`); absent — as the editor's own import leaves it — the plate
886
+ * turns on one radius on every row. Validated before anything reads it: an
887
+ * array of length `cropH` whose every entry is a finite number in
888
+ * [0, cropW / 2], the most an inclusive span inside the crop can be.
889
+ */
890
+ rowHalfWidths?: number[];
878
891
  }
879
892
  /**
880
893
  * Map an array of raw filenames to canonical `{ role, fileName }` pairs.
@@ -983,16 +996,23 @@ interface TurnSolveReport {
983
996
  *
984
997
  * - Validate all inputs before deriving anything.
985
998
  * - Place parts at source-derived positions (bboxToTransform, unshifted).
986
- * - Emit the standard parameters (same ids/ranges as sample-model.ts), plus a
987
- * conditional HairSwayX descriptor + hair-sway physics rig when a hair_front
988
- * layer is present.
999
+ * - Emit the standard parameters (STANDARD_PARAMETERS), plus a conditional
1000
+ * HairSwayX/Z pair + hair-sway physics rigs when a hair_front layer is
1001
+ * present.
1002
+ * - Size every turn group's grid to its own members and the virtual lattice
1003
+ * to those grids, then solve the turn on them (turnSetup, solveTurnModel):
1004
+ * one surface — radius, travel, the head-level nod radius — that every
1005
+ * bake below samples.
989
1006
  * - Build headDeformer (matrix, neck pivot, nod/tilt/breath bindings — the
990
- * turn translates nothing rigidly; its travel is in the face warp),
1007
+ * turn translates nothing rigidly; its travel is in the group grids), one
1008
+ * warp deformer per turn group present — `faceWarp` for the plate,
1009
+ * `eyeWarp_L/R`, `mouthWarp`, `noseWarp`, `browWarp_L/R`, `blushWarp_L/R`
1010
+ * — each a warp2d over its own grid baked from that surface with the
1011
+ * family's solved depth as keyform geometry (bakeTurnGroupWarp2D), and
991
1012
  * bodyDeformer when a body layer is present (matrix, torso-base pivot,
992
- * AngleX follow + Breath follow), and faceWarp (warp, FACE_GRID_CELLS²,
993
- * baked cylinder warp center-relative on faceCenterX).
1013
+ * AngleX follow + Breath follow).
994
1014
  * - Mesh parts (spec.mesh===true) → width:1, height:1, pixel grid mesh sized by
995
- * meshCellsFor + role bindings.
1015
+ * meshCellsFor + role bindings, each face-family part on its group's warp.
996
1016
  * - Static parts (spec.mesh===false) → width:cropW, height:cropH, no mesh.
997
1017
  * - Part ids equal the role string (deterministic, no crypto.randomUUID).
998
1018
  * - Return parseIkiModel(structuredClone(model)) — every caller gets a