@lovelace_lol/loom3 1.0.39 → 1.0.41
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 +23 -3
- package/dist/index.cjs +234 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -6
- package/dist/index.d.ts +61 -6
- package/dist/index.js +235 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -92,7 +92,7 @@ declare const CC4_PRESET: Profile;
|
|
|
92
92
|
* - Scalars: extension wins when provided.
|
|
93
93
|
* - Maps: shallow-merged by key, values cloned.
|
|
94
94
|
* - Arrays: replaced when the extension provides them (except annotationRegions).
|
|
95
|
-
* - annotationRegions: merged by region name,
|
|
95
|
+
* - annotationRegions: merged by region name, with nested camera/style fields preserved.
|
|
96
96
|
*/
|
|
97
97
|
declare function extendPresetWithProfile(base: Profile, extension?: Partial<Profile>): Profile;
|
|
98
98
|
|
|
@@ -224,7 +224,7 @@ declare const FISH_AU_MAPPING_CONFIG: {
|
|
|
224
224
|
* Loom3 - Preset Exports
|
|
225
225
|
*
|
|
226
226
|
* All AU presets are exported from here.
|
|
227
|
-
* Frontend passes a presetType string and Loom3 looks up the preset internally.
|
|
227
|
+
* Frontend passes a presetType string and Loom3 looks up or extends the preset internally.
|
|
228
228
|
*/
|
|
229
229
|
|
|
230
230
|
/**
|
|
@@ -315,6 +315,33 @@ interface CompositeRotationState {
|
|
|
315
315
|
roll: number;
|
|
316
316
|
}
|
|
317
317
|
type RotationsState = Record<string, CompositeRotationState>;
|
|
318
|
+
type MorphTargetAttributeData = Float32Array | number[];
|
|
319
|
+
interface MorphTargetDelta {
|
|
320
|
+
/** Mesh name from the loaded Three.js scene. */
|
|
321
|
+
meshName: string;
|
|
322
|
+
/** Morph target name to add to morphTargetDictionary. */
|
|
323
|
+
name: string;
|
|
324
|
+
/** POSITION deltas, usually XYZ values relative to the base mesh. */
|
|
325
|
+
position: MorphTargetAttributeData;
|
|
326
|
+
/** Optional NORMAL deltas. */
|
|
327
|
+
normal?: MorphTargetAttributeData;
|
|
328
|
+
/** Optional TANGENT deltas. */
|
|
329
|
+
tangent?: MorphTargetAttributeData;
|
|
330
|
+
/** Whether deltas are relative to base attributes. Defaults to true. */
|
|
331
|
+
relative?: boolean;
|
|
332
|
+
}
|
|
333
|
+
interface AddMorphTargetOptions {
|
|
334
|
+
/** Replace an existing morph target with the same name. */
|
|
335
|
+
replace?: boolean;
|
|
336
|
+
/** Initialize the new or replaced influence value to zero. Defaults to true. */
|
|
337
|
+
resetInfluence?: boolean;
|
|
338
|
+
/**
|
|
339
|
+
* Replace and dispose the BufferGeometry instead of mutating it in place.
|
|
340
|
+
* Defaults to true because Three.js does not support mutating morph attributes
|
|
341
|
+
* after a geometry has rendered.
|
|
342
|
+
*/
|
|
343
|
+
forceGeometryReplacement?: boolean;
|
|
344
|
+
}
|
|
318
345
|
/** Source category for mixer-driven animations. */
|
|
319
346
|
type AnimationSource = 'baked' | 'clip' | 'snippet';
|
|
320
347
|
/** Shared blend-mode surface for downstream animation UIs. */
|
|
@@ -958,6 +985,25 @@ interface Animation {
|
|
|
958
985
|
* @param meshNames - Optional specific meshes to target
|
|
959
986
|
*/
|
|
960
987
|
transitionMorphInfluence(index: number, to: number, durationMs?: number, meshNames?: string[]): TransitionHandle;
|
|
988
|
+
/**
|
|
989
|
+
* Add or replace a runtime morph target on a mesh.
|
|
990
|
+
* Returns the morphTargetInfluences index assigned to the target.
|
|
991
|
+
*/
|
|
992
|
+
addMorphTarget(target: MorphTargetDelta, options?: AddMorphTargetOptions): number;
|
|
993
|
+
/**
|
|
994
|
+
* Add multiple runtime morph targets and return their assigned indices keyed
|
|
995
|
+
* by "meshName:name".
|
|
996
|
+
*/
|
|
997
|
+
addMorphTargets(targets: MorphTargetDelta[], options?: AddMorphTargetOptions): Record<string, number>;
|
|
998
|
+
/**
|
|
999
|
+
* Ensure a named morph influence slot exists on the mesh.
|
|
1000
|
+
* If the target is missing, a zero-delta morph target is created.
|
|
1001
|
+
*/
|
|
1002
|
+
ensureMorphInfluence(meshName: string, morphName: string): number;
|
|
1003
|
+
/**
|
|
1004
|
+
* Rebuild runtime morph caches after external geometry or dictionary changes.
|
|
1005
|
+
*/
|
|
1006
|
+
refreshMorphTargets(meshNames?: string[]): void;
|
|
961
1007
|
/**
|
|
962
1008
|
* Set viseme value immediately (for lip-sync)
|
|
963
1009
|
* @param visemeIndex - Viseme index 0-14
|
|
@@ -1461,6 +1507,10 @@ declare class Loom3 implements LoomLarge {
|
|
|
1461
1507
|
* @param balance - Optional L/R balance for bilateral morphs
|
|
1462
1508
|
*/
|
|
1463
1509
|
transitionContinuum(negAU: number, posAU: number, continuumValue: number, durationMs?: number, balance?: number): TransitionHandle;
|
|
1510
|
+
addMorphTarget(target: MorphTargetDelta, options?: AddMorphTargetOptions): number;
|
|
1511
|
+
addMorphTargets(targets: MorphTargetDelta[], options?: AddMorphTargetOptions): Record<string, number>;
|
|
1512
|
+
ensureMorphInfluence(meshName: string, morphName: string): number;
|
|
1513
|
+
refreshMorphTargets(_meshNames?: string[]): void;
|
|
1464
1514
|
/**
|
|
1465
1515
|
* Set a morph target value.
|
|
1466
1516
|
*
|
|
@@ -1607,6 +1657,12 @@ declare class Loom3 implements LoomLarge {
|
|
|
1607
1657
|
private applyMorphTargets;
|
|
1608
1658
|
private getMorphValue;
|
|
1609
1659
|
private getMorphValueByIndex;
|
|
1660
|
+
private applyMorphTargetDelta;
|
|
1661
|
+
private requireNamedMesh;
|
|
1662
|
+
private getMeshMorphDictionary;
|
|
1663
|
+
private setMorphAttributeAtIndex;
|
|
1664
|
+
private setZeroMorphAttributeAtIndex;
|
|
1665
|
+
private addRuntimeMorphMesh;
|
|
1610
1666
|
private getMorphKeyCacheKey;
|
|
1611
1667
|
private getMorphIndexCacheKey;
|
|
1612
1668
|
private syncVisemeRuntimeState;
|
|
@@ -2002,10 +2058,9 @@ declare function applyCharacterProfileToPreset(config: CharacterConfig): Profile
|
|
|
2002
2058
|
*
|
|
2003
2059
|
* Precedence:
|
|
2004
2060
|
* 1. preset defaults
|
|
2005
|
-
* 2.
|
|
2006
|
-
* is present
|
|
2061
|
+
* 2. canonical flattened `annotationRegions` / top-level profile overrides
|
|
2007
2062
|
* 3. legacy nested `config.profile` overrides (compatibility only)
|
|
2008
|
-
* 4.
|
|
2063
|
+
* 4. legacy `config.regions` fallback only when canonical annotation overrides are absent
|
|
2009
2064
|
*/
|
|
2010
2065
|
declare function extendCharacterConfigWithPreset(config: CharacterConfig): CharacterConfig;
|
|
2011
2066
|
|
|
@@ -2462,4 +2517,4 @@ declare function detectFacingDirection(model: THREE.Object3D, eyeBoneNames?: {
|
|
|
2462
2517
|
right: string[];
|
|
2463
2518
|
}): 'forward' | 'backward' | 'unknown';
|
|
2464
2519
|
|
|
2465
|
-
export { type AUInfo, type AUSelector, AU_INFO, AU_MAPPING_CONFIG, AU_MIX_DEFAULTS, AU_TO_MORPHS, type AnalyzeModelOptions, type Animation, type AnimationActionHandle, type AnimationAnalysis, type AnimationBlendMode, type AnimationClipInfo, type AnimationEasing, type AnimationInfo, type AnimationPlayOptions, type AnimationSource, type AnimationState, AnimationThree, BETTA_FISH_PRESET, BLENDING_MODES, BONE_AU_TO_BINDINGS, type BlendingMode, type BoneBinding, type BoneInfo, type BoneKey, CC4_BONE_NODES, CC4_BONE_PREFIX, CC4_EYE_MESH_NODES, CC4_MESHES, CC4_PRESET, CC4_SUFFIX_PATTERN, COMPOSITE_ROTATIONS, CONTINUUM_LABELS, CONTINUUM_PAIRS_MAP, type CameraRelativeGazeOffset, type CameraRelativeGazeOptions, type CharacterConfig, type CharacterRegistry, type ClipEvent, type ClipEventListener, type ClipHandle, type ClipOptions, type CompositeRotation, type CompositeRotationState, type CurvePoint, type CurvesMap, DEFAULT_HAIR_PHYSICS_CONFIG, type ExpandAnimation, type ExpandedRegionState, FISH_AU_MAPPING_CONFIG, type FaceCenterResult, type FallbackConfig, type FindFaceCenterOptions, type Hair, type HairMorphAxis, type HairMorphOutput$1 as HairMorphOutput, type HairMorphTargetMapping, type HairMorphTargetValueMapping, type HairMorphTargetsConfig, type HairObjectRef, type HairObjectState, HairPhysics, type HairPhysicsConfig$1 as HairPhysicsConfig, type HairPhysicsDirectionConfig, type HairPhysics$1 as HairPhysicsInterface, type HairMorphOutput as HairPhysicsMorphOutput, type HairPhysicsProfileConfig, type HairPhysicsRuntimeConfig, type HairPhysicsRuntimeConfigUpdate, type HairPhysicsState, type HairState, type HairStrand, type HeadState$1 as HeadState, type LineConfig, type LineCurve, type LineStyle, Loom3, type Loom3Config, Loom3 as Loom3Three, type LoomLarge, type LoomLargeConfig, Loom3 as LoomLargeThree, MORPH_TO_MESH, type MappingConsistencyResult, type MappingCorrection, type MappingCorrectionOptions, type MappingCorrectionResult, type MappingIssue, type MarkerGroup, type MarkerStyle, type MarkerStyleOverrides, type MeshCategory, type MeshInfo, type MeshMaterialSettings, type MixerLoopMode, type ModelAnalysisReport, type ModelData, type ModelMeshInfo, type MorphCategory, type MorphInfo, type MorphTargetRef, type MorphTargetsBySide, type NamedDirection, type PresetType, type Profile, type ReadyPayload, type Region, type RotationAxis, type RotationsState, type Snippet, type TrackInfo, type TransitionHandle, VISEME_JAW_AMOUNTS, VISEME_KEYS, type ValidateMappingOptions, type ValidationResult, analyzeModel, applyCharacterProfileToPreset, collectMorphMeshes, computeCameraRelativeGazeOffset, detectFacingDirection, extendCharacterConfigWithPreset, extendPresetWithProfile, extractFromGLTF, extractModelData, extractProfileOverrides, findFaceCenter, fuzzyNameMatch, generateMappingCorrections, getModelForwardDirection, getPreset, getPresetWithProfile, hasLeftRightMorphs, isMixedAU, isPresetCompatible, mergeRegionsByName as mergeCharacterRegionsByName, resolveBoneName, resolveBoneNames, resolveFaceCenter, resolvePreset, resolvePresetWithOverrides, suggestBestPreset, validateMappingConfig, validateMappings };
|
|
2520
|
+
export { type AUInfo, type AUSelector, AU_INFO, AU_MAPPING_CONFIG, AU_MIX_DEFAULTS, AU_TO_MORPHS, type AddMorphTargetOptions, type AnalyzeModelOptions, type Animation, type AnimationActionHandle, type AnimationAnalysis, type AnimationBlendMode, type AnimationClipInfo, type AnimationEasing, type AnimationInfo, type AnimationPlayOptions, type AnimationSource, type AnimationState, AnimationThree, BETTA_FISH_PRESET, BLENDING_MODES, BONE_AU_TO_BINDINGS, type BlendingMode, type BoneBinding, type BoneInfo, type BoneKey, CC4_BONE_NODES, CC4_BONE_PREFIX, CC4_EYE_MESH_NODES, CC4_MESHES, CC4_PRESET, CC4_SUFFIX_PATTERN, COMPOSITE_ROTATIONS, CONTINUUM_LABELS, CONTINUUM_PAIRS_MAP, type CameraRelativeGazeOffset, type CameraRelativeGazeOptions, type CharacterConfig, type CharacterRegistry, type ClipEvent, type ClipEventListener, type ClipHandle, type ClipOptions, type CompositeRotation, type CompositeRotationState, type CurvePoint, type CurvesMap, DEFAULT_HAIR_PHYSICS_CONFIG, type ExpandAnimation, type ExpandedRegionState, FISH_AU_MAPPING_CONFIG, type FaceCenterResult, type FallbackConfig, type FindFaceCenterOptions, type Hair, type HairMorphAxis, type HairMorphOutput$1 as HairMorphOutput, type HairMorphTargetMapping, type HairMorphTargetValueMapping, type HairMorphTargetsConfig, type HairObjectRef, type HairObjectState, HairPhysics, type HairPhysicsConfig$1 as HairPhysicsConfig, type HairPhysicsDirectionConfig, type HairPhysics$1 as HairPhysicsInterface, type HairMorphOutput as HairPhysicsMorphOutput, type HairPhysicsProfileConfig, type HairPhysicsRuntimeConfig, type HairPhysicsRuntimeConfigUpdate, type HairPhysicsState, type HairState, type HairStrand, type HeadState$1 as HeadState, type LineConfig, type LineCurve, type LineStyle, Loom3, type Loom3Config, Loom3 as Loom3Three, type LoomLarge, type LoomLargeConfig, Loom3 as LoomLargeThree, MORPH_TO_MESH, type MappingConsistencyResult, type MappingCorrection, type MappingCorrectionOptions, type MappingCorrectionResult, type MappingIssue, type MarkerGroup, type MarkerStyle, type MarkerStyleOverrides, type MeshCategory, type MeshInfo, type MeshMaterialSettings, type MixerLoopMode, type ModelAnalysisReport, type ModelData, type ModelMeshInfo, type MorphCategory, type MorphInfo, type MorphTargetAttributeData, type MorphTargetDelta, type MorphTargetRef, type MorphTargetsBySide, type NamedDirection, type PresetType, type Profile, type ReadyPayload, type Region, type RotationAxis, type RotationsState, type Snippet, type TrackInfo, type TransitionHandle, VISEME_JAW_AMOUNTS, VISEME_KEYS, type ValidateMappingOptions, type ValidationResult, analyzeModel, applyCharacterProfileToPreset, collectMorphMeshes, computeCameraRelativeGazeOffset, detectFacingDirection, extendCharacterConfigWithPreset, extendPresetWithProfile, extractFromGLTF, extractModelData, extractProfileOverrides, findFaceCenter, fuzzyNameMatch, generateMappingCorrections, getModelForwardDirection, getPreset, getPresetWithProfile, hasLeftRightMorphs, isMixedAU, isPresetCompatible, mergeRegionsByName as mergeCharacterRegionsByName, resolveBoneName, resolveBoneNames, resolveFaceCenter, resolvePreset, resolvePresetWithOverrides, suggestBestPreset, validateMappingConfig, validateMappings };
|
package/dist/index.d.ts
CHANGED
|
@@ -92,7 +92,7 @@ declare const CC4_PRESET: Profile;
|
|
|
92
92
|
* - Scalars: extension wins when provided.
|
|
93
93
|
* - Maps: shallow-merged by key, values cloned.
|
|
94
94
|
* - Arrays: replaced when the extension provides them (except annotationRegions).
|
|
95
|
-
* - annotationRegions: merged by region name,
|
|
95
|
+
* - annotationRegions: merged by region name, with nested camera/style fields preserved.
|
|
96
96
|
*/
|
|
97
97
|
declare function extendPresetWithProfile(base: Profile, extension?: Partial<Profile>): Profile;
|
|
98
98
|
|
|
@@ -224,7 +224,7 @@ declare const FISH_AU_MAPPING_CONFIG: {
|
|
|
224
224
|
* Loom3 - Preset Exports
|
|
225
225
|
*
|
|
226
226
|
* All AU presets are exported from here.
|
|
227
|
-
* Frontend passes a presetType string and Loom3 looks up the preset internally.
|
|
227
|
+
* Frontend passes a presetType string and Loom3 looks up or extends the preset internally.
|
|
228
228
|
*/
|
|
229
229
|
|
|
230
230
|
/**
|
|
@@ -315,6 +315,33 @@ interface CompositeRotationState {
|
|
|
315
315
|
roll: number;
|
|
316
316
|
}
|
|
317
317
|
type RotationsState = Record<string, CompositeRotationState>;
|
|
318
|
+
type MorphTargetAttributeData = Float32Array | number[];
|
|
319
|
+
interface MorphTargetDelta {
|
|
320
|
+
/** Mesh name from the loaded Three.js scene. */
|
|
321
|
+
meshName: string;
|
|
322
|
+
/** Morph target name to add to morphTargetDictionary. */
|
|
323
|
+
name: string;
|
|
324
|
+
/** POSITION deltas, usually XYZ values relative to the base mesh. */
|
|
325
|
+
position: MorphTargetAttributeData;
|
|
326
|
+
/** Optional NORMAL deltas. */
|
|
327
|
+
normal?: MorphTargetAttributeData;
|
|
328
|
+
/** Optional TANGENT deltas. */
|
|
329
|
+
tangent?: MorphTargetAttributeData;
|
|
330
|
+
/** Whether deltas are relative to base attributes. Defaults to true. */
|
|
331
|
+
relative?: boolean;
|
|
332
|
+
}
|
|
333
|
+
interface AddMorphTargetOptions {
|
|
334
|
+
/** Replace an existing morph target with the same name. */
|
|
335
|
+
replace?: boolean;
|
|
336
|
+
/** Initialize the new or replaced influence value to zero. Defaults to true. */
|
|
337
|
+
resetInfluence?: boolean;
|
|
338
|
+
/**
|
|
339
|
+
* Replace and dispose the BufferGeometry instead of mutating it in place.
|
|
340
|
+
* Defaults to true because Three.js does not support mutating morph attributes
|
|
341
|
+
* after a geometry has rendered.
|
|
342
|
+
*/
|
|
343
|
+
forceGeometryReplacement?: boolean;
|
|
344
|
+
}
|
|
318
345
|
/** Source category for mixer-driven animations. */
|
|
319
346
|
type AnimationSource = 'baked' | 'clip' | 'snippet';
|
|
320
347
|
/** Shared blend-mode surface for downstream animation UIs. */
|
|
@@ -958,6 +985,25 @@ interface Animation {
|
|
|
958
985
|
* @param meshNames - Optional specific meshes to target
|
|
959
986
|
*/
|
|
960
987
|
transitionMorphInfluence(index: number, to: number, durationMs?: number, meshNames?: string[]): TransitionHandle;
|
|
988
|
+
/**
|
|
989
|
+
* Add or replace a runtime morph target on a mesh.
|
|
990
|
+
* Returns the morphTargetInfluences index assigned to the target.
|
|
991
|
+
*/
|
|
992
|
+
addMorphTarget(target: MorphTargetDelta, options?: AddMorphTargetOptions): number;
|
|
993
|
+
/**
|
|
994
|
+
* Add multiple runtime morph targets and return their assigned indices keyed
|
|
995
|
+
* by "meshName:name".
|
|
996
|
+
*/
|
|
997
|
+
addMorphTargets(targets: MorphTargetDelta[], options?: AddMorphTargetOptions): Record<string, number>;
|
|
998
|
+
/**
|
|
999
|
+
* Ensure a named morph influence slot exists on the mesh.
|
|
1000
|
+
* If the target is missing, a zero-delta morph target is created.
|
|
1001
|
+
*/
|
|
1002
|
+
ensureMorphInfluence(meshName: string, morphName: string): number;
|
|
1003
|
+
/**
|
|
1004
|
+
* Rebuild runtime morph caches after external geometry or dictionary changes.
|
|
1005
|
+
*/
|
|
1006
|
+
refreshMorphTargets(meshNames?: string[]): void;
|
|
961
1007
|
/**
|
|
962
1008
|
* Set viseme value immediately (for lip-sync)
|
|
963
1009
|
* @param visemeIndex - Viseme index 0-14
|
|
@@ -1461,6 +1507,10 @@ declare class Loom3 implements LoomLarge {
|
|
|
1461
1507
|
* @param balance - Optional L/R balance for bilateral morphs
|
|
1462
1508
|
*/
|
|
1463
1509
|
transitionContinuum(negAU: number, posAU: number, continuumValue: number, durationMs?: number, balance?: number): TransitionHandle;
|
|
1510
|
+
addMorphTarget(target: MorphTargetDelta, options?: AddMorphTargetOptions): number;
|
|
1511
|
+
addMorphTargets(targets: MorphTargetDelta[], options?: AddMorphTargetOptions): Record<string, number>;
|
|
1512
|
+
ensureMorphInfluence(meshName: string, morphName: string): number;
|
|
1513
|
+
refreshMorphTargets(_meshNames?: string[]): void;
|
|
1464
1514
|
/**
|
|
1465
1515
|
* Set a morph target value.
|
|
1466
1516
|
*
|
|
@@ -1607,6 +1657,12 @@ declare class Loom3 implements LoomLarge {
|
|
|
1607
1657
|
private applyMorphTargets;
|
|
1608
1658
|
private getMorphValue;
|
|
1609
1659
|
private getMorphValueByIndex;
|
|
1660
|
+
private applyMorphTargetDelta;
|
|
1661
|
+
private requireNamedMesh;
|
|
1662
|
+
private getMeshMorphDictionary;
|
|
1663
|
+
private setMorphAttributeAtIndex;
|
|
1664
|
+
private setZeroMorphAttributeAtIndex;
|
|
1665
|
+
private addRuntimeMorphMesh;
|
|
1610
1666
|
private getMorphKeyCacheKey;
|
|
1611
1667
|
private getMorphIndexCacheKey;
|
|
1612
1668
|
private syncVisemeRuntimeState;
|
|
@@ -2002,10 +2058,9 @@ declare function applyCharacterProfileToPreset(config: CharacterConfig): Profile
|
|
|
2002
2058
|
*
|
|
2003
2059
|
* Precedence:
|
|
2004
2060
|
* 1. preset defaults
|
|
2005
|
-
* 2.
|
|
2006
|
-
* is present
|
|
2061
|
+
* 2. canonical flattened `annotationRegions` / top-level profile overrides
|
|
2007
2062
|
* 3. legacy nested `config.profile` overrides (compatibility only)
|
|
2008
|
-
* 4.
|
|
2063
|
+
* 4. legacy `config.regions` fallback only when canonical annotation overrides are absent
|
|
2009
2064
|
*/
|
|
2010
2065
|
declare function extendCharacterConfigWithPreset(config: CharacterConfig): CharacterConfig;
|
|
2011
2066
|
|
|
@@ -2462,4 +2517,4 @@ declare function detectFacingDirection(model: THREE.Object3D, eyeBoneNames?: {
|
|
|
2462
2517
|
right: string[];
|
|
2463
2518
|
}): 'forward' | 'backward' | 'unknown';
|
|
2464
2519
|
|
|
2465
|
-
export { type AUInfo, type AUSelector, AU_INFO, AU_MAPPING_CONFIG, AU_MIX_DEFAULTS, AU_TO_MORPHS, type AnalyzeModelOptions, type Animation, type AnimationActionHandle, type AnimationAnalysis, type AnimationBlendMode, type AnimationClipInfo, type AnimationEasing, type AnimationInfo, type AnimationPlayOptions, type AnimationSource, type AnimationState, AnimationThree, BETTA_FISH_PRESET, BLENDING_MODES, BONE_AU_TO_BINDINGS, type BlendingMode, type BoneBinding, type BoneInfo, type BoneKey, CC4_BONE_NODES, CC4_BONE_PREFIX, CC4_EYE_MESH_NODES, CC4_MESHES, CC4_PRESET, CC4_SUFFIX_PATTERN, COMPOSITE_ROTATIONS, CONTINUUM_LABELS, CONTINUUM_PAIRS_MAP, type CameraRelativeGazeOffset, type CameraRelativeGazeOptions, type CharacterConfig, type CharacterRegistry, type ClipEvent, type ClipEventListener, type ClipHandle, type ClipOptions, type CompositeRotation, type CompositeRotationState, type CurvePoint, type CurvesMap, DEFAULT_HAIR_PHYSICS_CONFIG, type ExpandAnimation, type ExpandedRegionState, FISH_AU_MAPPING_CONFIG, type FaceCenterResult, type FallbackConfig, type FindFaceCenterOptions, type Hair, type HairMorphAxis, type HairMorphOutput$1 as HairMorphOutput, type HairMorphTargetMapping, type HairMorphTargetValueMapping, type HairMorphTargetsConfig, type HairObjectRef, type HairObjectState, HairPhysics, type HairPhysicsConfig$1 as HairPhysicsConfig, type HairPhysicsDirectionConfig, type HairPhysics$1 as HairPhysicsInterface, type HairMorphOutput as HairPhysicsMorphOutput, type HairPhysicsProfileConfig, type HairPhysicsRuntimeConfig, type HairPhysicsRuntimeConfigUpdate, type HairPhysicsState, type HairState, type HairStrand, type HeadState$1 as HeadState, type LineConfig, type LineCurve, type LineStyle, Loom3, type Loom3Config, Loom3 as Loom3Three, type LoomLarge, type LoomLargeConfig, Loom3 as LoomLargeThree, MORPH_TO_MESH, type MappingConsistencyResult, type MappingCorrection, type MappingCorrectionOptions, type MappingCorrectionResult, type MappingIssue, type MarkerGroup, type MarkerStyle, type MarkerStyleOverrides, type MeshCategory, type MeshInfo, type MeshMaterialSettings, type MixerLoopMode, type ModelAnalysisReport, type ModelData, type ModelMeshInfo, type MorphCategory, type MorphInfo, type MorphTargetRef, type MorphTargetsBySide, type NamedDirection, type PresetType, type Profile, type ReadyPayload, type Region, type RotationAxis, type RotationsState, type Snippet, type TrackInfo, type TransitionHandle, VISEME_JAW_AMOUNTS, VISEME_KEYS, type ValidateMappingOptions, type ValidationResult, analyzeModel, applyCharacterProfileToPreset, collectMorphMeshes, computeCameraRelativeGazeOffset, detectFacingDirection, extendCharacterConfigWithPreset, extendPresetWithProfile, extractFromGLTF, extractModelData, extractProfileOverrides, findFaceCenter, fuzzyNameMatch, generateMappingCorrections, getModelForwardDirection, getPreset, getPresetWithProfile, hasLeftRightMorphs, isMixedAU, isPresetCompatible, mergeRegionsByName as mergeCharacterRegionsByName, resolveBoneName, resolveBoneNames, resolveFaceCenter, resolvePreset, resolvePresetWithOverrides, suggestBestPreset, validateMappingConfig, validateMappings };
|
|
2520
|
+
export { type AUInfo, type AUSelector, AU_INFO, AU_MAPPING_CONFIG, AU_MIX_DEFAULTS, AU_TO_MORPHS, type AddMorphTargetOptions, type AnalyzeModelOptions, type Animation, type AnimationActionHandle, type AnimationAnalysis, type AnimationBlendMode, type AnimationClipInfo, type AnimationEasing, type AnimationInfo, type AnimationPlayOptions, type AnimationSource, type AnimationState, AnimationThree, BETTA_FISH_PRESET, BLENDING_MODES, BONE_AU_TO_BINDINGS, type BlendingMode, type BoneBinding, type BoneInfo, type BoneKey, CC4_BONE_NODES, CC4_BONE_PREFIX, CC4_EYE_MESH_NODES, CC4_MESHES, CC4_PRESET, CC4_SUFFIX_PATTERN, COMPOSITE_ROTATIONS, CONTINUUM_LABELS, CONTINUUM_PAIRS_MAP, type CameraRelativeGazeOffset, type CameraRelativeGazeOptions, type CharacterConfig, type CharacterRegistry, type ClipEvent, type ClipEventListener, type ClipHandle, type ClipOptions, type CompositeRotation, type CompositeRotationState, type CurvePoint, type CurvesMap, DEFAULT_HAIR_PHYSICS_CONFIG, type ExpandAnimation, type ExpandedRegionState, FISH_AU_MAPPING_CONFIG, type FaceCenterResult, type FallbackConfig, type FindFaceCenterOptions, type Hair, type HairMorphAxis, type HairMorphOutput$1 as HairMorphOutput, type HairMorphTargetMapping, type HairMorphTargetValueMapping, type HairMorphTargetsConfig, type HairObjectRef, type HairObjectState, HairPhysics, type HairPhysicsConfig$1 as HairPhysicsConfig, type HairPhysicsDirectionConfig, type HairPhysics$1 as HairPhysicsInterface, type HairMorphOutput as HairPhysicsMorphOutput, type HairPhysicsProfileConfig, type HairPhysicsRuntimeConfig, type HairPhysicsRuntimeConfigUpdate, type HairPhysicsState, type HairState, type HairStrand, type HeadState$1 as HeadState, type LineConfig, type LineCurve, type LineStyle, Loom3, type Loom3Config, Loom3 as Loom3Three, type LoomLarge, type LoomLargeConfig, Loom3 as LoomLargeThree, MORPH_TO_MESH, type MappingConsistencyResult, type MappingCorrection, type MappingCorrectionOptions, type MappingCorrectionResult, type MappingIssue, type MarkerGroup, type MarkerStyle, type MarkerStyleOverrides, type MeshCategory, type MeshInfo, type MeshMaterialSettings, type MixerLoopMode, type ModelAnalysisReport, type ModelData, type ModelMeshInfo, type MorphCategory, type MorphInfo, type MorphTargetAttributeData, type MorphTargetDelta, type MorphTargetRef, type MorphTargetsBySide, type NamedDirection, type PresetType, type Profile, type ReadyPayload, type Region, type RotationAxis, type RotationsState, type Snippet, type TrackInfo, type TransitionHandle, VISEME_JAW_AMOUNTS, VISEME_KEYS, type ValidateMappingOptions, type ValidationResult, analyzeModel, applyCharacterProfileToPreset, collectMorphMeshes, computeCameraRelativeGazeOffset, detectFacingDirection, extendCharacterConfigWithPreset, extendPresetWithProfile, extractFromGLTF, extractModelData, extractProfileOverrides, findFaceCenter, fuzzyNameMatch, generateMappingCorrections, getModelForwardDirection, getPreset, getPresetWithProfile, hasLeftRightMorphs, isMixedAU, isPresetCompatible, mergeRegionsByName as mergeCharacterRegionsByName, resolveBoneName, resolveBoneNames, resolveFaceCenter, resolvePreset, resolvePresetWithOverrides, suggestBestPreset, validateMappingConfig, validateMappings };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as THREE2 from 'three';
|
|
2
|
-
import { Vector3, Clock, Box3, Quaternion, AdditiveAnimationBlendMode, NormalAnimationBlendMode, LoopPingPong, LoopOnce, LoopRepeat, QuaternionKeyframeTrack, NumberKeyframeTrack, AnimationClip, AnimationMixer, Mesh, PropertyBinding } from 'three';
|
|
2
|
+
import { Vector3, Clock, Box3, BufferAttribute, Quaternion, AdditiveAnimationBlendMode, NormalAnimationBlendMode, LoopPingPong, LoopOnce, LoopRepeat, QuaternionKeyframeTrack, NumberKeyframeTrack, AnimationClip, AnimationMixer, Mesh, PropertyBinding } from 'three';
|
|
3
3
|
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -3552,7 +3552,7 @@ var mergeAnnotationRegion = (base, override) => {
|
|
|
3552
3552
|
merged.meshes = override.meshes ? [...override.meshes] : base.meshes ? [...base.meshes] : void 0;
|
|
3553
3553
|
merged.objects = override.objects ? [...override.objects] : base.objects ? [...base.objects] : void 0;
|
|
3554
3554
|
merged.children = override.children ? [...override.children] : base.children ? [...base.children] : void 0;
|
|
3555
|
-
merged.cameraOffset = override.cameraOffset ? { ...override.cameraOffset } : base.cameraOffset ? { ...base.cameraOffset } : void 0;
|
|
3555
|
+
merged.cameraOffset = override.cameraOffset ? { ...base.cameraOffset, ...override.cameraOffset } : base.cameraOffset ? { ...base.cameraOffset } : void 0;
|
|
3556
3556
|
merged.style = override.style ? {
|
|
3557
3557
|
...base.style,
|
|
3558
3558
|
...override.style,
|
|
@@ -4617,11 +4617,7 @@ var _Loom3 = class _Loom3 {
|
|
|
4617
4617
|
this.morphIndexCache.clear();
|
|
4618
4618
|
model.traverse((obj) => {
|
|
4619
4619
|
if (obj.isMesh && obj.name) {
|
|
4620
|
-
|
|
4621
|
-
const dict = obj.morphTargetDictionary;
|
|
4622
|
-
if (Array.isArray(infl) && infl.length > 0 || dict && Object.keys(dict).length > 0) {
|
|
4623
|
-
this.meshByName.set(obj.name, obj);
|
|
4624
|
-
}
|
|
4620
|
+
this.meshByName.set(obj.name, obj);
|
|
4625
4621
|
}
|
|
4626
4622
|
});
|
|
4627
4623
|
this.bones = this.resolveBones(model);
|
|
@@ -4989,6 +4985,58 @@ var _Loom3 = class _Loom3 {
|
|
|
4989
4985
|
const currentContinuum = currentPos - currentNeg;
|
|
4990
4986
|
return this.animation.addTransition(driverKey, currentContinuum, target, durationMs, (value) => this.setContinuum(negAU, posAU, value, balance));
|
|
4991
4987
|
}
|
|
4988
|
+
// ============================================================================
|
|
4989
|
+
// MORPH CONTROL
|
|
4990
|
+
// ============================================================================
|
|
4991
|
+
addMorphTarget(target, options = {}) {
|
|
4992
|
+
const staleMorphTargets = this.collectResolvedExpressionMorphTargets();
|
|
4993
|
+
const index = this.applyMorphTargetDelta(target, options);
|
|
4994
|
+
this.refreshMorphTargets([target.meshName]);
|
|
4995
|
+
this.reinitializeRuntimeStateFromCurrentControls(staleMorphTargets);
|
|
4996
|
+
return index;
|
|
4997
|
+
}
|
|
4998
|
+
addMorphTargets(targets, options = {}) {
|
|
4999
|
+
const staleMorphTargets = this.collectResolvedExpressionMorphTargets();
|
|
5000
|
+
const result = {};
|
|
5001
|
+
for (const target of targets) {
|
|
5002
|
+
const index = this.applyMorphTargetDelta(target, options);
|
|
5003
|
+
result[`${target.meshName}:${target.name}`] = index;
|
|
5004
|
+
}
|
|
5005
|
+
this.refreshMorphTargets(Array.from(new Set(targets.map((target) => target.meshName))));
|
|
5006
|
+
this.reinitializeRuntimeStateFromCurrentControls(staleMorphTargets);
|
|
5007
|
+
return result;
|
|
5008
|
+
}
|
|
5009
|
+
ensureMorphInfluence(meshName, morphName) {
|
|
5010
|
+
const mesh = this.requireNamedMesh(meshName);
|
|
5011
|
+
const dict = this.getMeshMorphDictionary(mesh);
|
|
5012
|
+
const existing = dict[morphName];
|
|
5013
|
+
if (existing !== void 0) return existing;
|
|
5014
|
+
const position = mesh.geometry.getAttribute("position");
|
|
5015
|
+
if (!position) {
|
|
5016
|
+
throw new Error(`Cannot create morph target "${morphName}" on mesh "${meshName}": geometry has no position attribute.`);
|
|
5017
|
+
}
|
|
5018
|
+
return this.addMorphTarget({
|
|
5019
|
+
meshName,
|
|
5020
|
+
name: morphName,
|
|
5021
|
+
position: new Float32Array(position.count * position.itemSize),
|
|
5022
|
+
relative: true
|
|
5023
|
+
});
|
|
5024
|
+
}
|
|
5025
|
+
refreshMorphTargets(_meshNames) {
|
|
5026
|
+
this.morphKeyCache.clear();
|
|
5027
|
+
this.morphIndexCache.clear();
|
|
5028
|
+
if (this.model) {
|
|
5029
|
+
this.meshByName.clear();
|
|
5030
|
+
this.model.traverse((obj) => {
|
|
5031
|
+
if (obj.isMesh && obj.name) {
|
|
5032
|
+
this.meshByName.set(obj.name, obj);
|
|
5033
|
+
}
|
|
5034
|
+
});
|
|
5035
|
+
this.meshes = collectMorphMeshes(this.model);
|
|
5036
|
+
}
|
|
5037
|
+
this.rebuildMorphTargetsCache();
|
|
5038
|
+
this.hairPhysics.refreshMeshSelection();
|
|
5039
|
+
}
|
|
4992
5040
|
setMorph(key, v, meshNamesOrTargets) {
|
|
4993
5041
|
const val = clamp012(v);
|
|
4994
5042
|
if (Array.isArray(meshNamesOrTargets) && meshNamesOrTargets.length > 0 && typeof meshNamesOrTargets[0] === "object" && "infl" in meshNamesOrTargets[0]) {
|
|
@@ -5607,6 +5655,148 @@ var _Loom3 = class _Loom3 {
|
|
|
5607
5655
|
}
|
|
5608
5656
|
return 0;
|
|
5609
5657
|
}
|
|
5658
|
+
applyMorphTargetDelta(target, options) {
|
|
5659
|
+
const mesh = this.requireNamedMesh(target.meshName);
|
|
5660
|
+
const sourceGeometry = mesh.geometry;
|
|
5661
|
+
const position = sourceGeometry.getAttribute("position");
|
|
5662
|
+
if (!position) {
|
|
5663
|
+
throw new Error(`Cannot add morph target "${target.name}" to mesh "${target.meshName}": geometry has no position attribute.`);
|
|
5664
|
+
}
|
|
5665
|
+
if (!target.name || !target.name.trim()) {
|
|
5666
|
+
throw new Error(`Cannot add morph target to mesh "${target.meshName}": target name is required.`);
|
|
5667
|
+
}
|
|
5668
|
+
const replace = options.replace === true;
|
|
5669
|
+
const resetInfluence = options.resetInfluence !== false;
|
|
5670
|
+
const forceGeometryReplacement = options.forceGeometryReplacement !== false;
|
|
5671
|
+
const previousInfluences = mesh.morphTargetInfluences ? [...mesh.morphTargetInfluences] : [];
|
|
5672
|
+
const previousDictionary = this.getMeshMorphDictionary(mesh);
|
|
5673
|
+
const existingIndex = previousDictionary[target.name];
|
|
5674
|
+
if (existingIndex !== void 0 && !replace) {
|
|
5675
|
+
throw new Error(`Morph target "${target.name}" already exists on mesh "${target.meshName}". Pass replace: true to overwrite it.`);
|
|
5676
|
+
}
|
|
5677
|
+
const geometry = forceGeometryReplacement ? sourceGeometry.clone() : sourceGeometry;
|
|
5678
|
+
const dictionary = { ...previousDictionary };
|
|
5679
|
+
const usedIndices = Object.values(dictionary).filter(Number.isInteger);
|
|
5680
|
+
const existingAttributeTargetCount = Math.max(
|
|
5681
|
+
0,
|
|
5682
|
+
...Object.values(geometry.morphAttributes).map((attributes) => attributes?.length ?? 0)
|
|
5683
|
+
);
|
|
5684
|
+
const nextIndex = Math.max(existingAttributeTargetCount, usedIndices.length ? Math.max(...usedIndices) + 1 : 0);
|
|
5685
|
+
const index = existingIndex ?? nextIndex;
|
|
5686
|
+
dictionary[target.name] = index;
|
|
5687
|
+
this.setMorphAttributeAtIndex(geometry, "position", target.position, position.itemSize, position.count, index, target.name);
|
|
5688
|
+
const normal = geometry.getAttribute("normal");
|
|
5689
|
+
if (target.normal) {
|
|
5690
|
+
this.setMorphAttributeAtIndex(geometry, "normal", target.normal, normal?.itemSize ?? 3, position.count, index, target.name);
|
|
5691
|
+
} else {
|
|
5692
|
+
this.setZeroMorphAttributeAtIndex(geometry, "normal", normal?.itemSize ?? 3, position.count, index, target.name);
|
|
5693
|
+
}
|
|
5694
|
+
const tangent = geometry.getAttribute("tangent");
|
|
5695
|
+
if (target.tangent) {
|
|
5696
|
+
this.setMorphAttributeAtIndex(geometry, "tangent", target.tangent, tangent?.itemSize ?? 4, position.count, index, target.name);
|
|
5697
|
+
} else {
|
|
5698
|
+
this.setZeroMorphAttributeAtIndex(geometry, "tangent", tangent?.itemSize ?? 4, position.count, index, target.name);
|
|
5699
|
+
}
|
|
5700
|
+
const color = geometry.getAttribute("color");
|
|
5701
|
+
const existingColorMorph = geometry.morphAttributes.color?.find(Boolean);
|
|
5702
|
+
this.setZeroMorphAttributeAtIndex(
|
|
5703
|
+
geometry,
|
|
5704
|
+
"color",
|
|
5705
|
+
color?.itemSize ?? existingColorMorph?.itemSize ?? 3,
|
|
5706
|
+
position.count,
|
|
5707
|
+
index,
|
|
5708
|
+
target.name
|
|
5709
|
+
);
|
|
5710
|
+
geometry.morphTargetsRelative = target.relative !== false;
|
|
5711
|
+
geometry.morphTargetDictionary = dictionary;
|
|
5712
|
+
if (forceGeometryReplacement) {
|
|
5713
|
+
mesh.geometry = geometry;
|
|
5714
|
+
sourceGeometry.dispose();
|
|
5715
|
+
}
|
|
5716
|
+
const influenceLength = Math.max(previousInfluences.length, index + 1);
|
|
5717
|
+
const influences = previousInfluences.slice(0, influenceLength);
|
|
5718
|
+
while (influences.length < influenceLength) {
|
|
5719
|
+
influences.push(0);
|
|
5720
|
+
}
|
|
5721
|
+
if (resetInfluence) {
|
|
5722
|
+
influences[index] = 0;
|
|
5723
|
+
}
|
|
5724
|
+
mesh.morphTargetDictionary = dictionary;
|
|
5725
|
+
mesh.morphTargetInfluences = influences;
|
|
5726
|
+
this.addRuntimeMorphMesh(mesh);
|
|
5727
|
+
if (!this.config.morphToMesh?.face?.length) {
|
|
5728
|
+
this.config.morphToMesh = {
|
|
5729
|
+
...this.config.morphToMesh,
|
|
5730
|
+
face: [mesh.name]
|
|
5731
|
+
};
|
|
5732
|
+
}
|
|
5733
|
+
return index;
|
|
5734
|
+
}
|
|
5735
|
+
requireNamedMesh(meshName) {
|
|
5736
|
+
const mesh = this.meshByName.get(meshName);
|
|
5737
|
+
if (mesh) return mesh;
|
|
5738
|
+
if (this.model) {
|
|
5739
|
+
let found = null;
|
|
5740
|
+
this.model.traverse((obj) => {
|
|
5741
|
+
if (!found && obj.isMesh && obj.name === meshName) {
|
|
5742
|
+
found = obj;
|
|
5743
|
+
}
|
|
5744
|
+
});
|
|
5745
|
+
if (found) {
|
|
5746
|
+
this.meshByName.set(meshName, found);
|
|
5747
|
+
return found;
|
|
5748
|
+
}
|
|
5749
|
+
}
|
|
5750
|
+
throw new Error(`Mesh "${meshName}" was not found in the current model.`);
|
|
5751
|
+
}
|
|
5752
|
+
getMeshMorphDictionary(mesh) {
|
|
5753
|
+
const meshDictionary = mesh.morphTargetDictionary;
|
|
5754
|
+
const geometryDictionary = mesh.geometry.morphTargetDictionary;
|
|
5755
|
+
const dictionary = meshDictionary || geometryDictionary || {};
|
|
5756
|
+
mesh.morphTargetDictionary = dictionary;
|
|
5757
|
+
mesh.geometry.morphTargetDictionary = dictionary;
|
|
5758
|
+
return dictionary;
|
|
5759
|
+
}
|
|
5760
|
+
setMorphAttributeAtIndex(geometry, semantic, data, itemSize, vertexCount, index, name) {
|
|
5761
|
+
const expectedLength = vertexCount * itemSize;
|
|
5762
|
+
if (data.length !== expectedLength) {
|
|
5763
|
+
throw new Error(
|
|
5764
|
+
`Morph target "${name}" ${semantic} data has ${data.length} values; expected ${expectedLength} (${vertexCount} vertices * itemSize ${itemSize}).`
|
|
5765
|
+
);
|
|
5766
|
+
}
|
|
5767
|
+
const attributes = geometry.morphAttributes[semantic] ? [...geometry.morphAttributes[semantic]] : [];
|
|
5768
|
+
while (attributes.length < index) {
|
|
5769
|
+
const empty = new BufferAttribute(new Float32Array(expectedLength), itemSize);
|
|
5770
|
+
empty.name = `morph_${attributes.length}`;
|
|
5771
|
+
attributes.push(empty);
|
|
5772
|
+
}
|
|
5773
|
+
const values = data instanceof Float32Array ? new Float32Array(data) : Float32Array.from(data);
|
|
5774
|
+
const attribute = new BufferAttribute(values, itemSize);
|
|
5775
|
+
attribute.name = name;
|
|
5776
|
+
attributes[index] = attribute;
|
|
5777
|
+
geometry.morphAttributes[semantic] = attributes;
|
|
5778
|
+
}
|
|
5779
|
+
setZeroMorphAttributeAtIndex(geometry, semantic, itemSize, vertexCount, index, name) {
|
|
5780
|
+
if (!geometry.morphAttributes[semantic]?.length) return;
|
|
5781
|
+
const expectedLength = vertexCount * itemSize;
|
|
5782
|
+
const attributes = [...geometry.morphAttributes[semantic]];
|
|
5783
|
+
while (attributes.length < index) {
|
|
5784
|
+
const empty2 = new BufferAttribute(new Float32Array(expectedLength), itemSize);
|
|
5785
|
+
empty2.name = `morph_${attributes.length}`;
|
|
5786
|
+
attributes.push(empty2);
|
|
5787
|
+
}
|
|
5788
|
+
const empty = new BufferAttribute(new Float32Array(expectedLength), itemSize);
|
|
5789
|
+
empty.name = name;
|
|
5790
|
+
attributes[index] = empty;
|
|
5791
|
+
geometry.morphAttributes[semantic] = attributes;
|
|
5792
|
+
}
|
|
5793
|
+
addRuntimeMorphMesh(mesh) {
|
|
5794
|
+
const key = mesh.name || mesh.uuid;
|
|
5795
|
+
const exists = this.meshes.some((candidate) => (candidate.name || candidate.uuid) === key);
|
|
5796
|
+
if (!exists) {
|
|
5797
|
+
this.meshes.push(mesh);
|
|
5798
|
+
}
|
|
5799
|
+
}
|
|
5610
5800
|
getMorphKeyCacheKey(key, meshNames) {
|
|
5611
5801
|
return meshNames?.length ? `key:${key}@${meshNames.join(",")}` : `key:${key}`;
|
|
5612
5802
|
}
|
|
@@ -6201,22 +6391,32 @@ function mergeRegionsByName(base, override) {
|
|
|
6201
6391
|
}
|
|
6202
6392
|
return Array.from(merged.values());
|
|
6203
6393
|
}
|
|
6394
|
+
function getAnnotationRegions(value) {
|
|
6395
|
+
return Array.isArray(value) ? value : void 0;
|
|
6396
|
+
}
|
|
6397
|
+
function getLegacyNestedOverrides(config) {
|
|
6398
|
+
return isPlainObject2(config.profile) ? config.profile : {};
|
|
6399
|
+
}
|
|
6400
|
+
function getLegacyRuntimeRegions(config) {
|
|
6401
|
+
return Array.isArray(config.regions) && config.regions.length > 0 ? config.regions : void 0;
|
|
6402
|
+
}
|
|
6403
|
+
function getCanonicalAnnotationOverrides(config) {
|
|
6404
|
+
return mergeRegionsByName(
|
|
6405
|
+
getAnnotationRegions(getLegacyNestedOverrides(config).annotationRegions),
|
|
6406
|
+
getAnnotationRegions(config.annotationRegions)
|
|
6407
|
+
);
|
|
6408
|
+
}
|
|
6204
6409
|
function extractProfileOverrides(config) {
|
|
6205
6410
|
const topLevelConfig = config;
|
|
6206
|
-
const legacyNestedOverrides =
|
|
6411
|
+
const legacyNestedOverrides = getLegacyNestedOverrides(config);
|
|
6412
|
+
const canonicalAnnotationOverrides = getCanonicalAnnotationOverrides(config);
|
|
6413
|
+
const legacyRuntimeRegions = getLegacyRuntimeRegions(config);
|
|
6414
|
+
const annotationOverrides = canonicalAnnotationOverrides ?? (legacyRuntimeRegions ? legacyRuntimeRegions.map((region) => cloneRegion(region)) : void 0);
|
|
6207
6415
|
const overrides = {};
|
|
6208
6416
|
for (const key of PROFILE_OVERRIDE_KEYS) {
|
|
6209
6417
|
if (key === "annotationRegions") {
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
const legacyRegionFallback = Array.isArray(config.regions) && config.regions.length > 0 ? config.regions : void 0;
|
|
6213
|
-
const legacyProfileRegions = mergeRegionsByName(legacyRegionFallback, legacyAnnotationRegions);
|
|
6214
|
-
const regions = mergeRegionsByName(
|
|
6215
|
-
legacyProfileRegions,
|
|
6216
|
-
topLevelAnnotationRegions
|
|
6217
|
-
);
|
|
6218
|
-
if (regions) {
|
|
6219
|
-
overrides.annotationRegions = regions.map((region) => cloneRegion(region));
|
|
6418
|
+
if (annotationOverrides) {
|
|
6419
|
+
overrides.annotationRegions = annotationOverrides.map((region) => cloneRegion(region));
|
|
6220
6420
|
}
|
|
6221
6421
|
continue;
|
|
6222
6422
|
}
|
|
@@ -6229,13 +6429,6 @@ function extractProfileOverrides(config) {
|
|
|
6229
6429
|
}
|
|
6230
6430
|
return overrides;
|
|
6231
6431
|
}
|
|
6232
|
-
function hasCanonicalAnnotationRegionOverrides(config) {
|
|
6233
|
-
const topLevelConfig = config;
|
|
6234
|
-
if (Array.isArray(topLevelConfig.annotationRegions)) {
|
|
6235
|
-
return true;
|
|
6236
|
-
}
|
|
6237
|
-
return isPlainObject2(config.profile) && Array.isArray(config.profile.annotationRegions);
|
|
6238
|
-
}
|
|
6239
6432
|
function applyCharacterProfileToPreset(config) {
|
|
6240
6433
|
const presetType = config.auPresetType;
|
|
6241
6434
|
if (!presetType) {
|
|
@@ -6267,24 +6460,34 @@ function extendCharacterConfigWithPreset(config) {
|
|
|
6267
6460
|
if (!presetType || presetType === "custom") {
|
|
6268
6461
|
return config;
|
|
6269
6462
|
}
|
|
6463
|
+
const canonicalAnnotationOverrides = getCanonicalAnnotationOverrides(config);
|
|
6464
|
+
const legacyRuntimeRegions = getLegacyRuntimeRegions(config);
|
|
6270
6465
|
const profileOverrides = extractProfileOverrides(config);
|
|
6271
6466
|
const extendedPresetProfile = applyCharacterProfileToPreset(config);
|
|
6272
6467
|
if (!extendedPresetProfile) {
|
|
6273
6468
|
return config;
|
|
6274
6469
|
}
|
|
6275
|
-
const
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6470
|
+
const presetRegionNames = new Set(
|
|
6471
|
+
(getPreset(presetType).annotationRegions ?? []).map((region) => region.name)
|
|
6472
|
+
);
|
|
6473
|
+
const extendedAnnotationRegions = normalizeRegionTree(
|
|
6474
|
+
extendedPresetProfile.annotationRegions,
|
|
6475
|
+
profileOverrides.disabledRegions
|
|
6476
|
+
);
|
|
6477
|
+
const extendedRegionNames = new Set((extendedAnnotationRegions ?? []).map((region) => region.name));
|
|
6478
|
+
const legacyExtraRegions = canonicalAnnotationOverrides && legacyRuntimeRegions ? legacyRuntimeRegions.filter((region) => !presetRegionNames.has(region.name) && !extendedRegionNames.has(region.name)).map((region) => cloneRegion(region)) : void 0;
|
|
6479
|
+
const mergedRegions = normalizeRegionTree(
|
|
6480
|
+
mergeRegionsByName(extendedAnnotationRegions, legacyExtraRegions),
|
|
6279
6481
|
profileOverrides.disabledRegions
|
|
6280
6482
|
);
|
|
6281
6483
|
const extendedRegions = orderExtendedRegions(
|
|
6282
|
-
|
|
6283
|
-
[
|
|
6484
|
+
mergedRegions,
|
|
6485
|
+
canonicalAnnotationOverrides ? [extendedAnnotationRegions, legacyExtraRegions] : [legacyRuntimeRegions, extendedAnnotationRegions]
|
|
6284
6486
|
);
|
|
6285
6487
|
return {
|
|
6286
6488
|
...config,
|
|
6287
6489
|
...extendedPresetProfile,
|
|
6490
|
+
annotationRegions: extendedRegions ?? extendedAnnotationRegions,
|
|
6288
6491
|
regions: extendedRegions ?? config.regions
|
|
6289
6492
|
};
|
|
6290
6493
|
}
|
|
@@ -7444,7 +7647,7 @@ function extractMorphs(meshes) {
|
|
|
7444
7647
|
for (const mesh of meshes) {
|
|
7445
7648
|
const geo = mesh.geometry;
|
|
7446
7649
|
if (!geo.morphAttributes) continue;
|
|
7447
|
-
const dict = geo.morphTargetDictionary;
|
|
7650
|
+
const dict = mesh.morphTargetDictionary || geo.morphTargetDictionary;
|
|
7448
7651
|
if (dict) {
|
|
7449
7652
|
for (const [name, index] of Object.entries(dict)) {
|
|
7450
7653
|
morphs.push({
|