@lovelace_lol/embody 0.0.4 → 0.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/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as THREE from 'three';
2
2
  import { Vector3, NoBlending, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NormalBlending, PropertyBinding, NumberKeyframeTrack, QuaternionKeyframeTrack, VectorKeyframeTrack, AnimationClip, AnimationUtils, AdditiveAnimationBlendMode, NormalAnimationBlendMode, LoopPingPong, LoopOnce, LoopRepeat, Quaternion, AnimationMixer, Box3, Mesh, Clock, BufferAttribute, PlaneGeometry, ShadowMaterial, PMREMGenerator, WebGLRenderer, PCFSoftShadowMap, Scene, Color, PerspectiveCamera, HemisphereLight, DirectionalLight, MathUtils, SRGBColorSpace, ACESFilmicToneMapping } from 'three';
3
- import { initEmbodyCore, HAIR_MORPH_OUTPUT_FIELDS, HAIR_CONFIG_STRIDE, HAIR_HEAD_STATE_STRIDE, HAIR_MORPH_OUTPUT_STRIDE, HAIR_STATE_STRIDE } from '@lovelace_lol/embody/wasm';
3
+ import { initEmbodyCore, requireInitializedEmbodyCore, HAIR_MORPH_OUTPUT_FIELDS, HAIR_CONFIG_STRIDE, HAIR_HEAD_STATE_STRIDE, HAIR_MORPH_OUTPUT_STRIDE, HAIR_STATE_STRIDE } from '@lovelace_lol/embody/wasm';
4
4
  export { EMBODY_CORE_ABI_VERSION, HAIR_CONFIG_FIELDS, HAIR_CONFIG_STRIDE, HAIR_HEAD_STATE_FIELDS, HAIR_HEAD_STATE_STRIDE, HAIR_MORPH_OUTPUT_FIELDS, HAIR_MORPH_OUTPUT_STRIDE, HAIR_STATE_FIELDS, HAIR_STATE_STRIDE, MESH_PROPORTIONS_FIELDS, MESH_PROPORTIONS_STRIDE, PACKED_BONE_FRAME_DELTA_FIELDS, PACKED_BONE_FRAME_DELTA_STRIDE, PACKED_MORPH_FRAME_DELTA_FIELDS, PACKED_MORPH_FRAME_DELTA_STRIDE, TEMPLATE_SKELETON_FIT_SOLUTION_FIELDS, TEMPLATE_SKELETON_FIT_SOLUTION_STRIDE, TEMPLATE_SKELETON_FIT_TRANSFORM_FIELDS, TEMPLATE_SKELETON_FIT_TRANSFORM_STRIDE, getEmbodyCore, initEmbodyCore, requireInitializedEmbodyCore, resetEmbodyCoreForTests } from '@lovelace_lol/embody/wasm';
5
5
  import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js';
6
6
  import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
@@ -3676,410 +3676,6 @@ function getBlendingName(value) {
3676
3676
  return "Normal";
3677
3677
  }
3678
3678
 
3679
- // src/core/TsRuntimeCore.ts
3680
- var identityQuat = { x: 0, y: 0, z: 0, w: 1 };
3681
- function isRotationBoneBinding2(binding) {
3682
- return binding?.channel === "rx" || binding?.channel === "ry" || binding?.channel === "rz";
3683
- }
3684
- var TsRuntimeCore = class {
3685
- constructor(options) {
3686
- __publicField(this, "profile");
3687
- __publicField(this, "model");
3688
- __publicField(this, "auValues", {});
3689
- __publicField(this, "auBalances", {});
3690
- __publicField(this, "visemeValues");
3691
- __publicField(this, "visemeJawScales");
3692
- __publicField(this, "mixWeights");
3693
- this.profile = options.profile;
3694
- this.model = options.model;
3695
- this.visemeValues = new Array(getProfileVisemeSlots(this.profile).length).fill(0);
3696
- this.visemeJawScales = new Array(this.visemeValues.length).fill(1);
3697
- this.mixWeights = { ...this.profile.auMixDefaults };
3698
- }
3699
- setProfile(profile) {
3700
- this.profile = profile;
3701
- this.visemeValues = new Array(getProfileVisemeSlots(this.profile).length).fill(0);
3702
- this.visemeJawScales = new Array(this.visemeValues.length).fill(1);
3703
- this.mixWeights = { ...this.profile.auMixDefaults };
3704
- }
3705
- setModelDescriptor(model) {
3706
- this.model = model;
3707
- }
3708
- setAU(id, value, balance) {
3709
- if (value < 0 && this.profile.continuumPairs) {
3710
- const pairInfo = this.profile.continuumPairs[id];
3711
- if (pairInfo) {
3712
- const negAU = pairInfo.isNegative ? id : pairInfo.pairId;
3713
- const posAU = pairInfo.isNegative ? pairInfo.pairId : id;
3714
- this.setContinuum(negAU, posAU, pairInfo.isNegative ? -value : value, balance);
3715
- return;
3716
- }
3717
- }
3718
- this.auValues[id] = clamp01(value);
3719
- if (balance !== void 0) {
3720
- this.auBalances[id] = clampBalance2(balance);
3721
- }
3722
- }
3723
- getAU(id) {
3724
- return this.auValues[id] ?? 0;
3725
- }
3726
- setContinuum(negAU, posAU, continuumValue, balance) {
3727
- const value = Math.max(-1, Math.min(1, continuumValue));
3728
- if (value < 0) {
3729
- this.setAU(posAU, 0, balance);
3730
- this.setAU(negAU, Math.abs(value), balance);
3731
- return;
3732
- }
3733
- if (value > 0) {
3734
- this.setAU(negAU, 0, balance);
3735
- this.setAU(posAU, value, balance);
3736
- return;
3737
- }
3738
- this.setAU(negAU, 0, balance);
3739
- this.setAU(posAU, 0, balance);
3740
- }
3741
- setViseme(visemeIndex, value, jawScale = 1) {
3742
- if (visemeIndex < 0 || visemeIndex >= this.visemeValues.length) return;
3743
- this.visemeValues[visemeIndex] = clamp01(value);
3744
- this.visemeJawScales[visemeIndex] = jawScale;
3745
- }
3746
- setVisemeById(slotId, value, jawScale = 1) {
3747
- const index = getVisemeSlotIndex(this.profile, slotId);
3748
- if (index < 0) return;
3749
- this.setViseme(index, value, jawScale);
3750
- }
3751
- setAUMixWeight(id, weight) {
3752
- this.mixWeights[id] = clamp01(weight);
3753
- }
3754
- evaluateFrameDelta(deltaSeconds) {
3755
- const morphWrites = /* @__PURE__ */ new Map();
3756
- this.collectAUWrites(morphWrites);
3757
- this.collectVisemeWrites(morphWrites);
3758
- return {
3759
- deltaSeconds,
3760
- morphTargets: Array.from(morphWrites.values()),
3761
- bones: this.collectBoneWrites()
3762
- };
3763
- }
3764
- collectAUWrites(morphWrites) {
3765
- for (const [auIdText, entry] of Object.entries(this.profile.auToMorphs || {})) {
3766
- const auId = Number(auIdText);
3767
- if (Number.isNaN(auId) || !entry) continue;
3768
- const mixWeight = this.isMixedAU(auId) ? this.getAUMixWeight(auId) : 1;
3769
- const base = clamp01(this.auValues[auId] ?? 0) * mixWeight;
3770
- const { left, right } = computeSideValues(base, this.auBalances[auId]);
3771
- const meshNames = getMeshNamesForAUProfile(this.profile, auId);
3772
- for (const morph of entry.left || []) {
3773
- this.addMorphWrites(morphWrites, morph, meshNames, left);
3774
- }
3775
- for (const morph of entry.right || []) {
3776
- this.addMorphWrites(morphWrites, morph, meshNames, right);
3777
- }
3778
- for (const morph of entry.center || []) {
3779
- this.addMorphWrites(morphWrites, morph, meshNames, base);
3780
- }
3781
- }
3782
- }
3783
- collectVisemeWrites(morphWrites) {
3784
- const meshNames = getMeshNamesForVisemeProfile(this.profile);
3785
- const localMax = /* @__PURE__ */ new Map();
3786
- for (let index = 0; index < this.visemeValues.length; index += 1) {
3787
- const value = clamp01(this.visemeValues[index] ?? 0);
3788
- for (const bindingTarget of getVisemeBindingTargets(this.profile, index)) {
3789
- const weighted = clamp01(value * bindingTarget.weight);
3790
- for (const resolved of this.resolveMorphTargets(bindingTarget.morph, meshNames)) {
3791
- const key = morphWriteKey(resolved.mesh.id, resolved.morphTarget.id);
3792
- const existing = localMax.get(key);
3793
- if (!existing || weighted > existing.value) {
3794
- localMax.set(key, {
3795
- meshId: resolved.mesh.id,
3796
- morphTargetId: resolved.morphTarget.id,
3797
- value: weighted,
3798
- mode: "absolute"
3799
- });
3800
- }
3801
- }
3802
- }
3803
- }
3804
- for (const [key, write] of localMax) {
3805
- const existing = morphWrites.get(key);
3806
- if (!existing || write.value > existing.value) {
3807
- morphWrites.set(key, write);
3808
- }
3809
- }
3810
- }
3811
- collectBoneWrites() {
3812
- const writes = [];
3813
- const rotations = this.computeRotationState();
3814
- for (const composite of this.profile.compositeRotations || []) {
3815
- const bone = this.findBoneDescriptor(composite.node);
3816
- if (!bone) continue;
3817
- const transform = this.evaluateCompositeTransform(bone, composite, rotations[composite.node]);
3818
- if (transform) {
3819
- writes.push({
3820
- boneId: bone.id,
3821
- transform,
3822
- mode: "absolute",
3823
- space: "local"
3824
- });
3825
- }
3826
- }
3827
- for (const [nodeKey, translation] of Object.entries(this.computeTranslations())) {
3828
- const bone = this.findBoneDescriptor(nodeKey);
3829
- if (!bone) continue;
3830
- const position = addVec3(bone.restTransform?.position, translation);
3831
- upsertBoneWrite(writes, bone.id, { position });
3832
- }
3833
- const jawAmount = this.getActiveVisemeJawAmount();
3834
- const jawBinding = this.findAutoVisemeJawBinding();
3835
- const jawBone = jawBinding ? this.findBoneDescriptor(jawBinding.node) : void 0;
3836
- if (jawBone && jawBinding?.maxDegrees && jawBinding.channel) {
3837
- const current = writes.find((write) => write.boneId === jawBone.id);
3838
- if (jawAmount > 1e-6 || !current?.transform.rotation) {
3839
- const rest = jawBone.restTransform?.rotation ?? identityQuat;
3840
- const rotation = jawAmount > 1e-6 ? multiplyQuat(
3841
- rest,
3842
- quatFromChannel(jawBinding.channel, deg2rad(jawBinding.maxDegrees) * jawAmount * jawBinding.scale)
3843
- ) : rest;
3844
- upsertBoneWrite(writes, jawBone.id, { rotation });
3845
- }
3846
- }
3847
- return writes;
3848
- }
3849
- computeRotationState() {
3850
- const rotations = {};
3851
- for (const composite of this.profile.compositeRotations || []) {
3852
- rotations[composite.node] = {
3853
- pitch: this.getCompositeAxisValueForNode(composite.node, composite.pitch),
3854
- yaw: this.getCompositeAxisValueForNode(composite.node, composite.yaw),
3855
- roll: this.getCompositeAxisValueForNode(composite.node, composite.roll)
3856
- };
3857
- }
3858
- return rotations;
3859
- }
3860
- evaluateCompositeTransform(bone, composite, state) {
3861
- if (!state) return null;
3862
- let rotation = bone.restTransform?.rotation ?? identityQuat;
3863
- const applyAxis = (axisConfig, direction) => {
3864
- if (!axisConfig || Math.abs(direction) <= 1e-6) return;
3865
- const binding = getCompositeAxisBinding(
3866
- composite.node,
3867
- axisConfig,
3868
- direction,
3869
- (auId) => this.getEffectiveBoneAUValue(auId, composite.node),
3870
- this.profile.auToBones
3871
- );
3872
- if (!binding?.maxDegrees || !binding.channel) return;
3873
- rotation = multiplyQuat(
3874
- rotation,
3875
- quatFromChannel(binding.channel, deg2rad(binding.maxDegrees) * Math.abs(direction) * binding.scale)
3876
- );
3877
- };
3878
- applyAxis(composite.yaw, state.yaw);
3879
- applyAxis(composite.pitch, state.pitch);
3880
- applyAxis(composite.roll, state.roll);
3881
- return { rotation };
3882
- }
3883
- computeTranslations() {
3884
- const translations = {};
3885
- for (const [auIdText, bindings] of Object.entries(this.profile.auToBones || {})) {
3886
- const auId = Number(auIdText);
3887
- if (Number.isNaN(auId)) continue;
3888
- const value = clamp01(this.auValues[auId] ?? 0);
3889
- for (const binding of bindings || []) {
3890
- if (binding.channel !== "tx" && binding.channel !== "ty" && binding.channel !== "tz") continue;
3891
- if (binding.maxUnits === void 0) continue;
3892
- const current = translations[binding.node] ?? { x: 0, y: 0, z: 0 };
3893
- translations[binding.node] = current;
3894
- if (value <= 1e-6) continue;
3895
- const offset = clampSigned(value * binding.scale) * binding.maxUnits;
3896
- translations[binding.node] = {
3897
- x: binding.channel === "tx" ? offset : current.x,
3898
- y: binding.channel === "ty" ? offset : current.y,
3899
- z: binding.channel === "tz" ? offset : current.z
3900
- };
3901
- }
3902
- }
3903
- return translations;
3904
- }
3905
- addMorphWrites(morphWrites, morph, meshNames, value) {
3906
- for (const resolved of this.resolveMorphTargets(morph, meshNames)) {
3907
- const key = morphWriteKey(resolved.mesh.id, resolved.morphTarget.id);
3908
- const existing = morphWrites.get(key);
3909
- if (existing && existing.value >= value) continue;
3910
- morphWrites.set(key, {
3911
- meshId: resolved.mesh.id,
3912
- morphTargetId: resolved.morphTarget.id,
3913
- value,
3914
- mode: "absolute"
3915
- });
3916
- }
3917
- }
3918
- resolveMorphTargets(morph, meshNames) {
3919
- const result = [];
3920
- for (const meshName of meshNames) {
3921
- const mesh = this.model.meshes.find((candidate) => candidate.name === meshName);
3922
- if (!mesh) continue;
3923
- const morphTargets = mesh.morphTargetIds.map((id) => this.model.morphTargets.find((candidate) => candidate.id === id)).filter((target2) => !!target2);
3924
- const target = typeof morph === "number" ? morphTargets.find((candidate) => candidate.hostIndex === morph) : resolveMorphTargetByName(morphTargets, morph, this.profile);
3925
- if (target) {
3926
- result.push({ mesh, morphTarget: target });
3927
- }
3928
- }
3929
- return result;
3930
- }
3931
- findBoneDescriptor(nodeKey) {
3932
- const configuredName = this.profile.boneNodes[nodeKey] || nodeKey;
3933
- const prefix = this.profile.bonePrefix ?? "";
3934
- const suffix = this.profile.boneSuffix ?? "";
3935
- const prefixedName = prefix && !configuredName.startsWith(prefix) ? `${prefix}${configuredName}` : configuredName;
3936
- const fullName = suffix && !prefixedName.endsWith(suffix) ? `${prefixedName}${suffix}` : prefixedName;
3937
- const candidates = /* @__PURE__ */ new Set([nodeKey, configuredName, fullName]);
3938
- return this.model.bones.find((bone) => candidates.has(bone.name));
3939
- }
3940
- findAutoVisemeJawBinding() {
3941
- const candidates = [
3942
- this.profile.auToBones[103]?.find(isRotationBoneBinding2),
3943
- this.profile.auToBones[26]?.find(isRotationBoneBinding2)
3944
- ].filter((binding) => !!binding);
3945
- return candidates.find((binding) => !!this.findBoneDescriptor(binding.node)) ?? candidates[0] ?? null;
3946
- }
3947
- getActiveVisemeJawAmount() {
3948
- const jawAmounts = getVisemeJawAmounts(this.profile) ?? [];
3949
- let jawAmount = 0;
3950
- for (let index = 0; index < this.visemeValues.length; index += 1) {
3951
- const value = clamp01(this.visemeValues[index] ?? 0);
3952
- if (value <= 1e-6) continue;
3953
- const jawScale = this.visemeJawScales[index] ?? 1;
3954
- if (Math.abs(jawScale) <= 1e-6) continue;
3955
- jawAmount = Math.max(jawAmount, (jawAmounts[index] ?? 0) * value * jawScale);
3956
- }
3957
- return jawAmount;
3958
- }
3959
- getCompositeAxisValueForNode(nodeKey, axisConfig) {
3960
- return getCompositeAxisValue(axisConfig, (auId) => this.getEffectiveBoneAUValue(auId, nodeKey));
3961
- }
3962
- getEffectiveBoneAUValue(auId, nodeKey) {
3963
- const rawValue = clamp01(this.auValues[auId] ?? 0);
3964
- if (rawValue <= 1e-6) return 0;
3965
- const binding = this.profile.auToBones[auId]?.find((candidate) => candidate.node === nodeKey) ?? null;
3966
- if (!binding?.side) return rawValue;
3967
- return rawValue * getSideScale2(this.auBalances[auId] ?? 0, binding.side);
3968
- }
3969
- getAUMixWeight(auId) {
3970
- return this.mixWeights[auId] ?? this.profile.auMixDefaults?.[auId] ?? 1;
3971
- }
3972
- isMixedAU(auId) {
3973
- const morphs = this.profile.auToMorphs[auId];
3974
- const hasMorphs = !!(morphs?.left?.length || morphs?.right?.length || morphs?.center?.length);
3975
- return !!(hasMorphs && this.profile.auToBones[auId]?.length);
3976
- }
3977
- };
3978
- function resolveMorphTargetByName(targets, key, profile) {
3979
- const prefix = profile.morphPrefix || "";
3980
- const suffix = profile.morphSuffix || "";
3981
- const fullName = prefix + key + suffix;
3982
- const exact = targets.find((target) => target.name === fullName);
3983
- if (exact) return exact;
3984
- const suffixRegex = profile.suffixPattern ? new RegExp(profile.suffixPattern) : null;
3985
- if (!suffixRegex) return void 0;
3986
- return targets.find((target) => {
3987
- if (!target.name.startsWith(fullName)) return false;
3988
- const candidateSuffix = target.name.slice(fullName.length);
3989
- return candidateSuffix === "" || suffixRegex.test(candidateSuffix);
3990
- });
3991
- }
3992
- function computeSideValues(base, balance) {
3993
- const b = clampBalance2(balance ?? 0);
3994
- if (b === 0) return { left: base, right: base };
3995
- if (b < 0) return { left: base, right: base * (1 + b) };
3996
- return { left: base * (1 - b), right: base };
3997
- }
3998
- function getSideScale2(balance, side) {
3999
- if (side !== "left" && side !== "right") return 1;
4000
- const b = clampBalance2(balance);
4001
- if (side === "left") return b > 0 ? 1 - b : 1;
4002
- return b < 0 ? 1 + b : 1;
4003
- }
4004
- function addVec3(base, offset) {
4005
- return {
4006
- x: (base?.x ?? 0) + offset.x,
4007
- y: (base?.y ?? 0) + offset.y,
4008
- z: (base?.z ?? 0) + offset.z
4009
- };
4010
- }
4011
- function upsertBoneWrite(writes, boneId2, transform) {
4012
- const existingIndex = writes.findIndex((write) => write.boneId === boneId2);
4013
- if (existingIndex >= 0) {
4014
- const existing = writes[existingIndex];
4015
- writes[existingIndex] = {
4016
- ...existing,
4017
- transform: {
4018
- ...existing.transform,
4019
- ...transform
4020
- }
4021
- };
4022
- return;
4023
- }
4024
- writes.push({
4025
- boneId: boneId2,
4026
- transform,
4027
- mode: "absolute",
4028
- space: "local"
4029
- });
4030
- }
4031
- function quatFromChannel(channel, radians) {
4032
- if (channel === "rx") return quatFromAxis({ x: 1, y: 0, z: 0 }, radians);
4033
- if (channel === "ry") return quatFromAxis({ x: 0, y: 1, z: 0 }, radians);
4034
- return quatFromAxis({ x: 0, y: 0, z: 1 }, radians);
4035
- }
4036
- function quatFromAxis(axis, radians) {
4037
- const half = radians / 2;
4038
- const s = Math.sin(half);
4039
- return normalizeQuat({
4040
- x: axis.x * s,
4041
- y: axis.y * s,
4042
- z: axis.z * s,
4043
- w: Math.cos(half)
4044
- });
4045
- }
4046
- function multiplyQuat(a, b) {
4047
- return normalizeQuat({
4048
- x: a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
4049
- y: a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
4050
- z: a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
4051
- w: a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z
4052
- });
4053
- }
4054
- function normalizeQuat(q) {
4055
- const len = Math.hypot(q.x, q.y, q.z, q.w);
4056
- if (len <= 1e-12) return identityQuat;
4057
- return {
4058
- x: q.x / len,
4059
- y: q.y / len,
4060
- z: q.z / len,
4061
- w: q.w / len
4062
- };
4063
- }
4064
- function deg2rad(degrees) {
4065
- return degrees * Math.PI / 180;
4066
- }
4067
- function clamp01(value) {
4068
- if (!Number.isFinite(value)) return 0;
4069
- return value < 0 ? 0 : value > 1 ? 1 : value;
4070
- }
4071
- function clampSigned(value) {
4072
- if (!Number.isFinite(value)) return 0;
4073
- return value < -1 ? -1 : value > 1 ? 1 : value;
4074
- }
4075
- function clampBalance2(value) {
4076
- if (!Number.isFinite(value)) return 0;
4077
- return Math.max(-1, Math.min(1, value));
4078
- }
4079
- function morphWriteKey(meshId2, morphTargetId2) {
4080
- return `${meshId2}:${morphTargetId2}`;
4081
- }
4082
-
4083
3679
  // src/core/contracts/abi.ts
4084
3680
  var PACKED_MORPH_FRAME_DELTA_STRIDE = 4;
4085
3681
  var PACKED_BONE_FRAME_DELTA_STRIDE = 9;
@@ -4209,25 +3805,17 @@ function positiveFiniteOr(value, fallback) {
4209
3805
  }
4210
3806
 
4211
3807
  // src/core/WasmRuntimeCore.ts
4212
- var AU_MORPH_BINDING_STRIDE = 5;
4213
- var VISEME_MORPH_BINDING_STRIDE = 4;
4214
- var AXIS_GROUP_NEGATIVE = 0;
4215
- var AXIS_GROUP_POSITIVE = 1;
4216
- var AXIS_GROUP_PLAIN = 2;
4217
- var BONE_SIDE_NONE = 0;
4218
- var BONE_SIDE_LEFT = 1;
4219
- var BONE_SIDE_RIGHT = 2;
4220
- var ROTATION_CHANNELS = { rx: 0, ry: 1, rz: 2 };
4221
- var TRANSLATION_CHANNELS = { tx: 0, ty: 1, tz: 2 };
4222
3808
  var WasmRuntimeCore = class {
4223
3809
  constructor(options) {
4224
3810
  __publicField(this, "wasm");
4225
3811
  __publicField(this, "core");
3812
+ __publicField(this, "allowEmptyBindings");
4226
3813
  __publicField(this, "profile");
4227
3814
  __publicField(this, "model");
4228
3815
  this.wasm = options.wasm;
4229
3816
  this.profile = options.profile;
4230
3817
  this.model = options.model;
3818
+ this.allowEmptyBindings = options.allowEmptyBindings ?? false;
4231
3819
  const RuntimeCtor = options.wasm.RuntimeCore;
4232
3820
  if (!RuntimeCtor) {
4233
3821
  throw new Error("Embody Wasm module does not export RuntimeCore");
@@ -4246,6 +3834,24 @@ var WasmRuntimeCore = class {
4246
3834
  setAU(id, value, balance = 0) {
4247
3835
  this.core.set_au(id >>> 0, value, balance);
4248
3836
  }
3837
+ setContinuum(negativeAU, positiveAU, value, balance = 0) {
3838
+ this.core.set_continuum(negativeAU >>> 0, positiveAU >>> 0, value, balance);
3839
+ }
3840
+ transitionAU(id, to, durationMs, balance = Number.NaN) {
3841
+ this.core.transition_au(id >>> 0, to, durationMs, balance);
3842
+ }
3843
+ transitionViseme(visemeIndex, to, durationMs, jawScale = 1) {
3844
+ this.core.transition_viseme(visemeIndex >>> 0, to, durationMs, jawScale);
3845
+ }
3846
+ update(deltaSeconds) {
3847
+ return this.core.update(deltaSeconds);
3848
+ }
3849
+ activeTransitionCount() {
3850
+ return this.core.active_transition_count();
3851
+ }
3852
+ clearTransitions() {
3853
+ this.core.clear_transitions();
3854
+ }
4249
3855
  getAU(id) {
4250
3856
  return this.core.get_au(id >>> 0);
4251
3857
  }
@@ -4281,182 +3887,15 @@ var WasmRuntimeCore = class {
4281
3887
  };
4282
3888
  }
4283
3889
  reloadBindings() {
4284
- this.core.configure_with_profile(JSON.stringify(this.profile), JSON.stringify(this.model));
4285
- }
4286
- };
4287
- function compileMorphBindings(profile, model) {
4288
- const auRows = [];
4289
- const mixed = [];
4290
- for (const [auIdText, entry] of Object.entries(profile.auToMorphs || {})) {
4291
- const auId = Number(auIdText);
4292
- if (Number.isNaN(auId) || !entry) continue;
4293
- const meshNames = getMeshNamesForAUProfile(profile, auId);
4294
- const hasMorphs = !!(entry.left?.length || entry.right?.length || entry.center?.length);
4295
- if (hasMorphs && profile.auToBones?.[auId]?.length) {
4296
- mixed.push(auId);
4297
- }
4298
- pushAuSide(auRows, auId, 0, entry.left || [], meshNames, model, profile);
4299
- pushAuSide(auRows, auId, 1, entry.right || [], meshNames, model, profile);
4300
- pushAuSide(auRows, auId, 2, entry.center || [], meshNames, model, profile);
4301
- }
4302
- const visemeRows = [];
4303
- const visemeMeshNames = getMeshNamesForVisemeProfile(profile);
4304
- const slotCount = getProfileVisemeSlots(profile).length;
4305
- for (let index = 0; index < slotCount; index += 1) {
4306
- for (const bindingTarget of getVisemeBindingTargets(profile, index)) {
4307
- for (const resolved of resolveMorphTargets(model, profile, bindingTarget.morph, visemeMeshNames)) {
4308
- visemeRows.push(
4309
- index,
4310
- Number(resolved.mesh.id),
4311
- Number(resolved.morphTarget.id),
4312
- bindingTarget.weight
4313
- );
4314
- }
3890
+ const profileJson = JSON.stringify(this.profile);
3891
+ const modelJson = JSON.stringify(this.model);
3892
+ if (this.allowEmptyBindings) {
3893
+ this.core.configure(profileJson, modelJson);
3894
+ } else {
3895
+ this.core.configure_with_profile(profileJson, modelJson);
4315
3896
  }
4316
3897
  }
4317
- return {
4318
- auBindings: Float32Array.from(auRows),
4319
- visemeBindings: Float32Array.from(visemeRows),
4320
- mixedAus: Uint32Array.from(mixed)
4321
- };
4322
- }
4323
- function compileBoneBindings(profile, model) {
4324
- const referencedBones = /* @__PURE__ */ new Map();
4325
- const findBone = (nodeKey) => {
4326
- const bone = findBoneDescriptor(profile, model, nodeKey);
4327
- if (bone) referencedBones.set(bone.id, bone);
4328
- return bone;
4329
- };
4330
- const boneSideForAU = (auId, nodeKey) => {
4331
- const side = profile.auToBones?.[auId]?.find((candidate) => candidate.node === nodeKey)?.side;
4332
- if (side === "left") return BONE_SIDE_LEFT;
4333
- if (side === "right") return BONE_SIDE_RIGHT;
4334
- return BONE_SIDE_NONE;
4335
- };
4336
- const compositeRows = [];
4337
- for (const composite of profile.compositeRotations || []) {
4338
- const bone = findBone(composite.node);
4339
- if (!bone) continue;
4340
- const axes = [
4341
- { axis: 1, config: composite.yaw },
4342
- { axis: 0, config: composite.pitch },
4343
- { axis: 2, config: composite.roll }
4344
- ];
4345
- for (const { axis, config } of axes) {
4346
- if (!config) continue;
4347
- const negativeAUs = toAUList(config.negative);
4348
- const positiveAUs = toAUList(config.positive);
4349
- const hasDirectional = negativeAUs.length > 0 && positiveAUs.length > 0;
4350
- const valueRows = [];
4351
- if (hasDirectional) {
4352
- for (const auId of negativeAUs) {
4353
- valueRows.push([auId, AXIS_GROUP_NEGATIVE, boneSideForAU(auId, composite.node)]);
4354
- }
4355
- for (const auId of positiveAUs) {
4356
- valueRows.push([auId, AXIS_GROUP_POSITIVE, boneSideForAU(auId, composite.node)]);
4357
- }
4358
- } else {
4359
- for (const auId of config.aus) {
4360
- valueRows.push([auId, AXIS_GROUP_PLAIN, boneSideForAU(auId, composite.node)]);
4361
- }
4362
- }
4363
- const bindingRows = [];
4364
- const pushBindingRows = (auIds, group) => {
4365
- for (const auId of auIds) {
4366
- const binding = profile.auToBones?.[auId]?.find(
4367
- (candidate) => candidate.node === composite.node
4368
- );
4369
- if (!binding?.maxDegrees) continue;
4370
- const channel = ROTATION_CHANNELS[binding.channel];
4371
- if (channel === void 0) continue;
4372
- bindingRows.push([
4373
- auId,
4374
- group,
4375
- boneSideForAU(auId, composite.node),
4376
- channel,
4377
- binding.scale,
4378
- binding.maxDegrees
4379
- ]);
4380
- }
4381
- };
4382
- pushBindingRows(negativeAUs, AXIS_GROUP_NEGATIVE);
4383
- pushBindingRows(positiveAUs, AXIS_GROUP_POSITIVE);
4384
- pushBindingRows(config.aus, AXIS_GROUP_PLAIN);
4385
- compositeRows.push(
4386
- Number(bone.id),
4387
- axis,
4388
- hasDirectional ? 1 : 0,
4389
- valueRows.length,
4390
- bindingRows.length,
4391
- 0,
4392
- 0,
4393
- 0
4394
- );
4395
- for (const row of valueRows) compositeRows.push(...row);
4396
- for (const row of bindingRows) compositeRows.push(...row);
4397
- }
4398
- }
4399
- const translationRows = [];
4400
- for (const [auIdText, bindings] of Object.entries(profile.auToBones || {})) {
4401
- const auId = Number(auIdText);
4402
- if (Number.isNaN(auId)) continue;
4403
- for (const binding of bindings || []) {
4404
- const channel = TRANSLATION_CHANNELS[binding.channel];
4405
- if (channel === void 0 || binding.maxUnits === void 0) continue;
4406
- const bone = findBone(binding.node);
4407
- if (!bone) continue;
4408
- translationRows.push(auId, Number(bone.id), channel, binding.scale, binding.maxUnits);
4409
- }
4410
- }
4411
- const jawRow = [];
4412
- const jawBinding = findAutoVisemeJawBinding(profile, model);
4413
- if (jawBinding?.maxDegrees) {
4414
- const bone = findBone(jawBinding.node);
4415
- const channel = ROTATION_CHANNELS[jawBinding.channel];
4416
- if (bone && channel !== void 0) {
4417
- jawRow.push(Number(bone.id), channel, jawBinding.scale, jawBinding.maxDegrees);
4418
- }
4419
- }
4420
- const restRows = [];
4421
- for (const bone of referencedBones.values()) {
4422
- const position = bone.restTransform?.position;
4423
- const rotation = bone.restTransform?.rotation;
4424
- restRows.push(
4425
- Number(bone.id),
4426
- position?.x ?? 0,
4427
- position?.y ?? 0,
4428
- position?.z ?? 0,
4429
- rotation?.x ?? 0,
4430
- rotation?.y ?? 0,
4431
- rotation?.z ?? 0,
4432
- rotation?.w ?? 1
4433
- );
4434
- }
4435
- return {
4436
- restTransforms: Float32Array.from(restRows),
4437
- compositeAxes: Float32Array.from(compositeRows),
4438
- translations: Float32Array.from(translationRows),
4439
- jawBinding: Float32Array.from(jawRow),
4440
- visemeJawAmounts: Float32Array.from(getVisemeJawAmounts(profile) ?? [])
4441
- };
4442
- }
4443
- function findBoneDescriptor(profile, model, nodeKey) {
4444
- const configuredName = profile.boneNodes?.[nodeKey] || nodeKey;
4445
- const prefix = profile.bonePrefix ?? "";
4446
- const suffix = profile.boneSuffix ?? "";
4447
- const prefixedName = prefix && !configuredName.startsWith(prefix) ? `${prefix}${configuredName}` : configuredName;
4448
- const fullName = suffix && !prefixedName.endsWith(suffix) ? `${prefixedName}${suffix}` : prefixedName;
4449
- const candidates = /* @__PURE__ */ new Set([nodeKey, configuredName, fullName]);
4450
- return model.bones.find((bone) => candidates.has(bone.name));
4451
- }
4452
- function findAutoVisemeJawBinding(profile, model) {
4453
- const isRotation = (binding) => binding?.channel === "rx" || binding?.channel === "ry" || binding?.channel === "rz";
4454
- const candidates = [
4455
- profile.auToBones?.[103]?.find(isRotation),
4456
- profile.auToBones?.[26]?.find(isRotation)
4457
- ].filter((binding) => !!binding);
4458
- return candidates.find((binding) => !!findBoneDescriptor(profile, model, binding.node)) ?? candidates[0] ?? null;
4459
- }
3898
+ };
4460
3899
  function unpackBoneFrameDelta(values) {
4461
3900
  const stride = PACKED_BONE_FRAME_DELTA_STRIDE;
4462
3901
  const writes = [];
@@ -4497,46 +3936,6 @@ function unpackMorphFrameDelta(values) {
4497
3936
  }
4498
3937
  return writes;
4499
3938
  }
4500
- function pushAuSide(rows, auId, side, morphs, meshNames, model, profile) {
4501
- for (const morph of morphs) {
4502
- for (const resolved of resolveMorphTargets(model, profile, morph, meshNames)) {
4503
- rows.push(
4504
- auId,
4505
- side,
4506
- Number(resolved.mesh.id),
4507
- Number(resolved.morphTarget.id),
4508
- 1
4509
- );
4510
- }
4511
- }
4512
- }
4513
- function resolveMorphTargets(model, profile, morph, meshNames) {
4514
- const result = [];
4515
- for (const meshName of meshNames) {
4516
- const mesh = model.meshes.find((candidate) => candidate.name === meshName);
4517
- if (!mesh) continue;
4518
- const morphTargets = mesh.morphTargetIds.map((id) => model.morphTargets.find((candidate) => candidate.id === id)).filter((target2) => !!target2);
4519
- const target = typeof morph === "number" ? morphTargets.find((candidate) => candidate.hostIndex === morph) : resolveMorphTargetByName2(morphTargets, morph, profile);
4520
- if (target) {
4521
- result.push({ mesh, morphTarget: target });
4522
- }
4523
- }
4524
- return result;
4525
- }
4526
- function resolveMorphTargetByName2(targets, key, profile) {
4527
- const prefix = profile.morphPrefix || "";
4528
- const suffix = profile.morphSuffix || "";
4529
- const fullName = prefix + key + suffix;
4530
- const exact = targets.find((target) => target.name === fullName);
4531
- if (exact) return exact;
4532
- const suffixRegex = profile.suffixPattern ? new RegExp(profile.suffixPattern) : null;
4533
- if (!suffixRegex) return void 0;
4534
- return targets.find((target) => {
4535
- if (!target.name.startsWith(fullName)) return false;
4536
- const candidateSuffix = target.name.slice(fullName.length);
4537
- return candidateSuffix === "" || suffixRegex.test(candidateSuffix);
4538
- });
4539
- }
4540
3939
 
4541
3940
  // src/hair/appearance.ts
4542
3941
  var HAIR_COLOR_PRESETS = {
@@ -5852,7 +5251,7 @@ var CC4_PRESET = {
5852
5251
  };
5853
5252
 
5854
5253
  // src/engines/three/hair/HairPhysicsController.ts
5855
- var clamp012 = (value) => value < 0 ? 0 : value > 1 ? 1 : value;
5254
+ var clamp01 = (value) => value < 0 ? 0 : value > 1 ? 1 : value;
5856
5255
  var HairPhysicsController = class {
5857
5256
  constructor(host) {
5858
5257
  __publicField(this, "host");
@@ -6350,7 +5749,7 @@ var HairPhysicsController = class {
6350
5749
  }
6351
5750
  }
6352
5751
  setMorphOnMeshes(meshNames, morphKey, value) {
6353
- const val = clamp012(value);
5752
+ const val = clamp01(value);
6354
5753
  for (const name of meshNames) {
6355
5754
  const mesh = this.registeredHairObjects.get(name) || this.host.getMeshByName(name);
6356
5755
  if (!mesh) continue;
@@ -6594,9 +5993,9 @@ var HairPhysicsController = class {
6594
5993
  const deltaVertical = vertical - this.lastHeadVertical;
6595
5994
  this.lastHeadHorizontal = horizontal;
6596
5995
  this.lastHeadVertical = vertical;
6597
- const leftWeight = clamp012(deltaHorizontal > 0 ? deltaHorizontal : 0);
6598
- const rightWeight = clamp012(deltaHorizontal < 0 ? -deltaHorizontal : 0);
6599
- const frontWeight = clamp012(deltaVertical > 0 ? deltaVertical : 0);
5996
+ const leftWeight = clamp01(deltaHorizontal > 0 ? deltaHorizontal : 0);
5997
+ const rightWeight = clamp01(deltaHorizontal < 0 ? -deltaHorizontal : 0);
5998
+ const frontWeight = clamp01(deltaVertical > 0 ? deltaVertical : 0);
6600
5999
  const minTrigger = 0.01;
6601
6000
  if (leftWeight <= minTrigger && rightWeight <= minTrigger && frontWeight <= minTrigger) return;
6602
6001
  if (this.impulseClipDirty) {
@@ -7566,7 +6965,7 @@ async function getPresetWithProfile(presetType, profile) {
7566
6965
  var resolvePresetWithOverrides = getPresetWithProfile;
7567
6966
 
7568
6967
  // src/engines/three/Embody.ts
7569
- var deg2rad2 = (d) => d * Math.PI / 180;
6968
+ var deg2rad = (d) => d * Math.PI / 180;
7570
6969
  var X_AXIS2 = new Vector3(1, 0, 0);
7571
6970
  var Y_AXIS2 = new Vector3(0, 1, 0);
7572
6971
  var Z_AXIS2 = new Vector3(0, 0, 1);
@@ -7589,9 +6988,18 @@ function buildAUToCompositeMap(composites) {
7589
6988
  });
7590
6989
  return map;
7591
6990
  }
7592
- function clamp013(x) {
6991
+ function clamp012(x) {
7593
6992
  return x < 0 ? 0 : x > 1 ? 1 : x;
7594
6993
  }
6994
+ var RESOLVED_TRANSITION_HANDLE = {
6995
+ promise: Promise.resolve(),
6996
+ pause: () => {
6997
+ },
6998
+ resume: () => {
6999
+ },
7000
+ cancel: () => {
7001
+ }
7002
+ };
7595
7003
  var _Embody = class _Embody {
7596
7004
  constructor(config = {}, animation) {
7597
7005
  // Optional hook for animation schedulers.
@@ -7635,7 +7043,6 @@ var _Embody = class _Embody {
7635
7043
  __publicField(this, "modelInspector", new ThreeModelInspector());
7636
7044
  __publicField(this, "frameApplier", new ThreeFrameApplier());
7637
7045
  __publicField(this, "modelDescriptor", null);
7638
- __publicField(this, "tsRuntimeCore", null);
7639
7046
  __publicField(this, "wasmRuntimeCore", null);
7640
7047
  __publicField(this, "framePathReady", false);
7641
7048
  // Internal animation loop
@@ -7748,48 +7155,21 @@ var _Embody = class _Embody {
7748
7155
  bindHostNeutralRuntime(inspection) {
7749
7156
  this.modelDescriptor = inspection.descriptor;
7750
7157
  this.frameApplier.setBindings(buildFrameApplierBindings(inspection));
7751
- this.tsRuntimeCore = new TsRuntimeCore({
7158
+ const wasm = requireInitializedEmbodyCore();
7159
+ this.attachWasmCore(wasm);
7160
+ this.wasmRuntimeCore = new WasmRuntimeCore({
7752
7161
  profile: this.config,
7753
- model: inspection.descriptor
7162
+ model: inspection.descriptor,
7163
+ wasm,
7164
+ allowEmptyBindings: true
7754
7165
  });
7755
7166
  this.syncRuntimeCoreState();
7756
7167
  this.framePathReady = true;
7757
- void initEmbodyCore().then((wasm) => {
7758
- if (!this.modelDescriptor) return;
7759
- this.attachWasmCore(wasm);
7760
- this.wasmRuntimeCore = new WasmRuntimeCore({
7761
- profile: this.config,
7762
- model: this.modelDescriptor,
7763
- wasm
7764
- });
7765
- this.syncRuntimeCoreState();
7766
- }).catch(() => {
7767
- this.wasmRuntimeCore = null;
7768
- });
7769
7168
  }
7770
7169
  attachWasmCore(core) {
7771
7170
  this.hairPhysics.setCore(core);
7772
7171
  }
7773
7172
  syncRuntimeCoreState() {
7774
- if (this.tsRuntimeCore) {
7775
- this.tsRuntimeCore.setProfile(this.config);
7776
- if (this.modelDescriptor) {
7777
- this.tsRuntimeCore.setModelDescriptor(this.modelDescriptor);
7778
- }
7779
- for (const [auIdText, value] of Object.entries(this.auValues)) {
7780
- const auId = Number(auIdText);
7781
- if (Number.isNaN(auId)) continue;
7782
- this.tsRuntimeCore.setAU(auId, value, this.auBalances[auId]);
7783
- }
7784
- for (const [auIdText, weight] of Object.entries(this.mixWeights)) {
7785
- const auId = Number(auIdText);
7786
- if (Number.isNaN(auId)) continue;
7787
- this.tsRuntimeCore.setAUMixWeight(auId, weight);
7788
- }
7789
- for (let index = 0; index < this.visemeValues.length; index += 1) {
7790
- this.tsRuntimeCore.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
7791
- }
7792
- }
7793
7173
  if (this.wasmRuntimeCore) {
7794
7174
  this.wasmRuntimeCore.setProfile(this.config);
7795
7175
  if (this.modelDescriptor) {
@@ -7807,7 +7187,7 @@ var _Embody = class _Embody {
7807
7187
  this.wasmRuntimeCore.setAUMixWeight(auId, weight);
7808
7188
  }
7809
7189
  for (let index = 0; index < this.visemeValues.length; index += 1) {
7810
- this.wasmRuntimeCore.setViseme(index, this.visemeValues[index] ?? 0);
7190
+ this.wasmRuntimeCore.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
7811
7191
  }
7812
7192
  }
7813
7193
  }
@@ -7825,25 +7205,13 @@ var _Embody = class _Embody {
7825
7205
  });
7826
7206
  this.modelDescriptor = inspection.descriptor;
7827
7207
  this.frameApplier.setBindings(buildFrameApplierBindings(inspection));
7828
- this.tsRuntimeCore?.setModelDescriptor(inspection.descriptor);
7829
7208
  this.wasmRuntimeCore?.setModelDescriptor(inspection.descriptor);
7830
7209
  }
7831
- applyLiveMorphFrameDelta() {
7832
- if (!this.framePathReady || !this.model) return false;
7833
- if (this.wasmRuntimeCore) {
7834
- this.frameApplier.applyPackedMorphFrameDelta(
7835
- this.wasmRuntimeCore.evaluatePackedMorphFrameDelta()
7836
- );
7837
- return true;
7838
- }
7839
- if (this.tsRuntimeCore) {
7840
- const frame = this.tsRuntimeCore.evaluateFrameDelta();
7841
- this.frameApplier.applyFrameDelta(this.model, {
7842
- morphTargets: frame.morphTargets
7843
- });
7844
- return true;
7845
- }
7846
- return false;
7210
+ applyLiveFrameDelta() {
7211
+ if (!this.framePathReady || !this.model || !this.wasmRuntimeCore) return false;
7212
+ this.frameApplier.applyFrameDelta(this.model, this.wasmRuntimeCore.evaluateFrameDelta());
7213
+ this.pendingCompositeNodes.clear();
7214
+ return true;
7847
7215
  }
7848
7216
  rebuildMorphTargetsCache() {
7849
7217
  this.morphKeyCache.clear();
@@ -7945,6 +7313,11 @@ var _Embody = class _Embody {
7945
7313
  const dtSeconds = Math.max(0, deltaSeconds || 0);
7946
7314
  if (dtSeconds <= 0 || this.isPaused) return;
7947
7315
  this.animation.tick(dtSeconds);
7316
+ const wasmTransitionCount = this.wasmRuntimeCore?.activeTransitionCount() ?? 0;
7317
+ const remainingWasmTransitions = this.wasmRuntimeCore?.update(dtSeconds) ?? 0;
7318
+ if (wasmTransitionCount > 0 || remainingWasmTransitions > 0) {
7319
+ this.applyLiveFrameDelta();
7320
+ }
7948
7321
  this.flushPendingComposites();
7949
7322
  this.animationController.update(dtSeconds);
7950
7323
  this.hairPhysics.update(dtSeconds);
@@ -7979,7 +7352,6 @@ var _Embody = class _Embody {
7979
7352
  this.model = null;
7980
7353
  this.bones = {};
7981
7354
  this.modelDescriptor = null;
7982
- this.tsRuntimeCore = null;
7983
7355
  this.wasmRuntimeCore = null;
7984
7356
  this.framePathReady = false;
7985
7357
  }
@@ -8016,15 +7388,14 @@ var _Embody = class _Embody {
8016
7388
  if (balance !== void 0) {
8017
7389
  this.auBalances[id] = balance;
8018
7390
  }
8019
- this.tsRuntimeCore?.setAU(id, v, balance);
8020
7391
  this.wasmRuntimeCore?.setAU(id, v, balance ?? this.auBalances[id] ?? 0);
8021
- const appliedViaFrame = this.applyLiveMorphFrameDelta();
7392
+ const appliedViaFrame = this.applyLiveFrameDelta();
8022
7393
  if (!appliedViaFrame) {
8023
7394
  const resolvedMorphTargets = this.resolvedAUMorphTargets.get(id);
8024
7395
  const { left: leftKeys, right: rightKeys, center: centerKeys } = this.getAUMorphsBySide(id);
8025
7396
  if (resolvedMorphTargets) {
8026
7397
  const mixWeight = this.isMixedAU(id) ? this.getAUMixWeight(id) : 1;
8027
- const base = clamp013(v) * mixWeight;
7398
+ const base = clamp012(v) * mixWeight;
8028
7399
  const { left: leftVal, right: rightVal } = this.computeSideValues(base, balance);
8029
7400
  if (resolvedMorphTargets.left.length || resolvedMorphTargets.right.length) {
8030
7401
  this.applyMorphTargets(resolvedMorphTargets.left, leftVal);
@@ -8033,7 +7404,7 @@ var _Embody = class _Embody {
8033
7404
  this.applyMorphTargets(resolvedMorphTargets.center, base);
8034
7405
  } else if (leftKeys.length || rightKeys.length || centerKeys.length) {
8035
7406
  const mixWeight = this.isMixedAU(id) ? this.getAUMixWeight(id) : 1;
8036
- const base = clamp013(v) * mixWeight;
7407
+ const base = clamp012(v) * mixWeight;
8037
7408
  const meshNames = this.getMeshNamesForAU(id);
8038
7409
  const { left: leftVal, right: rightVal } = this.computeSideValues(base, balance);
8039
7410
  if (leftKeys.length || rightKeys.length) {
@@ -8052,6 +7423,7 @@ var _Embody = class _Embody {
8052
7423
  }
8053
7424
  }
8054
7425
  }
7426
+ if (appliedViaFrame) return;
8055
7427
  const compositeInfo = this.auToCompositeMap.get(id);
8056
7428
  if (compositeInfo) {
8057
7429
  for (const nodeKey of compositeInfo.nodes) {
@@ -8086,7 +7458,7 @@ var _Embody = class _Embody {
8086
7458
  return this.transitionContinuum(negAU, posAU, continuumValue, durationMs, balance);
8087
7459
  }
8088
7460
  }
8089
- const target = clamp013(to);
7461
+ const target = clamp012(to);
8090
7462
  if (balance !== void 0) {
8091
7463
  this.auBalances[numId] = balance;
8092
7464
  }
@@ -8097,6 +7469,19 @@ var _Embody = class _Embody {
8097
7469
  const base = target * mixWeight;
8098
7470
  const { left: leftVal, right: rightVal } = this.computeSideValues(base, storedBalance);
8099
7471
  this.auValues[numId] = target;
7472
+ if (this.wasmRuntimeCore) {
7473
+ this.wasmRuntimeCore.transitionAU(
7474
+ numId,
7475
+ target,
7476
+ durationMs,
7477
+ balance ?? this.auBalances[numId] ?? Number.NaN
7478
+ );
7479
+ this.update(0);
7480
+ if (durationMs <= 0) {
7481
+ this.applyLiveFrameDelta();
7482
+ }
7483
+ return RESOLVED_TRANSITION_HANDLE;
7484
+ }
8100
7485
  const handles = [];
8101
7486
  const meshNames = this.getMeshNamesForAU(numId);
8102
7487
  if (leftKeys.length || rightKeys.length) {
@@ -8159,6 +7544,17 @@ var _Embody = class _Embody {
8159
7544
  */
8160
7545
  setContinuum(negAU, posAU, continuumValue, balance) {
8161
7546
  const value = Math.max(-1, Math.min(1, continuumValue));
7547
+ this.auValues[negAU] = value < 0 ? Math.abs(value) : 0;
7548
+ this.auValues[posAU] = value > 0 ? value : 0;
7549
+ if (balance !== void 0) {
7550
+ this.auBalances[negAU] = balance;
7551
+ this.auBalances[posAU] = balance;
7552
+ }
7553
+ if (this.wasmRuntimeCore) {
7554
+ this.wasmRuntimeCore.setContinuum(negAU, posAU, value, balance ?? 0);
7555
+ this.applyLiveFrameDelta();
7556
+ return;
7557
+ }
8162
7558
  if (value < 0) {
8163
7559
  this.setAU(posAU, 0, balance);
8164
7560
  this.setAU(negAU, Math.abs(value), balance);
@@ -8184,10 +7580,32 @@ var _Embody = class _Embody {
8184
7580
  */
8185
7581
  transitionContinuum(negAU, posAU, continuumValue, durationMs = 200, balance) {
8186
7582
  const target = Math.max(-1, Math.min(1, continuumValue));
8187
- const driverKey = `continuum_${negAU}_${posAU}`;
8188
7583
  const currentNeg = this.auValues[negAU] ?? 0;
8189
7584
  const currentPos = this.auValues[posAU] ?? 0;
8190
7585
  const currentContinuum = currentPos - currentNeg;
7586
+ this.auValues[negAU] = target < 0 ? Math.abs(target) : 0;
7587
+ this.auValues[posAU] = target > 0 ? target : 0;
7588
+ if (balance !== void 0) {
7589
+ this.auBalances[negAU] = balance;
7590
+ this.auBalances[posAU] = balance;
7591
+ }
7592
+ if (this.wasmRuntimeCore) {
7593
+ if (target < 0) {
7594
+ this.wasmRuntimeCore.transitionAU(posAU, 0, durationMs, balance ?? this.auBalances[posAU] ?? Number.NaN);
7595
+ this.wasmRuntimeCore.transitionAU(negAU, Math.abs(target), durationMs, balance ?? this.auBalances[negAU] ?? Number.NaN);
7596
+ } else if (target > 0) {
7597
+ this.wasmRuntimeCore.transitionAU(negAU, 0, durationMs, balance ?? this.auBalances[negAU] ?? Number.NaN);
7598
+ this.wasmRuntimeCore.transitionAU(posAU, target, durationMs, balance ?? this.auBalances[posAU] ?? Number.NaN);
7599
+ } else {
7600
+ this.wasmRuntimeCore.transitionAU(negAU, 0, durationMs, balance ?? this.auBalances[negAU] ?? Number.NaN);
7601
+ this.wasmRuntimeCore.transitionAU(posAU, 0, durationMs, balance ?? this.auBalances[posAU] ?? Number.NaN);
7602
+ }
7603
+ if (durationMs <= 0) {
7604
+ this.applyLiveFrameDelta();
7605
+ }
7606
+ return RESOLVED_TRANSITION_HANDLE;
7607
+ }
7608
+ const driverKey = `continuum_${negAU}_${posAU}`;
8191
7609
  return this.animation.addTransition(driverKey, currentContinuum, target, durationMs, (value) => this.setContinuum(negAU, posAU, value, balance));
8192
7610
  }
8193
7611
  // ============================================================================
@@ -8269,7 +7687,7 @@ var _Embody = class _Embody {
8269
7687
  this.hairPhysics.refreshMeshSelection();
8270
7688
  }
8271
7689
  setMorph(key, v, meshNamesOrTargets) {
8272
- const val = clamp013(v);
7690
+ const val = clamp012(v);
8273
7691
  if (Array.isArray(meshNamesOrTargets) && meshNamesOrTargets.length > 0 && typeof meshNamesOrTargets[0] === "object" && "infl" in meshNamesOrTargets[0]) {
8274
7692
  const targets2 = meshNamesOrTargets;
8275
7693
  this.applyMorphTargets(targets2, val);
@@ -8281,7 +7699,7 @@ var _Embody = class _Embody {
8281
7699
  this.applyMorphTargets(targets, val);
8282
7700
  }
8283
7701
  setMorphInfluence(index, v, meshNames) {
8284
- const val = clamp013(v);
7702
+ const val = clamp012(v);
8285
7703
  const targets = this.resolveMorphTargetsByIndex(index, meshNames);
8286
7704
  if (targets.length === 0) return;
8287
7705
  this.applyMorphTargets(targets, val);
@@ -8356,21 +7774,21 @@ var _Embody = class _Embody {
8356
7774
  }
8357
7775
  transitionMorph(key, to, durationMs = 120, meshNames) {
8358
7776
  const transitionKey = meshNames?.length ? `morph_${this.getMorphKeyCacheKey(key, meshNames)}` : `morph_${this.getMorphKeyCacheKey(key)}`;
8359
- const target = clamp013(to);
7777
+ const target = clamp012(to);
8360
7778
  const targets = this.resolveMorphTargets(key, meshNames);
8361
7779
  const from = targets.length > 0 ? targets[0].infl[targets[0].idx] ?? 0 : this.getMorphValue(key);
8362
7780
  return this.animation.addTransition(transitionKey, from, target, durationMs, (value) => {
8363
- const val = clamp013(value);
7781
+ const val = clamp012(value);
8364
7782
  this.applyMorphTargets(targets, val);
8365
7783
  });
8366
7784
  }
8367
7785
  transitionMorphInfluence(index, to, durationMs = 120, meshNames) {
8368
7786
  const transitionKey = meshNames?.length ? `morph_${this.getMorphIndexCacheKey(index, meshNames)}` : `morph_${this.getMorphIndexCacheKey(index)}`;
8369
- const target = clamp013(to);
7787
+ const target = clamp012(to);
8370
7788
  const targets = this.resolveMorphTargetsByIndex(index, meshNames);
8371
7789
  const from = targets.length > 0 ? targets[0].infl[targets[0].idx] ?? 0 : this.getMorphValueByIndex(index);
8372
7790
  return this.animation.addTransition(transitionKey, from, target, durationMs, (value) => {
8373
- const val = clamp013(value);
7791
+ const val = clamp012(value);
8374
7792
  this.applyMorphTargets(targets, val);
8375
7793
  });
8376
7794
  }
@@ -8379,7 +7797,7 @@ var _Embody = class _Embody {
8379
7797
  // ============================================================================
8380
7798
  setViseme(visemeIndex, value, jawScale = 1) {
8381
7799
  if (visemeIndex < 0 || visemeIndex >= this.visemeValues.length) return;
8382
- const val = clamp013(value);
7800
+ const val = clamp012(value);
8383
7801
  this.visemeValues[visemeIndex] = val;
8384
7802
  this.visemeJawScales[visemeIndex] = jawScale;
8385
7803
  this.applyVisemeRuntimeState();
@@ -8391,16 +7809,24 @@ var _Embody = class _Embody {
8391
7809
  }, cancel: () => {
8392
7810
  } };
8393
7811
  }
8394
- const target = clamp013(to);
7812
+ const target = clamp012(to);
8395
7813
  const from = this.visemeValues[visemeIndex] ?? 0;
8396
7814
  this.visemeJawScales[visemeIndex] = jawScale;
7815
+ if (this.wasmRuntimeCore) {
7816
+ this.visemeValues[visemeIndex] = target;
7817
+ this.wasmRuntimeCore.transitionViseme(visemeIndex, target, durationMs, jawScale);
7818
+ if (durationMs <= 0) {
7819
+ this.applyLiveFrameDelta();
7820
+ }
7821
+ return RESOLVED_TRANSITION_HANDLE;
7822
+ }
8397
7823
  return this.animation.addTransition(
8398
7824
  `viseme_value_${visemeIndex}`,
8399
7825
  from,
8400
7826
  target,
8401
7827
  durationMs,
8402
7828
  (value) => {
8403
- this.visemeValues[visemeIndex] = clamp013(value);
7829
+ this.visemeValues[visemeIndex] = clamp012(value);
8404
7830
  this.visemeJawScales[visemeIndex] = jawScale;
8405
7831
  this.applyVisemeRuntimeState();
8406
7832
  }
@@ -8425,8 +7851,7 @@ var _Embody = class _Embody {
8425
7851
  // MIX WEIGHT CONTROL
8426
7852
  // ============================================================================
8427
7853
  setAUMixWeight(id, weight) {
8428
- this.mixWeights[id] = clamp013(weight);
8429
- this.tsRuntimeCore?.setAUMixWeight(id, weight);
7854
+ this.mixWeights[id] = clamp012(weight);
8430
7855
  this.wasmRuntimeCore?.setAUMixWeight(id, weight);
8431
7856
  const v = this.auValues[id] ?? 0;
8432
7857
  if (v > 0) this.setAU(id, v);
@@ -8464,9 +7889,10 @@ var _Embody = class _Embody {
8464
7889
  }
8465
7890
  clearTransitions() {
8466
7891
  this.animation.clearTransitions();
7892
+ this.wasmRuntimeCore?.clearTransitions();
8467
7893
  }
8468
7894
  getActiveTransitionCount() {
8469
- return this.animation.getActiveTransitionCount();
7895
+ return this.animation.getActiveTransitionCount() + (this.wasmRuntimeCore?.activeTransitionCount() ?? 0);
8470
7896
  }
8471
7897
  resetToNeutral() {
8472
7898
  this.auValues = {};
@@ -8476,6 +7902,7 @@ var _Embody = class _Embody {
8476
7902
  this.translations = {};
8477
7903
  this.initBoneRotations();
8478
7904
  this.clearTransitions();
7905
+ this.wasmRuntimeCore?.clear();
8479
7906
  const morphTargetsToReset = [];
8480
7907
  for (const m of this.meshes) {
8481
7908
  const infl = m.morphTargetInfluences;
@@ -8654,7 +8081,18 @@ var _Embody = class _Embody {
8654
8081
  this.bones = this.resolveBones(this.model);
8655
8082
  this.missingBoneWarnings.clear();
8656
8083
  this.rebuildMorphTargetsCache();
8657
- this.tsRuntimeCore?.setProfile(this.config);
8084
+ Object.values(this.bones).forEach((entry) => {
8085
+ if (!entry) return;
8086
+ this.frameApplier.applyObjectTransform(entry.obj, {
8087
+ position: { x: entry.basePos.x, y: entry.basePos.y, z: entry.basePos.z },
8088
+ rotation: {
8089
+ x: entry.baseQuat.x,
8090
+ y: entry.baseQuat.y,
8091
+ z: entry.baseQuat.z,
8092
+ w: entry.baseQuat.w
8093
+ }
8094
+ });
8095
+ });
8658
8096
  this.wasmRuntimeCore?.setProfile(this.config);
8659
8097
  this.refreshHostNeutralModelDescriptor();
8660
8098
  }
@@ -8771,20 +8209,20 @@ var _Embody = class _Embody {
8771
8209
  }
8772
8210
  applyVisemeRuntimeState() {
8773
8211
  for (let index = 0; index < this.visemeValues.length; index += 1) {
8774
- this.tsRuntimeCore?.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
8775
- this.wasmRuntimeCore?.setViseme(index, this.visemeValues[index] ?? 0);
8212
+ this.wasmRuntimeCore?.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
8776
8213
  }
8777
- if (!this.applyLiveMorphFrameDelta()) {
8214
+ const appliedViaFrame = this.applyLiveFrameDelta();
8215
+ if (!appliedViaFrame) {
8778
8216
  for (const targets of this.resolvedVisemeTargets) {
8779
8217
  this.frameApplier.resetMorphTargets(targets || []);
8780
8218
  }
8781
8219
  for (let index = 0; index < this.visemeValues.length; index += 1) {
8782
- const value = clamp013(this.visemeValues[index] ?? 0);
8220
+ const value = clamp012(this.visemeValues[index] ?? 0);
8783
8221
  if (value <= 1e-6) continue;
8784
8222
  const targets = this.resolvedVisemeTargets[index] || [];
8785
8223
  for (const target of targets) {
8786
8224
  if (target.idx >= target.infl.length) continue;
8787
- const weighted = clamp013(value * target.weight);
8225
+ const weighted = clamp012(value * target.weight);
8788
8226
  this.frameApplier.applyMorphTargets(
8789
8227
  [target],
8790
8228
  Math.max(target.infl[target.idx] ?? 0, weighted)
@@ -8792,7 +8230,9 @@ var _Embody = class _Embody {
8792
8230
  }
8793
8231
  }
8794
8232
  }
8795
- this.updateBoneRotation(this.getJawBoneNodeKey(), "pitch", this.getActiveVisemeJawAmount());
8233
+ if (!appliedViaFrame) {
8234
+ this.updateBoneRotation(this.getJawBoneNodeKey(), "pitch", this.getActiveVisemeJawAmount());
8235
+ }
8796
8236
  }
8797
8237
  getJawBoneNodeKey() {
8798
8238
  const candidates = [
@@ -8814,7 +8254,7 @@ var _Embody = class _Embody {
8814
8254
  getActiveVisemeJawAmount() {
8815
8255
  let jawAmount = 0;
8816
8256
  for (let index = 0; index < this.visemeValues.length; index += 1) {
8817
- const value = clamp013(this.visemeValues[index] ?? 0);
8257
+ const value = clamp012(this.visemeValues[index] ?? 0);
8818
8258
  if (value <= 1e-6) continue;
8819
8259
  const jawScale = this.visemeJawScales[index] ?? 1;
8820
8260
  if (Math.abs(jawScale) <= 1e-6) continue;
@@ -9097,7 +8537,7 @@ var _Embody = class _Embody {
9097
8537
  return !!(hasMorphs && this.config.auToBones[id]?.length);
9098
8538
  }
9099
8539
  getEffectiveBoneAUValue(auId, nodeKey) {
9100
- const rawValue = clamp013(this.auValues[auId] ?? 0);
8540
+ const rawValue = clamp012(this.auValues[auId] ?? 0);
9101
8541
  if (rawValue <= 1e-6) return 0;
9102
8542
  const binding = this.config.auToBones[auId]?.find((candidate) => candidate.node === nodeKey) ?? null;
9103
8543
  if (!binding?.side) return rawValue;
@@ -9197,7 +8637,7 @@ var _Embody = class _Embody {
9197
8637
  if (config.yaw && rotState.yaw !== 0) {
9198
8638
  const binding = this.getCompositeAxisBindingForNode(nodeKey, config.yaw, rotState.yaw);
9199
8639
  if (binding?.maxDegrees && binding.channel) {
9200
- const radians = deg2rad2(binding.maxDegrees) * Math.abs(rotState.yaw) * binding.scale;
8640
+ const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.yaw) * binding.scale;
9201
8641
  const axis = getAxis(binding.channel);
9202
8642
  const deltaQ = new Quaternion().setFromAxisAngle(axis, radians);
9203
8643
  compositeQ.multiply(deltaQ);
@@ -9206,7 +8646,7 @@ var _Embody = class _Embody {
9206
8646
  if (config.pitch && rotState.pitch !== 0) {
9207
8647
  const binding = this.getCompositeAxisBindingForNode(nodeKey, config.pitch, rotState.pitch);
9208
8648
  if (binding?.maxDegrees && binding.channel) {
9209
- const radians = deg2rad2(binding.maxDegrees) * Math.abs(rotState.pitch) * binding.scale;
8649
+ const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.pitch) * binding.scale;
9210
8650
  const axis = getAxis(binding.channel);
9211
8651
  const deltaQ = new Quaternion().setFromAxisAngle(axis, radians);
9212
8652
  compositeQ.multiply(deltaQ);
@@ -9215,7 +8655,7 @@ var _Embody = class _Embody {
9215
8655
  if (config.roll && rotState.roll !== 0) {
9216
8656
  const binding = this.getCompositeAxisBindingForNode(nodeKey, config.roll, rotState.roll);
9217
8657
  if (binding?.maxDegrees && binding.channel) {
9218
- const radians = deg2rad2(binding.maxDegrees) * Math.abs(rotState.roll) * binding.scale;
8658
+ const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.roll) * binding.scale;
9219
8659
  const axis = getAxis(binding.channel);
9220
8660
  const deltaQ = new Quaternion().setFromAxisAngle(axis, radians);
9221
8661
  compositeQ.multiply(deltaQ);
@@ -10054,11 +9494,11 @@ function applyCharacterModelTransform(model, transform = {}) {
10054
9494
  model.position.set(modelOffset.x ?? 0, modelOffset.y ?? 0, modelOffset.z ?? 0);
10055
9495
  }
10056
9496
  if (modelRotation) {
10057
- const deg2rad3 = Math.PI / 180;
9497
+ const deg2rad2 = Math.PI / 180;
10058
9498
  model.rotation.set(
10059
- (modelRotation.x ?? 0) * deg2rad3,
10060
- (modelRotation.y ?? 0) * deg2rad3,
10061
- (modelRotation.z ?? 0) * deg2rad3
9499
+ (modelRotation.x ?? 0) * deg2rad2,
9500
+ (modelRotation.y ?? 0) * deg2rad2,
9501
+ (modelRotation.z ?? 0) * deg2rad2
10062
9502
  );
10063
9503
  }
10064
9504
  if (modelScale !== void 0 && Number.isFinite(modelScale) && modelScale > 0) {
@@ -15074,7 +14514,7 @@ function computeHumanoidSkeletonTemplateRestBounds(template) {
15074
14514
  }
15075
14515
  const parentPosition = worldPositions.get(bone.parent);
15076
14516
  if (!parentPosition) continue;
15077
- worldPositions.set(bone.name, addVec32(parentPosition, bone.translation));
14517
+ worldPositions.set(bone.name, addVec3(parentPosition, bone.translation));
15078
14518
  unresolved.delete(bone.name);
15079
14519
  resolvedThisPass += 1;
15080
14520
  }
@@ -15135,10 +14575,10 @@ function assertNonEmptyString(value, fieldName) {
15135
14575
  throw new Error(`${fieldName} must be a non-empty string`);
15136
14576
  }
15137
14577
  }
15138
- function addVec32(a, b) {
14578
+ function addVec3(a, b) {
15139
14579
  return [a[0] + b[0], a[1] + b[1], a[2] + b[2]];
15140
14580
  }
15141
14581
 
15142
- export { AU_INFO, AU_MAPPING_CONFIG, AU_MIX_DEFAULTS, AU_MORPH_BINDING_STRIDE, AU_TO_MORPHS, ThreeAnimationSystem as AnimationController, BETTA_FISH_PRESET, BLENDING_MODES, BONE_AU_TO_BINDINGS, ThreeAnimationSystem as BakedAnimationController, CC4_BONES, CC4_BONE_NODES, CC4_BONE_PREFIX, CC4_EYE_MESH_NODES, CC4_MAPPING_SECTIONS, CC4_MESHES, CC4_PRESET, CC4_PROFILE_BONE_BINDINGS, CC4_SUFFIX_PATTERN, CC4_VISEME_SLOTS, CC4_VISEME_SYSTEM_ID, CHARACTER_SCENE_TYPES, CHARACTER_SCENE_TYPE_IDS, COMPOSITE_ROTATIONS, CONTINUUM_LABELS, CONTINUUM_PAIRS_MAP, DEFAULT_AXIS_TO_CHANNEL, DEFAULT_BONE_MAX_DEGREES, DEFAULT_CHARACTER_LIGHTING_PRESETS, DEFAULT_CHARACTER_LIGHTING_PRESET_ID, DEFAULT_CHARACTER_LIGHTING_PRESET_IDS, DEFAULT_CHARACTER_LIGHTING_SETTINGS, DEFAULT_CHARACTER_SCENE_TYPE_ID, DEFAULT_HAIR_COLOR_APPEARANCE, DEFAULT_HAIR_PHYSICS_CONFIG, Embody, FISH_AU_MAPPING_CONFIG, HAIR_COLOR_PRESETS, HUMANOID_SKELETON_TEMPLATES, HairPhysics, HairPhysicsController, JOINT_CONTROL_SECTION, JONATHAN_HUMANOID_SKELETON_TEMPLATE, LIP_SYNC_CONTROL_TO_BINDINGS, MORPH_TO_MESH, RustAnnotationCameraCore, RustCameraFlight, RustCameraOrbit, RustHairPhysics, TEMPLATE_SKELETON_FIT_METADATA_KIND, TEMPLATE_SKELETON_FIT_METADATA_VERSION, TEMPLATE_SKELETON_FIT_STATUSES, TEMPLATE_SKELETON_FIT_VERTICAL_ANCHORS, TEMPLATE_SKELETON_FIT_VERTICAL_AXES, THREE_BLENDING_MODES, ThreeAnimationRuntime, ThreeAnimationSystem, ThreeClipAdapter, ThreeFrameApplier, ThreeModelInspector, TsClipCompiler, TsRuntimeCore, VISEME_JAW_AMOUNTS, VISEME_KEYS, VISEME_MORPH_BINDING_STRIDE, WasmRuntimeCore, analyzeModel, applyAUBoneBindingUpdate, applyBilateralAxisBindingUpdate, applyBoneAxisBindingUpdate, applyCharacterModelTransform, applyCharacterProfileToPreset, buildBoneAuOptions, buildFrameApplierBindings, buildMappingEditorModel, classifyAuAsJointControl, collectMorphMeshes2 as collectMorphMeshes, compileBoneBindings, compileMorphBindings, compileVisemeKeys, composeTemplateSkeletonFitTransform, computeCameraRelativeGazeOffset, computeHumanoidSkeletonTemplateRestBounds, createBilateralBoneAxisAu, createBoneAxisAu, createCharacterHost, createDefaultCharacterLighting, createDefaultCharacterScene, createRustAnnotationCameraCore, createRustHairPhysics, createShadowPlane, createValidationSkeletonFromHumanoidTemplate, detectAnnotationLaterality, detectFacingDirection, disposeCharacterModel, ensureBilateralBoneNodeKeys, ensureBoneNodeKey, extendCharacterConfigWithPreset, extendPresetWithProfile, extendProfileConfigWithPreset, extractFromGLTF, extractHumanoidSkeletonTemplateFromModel, extractLegacyCharacterProfileOverrides, extractModelData, extractProfileOverrides, findFaceCenter, findNodeKeyForBone, formatAxisDirectionLabel, formatAxisLabel, fuzzyNameMatch, generateMappingCorrections, getAUBoneBindingState, getAxisFromChannel, getBilateralAxisBindingState, getBoneAxisBindingState, getDefaultAnnotationLaterality, getHumanoidSkeletonTemplate, getHumanoidSkeletonTemplateBoneNames, getMeshNamesForAUProfile, getMeshNamesForVisemeProfile, getModelForwardDirection, getModelLocalOrbitAngle, getPreset, getPresetWithProfile, getProfilePresetId, getProfileVisemeSlots, getRegionSemanticSide, getSemanticHorizontalSign, getSemanticHorizontalSignForSide, getVisemeBindingTargets, getVisemeJawAmounts, getVisemeSlotIndex, getWorldDirectionForCameraAngle, hasLeftRightMorphs, inferChiralBoneNamePair, inferEyeControlFamily, inferEyeControlScope, isJointControlAuInfo, isMaxDegreesOnlyAxisBindingUpdate, isMixedAU, isPresetCompatible, isTemplateSkeletonFitStatus, loadCharacterModel, mapProviderVisemeToSlot, mergeRegionsByName as mergeCharacterRegionsByName, mergePresetWithProfile, mergeProfileRegionsByName, normalizeCameraAngle, normalizeDefaultCharacterLightingSettings, normalizeHairColorAppearance, numericArrayToNumbers, packHairConfig, packHeadState, parseCharacterModel, passesMarkerCameraAngleGate, resolveBoneAxisChannel, resolveBoneName, resolveBoneNameForNodeKey, resolveBoneNames, resolveContinuumDisplayLabel, resolveFaceCenter, resolvePreset, resolvePresetWithOverrides, resolveProfileFromPreset, resolveRegionCameraAngle, resolveRegionVisibilityCameraAngle, resolveRustEmbeddedProfileView, resolveRustProfileView, resolveVisemeMeshCategory, stripConfiguredBoneAffixes, suggestBestPreset, toModelLocalDirection2 as toModelLocalDirection, toWorldDirection, unpackBoneFrameDelta, unpackHairConfig, unpackHairMorphOutput, unpackHairState, unpackMorphFrameDelta, validateMappingConfig, validateMappings, validateTemplateSkeletonFitMetadata };
14582
+ export { AU_INFO, AU_MAPPING_CONFIG, AU_MIX_DEFAULTS, AU_TO_MORPHS, ThreeAnimationSystem as AnimationController, BETTA_FISH_PRESET, BLENDING_MODES, BONE_AU_TO_BINDINGS, ThreeAnimationSystem as BakedAnimationController, CC4_BONES, CC4_BONE_NODES, CC4_BONE_PREFIX, CC4_EYE_MESH_NODES, CC4_MAPPING_SECTIONS, CC4_MESHES, CC4_PRESET, CC4_PROFILE_BONE_BINDINGS, CC4_SUFFIX_PATTERN, CC4_VISEME_SLOTS, CC4_VISEME_SYSTEM_ID, CHARACTER_SCENE_TYPES, CHARACTER_SCENE_TYPE_IDS, COMPOSITE_ROTATIONS, CONTINUUM_LABELS, CONTINUUM_PAIRS_MAP, DEFAULT_AXIS_TO_CHANNEL, DEFAULT_BONE_MAX_DEGREES, DEFAULT_CHARACTER_LIGHTING_PRESETS, DEFAULT_CHARACTER_LIGHTING_PRESET_ID, DEFAULT_CHARACTER_LIGHTING_PRESET_IDS, DEFAULT_CHARACTER_LIGHTING_SETTINGS, DEFAULT_CHARACTER_SCENE_TYPE_ID, DEFAULT_HAIR_COLOR_APPEARANCE, DEFAULT_HAIR_PHYSICS_CONFIG, Embody, FISH_AU_MAPPING_CONFIG, HAIR_COLOR_PRESETS, HUMANOID_SKELETON_TEMPLATES, HairPhysics, HairPhysicsController, JOINT_CONTROL_SECTION, JONATHAN_HUMANOID_SKELETON_TEMPLATE, LIP_SYNC_CONTROL_TO_BINDINGS, MORPH_TO_MESH, RustAnnotationCameraCore, RustCameraFlight, RustCameraOrbit, RustHairPhysics, TEMPLATE_SKELETON_FIT_METADATA_KIND, TEMPLATE_SKELETON_FIT_METADATA_VERSION, TEMPLATE_SKELETON_FIT_STATUSES, TEMPLATE_SKELETON_FIT_VERTICAL_ANCHORS, TEMPLATE_SKELETON_FIT_VERTICAL_AXES, THREE_BLENDING_MODES, ThreeAnimationRuntime, ThreeAnimationSystem, ThreeClipAdapter, ThreeFrameApplier, ThreeModelInspector, TsClipCompiler, VISEME_JAW_AMOUNTS, VISEME_KEYS, WasmRuntimeCore, analyzeModel, applyAUBoneBindingUpdate, applyBilateralAxisBindingUpdate, applyBoneAxisBindingUpdate, applyCharacterModelTransform, applyCharacterProfileToPreset, buildBoneAuOptions, buildFrameApplierBindings, buildMappingEditorModel, classifyAuAsJointControl, collectMorphMeshes2 as collectMorphMeshes, compileVisemeKeys, composeTemplateSkeletonFitTransform, computeCameraRelativeGazeOffset, computeHumanoidSkeletonTemplateRestBounds, createBilateralBoneAxisAu, createBoneAxisAu, createCharacterHost, createDefaultCharacterLighting, createDefaultCharacterScene, createRustAnnotationCameraCore, createRustHairPhysics, createShadowPlane, createValidationSkeletonFromHumanoidTemplate, detectAnnotationLaterality, detectFacingDirection, disposeCharacterModel, ensureBilateralBoneNodeKeys, ensureBoneNodeKey, extendCharacterConfigWithPreset, extendPresetWithProfile, extendProfileConfigWithPreset, extractFromGLTF, extractHumanoidSkeletonTemplateFromModel, extractLegacyCharacterProfileOverrides, extractModelData, extractProfileOverrides, findFaceCenter, findNodeKeyForBone, formatAxisDirectionLabel, formatAxisLabel, fuzzyNameMatch, generateMappingCorrections, getAUBoneBindingState, getAxisFromChannel, getBilateralAxisBindingState, getBoneAxisBindingState, getDefaultAnnotationLaterality, getHumanoidSkeletonTemplate, getHumanoidSkeletonTemplateBoneNames, getMeshNamesForAUProfile, getMeshNamesForVisemeProfile, getModelForwardDirection, getModelLocalOrbitAngle, getPreset, getPresetWithProfile, getProfilePresetId, getProfileVisemeSlots, getRegionSemanticSide, getSemanticHorizontalSign, getSemanticHorizontalSignForSide, getVisemeBindingTargets, getVisemeJawAmounts, getVisemeSlotIndex, getWorldDirectionForCameraAngle, hasLeftRightMorphs, inferChiralBoneNamePair, inferEyeControlFamily, inferEyeControlScope, isJointControlAuInfo, isMaxDegreesOnlyAxisBindingUpdate, isMixedAU, isPresetCompatible, isTemplateSkeletonFitStatus, loadCharacterModel, mapProviderVisemeToSlot, mergeRegionsByName as mergeCharacterRegionsByName, mergePresetWithProfile, mergeProfileRegionsByName, normalizeCameraAngle, normalizeDefaultCharacterLightingSettings, normalizeHairColorAppearance, numericArrayToNumbers, packHairConfig, packHeadState, parseCharacterModel, passesMarkerCameraAngleGate, resolveBoneAxisChannel, resolveBoneName, resolveBoneNameForNodeKey, resolveBoneNames, resolveContinuumDisplayLabel, resolveFaceCenter, resolvePreset, resolvePresetWithOverrides, resolveProfileFromPreset, resolveRegionCameraAngle, resolveRegionVisibilityCameraAngle, resolveRustEmbeddedProfileView, resolveRustProfileView, resolveVisemeMeshCategory, stripConfiguredBoneAffixes, suggestBestPreset, toModelLocalDirection2 as toModelLocalDirection, toWorldDirection, unpackBoneFrameDelta, unpackHairConfig, unpackHairMorphOutput, unpackHairState, unpackMorphFrameDelta, validateMappingConfig, validateMappings, validateTemplateSkeletonFitMetadata };
15143
14583
  //# sourceMappingURL=index.js.map
15144
14584
  //# sourceMappingURL=index.js.map