@lovelace_lol/embody 0.0.8 → 0.0.9

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.
@@ -45,6 +45,7 @@ export declare class DPthreeCameraController {
45
45
  private markerStateListeners;
46
46
  private domElement;
47
47
  private renderer;
48
+ private readonly playbackTimer;
48
49
  private renderFrame;
49
50
  private resizeRenderer;
50
51
  private onRenderError;
@@ -0,0 +1,95 @@
1
+ import type { AnimationClip, Mesh, Object3D } from 'three';
2
+ import type { GLTF } from 'three/examples/jsm/loaders/GLTFLoader.js';
3
+ import type { Region } from './annotations/types';
4
+ import type * as Types from './authoringTypes';
5
+ export * from './authoringTypes';
6
+ export { resolveBoneNames, fuzzyNameMatch } from './annotations/adapter';
7
+ export { DEFAULT_AXIS_TO_CHANNEL, DEFAULT_BONE_MAX_DEGREES, JOINT_CONTROL_SECTION, VISEME_KEYS, HAIR_COLOR_PRESETS, DEFAULT_HAIR_COLOR_APPEARANCE, HUMANOID_SKELETON_TEMPLATES, CC4_HUMANOID_SKELETON_TEMPLATE, } from '@lovelace_lol/embody/wasm';
8
+ export declare const getPreset: (id: Types.PresetType) => Types.Profile;
9
+ export declare const extendCharacterConfigWithPreset: <T extends Types.ProfileRuntimeConfig>(config: T) => T;
10
+ export declare const extractProfileOverrides: (config: Types.ProfileRuntimeConfig) => Partial<Types.Profile>;
11
+ export declare const mergeCharacterRegionsByName: (base?: Region[], override?: Region[]) => Region[];
12
+ export declare const getMeshNamesForAUProfile: (profile: Types.Profile, auId: number) => string[];
13
+ export declare const getHumanoidSpecification: () => Types.HumanoidSpecification;
14
+ export declare const setAUMorphTargets: (profile: Types.Profile, auId: number, side: "left" | "right" | "center", targets: Types.MorphTargetRef[]) => Types.Profile;
15
+ export declare const setHumanoidRoleBinding: (profile: Types.Profile, role: Types.VRMHumanoidRole, boneName: string | null) => Types.Profile;
16
+ export declare const resolveHumanoidCharacterization: (profile: Types.Profile) => Types.HumanoidCharacterizationResolution;
17
+ export declare const hasLeftRightMorphs: (profile: Types.Profile, auId: number) => boolean;
18
+ export declare const isMixedAU: (profile: Types.Profile, auId: number) => boolean;
19
+ export declare const resolveVisemeProfile: (profile: Partial<Types.Profile>) => Types.ResolvedVisemeProfile;
20
+ export declare const isMaxDegreesOnlyAxisBindingUpdate: (update: Types.BoneAxisBindingUpdate) => boolean;
21
+ export declare const findNodeKeyForBone: (boneName: string, profile: Types.Profile | null) => string | null;
22
+ export declare const ensureBoneNodeKey: (profile: Types.Profile, boneName: string) => {
23
+ nodeKey: string;
24
+ boneNodes: Record<string, string>;
25
+ };
26
+ export declare const ensureBilateralBoneNodeKeys: (profile: Types.Profile, leftBoneName: string, rightBoneName: string) => Types.Profile;
27
+ export declare const resolveBoneNameForNodeKey: (profile: Types.Profile, nodeKey: string) => string | null;
28
+ export declare const stripConfiguredBoneAffixes: (profile: Pick<Types.Profile, "bonePrefix" | "boneSuffix"> | null | undefined, boneName: string) => string;
29
+ export declare const inferChiralBoneNamePair: (boneNames: string[], selectedBoneName: string) => Types.ChiralBoneNamePair | null;
30
+ export declare const formatAxisLabel: (axis: Types.BoneAxisKey) => string;
31
+ export declare const formatAxisDirectionLabel: (axis: Types.BoneAxisKey, direction: Types.BoneAxisDirection) => string;
32
+ export declare const getAxisFromChannel: (channel?: string) => Types.BoneAxisKey | null;
33
+ export declare const getBoneAxisBindingState: (profile: Types.Profile, boneName: string, axis: Types.BoneAxisKey) => Types.BoneAxisBindingState | null;
34
+ export declare const resolveBoneAxisChannel: (profile: Types.Profile, boneName: string, axis: Types.BoneAxisKey) => Types.RotationChannel;
35
+ export declare const getBilateralAxisBindingState: (profile: Types.Profile, boneName: string, axis: Types.BoneAxisKey) => Types.BilateralAxisBindingState | null;
36
+ export declare const getAUBoneBindingState: (profile: Types.Profile, auId: number) => Types.AUBoneBindingState;
37
+ export declare const inferEyeControlScope: (profile: Pick<Types.Profile, "auToBones">, binding: Pick<Types.BoneAxisBindingState, "nodeKey" | "negativeAuId" | "positiveAuId">) => Types.BoneControlScope | null;
38
+ export declare const inferEyeControlFamily: (binding: Pick<Types.BoneAxisBindingState, "nodeKey" | "axis">) => Types.BoneControlFamily | null;
39
+ export declare const applyBoneAxisBindingUpdate: (profile: Types.Profile, boneName: string, axis: Types.BoneAxisKey, update: Types.BoneAxisBindingUpdate) => Types.Profile;
40
+ export declare const applyBilateralAxisBindingUpdate: (profile: Types.Profile, boneName: string, axis: Types.BoneAxisKey, scope: Types.BilateralBoneAxisScope, update: Types.BoneAxisBindingUpdate) => Types.Profile;
41
+ export declare const applyAUBoneBindingUpdate: (profile: Types.Profile, auId: number, update: {
42
+ boneName: string | null;
43
+ axis: Types.BoneAxisKey;
44
+ direction: Types.BoneAxisDirection;
45
+ maxDegrees: number | null;
46
+ }) => Types.Profile;
47
+ export declare const createBoneAxisAu: (profile: Types.Profile, boneName: string, axis: Types.BoneAxisKey, direction: Types.BoneAxisDirection, options?: {
48
+ name?: string;
49
+ }) => Types.CreatedBoneAxisAu;
50
+ export declare const createBilateralBoneAxisAu: (profile: Types.Profile, boneName: string, axis: Types.BoneAxisKey, scope: Types.BilateralBoneAxisScope, direction: Types.BoneAxisDirection, options?: {
51
+ name?: string;
52
+ }) => Types.CreatedBoneAxisAu;
53
+ export declare const buildBoneAuOptions: (profile: Types.Profile) => Array<{
54
+ value: string;
55
+ label: string;
56
+ detail?: string;
57
+ }>;
58
+ export declare const isJointControlAuInfo: (info?: Pick<Types.AUInfo, "facePart"> | null) => boolean;
59
+ export declare const classifyAuAsJointControl: (profile: Types.Profile, auId: number, options?: {
60
+ boneName?: string | null;
61
+ nodeKey?: string | null;
62
+ }) => Types.Profile;
63
+ export declare const resolveContinuumDisplayLabel: (profile: Pick<Types.Profile, "continuumPairs" | "continuumLabels" | "auInfo" | "boneNodes" | "bonePrefix" | "boneSuffix">, negativeAuId: number, positiveAuId: number) => string;
64
+ export declare function getBodyControls(profile: Types.Profile, model?: Object3D): Types.BodyControlDescriptor[];
65
+ export declare function extractModelData(model: Object3D, meshes?: Mesh[], animations?: AnimationClip[]): Types.ModelData;
66
+ export declare function analyzeModel(options: {
67
+ source: {
68
+ type: 'gltf';
69
+ gltf: GLTF;
70
+ } | {
71
+ type: 'runtime';
72
+ model: Object3D;
73
+ meshes?: Mesh[];
74
+ animations?: AnimationClip[];
75
+ };
76
+ preset?: Types.Profile;
77
+ suggestCorrections?: boolean;
78
+ }): Promise<Types.ModelAnalysisReport>;
79
+ export declare function validateMappings(meshes: unknown[], skeleton: unknown, profile: Types.Profile, options?: Record<string, unknown>): Types.ValidationResult;
80
+ export declare function validateHumanoidCharacterization(model: Object3D, profile: Types.Profile): Types.HumanoidCharacterizationResolution;
81
+ export declare function normalizeHairColorAppearance(value: Types.HairColorAppearance | string, fallback?: Types.HairColorAppearance): Types.HairColorAppearance;
82
+ export declare const getHumanoidSkeletonTemplate: (id: string) => Types.HumanoidSkeletonTemplate | null;
83
+ export declare function getHumanoidSkeletonTemplateBoneNames(template?: Types.HumanoidSkeletonTemplate): string[];
84
+ export declare function createValidationSkeletonFromHumanoidTemplate(template?: Types.HumanoidSkeletonTemplate): {
85
+ bones: Array<{
86
+ name: string;
87
+ }>;
88
+ };
89
+ export declare function computeHumanoidSkeletonTemplateRestBounds(template: Types.HumanoidSkeletonTemplate): Types.HumanoidSkeletonTemplateBounds;
90
+ export declare function extractHumanoidSkeletonTemplateFromModel(model: Object3D, options: {
91
+ id: string;
92
+ sourceCharacterId: string;
93
+ sourceAsset?: string;
94
+ sourceSkinName?: string;
95
+ }): Types.HumanoidSkeletonTemplate;
@@ -0,0 +1,576 @@
1
+ import type { Region, MarkerStyle, MarkerGroup, LineConfig, MarkerStyleOverrides } from './annotations/types';
2
+ export interface AuthoringVector3 {
3
+ x: number;
4
+ y: number;
5
+ z: number;
6
+ }
7
+ export interface AuthoringQuaternion extends AuthoringVector3 {
8
+ w: number;
9
+ }
10
+ export type PresetType = 'cc4' | 'fish' | string;
11
+ export type BoneAxisKey = 'pitch' | 'yaw' | 'roll';
12
+ export type BoneAxisDirection = 'negative' | 'positive';
13
+ export type BoneAxisDirectionScale = -1 | 1;
14
+ export type RotationChannel = 'rx' | 'ry' | 'rz';
15
+ export type BilateralBoneAxisScope = 'shared' | 'left' | 'right';
16
+ export type BoneControlFamily = 'Horizontal Gaze' | 'Vertical Gaze';
17
+ export type BoneControlScope = 'Both Eyes' | 'Left Eye Only' | 'Right Eye Only';
18
+ export type HumanoidSkeletonTemplateVec3 = readonly [number, number, number];
19
+ export type HumanoidSkeletonTemplateBounds = readonly [number, number, number, number, number, number];
20
+ export type MorphTargetRef = string | number;
21
+ export type MeshCategory = 'body' | 'eye' | 'eyeOcclusion' | 'tearLine' | 'teeth' | 'tongue' | 'hair' | 'eyebrow' | 'cornea' | 'eyelash';
22
+ export type BlendingMode = 'Normal' | 'Additive' | 'Subtractive' | 'Multiply' | 'None';
23
+ export interface MorphTargetsBySide {
24
+ left: MorphTargetRef[];
25
+ right: MorphTargetRef[];
26
+ center: MorphTargetRef[];
27
+ }
28
+ export interface BoneBinding {
29
+ node: string;
30
+ channel: 'rx' | 'ry' | 'rz' | 'tx' | 'ty' | 'tz';
31
+ scale: BoneAxisDirectionScale;
32
+ maxDegrees?: number;
33
+ maxUnits?: number;
34
+ side?: 'left' | 'right';
35
+ }
36
+ export interface AUInfo {
37
+ id: string;
38
+ name: string;
39
+ muscularBasis?: string;
40
+ links?: string[];
41
+ faceArea?: 'Upper' | 'Lower' | 'Body';
42
+ facePart?: string;
43
+ }
44
+ export interface RotationAxis {
45
+ aus: number[];
46
+ axis: RotationChannel;
47
+ negative?: number | number[];
48
+ positive?: number | number[];
49
+ }
50
+ export interface CompositeRotation {
51
+ node: string;
52
+ pitch: RotationAxis | null;
53
+ yaw: RotationAxis | null;
54
+ roll: RotationAxis | null;
55
+ }
56
+ export interface VisemeSlotFeatures {
57
+ jawOpen?: number;
58
+ lipClosed?: number;
59
+ lipRound?: number;
60
+ lipSpread?: number;
61
+ tongueTip?: number;
62
+ fricative?: number;
63
+ nasal?: number;
64
+ }
65
+ export interface VisemeSlot {
66
+ id: string;
67
+ label: string;
68
+ order?: number;
69
+ providerIds?: Record<string, Array<string | number>>;
70
+ phonemes?: string[];
71
+ matchers?: string[];
72
+ features?: VisemeSlotFeatures;
73
+ defaultJawAmount?: number;
74
+ }
75
+ export type VisemeTongueTarget = Record<string, number>;
76
+ export interface VisemeBindingTarget {
77
+ morph: MorphTargetRef;
78
+ weight?: number;
79
+ }
80
+ export interface VisemeBinding {
81
+ targets?: VisemeBindingTarget[];
82
+ morph?: MorphTargetRef;
83
+ jawAmount?: number;
84
+ note?: string;
85
+ sharedWith?: string[];
86
+ }
87
+ export interface ResolvedVisemeSlot extends Omit<VisemeSlot, 'label'> {
88
+ label?: string;
89
+ [extension: string]: unknown;
90
+ }
91
+ /** Model-independent authored resolution. Array indices equal Embody runtime slot indices. */
92
+ export interface ResolvedVisemeProfile {
93
+ routingMode: 'explicit' | 'legacy';
94
+ /** Stock canonical sound index to runtime slot index, including reordered stock profiles. */
95
+ canonicalSlotIndices?: number[];
96
+ visemeSlots: ResolvedVisemeSlot[];
97
+ visemeBindingTargets: Array<Array<Required<VisemeBindingTarget>>>;
98
+ visemeJawAmounts: number[];
99
+ visemeTongueTargets: VisemeTongueTarget[];
100
+ visemeMeshNames: string[];
101
+ visemeMeshCategory: string;
102
+ }
103
+ export interface MappingEditorSection {
104
+ id: string;
105
+ label: string;
106
+ kind: 'au' | 'viseme' | 'lipSync' | 'hair' | 'unmapped' | 'custom';
107
+ order: number;
108
+ meshCategory?: string;
109
+ facePart?: string;
110
+ }
111
+ export interface MeshMaterialSettings {
112
+ renderOrder?: number;
113
+ transparent?: boolean;
114
+ opacity?: number;
115
+ depthWrite?: boolean;
116
+ depthTest?: boolean;
117
+ blending?: BlendingMode;
118
+ }
119
+ export interface MeshInfo {
120
+ name?: string;
121
+ visible?: boolean;
122
+ category: MeshCategory;
123
+ morphCount: number;
124
+ material?: MeshMaterialSettings;
125
+ }
126
+ export type HairMorphAxis = 'yaw' | 'pitch' | 'roll';
127
+ export interface HairMorphTargetMapping {
128
+ key: string;
129
+ axis: HairMorphAxis;
130
+ }
131
+ export interface HairMorphTargetValueMapping {
132
+ value: number;
133
+ axis: HairMorphAxis;
134
+ }
135
+ export interface HairPhysicsProfileConfig {
136
+ enabled?: boolean;
137
+ stiffness?: number;
138
+ damping?: number;
139
+ inertia?: number;
140
+ gravity?: number;
141
+ responseScale?: number;
142
+ idleSwayAmount?: number;
143
+ idleSwaySpeed?: number;
144
+ windStrength?: number;
145
+ windDirectionX?: number;
146
+ windDirectionZ?: number;
147
+ windTurbulence?: number;
148
+ windFrequency?: number;
149
+ idleClipDuration?: number;
150
+ impulseClipDuration?: number;
151
+ direction?: {
152
+ yawSign?: 1 | -1;
153
+ pitchSign?: 1 | -1;
154
+ };
155
+ morphTargets?: {
156
+ swayLeft?: HairMorphTargetMapping | null;
157
+ swayRight?: HairMorphTargetMapping | null;
158
+ swayFront?: HairMorphTargetMapping | null;
159
+ fluffRight?: HairMorphTargetMapping | null;
160
+ fluffBottom?: HairMorphTargetMapping | null;
161
+ headUp?: Record<string, HairMorphTargetValueMapping | null> | null;
162
+ headDown?: Record<string, HairMorphTargetValueMapping | null> | null;
163
+ } | null;
164
+ }
165
+ export type VRMHumanoidRole = 'hips' | 'spine' | 'chest' | 'upperChest' | 'neck' | 'head' | 'leftEye' | 'rightEye' | 'jaw' | 'leftShoulder' | 'leftUpperArm' | 'leftLowerArm' | 'leftHand' | 'rightShoulder' | 'rightUpperArm' | 'rightLowerArm' | 'rightHand' | 'leftUpperLeg' | 'leftLowerLeg' | 'leftFoot' | 'leftToes' | 'rightUpperLeg' | 'rightLowerLeg' | 'rightFoot' | 'rightToes' | 'leftThumbMetacarpal' | 'leftThumbProximal' | 'leftThumbDistal' | 'rightThumbMetacarpal' | 'rightThumbProximal' | 'rightThumbDistal' | 'leftIndexProximal' | 'leftIndexIntermediate' | 'leftIndexDistal' | 'rightIndexProximal' | 'rightIndexIntermediate' | 'rightIndexDistal' | 'leftMiddleProximal' | 'leftMiddleIntermediate' | 'leftMiddleDistal' | 'rightMiddleProximal' | 'rightMiddleIntermediate' | 'rightMiddleDistal' | 'leftRingProximal' | 'leftRingIntermediate' | 'leftRingDistal' | 'rightRingProximal' | 'rightRingIntermediate' | 'rightRingDistal' | 'leftLittleProximal' | 'leftLittleIntermediate' | 'leftLittleDistal' | 'rightLittleProximal' | 'rightLittleIntermediate' | 'rightLittleDistal';
166
+ /** A standard bone role; motion axes/ranges belong to the authored rig profile. */
167
+ export interface HumanoidBoneDefinition {
168
+ role: VRMHumanoidRole;
169
+ label: string;
170
+ section: 'Torso' | 'Head' | 'Arms' | 'Hands' | 'Legs' | 'Feet';
171
+ parent: VRMHumanoidRole | null;
172
+ required: boolean;
173
+ /** This optional parent must be mapped when the child is mapped. */
174
+ requiresParent: boolean;
175
+ }
176
+ export interface HumanoidSpecification {
177
+ standard: 'VRMC_vrm-1.0';
178
+ bones: HumanoidBoneDefinition[];
179
+ }
180
+ export interface HumanoidRoleBinding {
181
+ nodeKey: string;
182
+ /** Literal model bone selected by the role editor, before preset prefix lookup. */
183
+ exactBoneName?: string;
184
+ source?: string;
185
+ confidence?: number;
186
+ }
187
+ export interface HumanoidCharacterization {
188
+ schemaVersion: 1;
189
+ standard: 'VRMC_vrm-1.0';
190
+ status: 'verified-vrm' | 'characterized' | 'incomplete';
191
+ /** Explicitly edited role catalogs are authoritative across preset upgrades. */
192
+ authored?: boolean;
193
+ roles: Partial<Record<VRMHumanoidRole, HumanoidRoleBinding>>;
194
+ }
195
+ export interface HumanoidCharacterizationResolution {
196
+ schemaVersion: number | null;
197
+ standard: string | null;
198
+ status: string | null;
199
+ roles: Record<string, {
200
+ nodeKey: string;
201
+ boneName: string;
202
+ source: string | null;
203
+ confidence: number | null;
204
+ }>;
205
+ missingRequiredRoles: string[];
206
+ errors: string[];
207
+ warnings: string[];
208
+ valid: boolean;
209
+ }
210
+ /** Semantic body actions reuse the AU bone/morph evaluator. VRM names identify targets. */
211
+ export interface BodyControlDefinition {
212
+ label: string;
213
+ section: string;
214
+ auId: number;
215
+ negativeAuId?: number | null;
216
+ bilateral: boolean;
217
+ roles: VRMHumanoidRole[];
218
+ order?: number;
219
+ }
220
+ export interface BodyControlDescriptor {
221
+ id: string;
222
+ label: string;
223
+ section: string;
224
+ auId: number;
225
+ negativeAuId: number | null;
226
+ auIds: number[];
227
+ bilateral: boolean;
228
+ roles: VRMHumanoidRole[];
229
+ order: number;
230
+ boneBindings: Array<BoneBinding & {
231
+ auId: number;
232
+ boneName: string;
233
+ }>;
234
+ morphBindings: MorphTargetsBySide;
235
+ meshNames: string[];
236
+ hasBones: boolean;
237
+ hasMorphs: boolean;
238
+ isMixed: boolean;
239
+ available: boolean;
240
+ diagnostics: string[];
241
+ }
242
+ /** Pose values are normalized authored action amounts, never world Euler angles. */
243
+ export interface SemanticPoseChannel {
244
+ intensity: number;
245
+ /** -1 = character's left, 0 = both, +1 = character's right. */
246
+ balance?: number;
247
+ /** Morph contribution only; bone activation remains intensity. Defaults to profile. */
248
+ morphStrength?: number;
249
+ }
250
+ export interface SemanticPose {
251
+ version: 1;
252
+ controls: Array<{
253
+ controlId: string;
254
+ positive?: SemanticPoseChannel;
255
+ negative?: SemanticPoseChannel;
256
+ }>;
257
+ }
258
+ export interface SemanticPoseDirection {
259
+ auId: number;
260
+ label: string;
261
+ available: boolean;
262
+ availableSides?: Array<'left' | 'right' | 'center'>;
263
+ hasBones: boolean;
264
+ hasMorphs: boolean;
265
+ morphStrength: number;
266
+ }
267
+ export interface SemanticPoseControl {
268
+ id: string;
269
+ label: string;
270
+ section: string;
271
+ roles: string[];
272
+ bilateral: boolean;
273
+ boneNames: string[];
274
+ morphNames: string[];
275
+ positive: SemanticPoseDirection;
276
+ negative?: SemanticPoseDirection;
277
+ }
278
+ export interface SemanticAnimation {
279
+ version: 1;
280
+ durationSeconds: number;
281
+ tracks: Array<{
282
+ controlId: string;
283
+ direction: 'positive' | 'negative';
284
+ balance?: number;
285
+ morphStrength?: number;
286
+ keyframes: Array<{
287
+ time: number;
288
+ intensity: number;
289
+ }>;
290
+ }>;
291
+ }
292
+ export interface SemanticAnimationOptions extends Record<string, unknown> {
293
+ faceCurves?: Record<string, Array<{
294
+ time: number;
295
+ intensity: number;
296
+ inherit?: boolean;
297
+ }>>;
298
+ }
299
+ export interface Profile {
300
+ name?: string;
301
+ animalType?: string;
302
+ emoji?: string;
303
+ auToMorphs: Record<number, MorphTargetsBySide>;
304
+ auToBones: Record<number, BoneBinding[]>;
305
+ boneNodes: Record<string, string>;
306
+ bonePrefix?: string;
307
+ boneSuffix?: string;
308
+ morphPrefix?: string;
309
+ morphSuffix?: string;
310
+ suffixPattern?: string;
311
+ leftMorphSuffixes?: string[];
312
+ rightMorphSuffixes?: string[];
313
+ morphToMesh: Record<string, string[]>;
314
+ auFacePartToMeshCategory?: Record<string, string>;
315
+ mappingSections?: MappingEditorSection[];
316
+ visemeKeys: MorphTargetRef[];
317
+ visemeSystemId?: string;
318
+ visemeSlots?: VisemeSlot[];
319
+ visemeBindings?: Record<string, VisemeBinding>;
320
+ visemeMeshCategory?: string;
321
+ visemeJawAmounts?: number[];
322
+ /** Per-viseme tongue AU targets in canonical slot order. */
323
+ visemeTongueTargets?: VisemeTongueTarget[];
324
+ auMixDefaults?: Record<number, number>;
325
+ auInfo?: Record<string, AUInfo>;
326
+ eyeMeshNodes?: {
327
+ LEFT: string;
328
+ RIGHT: string;
329
+ };
330
+ compositeRotations?: CompositeRotation[];
331
+ meshes?: Record<string, MeshInfo>;
332
+ continuumPairs?: Record<number, {
333
+ pairId: number;
334
+ isNegative: boolean;
335
+ axis: BoneAxisKey;
336
+ node: string;
337
+ }>;
338
+ continuumLabels?: Record<string, string>;
339
+ annotationRegions?: Region[];
340
+ disabledRegions?: string[];
341
+ hairPhysics?: HairPhysicsProfileConfig;
342
+ humanoidCharacterization?: HumanoidCharacterization;
343
+ /** Authored overrides may patch individual fields; null removes a preset control. */
344
+ bodyControls?: Record<string, Partial<BodyControlDefinition> | null>;
345
+ }
346
+ export interface ProfileRuntimeConfig extends Partial<Profile> {
347
+ profilePresetId?: PresetType;
348
+ presetId?: PresetType;
349
+ baseProfileId?: PresetType;
350
+ auPresetType?: PresetType;
351
+ profile?: Partial<Profile>;
352
+ defaultRegion?: string;
353
+ regions?: Region[];
354
+ markerStyle?: MarkerStyle;
355
+ playIntroOnLoad?: boolean;
356
+ modelOffset?: {
357
+ x?: number;
358
+ y?: number;
359
+ z?: number;
360
+ };
361
+ modelRotation?: {
362
+ x?: number;
363
+ y?: number;
364
+ z?: number;
365
+ };
366
+ modelScale?: number;
367
+ modelGroundClearance?: number;
368
+ deletedBakedAnimationClips?: string[];
369
+ markerGroups?: MarkerGroup[];
370
+ lineDefaults?: LineConfig;
371
+ markerDefaults?: Partial<MarkerStyleOverrides>;
372
+ }
373
+ export interface CharacterProfile extends ProfileRuntimeConfig {
374
+ characterId?: string;
375
+ characterName?: string;
376
+ modelPath?: string;
377
+ }
378
+ export type CharacterConfig = CharacterProfile & {
379
+ characterId: string;
380
+ characterName: string;
381
+ modelPath: string;
382
+ regions: Region[];
383
+ };
384
+ export interface HairColorAppearance {
385
+ name: string;
386
+ baseColor: string;
387
+ emissive: string;
388
+ emissiveIntensity: number;
389
+ }
390
+ export interface HairAppearanceState {
391
+ hairColor: HairColorAppearance;
392
+ eyebrowColor: HairColorAppearance;
393
+ showOutline: boolean;
394
+ outlineColor: string;
395
+ outlineOpacity: number;
396
+ }
397
+ export interface HairPhysicsRuntimeConfig {
398
+ enabled: boolean;
399
+ [key: string]: any;
400
+ }
401
+ export type HairPhysicsRuntimeConfigUpdate = Partial<HairPhysicsRuntimeConfig>;
402
+ export interface TransitionHandle {
403
+ promise: Promise<void>;
404
+ pause(): void;
405
+ resume(): void;
406
+ cancel(): void;
407
+ }
408
+ export interface BoneAxisBindingUpdate {
409
+ channel?: RotationChannel;
410
+ positiveAuId?: number | null;
411
+ negativeAuId?: number | null;
412
+ positiveMaxDegrees?: number | null;
413
+ negativeMaxDegrees?: number | null;
414
+ positiveScale?: BoneAxisDirectionScale | null;
415
+ negativeScale?: BoneAxisDirectionScale | null;
416
+ positiveLeftScale?: BoneAxisDirectionScale | null;
417
+ positiveRightScale?: BoneAxisDirectionScale | null;
418
+ negativeLeftScale?: BoneAxisDirectionScale | null;
419
+ negativeRightScale?: BoneAxisDirectionScale | null;
420
+ }
421
+ export interface BoneAxisBindingState {
422
+ axis: BoneAxisKey;
423
+ channel: RotationChannel;
424
+ nodeKey: string;
425
+ positiveAuId: number | null;
426
+ negativeAuId: number | null;
427
+ positiveMaxDegrees: number | null;
428
+ negativeMaxDegrees: number | null;
429
+ positiveScale: BoneAxisDirectionScale | null;
430
+ negativeScale: BoneAxisDirectionScale | null;
431
+ }
432
+ export interface AUBoneBindingState {
433
+ auId: number;
434
+ boneName: string | null;
435
+ nodeKey: string | null;
436
+ axis: BoneAxisKey;
437
+ direction: BoneAxisDirection;
438
+ channel: RotationChannel | null;
439
+ maxDegrees: number | null;
440
+ oppositeAuId: number | null;
441
+ oppositeMaxDegrees: number | null;
442
+ hasBinding: boolean;
443
+ hasMultipleBindings: boolean;
444
+ }
445
+ export interface BilateralAxisDirectionScaleState {
446
+ left: BoneAxisDirectionScale | null;
447
+ right: BoneAxisDirectionScale | null;
448
+ }
449
+ export interface BilateralAxisScopeBindingState {
450
+ scope: BilateralBoneAxisScope;
451
+ label: string;
452
+ negativeAuId: number | null;
453
+ positiveAuId: number | null;
454
+ negativeMaxDegrees: number | null;
455
+ positiveMaxDegrees: number | null;
456
+ negativeScale: BilateralAxisDirectionScaleState;
457
+ positiveScale: BilateralAxisDirectionScaleState;
458
+ }
459
+ export interface BilateralAxisBindingState {
460
+ axis: BoneAxisKey;
461
+ familyLabel: string;
462
+ leftBoneName: string;
463
+ leftNodeKey: string;
464
+ rightBoneName: string;
465
+ rightNodeKey: string;
466
+ selectedSide: 'left' | 'right';
467
+ shared: BilateralAxisScopeBindingState;
468
+ left: BilateralAxisScopeBindingState;
469
+ right: BilateralAxisScopeBindingState;
470
+ }
471
+ export interface ChiralBoneNamePair {
472
+ leftBoneName: string;
473
+ rightBoneName: string;
474
+ selectedSide: 'left' | 'right';
475
+ familyLabel: string;
476
+ }
477
+ export interface CreatedBoneAxisAu {
478
+ auId: number;
479
+ profile: Profile;
480
+ }
481
+ export interface BoneInfo {
482
+ name: string;
483
+ parent: string | null;
484
+ children: string[];
485
+ worldPosition: {
486
+ x: number;
487
+ y: number;
488
+ z: number;
489
+ };
490
+ depth: number;
491
+ }
492
+ export interface TrackInfo {
493
+ name: string;
494
+ targetName: string;
495
+ property: string;
496
+ type: string;
497
+ keyframeCount: number;
498
+ valueRange?: {
499
+ min: number[];
500
+ max: number[];
501
+ };
502
+ }
503
+ export interface AnimationInfo {
504
+ name: string;
505
+ duration: number;
506
+ tracks: TrackInfo[];
507
+ animatedBones: string[];
508
+ animatedMorphs: string[];
509
+ }
510
+ export interface ModelData {
511
+ bones: BoneInfo[];
512
+ morphs: Array<{
513
+ name: string;
514
+ meshName: string;
515
+ index: number;
516
+ }>;
517
+ meshes: Array<{
518
+ name: string;
519
+ hasMorphTargets: boolean;
520
+ morphCount: number;
521
+ }>;
522
+ animations: AnimationInfo[];
523
+ boneNames: string[];
524
+ morphNames: string[];
525
+ meshNames: string[];
526
+ }
527
+ export interface MappingCorrection {
528
+ type: 'bone' | 'morph' | 'viseme' | 'mesh';
529
+ source: string;
530
+ target: string;
531
+ confidence: number;
532
+ reason: string;
533
+ applied: boolean;
534
+ auId?: number;
535
+ key?: string;
536
+ }
537
+ export interface ValidationResult {
538
+ valid: boolean;
539
+ score: number;
540
+ missingMorphs: string[];
541
+ missingBones: string[];
542
+ foundMorphs: string[];
543
+ foundBones: string[];
544
+ unmappedMorphs: string[];
545
+ unmappedBones: string[];
546
+ missingMeshes: string[];
547
+ foundMeshes: string[];
548
+ unmappedMeshes: string[];
549
+ warnings: string[];
550
+ suggestedConfig?: Profile;
551
+ corrections?: MappingCorrection[];
552
+ unresolved?: MappingCorrection[];
553
+ }
554
+ export interface ModelAnalysisReport {
555
+ model: ModelData;
556
+ validation?: ValidationResult;
557
+ animations: {
558
+ count: number;
559
+ hasIdleCandidate: boolean;
560
+ clips: unknown[];
561
+ };
562
+ overallScore: number;
563
+ summary: string;
564
+ }
565
+ export interface HumanoidSkeletonTemplateBone {
566
+ readonly name: string;
567
+ readonly parent: string | null;
568
+ readonly translation: HumanoidSkeletonTemplateVec3;
569
+ }
570
+ export interface HumanoidSkeletonTemplate {
571
+ readonly id: string;
572
+ readonly sourceCharacterId: string;
573
+ readonly sourceAsset: string;
574
+ readonly sourceSkinName: string;
575
+ readonly bones: readonly HumanoidSkeletonTemplateBone[];
576
+ }