@ikijs/editor 0.18.0 → 0.20.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 +20 -16
- package/dist/index.d.mts +106 -34
- package/dist/index.d.ts +106 -34
- package/dist/index.js +376 -132
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +375 -130
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -40,19 +40,19 @@ 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`, `TurnTargets`, `DEFAULT_TURN_TARGETS`, `TurnSolveReport`, `RigStyle`, `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`, `TurnTargets`, `DEFAULT_TURN_TARGETS`, `TurnSolveReport`, `RigStyle`, `LayerGeometryError` |
|
|
55
|
+
| Bindings | `captureBindingEndpoint` |
|
|
56
56
|
|
|
57
57
|
## Auto-rig
|
|
58
58
|
|
|
@@ -82,9 +82,13 @@ it), the ears lag the face, the far one narrowing. AngleZ rolls the head 14° ab
|
|
|
82
82
|
A `body` rides a body warp that breathes, follows the head's turn and tilt a
|
|
83
83
|
little and turns on `ParamBodyAngleX/Y/Z`, its legs planted, and the head
|
|
84
84
|
hangs from it. `arm_L` / `arm_R`, each a whole arm drawn hanging with its
|
|
85
|
-
shoulder at the top, hang from it too: each becomes an
|
|
86
|
-
forearm cut from the one crop, turning about the shoulder and the
|
|
87
|
-
`ParamArmL/R` and `ParamElbowL/R`. An arm needs a `body`.
|
|
85
|
+
shoulder at the top, hang from it too: each becomes an elbow cap, an upper
|
|
86
|
+
arm and a forearm cut from the one crop, turning about the shoulder and the
|
|
87
|
+
elbow on `ParamArmL/R` and `ParamElbowL/R`. An arm needs a `body`.
|
|
88
|
+
`forearm_pose_L` / `forearm_pose_R`, a second forearm drawn raised, swap in for
|
|
89
|
+
the hanging one at the elbow on `ParamArmPoseL/R` and rock on
|
|
90
|
+
`ParamArmPoseAngleL/R`; a model with them also declares a `Wave` motion. A
|
|
91
|
+
pose forearm needs its arm.
|
|
88
92
|
|
|
89
93
|
On a layer set with a `nose`, `options.turnTargets` — the cues a 30° reference
|
|
90
94
|
measures (how far the eye pair slides, how much the far eye foreshortens,
|
package/dist/index.d.mts
CHANGED
|
@@ -713,14 +713,15 @@ interface LayerInput {
|
|
|
713
713
|
cropH: number;
|
|
714
714
|
/** Face only: half the opaque span of each crop row, canvas px (0 = none). */
|
|
715
715
|
rowHalfWidths?: number[];
|
|
716
|
-
/** `face` / `hair_front` / `hair_back` / `body` / `arm_L` / `arm_R`
|
|
716
|
+
/** `face` / `hair_front` / `hair_back` / `body` / `arm_L` / `arm_R` /
|
|
717
|
+
* `forearm_pose_L` / `forearm_pose_R` only:
|
|
717
718
|
* per crop row, its opaque (alpha ≥ 128) runs as a flat list of canvas
|
|
718
719
|
* columns `[start0, end0, start1, end1, …]`, each end exclusive (`[]` for a
|
|
719
720
|
* row with none). The actual pixels, so a gap in the hair is a gap here:
|
|
720
721
|
* the turn and the nod read off it where back hair is painted behind the
|
|
721
722
|
* front hair, and the crown's turn reads the face's so it never bares skin.
|
|
722
723
|
* The body's place the hips (where it splits into legs), and an arm's place
|
|
723
|
-
* its shoulder and elbow pivots. */
|
|
724
|
+
* its shoulder and elbow pivots, a pose forearm's its elbow-end pivot. */
|
|
724
725
|
rowRuns?: number[][];
|
|
725
726
|
/** Nose only: the tight box of its alpha ≥ 128 pixels, canvas px. */
|
|
726
727
|
denseCore?: {
|
|
@@ -857,31 +858,43 @@ interface GenerateOptions {
|
|
|
857
858
|
|
|
858
859
|
/**
|
|
859
860
|
* The arms. Each `arm_L` / `arm_R` layer is one drawing of the whole arm,
|
|
860
|
-
* hanging, its shoulder at the top. It becomes
|
|
861
|
-
* deformers hung from the body warp:
|
|
861
|
+
* hanging, its shoulder at the top. It becomes three parts on two nested
|
|
862
|
+
* matrix deformers hung from the body warp:
|
|
862
863
|
* - the upper arm (the role's own id) on `armDeformer_X`, which turns about
|
|
863
864
|
* the shoulder, the deltoid cap's centre;
|
|
864
865
|
* - the forearm (`forearm_X`) on `forearmDeformer_X`, a child of the arm's,
|
|
865
|
-
* which turns about the elbow
|
|
866
|
+
* which turns about the elbow;
|
|
867
|
+
* - the elbow cap (`elbow_X`), also on `forearmDeformer_X`, drawn behind the
|
|
868
|
+
* upper arm.
|
|
866
869
|
* The shoulder pivot rides an all-weight-1 cell of the body warp (`body.ts`),
|
|
867
870
|
* so the arm breathes and turns with the chest rigidly, never sheared.
|
|
868
871
|
*
|
|
869
|
-
*
|
|
870
|
-
* texture rect
|
|
871
|
-
*
|
|
872
|
-
*
|
|
873
|
-
*
|
|
874
|
-
*
|
|
875
|
-
*
|
|
872
|
+
* All three parts are cut from the one crop: they share its box, transform
|
|
873
|
+
* and texture rect. The upper arm is the band above the seam, the elbow
|
|
874
|
+
* pivot's row; the forearm is the band below it. Iki has no glue between
|
|
875
|
+
* meshes, and two bands hinged at a seam open a wedge as wide as the arm on a
|
|
876
|
+
* bend. The cap fills it: a half-disc fan centred on the elbow pivot turns
|
|
877
|
+
* about its own centre, so it rotates into itself and keeps the joint covered
|
|
878
|
+
* at any bend.
|
|
876
879
|
*
|
|
877
|
-
*
|
|
878
|
-
*
|
|
879
|
-
*
|
|
880
|
+
* Behind the upper arm, the cap shows only where the forearm's bend uncovers
|
|
881
|
+
* it, so it must lie inside the paint at rest, or its edge would show past
|
|
882
|
+
* the arm's. Its boundary is therefore the arm's own contour, not a circle:
|
|
883
|
+
* `armGeometry` walks each of the fan's 13 rays out from the elbow to the
|
|
884
|
+
* contour (`capRays`). A ring at the boundary, `CAP_RIM` wide, takes the UVs
|
|
885
|
+
* of the seam row's edge cross-section swept round the arc, so the exposed
|
|
886
|
+
* wedge carries the painted line, fading out in the antialias column as the
|
|
887
|
+
* painted edge does; the fan inside it is the crop's own pixels.
|
|
880
888
|
*
|
|
881
|
-
*
|
|
882
|
-
*
|
|
883
|
-
*
|
|
884
|
-
*
|
|
889
|
+
* Draw order: hair_back < body < elbow_L, arm_L, forearm_L, elbow_R, arm_R,
|
|
890
|
+
* forearm_R < face … < hair_front. The forearm draws over the upper arm,
|
|
891
|
+
* which draws over the cap.
|
|
892
|
+
*
|
|
893
|
+
* Signs: ParamArmX + raises the arm outward on either side, in degrees 1:1.
|
|
894
|
+
* A rotation is CCW-positive, so an arm whose shoulder lies right of the
|
|
895
|
+
* body's axis (+x, the character's left) turns CCW for +, and one at −x turns
|
|
896
|
+
* CW. ParamElbowX + bends the forearm toward the body, the opposite turn to
|
|
897
|
+
* the shoulder's +: it turns CW on the +x side, CCW on the −x side.
|
|
885
898
|
*/
|
|
886
899
|
|
|
887
900
|
type Point = {
|
|
@@ -895,8 +908,14 @@ interface ArmGeometry {
|
|
|
895
908
|
shoulderRadius: number;
|
|
896
909
|
/** The elbow pivot, model space. Its y is the seam the two meshes meet on. */
|
|
897
910
|
elbow: Point;
|
|
898
|
-
/** The
|
|
911
|
+
/** The elbow cap's largest radius, px. */
|
|
899
912
|
capRadius: number;
|
|
913
|
+
/** The cap's radius on each of its `CAP_SEGMENTS + 1` rays, from the elbow
|
|
914
|
+
* at angles 0..π, px: the walk out to the contour, less `capInset`, at
|
|
915
|
+
* most `capRadius`. */
|
|
916
|
+
capRays: number[];
|
|
917
|
+
/** The seam row's widest run, crop columns [start, end). */
|
|
918
|
+
seamRun: [number, number];
|
|
900
919
|
/** +1 for a shoulder right of the body's axis (+ turns CCW), −1 left of it
|
|
901
920
|
* (+ turns CW). */
|
|
902
921
|
side: 1 | -1;
|
|
@@ -905,12 +924,17 @@ interface ArmGeometry {
|
|
|
905
924
|
* The arm's pivots, read off the widest opaque run of each crop row
|
|
906
925
|
* (`rowRuns`); a row without one, or a layer without runs, reads as the
|
|
907
926
|
* crop:
|
|
908
|
-
* - r_u
|
|
909
|
-
*
|
|
910
|
-
* run centre of the row it lands in;
|
|
927
|
+
* - the shoulder pivot and r_u are `endPivot(layer, "top")`: r_u is half the
|
|
928
|
+
* median width over the `CAP_ROWS` rows, the pivot lies r_u under the first
|
|
929
|
+
* painted row's centre, at the run centre of the row it lands in;
|
|
911
930
|
* - the elbow is the centre of the row `ELBOW_AT` of the way from there to
|
|
912
931
|
* the last painted row, at its run centre;
|
|
913
|
-
* - the cap radius is half the elbow's run + 1 px, kept inside the crop
|
|
932
|
+
* - the cap radius is half the elbow's run + 1 px, kept inside the crop;
|
|
933
|
+
* - each cap ray walks 1 px at a time from the elbow until it leaves the
|
|
934
|
+
* widest run of the crop row it is in (strictly inside: `start < x < end`,
|
|
935
|
+
* on canvas columns, the row the floor of the canvas y), then stops
|
|
936
|
+
* `capInset(i)` short of that exit (none on the two seam-end rays, 2 px on
|
|
937
|
+
* the next, `CAP_INSET` on the rest), and at `capRadius`.
|
|
914
938
|
* Pivots are on the 0.01 grid, as the written model is. `bodyAxisX` is the
|
|
915
939
|
* body's axis, model x: the shoulder's side of it sets the sign. An arm too
|
|
916
940
|
* short for its width to put the elbow under the shoulder would rig
|
|
@@ -918,13 +942,59 @@ interface ArmGeometry {
|
|
|
918
942
|
*/
|
|
919
943
|
declare function armGeometry(layer: LayerInput, bodyAxisX: number): ArmGeometry;
|
|
920
944
|
|
|
945
|
+
/**
|
|
946
|
+
* The pose forearm. A second drawn forearm per side (`forearm_pose_L` /
|
|
947
|
+
* `forearm_pose_R`), drawn raised: it hangs from the arm's elbow and is
|
|
948
|
+
* swapped in for the hanging forearm by a switch.
|
|
949
|
+
* - One part, the role's own id, over its crop's box on `armPoseDeformer_X`,
|
|
950
|
+
* a child of `armDeformer_X` pivoting at the arm's elbow. It is not a child
|
|
951
|
+
* of `forearmDeformer_X`, so `ParamElbowX` never moves it, and the shoulder
|
|
952
|
+
* still carries it.
|
|
953
|
+
* - `ParamArmPoseX` (0..1) swaps: the hanging forearm and the elbow cap fade
|
|
954
|
+
* out on it, 1 to 0 (`armParts`), the pose forearm fades in, 0 to 1. The
|
|
955
|
+
* pair is exclusive by construction, and between the ends both show at
|
|
956
|
+
* partial opacity. The part has no mesh: the engine draws a meshless part
|
|
957
|
+
* as its full-box quad with its texture rect, and a rigid part needs no
|
|
958
|
+
* more.
|
|
959
|
+
* - `ParamArmPoseAngleX` rocks it about the elbow, in degrees over
|
|
960
|
+
* `POSE_ANGLE_RANGE`. + tips the raised hand outward, away from the body,
|
|
961
|
+
* mirrored per side. The part points up from its pivot where the hanging
|
|
962
|
+
* forearm points down, so its rotate binding takes −side × the value; the
|
|
963
|
+
* elbow's multiplier is the same −side, which gives the shoulder's reading.
|
|
964
|
+
* The composer puts the drawing's elbow end on the pivot (`measure` warns
|
|
965
|
+
* when it is off), so the rig does not use the crop's own pivot
|
|
966
|
+
* (`forearmPoseGeometry`).
|
|
967
|
+
*
|
|
968
|
+
* It draws after the hair, above the face and the front hair: a raised hand
|
|
969
|
+
* passes them (`ROLE_TABLE`).
|
|
970
|
+
*/
|
|
971
|
+
|
|
972
|
+
interface ForearmPoseGeometry {
|
|
973
|
+
/** The elbow end's pivot, model space: where the drawing's elbow end is
|
|
974
|
+
* centred. */
|
|
975
|
+
pivot: {
|
|
976
|
+
x: number;
|
|
977
|
+
y: number;
|
|
978
|
+
};
|
|
979
|
+
/** r_e: half the elbow end's width, px. */
|
|
980
|
+
radius: number;
|
|
981
|
+
/** The first painted row's model y: the raised hand's top. */
|
|
982
|
+
top: number;
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* The pose forearm's own geometry: the shoulder rule run from the bottom
|
|
986
|
+
* (`endPivot`), since it is drawn standing up from its elbow, plus the top of
|
|
987
|
+
* the paint.
|
|
988
|
+
*/
|
|
989
|
+
declare function forearmPoseGeometry(layer: LayerInput): ForearmPoseGeometry;
|
|
990
|
+
|
|
921
991
|
/** The part ids a `role`'s layer becomes, back to front: every one of them
|
|
922
992
|
* takes its texture from the layer's crop. Throws on an unknown role. */
|
|
923
993
|
declare function partIdsOfRole(role: string): readonly string[];
|
|
924
994
|
/**
|
|
925
995
|
* Map file names to roles. Throws on an unknown role, a role named twice, a
|
|
926
|
-
* required role (`face`, `eye_L`, `eye_R`, `mouth`) missing,
|
|
927
|
-
*
|
|
996
|
+
* required role (`face`, `eye_L`, `eye_R`, `mouth`) missing, an arm without a
|
|
997
|
+
* body, or a pose forearm without its arm.
|
|
928
998
|
*/
|
|
929
999
|
declare function parseLayerRoles(fileNames: string[]): {
|
|
930
1000
|
role: string;
|
|
@@ -938,16 +1008,17 @@ declare function parseLayerRoles(fileNames: string[]): {
|
|
|
938
1008
|
* (`body.ts`) that breathes, follows the head's turn and tilt a little and
|
|
939
1009
|
* turns on BodyAngleX/Y/Z, its legs planted; a head deformer hung from it
|
|
940
1010
|
* that rolls about the chin and breathes; each arm hung from it too, as an
|
|
941
|
-
* upper arm
|
|
942
|
-
* (`arms.ts`)
|
|
1011
|
+
* upper arm, a forearm and an elbow cap turning about the shoulder and the
|
|
1012
|
+
* elbow (`arms.ts`), and with a drawn pose forearm a switch that swaps it in
|
|
1013
|
+
* for the hanging one (`forearm-pose.ts`); one small warp grid per feature
|
|
943
1014
|
* (each eye, each brow, the nose, the mouth), translating and foreshortening
|
|
944
1015
|
* it by its own lead over the plate; and the plate, the hair and the blush
|
|
945
1016
|
* moved by per-vertex keyforms of their own — the plate as up to four
|
|
946
1017
|
* islands of one drawing: a head that slides, a neck that stays on the torso
|
|
947
1018
|
* and two ears that lag. Blink, gaze, brows, mouth, breath and
|
|
948
1019
|
* hair sway are part warps and bindings under those. The model also declares
|
|
949
|
-
* the default expressions and the Nod, Shake and Tilt motions
|
|
950
|
-
* (`animations.ts`).
|
|
1020
|
+
* the default expressions and the Nod, Shake and Tilt motions, and
|
|
1021
|
+
* with a pose forearm the Wave (`animations.ts`).
|
|
951
1022
|
*/
|
|
952
1023
|
|
|
953
1024
|
declare function generateIkiFromLayerSet(layers: LayerInput[], canvas: {
|
|
@@ -1083,11 +1154,12 @@ interface RgbaLayer {
|
|
|
1083
1154
|
interface LayerSetMeasurer {
|
|
1084
1155
|
/**
|
|
1085
1156
|
* Measure one layer while its `rgba` is in memory, keeping no reference to
|
|
1086
|
-
* it: only the set's opaque union,
|
|
1157
|
+
* it: only the set's opaque union (a pose forearm, hidden at rest, stays out
|
|
1158
|
+
* of it and of the per-role edges), this layer's per-row opaque extent and
|
|
1087
1159
|
* the `LayerInput` it returns outlive the call, so the host may drop `rgba`
|
|
1088
1160
|
* as soon as it returns. Returns the layer's `LayerInput` — its crop
|
|
1089
|
-
* box, the face's `rowHalfWidths`, the face's, hair layers', body's
|
|
1090
|
-
*
|
|
1161
|
+
* box, the face's `rowHalfWidths`, the face's, hair layers', body's, arms'
|
|
1162
|
+
* and pose forearms' `rowRuns`, the nose's
|
|
1091
1163
|
* `denseCore` unless that is a speck of its crop (`isSpeckCore`) — or
|
|
1092
1164
|
* `null` for an empty layer, one with no pixel at or above
|
|
1093
1165
|
* `ALPHA_BBOX_THRESHOLD`, which it records nothing for: the host reports
|
|
@@ -1344,4 +1416,4 @@ declare function createGridMesh(cols: number, rows: number): IkiMesh;
|
|
|
1344
1416
|
*/
|
|
1345
1417
|
declare function createDefaultWarpDeformer(model: IkiModel): IkiWarpDeformer;
|
|
1346
1418
|
|
|
1347
|
-
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, HEAD_BAND, type IrisStrand, LayerGeometryError, type LayerInput, type LayerSetMeasurement, type LayerSetMeasurer, 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, computeGridOffsets, createDefaultMatrixDeformer, createDefaultPart, createDefaultWarpDeformer, createGridMesh, createLayerSetMeasurer, denseCoreOf, detectAlphaBbox, foregroundSpan, generateIkiFromLayerSet, headHalfOf, interpolateGridOffsets, isSpeckCore, packAtlas, parseLayerRoles, partIdsOfRole, upsertGridKeyform, uvRectFor, validateDeformerDelete, validateDeformerReparent, validatePartAttach };
|
|
1419
|
+
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, LayerGeometryError, type LayerInput, type LayerSetMeasurement, type LayerSetMeasurer, 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, computeGridOffsets, createDefaultMatrixDeformer, createDefaultPart, createDefaultWarpDeformer, createGridMesh, createLayerSetMeasurer, denseCoreOf, detectAlphaBbox, forearmPoseGeometry, foregroundSpan, generateIkiFromLayerSet, headHalfOf, interpolateGridOffsets, isSpeckCore, packAtlas, parseLayerRoles, partIdsOfRole, upsertGridKeyform, uvRectFor, validateDeformerDelete, validateDeformerReparent, validatePartAttach };
|
package/dist/index.d.ts
CHANGED
|
@@ -713,14 +713,15 @@ interface LayerInput {
|
|
|
713
713
|
cropH: number;
|
|
714
714
|
/** Face only: half the opaque span of each crop row, canvas px (0 = none). */
|
|
715
715
|
rowHalfWidths?: number[];
|
|
716
|
-
/** `face` / `hair_front` / `hair_back` / `body` / `arm_L` / `arm_R`
|
|
716
|
+
/** `face` / `hair_front` / `hair_back` / `body` / `arm_L` / `arm_R` /
|
|
717
|
+
* `forearm_pose_L` / `forearm_pose_R` only:
|
|
717
718
|
* per crop row, its opaque (alpha ≥ 128) runs as a flat list of canvas
|
|
718
719
|
* columns `[start0, end0, start1, end1, …]`, each end exclusive (`[]` for a
|
|
719
720
|
* row with none). The actual pixels, so a gap in the hair is a gap here:
|
|
720
721
|
* the turn and the nod read off it where back hair is painted behind the
|
|
721
722
|
* front hair, and the crown's turn reads the face's so it never bares skin.
|
|
722
723
|
* The body's place the hips (where it splits into legs), and an arm's place
|
|
723
|
-
* its shoulder and elbow pivots. */
|
|
724
|
+
* its shoulder and elbow pivots, a pose forearm's its elbow-end pivot. */
|
|
724
725
|
rowRuns?: number[][];
|
|
725
726
|
/** Nose only: the tight box of its alpha ≥ 128 pixels, canvas px. */
|
|
726
727
|
denseCore?: {
|
|
@@ -857,31 +858,43 @@ interface GenerateOptions {
|
|
|
857
858
|
|
|
858
859
|
/**
|
|
859
860
|
* The arms. Each `arm_L` / `arm_R` layer is one drawing of the whole arm,
|
|
860
|
-
* hanging, its shoulder at the top. It becomes
|
|
861
|
-
* deformers hung from the body warp:
|
|
861
|
+
* hanging, its shoulder at the top. It becomes three parts on two nested
|
|
862
|
+
* matrix deformers hung from the body warp:
|
|
862
863
|
* - the upper arm (the role's own id) on `armDeformer_X`, which turns about
|
|
863
864
|
* the shoulder, the deltoid cap's centre;
|
|
864
865
|
* - the forearm (`forearm_X`) on `forearmDeformer_X`, a child of the arm's,
|
|
865
|
-
* which turns about the elbow
|
|
866
|
+
* which turns about the elbow;
|
|
867
|
+
* - the elbow cap (`elbow_X`), also on `forearmDeformer_X`, drawn behind the
|
|
868
|
+
* upper arm.
|
|
866
869
|
* The shoulder pivot rides an all-weight-1 cell of the body warp (`body.ts`),
|
|
867
870
|
* so the arm breathes and turns with the chest rigidly, never sheared.
|
|
868
871
|
*
|
|
869
|
-
*
|
|
870
|
-
* texture rect
|
|
871
|
-
*
|
|
872
|
-
*
|
|
873
|
-
*
|
|
874
|
-
*
|
|
875
|
-
*
|
|
872
|
+
* All three parts are cut from the one crop: they share its box, transform
|
|
873
|
+
* and texture rect. The upper arm is the band above the seam, the elbow
|
|
874
|
+
* pivot's row; the forearm is the band below it. Iki has no glue between
|
|
875
|
+
* meshes, and two bands hinged at a seam open a wedge as wide as the arm on a
|
|
876
|
+
* bend. The cap fills it: a half-disc fan centred on the elbow pivot turns
|
|
877
|
+
* about its own centre, so it rotates into itself and keeps the joint covered
|
|
878
|
+
* at any bend.
|
|
876
879
|
*
|
|
877
|
-
*
|
|
878
|
-
*
|
|
879
|
-
*
|
|
880
|
+
* Behind the upper arm, the cap shows only where the forearm's bend uncovers
|
|
881
|
+
* it, so it must lie inside the paint at rest, or its edge would show past
|
|
882
|
+
* the arm's. Its boundary is therefore the arm's own contour, not a circle:
|
|
883
|
+
* `armGeometry` walks each of the fan's 13 rays out from the elbow to the
|
|
884
|
+
* contour (`capRays`). A ring at the boundary, `CAP_RIM` wide, takes the UVs
|
|
885
|
+
* of the seam row's edge cross-section swept round the arc, so the exposed
|
|
886
|
+
* wedge carries the painted line, fading out in the antialias column as the
|
|
887
|
+
* painted edge does; the fan inside it is the crop's own pixels.
|
|
880
888
|
*
|
|
881
|
-
*
|
|
882
|
-
*
|
|
883
|
-
*
|
|
884
|
-
*
|
|
889
|
+
* Draw order: hair_back < body < elbow_L, arm_L, forearm_L, elbow_R, arm_R,
|
|
890
|
+
* forearm_R < face … < hair_front. The forearm draws over the upper arm,
|
|
891
|
+
* which draws over the cap.
|
|
892
|
+
*
|
|
893
|
+
* Signs: ParamArmX + raises the arm outward on either side, in degrees 1:1.
|
|
894
|
+
* A rotation is CCW-positive, so an arm whose shoulder lies right of the
|
|
895
|
+
* body's axis (+x, the character's left) turns CCW for +, and one at −x turns
|
|
896
|
+
* CW. ParamElbowX + bends the forearm toward the body, the opposite turn to
|
|
897
|
+
* the shoulder's +: it turns CW on the +x side, CCW on the −x side.
|
|
885
898
|
*/
|
|
886
899
|
|
|
887
900
|
type Point = {
|
|
@@ -895,8 +908,14 @@ interface ArmGeometry {
|
|
|
895
908
|
shoulderRadius: number;
|
|
896
909
|
/** The elbow pivot, model space. Its y is the seam the two meshes meet on. */
|
|
897
910
|
elbow: Point;
|
|
898
|
-
/** The
|
|
911
|
+
/** The elbow cap's largest radius, px. */
|
|
899
912
|
capRadius: number;
|
|
913
|
+
/** The cap's radius on each of its `CAP_SEGMENTS + 1` rays, from the elbow
|
|
914
|
+
* at angles 0..π, px: the walk out to the contour, less `capInset`, at
|
|
915
|
+
* most `capRadius`. */
|
|
916
|
+
capRays: number[];
|
|
917
|
+
/** The seam row's widest run, crop columns [start, end). */
|
|
918
|
+
seamRun: [number, number];
|
|
900
919
|
/** +1 for a shoulder right of the body's axis (+ turns CCW), −1 left of it
|
|
901
920
|
* (+ turns CW). */
|
|
902
921
|
side: 1 | -1;
|
|
@@ -905,12 +924,17 @@ interface ArmGeometry {
|
|
|
905
924
|
* The arm's pivots, read off the widest opaque run of each crop row
|
|
906
925
|
* (`rowRuns`); a row without one, or a layer without runs, reads as the
|
|
907
926
|
* crop:
|
|
908
|
-
* - r_u
|
|
909
|
-
*
|
|
910
|
-
* run centre of the row it lands in;
|
|
927
|
+
* - the shoulder pivot and r_u are `endPivot(layer, "top")`: r_u is half the
|
|
928
|
+
* median width over the `CAP_ROWS` rows, the pivot lies r_u under the first
|
|
929
|
+
* painted row's centre, at the run centre of the row it lands in;
|
|
911
930
|
* - the elbow is the centre of the row `ELBOW_AT` of the way from there to
|
|
912
931
|
* the last painted row, at its run centre;
|
|
913
|
-
* - the cap radius is half the elbow's run + 1 px, kept inside the crop
|
|
932
|
+
* - the cap radius is half the elbow's run + 1 px, kept inside the crop;
|
|
933
|
+
* - each cap ray walks 1 px at a time from the elbow until it leaves the
|
|
934
|
+
* widest run of the crop row it is in (strictly inside: `start < x < end`,
|
|
935
|
+
* on canvas columns, the row the floor of the canvas y), then stops
|
|
936
|
+
* `capInset(i)` short of that exit (none on the two seam-end rays, 2 px on
|
|
937
|
+
* the next, `CAP_INSET` on the rest), and at `capRadius`.
|
|
914
938
|
* Pivots are on the 0.01 grid, as the written model is. `bodyAxisX` is the
|
|
915
939
|
* body's axis, model x: the shoulder's side of it sets the sign. An arm too
|
|
916
940
|
* short for its width to put the elbow under the shoulder would rig
|
|
@@ -918,13 +942,59 @@ interface ArmGeometry {
|
|
|
918
942
|
*/
|
|
919
943
|
declare function armGeometry(layer: LayerInput, bodyAxisX: number): ArmGeometry;
|
|
920
944
|
|
|
945
|
+
/**
|
|
946
|
+
* The pose forearm. A second drawn forearm per side (`forearm_pose_L` /
|
|
947
|
+
* `forearm_pose_R`), drawn raised: it hangs from the arm's elbow and is
|
|
948
|
+
* swapped in for the hanging forearm by a switch.
|
|
949
|
+
* - One part, the role's own id, over its crop's box on `armPoseDeformer_X`,
|
|
950
|
+
* a child of `armDeformer_X` pivoting at the arm's elbow. It is not a child
|
|
951
|
+
* of `forearmDeformer_X`, so `ParamElbowX` never moves it, and the shoulder
|
|
952
|
+
* still carries it.
|
|
953
|
+
* - `ParamArmPoseX` (0..1) swaps: the hanging forearm and the elbow cap fade
|
|
954
|
+
* out on it, 1 to 0 (`armParts`), the pose forearm fades in, 0 to 1. The
|
|
955
|
+
* pair is exclusive by construction, and between the ends both show at
|
|
956
|
+
* partial opacity. The part has no mesh: the engine draws a meshless part
|
|
957
|
+
* as its full-box quad with its texture rect, and a rigid part needs no
|
|
958
|
+
* more.
|
|
959
|
+
* - `ParamArmPoseAngleX` rocks it about the elbow, in degrees over
|
|
960
|
+
* `POSE_ANGLE_RANGE`. + tips the raised hand outward, away from the body,
|
|
961
|
+
* mirrored per side. The part points up from its pivot where the hanging
|
|
962
|
+
* forearm points down, so its rotate binding takes −side × the value; the
|
|
963
|
+
* elbow's multiplier is the same −side, which gives the shoulder's reading.
|
|
964
|
+
* The composer puts the drawing's elbow end on the pivot (`measure` warns
|
|
965
|
+
* when it is off), so the rig does not use the crop's own pivot
|
|
966
|
+
* (`forearmPoseGeometry`).
|
|
967
|
+
*
|
|
968
|
+
* It draws after the hair, above the face and the front hair: a raised hand
|
|
969
|
+
* passes them (`ROLE_TABLE`).
|
|
970
|
+
*/
|
|
971
|
+
|
|
972
|
+
interface ForearmPoseGeometry {
|
|
973
|
+
/** The elbow end's pivot, model space: where the drawing's elbow end is
|
|
974
|
+
* centred. */
|
|
975
|
+
pivot: {
|
|
976
|
+
x: number;
|
|
977
|
+
y: number;
|
|
978
|
+
};
|
|
979
|
+
/** r_e: half the elbow end's width, px. */
|
|
980
|
+
radius: number;
|
|
981
|
+
/** The first painted row's model y: the raised hand's top. */
|
|
982
|
+
top: number;
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* The pose forearm's own geometry: the shoulder rule run from the bottom
|
|
986
|
+
* (`endPivot`), since it is drawn standing up from its elbow, plus the top of
|
|
987
|
+
* the paint.
|
|
988
|
+
*/
|
|
989
|
+
declare function forearmPoseGeometry(layer: LayerInput): ForearmPoseGeometry;
|
|
990
|
+
|
|
921
991
|
/** The part ids a `role`'s layer becomes, back to front: every one of them
|
|
922
992
|
* takes its texture from the layer's crop. Throws on an unknown role. */
|
|
923
993
|
declare function partIdsOfRole(role: string): readonly string[];
|
|
924
994
|
/**
|
|
925
995
|
* Map file names to roles. Throws on an unknown role, a role named twice, a
|
|
926
|
-
* required role (`face`, `eye_L`, `eye_R`, `mouth`) missing,
|
|
927
|
-
*
|
|
996
|
+
* required role (`face`, `eye_L`, `eye_R`, `mouth`) missing, an arm without a
|
|
997
|
+
* body, or a pose forearm without its arm.
|
|
928
998
|
*/
|
|
929
999
|
declare function parseLayerRoles(fileNames: string[]): {
|
|
930
1000
|
role: string;
|
|
@@ -938,16 +1008,17 @@ declare function parseLayerRoles(fileNames: string[]): {
|
|
|
938
1008
|
* (`body.ts`) that breathes, follows the head's turn and tilt a little and
|
|
939
1009
|
* turns on BodyAngleX/Y/Z, its legs planted; a head deformer hung from it
|
|
940
1010
|
* that rolls about the chin and breathes; each arm hung from it too, as an
|
|
941
|
-
* upper arm
|
|
942
|
-
* (`arms.ts`)
|
|
1011
|
+
* upper arm, a forearm and an elbow cap turning about the shoulder and the
|
|
1012
|
+
* elbow (`arms.ts`), and with a drawn pose forearm a switch that swaps it in
|
|
1013
|
+
* for the hanging one (`forearm-pose.ts`); one small warp grid per feature
|
|
943
1014
|
* (each eye, each brow, the nose, the mouth), translating and foreshortening
|
|
944
1015
|
* it by its own lead over the plate; and the plate, the hair and the blush
|
|
945
1016
|
* moved by per-vertex keyforms of their own — the plate as up to four
|
|
946
1017
|
* islands of one drawing: a head that slides, a neck that stays on the torso
|
|
947
1018
|
* and two ears that lag. Blink, gaze, brows, mouth, breath and
|
|
948
1019
|
* hair sway are part warps and bindings under those. The model also declares
|
|
949
|
-
* the default expressions and the Nod, Shake and Tilt motions
|
|
950
|
-
* (`animations.ts`).
|
|
1020
|
+
* the default expressions and the Nod, Shake and Tilt motions, and
|
|
1021
|
+
* with a pose forearm the Wave (`animations.ts`).
|
|
951
1022
|
*/
|
|
952
1023
|
|
|
953
1024
|
declare function generateIkiFromLayerSet(layers: LayerInput[], canvas: {
|
|
@@ -1083,11 +1154,12 @@ interface RgbaLayer {
|
|
|
1083
1154
|
interface LayerSetMeasurer {
|
|
1084
1155
|
/**
|
|
1085
1156
|
* Measure one layer while its `rgba` is in memory, keeping no reference to
|
|
1086
|
-
* it: only the set's opaque union,
|
|
1157
|
+
* it: only the set's opaque union (a pose forearm, hidden at rest, stays out
|
|
1158
|
+
* of it and of the per-role edges), this layer's per-row opaque extent and
|
|
1087
1159
|
* the `LayerInput` it returns outlive the call, so the host may drop `rgba`
|
|
1088
1160
|
* as soon as it returns. Returns the layer's `LayerInput` — its crop
|
|
1089
|
-
* box, the face's `rowHalfWidths`, the face's, hair layers', body's
|
|
1090
|
-
*
|
|
1161
|
+
* box, the face's `rowHalfWidths`, the face's, hair layers', body's, arms'
|
|
1162
|
+
* and pose forearms' `rowRuns`, the nose's
|
|
1091
1163
|
* `denseCore` unless that is a speck of its crop (`isSpeckCore`) — or
|
|
1092
1164
|
* `null` for an empty layer, one with no pixel at or above
|
|
1093
1165
|
* `ALPHA_BBOX_THRESHOLD`, which it records nothing for: the host reports
|
|
@@ -1344,4 +1416,4 @@ declare function createGridMesh(cols: number, rows: number): IkiMesh;
|
|
|
1344
1416
|
*/
|
|
1345
1417
|
declare function createDefaultWarpDeformer(model: IkiModel): IkiWarpDeformer;
|
|
1346
1418
|
|
|
1347
|
-
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, HEAD_BAND, type IrisStrand, LayerGeometryError, type LayerInput, type LayerSetMeasurement, type LayerSetMeasurer, 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, computeGridOffsets, createDefaultMatrixDeformer, createDefaultPart, createDefaultWarpDeformer, createGridMesh, createLayerSetMeasurer, denseCoreOf, detectAlphaBbox, foregroundSpan, generateIkiFromLayerSet, headHalfOf, interpolateGridOffsets, isSpeckCore, packAtlas, parseLayerRoles, partIdsOfRole, upsertGridKeyform, uvRectFor, validateDeformerDelete, validateDeformerReparent, validatePartAttach };
|
|
1419
|
+
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, LayerGeometryError, type LayerInput, type LayerSetMeasurement, type LayerSetMeasurer, 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, computeGridOffsets, createDefaultMatrixDeformer, createDefaultPart, createDefaultWarpDeformer, createGridMesh, createLayerSetMeasurer, denseCoreOf, detectAlphaBbox, forearmPoseGeometry, foregroundSpan, generateIkiFromLayerSet, headHalfOf, interpolateGridOffsets, isSpeckCore, packAtlas, parseLayerRoles, partIdsOfRole, upsertGridKeyform, uvRectFor, validateDeformerDelete, validateDeformerReparent, validatePartAttach };
|