@ikijs/editor 0.28.0 → 0.30.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
@@ -40,24 +40,24 @@ leaves the document untouched.
40
40
 
41
41
  ## API
42
42
 
43
- | Area | Exports |
44
- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
45
- | Document | `EditorDocument`, `EditCommand` |
46
- | Part edits | `AddPart`, `DeletePart`, `SetPartColor`, `SetPartWidth`, `SetPartHeight`, `SetPartOrder`, `SetPartTransform`, `SetPartBindings`, `SetPartMesh`, `SetPartDeformer` |
47
- | Deformer edits | `AddDeformer`, `DeleteDeformer`, `SetDeformerParent`, `SetDeformerTransform`, `SetDeformerBindings`, `SetDeformerPivot` (+ `X`/`Y`), `CaptureGridKeyform` |
48
- | Physics edits | `AddPhysicsRig`, `SetPhysicsRig`, `DeletePhysicsRig` |
49
- | Referential guards | `validateDeformerReparent`, `validateDeformerDelete`, `validatePartAttach` |
50
- | Atlas | `packAtlas`, `uvRectFor`, `ATLAS_PADDING`, `UV_INSET_PX` |
51
- | Grid keyforms | `computeGridOffsets`, `interpolateGridOffsets`, `upsertGridKeyform` |
52
- | Factories | `createDefaultPart`, `createDefaultMatrixDeformer`, `createDefaultWarpDeformer`, `createGridMesh` |
53
- | Pixels | `detectAlphaBbox`, `ALPHA_BBOX_THRESHOLD`, `AlphaBbox`, `ALPHA_OPAQUE`, `HEAD_BAND`, `SPECK_CORE_FRACTION`, `denseCoreOf`, `isSpeckCore`, `foregroundSpan`, `headHalfOf` |
54
- | Auto-rig | `generateIkiFromLayerSet`, `parseLayerRoles`, `partIdsOfRole`, `createLayerSetMeasurer`, `armGeometry`, `ArmGeometry`, `forearmPoseGeometry`, `ForearmPoseGeometry`, `mouthOpening`, `mouthFold`, `mouthRestShift`, `columnRuns`, `LIP_ROLES`, `LipRole`, `Opening`, `OpeningColumn`, `TurnTargets`, `DEFAULT_TURN_TARGETS`, `TurnSolveReport`, `RigPlan`, `RigPlanError`, `RIG_PLAN_FIELDS`, `RigPlanReport`, `RigPatch`, `PatchReport`, `PatchError`, `SHUT_BY`, `LayerGeometryError` |
55
- | Bindings | `captureBindingEndpoint` |
43
+ | Area | Exports |
44
+ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
45
+ | Document | `EditorDocument`, `EditCommand` |
46
+ | Part edits | `AddPart`, `DeletePart`, `SetPartColor`, `SetPartWidth`, `SetPartHeight`, `SetPartOrder`, `SetPartTransform`, `SetPartBindings`, `SetPartMesh`, `SetPartDeformer` |
47
+ | Deformer edits | `AddDeformer`, `DeleteDeformer`, `SetDeformerParent`, `SetDeformerTransform`, `SetDeformerBindings`, `SetDeformerPivot` (+ `X`/`Y`), `CaptureGridKeyform` |
48
+ | Physics edits | `AddPhysicsRig`, `SetPhysicsRig`, `DeletePhysicsRig` |
49
+ | Referential guards | `validateDeformerReparent`, `validateDeformerDelete`, `validatePartAttach` |
50
+ | Atlas | `packAtlas`, `uvRectFor`, `ATLAS_PADDING`, `UV_INSET_PX` |
51
+ | Grid keyforms | `computeGridOffsets`, `interpolateGridOffsets`, `upsertGridKeyform` |
52
+ | Factories | `createDefaultPart`, `createDefaultMatrixDeformer`, `createDefaultWarpDeformer`, `createGridMesh` |
53
+ | Pixels | `detectAlphaBbox`, `ALPHA_BBOX_THRESHOLD`, `AlphaBbox`, `ALPHA_OPAQUE`, `HEAD_BAND`, `SPECK_CORE_FRACTION`, `denseCoreOf`, `isSpeckCore`, `foregroundSpan`, `headHalfOf` |
54
+ | Auto-rig | `generateIkiFromLayerSet`, `parseLayerRoles`, `partIdsOfRole`, `createLayerSetMeasurer`, `armGeometry`, `ArmGeometry`, `forearmPoseGeometry`, `ForearmPoseGeometry`, `mouthOpening`, `mouthFold`, `mouthRestShift`, `columnRuns`, `LIP_ROLES`, `LipRole`, `Opening`, `OpeningColumn`, `TurnTargets`, `DEFAULT_TURN_TARGETS`, `TurnSolveReport`, `HairSideRoom`, `RigPlan`, `RigPlanError`, `RIG_PLAN_FIELDS`, `RigPlanReport`, `RigPatch`, `PatchReport`, `PatchError`, `SHUT_BY`, `LayerGeometryError` |
55
+ | Bindings | `captureBindingEndpoint` |
56
56
 
57
57
  ## Auto-rig
58
58
 
59
59
  `generateIkiFromLayerSet` turns role-named layers (`face`, `eye_L`, `eye_R`,
60
- and `mouth` — or the lip set `mouth_inner`, `lip_lower`, `lip_upper`, which folds open instead of crossfading, with optional `mouth_tongue` / `mouth_teeth` clipped to `mouth_inner` (only with the lip set) — plus optional `iris_*`, `brow_*`, `lash_*`, `lash_lower_*`, `hair_front`, `hair_back`,
60
+ and `mouth` — or the lip set `mouth_inner`, `lip_lower`, `lip_upper`, which folds open instead of crossfading, with optional `mouth_tongue` / `mouth_teeth` clipped to `mouth_inner` (only with the lip set) — plus optional `iris_*`, `brow_*`, `lash_*`, `lash_lower_*`, `hair_front`, `hair_side_*` (with `hair_front`), `hair_back`,
61
61
  `body`, `arm_*`, …) into a rigged model that blinks, gazes, opens its mouth, turns its head over
62
62
  a body warp that breathes, follows the head a little and turns on
63
63
  `ParamBodyAngleX/Y/Z`, and emotes with its brows — including a
@@ -107,7 +107,11 @@ any further than it is painted — best effort, never a refusal. The report's
107
107
  `strandOverlap` gives, per side whose far iris the bangs' run still covers at
108
108
  some far stop, the covered width: how much of the iris's painted row the run
109
109
  covers at the stop where that is largest, in px and head half-widths, next to
110
- how much it covers at rest, and whether the bound held.
110
+ how much it covers at rest, and whether the bound held. With
111
+ side locks the report also carries `hairSide` (`left` / `right`): the far
112
+ lock's `cover` of the head's edge and the far eye's and lash's `tail` against
113
+ the lock, report-only, a metric omitted where it cannot be read and
114
+ `unavailable` for a lock without `rowRuns`.
111
115
  [`AUTO-RIG.md`](./AUTO-RIG.md) describes the model, the fit and the limits.
112
116
 
113
117
  An `eyeShift` you passed that runs past the room the art leaves the far eye —
@@ -157,10 +161,12 @@ rather than its soft feather, and its top edge at its centre x is the bridge top
157
161
  the nose tilts 6° about on the turn, its tip toward the far side; absent, the
158
162
  crop stands in for both. And it takes the optional `rowRuns` (per crop row, the
159
163
  row's alpha ≥ 128 runs as a flat list of canvas columns `[start, end, …]`, each
160
- end exclusive), measured for `face`, `hair_front` and `hair_back` so the turn
161
- and the nod can tell where back hair is painted behind the front hair; absent,
162
- the front hair keeps its outline hold and its crown's ease to the back hair on
163
- the turn, and that ease looking down on the nod.
164
+ end exclusive), measured for `face`, `hair_front`, `hair_back`, `hair_side_L`
165
+ and `hair_side_R` so the turn and the nod can tell where back hair is painted
166
+ behind the front hair and the rig can tell where a side lock first shows under
167
+ the bangs; absent, the front hair keeps its outline hold and its crown's ease
168
+ to the back hair on the turn, and that ease looking down on the nod, while a
169
+ side lock's root band ends a quarter of the way down its box.
164
170
 
165
171
  `createLayerSetMeasurer(canvas)` measures all of it — `rowHalfWidths`,
166
172
  `rowRuns`, `denseCore`, `headHalfWidth`, `headEdges` and `strandEdges` — off
package/dist/index.d.mts CHANGED
@@ -680,7 +680,8 @@ declare function partIdsOfRole(role: string): readonly string[];
680
680
  * Map file names to roles. Throws on an unknown role, a role named twice, a
681
681
  * required role (`face`, `eye_L`, `eye_R`) missing, no mouth (`mouth`, or the
682
682
  * lip set) or a partial or mixed one, a lip set's inside part without the set,
683
- * an arm without a body, or a pose forearm without its arm.
683
+ * an arm without a body, a pose forearm without its arm, or a side lock
684
+ * without the front hair.
684
685
  */
685
686
  declare function parseLayerRoles(fileNames: string[]): {
686
687
  role: string;
@@ -806,18 +807,19 @@ interface LayerInput {
806
807
  cropH: number;
807
808
  /** Face only: half the opaque span of each crop row, canvas px (0 = none). */
808
809
  rowHalfWidths?: number[];
809
- /** `face` / `hair_front` / `hair_back` / `body` / `arm_L` / `arm_R` /
810
- * `forearm_pose_L` / `forearm_pose_R` /
810
+ /** `face` / `hair_front` / `hair_back` / `hair_side_L` / `hair_side_R` /
811
+ * `body` / `arm_L` / `arm_R` / `forearm_pose_L` / `forearm_pose_R` /
811
812
  * `mouth_inner` / `lip_lower` / `lip_upper` only:
812
813
  * per crop row, its opaque (alpha ≥ 128) runs as a flat list of canvas
813
814
  * columns `[start0, end0, start1, end1, …]`, each end exclusive (`[]` for a
814
815
  * row with none). The actual pixels, so a gap in the hair is a gap here:
815
816
  * the turn and the nod read off it where back hair is painted behind the
816
817
  * front hair, and the crown's turn reads the face's so it never bares skin.
817
- * The body's place the hips (where it splits into legs), and an arm's place
818
- * its shoulder and elbow pivots, a pose forearm's its elbow-end pivot, and
819
- * a lip set's place the mouth's opening: the upper line's bottom, the
820
- * interior's span, the skin's top. */
818
+ * A side lock's place where it leaves the bangs, and its edges for the
819
+ * report. The body's place the hips (where it splits into legs), and an
820
+ * arm's place its shoulder and elbow pivots, a pose forearm's its
821
+ * elbow-end pivot, and a lip set's place the mouth's opening: the upper
822
+ * line's bottom, the interior's span, the skin's top. */
821
823
  rowRuns?: number[][];
822
824
  /** Nose only: the tight box of its alpha ≥ 128 pixels, canvas px. */
823
825
  denseCore?: {
@@ -882,8 +884,9 @@ declare class LayerGeometryError extends Error {
882
884
  * silhouette holds its width.
883
885
  *
884
886
  * With no target given the rig renders the profile itself, whatever the cues
885
- * then read on its art (a head whose side locks draw its silhouette, and ride
886
- * the face, reads a smaller eyeShift); a given target is fitted.
887
+ * then read on its art (a head whose front hair or a `hair_side_*` lock draws
888
+ * its silhouette at the eye row, and rides the face, reads a smaller
889
+ * eyeShift); a given target is fitted.
887
890
  */
888
891
  declare const DEFAULT_TURN_TARGETS: Readonly<Required<Pick<TurnTargets, "eyeShift" | "farEyeRatio" | "silhouetteRatio">>>;
889
892
  /** How far each feature family stands in front of the plate, as the depth a
@@ -931,6 +934,61 @@ interface TurnSolveReport {
931
934
  left?: StrandOverlap;
932
935
  right?: StrandOverlap;
933
936
  };
937
+ /** The side locks' room, report only (nothing bounds by it): `left` is the
938
+ * lock on the −x side (the character's `hair_side_R`), `right` the one on
939
+ * +x, found by where its box lies about the head's axis (two locks on one
940
+ * side of the axis: the first role in the role table is reported).
941
+ * Present when a lock is. */
942
+ hairSide?: {
943
+ left?: HairSideRoom;
944
+ right?: HairSideRoom;
945
+ };
946
+ }
947
+ /**
948
+ * How one side lock keeps its room on the turn, measured as the far lock at
949
+ * that side's far stops (−15 and −30 on the −x side, 15 and 30 on +x), px,
950
+ * every x landed through the rendered rig. A number that cannot be read is
951
+ * left out.
952
+ */
953
+ interface HairSideRoom {
954
+ role: "hair_side_L" | "hair_side_R";
955
+ /** The lock's outer edge against the head's edge (the plate's painted
956
+ * edge, with any ear replaced by the head's edge beneath it, the cheek):
957
+ * over the lock's pixel rows that lie on the plate (`face.y0..y1`) and
958
+ * carry a run, and at rest (ParamAngleX 0) have the lock's outer edge at
959
+ * or outside the head's edge, the least over those rows and the far stops
960
+ * of (the lock's outer edge landed − the head's edge landed), signed
961
+ * outward: positive, the lock still covers the edge; negative, the turn
962
+ * bares cheek the lock hides at rest. `deg` is the stop and `y` the model
963
+ * row where it is least; `rest` is that row's cover at rest (≥ 0; the
964
+ * geometry's outer edge − the head's half-width, not a landed value). The
965
+ * far lock can gain cover, so `px` may exceed `rest`. Omitted when no
966
+ * lock row covers the head's edge at rest. */
967
+ cover?: {
968
+ deg: number;
969
+ px: number;
970
+ y: number;
971
+ rest: number;
972
+ };
973
+ /** The far eye's outer tail on the eye's centre row, at the stop where
974
+ * `eyeToLock` is least. `eyeToLock`: the eye white's outer corner landed
975
+ * vs the lock's face-side edge landed there (the inner end of the run
976
+ * holding its outer edge), signed toward the face: positive, a gap;
977
+ * negative, the corner is under the lock by that much (intended).
978
+ * `lashToLock`: the lash box's outer x, landed on the eye's centre row
979
+ * too, against the same lock edge, when a `lash_*` is present.
980
+ * `eyeToPlate`: the head's edge (as for `cover`: under an ear, the head's
981
+ * own) landed minus the eye's corner landed, signed toward the face: how
982
+ * far inside the head the corner sits. Omitted when the lock has
983
+ * no run on the eye's centre row. */
984
+ tail?: {
985
+ deg: number;
986
+ eyeToLock: number;
987
+ lashToLock?: number;
988
+ eyeToPlate: number;
989
+ };
990
+ /** The lock carries no `rowRuns`: nothing else is reported. */
991
+ unavailable?: string;
934
992
  }
935
993
  /**
936
994
  * One `displace` op of the rig patch layer: a displacement ADDED to one
@@ -1762,4 +1820,4 @@ declare function createGridMesh(cols: number, rows: number): IkiMesh;
1762
1820
  */
1763
1821
  declare function createDefaultWarpDeformer(model: IkiModel): IkiWarpDeformer;
1764
1822
 
1765
- export { ALPHA_BBOX_THRESHOLD, ALPHA_OPAQUE, ATLAS_PADDING, AddDeformer, AddPart, AddPhysicsRig, type AlphaBbox, type ApplyAtlasInput, type ArmGeometry, type AtlasAssignment, type AtlasLayout, type AtlasPlacement, type AtlasSource, CaptureGridKeyform, DEFAULT_TURN_TARGETS, type DeformerTransformChannel, DeleteDeformer, DeletePart, DeletePhysicsRig, type EditCommand, type EditTransformChannel, EditorDocument, type ForearmPoseGeometry, HEAD_BAND, type IrisStrand, LIP_INSIDE_ROLES, LIP_ROLES, LayerGeometryError, type LayerInput, type LayerSetMeasurement, type LayerSetMeasurer, type LipInsideRole, type LipRole, type Opening, type OpeningColumn, PatchError, type PatchReport, RIG_PLAN_FIELDS, type RgbaLayer, type RigPatch, type RigPlan, RigPlanError, type RigPlanField, type RigPlanReport, SHUT_BY, SPECK_CORE_FRACTION, SetDeformerBindings, SetDeformerParent, SetDeformerPivot, SetDeformerPivotX, SetDeformerPivotY, SetDeformerTransform, SetPartBindings, SetPartColor, SetPartDeformer, SetPartHeight, SetPartMesh, SetPartOrder, SetPartTransform, SetPartWidth, SetPhysicsRig, type StrandOverlap, type TurnDepths, type TurnSolveReport, TurnTargetError, type TurnTargets, UV_INSET_PX, armGeometry, captureBindingEndpoint, columnRuns, computeGridOffsets, createDefaultMatrixDeformer, createDefaultPart, createDefaultWarpDeformer, createGridMesh, createLayerSetMeasurer, denseCoreOf, detectAlphaBbox, forearmPoseGeometry, foregroundSpan, generateIkiFromLayerSet, headHalfOf, interpolateGridOffsets, isLipInsideRole, isSpeckCore, mouthFold, mouthOpening, mouthRestShift, packAtlas, parseLayerRoles, partIdsOfRole, styleRemovedMessage, upsertGridKeyform, uvRectFor, validateDeformerDelete, validateDeformerReparent, validatePartAttach };
1823
+ export { ALPHA_BBOX_THRESHOLD, ALPHA_OPAQUE, ATLAS_PADDING, AddDeformer, AddPart, AddPhysicsRig, type AlphaBbox, type ApplyAtlasInput, type ArmGeometry, type AtlasAssignment, type AtlasLayout, type AtlasPlacement, type AtlasSource, CaptureGridKeyform, DEFAULT_TURN_TARGETS, type DeformerTransformChannel, DeleteDeformer, DeletePart, DeletePhysicsRig, type EditCommand, type EditTransformChannel, EditorDocument, type ForearmPoseGeometry, HEAD_BAND, type HairSideRoom, type IrisStrand, LIP_INSIDE_ROLES, LIP_ROLES, LayerGeometryError, type LayerInput, type LayerSetMeasurement, type LayerSetMeasurer, type LipInsideRole, type LipRole, type Opening, type OpeningColumn, PatchError, type PatchReport, RIG_PLAN_FIELDS, type RgbaLayer, type RigPatch, type RigPlan, RigPlanError, type RigPlanField, type RigPlanReport, SHUT_BY, SPECK_CORE_FRACTION, SetDeformerBindings, SetDeformerParent, SetDeformerPivot, SetDeformerPivotX, SetDeformerPivotY, SetDeformerTransform, SetPartBindings, SetPartColor, SetPartDeformer, SetPartHeight, SetPartMesh, SetPartOrder, SetPartTransform, SetPartWidth, SetPhysicsRig, type StrandOverlap, type TurnDepths, type TurnSolveReport, TurnTargetError, type TurnTargets, UV_INSET_PX, armGeometry, captureBindingEndpoint, columnRuns, computeGridOffsets, createDefaultMatrixDeformer, createDefaultPart, createDefaultWarpDeformer, createGridMesh, createLayerSetMeasurer, denseCoreOf, detectAlphaBbox, forearmPoseGeometry, foregroundSpan, generateIkiFromLayerSet, headHalfOf, interpolateGridOffsets, isLipInsideRole, isSpeckCore, mouthFold, mouthOpening, mouthRestShift, packAtlas, parseLayerRoles, partIdsOfRole, styleRemovedMessage, upsertGridKeyform, uvRectFor, validateDeformerDelete, validateDeformerReparent, validatePartAttach };
package/dist/index.d.ts CHANGED
@@ -680,7 +680,8 @@ declare function partIdsOfRole(role: string): readonly string[];
680
680
  * Map file names to roles. Throws on an unknown role, a role named twice, a
681
681
  * required role (`face`, `eye_L`, `eye_R`) missing, no mouth (`mouth`, or the
682
682
  * lip set) or a partial or mixed one, a lip set's inside part without the set,
683
- * an arm without a body, or a pose forearm without its arm.
683
+ * an arm without a body, a pose forearm without its arm, or a side lock
684
+ * without the front hair.
684
685
  */
685
686
  declare function parseLayerRoles(fileNames: string[]): {
686
687
  role: string;
@@ -806,18 +807,19 @@ interface LayerInput {
806
807
  cropH: number;
807
808
  /** Face only: half the opaque span of each crop row, canvas px (0 = none). */
808
809
  rowHalfWidths?: number[];
809
- /** `face` / `hair_front` / `hair_back` / `body` / `arm_L` / `arm_R` /
810
- * `forearm_pose_L` / `forearm_pose_R` /
810
+ /** `face` / `hair_front` / `hair_back` / `hair_side_L` / `hair_side_R` /
811
+ * `body` / `arm_L` / `arm_R` / `forearm_pose_L` / `forearm_pose_R` /
811
812
  * `mouth_inner` / `lip_lower` / `lip_upper` only:
812
813
  * per crop row, its opaque (alpha ≥ 128) runs as a flat list of canvas
813
814
  * columns `[start0, end0, start1, end1, …]`, each end exclusive (`[]` for a
814
815
  * row with none). The actual pixels, so a gap in the hair is a gap here:
815
816
  * the turn and the nod read off it where back hair is painted behind the
816
817
  * front hair, and the crown's turn reads the face's so it never bares skin.
817
- * The body's place the hips (where it splits into legs), and an arm's place
818
- * its shoulder and elbow pivots, a pose forearm's its elbow-end pivot, and
819
- * a lip set's place the mouth's opening: the upper line's bottom, the
820
- * interior's span, the skin's top. */
818
+ * A side lock's place where it leaves the bangs, and its edges for the
819
+ * report. The body's place the hips (where it splits into legs), and an
820
+ * arm's place its shoulder and elbow pivots, a pose forearm's its
821
+ * elbow-end pivot, and a lip set's place the mouth's opening: the upper
822
+ * line's bottom, the interior's span, the skin's top. */
821
823
  rowRuns?: number[][];
822
824
  /** Nose only: the tight box of its alpha ≥ 128 pixels, canvas px. */
823
825
  denseCore?: {
@@ -882,8 +884,9 @@ declare class LayerGeometryError extends Error {
882
884
  * silhouette holds its width.
883
885
  *
884
886
  * With no target given the rig renders the profile itself, whatever the cues
885
- * then read on its art (a head whose side locks draw its silhouette, and ride
886
- * the face, reads a smaller eyeShift); a given target is fitted.
887
+ * then read on its art (a head whose front hair or a `hair_side_*` lock draws
888
+ * its silhouette at the eye row, and rides the face, reads a smaller
889
+ * eyeShift); a given target is fitted.
887
890
  */
888
891
  declare const DEFAULT_TURN_TARGETS: Readonly<Required<Pick<TurnTargets, "eyeShift" | "farEyeRatio" | "silhouetteRatio">>>;
889
892
  /** How far each feature family stands in front of the plate, as the depth a
@@ -931,6 +934,61 @@ interface TurnSolveReport {
931
934
  left?: StrandOverlap;
932
935
  right?: StrandOverlap;
933
936
  };
937
+ /** The side locks' room, report only (nothing bounds by it): `left` is the
938
+ * lock on the −x side (the character's `hair_side_R`), `right` the one on
939
+ * +x, found by where its box lies about the head's axis (two locks on one
940
+ * side of the axis: the first role in the role table is reported).
941
+ * Present when a lock is. */
942
+ hairSide?: {
943
+ left?: HairSideRoom;
944
+ right?: HairSideRoom;
945
+ };
946
+ }
947
+ /**
948
+ * How one side lock keeps its room on the turn, measured as the far lock at
949
+ * that side's far stops (−15 and −30 on the −x side, 15 and 30 on +x), px,
950
+ * every x landed through the rendered rig. A number that cannot be read is
951
+ * left out.
952
+ */
953
+ interface HairSideRoom {
954
+ role: "hair_side_L" | "hair_side_R";
955
+ /** The lock's outer edge against the head's edge (the plate's painted
956
+ * edge, with any ear replaced by the head's edge beneath it, the cheek):
957
+ * over the lock's pixel rows that lie on the plate (`face.y0..y1`) and
958
+ * carry a run, and at rest (ParamAngleX 0) have the lock's outer edge at
959
+ * or outside the head's edge, the least over those rows and the far stops
960
+ * of (the lock's outer edge landed − the head's edge landed), signed
961
+ * outward: positive, the lock still covers the edge; negative, the turn
962
+ * bares cheek the lock hides at rest. `deg` is the stop and `y` the model
963
+ * row where it is least; `rest` is that row's cover at rest (≥ 0; the
964
+ * geometry's outer edge − the head's half-width, not a landed value). The
965
+ * far lock can gain cover, so `px` may exceed `rest`. Omitted when no
966
+ * lock row covers the head's edge at rest. */
967
+ cover?: {
968
+ deg: number;
969
+ px: number;
970
+ y: number;
971
+ rest: number;
972
+ };
973
+ /** The far eye's outer tail on the eye's centre row, at the stop where
974
+ * `eyeToLock` is least. `eyeToLock`: the eye white's outer corner landed
975
+ * vs the lock's face-side edge landed there (the inner end of the run
976
+ * holding its outer edge), signed toward the face: positive, a gap;
977
+ * negative, the corner is under the lock by that much (intended).
978
+ * `lashToLock`: the lash box's outer x, landed on the eye's centre row
979
+ * too, against the same lock edge, when a `lash_*` is present.
980
+ * `eyeToPlate`: the head's edge (as for `cover`: under an ear, the head's
981
+ * own) landed minus the eye's corner landed, signed toward the face: how
982
+ * far inside the head the corner sits. Omitted when the lock has
983
+ * no run on the eye's centre row. */
984
+ tail?: {
985
+ deg: number;
986
+ eyeToLock: number;
987
+ lashToLock?: number;
988
+ eyeToPlate: number;
989
+ };
990
+ /** The lock carries no `rowRuns`: nothing else is reported. */
991
+ unavailable?: string;
934
992
  }
935
993
  /**
936
994
  * One `displace` op of the rig patch layer: a displacement ADDED to one
@@ -1762,4 +1820,4 @@ declare function createGridMesh(cols: number, rows: number): IkiMesh;
1762
1820
  */
1763
1821
  declare function createDefaultWarpDeformer(model: IkiModel): IkiWarpDeformer;
1764
1822
 
1765
- export { ALPHA_BBOX_THRESHOLD, ALPHA_OPAQUE, ATLAS_PADDING, AddDeformer, AddPart, AddPhysicsRig, type AlphaBbox, type ApplyAtlasInput, type ArmGeometry, type AtlasAssignment, type AtlasLayout, type AtlasPlacement, type AtlasSource, CaptureGridKeyform, DEFAULT_TURN_TARGETS, type DeformerTransformChannel, DeleteDeformer, DeletePart, DeletePhysicsRig, type EditCommand, type EditTransformChannel, EditorDocument, type ForearmPoseGeometry, HEAD_BAND, type IrisStrand, LIP_INSIDE_ROLES, LIP_ROLES, LayerGeometryError, type LayerInput, type LayerSetMeasurement, type LayerSetMeasurer, type LipInsideRole, type LipRole, type Opening, type OpeningColumn, PatchError, type PatchReport, RIG_PLAN_FIELDS, type RgbaLayer, type RigPatch, type RigPlan, RigPlanError, type RigPlanField, type RigPlanReport, SHUT_BY, SPECK_CORE_FRACTION, SetDeformerBindings, SetDeformerParent, SetDeformerPivot, SetDeformerPivotX, SetDeformerPivotY, SetDeformerTransform, SetPartBindings, SetPartColor, SetPartDeformer, SetPartHeight, SetPartMesh, SetPartOrder, SetPartTransform, SetPartWidth, SetPhysicsRig, type StrandOverlap, type TurnDepths, type TurnSolveReport, TurnTargetError, type TurnTargets, UV_INSET_PX, armGeometry, captureBindingEndpoint, columnRuns, computeGridOffsets, createDefaultMatrixDeformer, createDefaultPart, createDefaultWarpDeformer, createGridMesh, createLayerSetMeasurer, denseCoreOf, detectAlphaBbox, forearmPoseGeometry, foregroundSpan, generateIkiFromLayerSet, headHalfOf, interpolateGridOffsets, isLipInsideRole, isSpeckCore, mouthFold, mouthOpening, mouthRestShift, packAtlas, parseLayerRoles, partIdsOfRole, styleRemovedMessage, upsertGridKeyform, uvRectFor, validateDeformerDelete, validateDeformerReparent, validatePartAttach };
1823
+ export { ALPHA_BBOX_THRESHOLD, ALPHA_OPAQUE, ATLAS_PADDING, AddDeformer, AddPart, AddPhysicsRig, type AlphaBbox, type ApplyAtlasInput, type ArmGeometry, type AtlasAssignment, type AtlasLayout, type AtlasPlacement, type AtlasSource, CaptureGridKeyform, DEFAULT_TURN_TARGETS, type DeformerTransformChannel, DeleteDeformer, DeletePart, DeletePhysicsRig, type EditCommand, type EditTransformChannel, EditorDocument, type ForearmPoseGeometry, HEAD_BAND, type HairSideRoom, type IrisStrand, LIP_INSIDE_ROLES, LIP_ROLES, LayerGeometryError, type LayerInput, type LayerSetMeasurement, type LayerSetMeasurer, type LipInsideRole, type LipRole, type Opening, type OpeningColumn, PatchError, type PatchReport, RIG_PLAN_FIELDS, type RgbaLayer, type RigPatch, type RigPlan, RigPlanError, type RigPlanField, type RigPlanReport, SHUT_BY, SPECK_CORE_FRACTION, SetDeformerBindings, SetDeformerParent, SetDeformerPivot, SetDeformerPivotX, SetDeformerPivotY, SetDeformerTransform, SetPartBindings, SetPartColor, SetPartDeformer, SetPartHeight, SetPartMesh, SetPartOrder, SetPartTransform, SetPartWidth, SetPhysicsRig, type StrandOverlap, type TurnDepths, type TurnSolveReport, TurnTargetError, type TurnTargets, UV_INSET_PX, armGeometry, captureBindingEndpoint, columnRuns, computeGridOffsets, createDefaultMatrixDeformer, createDefaultPart, createDefaultWarpDeformer, createGridMesh, createLayerSetMeasurer, denseCoreOf, detectAlphaBbox, forearmPoseGeometry, foregroundSpan, generateIkiFromLayerSet, headHalfOf, interpolateGridOffsets, isLipInsideRole, isSpeckCore, mouthFold, mouthOpening, mouthRestShift, packAtlas, parseLayerRoles, partIdsOfRole, styleRemovedMessage, upsertGridKeyform, uvRectFor, validateDeformerDelete, validateDeformerReparent, validatePartAttach };