@ikijs/editor 0.9.0 → 0.10.1
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 +44 -40
- package/dist/index.d.mts +124 -260
- package/dist/index.d.ts +124 -260
- package/dist/index.js +2293 -2547
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2302 -2554
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -657,343 +657,207 @@ interface AlphaBbox {
|
|
|
657
657
|
declare function detectAlphaBbox(rgba: ArrayLike<number>, width: number, height: number): AlphaBbox | null;
|
|
658
658
|
|
|
659
659
|
/**
|
|
660
|
-
*
|
|
661
|
-
*
|
|
662
|
-
*
|
|
663
|
-
*
|
|
664
|
-
*
|
|
660
|
+
* Per-character tuning, starting from the profile: only the quantities the
|
|
661
|
+
* Live2D samples themselves disagree on by more than their own median
|
|
662
|
+
* (style, not construction). `turn`, `featureLead` and `sway` multiply the
|
|
663
|
+
* profile (1 = as measured); `hairFollow`, `outlineFollow` and `blink`
|
|
664
|
+
* replace its value.
|
|
665
665
|
*/
|
|
666
|
+
interface RigStyle {
|
|
667
|
+
/** The whole turn — plate, features and hair (the samples' face slides
|
|
668
|
+
* 0.05–0.25 hh). Ignored when a `turnTargets.eyeShift` is given, which
|
|
669
|
+
* fits it instead. */
|
|
670
|
+
turn?: number;
|
|
671
|
+
/** How far the features lead the plate (the nose leads it 2.2–4.4×). */
|
|
672
|
+
featureLead?: number;
|
|
673
|
+
/** The front hair's share of the face's turn (the samples' 1.0–1.37;
|
|
674
|
+
* profile 1.1). */
|
|
675
|
+
hairFollow?: number;
|
|
676
|
+
/** Its outer edge's share, where the front hair draws the head's outline
|
|
677
|
+
* (profile 0: the outline holds; `hairFollow` rides it whole). */
|
|
678
|
+
outlineFollow?: number;
|
|
679
|
+
/** How far the upper lid comes down, over the eye's height (0.30–0.67). */
|
|
680
|
+
blink?: number;
|
|
681
|
+
/** Hair sway amplitude (0.02–0.36 hh at the extremes). */
|
|
682
|
+
sway?: number;
|
|
683
|
+
}
|
|
666
684
|
|
|
667
685
|
/**
|
|
668
|
-
*
|
|
669
|
-
*
|
|
670
|
-
*
|
|
686
|
+
* The public shapes of the auto-rig: what a host hands `generateIkiFromLayerSet`
|
|
687
|
+
* and what the turn solve reports back. Pixel measurement lives in
|
|
688
|
+
* `layer-measure.ts`; everything here is already-decoded geometry.
|
|
671
689
|
*/
|
|
690
|
+
|
|
691
|
+
/** One role layer, as a host measured it off its decoded pixels. */
|
|
672
692
|
interface LayerInput {
|
|
673
|
-
/** Canonical role
|
|
693
|
+
/** Canonical role (see `parseLayerRoles`); becomes the part id. */
|
|
674
694
|
role: string;
|
|
675
|
-
/** Original file name — used in error messages and as a stable id. */
|
|
676
695
|
fileName: string;
|
|
677
|
-
/** Shared canvas width (all layers have the same canvas size). */
|
|
678
696
|
canvasW: number;
|
|
679
|
-
/** Shared canvas height. */
|
|
680
697
|
canvasH: number;
|
|
681
|
-
/** Alpha
|
|
698
|
+
/** Alpha bounding box in canvas px (y down) — the crop the atlas holds. */
|
|
682
699
|
bbox: {
|
|
683
700
|
x: number;
|
|
684
701
|
y: number;
|
|
685
702
|
w: number;
|
|
686
703
|
h: number;
|
|
687
704
|
};
|
|
688
|
-
/** Cropped image width = bbox.w. */
|
|
689
705
|
cropW: number;
|
|
690
|
-
/** Cropped image height = bbox.h. */
|
|
691
706
|
cropH: number;
|
|
692
|
-
/**
|
|
693
|
-
* The layer's painted half-width on every CROP row, top → bottom, one entry
|
|
694
|
-
* per row (`cropH` of them): half the row's opaque span in canvas px under
|
|
695
|
-
* the same alpha ≥ 128 rule the head's `headEdges` are measured with
|
|
696
|
-
* (`createLayerSetMeasurer`), 0 for a row with no opaque pixel.
|
|
697
|
-
* Optional, and only the FACE's is read: it gives the face plate a
|
|
698
|
-
* row-dependent turn radius and a chin swing (`faceRowProfile`,
|
|
699
|
-
* `turnSurface`); absent — from a host that does not measure it — the plate
|
|
700
|
-
* turns on one radius on every row. Validated before anything reads it: an
|
|
701
|
-
* array of length `cropH` whose every entry is a finite number in
|
|
702
|
-
* [0, cropW / 2], the most an inclusive span inside the crop can be.
|
|
703
|
-
*/
|
|
707
|
+
/** Face only: half the opaque span of each crop row, canvas px (0 = none). */
|
|
704
708
|
rowHalfWidths?: number[];
|
|
705
|
-
/**
|
|
706
|
-
* The tight box of the layer's alpha ≥ 128 pixels, in image coords like
|
|
707
|
-
* `bbox` and NOT grown: the drawing a viewer reads inside a soft feather,
|
|
708
|
-
* which the crop's alpha ≥ 8 rule takes in whole. Optional, and only the
|
|
709
|
-
* NOSE's is read: its centre and width are the nose's turn landmark
|
|
710
|
-
* (`turnLandmarks`), so a shaded nose is fitted by the drawing rather than
|
|
711
|
-
* by its feather, and its top edge at its centre x is the bridge top the
|
|
712
|
-
* nose tilts about on the turn (`NOSE_TURN_TILT_DEG`). Absent — from a
|
|
713
|
-
* host that does not measure it — the crop stands in for both. Validated
|
|
714
|
-
* before anything reads it: a plain object whose x, y, w and h are finite,
|
|
715
|
-
* w and h positive, and the box inside `bbox`.
|
|
716
|
-
*/
|
|
709
|
+
/** Nose only: the tight box of its alpha ≥ 128 pixels, canvas px. */
|
|
717
710
|
denseCore?: {
|
|
718
711
|
x: number;
|
|
719
712
|
y: number;
|
|
720
713
|
w: number;
|
|
721
714
|
h: number;
|
|
722
715
|
};
|
|
716
|
+
/** Face only: per crop column, the canvas row of the last pixel of the
|
|
717
|
+
* first dark stroke met going down from the plate's widest row (the jaw's
|
|
718
|
+
* outline, across a neck), or −1 where the column leaves the paint first.
|
|
719
|
+
* Where the head ends and the neck the body keeps begins. */
|
|
720
|
+
jawRows?: number[];
|
|
723
721
|
}
|
|
724
722
|
/**
|
|
725
|
-
*
|
|
726
|
-
*
|
|
727
|
-
*
|
|
728
|
-
* 1. Normalize each filename → role (normalizeRole).
|
|
729
|
-
* 2. Eagerly check each role against ROLE_TABLE — unknown roles throw early
|
|
730
|
-
* with the offending fileName included in the message.
|
|
731
|
-
* 3. Call assertRoleSet to check duplicates + required roles.
|
|
732
|
-
*
|
|
733
|
-
* Throws a path-qualified Error on any contract violation.
|
|
734
|
-
*/
|
|
735
|
-
declare function parseLayerRoles(fileNames: string[]): {
|
|
736
|
-
role: string;
|
|
737
|
-
fileName: string;
|
|
738
|
-
}[];
|
|
739
|
-
/**
|
|
740
|
-
* One side's iris and the bangs' run it would slide under on the turn, as
|
|
741
|
-
* real pixel boundaries on ONE image row — the row holding that iris's centre
|
|
742
|
-
* — in model coordinates: x is canvas x minus half the canvas width, like
|
|
743
|
-
* `bboxToTransform`'s crop edges, and `y` is that row's centre. Every x is the
|
|
744
|
-
* painted edge facing its clear neighbour, read under one opacity rule, so the
|
|
745
|
-
* gap between an iris edge and a run edge is a real distance with no margin to
|
|
746
|
-
* add. "Outer" is toward the head's edge on that side. The run is the one a
|
|
747
|
-
* producer judges a strand: it may skip runs it judges hair detail
|
|
748
|
-
* (`createLayerSetMeasurer` treats those narrower than half the iris's
|
|
749
|
-
* painted width on the row as clear), so an iris under only such a wisp counts
|
|
750
|
-
* as clear.
|
|
751
|
-
*
|
|
752
|
-
* One shape covers three cases:
|
|
753
|
-
* - an ordinary side strand outward of a clear iris (`runFace` outward of
|
|
754
|
-
* `irisOuter`);
|
|
755
|
-
* - a run over the iris centre that clears on the face side (`runFace`
|
|
756
|
-
* inward of that centre);
|
|
757
|
-
* - a fringe spanning the face: the run still covers the OTHER iris's
|
|
758
|
-
* centre, so it has no face-side end on this side and `runFace` is
|
|
759
|
-
* `null` — an absent edge, not an invented one.
|
|
723
|
+
* One side's iris against the `hair_front` run it would slide under on the
|
|
724
|
+
* turn, on the row holding the iris centre. Model coordinates: x is canvas x
|
|
725
|
+
* minus half the canvas width, y is half the canvas height minus canvas y.
|
|
760
726
|
*/
|
|
761
727
|
interface IrisStrand {
|
|
762
|
-
/** The iris row's centre, model y. */
|
|
763
728
|
y: number;
|
|
764
|
-
/** The outer end of that iris layer's opaque span on the row. */
|
|
765
729
|
irisOuter: number;
|
|
766
|
-
/** Its inner end, toward the face. */
|
|
767
730
|
irisInner: number;
|
|
768
|
-
/** The outer end of the `hair_front` run the iris would slide under. */
|
|
769
731
|
runOuter: number;
|
|
770
|
-
/** The run's face-side end
|
|
771
|
-
* centre. */
|
|
732
|
+
/** The run's face-side end; `null` for a fringe spanning the face. */
|
|
772
733
|
runFace: number | null;
|
|
773
734
|
}
|
|
774
735
|
/**
|
|
775
|
-
*
|
|
776
|
-
* a
|
|
777
|
-
*
|
|
778
|
-
*
|
|
779
|
-
* Every field is optional: `DEFAULT_TURN_TARGETS` supplies the three a
|
|
780
|
-
* reference measures, and the nose and the mouth derive from the eyes when they
|
|
781
|
-
* are not given.
|
|
782
|
-
*
|
|
783
|
-
* What happens when the layer set cannot reach a target depends on where the
|
|
784
|
-
* target came from. A number the CALLER passed is a measurement, so an
|
|
785
|
-
* unreachable one throws, naming the field and what was on offer — except a
|
|
786
|
-
* `silhouetteRatio` when no ratio in its own [0.5, 1.5] range renders on this
|
|
787
|
-
* layer set: that throw names the field and the whole range instead of an
|
|
788
|
-
* offer, since there is none narrower. Leaving the field out still rigs,
|
|
789
|
-
* because a defaulted one clamps.
|
|
790
|
-
*
|
|
791
|
-
* A number this module filled in — a default, or a nose/mouth derived from the
|
|
792
|
-
* eyes — is a style prior, not a promise about this character: it is CLAMPED
|
|
793
|
-
* to what the layer set can do and the rig is built. The alternative is a
|
|
794
|
-
* generator that refuses its own defaults, which would leave a perfectly good
|
|
795
|
-
* layer set with no model at all. `solveTurnModel` reports which fields it
|
|
796
|
-
* clamped.
|
|
797
|
-
*
|
|
798
|
-
* One measurement is clamped too: an `eyeShift` past the room the art leaves
|
|
799
|
-
* the far eye — the face plate's edge, and the bangs' side strand when
|
|
800
|
-
* `strandEdges` is given — whoever passed it. That room is a fact about this
|
|
801
|
-
* layer set, not about the reference the shift was measured on, so the rig
|
|
802
|
-
* takes as much of the shift as the art allows and keeps fitting the other
|
|
803
|
-
* cues. An `eyeShift` below the slide the face's own turn already gives the
|
|
804
|
-
* eyes is still refused: no depth reaches it.
|
|
736
|
+
* Head-turn cues at ±30°, as `measure_turn_reference` reads them off a front
|
|
737
|
+
* and a turned image. Shifts are fractions of the head half-width, taken as
|
|
738
|
+
* magnitudes: that tool signs them by the reference's turn direction.
|
|
805
739
|
*/
|
|
806
740
|
interface TurnTargets {
|
|
807
|
-
/** How far the eye pair's centre slides toward the far side at full turn, as
|
|
808
|
-
* a fraction of the head's half-width. The sign is ignored: which way is
|
|
809
|
-
* the turn's own business. */
|
|
810
741
|
eyeShift?: number;
|
|
811
|
-
/** The far eye's width over the near eye's at full turn, divided by the same
|
|
812
|
-
* ratio at rest. 1 is no foreshortening; 0 is an edge-on far eye. */
|
|
813
742
|
farEyeRatio?: number;
|
|
814
|
-
/** The head's half-width at full turn over its half-width at rest, as a
|
|
815
|
-
* RENDER measures it — the outermost opaque edge on each side, whichever
|
|
816
|
-
* part owns it. 1 holds the silhouette; below 1 narrows it. The hold that
|
|
817
|
-
* produces it is fitted to it, so a measured one is met or refused, never
|
|
818
|
-
* quietly rendered as something else. */
|
|
819
743
|
silhouetteRatio?: number;
|
|
820
|
-
/** `eyeShift` for the nose. Derived from `eyeShift` when absent. */
|
|
821
744
|
noseShift?: number;
|
|
822
|
-
/** `eyeShift` for the mouth. Derived from `eyeShift` when absent. */
|
|
823
745
|
mouthShift?: number;
|
|
824
|
-
/** The head
|
|
825
|
-
* fractions are fractions OF, and the rest distance the silhouette hold
|
|
826
|
-
* pivots on. Without it both fall back to the face plate's half-width, which
|
|
827
|
-
* is narrower than the head the hair draws, so the shifts land short — an
|
|
828
|
-
* approximation for callers that have no pixels, not a default to prefer. */
|
|
746
|
+
/** The head half-width the shifts are fractions of, canvas px. */
|
|
829
747
|
headHalfWidth?: number;
|
|
830
748
|
}
|
|
831
|
-
/**
|
|
832
|
-
* A `turnTargets` field this generator will not build a rig from: not a number,
|
|
833
|
-
* outside its range, unreachable on this layer set, or a measured head narrower
|
|
834
|
-
* than the face plate it is drawn around. Every one of them carries a number
|
|
835
|
-
* the CALLER passed, so a host can tell them apart from the invariant breaks the
|
|
836
|
-
* rest of the generator throws and report them as bad input instead of failing.
|
|
837
|
-
*/
|
|
749
|
+
/** A turn target this layer set cannot reach, or turn input that is malformed. */
|
|
838
750
|
declare class TurnTargetError extends Error {
|
|
839
751
|
constructor(message: string);
|
|
840
752
|
}
|
|
841
753
|
/**
|
|
842
|
-
* The
|
|
843
|
-
*
|
|
844
|
-
*
|
|
845
|
-
*
|
|
846
|
-
*
|
|
754
|
+
* The Live2D profile's own turn (`profile.ts`), in the cues' units — what a
|
|
755
|
+
* rig with no `turnTargets` renders on a head whose silhouette at the eye row
|
|
756
|
+
* is back hair about 1 hh (eye row → chin) wide. eyeShift: the eye pair moves
|
|
757
|
+
* 0.211 hh at ±30 and that silhouette's centre −0.009 hh, over a 1 hh head
|
|
758
|
+
* half-width, 0.22. farEyeRatio: the far eye narrows to 0.85 and the near one
|
|
759
|
+
* widens to 1.085, and the cue is their ratio, 0.78. silhouetteRatio: the
|
|
760
|
+
* silhouette holds its width.
|
|
761
|
+
*
|
|
762
|
+
* With no target given the rig renders the profile itself, whatever the cues
|
|
763
|
+
* then read on its art (a head whose side locks draw its silhouette, and ride
|
|
764
|
+
* the face, reads a smaller eyeShift); a given target is fitted.
|
|
847
765
|
*/
|
|
848
766
|
declare const DEFAULT_TURN_TARGETS: Readonly<Required<Pick<TurnTargets, "eyeShift" | "farEyeRatio" | "silhouetteRatio">>>;
|
|
849
|
-
/**
|
|
850
|
-
*
|
|
767
|
+
/** How far each feature family stands in front of the plate, as the depth a
|
|
768
|
+
* rotation would need to give its shift at ±30 (shift / sin 30°), in head
|
|
769
|
+
* half-widths — the nose leads the mouth and the mouth the eyes. */
|
|
851
770
|
interface TurnDepths {
|
|
852
771
|
eye: number;
|
|
853
772
|
nose: number;
|
|
854
773
|
mouth: number;
|
|
855
774
|
}
|
|
856
|
-
/**
|
|
857
|
-
|
|
775
|
+
/** How much of a far iris's painted row the bangs' run covers. */
|
|
776
|
+
interface StrandOverlap {
|
|
777
|
+
/** The turn stop (AngleX, degrees) where the coverage is largest. */
|
|
778
|
+
deg: number;
|
|
779
|
+
/** Covered width there, canvas px. */
|
|
780
|
+
px: number;
|
|
781
|
+
/** The same in head half-widths. */
|
|
782
|
+
hh: number;
|
|
783
|
+
/** Covered width at rest. */
|
|
784
|
+
restPx: number;
|
|
785
|
+
/** Whether the iris went no deeper under the run than it is painted.
|
|
786
|
+
* Always `false` for a fringe spanning the face (`runFace: null`), which
|
|
787
|
+
* has no side to keep the iris clear of. */
|
|
788
|
+
held: boolean;
|
|
789
|
+
}
|
|
858
790
|
interface TurnSolveReport {
|
|
859
|
-
/**
|
|
791
|
+
/** The curvature the plate would need to put the eyes as far in front of
|
|
792
|
+
* its edge as their lead over it does, as a radius, canvas px. */
|
|
860
793
|
radius: number;
|
|
861
|
-
/**
|
|
794
|
+
/** The measured head half-width, canvas px, which the shift cues are
|
|
795
|
+
* fractions of — on a set with none measured (hairless) the face crop's
|
|
796
|
+
* half-width, while the cues are then fractions of the plate's painted
|
|
797
|
+
* half-width at the eye row. */
|
|
862
798
|
holdBase: number;
|
|
863
799
|
depths: TurnDepths;
|
|
864
|
-
/** What the rig
|
|
800
|
+
/** What the rig renders at ±30° (mean of both directions). */
|
|
865
801
|
achieved: {
|
|
866
802
|
eyeShift: number;
|
|
867
803
|
farEyeRatio: number;
|
|
868
804
|
silhouetteRatio: number;
|
|
869
805
|
};
|
|
870
|
-
/**
|
|
871
|
-
* defaulted field it could not reach, and an `eyeShift` — the caller's own
|
|
872
|
-
* too — past the room the art leaves the far eye (the face plate's edge,
|
|
873
|
-
* and the bangs' strand when `strandEdges` was given). Empty when every
|
|
874
|
-
* target was met. */
|
|
806
|
+
/** Targets cut down to what this layer set can do. */
|
|
875
807
|
clamped: (keyof TurnTargets)[];
|
|
876
|
-
/** Per side whose far iris the bangs' run covers at some far stop at the
|
|
877
|
-
* fitted radius and depth (`options.strandEdges`): how much of it. Absent
|
|
878
|
-
* when no side has an entry. Never a clamp: `clamped` still names an
|
|
879
|
-
* `eyeShift` the strand bound cut short. */
|
|
880
808
|
strandOverlap?: {
|
|
881
809
|
left?: StrandOverlap;
|
|
882
810
|
right?: StrandOverlap;
|
|
883
811
|
};
|
|
884
812
|
}
|
|
813
|
+
interface HeadEdges {
|
|
814
|
+
left: {
|
|
815
|
+
role: string;
|
|
816
|
+
x: number;
|
|
817
|
+
}[];
|
|
818
|
+
right: {
|
|
819
|
+
role: string;
|
|
820
|
+
x: number;
|
|
821
|
+
}[];
|
|
822
|
+
}
|
|
823
|
+
interface GenerateOptions {
|
|
824
|
+
turnTargets?: TurnTargets;
|
|
825
|
+
/** Per-character tuning from the profile's defaults (`profile.ts`). */
|
|
826
|
+
style?: RigStyle;
|
|
827
|
+
onTurnSolved?: (report: TurnSolveReport) => void;
|
|
828
|
+
headEdges?: HeadEdges;
|
|
829
|
+
strandEdges?: {
|
|
830
|
+
left?: IrisStrand;
|
|
831
|
+
right?: IrisStrand;
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
|
|
885
835
|
/**
|
|
886
|
-
*
|
|
887
|
-
*
|
|
888
|
-
* landed run `[runOuter, runFace]` — face-ward without end for a run with no
|
|
889
|
-
* face-side edge (`runFace: null`) — at the far stop where that is largest.
|
|
890
|
-
* Always read off real landed boundaries (`IrisStrand`).
|
|
836
|
+
* Map file names to roles. Throws on an unknown role, a role named twice, or
|
|
837
|
+
* a required role (`face`, `eye_L`, `eye_R`, `mouth`) missing.
|
|
891
838
|
*/
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
/** `px` over the head half-width the shift cues are fractions of. */
|
|
898
|
-
hh: number;
|
|
899
|
-
/** The covered width as painted, at rest, px. */
|
|
900
|
-
restPx: number;
|
|
901
|
-
/** Whether this side's strand bound held at the fitted depth — the iris
|
|
902
|
-
* kept no deeper under the run than it is painted, at every far stop. When
|
|
903
|
-
* false the fitted radius could not hold it (always so for `runFace:
|
|
904
|
-
* null`), the eyes' turn depth is 0, and `px` is the coverage that is
|
|
905
|
-
* left. */
|
|
906
|
-
held: boolean;
|
|
907
|
-
}
|
|
839
|
+
declare function parseLayerRoles(fileNames: string[]): {
|
|
840
|
+
role: string;
|
|
841
|
+
fileName: string;
|
|
842
|
+
}[];
|
|
843
|
+
|
|
908
844
|
/**
|
|
909
|
-
*
|
|
910
|
-
* valid IkiModel ready for parseIkiModel.
|
|
911
|
-
*
|
|
912
|
-
* - Validate all inputs before deriving anything.
|
|
913
|
-
* - Place parts at source-derived positions (bboxToTransform, unshifted).
|
|
914
|
-
* - Emit the standard parameters (STANDARD_PARAMETERS), plus a conditional
|
|
915
|
-
* HairSwayX/Z pair + hair-sway physics rigs when a hair_front layer is
|
|
916
|
-
* present.
|
|
917
|
-
* - Size every turn group's grid to its own members and the virtual lattice
|
|
918
|
-
* to those grids, then solve the turn on them (turnSetup, solveTurnModel):
|
|
919
|
-
* one surface — radius, travel, the head-level nod radius — that every
|
|
920
|
-
* bake below samples.
|
|
921
|
-
* - Build headDeformer (matrix, neck pivot, nod/tilt/breath bindings — the
|
|
922
|
-
* turn translates nothing rigidly; its travel is in the group grids), one
|
|
923
|
-
* warp deformer per turn group present — `faceWarp` for the plate,
|
|
924
|
-
* `eyeWarp_L/R`, `mouthWarp`, `noseWarp`, `browWarp_L/R`, `blushWarp_L/R`
|
|
925
|
-
* — each a warp2d over its own grid baked from that surface with the
|
|
926
|
-
* family's solved depth as keyform geometry (bakeTurnGroupWarp2D), and
|
|
927
|
-
* bodyDeformer when a body layer is present (matrix, torso-base pivot,
|
|
928
|
-
* AngleX follow + Breath follow).
|
|
929
|
-
* - Mesh parts (spec.mesh===true) → width:1, height:1, pixel grid mesh sized by
|
|
930
|
-
* meshCellsFor + role bindings, each face-family part on its group's warp.
|
|
931
|
-
* - Static parts (spec.mesh===false) → width:cropW, height:cropH, no mesh.
|
|
932
|
-
* - Part ids equal the role string (deterministic, no crypto.randomUUID).
|
|
933
|
-
* - Return parseIkiModel(structuredClone(model)) — every caller gets a
|
|
934
|
-
* validated model; bad assembly fails loudly.
|
|
845
|
+
* `generateIkiFromLayerSet`: role layers in, a rigged `.iki` out.
|
|
935
846
|
*
|
|
936
|
-
*
|
|
937
|
-
*
|
|
938
|
-
*
|
|
939
|
-
*
|
|
940
|
-
*
|
|
941
|
-
*
|
|
942
|
-
*
|
|
943
|
-
*
|
|
944
|
-
* `options.strandEdges` gives each side's iris and the bangs' run it would
|
|
945
|
-
* slide under as measured pixel edges (`IrisStrand`), and with it the turn
|
|
946
|
-
* keeps each far iris from sliding under that run any further than it is
|
|
947
|
-
* painted, best effort: where no radius the fit can use holds that, the rig
|
|
948
|
-
* is still built, with the eyes' depth at 0, and the report's
|
|
949
|
-
* `strandOverlap` says how much of the iris the bangs cover.
|
|
847
|
+
* The rig's shape follows a Live2D default rig (`profile.ts`): a torso that
|
|
848
|
+
* only breathes; a head deformer that rolls about the chin and breathes; one
|
|
849
|
+
* small warp grid per feature (each eye, each brow, the nose, the mouth),
|
|
850
|
+
* translating and foreshortening it by its own lead over the plate; and the
|
|
851
|
+
* plate, the hair and the blush moved by per-vertex keyforms of their own —
|
|
852
|
+
* the plate as up to four islands of one drawing: a head that slides, a neck
|
|
853
|
+
* that stays and two ears that lag. Blink, gaze, brows, mouth, breath and
|
|
854
|
+
* hair sway are part warps and bindings under those.
|
|
950
855
|
*/
|
|
856
|
+
|
|
951
857
|
declare function generateIkiFromLayerSet(layers: LayerInput[], canvas: {
|
|
952
858
|
width: number;
|
|
953
859
|
height: number;
|
|
954
|
-
}, options?:
|
|
955
|
-
turnTargets?: TurnTargets;
|
|
956
|
-
/** Called once, after a turn is solved, with what it settled on. Not called
|
|
957
|
-
* for a layer set without a nose, which solves no turn at all. */
|
|
958
|
-
onTurnSolved?: (report: TurnSolveReport) => void;
|
|
959
|
-
/** Every role with an opaque pixel in the eye-row band, per side, when
|
|
960
|
-
* `turnTargets.headHalfWidth` was measured off that same union — a
|
|
961
|
-
* companion to it, not a turn target itself (the caller-facing contract
|
|
962
|
-
* stays the three cues). See `TurnSolveContext.headEdges`. */
|
|
963
|
-
headEdges?: {
|
|
964
|
-
left: {
|
|
965
|
-
role: string;
|
|
966
|
-
x: number;
|
|
967
|
-
}[];
|
|
968
|
-
right: {
|
|
969
|
-
role: string;
|
|
970
|
-
x: number;
|
|
971
|
-
}[];
|
|
972
|
-
};
|
|
973
|
-
/** Per side (`left` the −x side, `right` the +x side, like `headEdges`),
|
|
974
|
-
* that side's iris and the bangs' run it would slide under on the turn,
|
|
975
|
-
* as real pixel edges on the row holding the iris's centre — see
|
|
976
|
-
* `IrisStrand` for the contract and its three cases (a strand outward of
|
|
977
|
-
* a clear iris, a run over the iris centre that clears on the face side,
|
|
978
|
-
* a fringe spanning the face). A side's iris is whichever of `iris_L` /
|
|
979
|
-
* `iris_R` sits on that side; the sides are independent, so either may
|
|
980
|
-
* be absent. With it the turn keeps each far iris from sliding under its
|
|
981
|
-
* run any further than it is painted, best effort: never a refusal. The
|
|
982
|
-
* report's `strandOverlap` gives, per side whose far iris the run still
|
|
983
|
-
* covers at some far stop, the covered width at the stop where it is
|
|
984
|
-
* largest, next to the painted one, and whether the bound held — `true`
|
|
985
|
-
* for an iris painted under its run that the turn took no deeper,
|
|
986
|
-
* `false` where the fitted radius could not hold it and the eyes' turn
|
|
987
|
-
* depth is 0. It is always
|
|
988
|
-
* validated against the layers first (`validateStrandEdges`), but only
|
|
989
|
-
* the turn solve reads it, so like `headEdges` it has no effect on the
|
|
990
|
-
* rig without a nose; absent or `{}`, the rig is the one built without
|
|
991
|
-
* it. */
|
|
992
|
-
strandEdges?: {
|
|
993
|
-
left?: IrisStrand;
|
|
994
|
-
right?: IrisStrand;
|
|
995
|
-
};
|
|
996
|
-
}): IkiModel;
|
|
860
|
+
}, options?: GenerateOptions): IkiModel;
|
|
997
861
|
|
|
998
862
|
/**
|
|
999
863
|
* The alpha rules a layer set is measured by, and the pre-rig measurement of
|
|
@@ -1380,4 +1244,4 @@ declare function createGridMesh(cols: number, rows: number): IkiMesh;
|
|
|
1380
1244
|
*/
|
|
1381
1245
|
declare function createDefaultWarpDeformer(model: IkiModel): IkiWarpDeformer;
|
|
1382
1246
|
|
|
1383
|
-
export { ALPHA_BBOX_THRESHOLD, ALPHA_OPAQUE, ATLAS_PADDING, AddDeformer, AddPart, AddPhysicsRig, type AlphaBbox, type ApplyAtlasInput, 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, type LayerInput, type LayerSetMeasurement, type LayerSetMeasurer, type RgbaLayer, 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, captureBindingEndpoint, computeGridOffsets, createDefaultMatrixDeformer, createDefaultPart, createDefaultWarpDeformer, createGridMesh, createLayerSetMeasurer, denseCoreOf, detectAlphaBbox, foregroundSpan, generateIkiFromLayerSet, headHalfOf, interpolateGridOffsets, isSpeckCore, packAtlas, parseLayerRoles, upsertGridKeyform, uvRectFor, validateDeformerDelete, validateDeformerReparent, validatePartAttach };
|
|
1247
|
+
export { ALPHA_BBOX_THRESHOLD, ALPHA_OPAQUE, ATLAS_PADDING, AddDeformer, AddPart, AddPhysicsRig, type AlphaBbox, type ApplyAtlasInput, 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, 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, captureBindingEndpoint, computeGridOffsets, createDefaultMatrixDeformer, createDefaultPart, createDefaultWarpDeformer, createGridMesh, createLayerSetMeasurer, denseCoreOf, detectAlphaBbox, foregroundSpan, generateIkiFromLayerSet, headHalfOf, interpolateGridOffsets, isSpeckCore, packAtlas, parseLayerRoles, upsertGridKeyform, uvRectFor, validateDeformerDelete, validateDeformerReparent, validatePartAttach };
|