@lovelace_lol/loom3 1.0.36 → 1.0.37
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 +16 -1
- package/dist/index.cjs +242 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -1
- package/dist/index.d.ts +33 -1
- package/dist/index.js +241 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -236,10 +236,12 @@ type PresetType = 'cc4' | 'skeletal' | 'fish' | 'custom';
|
|
|
236
236
|
* This allows frontend to pass a string instead of importing the full preset.
|
|
237
237
|
*/
|
|
238
238
|
declare function getPreset(presetType: PresetType | string | undefined): Profile;
|
|
239
|
+
declare const resolvePreset: typeof getPreset;
|
|
239
240
|
/**
|
|
240
241
|
* Get a preset, then extend it with an optional profile.
|
|
241
242
|
*/
|
|
242
243
|
declare function getPresetWithProfile(presetType: PresetType | string | undefined, profile?: Partial<Profile>): Profile;
|
|
244
|
+
declare const resolvePresetWithOverrides: typeof getPresetWithProfile;
|
|
243
245
|
|
|
244
246
|
/**
|
|
245
247
|
* Loom3 - Core Type Definitions
|
|
@@ -452,6 +454,34 @@ interface AnimationActionHandle {
|
|
|
452
454
|
/** Promise that resolves when animation completes (only for non-looping) */
|
|
453
455
|
finished: Promise<void>;
|
|
454
456
|
}
|
|
457
|
+
type ClipEvent = {
|
|
458
|
+
type: 'keyframe';
|
|
459
|
+
clipName: string;
|
|
460
|
+
keyframeIndex: number;
|
|
461
|
+
totalKeyframes: number;
|
|
462
|
+
currentTime: number;
|
|
463
|
+
duration: number;
|
|
464
|
+
iteration: number;
|
|
465
|
+
} | {
|
|
466
|
+
type: 'loop';
|
|
467
|
+
clipName: string;
|
|
468
|
+
iteration: number;
|
|
469
|
+
currentTime: number;
|
|
470
|
+
duration: number;
|
|
471
|
+
} | {
|
|
472
|
+
type: 'seek';
|
|
473
|
+
clipName: string;
|
|
474
|
+
currentTime: number;
|
|
475
|
+
duration: number;
|
|
476
|
+
iteration: number;
|
|
477
|
+
} | {
|
|
478
|
+
type: 'completed';
|
|
479
|
+
clipName: string;
|
|
480
|
+
currentTime: number;
|
|
481
|
+
duration: number;
|
|
482
|
+
iteration: number;
|
|
483
|
+
};
|
|
484
|
+
type ClipEventListener = (event: ClipEvent) => void;
|
|
455
485
|
/**
|
|
456
486
|
* A single keyframe point in an animation curve.
|
|
457
487
|
*/
|
|
@@ -551,6 +581,8 @@ interface ClipHandle {
|
|
|
551
581
|
getTime: () => number;
|
|
552
582
|
/** Get total clip duration in seconds */
|
|
553
583
|
getDuration: () => number;
|
|
584
|
+
/** Subscribe to clip lifecycle events emitted by the runtime update loop */
|
|
585
|
+
subscribe?: (listener: ClipEventListener) => () => void;
|
|
554
586
|
/** Promise that resolves when clip finishes (non-looping only) */
|
|
555
587
|
finished: Promise<void>;
|
|
556
588
|
}
|
|
@@ -2414,4 +2446,4 @@ declare function detectFacingDirection(model: THREE.Object3D, eyeBoneNames?: {
|
|
|
2414
2446
|
right: string[];
|
|
2415
2447
|
}): 'forward' | 'backward' | 'unknown';
|
|
2416
2448
|
|
|
2417
|
-
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 CharacterConfig, type CharacterRegistry, 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, detectFacingDirection, extendCharacterConfigWithPreset, extendPresetWithProfile, extractFromGLTF, extractModelData, extractProfileOverrides, findFaceCenter, fuzzyNameMatch, generateMappingCorrections, getModelForwardDirection, getPreset, getPresetWithProfile, hasLeftRightMorphs, isMixedAU, isPresetCompatible, mergeRegionsByName as mergeCharacterRegionsByName, resolveBoneName, resolveBoneNames, resolveFaceCenter, suggestBestPreset, validateMappingConfig, validateMappings };
|
|
2449
|
+
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 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, 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
|
@@ -236,10 +236,12 @@ type PresetType = 'cc4' | 'skeletal' | 'fish' | 'custom';
|
|
|
236
236
|
* This allows frontend to pass a string instead of importing the full preset.
|
|
237
237
|
*/
|
|
238
238
|
declare function getPreset(presetType: PresetType | string | undefined): Profile;
|
|
239
|
+
declare const resolvePreset: typeof getPreset;
|
|
239
240
|
/**
|
|
240
241
|
* Get a preset, then extend it with an optional profile.
|
|
241
242
|
*/
|
|
242
243
|
declare function getPresetWithProfile(presetType: PresetType | string | undefined, profile?: Partial<Profile>): Profile;
|
|
244
|
+
declare const resolvePresetWithOverrides: typeof getPresetWithProfile;
|
|
243
245
|
|
|
244
246
|
/**
|
|
245
247
|
* Loom3 - Core Type Definitions
|
|
@@ -452,6 +454,34 @@ interface AnimationActionHandle {
|
|
|
452
454
|
/** Promise that resolves when animation completes (only for non-looping) */
|
|
453
455
|
finished: Promise<void>;
|
|
454
456
|
}
|
|
457
|
+
type ClipEvent = {
|
|
458
|
+
type: 'keyframe';
|
|
459
|
+
clipName: string;
|
|
460
|
+
keyframeIndex: number;
|
|
461
|
+
totalKeyframes: number;
|
|
462
|
+
currentTime: number;
|
|
463
|
+
duration: number;
|
|
464
|
+
iteration: number;
|
|
465
|
+
} | {
|
|
466
|
+
type: 'loop';
|
|
467
|
+
clipName: string;
|
|
468
|
+
iteration: number;
|
|
469
|
+
currentTime: number;
|
|
470
|
+
duration: number;
|
|
471
|
+
} | {
|
|
472
|
+
type: 'seek';
|
|
473
|
+
clipName: string;
|
|
474
|
+
currentTime: number;
|
|
475
|
+
duration: number;
|
|
476
|
+
iteration: number;
|
|
477
|
+
} | {
|
|
478
|
+
type: 'completed';
|
|
479
|
+
clipName: string;
|
|
480
|
+
currentTime: number;
|
|
481
|
+
duration: number;
|
|
482
|
+
iteration: number;
|
|
483
|
+
};
|
|
484
|
+
type ClipEventListener = (event: ClipEvent) => void;
|
|
455
485
|
/**
|
|
456
486
|
* A single keyframe point in an animation curve.
|
|
457
487
|
*/
|
|
@@ -551,6 +581,8 @@ interface ClipHandle {
|
|
|
551
581
|
getTime: () => number;
|
|
552
582
|
/** Get total clip duration in seconds */
|
|
553
583
|
getDuration: () => number;
|
|
584
|
+
/** Subscribe to clip lifecycle events emitted by the runtime update loop */
|
|
585
|
+
subscribe?: (listener: ClipEventListener) => () => void;
|
|
554
586
|
/** Promise that resolves when clip finishes (non-looping only) */
|
|
555
587
|
finished: Promise<void>;
|
|
556
588
|
}
|
|
@@ -2414,4 +2446,4 @@ declare function detectFacingDirection(model: THREE.Object3D, eyeBoneNames?: {
|
|
|
2414
2446
|
right: string[];
|
|
2415
2447
|
}): 'forward' | 'backward' | 'unknown';
|
|
2416
2448
|
|
|
2417
|
-
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 CharacterConfig, type CharacterRegistry, 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, detectFacingDirection, extendCharacterConfigWithPreset, extendPresetWithProfile, extractFromGLTF, extractModelData, extractProfileOverrides, findFaceCenter, fuzzyNameMatch, generateMappingCorrections, getModelForwardDirection, getPreset, getPresetWithProfile, hasLeftRightMorphs, isMixedAU, isPresetCompatible, mergeRegionsByName as mergeCharacterRegionsByName, resolveBoneName, resolveBoneNames, resolveFaceCenter, suggestBestPreset, validateMappingConfig, validateMappings };
|
|
2449
|
+
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 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, 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
|
@@ -270,6 +270,8 @@ var makeActionId = () => `act_${Math.random().toString(36).slice(2, 8)}_${Date.n
|
|
|
270
270
|
var X_AXIS = new Vector3(1, 0, 0);
|
|
271
271
|
var Y_AXIS = new Vector3(0, 1, 0);
|
|
272
272
|
var Z_AXIS = new Vector3(0, 0, 1);
|
|
273
|
+
var CLIP_EVENT_METADATA_KEY = "__loom3ClipEvents";
|
|
274
|
+
var CLIP_EVENT_EPSILON = 1e-4;
|
|
273
275
|
var BakedAnimationController = class {
|
|
274
276
|
constructor(host) {
|
|
275
277
|
__publicField(this, "host");
|
|
@@ -288,6 +290,7 @@ var BakedAnimationController = class {
|
|
|
288
290
|
__publicField(this, "playbackState", /* @__PURE__ */ new Map());
|
|
289
291
|
__publicField(this, "actionIds", /* @__PURE__ */ new WeakMap());
|
|
290
292
|
__publicField(this, "actionIdToClip", /* @__PURE__ */ new Map());
|
|
293
|
+
__publicField(this, "clipMonitors", /* @__PURE__ */ new Map());
|
|
291
294
|
this.host = host;
|
|
292
295
|
}
|
|
293
296
|
getActionId(action) {
|
|
@@ -301,6 +304,161 @@ var BakedAnimationController = class {
|
|
|
301
304
|
action.__actionId = actionId;
|
|
302
305
|
return actionId;
|
|
303
306
|
}
|
|
307
|
+
setClipEventMetadata(clip, metadata) {
|
|
308
|
+
const userData = clip.userData ?? (clip.userData = {});
|
|
309
|
+
userData[CLIP_EVENT_METADATA_KEY] = metadata;
|
|
310
|
+
}
|
|
311
|
+
getClipEventMetadata(clip) {
|
|
312
|
+
const userData = clip.userData;
|
|
313
|
+
const keyframeTimes = Array.isArray(userData?.[CLIP_EVENT_METADATA_KEY]?.keyframeTimes) ? userData[CLIP_EVENT_METADATA_KEY].keyframeTimes.filter((time) => Number.isFinite(time)) : [];
|
|
314
|
+
return { keyframeTimes };
|
|
315
|
+
}
|
|
316
|
+
getKeyframeIndex(times, currentTime) {
|
|
317
|
+
if (!times.length) return -1;
|
|
318
|
+
const target = Math.max(0, currentTime) + 1e-3;
|
|
319
|
+
let lo = 0;
|
|
320
|
+
let hi = times.length - 1;
|
|
321
|
+
let idx = 0;
|
|
322
|
+
while (lo <= hi) {
|
|
323
|
+
const mid = lo + hi >>> 1;
|
|
324
|
+
if (times[mid] <= target) {
|
|
325
|
+
idx = mid;
|
|
326
|
+
lo = mid + 1;
|
|
327
|
+
} else {
|
|
328
|
+
hi = mid - 1;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return idx;
|
|
332
|
+
}
|
|
333
|
+
emitClipEvent(monitor, event) {
|
|
334
|
+
for (const listener of Array.from(monitor.listeners)) {
|
|
335
|
+
try {
|
|
336
|
+
listener(event);
|
|
337
|
+
} catch (error) {
|
|
338
|
+
console.error("[Loom3] clip event listener failed", error);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
emitKeyframesForRange(monitor, startTime, endTime, direction, includeStart) {
|
|
343
|
+
if (!monitor.keyframeTimes.length) return;
|
|
344
|
+
const times = direction === 1 ? monitor.keyframeTimes : [...monitor.keyframeTimes].reverse();
|
|
345
|
+
for (const time of times) {
|
|
346
|
+
const matchesForward = direction === 1 && (includeStart ? time >= startTime - CLIP_EVENT_EPSILON : time > startTime + CLIP_EVENT_EPSILON) && time <= endTime + CLIP_EVENT_EPSILON;
|
|
347
|
+
const matchesReverse = direction === -1 && (includeStart ? time <= startTime + CLIP_EVENT_EPSILON : time < startTime - CLIP_EVENT_EPSILON) && time >= endTime - CLIP_EVENT_EPSILON;
|
|
348
|
+
if (!matchesForward && !matchesReverse) continue;
|
|
349
|
+
const keyframeIndex = monitor.keyframeTimes.indexOf(time);
|
|
350
|
+
monitor.lastKeyframeIndex = keyframeIndex;
|
|
351
|
+
this.emitClipEvent(monitor, {
|
|
352
|
+
type: "keyframe",
|
|
353
|
+
clipName: monitor.clipName,
|
|
354
|
+
keyframeIndex,
|
|
355
|
+
totalKeyframes: monitor.keyframeTimes.length,
|
|
356
|
+
currentTime: time,
|
|
357
|
+
duration: monitor.duration,
|
|
358
|
+
iteration: monitor.iteration
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
resetClipMonitor(monitor, currentTime) {
|
|
363
|
+
monitor.iteration = 0;
|
|
364
|
+
monitor.direction = monitor.initialDirection;
|
|
365
|
+
monitor.lastTime = currentTime;
|
|
366
|
+
monitor.lastKeyframeIndex = this.getKeyframeIndex(monitor.keyframeTimes, currentTime);
|
|
367
|
+
monitor.finishedPending = false;
|
|
368
|
+
}
|
|
369
|
+
syncClipMonitorTime(monitor, currentTime, emitSeek = false) {
|
|
370
|
+
const clamped = Math.max(0, Math.min(monitor.duration, currentTime));
|
|
371
|
+
monitor.lastTime = clamped;
|
|
372
|
+
monitor.lastKeyframeIndex = this.getKeyframeIndex(monitor.keyframeTimes, clamped);
|
|
373
|
+
if (emitSeek) {
|
|
374
|
+
this.emitClipEvent(monitor, {
|
|
375
|
+
type: "seek",
|
|
376
|
+
clipName: monitor.clipName,
|
|
377
|
+
currentTime: clamped,
|
|
378
|
+
duration: monitor.duration,
|
|
379
|
+
iteration: monitor.iteration
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
cleanupClipMonitor(actionId) {
|
|
384
|
+
const monitor = this.clipMonitors.get(actionId);
|
|
385
|
+
if (!monitor || monitor.cleanedUp) return;
|
|
386
|
+
monitor.cleanedUp = true;
|
|
387
|
+
try {
|
|
388
|
+
monitor.action.paused = true;
|
|
389
|
+
} catch {
|
|
390
|
+
}
|
|
391
|
+
monitor.resolveFinished();
|
|
392
|
+
monitor.listeners.clear();
|
|
393
|
+
this.clipMonitors.delete(actionId);
|
|
394
|
+
this.actionIdToClip.delete(actionId);
|
|
395
|
+
}
|
|
396
|
+
advanceClipMonitor(monitor, previousTime) {
|
|
397
|
+
if (monitor.cleanedUp || monitor.action.paused && !monitor.finishedPending) return;
|
|
398
|
+
const currentTime = Math.max(0, Math.min(monitor.duration, monitor.action.time));
|
|
399
|
+
const delta = currentTime - previousTime;
|
|
400
|
+
if (monitor.loopMode === "pingpong") {
|
|
401
|
+
const movingForward = monitor.direction === 1;
|
|
402
|
+
const bouncedAtEnd = movingForward && delta < -CLIP_EVENT_EPSILON;
|
|
403
|
+
const bouncedAtStart = !movingForward && delta > CLIP_EVENT_EPSILON;
|
|
404
|
+
if (bouncedAtEnd) {
|
|
405
|
+
this.emitKeyframesForRange(monitor, previousTime, monitor.duration, 1, false);
|
|
406
|
+
monitor.direction = -1;
|
|
407
|
+
this.emitKeyframesForRange(monitor, monitor.duration, currentTime, -1, false);
|
|
408
|
+
} else if (bouncedAtStart) {
|
|
409
|
+
this.emitKeyframesForRange(monitor, previousTime, 0, -1, false);
|
|
410
|
+
monitor.direction = 1;
|
|
411
|
+
monitor.iteration += 1;
|
|
412
|
+
this.emitClipEvent(monitor, {
|
|
413
|
+
type: "loop",
|
|
414
|
+
clipName: monitor.clipName,
|
|
415
|
+
iteration: monitor.iteration,
|
|
416
|
+
currentTime: 0,
|
|
417
|
+
duration: monitor.duration
|
|
418
|
+
});
|
|
419
|
+
this.emitKeyframesForRange(monitor, 0, currentTime, 1, false);
|
|
420
|
+
} else if (delta > CLIP_EVENT_EPSILON) {
|
|
421
|
+
this.emitKeyframesForRange(monitor, previousTime, currentTime, 1, false);
|
|
422
|
+
monitor.direction = 1;
|
|
423
|
+
} else if (delta < -CLIP_EVENT_EPSILON) {
|
|
424
|
+
this.emitKeyframesForRange(monitor, previousTime, currentTime, -1, false);
|
|
425
|
+
monitor.direction = -1;
|
|
426
|
+
}
|
|
427
|
+
} else if (monitor.direction === 1) {
|
|
428
|
+
const wrapped = currentTime + CLIP_EVENT_EPSILON < previousTime;
|
|
429
|
+
if (wrapped) {
|
|
430
|
+
this.emitKeyframesForRange(monitor, previousTime, monitor.duration, 1, false);
|
|
431
|
+
monitor.iteration += 1;
|
|
432
|
+
this.emitClipEvent(monitor, {
|
|
433
|
+
type: "loop",
|
|
434
|
+
clipName: monitor.clipName,
|
|
435
|
+
iteration: monitor.iteration,
|
|
436
|
+
currentTime: 0,
|
|
437
|
+
duration: monitor.duration
|
|
438
|
+
});
|
|
439
|
+
this.emitKeyframesForRange(monitor, 0, currentTime, 1, true);
|
|
440
|
+
} else if (delta > CLIP_EVENT_EPSILON) {
|
|
441
|
+
this.emitKeyframesForRange(monitor, previousTime, currentTime, 1, false);
|
|
442
|
+
}
|
|
443
|
+
} else {
|
|
444
|
+
const wrapped = currentTime > previousTime + CLIP_EVENT_EPSILON;
|
|
445
|
+
if (wrapped) {
|
|
446
|
+
this.emitKeyframesForRange(monitor, previousTime, 0, -1, false);
|
|
447
|
+
monitor.iteration += 1;
|
|
448
|
+
this.emitClipEvent(monitor, {
|
|
449
|
+
type: "loop",
|
|
450
|
+
clipName: monitor.clipName,
|
|
451
|
+
iteration: monitor.iteration,
|
|
452
|
+
currentTime: monitor.duration,
|
|
453
|
+
duration: monitor.duration
|
|
454
|
+
});
|
|
455
|
+
this.emitKeyframesForRange(monitor, monitor.duration, currentTime, -1, true);
|
|
456
|
+
} else if (delta < -CLIP_EVENT_EPSILON) {
|
|
457
|
+
this.emitKeyframesForRange(monitor, previousTime, currentTime, -1, false);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
this.syncClipMonitorTime(monitor, currentTime);
|
|
461
|
+
}
|
|
304
462
|
normalizePlaybackOptions(options, defaults) {
|
|
305
463
|
const clipOptions = options;
|
|
306
464
|
const rawRate = options?.playbackRate ?? options?.speed ?? 1;
|
|
@@ -512,7 +670,28 @@ var BakedAnimationController = class {
|
|
|
512
670
|
}
|
|
513
671
|
update(dtSeconds) {
|
|
514
672
|
if (this.animationMixer) {
|
|
673
|
+
const snapshots = Array.from(this.clipMonitors.values()).map((monitor) => ({
|
|
674
|
+
actionId: monitor.actionId,
|
|
675
|
+
previousTime: monitor.action.time
|
|
676
|
+
}));
|
|
515
677
|
this.animationMixer.update(dtSeconds);
|
|
678
|
+
for (const { actionId, previousTime } of snapshots) {
|
|
679
|
+
const monitor = this.clipMonitors.get(actionId);
|
|
680
|
+
if (!monitor) continue;
|
|
681
|
+
this.advanceClipMonitor(monitor, previousTime);
|
|
682
|
+
if (monitor.finishedPending) {
|
|
683
|
+
const finalTime = Math.max(0, Math.min(monitor.duration, monitor.action.time));
|
|
684
|
+
this.syncClipMonitorTime(monitor, finalTime);
|
|
685
|
+
this.emitClipEvent(monitor, {
|
|
686
|
+
type: "completed",
|
|
687
|
+
clipName: monitor.clipName,
|
|
688
|
+
currentTime: finalTime,
|
|
689
|
+
duration: monitor.duration,
|
|
690
|
+
iteration: monitor.iteration
|
|
691
|
+
});
|
|
692
|
+
this.cleanupClipMonitor(actionId);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
516
695
|
}
|
|
517
696
|
}
|
|
518
697
|
dispose() {
|
|
@@ -532,6 +711,7 @@ var BakedAnimationController = class {
|
|
|
532
711
|
this.clipHandles.clear();
|
|
533
712
|
this.clipSources.clear();
|
|
534
713
|
this.playbackState.clear();
|
|
714
|
+
this.clipMonitors.clear();
|
|
535
715
|
}
|
|
536
716
|
loadAnimationClips(clips) {
|
|
537
717
|
const model = this.host.getModel();
|
|
@@ -670,6 +850,7 @@ var BakedAnimationController = class {
|
|
|
670
850
|
}
|
|
671
851
|
const action = this.animationActions.get(clipName);
|
|
672
852
|
if (action) {
|
|
853
|
+
const actionId = this.getActionId(action);
|
|
673
854
|
const isBaked = (this.clipSources.get(clipName) ?? "baked") === "baked";
|
|
674
855
|
action.stop();
|
|
675
856
|
if (!isBaked && this.animationMixer) {
|
|
@@ -692,9 +873,11 @@ var BakedAnimationController = class {
|
|
|
692
873
|
}
|
|
693
874
|
}
|
|
694
875
|
this.animationFinishedCallbacks.delete(clipName);
|
|
876
|
+
if (actionId) this.cleanupClipMonitor(actionId);
|
|
695
877
|
}
|
|
696
878
|
const clipAction = this.clipActions.get(clipName);
|
|
697
879
|
if (clipAction && clipAction !== action) {
|
|
880
|
+
const actionId = this.getActionId(clipAction);
|
|
698
881
|
try {
|
|
699
882
|
clipAction.stop();
|
|
700
883
|
if (this.animationMixer) {
|
|
@@ -707,6 +890,7 @@ var BakedAnimationController = class {
|
|
|
707
890
|
} catch {
|
|
708
891
|
}
|
|
709
892
|
this.clipActions.delete(clipName);
|
|
893
|
+
if (actionId) this.cleanupClipMonitor(actionId);
|
|
710
894
|
}
|
|
711
895
|
if (this.clipActions.get(clipName) === action) {
|
|
712
896
|
this.clipActions.delete(clipName);
|
|
@@ -1268,6 +1452,7 @@ var BakedAnimationController = class {
|
|
|
1268
1452
|
return null;
|
|
1269
1453
|
}
|
|
1270
1454
|
const clip = new AnimationClip(clipName, maxTime, tracks);
|
|
1455
|
+
this.setClipEventMetadata(clip, { keyframeTimes });
|
|
1271
1456
|
console.log(`[Loom3] snippetToClip: Created clip "${clipName}" with ${tracks.length} tracks, duration ${maxTime.toFixed(2)}s`);
|
|
1272
1457
|
return clip;
|
|
1273
1458
|
}
|
|
@@ -1299,28 +1484,38 @@ var BakedAnimationController = class {
|
|
|
1299
1484
|
this.animationClips.push(clip);
|
|
1300
1485
|
}
|
|
1301
1486
|
this.applyPlaybackState(action, playbackState);
|
|
1487
|
+
if (actionId) {
|
|
1488
|
+
this.cleanupClipMonitor(actionId);
|
|
1489
|
+
}
|
|
1302
1490
|
let resolveFinished;
|
|
1303
1491
|
const finishedPromise = new Promise((resolve) => {
|
|
1304
1492
|
resolveFinished = resolve;
|
|
1305
1493
|
});
|
|
1306
|
-
const
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1494
|
+
const keyframeTimes = this.getClipEventMetadata(clip).keyframeTimes;
|
|
1495
|
+
const initialDirection = playbackState.reverse ? -1 : 1;
|
|
1496
|
+
const monitor = {
|
|
1497
|
+
action,
|
|
1498
|
+
actionId,
|
|
1499
|
+
clip,
|
|
1500
|
+
clipName: clip.name,
|
|
1501
|
+
duration: clip.duration,
|
|
1502
|
+
keyframeTimes,
|
|
1503
|
+
listeners: /* @__PURE__ */ new Set(),
|
|
1504
|
+
initialDirection,
|
|
1505
|
+
direction: initialDirection,
|
|
1506
|
+
iteration: 0,
|
|
1507
|
+
lastTime: Math.max(0, Math.min(clip.duration, action.time)),
|
|
1508
|
+
lastKeyframeIndex: this.getKeyframeIndex(keyframeTimes, action.time),
|
|
1509
|
+
loopMode: playbackState.loopMode,
|
|
1510
|
+
finishedPending: false,
|
|
1511
|
+
cleanedUp: false,
|
|
1512
|
+
resolveFinished
|
|
1315
1513
|
};
|
|
1316
|
-
this.
|
|
1317
|
-
resolveFinished();
|
|
1318
|
-
cleanup();
|
|
1319
|
-
});
|
|
1320
|
-
finishedPromise.catch(() => cleanup());
|
|
1514
|
+
this.clipMonitors.set(actionId, monitor);
|
|
1321
1515
|
action.reset();
|
|
1322
1516
|
action.time = startTime;
|
|
1323
1517
|
action.play();
|
|
1518
|
+
this.resetClipMonitor(monitor, action.time);
|
|
1324
1519
|
this.clipActions.set(clip.name, action);
|
|
1325
1520
|
this.animationActions.set(clip.name, action);
|
|
1326
1521
|
this.setPlaybackState(clip.name, playbackState);
|
|
@@ -1338,6 +1533,7 @@ var BakedAnimationController = class {
|
|
|
1338
1533
|
})
|
|
1339
1534
|
);
|
|
1340
1535
|
action.play();
|
|
1536
|
+
this.resetClipMonitor(monitor, action.time);
|
|
1341
1537
|
},
|
|
1342
1538
|
stop: () => {
|
|
1343
1539
|
action.stop();
|
|
@@ -1355,8 +1551,7 @@ var BakedAnimationController = class {
|
|
|
1355
1551
|
this.animationActions.delete(clip.name);
|
|
1356
1552
|
this.animationFinishedCallbacks.delete(clip.name);
|
|
1357
1553
|
this.playbackState.delete(clip.name);
|
|
1358
|
-
|
|
1359
|
-
cleanup();
|
|
1554
|
+
this.cleanupClipMonitor(actionId);
|
|
1360
1555
|
},
|
|
1361
1556
|
pause: () => {
|
|
1362
1557
|
action.paused = true;
|
|
@@ -1374,6 +1569,8 @@ var BakedAnimationController = class {
|
|
|
1374
1569
|
const next = this.playbackState.get(clip.name) ?? playbackState;
|
|
1375
1570
|
next.playbackRate = Number.isFinite(r) ? Math.max(0, Math.abs(r)) : 1;
|
|
1376
1571
|
this.applyPlaybackState(action, next);
|
|
1572
|
+
monitor.direction = next.reverse ? -1 : 1;
|
|
1573
|
+
monitor.initialDirection = monitor.direction;
|
|
1377
1574
|
this.setPlaybackState(clip.name, next);
|
|
1378
1575
|
},
|
|
1379
1576
|
setLoop: (mode, repeatCount) => {
|
|
@@ -1382,6 +1579,7 @@ var BakedAnimationController = class {
|
|
|
1382
1579
|
next.loop = mode !== "once";
|
|
1383
1580
|
next.repeatCount = repeatCount;
|
|
1384
1581
|
this.applyPlaybackState(action, next);
|
|
1582
|
+
monitor.loopMode = mode;
|
|
1385
1583
|
this.setPlaybackState(clip.name, next);
|
|
1386
1584
|
},
|
|
1387
1585
|
setTime: (t) => {
|
|
@@ -1391,9 +1589,16 @@ var BakedAnimationController = class {
|
|
|
1391
1589
|
this.animationMixer?.update(0);
|
|
1392
1590
|
} catch {
|
|
1393
1591
|
}
|
|
1592
|
+
this.syncClipMonitorTime(monitor, clamped, true);
|
|
1394
1593
|
},
|
|
1395
1594
|
getTime: () => action.time,
|
|
1396
1595
|
getDuration: () => clip.duration,
|
|
1596
|
+
subscribe: (listener) => {
|
|
1597
|
+
monitor.listeners.add(listener);
|
|
1598
|
+
return () => {
|
|
1599
|
+
monitor.listeners.delete(listener);
|
|
1600
|
+
};
|
|
1601
|
+
},
|
|
1397
1602
|
finished: finishedPromise
|
|
1398
1603
|
};
|
|
1399
1604
|
this.clipHandles.set(clip.name, handle);
|
|
@@ -1417,6 +1622,7 @@ var BakedAnimationController = class {
|
|
|
1417
1622
|
if (!this.animationMixer || !this.host.getModel()) return;
|
|
1418
1623
|
for (const [clipName, action] of Array.from(this.clipActions.entries())) {
|
|
1419
1624
|
if (clipName === name || clipName.startsWith(`${name}_`)) {
|
|
1625
|
+
const actionId = this.getActionId(action);
|
|
1420
1626
|
try {
|
|
1421
1627
|
action.stop();
|
|
1422
1628
|
const clip = action.getClip();
|
|
@@ -1431,6 +1637,7 @@ var BakedAnimationController = class {
|
|
|
1431
1637
|
this.clipHandles.delete(clipName);
|
|
1432
1638
|
this.animationFinishedCallbacks.delete(clipName);
|
|
1433
1639
|
this.playbackState.delete(clipName);
|
|
1640
|
+
if (actionId) this.cleanupClipMonitor(actionId);
|
|
1434
1641
|
}
|
|
1435
1642
|
}
|
|
1436
1643
|
}
|
|
@@ -1454,6 +1661,8 @@ var BakedAnimationController = class {
|
|
|
1454
1661
|
console.log("[Loom3] updateClipParams start", debugSnapshot());
|
|
1455
1662
|
const apply = (action) => {
|
|
1456
1663
|
if (!action) return;
|
|
1664
|
+
const actionId = this.getActionId(action);
|
|
1665
|
+
const monitor = actionId ? this.clipMonitors.get(actionId) : void 0;
|
|
1457
1666
|
const clipName = action.getClip().name;
|
|
1458
1667
|
const next = this.playbackState.get(clipName) ?? this.normalizePlaybackOptions(void 0, { loop: false, source: this.clipSources.get(clipName) ?? "clip" });
|
|
1459
1668
|
try {
|
|
@@ -1472,6 +1681,10 @@ var BakedAnimationController = class {
|
|
|
1472
1681
|
}
|
|
1473
1682
|
const signedRate = next.reverse ? -next.playbackRate : next.playbackRate;
|
|
1474
1683
|
action.setEffectiveTimeScale(signedRate);
|
|
1684
|
+
if (monitor) {
|
|
1685
|
+
monitor.direction = next.reverse ? -1 : 1;
|
|
1686
|
+
monitor.initialDirection = monitor.direction;
|
|
1687
|
+
}
|
|
1475
1688
|
updated = true;
|
|
1476
1689
|
}
|
|
1477
1690
|
if (typeof params.loop === "boolean" || params.loopMode || params.repeatCount !== void 0) {
|
|
@@ -1479,6 +1692,7 @@ var BakedAnimationController = class {
|
|
|
1479
1692
|
next.loop = next.loopMode !== "once";
|
|
1480
1693
|
next.repeatCount = params.repeatCount;
|
|
1481
1694
|
this.applyPlaybackState(action, next);
|
|
1695
|
+
if (monitor) monitor.loopMode = next.loopMode;
|
|
1482
1696
|
updated = true;
|
|
1483
1697
|
}
|
|
1484
1698
|
this.setPlaybackState(clipName, next);
|
|
@@ -1558,6 +1772,14 @@ var BakedAnimationController = class {
|
|
|
1558
1772
|
if (this.animationMixer && !this.mixerFinishedListenerAttached) {
|
|
1559
1773
|
this.animationMixer.addEventListener("finished", (event) => {
|
|
1560
1774
|
const action = event.action;
|
|
1775
|
+
const actionId = this.getActionId(action);
|
|
1776
|
+
if (actionId) {
|
|
1777
|
+
const monitor = this.clipMonitors.get(actionId);
|
|
1778
|
+
if (monitor) {
|
|
1779
|
+
monitor.finishedPending = true;
|
|
1780
|
+
return;
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1561
1783
|
const clip = action.getClip();
|
|
1562
1784
|
const bakedRuntime = this.bakedRuntimeClipToSource.get(clip.name);
|
|
1563
1785
|
if (bakedRuntime) {
|
|
@@ -4264,9 +4486,11 @@ function getPreset(presetType) {
|
|
|
4264
4486
|
return CC4_PRESET;
|
|
4265
4487
|
}
|
|
4266
4488
|
}
|
|
4489
|
+
var resolvePreset = getPreset;
|
|
4267
4490
|
function getPresetWithProfile(presetType, profile) {
|
|
4268
4491
|
return extendPresetWithProfile(getPreset(presetType), profile);
|
|
4269
4492
|
}
|
|
4493
|
+
var resolvePresetWithOverrides = getPresetWithProfile;
|
|
4270
4494
|
|
|
4271
4495
|
// src/engines/three/Loom3.ts
|
|
4272
4496
|
var deg2rad = (d) => d * Math.PI / 180;
|
|
@@ -7374,6 +7598,6 @@ async function analyzeModel(options) {
|
|
|
7374
7598
|
};
|
|
7375
7599
|
}
|
|
7376
7600
|
|
|
7377
|
-
export { AU_INFO, AU_MAPPING_CONFIG, AU_MIX_DEFAULTS, AU_TO_MORPHS, AnimationThree, BETTA_FISH_PRESET, BLENDING_MODES, BONE_AU_TO_BINDINGS, CC4_BONE_NODES, CC4_BONE_PREFIX, CC4_EYE_MESH_NODES, CC4_MESHES, CC4_PRESET, CC4_SUFFIX_PATTERN, COMPOSITE_ROTATIONS, CONTINUUM_LABELS, CONTINUUM_PAIRS_MAP, DEFAULT_HAIR_PHYSICS_CONFIG, FISH_AU_MAPPING_CONFIG, HairPhysics, Loom3, Loom3 as Loom3Three, Loom3 as LoomLargeThree, MORPH_TO_MESH, VISEME_JAW_AMOUNTS, VISEME_KEYS, analyzeModel, applyCharacterProfileToPreset, collectMorphMeshes, detectFacingDirection, extendCharacterConfigWithPreset, extendPresetWithProfile, extractFromGLTF, extractModelData, extractProfileOverrides, findFaceCenter, fuzzyNameMatch, generateMappingCorrections, getModelForwardDirection, getPreset, getPresetWithProfile, hasLeftRightMorphs, isMixedAU, isPresetCompatible, mergeRegionsByName as mergeCharacterRegionsByName, resolveBoneName, resolveBoneNames, resolveFaceCenter, suggestBestPreset, validateMappingConfig, validateMappings };
|
|
7601
|
+
export { AU_INFO, AU_MAPPING_CONFIG, AU_MIX_DEFAULTS, AU_TO_MORPHS, AnimationThree, BETTA_FISH_PRESET, BLENDING_MODES, BONE_AU_TO_BINDINGS, CC4_BONE_NODES, CC4_BONE_PREFIX, CC4_EYE_MESH_NODES, CC4_MESHES, CC4_PRESET, CC4_SUFFIX_PATTERN, COMPOSITE_ROTATIONS, CONTINUUM_LABELS, CONTINUUM_PAIRS_MAP, DEFAULT_HAIR_PHYSICS_CONFIG, FISH_AU_MAPPING_CONFIG, HairPhysics, Loom3, Loom3 as Loom3Three, Loom3 as LoomLargeThree, MORPH_TO_MESH, VISEME_JAW_AMOUNTS, VISEME_KEYS, analyzeModel, applyCharacterProfileToPreset, collectMorphMeshes, 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 };
|
|
7378
7602
|
//# sourceMappingURL=index.js.map
|
|
7379
7603
|
//# sourceMappingURL=index.js.map
|