@aura3d/animation 1.0.6
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 +19 -0
- package/dist/AnimationAction.d.ts +40 -0
- package/dist/AnimationAction.d.ts.map +1 -0
- package/dist/AnimationAction.js +143 -0
- package/dist/AnimationAction.js.map +1 -0
- package/dist/AnimationClip.d.ts +24 -0
- package/dist/AnimationClip.d.ts.map +1 -0
- package/dist/AnimationClip.js +45 -0
- package/dist/AnimationClip.js.map +1 -0
- package/dist/AnimationClipEvents.d.ts +57 -0
- package/dist/AnimationClipEvents.d.ts.map +1 -0
- package/dist/AnimationClipEvents.js +171 -0
- package/dist/AnimationClipEvents.js.map +1 -0
- package/dist/AnimationClipRegistry.d.ts +76 -0
- package/dist/AnimationClipRegistry.d.ts.map +1 -0
- package/dist/AnimationClipRegistry.js +130 -0
- package/dist/AnimationClipRegistry.js.map +1 -0
- package/dist/AnimationController.d.ts +168 -0
- package/dist/AnimationController.d.ts.map +1 -0
- package/dist/AnimationController.js +619 -0
- package/dist/AnimationController.js.map +1 -0
- package/dist/AnimationEvents.d.ts +10 -0
- package/dist/AnimationEvents.d.ts.map +1 -0
- package/dist/AnimationEvents.js +26 -0
- package/dist/AnimationEvents.js.map +1 -0
- package/dist/AnimationLayer.d.ts +27 -0
- package/dist/AnimationLayer.d.ts.map +1 -0
- package/dist/AnimationLayer.js +53 -0
- package/dist/AnimationLayer.js.map +1 -0
- package/dist/AnimationMixer.d.ts +54 -0
- package/dist/AnimationMixer.d.ts.map +1 -0
- package/dist/AnimationMixer.js +319 -0
- package/dist/AnimationMixer.js.map +1 -0
- package/dist/AnimationStateGraph.d.ts +2 -0
- package/dist/AnimationStateGraph.d.ts.map +1 -0
- package/dist/AnimationStateGraph.js +2 -0
- package/dist/AnimationStateGraph.js.map +1 -0
- package/dist/AnimationStateMachine.d.ts +59 -0
- package/dist/AnimationStateMachine.d.ts.map +1 -0
- package/dist/AnimationStateMachine.js +154 -0
- package/dist/AnimationStateMachine.js.map +1 -0
- package/dist/AnimationTrack.d.ts +23 -0
- package/dist/AnimationTrack.d.ts.map +1 -0
- package/dist/AnimationTrack.js +124 -0
- package/dist/AnimationTrack.js.map +1 -0
- package/dist/BlendTree.d.ts +23 -0
- package/dist/BlendTree.d.ts.map +1 -0
- package/dist/BlendTree.js +68 -0
- package/dist/BlendTree.js.map +1 -0
- package/dist/Bone.d.ts +20 -0
- package/dist/Bone.d.ts.map +1 -0
- package/dist/Bone.js +24 -0
- package/dist/Bone.js.map +1 -0
- package/dist/CrowdAnimation.d.ts +13 -0
- package/dist/CrowdAnimation.d.ts.map +1 -0
- package/dist/CrowdAnimation.js +14 -0
- package/dist/CrowdAnimation.js.map +1 -0
- package/dist/ECSAnimationBridge.d.ts +9 -0
- package/dist/ECSAnimationBridge.d.ts.map +1 -0
- package/dist/ECSAnimationBridge.js +24 -0
- package/dist/ECSAnimationBridge.js.map +1 -0
- package/dist/HumanoidRetargeting.d.ts +76 -0
- package/dist/HumanoidRetargeting.d.ts.map +1 -0
- package/dist/HumanoidRetargeting.js +331 -0
- package/dist/HumanoidRetargeting.js.map +1 -0
- package/dist/IK.d.ts +24 -0
- package/dist/IK.d.ts.map +1 -0
- package/dist/IK.js +76 -0
- package/dist/IK.js.map +1 -0
- package/dist/Keyframe.d.ts +50 -0
- package/dist/Keyframe.d.ts.map +1 -0
- package/dist/Keyframe.js +118 -0
- package/dist/Keyframe.js.map +1 -0
- package/dist/LocomotionController.d.ts +47 -0
- package/dist/LocomotionController.d.ts.map +1 -0
- package/dist/LocomotionController.js +106 -0
- package/dist/LocomotionController.js.map +1 -0
- package/dist/MotionMatchingFixtures.d.ts +58 -0
- package/dist/MotionMatchingFixtures.d.ts.map +1 -0
- package/dist/MotionMatchingFixtures.js +175 -0
- package/dist/MotionMatchingFixtures.js.map +1 -0
- package/dist/MotionQuality.d.ts +36 -0
- package/dist/MotionQuality.d.ts.map +1 -0
- package/dist/MotionQuality.js +117 -0
- package/dist/MotionQuality.js.map +1 -0
- package/dist/Retargeting.d.ts +12 -0
- package/dist/Retargeting.d.ts.map +1 -0
- package/dist/Retargeting.js +19 -0
- package/dist/Retargeting.js.map +1 -0
- package/dist/RootMotion.d.ts +21 -0
- package/dist/RootMotion.d.ts.map +1 -0
- package/dist/RootMotion.js +84 -0
- package/dist/RootMotion.js.map +1 -0
- package/dist/SceneAnimationBridge.d.ts +18 -0
- package/dist/SceneAnimationBridge.d.ts.map +1 -0
- package/dist/SceneAnimationBridge.js +69 -0
- package/dist/SceneAnimationBridge.js.map +1 -0
- package/dist/SecondaryAnimationFixtures.d.ts +55 -0
- package/dist/SecondaryAnimationFixtures.d.ts.map +1 -0
- package/dist/SecondaryAnimationFixtures.js +147 -0
- package/dist/SecondaryAnimationFixtures.js.map +1 -0
- package/dist/Skeleton.d.ts +9 -0
- package/dist/Skeleton.d.ts.map +1 -0
- package/dist/Skeleton.js +31 -0
- package/dist/Skeleton.js.map +1 -0
- package/dist/Skinning.d.ts +7 -0
- package/dist/Skinning.d.ts.map +1 -0
- package/dist/Skinning.js +12 -0
- package/dist/Skinning.js.map +1 -0
- package/dist/browser-index.d.ts +39 -0
- package/dist/browser-index.d.ts.map +1 -0
- package/dist/browser-index.js +34 -0
- package/dist/browser-index.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/threejs-compatibility/AnimationAction.d.ts +16 -0
- package/dist/threejs-compatibility/AnimationAction.d.ts.map +1 -0
- package/dist/threejs-compatibility/AnimationAction.js +25 -0
- package/dist/threejs-compatibility/AnimationAction.js.map +1 -0
- package/dist/threejs-compatibility/AnimationClip.d.ts +14 -0
- package/dist/threejs-compatibility/AnimationClip.d.ts.map +1 -0
- package/dist/threejs-compatibility/AnimationClip.js +11 -0
- package/dist/threejs-compatibility/AnimationClip.js.map +1 -0
- package/dist/threejs-compatibility/AnimationDiagnostics.d.ts +44 -0
- package/dist/threejs-compatibility/AnimationDiagnostics.d.ts.map +1 -0
- package/dist/threejs-compatibility/AnimationDiagnostics.js +29 -0
- package/dist/threejs-compatibility/AnimationDiagnostics.js.map +1 -0
- package/dist/threejs-compatibility/AnimationMixer.d.ts +9 -0
- package/dist/threejs-compatibility/AnimationMixer.d.ts.map +1 -0
- package/dist/threejs-compatibility/AnimationMixer.js +24 -0
- package/dist/threejs-compatibility/AnimationMixer.js.map +1 -0
- package/dist/threejs-compatibility/MorphTargetMixer.d.ts +10 -0
- package/dist/threejs-compatibility/MorphTargetMixer.d.ts.map +1 -0
- package/dist/threejs-compatibility/MorphTargetMixer.js +10 -0
- package/dist/threejs-compatibility/MorphTargetMixer.js.map +1 -0
- package/dist/threejs-compatibility/Skeleton.d.ts +10 -0
- package/dist/threejs-compatibility/Skeleton.d.ts.map +1 -0
- package/dist/threejs-compatibility/Skeleton.js +8 -0
- package/dist/threejs-compatibility/Skeleton.js.map +1 -0
- package/dist/threejs-compatibility/SkinnedMesh.d.ts +11 -0
- package/dist/threejs-compatibility/SkinnedMesh.d.ts.map +1 -0
- package/dist/threejs-compatibility/SkinnedMesh.js +16 -0
- package/dist/threejs-compatibility/SkinnedMesh.js.map +1 -0
- package/dist/threejs-compatibility/index.d.ts +12 -0
- package/dist/threejs-compatibility/index.d.ts.map +1 -0
- package/dist/threejs-compatibility/index.js +8 -0
- package/dist/threejs-compatibility/index.js.map +1 -0
- package/package.json +17 -0
- package/src/AnimationAction.ts +166 -0
- package/src/AnimationClip.ts +63 -0
- package/src/AnimationClipEvents.ts +320 -0
- package/src/AnimationClipRegistry.ts +280 -0
- package/src/AnimationController.ts +967 -0
- package/src/AnimationEvents.ts +34 -0
- package/src/AnimationLayer.ts +73 -0
- package/src/AnimationMixer.ts +366 -0
- package/src/AnimationStateGraph.ts +8 -0
- package/src/AnimationStateMachine.ts +217 -0
- package/src/AnimationTrack.ts +176 -0
- package/src/BlendTree.ts +89 -0
- package/src/Bone.ts +35 -0
- package/src/CrowdAnimation.ts +25 -0
- package/src/ECSAnimationBridge.ts +30 -0
- package/src/HumanoidRetargeting.ts +476 -0
- package/src/IK.ts +107 -0
- package/src/Keyframe.ts +159 -0
- package/src/LocomotionController.ts +149 -0
- package/src/MotionMatchingFixtures.ts +254 -0
- package/src/MotionQuality.ts +156 -0
- package/src/Retargeting.ts +29 -0
- package/src/RootMotion.ts +124 -0
- package/src/SceneAnimationBridge.ts +80 -0
- package/src/SecondaryAnimationFixtures.ts +212 -0
- package/src/Skeleton.ts +34 -0
- package/src/Skinning.ts +18 -0
- package/src/browser-index.ts +55 -0
- package/src/index.ts +56 -0
- package/src/threejs-compatibility/AnimationAction.ts +27 -0
- package/src/threejs-compatibility/AnimationClip.ts +16 -0
- package/src/threejs-compatibility/AnimationDiagnostics.ts +42 -0
- package/src/threejs-compatibility/AnimationMixer.ts +24 -0
- package/src/threejs-compatibility/MorphTargetMixer.ts +16 -0
- package/src/threejs-compatibility/Skeleton.ts +9 -0
- package/src/threejs-compatibility/SkinnedMesh.ts +12 -0
- package/src/threejs-compatibility/index.ts +11 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import {
|
|
2
|
+
normalizeClipEvents,
|
|
3
|
+
type AnimationClipEvent
|
|
4
|
+
} from "./AnimationClipEvents.js";
|
|
5
|
+
|
|
6
|
+
export type AnimationClipId = string;
|
|
7
|
+
|
|
8
|
+
export type AnimationTrackTarget =
|
|
9
|
+
| "translation"
|
|
10
|
+
| "rotation"
|
|
11
|
+
| "scale"
|
|
12
|
+
| "morph"
|
|
13
|
+
| "material"
|
|
14
|
+
| "visibility"
|
|
15
|
+
| (string & {});
|
|
16
|
+
|
|
17
|
+
export interface AnimationKeyframe<TValue = unknown> {
|
|
18
|
+
readonly time: number;
|
|
19
|
+
readonly value: TValue;
|
|
20
|
+
readonly easing?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface AnimationTrack<TValue = unknown> {
|
|
24
|
+
readonly id?: string;
|
|
25
|
+
readonly target: string;
|
|
26
|
+
readonly property?: AnimationTrackTarget;
|
|
27
|
+
readonly keyframes?: readonly AnimationKeyframe<TValue>[];
|
|
28
|
+
readonly metadata?: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface AnimationClipSampleContext<
|
|
32
|
+
TClipId extends string = string,
|
|
33
|
+
TEvent extends AnimationClipEvent = AnimationClipEvent
|
|
34
|
+
> {
|
|
35
|
+
readonly clip: RegisteredAnimationClip<TClipId, TEvent>;
|
|
36
|
+
readonly time: number;
|
|
37
|
+
readonly normalizedTime: number;
|
|
38
|
+
readonly playbackState?: unknown;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type AnimationClipSampler<
|
|
42
|
+
TPose = unknown,
|
|
43
|
+
TClipId extends string = string,
|
|
44
|
+
TEvent extends AnimationClipEvent = AnimationClipEvent
|
|
45
|
+
> = (context: AnimationClipSampleContext<TClipId, TEvent>) => TPose;
|
|
46
|
+
|
|
47
|
+
export interface AnimationClipDefinition<
|
|
48
|
+
TClipId extends string = string,
|
|
49
|
+
TEvent extends AnimationClipEvent = AnimationClipEvent,
|
|
50
|
+
TPose = unknown
|
|
51
|
+
> {
|
|
52
|
+
readonly id: TClipId;
|
|
53
|
+
readonly name?: string;
|
|
54
|
+
readonly duration: number;
|
|
55
|
+
readonly frameRate?: number;
|
|
56
|
+
readonly loop?: boolean;
|
|
57
|
+
readonly tags?: readonly string[];
|
|
58
|
+
readonly tracks?: readonly AnimationTrack[];
|
|
59
|
+
readonly events?: readonly TEvent[];
|
|
60
|
+
readonly sample?: AnimationClipSampler<TPose, TClipId, TEvent>;
|
|
61
|
+
readonly source?: string;
|
|
62
|
+
readonly metadata?: Record<string, unknown>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface RegisteredAnimationClip<
|
|
66
|
+
TClipId extends string = string,
|
|
67
|
+
TEvent extends AnimationClipEvent = AnimationClipEvent,
|
|
68
|
+
TPose = unknown
|
|
69
|
+
> extends AnimationClipDefinition<TClipId, TEvent, TPose> {
|
|
70
|
+
readonly duration: number;
|
|
71
|
+
readonly loop: boolean;
|
|
72
|
+
readonly tags: readonly string[];
|
|
73
|
+
readonly tracks: readonly AnimationTrack[];
|
|
74
|
+
readonly events: readonly TEvent[];
|
|
75
|
+
readonly registryIndex: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface AnimationClipRegistryOptions {
|
|
79
|
+
readonly replace?: boolean;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export type AnimationClipRegistryDiagnosticSeverity = "info" | "warning" | "error";
|
|
83
|
+
|
|
84
|
+
export interface AnimationClipRegistryDiagnostic<TClipId extends string = string> {
|
|
85
|
+
readonly severity: AnimationClipRegistryDiagnosticSeverity;
|
|
86
|
+
readonly code: string;
|
|
87
|
+
readonly message: string;
|
|
88
|
+
readonly clipId?: TClipId;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface AnimationClipManifest<
|
|
92
|
+
TClipId extends string = string,
|
|
93
|
+
TEvent extends AnimationClipEvent = AnimationClipEvent,
|
|
94
|
+
TPose = unknown
|
|
95
|
+
> {
|
|
96
|
+
readonly clips: readonly AnimationClipDefinition<TClipId, TEvent, TPose>[];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export class AnimationClipRegistry<
|
|
100
|
+
TClipId extends string = string,
|
|
101
|
+
TEvent extends AnimationClipEvent = AnimationClipEvent,
|
|
102
|
+
TPose = unknown
|
|
103
|
+
> {
|
|
104
|
+
private readonly clips = new Map<TClipId, RegisteredAnimationClip<TClipId, TEvent, TPose>>();
|
|
105
|
+
private nextRegistryIndex = 0;
|
|
106
|
+
|
|
107
|
+
constructor(
|
|
108
|
+
clips: readonly AnimationClipDefinition<TClipId, TEvent, TPose>[] = [],
|
|
109
|
+
options: AnimationClipRegistryOptions = {}
|
|
110
|
+
) {
|
|
111
|
+
this.registerMany(clips, options);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
static fromManifest<
|
|
115
|
+
TClipId extends string = string,
|
|
116
|
+
TEvent extends AnimationClipEvent = AnimationClipEvent,
|
|
117
|
+
TPose = unknown
|
|
118
|
+
>(
|
|
119
|
+
manifest: AnimationClipManifest<TClipId, TEvent, TPose>,
|
|
120
|
+
options: AnimationClipRegistryOptions = {}
|
|
121
|
+
): AnimationClipRegistry<TClipId, TEvent, TPose> {
|
|
122
|
+
return new AnimationClipRegistry(manifest.clips, options);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
register(
|
|
126
|
+
definition: AnimationClipDefinition<TClipId, TEvent, TPose>,
|
|
127
|
+
options: AnimationClipRegistryOptions = {}
|
|
128
|
+
): RegisteredAnimationClip<TClipId, TEvent, TPose> {
|
|
129
|
+
validateClipDefinition(definition);
|
|
130
|
+
|
|
131
|
+
if (!options.replace && this.clips.has(definition.id)) {
|
|
132
|
+
throw new Error(`Animation clip "${definition.id}" is already registered.`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const registered: RegisteredAnimationClip<TClipId, TEvent, TPose> = {
|
|
136
|
+
...definition,
|
|
137
|
+
duration: sanitizeDuration(definition.duration),
|
|
138
|
+
loop: definition.loop ?? true,
|
|
139
|
+
tags: [...(definition.tags ?? [])],
|
|
140
|
+
tracks: [...(definition.tracks ?? [])],
|
|
141
|
+
events: normalizeClipEvents(definition.events),
|
|
142
|
+
registryIndex: this.nextRegistryIndex
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
this.nextRegistryIndex += 1;
|
|
146
|
+
this.clips.set(registered.id, registered);
|
|
147
|
+
return registered;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
registerMany(
|
|
151
|
+
definitions: readonly AnimationClipDefinition<TClipId, TEvent, TPose>[],
|
|
152
|
+
options: AnimationClipRegistryOptions = {}
|
|
153
|
+
): readonly RegisteredAnimationClip<TClipId, TEvent, TPose>[] {
|
|
154
|
+
return definitions.map((definition) => this.register(definition, options));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
get(id: TClipId): RegisteredAnimationClip<TClipId, TEvent, TPose> | undefined {
|
|
158
|
+
return this.clips.get(id);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
require(id: TClipId): RegisteredAnimationClip<TClipId, TEvent, TPose> {
|
|
162
|
+
const clip = this.get(id);
|
|
163
|
+
if (!clip) {
|
|
164
|
+
throw new Error(`Animation clip "${id}" is not registered.`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return clip;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
has(id: TClipId): boolean {
|
|
171
|
+
return this.clips.has(id);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
remove(id: TClipId): boolean {
|
|
175
|
+
return this.clips.delete(id);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
clear(): void {
|
|
179
|
+
this.clips.clear();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
ids(): readonly TClipId[] {
|
|
183
|
+
return [...this.clips.keys()];
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
list(): readonly RegisteredAnimationClip<TClipId, TEvent, TPose>[] {
|
|
187
|
+
return [...this.clips.values()].sort((a, b) => a.registryIndex - b.registryIndex);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
findByTag(tag: string): readonly RegisteredAnimationClip<TClipId, TEvent, TPose>[] {
|
|
191
|
+
return this.list().filter((clip) => clip.tags.includes(tag));
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
toManifest(): AnimationClipManifest<TClipId, TEvent, TPose> {
|
|
195
|
+
return {
|
|
196
|
+
clips: this.list()
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
diagnose(): readonly AnimationClipRegistryDiagnostic<TClipId>[] {
|
|
201
|
+
const diagnostics: AnimationClipRegistryDiagnostic<TClipId>[] = [];
|
|
202
|
+
|
|
203
|
+
if (this.clips.size === 0) {
|
|
204
|
+
diagnostics.push({
|
|
205
|
+
severity: "warning",
|
|
206
|
+
code: "ANIMATION_REGISTRY_EMPTY",
|
|
207
|
+
message: "No animation clips are registered."
|
|
208
|
+
});
|
|
209
|
+
return diagnostics;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
for (const clip of this.list()) {
|
|
213
|
+
if (clip.duration <= 0) {
|
|
214
|
+
diagnostics.push({
|
|
215
|
+
severity: "error",
|
|
216
|
+
code: "ANIMATION_CLIP_DURATION_INVALID",
|
|
217
|
+
message: `Animation clip "${clip.id}" must have a positive duration.`,
|
|
218
|
+
clipId: clip.id
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (clip.frameRate !== undefined && (!Number.isFinite(clip.frameRate) || clip.frameRate <= 0)) {
|
|
223
|
+
diagnostics.push({
|
|
224
|
+
severity: "warning",
|
|
225
|
+
code: "ANIMATION_CLIP_FRAME_RATE_INVALID",
|
|
226
|
+
message: `Animation clip "${clip.id}" has an invalid frame rate.`,
|
|
227
|
+
clipId: clip.id
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (clip.tracks.length === 0 && !clip.sample) {
|
|
232
|
+
diagnostics.push({
|
|
233
|
+
severity: "info",
|
|
234
|
+
code: "ANIMATION_CLIP_NO_SAMPLE_SOURCE",
|
|
235
|
+
message: `Animation clip "${clip.id}" has no tracks or sampler. capturePose() will return an empty pose for it.`,
|
|
236
|
+
clipId: clip.id
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
for (const event of clip.events) {
|
|
241
|
+
if (!Number.isFinite(event.time) || event.time < 0 || event.time > clip.duration) {
|
|
242
|
+
diagnostics.push({
|
|
243
|
+
severity: "warning",
|
|
244
|
+
code: "ANIMATION_CLIP_EVENT_TIME_OUT_OF_RANGE",
|
|
245
|
+
message: `Animation event "${event.name}" is outside the duration of clip "${clip.id}".`,
|
|
246
|
+
clipId: clip.id
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return diagnostics;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export function createAnimationClipRegistry<
|
|
257
|
+
TClipId extends string = string,
|
|
258
|
+
TEvent extends AnimationClipEvent = AnimationClipEvent,
|
|
259
|
+
TPose = unknown
|
|
260
|
+
>(
|
|
261
|
+
clips: readonly AnimationClipDefinition<TClipId, TEvent, TPose>[] = [],
|
|
262
|
+
options: AnimationClipRegistryOptions = {}
|
|
263
|
+
): AnimationClipRegistry<TClipId, TEvent, TPose> {
|
|
264
|
+
return new AnimationClipRegistry(clips, options);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function validateClipDefinition(definition: AnimationClipDefinition): void {
|
|
268
|
+
if (!definition.id) {
|
|
269
|
+
throw new Error("Animation clips must have a stable id.");
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (!Number.isFinite(definition.duration) || definition.duration < 0) {
|
|
273
|
+
throw new Error(`Animation clip "${definition.id}" has an invalid duration.`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function sanitizeDuration(duration: number): number {
|
|
278
|
+
if (!Number.isFinite(duration) || duration < 0) return 0;
|
|
279
|
+
return duration;
|
|
280
|
+
}
|