@lovelace_lol/embody 0.0.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/LICENSE +21 -0
- package/README.md +2411 -0
- package/dist/authoring/boneAuthoring.d.ts +132 -0
- package/dist/camera/annotationCameraAngles.d.ts +28 -0
- package/dist/camera/cameraRelativeGaze.d.ts +15 -0
- package/dist/camera/rustAnnotationCameraCore.d.ts +136 -0
- package/dist/cljs.cjs +362 -0
- package/dist/cljs.cjs.map +1 -0
- package/dist/cljs.d.ts +5 -0
- package/dist/cljs.js +359 -0
- package/dist/cljs.js.map +1 -0
- package/dist/core/TsClipCompiler.d.ts +51 -0
- package/dist/core/TsRuntimeCore.d.ts +40 -0
- package/dist/core/WasmRuntimeCore.d.ts +55 -0
- package/dist/core/compositeAxis.d.ts +4 -0
- package/dist/core/contracts/abi.d.ts +70 -0
- package/dist/core/contracts/clip.d.ts +44 -0
- package/dist/core/contracts/frame.d.ts +27 -0
- package/dist/core/contracts/host.d.ts +28 -0
- package/dist/core/contracts/ids.d.ts +15 -0
- package/dist/core/contracts/index.d.ts +10 -0
- package/dist/core/contracts/model.d.ts +31 -0
- package/dist/core/contracts/primitives.d.ts +17 -0
- package/dist/core/contracts/skeletonFit.d.ts +41 -0
- package/dist/core/index.d.ts +8 -0
- package/dist/core/types.d.ts +472 -0
- package/dist/core.cjs +1065 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.js +1040 -0
- package/dist/core.js.map +1 -0
- package/dist/engines/three/Embody.d.ts +373 -0
- package/dist/engines/three/ThreeAnimationRuntime.d.ts +203 -0
- package/dist/engines/three/ThreeClipAdapter.d.ts +24 -0
- package/dist/engines/three/ThreeFrameApplier.d.ts +68 -0
- package/dist/engines/three/ThreeModelInspector.d.ts +54 -0
- package/dist/engines/three/bakedClipPartitioning.d.ts +16 -0
- package/dist/engines/three/balanceUtils.d.ts +3 -0
- package/dist/engines/three/characterHost.d.ts +80 -0
- package/dist/engines/three/characterScene.d.ts +98 -0
- package/dist/engines/three/hair/HairPhysicsController.d.ts +124 -0
- package/dist/engines/three/index.d.ts +20 -0
- package/dist/engines/three/modelLoader.d.ts +61 -0
- package/dist/engines/three/profileTestScene.d.ts +52 -0
- package/dist/engines/three/types.d.ts +20 -0
- package/dist/hair/appearance.d.ts +29 -0
- package/dist/index.cjs +15431 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.js +15141 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/Animation.d.ts +315 -0
- package/dist/interfaces/EmbodyRuntime.d.ts +90 -0
- package/dist/interfaces/Hair.d.ts +181 -0
- package/dist/interfaces/HairPhysics.d.ts +90 -0
- package/dist/interfaces/index.d.ts +11 -0
- package/dist/mappings/extendPresetWithProfile.d.ts +17 -0
- package/dist/mappings/types.d.ts +309 -0
- package/dist/mappings/visemeSystem.d.ts +26 -0
- package/dist/physics/HairPhysics.d.ts +86 -0
- package/dist/physics/RustHairPhysics.d.ts +18 -0
- package/dist/physics/index.d.ts +6 -0
- package/dist/preset.cjs +2000 -0
- package/dist/preset.cjs.map +1 -0
- package/dist/preset.js +1997 -0
- package/dist/preset.js.map +1 -0
- package/dist/presets/bettaFish.d.ts +328 -0
- package/dist/presets/cc4.d.ts +145 -0
- package/dist/presets/index.d.ts +27 -0
- package/dist/profiles/resolveProfileConfig.d.ts +36 -0
- package/dist/profiles/types.d.ts +118 -0
- package/dist/regions/normalizeRegionTree.d.ts +6 -0
- package/dist/regions/regionMapping.d.ts +17 -0
- package/dist/regions/types.d.ts +122 -0
- package/dist/skeletonTemplates/humanoidSkeletonTemplates.d.ts +32 -0
- package/dist/test/setupWasm.d.ts +1 -0
- package/dist/three.cjs +10115 -0
- package/dist/three.cjs.map +1 -0
- package/dist/three.js +10086 -0
- package/dist/three.js.map +1 -0
- package/dist/validation/analyzeModel.d.ts +68 -0
- package/dist/validation/extractModelData.d.ts +90 -0
- package/dist/validation/generateMappingCorrections.d.ts +32 -0
- package/dist/validation/geometryHelpers.d.ts +66 -0
- package/dist/validation/types.d.ts +10 -0
- package/dist/validation/validateMappings.d.ts +77 -0
- package/dist/wasm/LICENSE +21 -0
- package/dist/wasm/README.md +72 -0
- package/dist/wasm/embody_wasm.d.ts +531 -0
- package/dist/wasm/embody_wasm.js +1635 -0
- package/dist/wasm/embody_wasm_bg.wasm +0 -0
- package/dist/wasm/embody_wasm_bg.wasm.d.ts +107 -0
- package/dist/wasm.cjs +302 -0
- package/dist/wasm.cjs.map +1 -0
- package/dist/wasm.d.ts +43 -0
- package/dist/wasm.js +268 -0
- package/dist/wasm.js.map +1 -0
- package/dist/wasmTypes.d.ts +121 -0
- package/package.json +99 -0
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embody - Core Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for the 3D character animation engine.
|
|
5
|
+
* These are framework-agnostic interfaces that work with any 3D engine.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* TransitionHandle - returned from transition methods
|
|
9
|
+
* Provides promise-based completion notification plus fine-grained control.
|
|
10
|
+
*/
|
|
11
|
+
export interface TransitionHandle {
|
|
12
|
+
/** Resolves when the transition completes (or is cancelled) */
|
|
13
|
+
promise: Promise<void>;
|
|
14
|
+
/** Pause this transition (holds at current value) */
|
|
15
|
+
pause: () => void;
|
|
16
|
+
/** Resume this transition after pause */
|
|
17
|
+
resume: () => void;
|
|
18
|
+
/** Cancel this transition immediately (resolves promise) */
|
|
19
|
+
cancel: () => void;
|
|
20
|
+
}
|
|
21
|
+
/** Standard bone keys used in AU bindings */
|
|
22
|
+
export type BoneKey = 'EYE_L' | 'EYE_R' | 'JAW' | 'HEAD' | 'NECK' | 'TONGUE' | string;
|
|
23
|
+
/**
|
|
24
|
+
* BoneBinding - Defines how an AU maps to bone transformations
|
|
25
|
+
*/
|
|
26
|
+
export interface BoneBinding {
|
|
27
|
+
node: BoneKey;
|
|
28
|
+
channel: 'rx' | 'ry' | 'rz' | 'tx' | 'ty' | 'tz';
|
|
29
|
+
scale: -1 | 1;
|
|
30
|
+
maxDegrees?: number;
|
|
31
|
+
maxUnits?: number;
|
|
32
|
+
/** Optional side hint for balance-aware AUs. */
|
|
33
|
+
side?: 'left' | 'right';
|
|
34
|
+
}
|
|
35
|
+
/** A single AU id or a grouped list of AU ids that share one semantic direction. */
|
|
36
|
+
export type AUSelector = number | number[];
|
|
37
|
+
/**
|
|
38
|
+
* RotationAxis - Defines which AUs control a specific rotation axis
|
|
39
|
+
*/
|
|
40
|
+
export interface RotationAxis {
|
|
41
|
+
aus: number[];
|
|
42
|
+
axis: 'rx' | 'ry' | 'rz';
|
|
43
|
+
negative?: AUSelector;
|
|
44
|
+
positive?: AUSelector;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* CompositeRotation - Defines unified rotation axes for bones
|
|
48
|
+
*/
|
|
49
|
+
export interface CompositeRotation {
|
|
50
|
+
node: string;
|
|
51
|
+
pitch: RotationAxis | null;
|
|
52
|
+
yaw: RotationAxis | null;
|
|
53
|
+
roll: RotationAxis | null;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* AUInfo - Metadata about an Action Unit
|
|
57
|
+
*/
|
|
58
|
+
export interface AUInfo {
|
|
59
|
+
id: string;
|
|
60
|
+
name: string;
|
|
61
|
+
muscularBasis?: string;
|
|
62
|
+
links?: string[];
|
|
63
|
+
faceArea?: 'Upper' | 'Lower';
|
|
64
|
+
facePart?: string;
|
|
65
|
+
}
|
|
66
|
+
/** Per-axis rotation state - simple -1 to 1 values like stable version */
|
|
67
|
+
export interface CompositeRotationState {
|
|
68
|
+
pitch: number;
|
|
69
|
+
yaw: number;
|
|
70
|
+
roll: number;
|
|
71
|
+
}
|
|
72
|
+
export type RotationsState = Record<string, CompositeRotationState>;
|
|
73
|
+
/**
|
|
74
|
+
* EmbodyConfig - Configuration options for the Embody engine
|
|
75
|
+
*/
|
|
76
|
+
export interface EmbodyConfig {
|
|
77
|
+
/** AU to morph target mappings (defaults to CC4_PRESET) */
|
|
78
|
+
profile?: import('../mappings/types').Profile;
|
|
79
|
+
/** Preset type to resolve if profile is not provided. */
|
|
80
|
+
presetType?: import('../presets').PresetType | string;
|
|
81
|
+
}
|
|
82
|
+
export type MorphTargetAttributeData = Float32Array | number[];
|
|
83
|
+
export interface MorphTargetDelta {
|
|
84
|
+
/** Mesh name from the loaded Three.js scene. */
|
|
85
|
+
meshName: string;
|
|
86
|
+
/** Morph target name to add to morphTargetDictionary. */
|
|
87
|
+
name: string;
|
|
88
|
+
/** POSITION deltas, usually XYZ values relative to the base mesh. */
|
|
89
|
+
position: MorphTargetAttributeData;
|
|
90
|
+
/** Optional NORMAL deltas. */
|
|
91
|
+
normal?: MorphTargetAttributeData;
|
|
92
|
+
/** Optional TANGENT deltas. */
|
|
93
|
+
tangent?: MorphTargetAttributeData;
|
|
94
|
+
/** Whether deltas are relative to base attributes. Defaults to true. */
|
|
95
|
+
relative?: boolean;
|
|
96
|
+
}
|
|
97
|
+
export interface AddMorphTargetOptions {
|
|
98
|
+
/** Replace an existing morph target with the same name. */
|
|
99
|
+
replace?: boolean;
|
|
100
|
+
/** Initialize the new or replaced influence value to zero. Defaults to true. */
|
|
101
|
+
resetInfluence?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Replace and dispose the BufferGeometry instead of mutating it in place.
|
|
104
|
+
* Defaults to true because Three.js does not support mutating morph attributes
|
|
105
|
+
* after a geometry has rendered.
|
|
106
|
+
*/
|
|
107
|
+
forceGeometryReplacement?: boolean;
|
|
108
|
+
}
|
|
109
|
+
/** Source category for mixer-driven animations. */
|
|
110
|
+
export type AnimationSource = 'baked' | 'clip' | 'snippet';
|
|
111
|
+
/** Shared blend-mode surface for downstream animation UIs. */
|
|
112
|
+
export type AnimationBlendMode = 'replace' | 'additive';
|
|
113
|
+
/** Mixer channel classes derived from one authored baked source clip. */
|
|
114
|
+
export type BakedClipChannel = 'face' | 'body' | 'scene';
|
|
115
|
+
/** Metadata describing one derived baked mixer channel. */
|
|
116
|
+
export interface BakedClipChannelInfo {
|
|
117
|
+
/** Logical channel key surfaced to downstream UIs. */
|
|
118
|
+
channel: BakedClipChannel;
|
|
119
|
+
/** Number of tracks routed into this channel. */
|
|
120
|
+
trackCount: number;
|
|
121
|
+
/** Whether Embody can play this channel directly. */
|
|
122
|
+
playable: boolean;
|
|
123
|
+
/** Effective/default blend mode for this channel when playable. */
|
|
124
|
+
blendMode?: AnimationBlendMode;
|
|
125
|
+
}
|
|
126
|
+
/** Shared easing labels for downstream animation UIs. */
|
|
127
|
+
export type AnimationEasing = 'linear' | 'easeInOut' | 'easeInOutCubic' | 'easeIn' | 'easeOut';
|
|
128
|
+
/**
|
|
129
|
+
* Options for playing a mixer animation clip.
|
|
130
|
+
*/
|
|
131
|
+
export interface AnimationPlayOptions {
|
|
132
|
+
/** Playback speed multiplier (default: 1.0). Alias: playbackRate. */
|
|
133
|
+
speed?: number;
|
|
134
|
+
/** Alias for speed so loaded clips and dynamic clips can share one UI contract. */
|
|
135
|
+
playbackRate?: number;
|
|
136
|
+
/** Animation intensity/weight (default: 1.0). Alias: weight. */
|
|
137
|
+
intensity?: number;
|
|
138
|
+
/** Alias for intensity so loaded clips and dynamic clips can share one UI contract. */
|
|
139
|
+
weight?: number;
|
|
140
|
+
/** Whether the animation should loop (default: true) */
|
|
141
|
+
loop?: boolean;
|
|
142
|
+
/** Loop mode: 'repeat' (restart from beginning), 'pingpong' (reverse direction), 'once' (no loop) */
|
|
143
|
+
loopMode?: 'repeat' | 'pingpong' | 'once';
|
|
144
|
+
/** Number of repetitions when looping (default: Infinity for repeat/pingpong) */
|
|
145
|
+
repeatCount?: number;
|
|
146
|
+
/** Play clip backwards when true (implemented via negative time scale) */
|
|
147
|
+
reverse?: boolean;
|
|
148
|
+
/** Shared balance metadata for downstream UIs (-1 to 1, default: 0) */
|
|
149
|
+
balance?: number;
|
|
150
|
+
/** Shared blend metadata for downstream UIs (default: replace) */
|
|
151
|
+
blendMode?: AnimationBlendMode;
|
|
152
|
+
/** Shared easing metadata for downstream UIs (default: linear) */
|
|
153
|
+
easing?: AnimationEasing;
|
|
154
|
+
/** Crossfade duration in seconds when transitioning from another animation (default: 0.3) */
|
|
155
|
+
crossfadeDuration?: number;
|
|
156
|
+
/** Clamp animation at end when not looping (default: true) */
|
|
157
|
+
clampWhenFinished?: boolean;
|
|
158
|
+
/** Start time offset in seconds (default: 0) */
|
|
159
|
+
startTime?: number;
|
|
160
|
+
/** Optional source override for downstream consumers */
|
|
161
|
+
source?: AnimationSource;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Information about a loaded animation clip.
|
|
165
|
+
*/
|
|
166
|
+
export interface AnimationClipInfo {
|
|
167
|
+
/** Name of the animation clip */
|
|
168
|
+
name: string;
|
|
169
|
+
/** Duration of the animation in seconds */
|
|
170
|
+
duration: number;
|
|
171
|
+
/** Number of tracks (bones/morphs being animated) */
|
|
172
|
+
trackCount: number;
|
|
173
|
+
/** Source of the clip for downstream UI grouping */
|
|
174
|
+
source?: AnimationSource;
|
|
175
|
+
/** Derived channel metadata for partitioned baked clips. */
|
|
176
|
+
channels?: BakedClipChannelInfo[];
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* State of a currently playing animation.
|
|
180
|
+
*/
|
|
181
|
+
export interface AnimationState {
|
|
182
|
+
/** Name of the animation */
|
|
183
|
+
name: string;
|
|
184
|
+
/** Optional action id for the current mixer action */
|
|
185
|
+
actionId?: string;
|
|
186
|
+
/** Source of the animation for downstream UIs */
|
|
187
|
+
source?: AnimationSource;
|
|
188
|
+
/** Whether the animation is currently playing */
|
|
189
|
+
isPlaying: boolean;
|
|
190
|
+
/** Whether the animation is paused */
|
|
191
|
+
isPaused: boolean;
|
|
192
|
+
/** Current playback time in seconds */
|
|
193
|
+
time: number;
|
|
194
|
+
/** Duration of the animation in seconds */
|
|
195
|
+
duration: number;
|
|
196
|
+
/** Current playback speed magnitude. */
|
|
197
|
+
speed: number;
|
|
198
|
+
/** Alias for speed to match snippet-style UIs. */
|
|
199
|
+
playbackRate: number;
|
|
200
|
+
/** Whether the animation is playing in reverse */
|
|
201
|
+
reverse: boolean;
|
|
202
|
+
/** Current weight/intensity */
|
|
203
|
+
weight: number;
|
|
204
|
+
/** Shared balance metadata for downstream UIs */
|
|
205
|
+
balance: number;
|
|
206
|
+
/** Requested source-level blend mode before per-channel routing. */
|
|
207
|
+
requestedBlendMode: AnimationBlendMode;
|
|
208
|
+
/** Shared blend metadata for downstream UIs */
|
|
209
|
+
blendMode: AnimationBlendMode;
|
|
210
|
+
/** Derived channel metadata for partitioned baked clips. */
|
|
211
|
+
channels?: BakedClipChannelInfo[];
|
|
212
|
+
/** Shared easing metadata for downstream UIs */
|
|
213
|
+
easing: AnimationEasing;
|
|
214
|
+
/** Whether the animation is looping */
|
|
215
|
+
loop: boolean;
|
|
216
|
+
/** Loop mode */
|
|
217
|
+
loopMode: 'repeat' | 'pingpong' | 'once';
|
|
218
|
+
/** Number of repetitions when looping (if configured) */
|
|
219
|
+
repeatCount?: number;
|
|
220
|
+
/** Whether the animation is looping */
|
|
221
|
+
isLooping: boolean;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Handle returned when playing an animation, providing control methods.
|
|
225
|
+
*/
|
|
226
|
+
export interface AnimationActionHandle {
|
|
227
|
+
/** Optional unique id for the underlying mixer action */
|
|
228
|
+
actionId?: string;
|
|
229
|
+
/** Stop the animation */
|
|
230
|
+
stop: () => void;
|
|
231
|
+
/** Pause the animation */
|
|
232
|
+
pause: () => void;
|
|
233
|
+
/** Resume a paused animation */
|
|
234
|
+
resume: () => void;
|
|
235
|
+
/** Set playback speed */
|
|
236
|
+
setSpeed: (speed: number) => void;
|
|
237
|
+
/** Set animation weight/intensity (0-1) */
|
|
238
|
+
setWeight: (weight: number) => void;
|
|
239
|
+
/** Seek to a specific time in seconds */
|
|
240
|
+
seekTo: (time: number) => void;
|
|
241
|
+
/** Get current animation state */
|
|
242
|
+
getState: () => AnimationState;
|
|
243
|
+
/** Crossfade to another animation */
|
|
244
|
+
crossfadeTo: (clipName: string, duration?: number) => AnimationActionHandle | null;
|
|
245
|
+
/** Promise that resolves when animation completes (only for non-looping) */
|
|
246
|
+
finished: Promise<void>;
|
|
247
|
+
}
|
|
248
|
+
export type ClipEvent = {
|
|
249
|
+
type: 'keyframe';
|
|
250
|
+
clipName: string;
|
|
251
|
+
keyframeIndex: number;
|
|
252
|
+
totalKeyframes: number;
|
|
253
|
+
currentTime: number;
|
|
254
|
+
duration: number;
|
|
255
|
+
iteration: number;
|
|
256
|
+
} | {
|
|
257
|
+
type: 'loop';
|
|
258
|
+
clipName: string;
|
|
259
|
+
iteration: number;
|
|
260
|
+
currentTime: number;
|
|
261
|
+
duration: number;
|
|
262
|
+
} | {
|
|
263
|
+
type: 'seek';
|
|
264
|
+
clipName: string;
|
|
265
|
+
currentTime: number;
|
|
266
|
+
duration: number;
|
|
267
|
+
iteration: number;
|
|
268
|
+
} | {
|
|
269
|
+
type: 'completed';
|
|
270
|
+
clipName: string;
|
|
271
|
+
currentTime: number;
|
|
272
|
+
duration: number;
|
|
273
|
+
iteration: number;
|
|
274
|
+
};
|
|
275
|
+
export type ClipEventListener = (event: ClipEvent) => void;
|
|
276
|
+
export interface EmbodyAnimationRuntimeConnector {
|
|
277
|
+
buildClip?: (clipName: string, curves: CurvesMap, options?: ClipOptions) => unknown;
|
|
278
|
+
playClip?: (clipName: string, curves?: CurvesMap, options?: ClipOptions) => unknown;
|
|
279
|
+
buildTypedClip?: (clipName: string, channels: SnippetChannel[], options?: ClipOptions) => unknown;
|
|
280
|
+
playTypedSnippet?: (snippet: TypedSnippet, options?: ClipOptions) => unknown;
|
|
281
|
+
stopClip?: (clipName: string) => void;
|
|
282
|
+
pauseClip?: (clipName: string) => void;
|
|
283
|
+
resumeClip?: (clipName: string) => void;
|
|
284
|
+
setClipWeight?: (clipName: string, weight: number) => void;
|
|
285
|
+
setClipPlaybackRate?: (clipName: string, rate: number) => void;
|
|
286
|
+
setClipLoop?: (clipName: string, mode: 'once' | 'repeat' | 'pingpong', repeatCount?: number) => void;
|
|
287
|
+
setClipTime?: (clipName: string, time: number) => void;
|
|
288
|
+
getClipTime?: (clipName: string) => number;
|
|
289
|
+
getClipDuration?: (clipName: string) => number;
|
|
290
|
+
updateClipParams?: (clipName: string, params: Record<string, unknown>) => boolean;
|
|
291
|
+
cleanupSnippet?: (clipName: string) => void;
|
|
292
|
+
onCommand?: (command: Record<string, unknown>) => void;
|
|
293
|
+
onState?: (state: Record<string, unknown>) => void;
|
|
294
|
+
}
|
|
295
|
+
export interface EmbodyAnimationRuntime {
|
|
296
|
+
snapshot(): Record<string, unknown>;
|
|
297
|
+
buildClip(clipName: string, curves: CurvesMap, options?: ClipOptions): ClipHandle | null;
|
|
298
|
+
playSnippet(clipName: string, curves: CurvesMap, options?: ClipOptions): ClipHandle | null;
|
|
299
|
+
buildTypedClip?: (clipName: string, channels: SnippetChannel[], options?: ClipOptions) => ClipHandle | null;
|
|
300
|
+
playTypedSnippet?: (snippet: TypedSnippet, options?: ClipOptions) => ClipHandle | null;
|
|
301
|
+
acceptClipEvent(event: ClipEvent | Record<string, unknown>): boolean;
|
|
302
|
+
cleanupSnippet(clipName: string): boolean;
|
|
303
|
+
updateClipParams(clipName: string, params: Record<string, unknown>): boolean;
|
|
304
|
+
}
|
|
305
|
+
export type EmbodyAnimationRuntimeFactory = (config?: Record<string, unknown> | null, connector?: EmbodyAnimationRuntimeConnector | null) => EmbodyAnimationRuntime;
|
|
306
|
+
/**
|
|
307
|
+
* A single keyframe point in an animation curve.
|
|
308
|
+
*/
|
|
309
|
+
export interface CurvePoint {
|
|
310
|
+
/** Time in seconds */
|
|
311
|
+
time: number;
|
|
312
|
+
/** Intensity value (0-1) */
|
|
313
|
+
intensity: number;
|
|
314
|
+
/**
|
|
315
|
+
* When true on the first keyframe, capture the driven target's current live
|
|
316
|
+
* value at clip construction/playback start and transition from that anchor
|
|
317
|
+
* into the following authored keyframes.
|
|
318
|
+
*/
|
|
319
|
+
inherit?: boolean;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Map of curve IDs (AU numbers or morph names) to keyframe arrays.
|
|
323
|
+
*/
|
|
324
|
+
export type CurvesMap = Record<string, CurvePoint[]>;
|
|
325
|
+
export type SnippetChannelTarget = {
|
|
326
|
+
type: 'au';
|
|
327
|
+
id: number;
|
|
328
|
+
balance?: number;
|
|
329
|
+
} | {
|
|
330
|
+
type: 'viseme';
|
|
331
|
+
id: number;
|
|
332
|
+
meshNames?: string[];
|
|
333
|
+
} | {
|
|
334
|
+
type: 'lipSync';
|
|
335
|
+
id: number;
|
|
336
|
+
} | {
|
|
337
|
+
type: 'morph';
|
|
338
|
+
id: string | number;
|
|
339
|
+
meshNames?: string[];
|
|
340
|
+
} | {
|
|
341
|
+
type: 'bone';
|
|
342
|
+
id: BoneKey;
|
|
343
|
+
channel: 'rx' | 'ry' | 'rz' | 'tx' | 'ty' | 'tz';
|
|
344
|
+
scale?: number;
|
|
345
|
+
maxDegrees?: number;
|
|
346
|
+
maxUnits?: number;
|
|
347
|
+
};
|
|
348
|
+
/**
|
|
349
|
+
* A typed snippet channel names the target namespace explicitly. This avoids
|
|
350
|
+
* the legacy curve-map ambiguity where numeric key "1" can mean AU 1 or
|
|
351
|
+
* viseme slot 1 depending on snippetCategory, and it keeps speech-only
|
|
352
|
+
* lip-sync controls out of FACS AU space.
|
|
353
|
+
*/
|
|
354
|
+
export interface SnippetChannel {
|
|
355
|
+
target: SnippetChannelTarget;
|
|
356
|
+
keyframes: CurvePoint[];
|
|
357
|
+
/** Per-channel intensity multiplier applied in addition to ClipOptions.intensityScale. */
|
|
358
|
+
intensityScale?: number;
|
|
359
|
+
}
|
|
360
|
+
export interface TypedSnippet {
|
|
361
|
+
name: string;
|
|
362
|
+
channels: SnippetChannel[];
|
|
363
|
+
maxTime?: number;
|
|
364
|
+
loop?: boolean;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Options for building and playing a clip from curves.
|
|
368
|
+
*/
|
|
369
|
+
export interface ClipOptions {
|
|
370
|
+
/** Whether the clip should loop (default: false) */
|
|
371
|
+
loop?: boolean;
|
|
372
|
+
/** Loop mode: repeat (default), pingpong (forward/back), or once */
|
|
373
|
+
loopMode?: 'repeat' | 'pingpong' | 'once';
|
|
374
|
+
/** Number of repetitions when looping (default: Infinity for repeat/pingpong) */
|
|
375
|
+
repeatCount?: number;
|
|
376
|
+
/** Playback rate multiplier (default: 1.0) */
|
|
377
|
+
playbackRate?: number;
|
|
378
|
+
/** Alias for playbackRate so dynamic clips can share one UI contract with loaded clips. */
|
|
379
|
+
speed?: number;
|
|
380
|
+
/** Play clip backwards when true (implemented via negative time scale) */
|
|
381
|
+
reverse?: boolean;
|
|
382
|
+
/** Start time offset in seconds (default: clip start, or clip end for reverse once playback) */
|
|
383
|
+
startTime?: number;
|
|
384
|
+
/** Mixer weight/intensity (default: 1.0) */
|
|
385
|
+
mixerWeight?: number;
|
|
386
|
+
/** Alias for mixerWeight/intensity so clip-backed animations can share one UI contract. */
|
|
387
|
+
weight?: number;
|
|
388
|
+
/** Alias for weight/intensity so clip-backed animations can share one UI contract. */
|
|
389
|
+
intensity?: number;
|
|
390
|
+
/** Left/right balance for bilateral AUs (-1 to 1, default: 0) */
|
|
391
|
+
balance?: number;
|
|
392
|
+
/** Shared blend metadata for downstream UIs (default: replace) */
|
|
393
|
+
blendMode?: AnimationBlendMode;
|
|
394
|
+
/** Shared easing metadata for downstream UIs (default: linear) */
|
|
395
|
+
easing?: AnimationEasing;
|
|
396
|
+
/** Legacy additive toggle alias for downstream compatibility */
|
|
397
|
+
mixerAdditive?: boolean;
|
|
398
|
+
/**
|
|
399
|
+
* Per-curve left/right balance overrides keyed by curve id (typically AU ids as strings).
|
|
400
|
+
* Example: { "43": 1, "12": 0.7 }.
|
|
401
|
+
* Falls back to `balance` when a curve id is not present.
|
|
402
|
+
*/
|
|
403
|
+
balanceMap?: Record<string, number>;
|
|
404
|
+
/** Jaw scale for viseme playback (default: 1.0) */
|
|
405
|
+
jawScale?: number;
|
|
406
|
+
/** Intensity scale multiplier (default: 1.0) */
|
|
407
|
+
intensityScale?: number;
|
|
408
|
+
/** Optional morph target mesh names to constrain track creation */
|
|
409
|
+
meshNames?: string[];
|
|
410
|
+
/** Snippet category - when 'visemeSnippet', numeric curve IDs (0-14) are viseme indices; otherwise they're AU IDs */
|
|
411
|
+
snippetCategory?: 'auSnippet' | 'visemeSnippet';
|
|
412
|
+
/**
|
|
413
|
+
* When true, automatically generate jaw bone rotation from viseme curves.
|
|
414
|
+
* Uses VISEME_JAW_AMOUNTS to determine jaw opening per viseme index.
|
|
415
|
+
* Only applies when snippetCategory is 'visemeSnippet'.
|
|
416
|
+
* Default: true (for backwards compatibility with transitionViseme behavior)
|
|
417
|
+
*/
|
|
418
|
+
autoVisemeJaw?: boolean;
|
|
419
|
+
/** Optional source override for downstream consumers */
|
|
420
|
+
source?: AnimationSource;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Handle returned when playing a dynamically-built clip.
|
|
424
|
+
*/
|
|
425
|
+
export interface ClipHandle {
|
|
426
|
+
/** Name of the clip */
|
|
427
|
+
clipName: string;
|
|
428
|
+
/** Optional unique id for the underlying mixer action */
|
|
429
|
+
actionId?: string;
|
|
430
|
+
/** Start or restart playback */
|
|
431
|
+
play: () => void;
|
|
432
|
+
/** Stop playback and reset */
|
|
433
|
+
stop: () => void;
|
|
434
|
+
/** Pause playback at current position */
|
|
435
|
+
pause: () => void;
|
|
436
|
+
/** Resume paused playback */
|
|
437
|
+
resume: () => void;
|
|
438
|
+
/** Optional weight setter for live mixer updates */
|
|
439
|
+
setWeight?: (w: number) => void;
|
|
440
|
+
/** Optional playback-rate setter for live mixer updates */
|
|
441
|
+
setPlaybackRate?: (r: number) => void;
|
|
442
|
+
/** Optional loop setter for live mixer updates */
|
|
443
|
+
setLoop?: (mode: 'once' | 'repeat' | 'pingpong', repeatCount?: number) => void;
|
|
444
|
+
/** Optional time setter for scrubbing */
|
|
445
|
+
setTime?: (time: number) => void;
|
|
446
|
+
/** Get current playback time in seconds */
|
|
447
|
+
getTime: () => number;
|
|
448
|
+
/** Get total clip duration in seconds */
|
|
449
|
+
getDuration: () => number;
|
|
450
|
+
/** Subscribe to clip lifecycle events emitted during mixer updates */
|
|
451
|
+
subscribe?: (listener: ClipEventListener) => () => void;
|
|
452
|
+
/** Promise that resolves when clip finishes (non-looping only) */
|
|
453
|
+
finished: Promise<void>;
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Snippet definition for animation playback.
|
|
457
|
+
* Can be loaded from JSON and converted to a mixer clip.
|
|
458
|
+
*/
|
|
459
|
+
export interface Snippet {
|
|
460
|
+
/** Unique name for this snippet */
|
|
461
|
+
name: string;
|
|
462
|
+
/** Optional description */
|
|
463
|
+
description?: string;
|
|
464
|
+
/** Map of AU/morph IDs to keyframe curves */
|
|
465
|
+
curves: CurvesMap;
|
|
466
|
+
/** Category for grouping (e.g., 'eyeHeadTracking', 'visemeSnippet') */
|
|
467
|
+
snippetCategory?: string;
|
|
468
|
+
/** Priority for scheduling conflicts */
|
|
469
|
+
snippetPriority?: number;
|
|
470
|
+
/** Whether to loop playback */
|
|
471
|
+
loop?: boolean;
|
|
472
|
+
}
|