@lovelace_lol/embody 0.0.5 → 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/three.js CHANGED
@@ -1,5 +1,5 @@
1
1
  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';
2
- import { initEmbodyCore } from '@lovelace_lol/embody/wasm';
2
+ import { initEmbodyCore, requireInitializedEmbodyCore } from '@lovelace_lol/embody/wasm';
3
3
  import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js';
4
4
  import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
5
5
  import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js';
@@ -3509,410 +3509,6 @@ function getBlendingName(value) {
3509
3509
  return "Normal";
3510
3510
  }
3511
3511
 
3512
- // src/core/TsRuntimeCore.ts
3513
- var identityQuat = { x: 0, y: 0, z: 0, w: 1 };
3514
- function isRotationBoneBinding2(binding) {
3515
- return binding?.channel === "rx" || binding?.channel === "ry" || binding?.channel === "rz";
3516
- }
3517
- var TsRuntimeCore = class {
3518
- constructor(options) {
3519
- __publicField(this, "profile");
3520
- __publicField(this, "model");
3521
- __publicField(this, "auValues", {});
3522
- __publicField(this, "auBalances", {});
3523
- __publicField(this, "visemeValues");
3524
- __publicField(this, "visemeJawScales");
3525
- __publicField(this, "mixWeights");
3526
- this.profile = options.profile;
3527
- this.model = options.model;
3528
- this.visemeValues = new Array(getProfileVisemeSlots(this.profile).length).fill(0);
3529
- this.visemeJawScales = new Array(this.visemeValues.length).fill(1);
3530
- this.mixWeights = { ...this.profile.auMixDefaults };
3531
- }
3532
- setProfile(profile) {
3533
- this.profile = profile;
3534
- this.visemeValues = new Array(getProfileVisemeSlots(this.profile).length).fill(0);
3535
- this.visemeJawScales = new Array(this.visemeValues.length).fill(1);
3536
- this.mixWeights = { ...this.profile.auMixDefaults };
3537
- }
3538
- setModelDescriptor(model) {
3539
- this.model = model;
3540
- }
3541
- setAU(id, value, balance) {
3542
- if (value < 0 && this.profile.continuumPairs) {
3543
- const pairInfo = this.profile.continuumPairs[id];
3544
- if (pairInfo) {
3545
- const negAU = pairInfo.isNegative ? id : pairInfo.pairId;
3546
- const posAU = pairInfo.isNegative ? pairInfo.pairId : id;
3547
- this.setContinuum(negAU, posAU, pairInfo.isNegative ? -value : value, balance);
3548
- return;
3549
- }
3550
- }
3551
- this.auValues[id] = clamp01(value);
3552
- if (balance !== void 0) {
3553
- this.auBalances[id] = clampBalance2(balance);
3554
- }
3555
- }
3556
- getAU(id) {
3557
- return this.auValues[id] ?? 0;
3558
- }
3559
- setContinuum(negAU, posAU, continuumValue, balance) {
3560
- const value = Math.max(-1, Math.min(1, continuumValue));
3561
- if (value < 0) {
3562
- this.setAU(posAU, 0, balance);
3563
- this.setAU(negAU, Math.abs(value), balance);
3564
- return;
3565
- }
3566
- if (value > 0) {
3567
- this.setAU(negAU, 0, balance);
3568
- this.setAU(posAU, value, balance);
3569
- return;
3570
- }
3571
- this.setAU(negAU, 0, balance);
3572
- this.setAU(posAU, 0, balance);
3573
- }
3574
- setViseme(visemeIndex, value, jawScale = 1) {
3575
- if (visemeIndex < 0 || visemeIndex >= this.visemeValues.length) return;
3576
- this.visemeValues[visemeIndex] = clamp01(value);
3577
- this.visemeJawScales[visemeIndex] = jawScale;
3578
- }
3579
- setVisemeById(slotId, value, jawScale = 1) {
3580
- const index = getVisemeSlotIndex(this.profile, slotId);
3581
- if (index < 0) return;
3582
- this.setViseme(index, value, jawScale);
3583
- }
3584
- setAUMixWeight(id, weight) {
3585
- this.mixWeights[id] = clamp01(weight);
3586
- }
3587
- evaluateFrameDelta(deltaSeconds) {
3588
- const morphWrites = /* @__PURE__ */ new Map();
3589
- this.collectAUWrites(morphWrites);
3590
- this.collectVisemeWrites(morphWrites);
3591
- return {
3592
- deltaSeconds,
3593
- morphTargets: Array.from(morphWrites.values()),
3594
- bones: this.collectBoneWrites()
3595
- };
3596
- }
3597
- collectAUWrites(morphWrites) {
3598
- for (const [auIdText, entry] of Object.entries(this.profile.auToMorphs || {})) {
3599
- const auId = Number(auIdText);
3600
- if (Number.isNaN(auId) || !entry) continue;
3601
- const mixWeight = this.isMixedAU(auId) ? this.getAUMixWeight(auId) : 1;
3602
- const base = clamp01(this.auValues[auId] ?? 0) * mixWeight;
3603
- const { left, right } = computeSideValues(base, this.auBalances[auId]);
3604
- const meshNames = getMeshNamesForAUProfile(this.profile, auId);
3605
- for (const morph of entry.left || []) {
3606
- this.addMorphWrites(morphWrites, morph, meshNames, left);
3607
- }
3608
- for (const morph of entry.right || []) {
3609
- this.addMorphWrites(morphWrites, morph, meshNames, right);
3610
- }
3611
- for (const morph of entry.center || []) {
3612
- this.addMorphWrites(morphWrites, morph, meshNames, base);
3613
- }
3614
- }
3615
- }
3616
- collectVisemeWrites(morphWrites) {
3617
- const meshNames = getMeshNamesForVisemeProfile(this.profile);
3618
- const localMax = /* @__PURE__ */ new Map();
3619
- for (let index = 0; index < this.visemeValues.length; index += 1) {
3620
- const value = clamp01(this.visemeValues[index] ?? 0);
3621
- for (const bindingTarget of getVisemeBindingTargets(this.profile, index)) {
3622
- const weighted = clamp01(value * bindingTarget.weight);
3623
- for (const resolved of this.resolveMorphTargets(bindingTarget.morph, meshNames)) {
3624
- const key = morphWriteKey(resolved.mesh.id, resolved.morphTarget.id);
3625
- const existing = localMax.get(key);
3626
- if (!existing || weighted > existing.value) {
3627
- localMax.set(key, {
3628
- meshId: resolved.mesh.id,
3629
- morphTargetId: resolved.morphTarget.id,
3630
- value: weighted,
3631
- mode: "absolute"
3632
- });
3633
- }
3634
- }
3635
- }
3636
- }
3637
- for (const [key, write] of localMax) {
3638
- const existing = morphWrites.get(key);
3639
- if (!existing || write.value > existing.value) {
3640
- morphWrites.set(key, write);
3641
- }
3642
- }
3643
- }
3644
- collectBoneWrites() {
3645
- const writes = [];
3646
- const rotations = this.computeRotationState();
3647
- for (const composite of this.profile.compositeRotations || []) {
3648
- const bone = this.findBoneDescriptor(composite.node);
3649
- if (!bone) continue;
3650
- const transform = this.evaluateCompositeTransform(bone, composite, rotations[composite.node]);
3651
- if (transform) {
3652
- writes.push({
3653
- boneId: bone.id,
3654
- transform,
3655
- mode: "absolute",
3656
- space: "local"
3657
- });
3658
- }
3659
- }
3660
- for (const [nodeKey, translation] of Object.entries(this.computeTranslations())) {
3661
- const bone = this.findBoneDescriptor(nodeKey);
3662
- if (!bone) continue;
3663
- const position = addVec3(bone.restTransform?.position, translation);
3664
- upsertBoneWrite(writes, bone.id, { position });
3665
- }
3666
- const jawAmount = this.getActiveVisemeJawAmount();
3667
- const jawBinding = this.findAutoVisemeJawBinding();
3668
- const jawBone = jawBinding ? this.findBoneDescriptor(jawBinding.node) : void 0;
3669
- if (jawBone && jawBinding?.maxDegrees && jawBinding.channel) {
3670
- const current = writes.find((write) => write.boneId === jawBone.id);
3671
- if (jawAmount > 1e-6 || !current?.transform.rotation) {
3672
- const rest = jawBone.restTransform?.rotation ?? identityQuat;
3673
- const rotation = jawAmount > 1e-6 ? multiplyQuat(
3674
- rest,
3675
- quatFromChannel(jawBinding.channel, deg2rad(jawBinding.maxDegrees) * jawAmount * jawBinding.scale)
3676
- ) : rest;
3677
- upsertBoneWrite(writes, jawBone.id, { rotation });
3678
- }
3679
- }
3680
- return writes;
3681
- }
3682
- computeRotationState() {
3683
- const rotations = {};
3684
- for (const composite of this.profile.compositeRotations || []) {
3685
- rotations[composite.node] = {
3686
- pitch: this.getCompositeAxisValueForNode(composite.node, composite.pitch),
3687
- yaw: this.getCompositeAxisValueForNode(composite.node, composite.yaw),
3688
- roll: this.getCompositeAxisValueForNode(composite.node, composite.roll)
3689
- };
3690
- }
3691
- return rotations;
3692
- }
3693
- evaluateCompositeTransform(bone, composite, state) {
3694
- if (!state) return null;
3695
- let rotation = bone.restTransform?.rotation ?? identityQuat;
3696
- const applyAxis = (axisConfig, direction) => {
3697
- if (!axisConfig || Math.abs(direction) <= 1e-6) return;
3698
- const binding = getCompositeAxisBinding(
3699
- composite.node,
3700
- axisConfig,
3701
- direction,
3702
- (auId) => this.getEffectiveBoneAUValue(auId, composite.node),
3703
- this.profile.auToBones
3704
- );
3705
- if (!binding?.maxDegrees || !binding.channel) return;
3706
- rotation = multiplyQuat(
3707
- rotation,
3708
- quatFromChannel(binding.channel, deg2rad(binding.maxDegrees) * Math.abs(direction) * binding.scale)
3709
- );
3710
- };
3711
- applyAxis(composite.yaw, state.yaw);
3712
- applyAxis(composite.pitch, state.pitch);
3713
- applyAxis(composite.roll, state.roll);
3714
- return { rotation };
3715
- }
3716
- computeTranslations() {
3717
- const translations = {};
3718
- for (const [auIdText, bindings] of Object.entries(this.profile.auToBones || {})) {
3719
- const auId = Number(auIdText);
3720
- if (Number.isNaN(auId)) continue;
3721
- const value = clamp01(this.auValues[auId] ?? 0);
3722
- for (const binding of bindings || []) {
3723
- if (binding.channel !== "tx" && binding.channel !== "ty" && binding.channel !== "tz") continue;
3724
- if (binding.maxUnits === void 0) continue;
3725
- const current = translations[binding.node] ?? { x: 0, y: 0, z: 0 };
3726
- translations[binding.node] = current;
3727
- if (value <= 1e-6) continue;
3728
- const offset = clampSigned(value * binding.scale) * binding.maxUnits;
3729
- translations[binding.node] = {
3730
- x: binding.channel === "tx" ? offset : current.x,
3731
- y: binding.channel === "ty" ? offset : current.y,
3732
- z: binding.channel === "tz" ? offset : current.z
3733
- };
3734
- }
3735
- }
3736
- return translations;
3737
- }
3738
- addMorphWrites(morphWrites, morph, meshNames, value) {
3739
- for (const resolved of this.resolveMorphTargets(morph, meshNames)) {
3740
- const key = morphWriteKey(resolved.mesh.id, resolved.morphTarget.id);
3741
- const existing = morphWrites.get(key);
3742
- if (existing && existing.value >= value) continue;
3743
- morphWrites.set(key, {
3744
- meshId: resolved.mesh.id,
3745
- morphTargetId: resolved.morphTarget.id,
3746
- value,
3747
- mode: "absolute"
3748
- });
3749
- }
3750
- }
3751
- resolveMorphTargets(morph, meshNames) {
3752
- const result = [];
3753
- for (const meshName of meshNames) {
3754
- const mesh = this.model.meshes.find((candidate) => candidate.name === meshName);
3755
- if (!mesh) continue;
3756
- const morphTargets = mesh.morphTargetIds.map((id) => this.model.morphTargets.find((candidate) => candidate.id === id)).filter((target2) => !!target2);
3757
- const target = typeof morph === "number" ? morphTargets.find((candidate) => candidate.hostIndex === morph) : resolveMorphTargetByName(morphTargets, morph, this.profile);
3758
- if (target) {
3759
- result.push({ mesh, morphTarget: target });
3760
- }
3761
- }
3762
- return result;
3763
- }
3764
- findBoneDescriptor(nodeKey) {
3765
- const configuredName = this.profile.boneNodes[nodeKey] || nodeKey;
3766
- const prefix = this.profile.bonePrefix ?? "";
3767
- const suffix = this.profile.boneSuffix ?? "";
3768
- const prefixedName = prefix && !configuredName.startsWith(prefix) ? `${prefix}${configuredName}` : configuredName;
3769
- const fullName = suffix && !prefixedName.endsWith(suffix) ? `${prefixedName}${suffix}` : prefixedName;
3770
- const candidates = /* @__PURE__ */ new Set([nodeKey, configuredName, fullName]);
3771
- return this.model.bones.find((bone) => candidates.has(bone.name));
3772
- }
3773
- findAutoVisemeJawBinding() {
3774
- const candidates = [
3775
- this.profile.auToBones[103]?.find(isRotationBoneBinding2),
3776
- this.profile.auToBones[26]?.find(isRotationBoneBinding2)
3777
- ].filter((binding) => !!binding);
3778
- return candidates.find((binding) => !!this.findBoneDescriptor(binding.node)) ?? candidates[0] ?? null;
3779
- }
3780
- getActiveVisemeJawAmount() {
3781
- const jawAmounts = getVisemeJawAmounts(this.profile) ?? [];
3782
- let jawAmount = 0;
3783
- for (let index = 0; index < this.visemeValues.length; index += 1) {
3784
- const value = clamp01(this.visemeValues[index] ?? 0);
3785
- if (value <= 1e-6) continue;
3786
- const jawScale = this.visemeJawScales[index] ?? 1;
3787
- if (Math.abs(jawScale) <= 1e-6) continue;
3788
- jawAmount = Math.max(jawAmount, (jawAmounts[index] ?? 0) * value * jawScale);
3789
- }
3790
- return jawAmount;
3791
- }
3792
- getCompositeAxisValueForNode(nodeKey, axisConfig) {
3793
- return getCompositeAxisValue(axisConfig, (auId) => this.getEffectiveBoneAUValue(auId, nodeKey));
3794
- }
3795
- getEffectiveBoneAUValue(auId, nodeKey) {
3796
- const rawValue = clamp01(this.auValues[auId] ?? 0);
3797
- if (rawValue <= 1e-6) return 0;
3798
- const binding = this.profile.auToBones[auId]?.find((candidate) => candidate.node === nodeKey) ?? null;
3799
- if (!binding?.side) return rawValue;
3800
- return rawValue * getSideScale2(this.auBalances[auId] ?? 0, binding.side);
3801
- }
3802
- getAUMixWeight(auId) {
3803
- return this.mixWeights[auId] ?? this.profile.auMixDefaults?.[auId] ?? 1;
3804
- }
3805
- isMixedAU(auId) {
3806
- const morphs = this.profile.auToMorphs[auId];
3807
- const hasMorphs = !!(morphs?.left?.length || morphs?.right?.length || morphs?.center?.length);
3808
- return !!(hasMorphs && this.profile.auToBones[auId]?.length);
3809
- }
3810
- };
3811
- function resolveMorphTargetByName(targets, key, profile) {
3812
- const prefix = profile.morphPrefix || "";
3813
- const suffix = profile.morphSuffix || "";
3814
- const fullName = prefix + key + suffix;
3815
- const exact = targets.find((target) => target.name === fullName);
3816
- if (exact) return exact;
3817
- const suffixRegex = profile.suffixPattern ? new RegExp(profile.suffixPattern) : null;
3818
- if (!suffixRegex) return void 0;
3819
- return targets.find((target) => {
3820
- if (!target.name.startsWith(fullName)) return false;
3821
- const candidateSuffix = target.name.slice(fullName.length);
3822
- return candidateSuffix === "" || suffixRegex.test(candidateSuffix);
3823
- });
3824
- }
3825
- function computeSideValues(base, balance) {
3826
- const b = clampBalance2(balance ?? 0);
3827
- if (b === 0) return { left: base, right: base };
3828
- if (b < 0) return { left: base, right: base * (1 + b) };
3829
- return { left: base * (1 - b), right: base };
3830
- }
3831
- function getSideScale2(balance, side) {
3832
- if (side !== "left" && side !== "right") return 1;
3833
- const b = clampBalance2(balance);
3834
- if (side === "left") return b > 0 ? 1 - b : 1;
3835
- return b < 0 ? 1 + b : 1;
3836
- }
3837
- function addVec3(base, offset) {
3838
- return {
3839
- x: (base?.x ?? 0) + offset.x,
3840
- y: (base?.y ?? 0) + offset.y,
3841
- z: (base?.z ?? 0) + offset.z
3842
- };
3843
- }
3844
- function upsertBoneWrite(writes, boneId2, transform) {
3845
- const existingIndex = writes.findIndex((write) => write.boneId === boneId2);
3846
- if (existingIndex >= 0) {
3847
- const existing = writes[existingIndex];
3848
- writes[existingIndex] = {
3849
- ...existing,
3850
- transform: {
3851
- ...existing.transform,
3852
- ...transform
3853
- }
3854
- };
3855
- return;
3856
- }
3857
- writes.push({
3858
- boneId: boneId2,
3859
- transform,
3860
- mode: "absolute",
3861
- space: "local"
3862
- });
3863
- }
3864
- function quatFromChannel(channel, radians) {
3865
- if (channel === "rx") return quatFromAxis({ x: 1, y: 0, z: 0 }, radians);
3866
- if (channel === "ry") return quatFromAxis({ x: 0, y: 1, z: 0 }, radians);
3867
- return quatFromAxis({ x: 0, y: 0, z: 1 }, radians);
3868
- }
3869
- function quatFromAxis(axis, radians) {
3870
- const half = radians / 2;
3871
- const s = Math.sin(half);
3872
- return normalizeQuat({
3873
- x: axis.x * s,
3874
- y: axis.y * s,
3875
- z: axis.z * s,
3876
- w: Math.cos(half)
3877
- });
3878
- }
3879
- function multiplyQuat(a, b) {
3880
- return normalizeQuat({
3881
- x: a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
3882
- y: a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
3883
- z: a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
3884
- w: a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z
3885
- });
3886
- }
3887
- function normalizeQuat(q) {
3888
- const len = Math.hypot(q.x, q.y, q.z, q.w);
3889
- if (len <= 1e-12) return identityQuat;
3890
- return {
3891
- x: q.x / len,
3892
- y: q.y / len,
3893
- z: q.z / len,
3894
- w: q.w / len
3895
- };
3896
- }
3897
- function deg2rad(degrees) {
3898
- return degrees * Math.PI / 180;
3899
- }
3900
- function clamp01(value) {
3901
- if (!Number.isFinite(value)) return 0;
3902
- return value < 0 ? 0 : value > 1 ? 1 : value;
3903
- }
3904
- function clampSigned(value) {
3905
- if (!Number.isFinite(value)) return 0;
3906
- return value < -1 ? -1 : value > 1 ? 1 : value;
3907
- }
3908
- function clampBalance2(value) {
3909
- if (!Number.isFinite(value)) return 0;
3910
- return Math.max(-1, Math.min(1, value));
3911
- }
3912
- function morphWriteKey(meshId2, morphTargetId2) {
3913
- return `${meshId2}:${morphTargetId2}`;
3914
- }
3915
-
3916
3512
  // src/core/contracts/abi.ts
3917
3513
  var PACKED_MORPH_FRAME_DELTA_STRIDE = 4;
3918
3514
  var PACKED_BONE_FRAME_DELTA_STRIDE = 9;
@@ -3924,11 +3520,13 @@ var WasmRuntimeCore = class {
3924
3520
  constructor(options) {
3925
3521
  __publicField(this, "wasm");
3926
3522
  __publicField(this, "core");
3523
+ __publicField(this, "allowEmptyBindings");
3927
3524
  __publicField(this, "profile");
3928
3525
  __publicField(this, "model");
3929
3526
  this.wasm = options.wasm;
3930
3527
  this.profile = options.profile;
3931
3528
  this.model = options.model;
3529
+ this.allowEmptyBindings = options.allowEmptyBindings ?? false;
3932
3530
  const RuntimeCtor = options.wasm.RuntimeCore;
3933
3531
  if (!RuntimeCtor) {
3934
3532
  throw new Error("Embody Wasm module does not export RuntimeCore");
@@ -3947,6 +3545,24 @@ var WasmRuntimeCore = class {
3947
3545
  setAU(id, value, balance = 0) {
3948
3546
  this.core.set_au(id >>> 0, value, balance);
3949
3547
  }
3548
+ setContinuum(negativeAU, positiveAU, value, balance = 0) {
3549
+ this.core.set_continuum(negativeAU >>> 0, positiveAU >>> 0, value, balance);
3550
+ }
3551
+ transitionAU(id, to, durationMs, balance = Number.NaN) {
3552
+ this.core.transition_au(id >>> 0, to, durationMs, balance);
3553
+ }
3554
+ transitionViseme(visemeIndex, to, durationMs, jawScale = 1) {
3555
+ this.core.transition_viseme(visemeIndex >>> 0, to, durationMs, jawScale);
3556
+ }
3557
+ update(deltaSeconds) {
3558
+ return this.core.update(deltaSeconds);
3559
+ }
3560
+ activeTransitionCount() {
3561
+ return this.core.active_transition_count();
3562
+ }
3563
+ clearTransitions() {
3564
+ this.core.clear_transitions();
3565
+ }
3950
3566
  getAU(id) {
3951
3567
  return this.core.get_au(id >>> 0);
3952
3568
  }
@@ -3982,7 +3598,13 @@ var WasmRuntimeCore = class {
3982
3598
  };
3983
3599
  }
3984
3600
  reloadBindings() {
3985
- this.core.configure_with_profile(JSON.stringify(this.profile), JSON.stringify(this.model));
3601
+ const profileJson = JSON.stringify(this.profile);
3602
+ const modelJson = JSON.stringify(this.model);
3603
+ if (this.allowEmptyBindings) {
3604
+ this.core.configure(profileJson, modelJson);
3605
+ } else {
3606
+ this.core.configure_with_profile(profileJson, modelJson);
3607
+ }
3986
3608
  }
3987
3609
  };
3988
3610
  function unpackBoneFrameDelta(values) {
@@ -5331,7 +4953,7 @@ var CC4_PRESET = {
5331
4953
  };
5332
4954
 
5333
4955
  // src/engines/three/hair/HairPhysicsController.ts
5334
- var clamp012 = (value) => value < 0 ? 0 : value > 1 ? 1 : value;
4956
+ var clamp01 = (value) => value < 0 ? 0 : value > 1 ? 1 : value;
5335
4957
  var HairPhysicsController = class {
5336
4958
  constructor(host) {
5337
4959
  __publicField(this, "host");
@@ -5829,7 +5451,7 @@ var HairPhysicsController = class {
5829
5451
  }
5830
5452
  }
5831
5453
  setMorphOnMeshes(meshNames, morphKey, value) {
5832
- const val = clamp012(value);
5454
+ const val = clamp01(value);
5833
5455
  for (const name of meshNames) {
5834
5456
  const mesh = this.registeredHairObjects.get(name) || this.host.getMeshByName(name);
5835
5457
  if (!mesh) continue;
@@ -6073,9 +5695,9 @@ var HairPhysicsController = class {
6073
5695
  const deltaVertical = vertical - this.lastHeadVertical;
6074
5696
  this.lastHeadHorizontal = horizontal;
6075
5697
  this.lastHeadVertical = vertical;
6076
- const leftWeight = clamp012(deltaHorizontal > 0 ? deltaHorizontal : 0);
6077
- const rightWeight = clamp012(deltaHorizontal < 0 ? -deltaHorizontal : 0);
6078
- const frontWeight = clamp012(deltaVertical > 0 ? deltaVertical : 0);
5698
+ const leftWeight = clamp01(deltaHorizontal > 0 ? deltaHorizontal : 0);
5699
+ const rightWeight = clamp01(deltaHorizontal < 0 ? -deltaHorizontal : 0);
5700
+ const frontWeight = clamp01(deltaVertical > 0 ? deltaVertical : 0);
6079
5701
  const minTrigger = 0.01;
6080
5702
  if (leftWeight <= minTrigger && rightWeight <= minTrigger && frontWeight <= minTrigger) return;
6081
5703
  if (this.impulseClipDirty) {
@@ -7041,7 +6663,7 @@ async function getPresetWithProfile(presetType, profile) {
7041
6663
  }
7042
6664
 
7043
6665
  // src/engines/three/Embody.ts
7044
- var deg2rad2 = (d) => d * Math.PI / 180;
6666
+ var deg2rad = (d) => d * Math.PI / 180;
7045
6667
  var X_AXIS2 = new Vector3(1, 0, 0);
7046
6668
  var Y_AXIS2 = new Vector3(0, 1, 0);
7047
6669
  var Z_AXIS2 = new Vector3(0, 0, 1);
@@ -7064,9 +6686,18 @@ function buildAUToCompositeMap(composites) {
7064
6686
  });
7065
6687
  return map;
7066
6688
  }
7067
- function clamp013(x) {
6689
+ function clamp012(x) {
7068
6690
  return x < 0 ? 0 : x > 1 ? 1 : x;
7069
6691
  }
6692
+ var RESOLVED_TRANSITION_HANDLE = {
6693
+ promise: Promise.resolve(),
6694
+ pause: () => {
6695
+ },
6696
+ resume: () => {
6697
+ },
6698
+ cancel: () => {
6699
+ }
6700
+ };
7070
6701
  var _Embody = class _Embody {
7071
6702
  constructor(config = {}, animation) {
7072
6703
  // Optional hook for animation schedulers.
@@ -7110,7 +6741,6 @@ var _Embody = class _Embody {
7110
6741
  __publicField(this, "modelInspector", new ThreeModelInspector());
7111
6742
  __publicField(this, "frameApplier", new ThreeFrameApplier());
7112
6743
  __publicField(this, "modelDescriptor", null);
7113
- __publicField(this, "tsRuntimeCore", null);
7114
6744
  __publicField(this, "wasmRuntimeCore", null);
7115
6745
  __publicField(this, "framePathReady", false);
7116
6746
  // Internal animation loop
@@ -7223,48 +6853,21 @@ var _Embody = class _Embody {
7223
6853
  bindHostNeutralRuntime(inspection) {
7224
6854
  this.modelDescriptor = inspection.descriptor;
7225
6855
  this.frameApplier.setBindings(buildFrameApplierBindings(inspection));
7226
- this.tsRuntimeCore = new TsRuntimeCore({
6856
+ const wasm = requireInitializedEmbodyCore();
6857
+ this.attachWasmCore(wasm);
6858
+ this.wasmRuntimeCore = new WasmRuntimeCore({
7227
6859
  profile: this.config,
7228
- model: inspection.descriptor
6860
+ model: inspection.descriptor,
6861
+ wasm,
6862
+ allowEmptyBindings: true
7229
6863
  });
7230
6864
  this.syncRuntimeCoreState();
7231
6865
  this.framePathReady = true;
7232
- void initEmbodyCore().then((wasm) => {
7233
- if (!this.modelDescriptor) return;
7234
- this.attachWasmCore(wasm);
7235
- this.wasmRuntimeCore = new WasmRuntimeCore({
7236
- profile: this.config,
7237
- model: this.modelDescriptor,
7238
- wasm
7239
- });
7240
- this.syncRuntimeCoreState();
7241
- }).catch(() => {
7242
- this.wasmRuntimeCore = null;
7243
- });
7244
6866
  }
7245
6867
  attachWasmCore(core) {
7246
6868
  this.hairPhysics.setCore(core);
7247
6869
  }
7248
6870
  syncRuntimeCoreState() {
7249
- if (this.tsRuntimeCore) {
7250
- this.tsRuntimeCore.setProfile(this.config);
7251
- if (this.modelDescriptor) {
7252
- this.tsRuntimeCore.setModelDescriptor(this.modelDescriptor);
7253
- }
7254
- for (const [auIdText, value] of Object.entries(this.auValues)) {
7255
- const auId = Number(auIdText);
7256
- if (Number.isNaN(auId)) continue;
7257
- this.tsRuntimeCore.setAU(auId, value, this.auBalances[auId]);
7258
- }
7259
- for (const [auIdText, weight] of Object.entries(this.mixWeights)) {
7260
- const auId = Number(auIdText);
7261
- if (Number.isNaN(auId)) continue;
7262
- this.tsRuntimeCore.setAUMixWeight(auId, weight);
7263
- }
7264
- for (let index = 0; index < this.visemeValues.length; index += 1) {
7265
- this.tsRuntimeCore.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
7266
- }
7267
- }
7268
6871
  if (this.wasmRuntimeCore) {
7269
6872
  this.wasmRuntimeCore.setProfile(this.config);
7270
6873
  if (this.modelDescriptor) {
@@ -7282,7 +6885,7 @@ var _Embody = class _Embody {
7282
6885
  this.wasmRuntimeCore.setAUMixWeight(auId, weight);
7283
6886
  }
7284
6887
  for (let index = 0; index < this.visemeValues.length; index += 1) {
7285
- this.wasmRuntimeCore.setViseme(index, this.visemeValues[index] ?? 0);
6888
+ this.wasmRuntimeCore.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
7286
6889
  }
7287
6890
  }
7288
6891
  }
@@ -7300,25 +6903,13 @@ var _Embody = class _Embody {
7300
6903
  });
7301
6904
  this.modelDescriptor = inspection.descriptor;
7302
6905
  this.frameApplier.setBindings(buildFrameApplierBindings(inspection));
7303
- this.tsRuntimeCore?.setModelDescriptor(inspection.descriptor);
7304
6906
  this.wasmRuntimeCore?.setModelDescriptor(inspection.descriptor);
7305
6907
  }
7306
- applyLiveMorphFrameDelta() {
7307
- if (!this.framePathReady || !this.model) return false;
7308
- if (this.wasmRuntimeCore) {
7309
- this.frameApplier.applyPackedMorphFrameDelta(
7310
- this.wasmRuntimeCore.evaluatePackedMorphFrameDelta()
7311
- );
7312
- return true;
7313
- }
7314
- if (this.tsRuntimeCore) {
7315
- const frame = this.tsRuntimeCore.evaluateFrameDelta();
7316
- this.frameApplier.applyFrameDelta(this.model, {
7317
- morphTargets: frame.morphTargets
7318
- });
7319
- return true;
7320
- }
7321
- return false;
6908
+ applyLiveFrameDelta() {
6909
+ if (!this.framePathReady || !this.model || !this.wasmRuntimeCore) return false;
6910
+ this.frameApplier.applyFrameDelta(this.model, this.wasmRuntimeCore.evaluateFrameDelta());
6911
+ this.pendingCompositeNodes.clear();
6912
+ return true;
7322
6913
  }
7323
6914
  rebuildMorphTargetsCache() {
7324
6915
  this.morphKeyCache.clear();
@@ -7420,6 +7011,11 @@ var _Embody = class _Embody {
7420
7011
  const dtSeconds = Math.max(0, deltaSeconds || 0);
7421
7012
  if (dtSeconds <= 0 || this.isPaused) return;
7422
7013
  this.animation.tick(dtSeconds);
7014
+ const wasmTransitionCount = this.wasmRuntimeCore?.activeTransitionCount() ?? 0;
7015
+ const remainingWasmTransitions = this.wasmRuntimeCore?.update(dtSeconds) ?? 0;
7016
+ if (wasmTransitionCount > 0 || remainingWasmTransitions > 0) {
7017
+ this.applyLiveFrameDelta();
7018
+ }
7423
7019
  this.flushPendingComposites();
7424
7020
  this.animationController.update(dtSeconds);
7425
7021
  this.hairPhysics.update(dtSeconds);
@@ -7454,7 +7050,6 @@ var _Embody = class _Embody {
7454
7050
  this.model = null;
7455
7051
  this.bones = {};
7456
7052
  this.modelDescriptor = null;
7457
- this.tsRuntimeCore = null;
7458
7053
  this.wasmRuntimeCore = null;
7459
7054
  this.framePathReady = false;
7460
7055
  }
@@ -7491,15 +7086,14 @@ var _Embody = class _Embody {
7491
7086
  if (balance !== void 0) {
7492
7087
  this.auBalances[id] = balance;
7493
7088
  }
7494
- this.tsRuntimeCore?.setAU(id, v, balance);
7495
7089
  this.wasmRuntimeCore?.setAU(id, v, balance ?? this.auBalances[id] ?? 0);
7496
- const appliedViaFrame = this.applyLiveMorphFrameDelta();
7090
+ const appliedViaFrame = this.applyLiveFrameDelta();
7497
7091
  if (!appliedViaFrame) {
7498
7092
  const resolvedMorphTargets = this.resolvedAUMorphTargets.get(id);
7499
7093
  const { left: leftKeys, right: rightKeys, center: centerKeys } = this.getAUMorphsBySide(id);
7500
7094
  if (resolvedMorphTargets) {
7501
7095
  const mixWeight = this.isMixedAU(id) ? this.getAUMixWeight(id) : 1;
7502
- const base = clamp013(v) * mixWeight;
7096
+ const base = clamp012(v) * mixWeight;
7503
7097
  const { left: leftVal, right: rightVal } = this.computeSideValues(base, balance);
7504
7098
  if (resolvedMorphTargets.left.length || resolvedMorphTargets.right.length) {
7505
7099
  this.applyMorphTargets(resolvedMorphTargets.left, leftVal);
@@ -7508,7 +7102,7 @@ var _Embody = class _Embody {
7508
7102
  this.applyMorphTargets(resolvedMorphTargets.center, base);
7509
7103
  } else if (leftKeys.length || rightKeys.length || centerKeys.length) {
7510
7104
  const mixWeight = this.isMixedAU(id) ? this.getAUMixWeight(id) : 1;
7511
- const base = clamp013(v) * mixWeight;
7105
+ const base = clamp012(v) * mixWeight;
7512
7106
  const meshNames = this.getMeshNamesForAU(id);
7513
7107
  const { left: leftVal, right: rightVal } = this.computeSideValues(base, balance);
7514
7108
  if (leftKeys.length || rightKeys.length) {
@@ -7527,6 +7121,7 @@ var _Embody = class _Embody {
7527
7121
  }
7528
7122
  }
7529
7123
  }
7124
+ if (appliedViaFrame) return;
7530
7125
  const compositeInfo = this.auToCompositeMap.get(id);
7531
7126
  if (compositeInfo) {
7532
7127
  for (const nodeKey of compositeInfo.nodes) {
@@ -7561,7 +7156,7 @@ var _Embody = class _Embody {
7561
7156
  return this.transitionContinuum(negAU, posAU, continuumValue, durationMs, balance);
7562
7157
  }
7563
7158
  }
7564
- const target = clamp013(to);
7159
+ const target = clamp012(to);
7565
7160
  if (balance !== void 0) {
7566
7161
  this.auBalances[numId] = balance;
7567
7162
  }
@@ -7572,6 +7167,19 @@ var _Embody = class _Embody {
7572
7167
  const base = target * mixWeight;
7573
7168
  const { left: leftVal, right: rightVal } = this.computeSideValues(base, storedBalance);
7574
7169
  this.auValues[numId] = target;
7170
+ if (this.wasmRuntimeCore) {
7171
+ this.wasmRuntimeCore.transitionAU(
7172
+ numId,
7173
+ target,
7174
+ durationMs,
7175
+ balance ?? this.auBalances[numId] ?? Number.NaN
7176
+ );
7177
+ this.update(0);
7178
+ if (durationMs <= 0) {
7179
+ this.applyLiveFrameDelta();
7180
+ }
7181
+ return RESOLVED_TRANSITION_HANDLE;
7182
+ }
7575
7183
  const handles = [];
7576
7184
  const meshNames = this.getMeshNamesForAU(numId);
7577
7185
  if (leftKeys.length || rightKeys.length) {
@@ -7634,6 +7242,17 @@ var _Embody = class _Embody {
7634
7242
  */
7635
7243
  setContinuum(negAU, posAU, continuumValue, balance) {
7636
7244
  const value = Math.max(-1, Math.min(1, continuumValue));
7245
+ this.auValues[negAU] = value < 0 ? Math.abs(value) : 0;
7246
+ this.auValues[posAU] = value > 0 ? value : 0;
7247
+ if (balance !== void 0) {
7248
+ this.auBalances[negAU] = balance;
7249
+ this.auBalances[posAU] = balance;
7250
+ }
7251
+ if (this.wasmRuntimeCore) {
7252
+ this.wasmRuntimeCore.setContinuum(negAU, posAU, value, balance ?? 0);
7253
+ this.applyLiveFrameDelta();
7254
+ return;
7255
+ }
7637
7256
  if (value < 0) {
7638
7257
  this.setAU(posAU, 0, balance);
7639
7258
  this.setAU(negAU, Math.abs(value), balance);
@@ -7659,10 +7278,32 @@ var _Embody = class _Embody {
7659
7278
  */
7660
7279
  transitionContinuum(negAU, posAU, continuumValue, durationMs = 200, balance) {
7661
7280
  const target = Math.max(-1, Math.min(1, continuumValue));
7662
- const driverKey = `continuum_${negAU}_${posAU}`;
7663
7281
  const currentNeg = this.auValues[negAU] ?? 0;
7664
7282
  const currentPos = this.auValues[posAU] ?? 0;
7665
7283
  const currentContinuum = currentPos - currentNeg;
7284
+ this.auValues[negAU] = target < 0 ? Math.abs(target) : 0;
7285
+ this.auValues[posAU] = target > 0 ? target : 0;
7286
+ if (balance !== void 0) {
7287
+ this.auBalances[negAU] = balance;
7288
+ this.auBalances[posAU] = balance;
7289
+ }
7290
+ if (this.wasmRuntimeCore) {
7291
+ if (target < 0) {
7292
+ this.wasmRuntimeCore.transitionAU(posAU, 0, durationMs, balance ?? this.auBalances[posAU] ?? Number.NaN);
7293
+ this.wasmRuntimeCore.transitionAU(negAU, Math.abs(target), durationMs, balance ?? this.auBalances[negAU] ?? Number.NaN);
7294
+ } else if (target > 0) {
7295
+ this.wasmRuntimeCore.transitionAU(negAU, 0, durationMs, balance ?? this.auBalances[negAU] ?? Number.NaN);
7296
+ this.wasmRuntimeCore.transitionAU(posAU, target, durationMs, balance ?? this.auBalances[posAU] ?? Number.NaN);
7297
+ } else {
7298
+ this.wasmRuntimeCore.transitionAU(negAU, 0, durationMs, balance ?? this.auBalances[negAU] ?? Number.NaN);
7299
+ this.wasmRuntimeCore.transitionAU(posAU, 0, durationMs, balance ?? this.auBalances[posAU] ?? Number.NaN);
7300
+ }
7301
+ if (durationMs <= 0) {
7302
+ this.applyLiveFrameDelta();
7303
+ }
7304
+ return RESOLVED_TRANSITION_HANDLE;
7305
+ }
7306
+ const driverKey = `continuum_${negAU}_${posAU}`;
7666
7307
  return this.animation.addTransition(driverKey, currentContinuum, target, durationMs, (value) => this.setContinuum(negAU, posAU, value, balance));
7667
7308
  }
7668
7309
  // ============================================================================
@@ -7744,7 +7385,7 @@ var _Embody = class _Embody {
7744
7385
  this.hairPhysics.refreshMeshSelection();
7745
7386
  }
7746
7387
  setMorph(key, v, meshNamesOrTargets) {
7747
- const val = clamp013(v);
7388
+ const val = clamp012(v);
7748
7389
  if (Array.isArray(meshNamesOrTargets) && meshNamesOrTargets.length > 0 && typeof meshNamesOrTargets[0] === "object" && "infl" in meshNamesOrTargets[0]) {
7749
7390
  const targets2 = meshNamesOrTargets;
7750
7391
  this.applyMorphTargets(targets2, val);
@@ -7756,7 +7397,7 @@ var _Embody = class _Embody {
7756
7397
  this.applyMorphTargets(targets, val);
7757
7398
  }
7758
7399
  setMorphInfluence(index, v, meshNames) {
7759
- const val = clamp013(v);
7400
+ const val = clamp012(v);
7760
7401
  const targets = this.resolveMorphTargetsByIndex(index, meshNames);
7761
7402
  if (targets.length === 0) return;
7762
7403
  this.applyMorphTargets(targets, val);
@@ -7831,21 +7472,21 @@ var _Embody = class _Embody {
7831
7472
  }
7832
7473
  transitionMorph(key, to, durationMs = 120, meshNames) {
7833
7474
  const transitionKey = meshNames?.length ? `morph_${this.getMorphKeyCacheKey(key, meshNames)}` : `morph_${this.getMorphKeyCacheKey(key)}`;
7834
- const target = clamp013(to);
7475
+ const target = clamp012(to);
7835
7476
  const targets = this.resolveMorphTargets(key, meshNames);
7836
7477
  const from = targets.length > 0 ? targets[0].infl[targets[0].idx] ?? 0 : this.getMorphValue(key);
7837
7478
  return this.animation.addTransition(transitionKey, from, target, durationMs, (value) => {
7838
- const val = clamp013(value);
7479
+ const val = clamp012(value);
7839
7480
  this.applyMorphTargets(targets, val);
7840
7481
  });
7841
7482
  }
7842
7483
  transitionMorphInfluence(index, to, durationMs = 120, meshNames) {
7843
7484
  const transitionKey = meshNames?.length ? `morph_${this.getMorphIndexCacheKey(index, meshNames)}` : `morph_${this.getMorphIndexCacheKey(index)}`;
7844
- const target = clamp013(to);
7485
+ const target = clamp012(to);
7845
7486
  const targets = this.resolveMorphTargetsByIndex(index, meshNames);
7846
7487
  const from = targets.length > 0 ? targets[0].infl[targets[0].idx] ?? 0 : this.getMorphValueByIndex(index);
7847
7488
  return this.animation.addTransition(transitionKey, from, target, durationMs, (value) => {
7848
- const val = clamp013(value);
7489
+ const val = clamp012(value);
7849
7490
  this.applyMorphTargets(targets, val);
7850
7491
  });
7851
7492
  }
@@ -7854,7 +7495,7 @@ var _Embody = class _Embody {
7854
7495
  // ============================================================================
7855
7496
  setViseme(visemeIndex, value, jawScale = 1) {
7856
7497
  if (visemeIndex < 0 || visemeIndex >= this.visemeValues.length) return;
7857
- const val = clamp013(value);
7498
+ const val = clamp012(value);
7858
7499
  this.visemeValues[visemeIndex] = val;
7859
7500
  this.visemeJawScales[visemeIndex] = jawScale;
7860
7501
  this.applyVisemeRuntimeState();
@@ -7866,16 +7507,24 @@ var _Embody = class _Embody {
7866
7507
  }, cancel: () => {
7867
7508
  } };
7868
7509
  }
7869
- const target = clamp013(to);
7510
+ const target = clamp012(to);
7870
7511
  const from = this.visemeValues[visemeIndex] ?? 0;
7871
7512
  this.visemeJawScales[visemeIndex] = jawScale;
7513
+ if (this.wasmRuntimeCore) {
7514
+ this.visemeValues[visemeIndex] = target;
7515
+ this.wasmRuntimeCore.transitionViseme(visemeIndex, target, durationMs, jawScale);
7516
+ if (durationMs <= 0) {
7517
+ this.applyLiveFrameDelta();
7518
+ }
7519
+ return RESOLVED_TRANSITION_HANDLE;
7520
+ }
7872
7521
  return this.animation.addTransition(
7873
7522
  `viseme_value_${visemeIndex}`,
7874
7523
  from,
7875
7524
  target,
7876
7525
  durationMs,
7877
7526
  (value) => {
7878
- this.visemeValues[visemeIndex] = clamp013(value);
7527
+ this.visemeValues[visemeIndex] = clamp012(value);
7879
7528
  this.visemeJawScales[visemeIndex] = jawScale;
7880
7529
  this.applyVisemeRuntimeState();
7881
7530
  }
@@ -7900,8 +7549,7 @@ var _Embody = class _Embody {
7900
7549
  // MIX WEIGHT CONTROL
7901
7550
  // ============================================================================
7902
7551
  setAUMixWeight(id, weight) {
7903
- this.mixWeights[id] = clamp013(weight);
7904
- this.tsRuntimeCore?.setAUMixWeight(id, weight);
7552
+ this.mixWeights[id] = clamp012(weight);
7905
7553
  this.wasmRuntimeCore?.setAUMixWeight(id, weight);
7906
7554
  const v = this.auValues[id] ?? 0;
7907
7555
  if (v > 0) this.setAU(id, v);
@@ -7939,9 +7587,10 @@ var _Embody = class _Embody {
7939
7587
  }
7940
7588
  clearTransitions() {
7941
7589
  this.animation.clearTransitions();
7590
+ this.wasmRuntimeCore?.clearTransitions();
7942
7591
  }
7943
7592
  getActiveTransitionCount() {
7944
- return this.animation.getActiveTransitionCount();
7593
+ return this.animation.getActiveTransitionCount() + (this.wasmRuntimeCore?.activeTransitionCount() ?? 0);
7945
7594
  }
7946
7595
  resetToNeutral() {
7947
7596
  this.auValues = {};
@@ -7951,6 +7600,7 @@ var _Embody = class _Embody {
7951
7600
  this.translations = {};
7952
7601
  this.initBoneRotations();
7953
7602
  this.clearTransitions();
7603
+ this.wasmRuntimeCore?.clear();
7954
7604
  const morphTargetsToReset = [];
7955
7605
  for (const m of this.meshes) {
7956
7606
  const infl = m.morphTargetInfluences;
@@ -8129,7 +7779,18 @@ var _Embody = class _Embody {
8129
7779
  this.bones = this.resolveBones(this.model);
8130
7780
  this.missingBoneWarnings.clear();
8131
7781
  this.rebuildMorphTargetsCache();
8132
- this.tsRuntimeCore?.setProfile(this.config);
7782
+ Object.values(this.bones).forEach((entry) => {
7783
+ if (!entry) return;
7784
+ this.frameApplier.applyObjectTransform(entry.obj, {
7785
+ position: { x: entry.basePos.x, y: entry.basePos.y, z: entry.basePos.z },
7786
+ rotation: {
7787
+ x: entry.baseQuat.x,
7788
+ y: entry.baseQuat.y,
7789
+ z: entry.baseQuat.z,
7790
+ w: entry.baseQuat.w
7791
+ }
7792
+ });
7793
+ });
8133
7794
  this.wasmRuntimeCore?.setProfile(this.config);
8134
7795
  this.refreshHostNeutralModelDescriptor();
8135
7796
  }
@@ -8246,20 +7907,20 @@ var _Embody = class _Embody {
8246
7907
  }
8247
7908
  applyVisemeRuntimeState() {
8248
7909
  for (let index = 0; index < this.visemeValues.length; index += 1) {
8249
- this.tsRuntimeCore?.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
8250
- this.wasmRuntimeCore?.setViseme(index, this.visemeValues[index] ?? 0);
7910
+ this.wasmRuntimeCore?.setViseme(index, this.visemeValues[index] ?? 0, this.visemeJawScales[index] ?? 1);
8251
7911
  }
8252
- if (!this.applyLiveMorphFrameDelta()) {
7912
+ const appliedViaFrame = this.applyLiveFrameDelta();
7913
+ if (!appliedViaFrame) {
8253
7914
  for (const targets of this.resolvedVisemeTargets) {
8254
7915
  this.frameApplier.resetMorphTargets(targets || []);
8255
7916
  }
8256
7917
  for (let index = 0; index < this.visemeValues.length; index += 1) {
8257
- const value = clamp013(this.visemeValues[index] ?? 0);
7918
+ const value = clamp012(this.visemeValues[index] ?? 0);
8258
7919
  if (value <= 1e-6) continue;
8259
7920
  const targets = this.resolvedVisemeTargets[index] || [];
8260
7921
  for (const target of targets) {
8261
7922
  if (target.idx >= target.infl.length) continue;
8262
- const weighted = clamp013(value * target.weight);
7923
+ const weighted = clamp012(value * target.weight);
8263
7924
  this.frameApplier.applyMorphTargets(
8264
7925
  [target],
8265
7926
  Math.max(target.infl[target.idx] ?? 0, weighted)
@@ -8267,7 +7928,9 @@ var _Embody = class _Embody {
8267
7928
  }
8268
7929
  }
8269
7930
  }
8270
- this.updateBoneRotation(this.getJawBoneNodeKey(), "pitch", this.getActiveVisemeJawAmount());
7931
+ if (!appliedViaFrame) {
7932
+ this.updateBoneRotation(this.getJawBoneNodeKey(), "pitch", this.getActiveVisemeJawAmount());
7933
+ }
8271
7934
  }
8272
7935
  getJawBoneNodeKey() {
8273
7936
  const candidates = [
@@ -8289,7 +7952,7 @@ var _Embody = class _Embody {
8289
7952
  getActiveVisemeJawAmount() {
8290
7953
  let jawAmount = 0;
8291
7954
  for (let index = 0; index < this.visemeValues.length; index += 1) {
8292
- const value = clamp013(this.visemeValues[index] ?? 0);
7955
+ const value = clamp012(this.visemeValues[index] ?? 0);
8293
7956
  if (value <= 1e-6) continue;
8294
7957
  const jawScale = this.visemeJawScales[index] ?? 1;
8295
7958
  if (Math.abs(jawScale) <= 1e-6) continue;
@@ -8572,7 +8235,7 @@ var _Embody = class _Embody {
8572
8235
  return !!(hasMorphs && this.config.auToBones[id]?.length);
8573
8236
  }
8574
8237
  getEffectiveBoneAUValue(auId, nodeKey) {
8575
- const rawValue = clamp013(this.auValues[auId] ?? 0);
8238
+ const rawValue = clamp012(this.auValues[auId] ?? 0);
8576
8239
  if (rawValue <= 1e-6) return 0;
8577
8240
  const binding = this.config.auToBones[auId]?.find((candidate) => candidate.node === nodeKey) ?? null;
8578
8241
  if (!binding?.side) return rawValue;
@@ -8672,7 +8335,7 @@ var _Embody = class _Embody {
8672
8335
  if (config.yaw && rotState.yaw !== 0) {
8673
8336
  const binding = this.getCompositeAxisBindingForNode(nodeKey, config.yaw, rotState.yaw);
8674
8337
  if (binding?.maxDegrees && binding.channel) {
8675
- const radians = deg2rad2(binding.maxDegrees) * Math.abs(rotState.yaw) * binding.scale;
8338
+ const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.yaw) * binding.scale;
8676
8339
  const axis = getAxis(binding.channel);
8677
8340
  const deltaQ = new Quaternion().setFromAxisAngle(axis, radians);
8678
8341
  compositeQ.multiply(deltaQ);
@@ -8681,7 +8344,7 @@ var _Embody = class _Embody {
8681
8344
  if (config.pitch && rotState.pitch !== 0) {
8682
8345
  const binding = this.getCompositeAxisBindingForNode(nodeKey, config.pitch, rotState.pitch);
8683
8346
  if (binding?.maxDegrees && binding.channel) {
8684
- const radians = deg2rad2(binding.maxDegrees) * Math.abs(rotState.pitch) * binding.scale;
8347
+ const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.pitch) * binding.scale;
8685
8348
  const axis = getAxis(binding.channel);
8686
8349
  const deltaQ = new Quaternion().setFromAxisAngle(axis, radians);
8687
8350
  compositeQ.multiply(deltaQ);
@@ -8690,7 +8353,7 @@ var _Embody = class _Embody {
8690
8353
  if (config.roll && rotState.roll !== 0) {
8691
8354
  const binding = this.getCompositeAxisBindingForNode(nodeKey, config.roll, rotState.roll);
8692
8355
  if (binding?.maxDegrees && binding.channel) {
8693
- const radians = deg2rad2(binding.maxDegrees) * Math.abs(rotState.roll) * binding.scale;
8356
+ const radians = deg2rad(binding.maxDegrees) * Math.abs(rotState.roll) * binding.scale;
8694
8357
  const axis = getAxis(binding.channel);
8695
8358
  const deltaQ = new Quaternion().setFromAxisAngle(axis, radians);
8696
8359
  compositeQ.multiply(deltaQ);
@@ -9529,11 +9192,11 @@ function applyCharacterModelTransform(model, transform = {}) {
9529
9192
  model.position.set(modelOffset.x ?? 0, modelOffset.y ?? 0, modelOffset.z ?? 0);
9530
9193
  }
9531
9194
  if (modelRotation) {
9532
- const deg2rad3 = Math.PI / 180;
9195
+ const deg2rad2 = Math.PI / 180;
9533
9196
  model.rotation.set(
9534
- (modelRotation.x ?? 0) * deg2rad3,
9535
- (modelRotation.y ?? 0) * deg2rad3,
9536
- (modelRotation.z ?? 0) * deg2rad3
9197
+ (modelRotation.x ?? 0) * deg2rad2,
9198
+ (modelRotation.y ?? 0) * deg2rad2,
9199
+ (modelRotation.z ?? 0) * deg2rad2
9537
9200
  );
9538
9201
  }
9539
9202
  if (modelScale !== void 0 && Number.isFinite(modelScale) && modelScale > 0) {