@lovelace_lol/embody 0.0.15 → 0.0.16

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.
@@ -1,5 +1,6 @@
1
1
  import * as THREE from 'three';
2
2
  import type { NativeAnnotationRuntime } from './runtime';
3
+ export { readAttribute } from './morphGeometry';
3
4
  type Bounds = {
4
5
  min: number[];
5
6
  max: number[];
@@ -20,25 +21,26 @@ export interface AnnotationModelObservation {
20
21
  morphNames: string[];
21
22
  }[];
22
23
  }
23
- export declare function readAttribute(attribute: THREE.BufferAttribute | THREE.InterleavedBufferAttribute): Float32Array;
24
24
  /** Stable native handle table. No region matching or anchor policy lives here. */
25
25
  export declare class AnnotationModelObserver {
26
26
  readonly model: THREE.Object3D;
27
27
  readonly objects: Map<number, THREE.Object3D<THREE.Object3DEventMap>>;
28
28
  readonly meshes: THREE.Mesh[];
29
29
  private readonly ids;
30
+ private morphGeneration;
31
+ private morphObservations;
32
+ private readonly morphGeometry;
33
+ private readonly vertex;
30
34
  constructor(model: THREE.Object3D);
31
35
  id(object: THREE.Object3D): number | undefined;
36
+ private updateWorldMatrices;
32
37
  capture(): AnnotationModelObservation;
33
38
  observe(runtime: NativeAnnotationRuntime): void;
34
39
  transforms(runtime: NativeAnnotationRuntime): Float32Array;
35
- morphAnchors(runtime: NativeAnnotationRuntime): Record<string, {
36
- x: number;
37
- y: number;
38
- z: number;
39
- }>;
40
+ private prepareMorphAnchors;
41
+ /** Transport only: Rust owns the vertex selection, weights and live anchor. */
42
+ observeMorphAnchors(runtime: NativeAnnotationRuntime): void;
40
43
  /** Rust selects influenced vertices; Three evaluates the current native pose. */
41
44
  observeFocus(runtime: NativeAnnotationRuntime, request: unknown): void;
42
45
  }
43
46
  export declare function observeAnnotationModel(model: THREE.Object3D): AnnotationModelObservation;
44
- export {};
@@ -0,0 +1,19 @@
1
+ import * as THREE from 'three';
2
+ type Attribute = THREE.BufferAttribute | THREE.InterleavedBufferAttribute;
3
+ export declare function readAttribute(attribute: Attribute): Float32Array;
4
+ export declare function readMorphGeometry(mesh: THREE.Mesh, names: string[]): {
5
+ base: Float32Array;
6
+ morphs: Float32Array;
7
+ relative: boolean;
8
+ } | null;
9
+ export declare function updateAnnotationWorldMatrices(model: THREE.Object3D): void;
10
+ export declare function sampleMorphVertices(mesh: THREE.Mesh, indices: ArrayLike<number>, samples: Float32Array, vertex?: THREE.Vector3): void;
11
+ /** Native identities/versions only. Rust decides whether this observation
12
+ * invalidates an attachment and which geometry/vertices are needed next. */
13
+ export declare class MorphGeometryObservation {
14
+ revision: number;
15
+ namesJson: string;
16
+ private signature;
17
+ observe(mesh: THREE.Mesh): void;
18
+ }
19
+ export {};
@@ -9,52 +9,52 @@ export declare const getPreset: (id: Types.PresetType) => Types.Profile;
9
9
  export declare const extendCharacterConfigWithPreset: <T extends Types.ProfileRuntimeConfig>(config: T) => T;
10
10
  export declare const extractProfileOverrides: (config: Types.ProfileRuntimeConfig) => Partial<Types.Profile>;
11
11
  export declare const mergeCharacterRegionsByName: (base?: Region[], override?: Region[]) => Region[];
12
- export declare const getMeshNamesForAUProfile: (profile: Types.Profile, auId: number) => string[];
12
+ export declare const getMeshNamesForAUProfile: (profile: Partial<Types.Profile>, auId: number) => string[];
13
13
  /** Resolve routing and legacy mesh aliases once for an editor inventory. */
14
14
  export declare const resolveMorphMeshSelections: (profile: Partial<Pick<Types.Profile, "morphToMesh" | "visemeMeshCategory">>, categories: string[], availableNames: string[]) => Record<string, Types.MorphMeshSelection>;
15
15
  export declare const getHumanoidSpecification: () => Types.HumanoidSpecification;
16
- export declare const setAUMorphTargets: (profile: Types.Profile, auId: number, side: "left" | "right" | "center", targets: Types.MorphTargetRef[]) => Types.Profile;
17
- export declare const setHumanoidRoleBinding: (profile: Types.Profile, role: Types.VRMHumanoidRole, boneName: string | null) => Types.Profile;
18
- export declare const resolveHumanoidCharacterization: (profile: Types.Profile) => Types.HumanoidCharacterizationResolution;
19
- export declare const hasLeftRightMorphs: (profile: Types.Profile, auId: number) => boolean;
20
- export declare const isMixedAU: (profile: Types.Profile, auId: number) => boolean;
16
+ export declare const setAUMorphTargets: (profile: Types.ProfileInput, auId: number, side: "left" | "right" | "center", targets: Types.MorphTargetRef[]) => Partial<Types.Profile> & Pick<Types.Profile, "auToMorphs">;
17
+ export declare const setHumanoidRoleBinding: (profile: Types.ProfileInput, role: Types.VRMHumanoidRole, boneName: string | null) => Partial<Types.Profile>;
18
+ export declare const resolveHumanoidCharacterization: (profile: Partial<Types.Profile>) => Types.HumanoidCharacterizationResolution;
19
+ export declare const hasLeftRightMorphs: (profile: Partial<Types.Profile>, auId: number) => boolean;
20
+ export declare const isMixedAU: (profile: Partial<Types.Profile>, auId: number) => boolean;
21
21
  export declare const resolveVisemeProfile: (profile: Partial<Types.Profile>) => Types.ResolvedVisemeProfile;
22
22
  export declare const isMaxDegreesOnlyAxisBindingUpdate: (update: Types.BoneAxisBindingUpdate) => boolean;
23
- export declare const findNodeKeyForBone: (boneName: string, profile: Types.Profile | null) => string | null;
23
+ export declare const findNodeKeyForBone: (boneName: string, profile: Partial<Types.Profile> | null) => string | null;
24
24
  export declare const ensureBoneNodeKey: (profile: Types.Profile, boneName: string) => {
25
25
  nodeKey: string;
26
26
  boneNodes: Record<string, string>;
27
27
  };
28
- export declare const ensureBilateralBoneNodeKeys: (profile: Types.Profile, leftBoneName: string, rightBoneName: string) => Types.Profile;
28
+ export declare const ensureBilateralBoneNodeKeys: (profile: Types.ProfileInput, leftBoneName: string, rightBoneName: string) => Partial<Types.Profile>;
29
29
  export declare const resolveBoneNameForNodeKey: (profile: Types.Profile, nodeKey: string) => string | null;
30
30
  export declare const stripConfiguredBoneAffixes: (profile: Pick<Types.Profile, "bonePrefix" | "boneSuffix"> | null | undefined, boneName: string) => string;
31
31
  export declare const inferChiralBoneNamePair: (boneNames: string[], selectedBoneName: string) => Types.ChiralBoneNamePair | null;
32
32
  export declare const formatAxisLabel: (axis: Types.BoneAxisKey) => string;
33
33
  export declare const formatAxisDirectionLabel: (axis: Types.BoneAxisKey, direction: Types.BoneAxisDirection) => string;
34
34
  export declare const getAxisFromChannel: (channel?: string) => Types.BoneAxisKey | null;
35
- export declare const getBoneAxisBindingState: (profile: Types.Profile, boneName: string, axis: Types.BoneAxisKey) => Types.BoneAxisBindingState | null;
35
+ export declare const getBoneAxisBindingState: (profile: Partial<Types.Profile>, boneName: string, axis: Types.BoneAxisKey) => Types.BoneAxisBindingState | null;
36
36
  export declare const resolveBoneAxisChannel: (profile: Types.Profile, boneName: string, axis: Types.BoneAxisKey) => Types.RotationChannel;
37
- export declare const getBilateralAxisBindingState: (profile: Types.Profile, boneName: string, axis: Types.BoneAxisKey) => Types.BilateralAxisBindingState | null;
38
- export declare const getAUBoneBindingState: (profile: Types.Profile, auId: number) => Types.AUBoneBindingState;
37
+ export declare const getBilateralAxisBindingState: (profile: Partial<Types.Profile>, boneName: string, axis: Types.BoneAxisKey) => Types.BilateralAxisBindingState | null;
38
+ export declare const getAUBoneBindingState: (profile: Partial<Types.Profile>, auId: number) => Types.AUBoneBindingState;
39
39
  /** Resolve a panel's bone links without repeatedly serializing its full character. */
40
40
  export declare const getAUBoneBindingStates: (profile: Partial<Pick<Types.Profile, "auToBones" | "boneNodes" | "bonePrefix" | "boneSuffix" | "suffixPattern" | "compositeRotations" | "continuumPairs" | "humanoidCharacterization">>, auIds: readonly number[]) => Record<number, Types.AUBoneBindingState>;
41
41
  export declare const inferEyeControlScope: (profile: Pick<Types.Profile, "auToBones">, binding: Pick<Types.BoneAxisBindingState, "nodeKey" | "negativeAuId" | "positiveAuId">) => Types.BoneControlScope | null;
42
42
  export declare const inferEyeControlFamily: (binding: Pick<Types.BoneAxisBindingState, "nodeKey" | "axis">) => Types.BoneControlFamily | null;
43
- export declare const applyBoneAxisBindingUpdate: (profile: Types.Profile, boneName: string, axis: Types.BoneAxisKey, update: Types.BoneAxisBindingUpdate) => Types.Profile;
44
- export declare const applyBilateralAxisBindingUpdate: (profile: Types.Profile, boneName: string, axis: Types.BoneAxisKey, scope: Types.BilateralBoneAxisScope, update: Types.BoneAxisBindingUpdate) => Types.Profile;
43
+ export declare const applyBoneAxisBindingUpdate: (profile: Types.ProfileInput, boneName: string, axis: Types.BoneAxisKey, update: Types.BoneAxisBindingUpdate) => Partial<Types.Profile>;
44
+ export declare const applyBilateralAxisBindingUpdate: (profile: Types.ProfileInput, boneName: string, axis: Types.BoneAxisKey, scope: Types.BilateralBoneAxisScope, update: Types.BoneAxisBindingUpdate) => Partial<Types.Profile>;
45
45
  export declare const applyAUBoneBindingUpdate: (profile: Types.Profile, auId: number, update: {
46
46
  boneName: string | null;
47
47
  axis: Types.BoneAxisKey;
48
48
  direction: Types.BoneAxisDirection;
49
49
  maxDegrees: number | null;
50
50
  }) => Types.Profile;
51
- export declare const createBoneAxisAu: (profile: Types.Profile, boneName: string, axis: Types.BoneAxisKey, direction: Types.BoneAxisDirection, options?: {
51
+ export declare const createBoneAxisAu: (profile: Types.ProfileInput, boneName: string, axis: Types.BoneAxisKey, direction: Types.BoneAxisDirection, options?: {
52
52
  name?: string;
53
53
  }) => Types.CreatedBoneAxisAu;
54
- export declare const createBilateralBoneAxisAu: (profile: Types.Profile, boneName: string, axis: Types.BoneAxisKey, scope: Types.BilateralBoneAxisScope, direction: Types.BoneAxisDirection, options?: {
54
+ export declare const createBilateralBoneAxisAu: (profile: Types.ProfileInput, boneName: string, axis: Types.BoneAxisKey, scope: Types.BilateralBoneAxisScope, direction: Types.BoneAxisDirection, options?: {
55
55
  name?: string;
56
56
  }) => Types.CreatedBoneAxisAu;
57
- export declare const buildBoneAuOptions: (profile: Types.Profile) => Array<{
57
+ export declare const buildBoneAuOptions: (profile: Partial<Types.Profile>) => Array<{
58
58
  value: string;
59
59
  label: string;
60
60
  detail?: string;
@@ -64,7 +64,7 @@ export declare const classifyAuAsJointControl: (profile: Types.Profile, auId: nu
64
64
  boneName?: string | null;
65
65
  nodeKey?: string | null;
66
66
  }) => Types.Profile;
67
- export declare const resolveContinuumDisplayLabel: (profile: Pick<Types.Profile, "continuumPairs" | "continuumLabels" | "auInfo" | "boneNodes" | "bonePrefix" | "boneSuffix">, negativeAuId: number, positiveAuId: number) => string;
67
+ export declare const resolveContinuumDisplayLabel: (profile: Partial<Pick<Types.Profile, "continuumPairs" | "continuumLabels" | "auInfo" | "boneNodes" | "bonePrefix" | "boneSuffix">>, negativeAuId: number, positiveAuId: number) => string;
68
68
  export declare function extractModelData(model: Object3D, meshes?: Mesh[], animations?: AnimationClip[]): Types.ModelData;
69
69
  export declare function analyzeModel(options: {
70
70
  source: {
@@ -80,7 +80,7 @@ export declare function analyzeModel(options: {
80
80
  suggestCorrections?: boolean;
81
81
  }): Promise<Types.ModelAnalysisReport>;
82
82
  export declare function validateMappings(meshes: unknown[], skeleton: unknown, profile: Partial<Types.Profile>, options?: Record<string, unknown>): Types.ValidationResult;
83
- export declare function validateHumanoidCharacterization(model: Object3D, profile: Types.Profile): Types.HumanoidCharacterizationResolution;
83
+ export declare function validateHumanoidCharacterization(model: Object3D, profile: Partial<Types.Profile>): Types.HumanoidCharacterizationResolution;
84
84
  export declare function normalizeHairColorAppearance(value: Types.HairColorAppearance | string, fallback?: Types.HairColorAppearance): Types.HairColorAppearance;
85
85
  export declare const getHumanoidSkeletonTemplate: (id: string) => Types.HumanoidSkeletonTemplate | null;
86
86
  export declare function getHumanoidSkeletonTemplateBoneNames(template?: Types.HumanoidSkeletonTemplate): string[];
@@ -25,7 +25,7 @@ export interface MorphMeshSelection {
25
25
  resolvedNames: string[];
26
26
  unresolvedNames: string[];
27
27
  }
28
- export type MeshCategory = 'body' | 'eye' | 'eyeOcclusion' | 'tearLine' | 'teeth' | 'tongue' | 'hair' | 'eyebrow' | 'cornea' | 'eyelash';
28
+ export type MeshCategory = 'body' | 'eye' | 'eyeOcclusion' | 'tearLine' | 'teeth' | 'tongue' | 'hair' | 'eyebrow' | 'cornea' | 'eyelash' | 'other';
29
29
  export type BlendingMode = 'Normal' | 'Additive' | 'Subtractive' | 'Multiply' | 'None';
30
30
  export interface MorphTargetsBySide {
31
31
  left: MorphTargetRef[];
@@ -123,6 +123,8 @@ export interface MeshMaterialSettings {
123
123
  depthTest?: boolean;
124
124
  blending?: BlendingMode;
125
125
  }
126
+ /** Current values read from a native mesh and its first material. */
127
+ export type ThreeResolvedMaterialConfig = Required<MeshMaterialSettings>;
126
128
  export interface MeshInfo {
127
129
  name?: string;
128
130
  visible?: boolean;
@@ -259,6 +261,8 @@ export interface Profile {
259
261
  hairPhysics?: HairPhysicsProfileConfig;
260
262
  humanoidCharacterization?: HumanoidCharacterization;
261
263
  }
264
+ /** Intake accepts app metadata while keeping the profile's known keys explicit. */
265
+ export type ProfileInput = Partial<Profile> | (Partial<Profile> & Record<string, unknown>);
262
266
  export interface ProfileRuntimeConfig extends Partial<Profile> {
263
267
  profilePresetId?: PresetType;
264
268
  presetId?: PresetType;
@@ -297,6 +301,22 @@ export type CharacterConfig = CharacterProfile & {
297
301
  modelPath: string;
298
302
  regions: Region[];
299
303
  };
304
+ export type AnimationSource = string;
305
+ export type BakedClipChannel = 'face' | 'body' | 'scene' | 'custom';
306
+ /** Rust's clip catalog describes which native channels can be played. */
307
+ export interface BakedClipChannelInfo {
308
+ channel: BakedClipChannel;
309
+ trackCount: number;
310
+ playable: boolean;
311
+ blendMode?: 'replace' | 'additive';
312
+ }
313
+ export interface AnimationClipInfo {
314
+ name: string;
315
+ duration: number;
316
+ trackCount: number;
317
+ source: AnimationSource;
318
+ channels: BakedClipChannelInfo[];
319
+ }
300
320
  export interface HairColorAppearance {
301
321
  name: string;
302
322
  baseColor: string;
@@ -310,9 +330,23 @@ export interface HairAppearanceState {
310
330
  outlineColor: string;
311
331
  outlineOpacity: number;
312
332
  }
313
- export interface HairPhysicsRuntimeConfig {
333
+ export interface HairPhysicsRuntimeConfig extends Omit<HairPhysicsProfileConfig, 'direction' | 'morphTargets'> {
314
334
  enabled: boolean;
315
- [key: string]: any;
335
+ direction?: {
336
+ yawSign?: number;
337
+ pitchSign?: number;
338
+ } | null;
339
+ /** Runtime normalization accepts authored records and returns names/weights. */
340
+ morphTargets?: {
341
+ swayLeft?: string | HairMorphTargetMapping | null;
342
+ swayRight?: string | HairMorphTargetMapping | null;
343
+ swayFront?: string | HairMorphTargetMapping | null;
344
+ fluffRight?: string | HairMorphTargetMapping | null;
345
+ fluffBottom?: string | HairMorphTargetMapping | null;
346
+ headUp?: Record<string, number | HairMorphTargetValueMapping | null> | null;
347
+ headDown?: Record<string, number | HairMorphTargetValueMapping | null> | null;
348
+ } | null;
349
+ [extension: string]: unknown;
316
350
  }
317
351
  export type HairPhysicsRuntimeConfigUpdate = Partial<HairPhysicsRuntimeConfig>;
318
352
  export interface TransitionHandle {
@@ -392,7 +426,7 @@ export interface ChiralBoneNamePair {
392
426
  }
393
427
  export interface CreatedBoneAxisAu {
394
428
  auId: number;
395
- profile: Profile;
429
+ profile: Partial<Profile>;
396
430
  }
397
431
  export interface BoneInfo {
398
432
  name: string;
@@ -4,17 +4,31 @@ import type { AUDescriptor } from '@lovelace_lol/embody/wasm';
4
4
  import { ThreeFrameApplier } from './index';
5
5
  import type { ThreeModelInspection } from './index';
6
6
  import type { ThreeModelReferencePose } from './reference-pose';
7
+ import type { VrmAnimationFile, VrmAnimationInfo, VrmAnimationUnits } from './vrm-animation';
7
8
  import type { ThreeNativePlaybackEvent } from './nativePlayback';
9
+ import type { AnimationClipInfo, HairAppearanceState, HairColorAppearance, HairPhysicsRuntimeConfig, HairPhysicsRuntimeConfigUpdate, MeshInfo, Profile, ProfileInput, ThreeResolvedMaterialConfig } from './authoringTypes';
8
10
  type JsonObject = Record<string, any>;
9
11
  export type RustEmbodyHostConfig = {
10
12
  profileMode?: 'preset' | 'profile';
11
13
  presetId?: string;
12
14
  presetType?: string;
13
- profile?: JsonObject;
15
+ profile?: ProfileInput;
14
16
  meshes?: Mesh[];
15
17
  referencePose?: ThreeModelReferencePose;
16
18
  };
17
19
  export type CharacterPlaybackOptions = JsonObject;
20
+ /** Semantic AU values keyed by numeric AU id. */
21
+ export type CharacterAUState = {
22
+ live: Record<string, number>;
23
+ animated: Record<string, number>;
24
+ total: Record<string, number>;
25
+ unreadable: string[];
26
+ };
27
+ export type CharacterAUGoalMeasurement = {
28
+ distance: number;
29
+ reversal: boolean;
30
+ current: Record<string, number>;
31
+ };
18
32
  export type CharacterPlaybackEvent = ThreeNativePlaybackEvent & {
19
33
  actionId: string;
20
34
  clipName: string;
@@ -69,10 +83,12 @@ export declare class Embody {
69
83
  private readonly profileMode;
70
84
  private readonly preset;
71
85
  private readonly sources;
86
+ private readonly vrmAnimations;
72
87
  private readonly playbacks;
73
88
  private readonly current;
74
89
  private playDepth;
75
90
  private readonly pendingEvents;
91
+ private readonly pendingReleases;
76
92
  private bindingGeneration;
77
93
  private disposed;
78
94
  private rendering;
@@ -80,6 +96,7 @@ export declare class Embody {
80
96
  private nextLiveTarget;
81
97
  private readonly liveTargets;
82
98
  private readonly hairObjects;
99
+ private hairHeadObservation?;
83
100
  private hairConfig;
84
101
  private hairAppearance;
85
102
  constructor(config?: RustEmbodyHostConfig);
@@ -98,12 +115,13 @@ export declare class Embody {
98
115
  private bind;
99
116
  bindModel(meshes?: Mesh[]): void;
100
117
  extendReferencePose(): ThreeModelReferencePose;
101
- setProfile(value: JsonObject): void;
102
- getProfile(): JsonObject;
118
+ setProfile(value: ProfileInput): void;
119
+ getProfile(): Partial<Profile>;
103
120
  getProfileMode(): 'preset' | 'profile';
104
121
  getPresetId(): string | null;
105
122
  supportsPreset(value?: string): boolean;
106
123
  private onPlaybackEvent;
124
+ private flushPendingPlaybackEvents;
107
125
  private compile;
108
126
  private restValues;
109
127
  private materialize;
@@ -113,10 +131,17 @@ export declare class Embody {
113
131
  private handle;
114
132
  private forget;
115
133
  private updatePlayback;
134
+ supportsVrmAnimation(): boolean;
135
+ convertMixamoFbxToVrmAnimations(bytes: ArrayBuffer, options: VrmAnimationUnits): VrmAnimationFile[];
136
+ getVrmAnimationInfo(bytes: Uint8Array): VrmAnimationInfo;
137
+ /** Registers a source; Animation owns the later playback request. */
138
+ registerVrmAnimation(name: string, bytes: Uint8Array, options: VrmAnimationUnits): void;
139
+ /** Stale editor cleanup must not remove a later same-name native source. */
140
+ releaseVrmAnimation(name: string): void;
116
141
  registerAnimationClips(clips: AnimationClip[]): void;
117
142
  loadAnimationClips(clips: AnimationClip[]): void;
118
143
  removeAnimationClip(name: string): boolean;
119
- getAnimationClips(): any[];
144
+ getAnimationClips(): AnimationClipInfo[];
120
145
  playAnimation(name: string, options?: CharacterPlaybackOptions): CharacterPlaybackHandle;
121
146
  private build;
122
147
  buildClip(name: string, curves: JsonObject, options?: CharacterPlaybackOptions): CharacterPlaybackHandle;
@@ -136,6 +161,7 @@ export declare class Embody {
136
161
  cleanupSnippet(name: string): void;
137
162
  crossfadeTo(name: string, seconds: number, options?: CharacterPlaybackOptions): CharacterPlaybackHandle;
138
163
  stopAnimation(name: string): void;
164
+ /** Stop every caller playback. Live setter targets and hair actions keep running. */
139
165
  stopAllAnimations(): void;
140
166
  pauseAnimation(name: string): void;
141
167
  resumeAnimation(name: string): void;
@@ -167,6 +193,24 @@ export declare class Embody {
167
193
  getAUDescriptors(): AUDescriptor[];
168
194
  setContinuum(negative: number, positive: number, value: number, balance?: number): void;
169
195
  getContinuum(negative: number, positive: number): number;
196
+ /**
197
+ * One clip slot's own semantic AU contribution right now (`{auId: value}`),
198
+ * evaluated in Rust at the native action's time and effective weight.
199
+ * Null when the slot is not playing or was not an AU-curve clip.
200
+ */
201
+ readAUContribution(name: string): Record<string, number> | null;
202
+ /**
203
+ * On-demand AU state: live control values, active AU-curve clip
204
+ * contributions and their sum. Baked/native and typed clips cannot be
205
+ * inverted to AU values and are listed as `unreadable`, never estimated.
206
+ */
207
+ readAUState(): CharacterAUState;
208
+ /**
209
+ * Distance from a slot's current contribution to AU destinations, measured
210
+ * along profile continuum pairs, and whether it reverses unfinished travel.
211
+ * A slot that is not playing is at zero. Callers choose any timing policy.
212
+ */
213
+ measureAUGoal(name: string, destinations: Record<string, number>): CharacterAUGoalMeasurement;
170
214
  transitionAU(id: number, value: number, durationMs?: number, balance?: number): CharacterTransitionHandle;
171
215
  setViseme(index: number, value: number, jawScale?: number): void;
172
216
  getViseme(index: number): number;
@@ -189,12 +233,12 @@ export declare class Embody {
189
233
  addMorphTarget(target: Parameters<ThreeFrameApplier['addMorphTarget']>[1], options?: Parameters<ThreeFrameApplier['addMorphTarget']>[2]): number;
190
234
  addMorphTargets(targets: Parameters<ThreeFrameApplier['addMorphTargets']>[1], options?: Parameters<ThreeFrameApplier['addMorphTargets']>[2]): Record<string, number>;
191
235
  private meshCategory;
192
- getMeshList(): JsonObject[];
236
+ getMeshList(): MeshInfo[];
193
237
  getBones(): ThreeModelInspection['bones'];
194
238
  private meshProfile;
195
239
  setMeshVisible(name: string, visible: boolean): void;
196
240
  highlightMesh(name: string | null, color?: number, value?: number): void;
197
- getMeshMaterialConfig(name: string): Record<string, unknown> | null;
241
+ getMeshMaterialConfig(name: string): ThreeResolvedMaterialConfig | null;
198
242
  setMeshMaterialConfig(name: string, value: Parameters<ThreeFrameApplier['setMeshMaterialConfig']>[2]): void;
199
243
  registerHairObjects(objects: Object3D[]): {
200
244
  name: string;
@@ -203,10 +247,10 @@ export declare class Embody {
203
247
  }[];
204
248
  getRegisteredHairObjects(): Object3D[];
205
249
  getHairMorphTargets(name?: string): string[];
206
- getHairAppearance(): JsonObject;
250
+ getHairAppearance(): HairAppearanceState;
207
251
  private setHairAppearance;
208
- setHairColor(value: string | JsonObject): void;
209
- setEyebrowColor(value: string | JsonObject): void;
252
+ setHairColor(value: string | Partial<HairColorAppearance>): void;
253
+ setEyebrowColor(value: string | Partial<HairColorAppearance>): void;
210
254
  setHairBaseColor(value: string): void;
211
255
  setEyebrowBaseColor(value: string): void;
212
256
  setHairGlow(color: string, value: number): void;
@@ -216,15 +260,15 @@ export declare class Embody {
216
260
  color?: string;
217
261
  opacity?: number;
218
262
  }): void;
219
- private restartHair;
263
+ private hairClipOptions;
264
+ private bindHairHead;
265
+ private sampleHairResponse;
220
266
  setHairPhysicsEnabled(value: boolean): void;
221
267
  isHairPhysicsEnabled(): boolean;
222
- setHairPhysicsConfig(value: JsonObject): void;
223
- getHairPhysicsConfig(): JsonObject;
268
+ setHairPhysicsConfig(value: HairPhysicsRuntimeConfigUpdate): void;
269
+ getHairPhysicsConfig(): Partial<HairPhysicsRuntimeConfig>;
224
270
  validateHairMorphTargets(): string[];
225
271
  applyHairStateToObject(name: string, state: JsonObject): void;
226
- private authoredHeadMotion;
227
- private setHairGravity;
228
272
  playHairImpulse(horizontal: number, vertical: number): CharacterPlaybackHandle | undefined;
229
273
  start(): void;
230
274
  stop(): void;
@@ -1,10 +1,13 @@
1
+ import type { MeshHighlightFrame } from '../wasm/highlighting';
1
2
  import { AnimationClip } from 'three';
2
3
  export * from './annotations/index';
4
+ export * from './vrm-animation';
3
5
  export * from './authoring';
4
6
  export * from './character';
5
7
  export * from './characterHost';
6
8
  export { renderScenePlayback, createScenePlaybackFrame } from './playbackRendering';
7
9
  import type { ThreeModelReferencePose } from './reference-pose';
10
+ import type { MeshMaterialSettings, ThreeResolvedMaterialConfig } from './authoringTypes';
8
11
  export { captureModelReferencePose, bindModelReferencePose, extendModelReferencePose } from './reference-pose';
9
12
  export type { ThreeModelReferencePose, ThreeReferencePoseNode } from './reference-pose';
10
13
  export { ThreeNativePlaybackConnector } from './nativePlayback';
@@ -133,20 +136,13 @@ export declare function serializeAnimationClips(model: Object3D, clips: readonly
133
136
  }[];
134
137
  tracks: ClipIRTrack[];
135
138
  }[];
136
- type MaterialConfig = {
137
- renderOrder?: number;
138
- transparent?: boolean;
139
- opacity?: number;
140
- depthWrite?: boolean;
141
- depthTest?: boolean;
142
- blending?: keyof typeof THREE_BLENDING_MODES;
143
- };
139
+ type MaterialConfig = MeshMaterialSettings;
144
140
  export declare class ThreeFrameApplier {
145
141
  private meshes;
146
142
  private morphs;
147
143
  private bones;
148
144
  private objects;
149
- private originalEmissive;
145
+ private highlighted;
150
146
  setBindings(inspection: ThreeModelInspection): void;
151
147
  applyPackedMorphFrameDelta(values: ArrayLike<number>, stride?: number): void;
152
148
  applyPackedBoneFrameDelta(values: ArrayLike<number>, stride?: number): void;
@@ -155,10 +151,14 @@ export declare class ThreeFrameApplier {
155
151
  visible?: boolean;
156
152
  material?: MaterialConfig;
157
153
  }>): void;
158
- getMeshMaterialConfig(root: Object3D, name: string): null;
154
+ getMeshMaterialConfig(root: Object3D, name: string): ThreeResolvedMaterialConfig | null;
159
155
  setMeshMaterialConfig(root: Object3D, name: string, config: MaterialConfig): void;
156
+ private applyHighlightedMeshMaterial;
160
157
  setMeshVisible(root: Object3D, name: string, visible: boolean): void;
161
- highlightMesh(root: Object3D, name: string | null, color?: number, intensity?: number): void;
158
+ /** Apply a complete Rust snapshot. Only native resources and ID bindings live here. */
159
+ applyMeshHighlightFrame(frame: MeshHighlightFrame): void;
160
+ clearMeshHighlights(): void;
161
+ private clearMeshHighlight;
162
162
  applyHairAppearance(meshes: readonly Mesh[], appearance: any): void;
163
163
  addMorphTarget(root: Object3D, target: MorphTargetInput, options?: AddMorphTargetOptions): number;
164
164
  addMorphTargets(root: Object3D, targets: readonly MorphTargetInput[], options?: AddMorphTargetOptions): Record<string, number>;
@@ -169,5 +169,6 @@ export declare class ThreeFrameApplier {
169
169
  export declare const collectMorphMeshes: (root: Object3D) => Mesh<import("three").BufferGeometry<import("three").NormalBufferAttributes, import("three").BufferGeometryEventMap>, Material<import("three").MaterialEventMap> | Material<import("three").MaterialEventMap>[], import("three").Object3DEventMap>[];
170
170
  export * from './model';
171
171
  export * from './scene';
172
+ export * from './scenery';
172
173
  export * from './editor/SkeletonOverlay';
173
174
  export * from './editor/morphVertexPreview';
@@ -6,7 +6,9 @@ export type CharacterModelLoadResult = {
6
6
  animations: AnimationClip[];
7
7
  gltf: GLTF | null;
8
8
  };
9
+ export type CharacterModelFormat = 'gltf' | 'fbx';
9
10
  export type CharacterModelLoadOptions = {
11
+ format?: CharacterModelFormat;
10
12
  onProgress?: (progress: number) => void;
11
13
  castShadows?: boolean;
12
14
  dracoDecoderPath?: string;
@@ -57,6 +57,8 @@ export type ThreeNativePlaybackBinding = {
57
57
  inspection: ThreeModelInspection;
58
58
  /** Optional existing native mixer. Otherwise the connector owns one. */
59
59
  mixer?: AnimationMixer;
60
+ /** Apply renderer effects using the existing scene clock; never starts a loop. */
61
+ onFrame?: (deltaSeconds: number) => void;
60
62
  };
61
63
  /**
62
64
  * Execute validated Rust commands on the native mixer. There is no
@@ -83,10 +85,13 @@ export declare class ThreeNativePlaybackConnector {
83
85
  private disposed;
84
86
  private readonly onError?;
85
87
  private readonly onRelease?;
88
+ private readonly afterSample?;
86
89
  constructor(session: NativePlaybackSession, binding: ThreeNativePlaybackBinding & {
87
90
  onError?: (error: Error) => void;
88
91
  onRelease?: (handle: string) => void;
92
+ afterSample?: (deltaSeconds: number) => void;
89
93
  });
94
+ private readonly afterFrame;
90
95
  /** Prepare bindings first; old actions are released before the new binding is exposed. */
91
96
  rebind(modelKey: string, profileKey: string, binding?: ThreeNativePlaybackBinding): void;
92
97
  play(clip: ClipIR, options?: ThreeNativePlaybackOptions): string;
@@ -105,6 +110,7 @@ export declare class ThreeNativePlaybackConnector {
105
110
  replaceClip(handle: string, clip: AnimationClip): void;
106
111
  /** Native state for the owning adapter; never exposed through Polymer. */
107
112
  getAction(handle: string): AnimationAction | undefined;
113
+ private readonly sampleResponse;
108
114
  /** Deliver native completion after the borrowed mixer has finished sampling. */
109
115
  flushEvents(): void;
110
116
  subscribe(listener: (event: ThreeNativePlaybackEvent) => void): () => void;
@@ -1,7 +1,7 @@
1
1
  import { Timer } from 'three';
2
2
  import type { AnimationMixer, Object3D } from 'three';
3
3
  /** Register native playback with the existing scene renderer; never starts a loop. */
4
- export declare function bindPlaybackRendering(model: Object3D, mixer: AnimationMixer, afterFrame: () => void): {
4
+ export declare function bindPlaybackRendering(model: Object3D, mixer: AnimationMixer, afterFrame: (deltaSeconds: number) => void, afterSample?: (deltaSeconds: number) => void): {
5
5
  setEnabled(enabled: boolean): void;
6
6
  dispose(): void;
7
7
  };
@@ -186,6 +186,8 @@ export interface CharacterSceneRenderingController {
186
186
  subscribe(listener: (snapshot: CharacterSceneRenderingSnapshot) => void): () => void;
187
187
  /** Borrow for capture/readback; release in finally. Unavailable during switching/loss. */
188
188
  acquireRenderer(): CharacterSceneRendererLease;
189
+ /** Wait for queued scene work, then atomically borrow the active renderer. Release in finally. */
190
+ acquireRendererAsync(): Promise<CharacterSceneRendererLease>;
189
191
  /** Drain borrowed work, then synchronously detach/free caller-owned resources, even after loss/disposal. */
190
192
  releaseSceneResources(release: () => void): Promise<void>;
191
193
  }
@@ -0,0 +1,11 @@
1
+ import { type Scene } from 'three';
2
+ /** Character settings update the inherited background even while scenery covers it. */
3
+ export declare function setSceneBaseBackground(scene: Scene, value: Scene['background']): void;
4
+ /** One scenery owner per scene prevents competing capture-and-restore cleanups. */
5
+ export declare function acquireSceneBackground(scene: Scene, onSceneDispose: () => void): {
6
+ set(value: Scene["background"], intensity: number, rotationDegrees: number): void;
7
+ clear(): void;
8
+ dispose(): void;
9
+ };
10
+ /** Called by the scene's existing lifetime; the renderer owns its async drain. */
11
+ export declare function disposeSceneBackground(scene: Scene): void;
@@ -0,0 +1,46 @@
1
+ import type { Scene } from 'three';
2
+ import type { CharacterSceneRenderingController } from './scene';
3
+ /** World coordinates in the scene's native units (Y up for default character scenes). */
4
+ export type SceneSceneryPosition = {
5
+ x: number;
6
+ y: number;
7
+ z: number;
8
+ };
9
+ export type SceneSceneryInstance = {
10
+ instanceId: string;
11
+ assetId: string;
12
+ position: SceneSceneryPosition;
13
+ };
14
+ export type SceneScenerySkybox = {
15
+ kind: 'skybox' | 'backdrop' | 'color';
16
+ assetId: string | null;
17
+ /** Six-digit #rrggbb, also used by the generated sky when assetId is null. */
18
+ color: string;
19
+ intensity: number;
20
+ /** Y-axis degrees. Applies to equirectangular skyboxes. */
21
+ rotation: number;
22
+ };
23
+ export type SceneSceneryLayout = {
24
+ skybox: SceneScenerySkybox | null;
25
+ instances: readonly SceneSceneryInstance[];
26
+ };
27
+ export type SceneSceneryAsset = {
28
+ bytes: ArrayBuffer;
29
+ contentType: string;
30
+ };
31
+ export type SceneSceneryRendererOptions = {
32
+ scene: Scene;
33
+ /** The scene's existing controller. Omit only for an externally managed scene. */
34
+ rendering?: CharacterSceneRenderingController | null;
35
+ /** Storage authorization, caching and asset identities remain with the caller. */
36
+ loadAsset(assetId: string, signal: AbortSignal): Promise<SceneSceneryAsset>;
37
+ onError?: (message: string) => void;
38
+ };
39
+ export type SceneSceneryRenderer = {
40
+ /** Validates and copies the entire layout before changing the current selection. */
41
+ update(layout: SceneSceneryLayout | null): void;
42
+ /** Cancels loads, drains borrowed rendering work, and releases only scenery. */
43
+ dispose(): Promise<void>;
44
+ };
45
+ /** Native scene resources only: no storage, character selection, mixer or render loop. */
46
+ export declare function createSceneSceneryRenderer(options: SceneSceneryRendererOptions): SceneSceneryRenderer;