@ikijs/editor 0.22.0 → 0.23.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 +1 -1
- package/dist/index.d.mts +91 -35
- package/dist/index.d.ts +91 -35
- package/dist/index.js +117 -32
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +115 -32
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ leaves the document untouched.
|
|
|
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 — 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_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
|
package/dist/index.d.mts
CHANGED
|
@@ -996,14 +996,19 @@ declare function forearmPoseGeometry(layer: LayerInput): ForearmPoseGeometry;
|
|
|
996
996
|
/** The lip set's roles, back to front (`mouth.ts`). */
|
|
997
997
|
declare const LIP_ROLES: readonly ["mouth_inner", "lip_lower", "lip_upper"];
|
|
998
998
|
type LipRole = (typeof LIP_ROLES)[number];
|
|
999
|
+
/** The lip set's optional inside parts, back to front: cut from the interior
|
|
1000
|
+
* and clipped to `mouth_inner` (`mouth.ts`). */
|
|
1001
|
+
declare const LIP_INSIDE_ROLES: readonly ["mouth_tongue", "mouth_teeth"];
|
|
1002
|
+
type LipInsideRole = (typeof LIP_INSIDE_ROLES)[number];
|
|
1003
|
+
declare const isLipInsideRole: (role: string) => role is LipInsideRole;
|
|
999
1004
|
/** The part ids a `role`'s layer becomes, back to front: every one of them
|
|
1000
1005
|
* takes its texture from the layer's crop. Throws on an unknown role. */
|
|
1001
1006
|
declare function partIdsOfRole(role: string): readonly string[];
|
|
1002
1007
|
/**
|
|
1003
1008
|
* Map file names to roles. Throws on an unknown role, a role named twice, a
|
|
1004
1009
|
* required role (`face`, `eye_L`, `eye_R`) missing, no mouth (`mouth`, or the
|
|
1005
|
-
* lip set) or a partial or mixed one,
|
|
1006
|
-
* without its arm.
|
|
1010
|
+
* lip set) or a partial or mixed one, a lip set's inside part without the set,
|
|
1011
|
+
* an arm without a body, or a pose forearm without its arm.
|
|
1007
1012
|
*/
|
|
1008
1013
|
declare function parseLayerRoles(fileNames: string[]): {
|
|
1009
1014
|
role: string;
|
|
@@ -1014,7 +1019,9 @@ declare function parseLayerRoles(fileNames: string[]): {
|
|
|
1014
1019
|
* The lip set: a mouth that folds open the way the eyelid folds shut. Three
|
|
1015
1020
|
* parts, back to front: `mouth_inner` (the interior and the opening's lower
|
|
1016
1021
|
* outline band), `lip_lower` (the lower lip's skin) and `lip_upper` (the upper
|
|
1017
|
-
* lip line and the corner hooks).
|
|
1022
|
+
* lip line and the corner hooks). Between the interior and the skin it may
|
|
1023
|
+
* carry two inside parts, `mouth_tongue` then `mouth_teeth`, cut from the
|
|
1024
|
+
* interior and clipped to it: the rig reads nothing off them but their box.
|
|
1018
1025
|
*
|
|
1019
1026
|
* What the rig reads is the layers' own alpha edges, as exclusive run
|
|
1020
1027
|
* boundaries in model y (+y up; a run of crop rows `[a, b)` is the span
|
|
@@ -1028,20 +1035,40 @@ declare function parseLayerRoles(fileNames: string[]): {
|
|
|
1028
1035
|
* them at rest) and the skin reaches the interior (`Bl >= Bb`; an overlap is
|
|
1029
1036
|
* fine, a gap is not).
|
|
1030
1037
|
*
|
|
1031
|
-
*
|
|
1032
|
-
* `
|
|
1033
|
-
*
|
|
1034
|
-
*
|
|
1035
|
-
*
|
|
1036
|
-
*
|
|
1037
|
-
*
|
|
1038
|
-
*
|
|
1039
|
-
*
|
|
1040
|
-
*
|
|
1041
|
-
*
|
|
1042
|
-
*
|
|
1043
|
-
*
|
|
1044
|
-
*
|
|
1038
|
+
* The line is thinned at every key: its column is squashed toward its bottom
|
|
1039
|
+
* edge by `UPPER_THIN` (`Tu` in the opening, the line's own bottom past it),
|
|
1040
|
+
* one scale per column so the mesh, linear between its rows, keeps that edge
|
|
1041
|
+
* where it was drawn. The thin belongs to the stack above the line's bottom,
|
|
1042
|
+
* not to the line alone: the contract lets the interior reach up inside the
|
|
1043
|
+
* line's ink (`Tu <= T <= lineTop`), and a line thinned over it would uncover
|
|
1044
|
+
* it under its old top, so the interior's rows above `Tu` come down by the
|
|
1045
|
+
* same scale. The fold below acts on the thinned positions.
|
|
1046
|
+
*
|
|
1047
|
+
* MouthOpen 0 folds shut onto a seam, 1 is the art as drawn and thinned (the
|
|
1048
|
+
* widening of `mouthWiden` apart). The line comes down until its bottom edge
|
|
1049
|
+
* is on the seam, the skin until its top is one overlap `w'` up under the
|
|
1050
|
+
* line, and the interior's bottom rides the skin's top, so the band is never
|
|
1051
|
+
* covered. The interior's top closes onto the same edge, `S + w'`: the whole
|
|
1052
|
+
* column scales by `v` about it, so shut its height is zero (a degenerate
|
|
1053
|
+
* triangle draws nothing, at every column and between knots; an inverted
|
|
1054
|
+
* sliver would leak through texture filtering where the line is thin), and
|
|
1055
|
+
* its top sits `w'(1 - v)` above the line's bottom edge, under the line's ink,
|
|
1056
|
+
* so the slit between the line and the skin is always backed. The slit opens
|
|
1057
|
+
* once `v * H > w'(1 - v)`; that dead zone is accepted: lip-sync noise near 0
|
|
1058
|
+
* does not flicker through it.
|
|
1059
|
+
*
|
|
1060
|
+
* Shut, the line is shaped the way an artist draws a closed mouth: from
|
|
1061
|
+
* `END_TAPER_FROM` of the opening's half-width out, each column is squashed
|
|
1062
|
+
* about its thinned centre row, down to `END_TAPER` of its height at the
|
|
1063
|
+
* line's box edge, so the ends taper; the drawn flick past a corner is pulled
|
|
1064
|
+
* toward it (`FLICK_PULL`) and squashed to `FLICK_SQUASH`. Every closed-key
|
|
1065
|
+
* shape is linear in `1 - v`. `w'` therefore follows the shaped line, not the
|
|
1066
|
+
* drawn one: it is measured up from the closed line's bottom edge (which the
|
|
1067
|
+
* taper raises by half the height it takes off) by the stroke `w` (the line's
|
|
1068
|
+
* height at the opening's centre), capped by the column's own ink and thinned
|
|
1069
|
+
* and squashed with the line. The skin's top and the interior's closing point
|
|
1070
|
+
* then stay inside the line's closed ink at every column, the tapered ends
|
|
1071
|
+
* included, and tucked skin never shows above the line.
|
|
1045
1072
|
*
|
|
1046
1073
|
* The seam is the line's drawn bottom edge `Tu` plus one smooth closing
|
|
1047
1074
|
* travel `D`, a cubic in the column index pinned to zero at the opening's two
|
|
@@ -1055,16 +1082,22 @@ declare function parseLayerRoles(fileNames: string[]): {
|
|
|
1055
1082
|
* the travel's depth (the sag), the art's two arcs its shape; the cubic keeps
|
|
1056
1083
|
* an asymmetric mouth's tilt and cannot wobble.
|
|
1057
1084
|
*
|
|
1058
|
-
*
|
|
1059
|
-
* the
|
|
1085
|
+
* The lower lip's columns outside the opening (the corner hooks) do not fold,
|
|
1086
|
+
* the line's are only thinned and shaped (no travel), and the interior's edge
|
|
1087
|
+
* columns read the nearest opening column.
|
|
1088
|
+
*
|
|
1089
|
+
* The inside parts move rigidly per column, after the stack's thin: the teeth
|
|
1090
|
+
* by the line's travel, so they ride under its bottom edge (no taper: the
|
|
1091
|
+
* closed interior clips them away), the tongue by the interior's bottom-edge
|
|
1092
|
+
* travel, so it rides the opening's bottom.
|
|
1060
1093
|
*
|
|
1061
|
-
* Knots: the
|
|
1094
|
+
* Knots: the parts share column knots every `MOUTH_KNOT_PX` plus the
|
|
1062
1095
|
* opening's boundaries `x0`, `x1` and `x1 + 1`, each an integer canvas
|
|
1063
1096
|
* boundary. The fit's x is the column index, which is the mesh's boundary
|
|
1064
1097
|
* position: a knot at boundary `b` samples column `b`, so the mesh renders the
|
|
1065
1098
|
* fit exactly at its knots and the pinned ends render as pinned (`x1` and
|
|
1066
1099
|
* `x1 + 1` both sample the last column; the second sits at its right edge).
|
|
1067
|
-
* The preview
|
|
1100
|
+
* The preview resamples each column through the lip meshes' own landed rows
|
|
1068
1101
|
* (`mouthRestShift`). A part's mesh rounds its local x, so one knot
|
|
1069
1102
|
* reconstructs to slightly different model x per part; the fold therefore
|
|
1070
1103
|
* reads the knot itself, by vertex index, and maps every knot through one rule
|
|
@@ -1093,7 +1126,8 @@ interface OpeningColumn {
|
|
|
1093
1126
|
Bl: number;
|
|
1094
1127
|
/** The interior's span. */
|
|
1095
1128
|
H: number;
|
|
1096
|
-
/** How far the skin tucks up under the line
|
|
1129
|
+
/** How far the skin tucks up under the line shut: inside the thinned,
|
|
1130
|
+
* squashed line's ink. */
|
|
1097
1131
|
overlap: number;
|
|
1098
1132
|
/** Where the lips meet when shut: the line's bottom edge after its smooth
|
|
1099
1133
|
* closing travel. */
|
|
@@ -1110,23 +1144,44 @@ interface Opening {
|
|
|
1110
1144
|
w: number;
|
|
1111
1145
|
/** A column's values; outside `x0..x1`, or in a gap, the nearest one's. */
|
|
1112
1146
|
at(col: number): OpeningColumn;
|
|
1147
|
+
/** The upper line at a column of `lip_upper`, model y: inside the opening
|
|
1148
|
+
* the run the contract reads (`Tu`, `lineTop`) and the closed taper's
|
|
1149
|
+
* squash; past it (the drawn flick) the column's own ink span and
|
|
1150
|
+
* `FLICK_SQUASH`; `undefined` where `lip_upper` has no run. */
|
|
1151
|
+
line(col: number): {
|
|
1152
|
+
bottom: number;
|
|
1153
|
+
top: number;
|
|
1154
|
+
squash: number;
|
|
1155
|
+
} | undefined;
|
|
1113
1156
|
}
|
|
1114
1157
|
declare function mouthOpening(byRole: Map<string, LayerInput>): Opening;
|
|
1115
1158
|
/**
|
|
1116
|
-
* dy of a model-y rest position at pixel column `col` for MouthOpen
|
|
1117
|
-
* (0 shut, 1 as drawn)
|
|
1159
|
+
* `[dx, dy]` of a model-y rest position at pixel column `col` for MouthOpen
|
|
1160
|
+
* `v` (0 shut, 1 as drawn), the thin first at every `v` and the fold on the
|
|
1161
|
+
* thinned position. `lip_upper`'s column is squashed toward its line's bottom;
|
|
1162
|
+
* shut, squashed by its `squash` about the thinned centre row and carried by
|
|
1163
|
+
* the travel, or past the opening (the drawn flick, which now moves too)
|
|
1164
|
+
* squashed and pulled toward the corner. `lip_lower` moves by its travel in
|
|
1165
|
+
* the opening and 0 outside it. `mouth_inner`, its rows above `Tu` thinned,
|
|
1118
1166
|
* scales its column by `v` about `S + w'`, which carries its top and bottom
|
|
1119
1167
|
* edges along the line and the skin and needs no read of its own height.
|
|
1168
|
+
* `mouth_teeth`, its rows above `Tu` thinned, moves by the line's travel and
|
|
1169
|
+
* `mouth_tongue` by the interior's bottom edge's, each one number per column.
|
|
1120
1170
|
*/
|
|
1121
|
-
declare function mouthFold(role: LipRole, opening: Opening): (col: number, y: number, v: number) => number;
|
|
1122
|
-
/** A lip's
|
|
1123
|
-
* for the composer's closed preview:
|
|
1124
|
-
*
|
|
1125
|
-
*
|
|
1126
|
-
*
|
|
1127
|
-
*
|
|
1128
|
-
*
|
|
1129
|
-
|
|
1171
|
+
declare function mouthFold(role: LipRole | LipInsideRole, opening: Opening): (col: number, y: number, v: number) => [number, number];
|
|
1172
|
+
/** A lip's dy at MouthOpen 0 at a canvas pixel `(col, row)` as the mesh
|
|
1173
|
+
* renders it, for the composer's closed preview: read at the pixel's centre
|
|
1174
|
+
* off the STORED offsets (the numbers the `.iki` carries, rounded as
|
|
1175
|
+
* `localWarp` rounds them) of the `columnMesh` triangle containing it — the
|
|
1176
|
+
* cell by knot and row, its triangle by the cell's top-left–bottom-right
|
|
1177
|
+
* diagonal, the three vertices weighted barycentrically. The thin and the
|
|
1178
|
+
* taper move a column's rows by different amounts and the renderer is
|
|
1179
|
+
* linear over a triangle, never bilinear over a cell, so no one row stands
|
|
1180
|
+
* for the column. `undefined` for a pixel centre outside the part's box (the
|
|
1181
|
+
* mesh's domain), which has no field. `byRole` must be the layers as the rig
|
|
1182
|
+
* measures them (the canvas-sized ones): a box measured on a smaller frame
|
|
1183
|
+
* clamps differently, and the knot grid starts at the union's edge. */
|
|
1184
|
+
declare function mouthRestShift(byRole: Map<string, LayerInput>): (role: "lip_upper" | "lip_lower", col: number, row: number) => number | undefined;
|
|
1130
1185
|
|
|
1131
1186
|
/**
|
|
1132
1187
|
* `generateIkiFromLayerSet`: role layers in, a rigged `.iki` out.
|
|
@@ -1147,7 +1202,8 @@ declare function mouthRestShift(byRole: Map<string, LayerInput>): (role: "lip_up
|
|
|
1147
1202
|
* the default expressions and the Nod, Shake and Tilt motions, and
|
|
1148
1203
|
* with a pose forearm the Wave (`animations.ts`). The mouth has two paths,
|
|
1149
1204
|
* chosen by the layers: `mouth` alone stretches, with `mouth_open` it
|
|
1150
|
-
* crossfades; the lip set folds open like the eyelid (`mouth.ts`)
|
|
1205
|
+
* crossfades; the lip set folds open like the eyelid (`mouth.ts`), its
|
|
1206
|
+
* optional `mouth_tongue` and `mouth_teeth` clipped to its interior.
|
|
1151
1207
|
*/
|
|
1152
1208
|
|
|
1153
1209
|
declare function generateIkiFromLayerSet(layers: LayerInput[], canvas: {
|
|
@@ -1545,4 +1601,4 @@ declare function createGridMesh(cols: number, rows: number): IkiMesh;
|
|
|
1545
1601
|
*/
|
|
1546
1602
|
declare function createDefaultWarpDeformer(model: IkiModel): IkiWarpDeformer;
|
|
1547
1603
|
|
|
1548
|
-
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_ROLES, LayerGeometryError, type LayerInput, type LayerSetMeasurement, type LayerSetMeasurer, type LipRole, type Opening, type OpeningColumn, type RgbaLayer, type RigStyle, 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, isSpeckCore, mouthFold, mouthOpening, mouthRestShift, packAtlas, parseLayerRoles, partIdsOfRole, upsertGridKeyform, uvRectFor, validateDeformerDelete, validateDeformerReparent, validatePartAttach };
|
|
1604
|
+
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, type RgbaLayer, type RigStyle, 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, upsertGridKeyform, uvRectFor, validateDeformerDelete, validateDeformerReparent, validatePartAttach };
|
package/dist/index.d.ts
CHANGED
|
@@ -996,14 +996,19 @@ declare function forearmPoseGeometry(layer: LayerInput): ForearmPoseGeometry;
|
|
|
996
996
|
/** The lip set's roles, back to front (`mouth.ts`). */
|
|
997
997
|
declare const LIP_ROLES: readonly ["mouth_inner", "lip_lower", "lip_upper"];
|
|
998
998
|
type LipRole = (typeof LIP_ROLES)[number];
|
|
999
|
+
/** The lip set's optional inside parts, back to front: cut from the interior
|
|
1000
|
+
* and clipped to `mouth_inner` (`mouth.ts`). */
|
|
1001
|
+
declare const LIP_INSIDE_ROLES: readonly ["mouth_tongue", "mouth_teeth"];
|
|
1002
|
+
type LipInsideRole = (typeof LIP_INSIDE_ROLES)[number];
|
|
1003
|
+
declare const isLipInsideRole: (role: string) => role is LipInsideRole;
|
|
999
1004
|
/** The part ids a `role`'s layer becomes, back to front: every one of them
|
|
1000
1005
|
* takes its texture from the layer's crop. Throws on an unknown role. */
|
|
1001
1006
|
declare function partIdsOfRole(role: string): readonly string[];
|
|
1002
1007
|
/**
|
|
1003
1008
|
* Map file names to roles. Throws on an unknown role, a role named twice, a
|
|
1004
1009
|
* required role (`face`, `eye_L`, `eye_R`) missing, no mouth (`mouth`, or the
|
|
1005
|
-
* lip set) or a partial or mixed one,
|
|
1006
|
-
* without its arm.
|
|
1010
|
+
* lip set) or a partial or mixed one, a lip set's inside part without the set,
|
|
1011
|
+
* an arm without a body, or a pose forearm without its arm.
|
|
1007
1012
|
*/
|
|
1008
1013
|
declare function parseLayerRoles(fileNames: string[]): {
|
|
1009
1014
|
role: string;
|
|
@@ -1014,7 +1019,9 @@ declare function parseLayerRoles(fileNames: string[]): {
|
|
|
1014
1019
|
* The lip set: a mouth that folds open the way the eyelid folds shut. Three
|
|
1015
1020
|
* parts, back to front: `mouth_inner` (the interior and the opening's lower
|
|
1016
1021
|
* outline band), `lip_lower` (the lower lip's skin) and `lip_upper` (the upper
|
|
1017
|
-
* lip line and the corner hooks).
|
|
1022
|
+
* lip line and the corner hooks). Between the interior and the skin it may
|
|
1023
|
+
* carry two inside parts, `mouth_tongue` then `mouth_teeth`, cut from the
|
|
1024
|
+
* interior and clipped to it: the rig reads nothing off them but their box.
|
|
1018
1025
|
*
|
|
1019
1026
|
* What the rig reads is the layers' own alpha edges, as exclusive run
|
|
1020
1027
|
* boundaries in model y (+y up; a run of crop rows `[a, b)` is the span
|
|
@@ -1028,20 +1035,40 @@ declare function parseLayerRoles(fileNames: string[]): {
|
|
|
1028
1035
|
* them at rest) and the skin reaches the interior (`Bl >= Bb`; an overlap is
|
|
1029
1036
|
* fine, a gap is not).
|
|
1030
1037
|
*
|
|
1031
|
-
*
|
|
1032
|
-
* `
|
|
1033
|
-
*
|
|
1034
|
-
*
|
|
1035
|
-
*
|
|
1036
|
-
*
|
|
1037
|
-
*
|
|
1038
|
-
*
|
|
1039
|
-
*
|
|
1040
|
-
*
|
|
1041
|
-
*
|
|
1042
|
-
*
|
|
1043
|
-
*
|
|
1044
|
-
*
|
|
1038
|
+
* The line is thinned at every key: its column is squashed toward its bottom
|
|
1039
|
+
* edge by `UPPER_THIN` (`Tu` in the opening, the line's own bottom past it),
|
|
1040
|
+
* one scale per column so the mesh, linear between its rows, keeps that edge
|
|
1041
|
+
* where it was drawn. The thin belongs to the stack above the line's bottom,
|
|
1042
|
+
* not to the line alone: the contract lets the interior reach up inside the
|
|
1043
|
+
* line's ink (`Tu <= T <= lineTop`), and a line thinned over it would uncover
|
|
1044
|
+
* it under its old top, so the interior's rows above `Tu` come down by the
|
|
1045
|
+
* same scale. The fold below acts on the thinned positions.
|
|
1046
|
+
*
|
|
1047
|
+
* MouthOpen 0 folds shut onto a seam, 1 is the art as drawn and thinned (the
|
|
1048
|
+
* widening of `mouthWiden` apart). The line comes down until its bottom edge
|
|
1049
|
+
* is on the seam, the skin until its top is one overlap `w'` up under the
|
|
1050
|
+
* line, and the interior's bottom rides the skin's top, so the band is never
|
|
1051
|
+
* covered. The interior's top closes onto the same edge, `S + w'`: the whole
|
|
1052
|
+
* column scales by `v` about it, so shut its height is zero (a degenerate
|
|
1053
|
+
* triangle draws nothing, at every column and between knots; an inverted
|
|
1054
|
+
* sliver would leak through texture filtering where the line is thin), and
|
|
1055
|
+
* its top sits `w'(1 - v)` above the line's bottom edge, under the line's ink,
|
|
1056
|
+
* so the slit between the line and the skin is always backed. The slit opens
|
|
1057
|
+
* once `v * H > w'(1 - v)`; that dead zone is accepted: lip-sync noise near 0
|
|
1058
|
+
* does not flicker through it.
|
|
1059
|
+
*
|
|
1060
|
+
* Shut, the line is shaped the way an artist draws a closed mouth: from
|
|
1061
|
+
* `END_TAPER_FROM` of the opening's half-width out, each column is squashed
|
|
1062
|
+
* about its thinned centre row, down to `END_TAPER` of its height at the
|
|
1063
|
+
* line's box edge, so the ends taper; the drawn flick past a corner is pulled
|
|
1064
|
+
* toward it (`FLICK_PULL`) and squashed to `FLICK_SQUASH`. Every closed-key
|
|
1065
|
+
* shape is linear in `1 - v`. `w'` therefore follows the shaped line, not the
|
|
1066
|
+
* drawn one: it is measured up from the closed line's bottom edge (which the
|
|
1067
|
+
* taper raises by half the height it takes off) by the stroke `w` (the line's
|
|
1068
|
+
* height at the opening's centre), capped by the column's own ink and thinned
|
|
1069
|
+
* and squashed with the line. The skin's top and the interior's closing point
|
|
1070
|
+
* then stay inside the line's closed ink at every column, the tapered ends
|
|
1071
|
+
* included, and tucked skin never shows above the line.
|
|
1045
1072
|
*
|
|
1046
1073
|
* The seam is the line's drawn bottom edge `Tu` plus one smooth closing
|
|
1047
1074
|
* travel `D`, a cubic in the column index pinned to zero at the opening's two
|
|
@@ -1055,16 +1082,22 @@ declare function parseLayerRoles(fileNames: string[]): {
|
|
|
1055
1082
|
* the travel's depth (the sag), the art's two arcs its shape; the cubic keeps
|
|
1056
1083
|
* an asymmetric mouth's tilt and cannot wobble.
|
|
1057
1084
|
*
|
|
1058
|
-
*
|
|
1059
|
-
* the
|
|
1085
|
+
* The lower lip's columns outside the opening (the corner hooks) do not fold,
|
|
1086
|
+
* the line's are only thinned and shaped (no travel), and the interior's edge
|
|
1087
|
+
* columns read the nearest opening column.
|
|
1088
|
+
*
|
|
1089
|
+
* The inside parts move rigidly per column, after the stack's thin: the teeth
|
|
1090
|
+
* by the line's travel, so they ride under its bottom edge (no taper: the
|
|
1091
|
+
* closed interior clips them away), the tongue by the interior's bottom-edge
|
|
1092
|
+
* travel, so it rides the opening's bottom.
|
|
1060
1093
|
*
|
|
1061
|
-
* Knots: the
|
|
1094
|
+
* Knots: the parts share column knots every `MOUTH_KNOT_PX` plus the
|
|
1062
1095
|
* opening's boundaries `x0`, `x1` and `x1 + 1`, each an integer canvas
|
|
1063
1096
|
* boundary. The fit's x is the column index, which is the mesh's boundary
|
|
1064
1097
|
* position: a knot at boundary `b` samples column `b`, so the mesh renders the
|
|
1065
1098
|
* fit exactly at its knots and the pinned ends render as pinned (`x1` and
|
|
1066
1099
|
* `x1 + 1` both sample the last column; the second sits at its right edge).
|
|
1067
|
-
* The preview
|
|
1100
|
+
* The preview resamples each column through the lip meshes' own landed rows
|
|
1068
1101
|
* (`mouthRestShift`). A part's mesh rounds its local x, so one knot
|
|
1069
1102
|
* reconstructs to slightly different model x per part; the fold therefore
|
|
1070
1103
|
* reads the knot itself, by vertex index, and maps every knot through one rule
|
|
@@ -1093,7 +1126,8 @@ interface OpeningColumn {
|
|
|
1093
1126
|
Bl: number;
|
|
1094
1127
|
/** The interior's span. */
|
|
1095
1128
|
H: number;
|
|
1096
|
-
/** How far the skin tucks up under the line
|
|
1129
|
+
/** How far the skin tucks up under the line shut: inside the thinned,
|
|
1130
|
+
* squashed line's ink. */
|
|
1097
1131
|
overlap: number;
|
|
1098
1132
|
/** Where the lips meet when shut: the line's bottom edge after its smooth
|
|
1099
1133
|
* closing travel. */
|
|
@@ -1110,23 +1144,44 @@ interface Opening {
|
|
|
1110
1144
|
w: number;
|
|
1111
1145
|
/** A column's values; outside `x0..x1`, or in a gap, the nearest one's. */
|
|
1112
1146
|
at(col: number): OpeningColumn;
|
|
1147
|
+
/** The upper line at a column of `lip_upper`, model y: inside the opening
|
|
1148
|
+
* the run the contract reads (`Tu`, `lineTop`) and the closed taper's
|
|
1149
|
+
* squash; past it (the drawn flick) the column's own ink span and
|
|
1150
|
+
* `FLICK_SQUASH`; `undefined` where `lip_upper` has no run. */
|
|
1151
|
+
line(col: number): {
|
|
1152
|
+
bottom: number;
|
|
1153
|
+
top: number;
|
|
1154
|
+
squash: number;
|
|
1155
|
+
} | undefined;
|
|
1113
1156
|
}
|
|
1114
1157
|
declare function mouthOpening(byRole: Map<string, LayerInput>): Opening;
|
|
1115
1158
|
/**
|
|
1116
|
-
* dy of a model-y rest position at pixel column `col` for MouthOpen
|
|
1117
|
-
* (0 shut, 1 as drawn)
|
|
1159
|
+
* `[dx, dy]` of a model-y rest position at pixel column `col` for MouthOpen
|
|
1160
|
+
* `v` (0 shut, 1 as drawn), the thin first at every `v` and the fold on the
|
|
1161
|
+
* thinned position. `lip_upper`'s column is squashed toward its line's bottom;
|
|
1162
|
+
* shut, squashed by its `squash` about the thinned centre row and carried by
|
|
1163
|
+
* the travel, or past the opening (the drawn flick, which now moves too)
|
|
1164
|
+
* squashed and pulled toward the corner. `lip_lower` moves by its travel in
|
|
1165
|
+
* the opening and 0 outside it. `mouth_inner`, its rows above `Tu` thinned,
|
|
1118
1166
|
* scales its column by `v` about `S + w'`, which carries its top and bottom
|
|
1119
1167
|
* edges along the line and the skin and needs no read of its own height.
|
|
1168
|
+
* `mouth_teeth`, its rows above `Tu` thinned, moves by the line's travel and
|
|
1169
|
+
* `mouth_tongue` by the interior's bottom edge's, each one number per column.
|
|
1120
1170
|
*/
|
|
1121
|
-
declare function mouthFold(role: LipRole, opening: Opening): (col: number, y: number, v: number) => number;
|
|
1122
|
-
/** A lip's
|
|
1123
|
-
* for the composer's closed preview:
|
|
1124
|
-
*
|
|
1125
|
-
*
|
|
1126
|
-
*
|
|
1127
|
-
*
|
|
1128
|
-
*
|
|
1129
|
-
|
|
1171
|
+
declare function mouthFold(role: LipRole | LipInsideRole, opening: Opening): (col: number, y: number, v: number) => [number, number];
|
|
1172
|
+
/** A lip's dy at MouthOpen 0 at a canvas pixel `(col, row)` as the mesh
|
|
1173
|
+
* renders it, for the composer's closed preview: read at the pixel's centre
|
|
1174
|
+
* off the STORED offsets (the numbers the `.iki` carries, rounded as
|
|
1175
|
+
* `localWarp` rounds them) of the `columnMesh` triangle containing it — the
|
|
1176
|
+
* cell by knot and row, its triangle by the cell's top-left–bottom-right
|
|
1177
|
+
* diagonal, the three vertices weighted barycentrically. The thin and the
|
|
1178
|
+
* taper move a column's rows by different amounts and the renderer is
|
|
1179
|
+
* linear over a triangle, never bilinear over a cell, so no one row stands
|
|
1180
|
+
* for the column. `undefined` for a pixel centre outside the part's box (the
|
|
1181
|
+
* mesh's domain), which has no field. `byRole` must be the layers as the rig
|
|
1182
|
+
* measures them (the canvas-sized ones): a box measured on a smaller frame
|
|
1183
|
+
* clamps differently, and the knot grid starts at the union's edge. */
|
|
1184
|
+
declare function mouthRestShift(byRole: Map<string, LayerInput>): (role: "lip_upper" | "lip_lower", col: number, row: number) => number | undefined;
|
|
1130
1185
|
|
|
1131
1186
|
/**
|
|
1132
1187
|
* `generateIkiFromLayerSet`: role layers in, a rigged `.iki` out.
|
|
@@ -1147,7 +1202,8 @@ declare function mouthRestShift(byRole: Map<string, LayerInput>): (role: "lip_up
|
|
|
1147
1202
|
* the default expressions and the Nod, Shake and Tilt motions, and
|
|
1148
1203
|
* with a pose forearm the Wave (`animations.ts`). The mouth has two paths,
|
|
1149
1204
|
* chosen by the layers: `mouth` alone stretches, with `mouth_open` it
|
|
1150
|
-
* crossfades; the lip set folds open like the eyelid (`mouth.ts`)
|
|
1205
|
+
* crossfades; the lip set folds open like the eyelid (`mouth.ts`), its
|
|
1206
|
+
* optional `mouth_tongue` and `mouth_teeth` clipped to its interior.
|
|
1151
1207
|
*/
|
|
1152
1208
|
|
|
1153
1209
|
declare function generateIkiFromLayerSet(layers: LayerInput[], canvas: {
|
|
@@ -1545,4 +1601,4 @@ declare function createGridMesh(cols: number, rows: number): IkiMesh;
|
|
|
1545
1601
|
*/
|
|
1546
1602
|
declare function createDefaultWarpDeformer(model: IkiModel): IkiWarpDeformer;
|
|
1547
1603
|
|
|
1548
|
-
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_ROLES, LayerGeometryError, type LayerInput, type LayerSetMeasurement, type LayerSetMeasurer, type LipRole, type Opening, type OpeningColumn, type RgbaLayer, type RigStyle, 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, isSpeckCore, mouthFold, mouthOpening, mouthRestShift, packAtlas, parseLayerRoles, partIdsOfRole, upsertGridKeyform, uvRectFor, validateDeformerDelete, validateDeformerReparent, validatePartAttach };
|
|
1604
|
+
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, type RgbaLayer, type RigStyle, 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, upsertGridKeyform, uvRectFor, validateDeformerDelete, validateDeformerReparent, validatePartAttach };
|