@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/core.js CHANGED
@@ -185,526 +185,18 @@ function numericArrayToNumbers(values) {
185
185
  return Array.from(values);
186
186
  }
187
187
 
188
- // src/core/compositeAxis.ts
189
- function toAUList(value) {
190
- if (value === void 0) return [];
191
- return Array.isArray(value) ? value : [value];
192
- }
193
- function findBoneBindingForNode(auToBones, auId, nodeKey) {
194
- return auToBones[auId]?.find((candidate) => candidate.node === nodeKey) ?? null;
195
- }
196
- function getCompositeAxisValue(axisConfig, getValue) {
197
- if (!axisConfig) return 0;
198
- const negativeAUs = toAUList(axisConfig.negative);
199
- const positiveAUs = toAUList(axisConfig.positive);
200
- if (negativeAUs.length > 0 && positiveAUs.length > 0) {
201
- const negativeValue = Math.max(...negativeAUs.map(getValue), 0);
202
- const positiveValue = Math.max(...positiveAUs.map(getValue), 0);
203
- return positiveValue - negativeValue;
204
- }
205
- if (axisConfig.aus.length > 1) {
206
- return Math.max(...axisConfig.aus.map(getValue), 0);
207
- }
208
- return getValue(axisConfig.aus[0]);
209
- }
210
- function getCompositeAxisBinding(nodeKey, axisConfig, direction, getValue, auToBones) {
211
- if (!axisConfig) return null;
212
- const directionalAUs = direction < 0 ? toAUList(axisConfig.negative) : toAUList(axisConfig.positive);
213
- const candidates = directionalAUs.length > 0 ? directionalAUs : axisConfig.aus;
214
- const ranked = [...candidates].sort((a, b) => getValue(b) - getValue(a));
215
- for (const auId of ranked) {
216
- const binding = findBoneBindingForNode(auToBones, auId, nodeKey);
217
- if (binding) return binding;
218
- }
219
- return null;
220
- }
221
-
222
- // src/mappings/visemeSystem.ts
223
- function hasOwn(value, key) {
224
- return Boolean(value && Object.prototype.hasOwnProperty.call(value, key));
225
- }
226
- function toSlotId(label, index) {
227
- const normalized = label.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
228
- return normalized || `viseme-${index}`;
229
- }
230
- function normalizeBindingWeight(weight) {
231
- return Number.isFinite(weight) ? Math.max(0, weight ?? 1) : 1;
232
- }
233
- function getProfileVisemeSlots(profile) {
234
- if (profile.visemeSlots && profile.visemeSlots.length > 0) {
235
- return [...profile.visemeSlots].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
236
- }
237
- return (profile.visemeKeys || []).map((key, index) => {
238
- const label = typeof key === "string" && key ? key : `Viseme ${index}`;
239
- return {
240
- id: toSlotId(label, index),
241
- label,
242
- order: index,
243
- defaultJawAmount: profile.visemeJawAmounts?.[index]
244
- };
245
- });
246
- }
247
- function getVisemeSlotIndex(profile, slotId) {
248
- return getProfileVisemeSlots(profile).findIndex((slot) => slot.id === slotId);
249
- }
250
- function getVisemeBindingTargets(profile, visemeIndex) {
251
- const slots = getProfileVisemeSlots(profile);
252
- const slot = slots[visemeIndex];
253
- const binding = slot ? profile.visemeBindings?.[slot.id] : void 0;
254
- const boundTargets = binding?.targets?.filter((target) => target.morph !== void 0 && target.morph !== "").map((target) => ({
255
- morph: target.morph,
256
- weight: normalizeBindingWeight(target.weight)
257
- }));
258
- if (boundTargets && boundTargets.length > 0) {
259
- return boundTargets;
260
- }
261
- if (binding?.morph !== void 0 && binding.morph !== "") {
262
- return [{ morph: binding.morph, weight: 1 }];
263
- }
264
- const legacyTarget = profile.visemeKeys?.[visemeIndex];
265
- return legacyTarget !== void 0 && legacyTarget !== "" ? [{ morph: legacyTarget, weight: 1 }] : [];
266
- }
267
- function getVisemeJawAmounts(profile) {
268
- const slots = getProfileVisemeSlots(profile);
269
- if (slots.length === 0) return profile.visemeJawAmounts ? [...profile.visemeJawAmounts] : void 0;
270
- return slots.map((slot, index) => slot.defaultJawAmount ?? profile.visemeJawAmounts?.[index] ?? 0);
271
- }
272
- function resolveVisemeMeshCategory(profile) {
273
- const morphToMesh = profile.morphToMesh || {};
274
- if (profile.visemeMeshCategory) return profile.visemeMeshCategory;
275
- if (hasOwn(morphToMesh, "viseme")) return "viseme";
276
- return "face";
277
- }
278
- function getMeshNamesForVisemeProfile(profile) {
279
- const morphToMesh = profile.morphToMesh || {};
280
- const category = resolveVisemeMeshCategory(profile);
281
- if (hasOwn(morphToMesh, category)) {
282
- return Array.isArray(morphToMesh[category]) ? [...morphToMesh[category]] : [];
283
- }
284
- return profile.visemeMeshCategory ? [] : [...morphToMesh.face || []];
285
- }
286
- function getMeshNamesForAUProfile(profile, auId) {
287
- const morphToMesh = profile.morphToMesh || {};
288
- const facePart = profile.auInfo?.[String(auId)]?.facePart;
289
- const category = facePart ? profile.auFacePartToMeshCategory?.[facePart] : void 0;
290
- if (category) return Array.isArray(morphToMesh[category]) ? [...morphToMesh[category]] : [];
291
- return [...morphToMesh.face || []];
292
- }
293
-
294
- // src/core/TsRuntimeCore.ts
295
- var identityQuat = { x: 0, y: 0, z: 0, w: 1 };
296
- function isRotationBoneBinding(binding) {
297
- return binding?.channel === "rx" || binding?.channel === "ry" || binding?.channel === "rz";
298
- }
299
- var TsRuntimeCore = class {
300
- constructor(options) {
301
- __publicField(this, "profile");
302
- __publicField(this, "model");
303
- __publicField(this, "auValues", {});
304
- __publicField(this, "auBalances", {});
305
- __publicField(this, "visemeValues");
306
- __publicField(this, "visemeJawScales");
307
- __publicField(this, "mixWeights");
308
- this.profile = options.profile;
309
- this.model = options.model;
310
- this.visemeValues = new Array(getProfileVisemeSlots(this.profile).length).fill(0);
311
- this.visemeJawScales = new Array(this.visemeValues.length).fill(1);
312
- this.mixWeights = { ...this.profile.auMixDefaults };
313
- }
314
- setProfile(profile) {
315
- this.profile = profile;
316
- this.visemeValues = new Array(getProfileVisemeSlots(this.profile).length).fill(0);
317
- this.visemeJawScales = new Array(this.visemeValues.length).fill(1);
318
- this.mixWeights = { ...this.profile.auMixDefaults };
319
- }
320
- setModelDescriptor(model) {
321
- this.model = model;
322
- }
323
- setAU(id, value, balance) {
324
- if (value < 0 && this.profile.continuumPairs) {
325
- const pairInfo = this.profile.continuumPairs[id];
326
- if (pairInfo) {
327
- const negAU = pairInfo.isNegative ? id : pairInfo.pairId;
328
- const posAU = pairInfo.isNegative ? pairInfo.pairId : id;
329
- this.setContinuum(negAU, posAU, pairInfo.isNegative ? -value : value, balance);
330
- return;
331
- }
332
- }
333
- this.auValues[id] = clamp01(value);
334
- if (balance !== void 0) {
335
- this.auBalances[id] = clampBalance(balance);
336
- }
337
- }
338
- getAU(id) {
339
- return this.auValues[id] ?? 0;
340
- }
341
- setContinuum(negAU, posAU, continuumValue, balance) {
342
- const value = Math.max(-1, Math.min(1, continuumValue));
343
- if (value < 0) {
344
- this.setAU(posAU, 0, balance);
345
- this.setAU(negAU, Math.abs(value), balance);
346
- return;
347
- }
348
- if (value > 0) {
349
- this.setAU(negAU, 0, balance);
350
- this.setAU(posAU, value, balance);
351
- return;
352
- }
353
- this.setAU(negAU, 0, balance);
354
- this.setAU(posAU, 0, balance);
355
- }
356
- setViseme(visemeIndex, value, jawScale = 1) {
357
- if (visemeIndex < 0 || visemeIndex >= this.visemeValues.length) return;
358
- this.visemeValues[visemeIndex] = clamp01(value);
359
- this.visemeJawScales[visemeIndex] = jawScale;
360
- }
361
- setVisemeById(slotId, value, jawScale = 1) {
362
- const index = getVisemeSlotIndex(this.profile, slotId);
363
- if (index < 0) return;
364
- this.setViseme(index, value, jawScale);
365
- }
366
- setAUMixWeight(id, weight) {
367
- this.mixWeights[id] = clamp01(weight);
368
- }
369
- evaluateFrameDelta(deltaSeconds) {
370
- const morphWrites = /* @__PURE__ */ new Map();
371
- this.collectAUWrites(morphWrites);
372
- this.collectVisemeWrites(morphWrites);
373
- return {
374
- deltaSeconds,
375
- morphTargets: Array.from(morphWrites.values()),
376
- bones: this.collectBoneWrites()
377
- };
378
- }
379
- collectAUWrites(morphWrites) {
380
- for (const [auIdText, entry] of Object.entries(this.profile.auToMorphs || {})) {
381
- const auId = Number(auIdText);
382
- if (Number.isNaN(auId) || !entry) continue;
383
- const mixWeight = this.isMixedAU(auId) ? this.getAUMixWeight(auId) : 1;
384
- const base = clamp01(this.auValues[auId] ?? 0) * mixWeight;
385
- const { left, right } = computeSideValues(base, this.auBalances[auId]);
386
- const meshNames = getMeshNamesForAUProfile(this.profile, auId);
387
- for (const morph of entry.left || []) {
388
- this.addMorphWrites(morphWrites, morph, meshNames, left);
389
- }
390
- for (const morph of entry.right || []) {
391
- this.addMorphWrites(morphWrites, morph, meshNames, right);
392
- }
393
- for (const morph of entry.center || []) {
394
- this.addMorphWrites(morphWrites, morph, meshNames, base);
395
- }
396
- }
397
- }
398
- collectVisemeWrites(morphWrites) {
399
- const meshNames = getMeshNamesForVisemeProfile(this.profile);
400
- const localMax = /* @__PURE__ */ new Map();
401
- for (let index = 0; index < this.visemeValues.length; index += 1) {
402
- const value = clamp01(this.visemeValues[index] ?? 0);
403
- for (const bindingTarget of getVisemeBindingTargets(this.profile, index)) {
404
- const weighted = clamp01(value * bindingTarget.weight);
405
- for (const resolved of this.resolveMorphTargets(bindingTarget.morph, meshNames)) {
406
- const key = morphWriteKey(resolved.mesh.id, resolved.morphTarget.id);
407
- const existing = localMax.get(key);
408
- if (!existing || weighted > existing.value) {
409
- localMax.set(key, {
410
- meshId: resolved.mesh.id,
411
- morphTargetId: resolved.morphTarget.id,
412
- value: weighted,
413
- mode: "absolute"
414
- });
415
- }
416
- }
417
- }
418
- }
419
- for (const [key, write] of localMax) {
420
- const existing = morphWrites.get(key);
421
- if (!existing || write.value > existing.value) {
422
- morphWrites.set(key, write);
423
- }
424
- }
425
- }
426
- collectBoneWrites() {
427
- const writes = [];
428
- const rotations = this.computeRotationState();
429
- for (const composite of this.profile.compositeRotations || []) {
430
- const bone = this.findBoneDescriptor(composite.node);
431
- if (!bone) continue;
432
- const transform = this.evaluateCompositeTransform(bone, composite, rotations[composite.node]);
433
- if (transform) {
434
- writes.push({
435
- boneId: bone.id,
436
- transform,
437
- mode: "absolute",
438
- space: "local"
439
- });
440
- }
441
- }
442
- for (const [nodeKey, translation] of Object.entries(this.computeTranslations())) {
443
- const bone = this.findBoneDescriptor(nodeKey);
444
- if (!bone) continue;
445
- const position = addVec3(bone.restTransform?.position, translation);
446
- upsertBoneWrite(writes, bone.id, { position });
447
- }
448
- const jawAmount = this.getActiveVisemeJawAmount();
449
- const jawBinding = this.findAutoVisemeJawBinding();
450
- const jawBone = jawBinding ? this.findBoneDescriptor(jawBinding.node) : void 0;
451
- if (jawBone && jawBinding?.maxDegrees && jawBinding.channel) {
452
- const current = writes.find((write) => write.boneId === jawBone.id);
453
- if (jawAmount > 1e-6 || !current?.transform.rotation) {
454
- const rest = jawBone.restTransform?.rotation ?? identityQuat;
455
- const rotation = jawAmount > 1e-6 ? multiplyQuat(
456
- rest,
457
- quatFromChannel(jawBinding.channel, deg2rad(jawBinding.maxDegrees) * jawAmount * jawBinding.scale)
458
- ) : rest;
459
- upsertBoneWrite(writes, jawBone.id, { rotation });
460
- }
461
- }
462
- return writes;
463
- }
464
- computeRotationState() {
465
- const rotations = {};
466
- for (const composite of this.profile.compositeRotations || []) {
467
- rotations[composite.node] = {
468
- pitch: this.getCompositeAxisValueForNode(composite.node, composite.pitch),
469
- yaw: this.getCompositeAxisValueForNode(composite.node, composite.yaw),
470
- roll: this.getCompositeAxisValueForNode(composite.node, composite.roll)
471
- };
472
- }
473
- return rotations;
474
- }
475
- evaluateCompositeTransform(bone, composite, state) {
476
- if (!state) return null;
477
- let rotation = bone.restTransform?.rotation ?? identityQuat;
478
- const applyAxis = (axisConfig, direction) => {
479
- if (!axisConfig || Math.abs(direction) <= 1e-6) return;
480
- const binding = getCompositeAxisBinding(
481
- composite.node,
482
- axisConfig,
483
- direction,
484
- (auId) => this.getEffectiveBoneAUValue(auId, composite.node),
485
- this.profile.auToBones
486
- );
487
- if (!binding?.maxDegrees || !binding.channel) return;
488
- rotation = multiplyQuat(
489
- rotation,
490
- quatFromChannel(binding.channel, deg2rad(binding.maxDegrees) * Math.abs(direction) * binding.scale)
491
- );
492
- };
493
- applyAxis(composite.yaw, state.yaw);
494
- applyAxis(composite.pitch, state.pitch);
495
- applyAxis(composite.roll, state.roll);
496
- return { rotation };
497
- }
498
- computeTranslations() {
499
- const translations = {};
500
- for (const [auIdText, bindings] of Object.entries(this.profile.auToBones || {})) {
501
- const auId = Number(auIdText);
502
- if (Number.isNaN(auId)) continue;
503
- const value = clamp01(this.auValues[auId] ?? 0);
504
- for (const binding of bindings || []) {
505
- if (binding.channel !== "tx" && binding.channel !== "ty" && binding.channel !== "tz") continue;
506
- if (binding.maxUnits === void 0) continue;
507
- const current = translations[binding.node] ?? { x: 0, y: 0, z: 0 };
508
- translations[binding.node] = current;
509
- if (value <= 1e-6) continue;
510
- const offset = clampSigned(value * binding.scale) * binding.maxUnits;
511
- translations[binding.node] = {
512
- x: binding.channel === "tx" ? offset : current.x,
513
- y: binding.channel === "ty" ? offset : current.y,
514
- z: binding.channel === "tz" ? offset : current.z
515
- };
516
- }
517
- }
518
- return translations;
519
- }
520
- addMorphWrites(morphWrites, morph, meshNames, value) {
521
- for (const resolved of this.resolveMorphTargets(morph, meshNames)) {
522
- const key = morphWriteKey(resolved.mesh.id, resolved.morphTarget.id);
523
- const existing = morphWrites.get(key);
524
- if (existing && existing.value >= value) continue;
525
- morphWrites.set(key, {
526
- meshId: resolved.mesh.id,
527
- morphTargetId: resolved.morphTarget.id,
528
- value,
529
- mode: "absolute"
530
- });
531
- }
532
- }
533
- resolveMorphTargets(morph, meshNames) {
534
- const result = [];
535
- for (const meshName of meshNames) {
536
- const mesh = this.model.meshes.find((candidate) => candidate.name === meshName);
537
- if (!mesh) continue;
538
- const morphTargets = mesh.morphTargetIds.map((id) => this.model.morphTargets.find((candidate) => candidate.id === id)).filter((target2) => !!target2);
539
- const target = typeof morph === "number" ? morphTargets.find((candidate) => candidate.hostIndex === morph) : resolveMorphTargetByName(morphTargets, morph, this.profile);
540
- if (target) {
541
- result.push({ mesh, morphTarget: target });
542
- }
543
- }
544
- return result;
545
- }
546
- findBoneDescriptor(nodeKey) {
547
- const configuredName = this.profile.boneNodes[nodeKey] || nodeKey;
548
- const prefix = this.profile.bonePrefix ?? "";
549
- const suffix = this.profile.boneSuffix ?? "";
550
- const prefixedName = prefix && !configuredName.startsWith(prefix) ? `${prefix}${configuredName}` : configuredName;
551
- const fullName = suffix && !prefixedName.endsWith(suffix) ? `${prefixedName}${suffix}` : prefixedName;
552
- const candidates = /* @__PURE__ */ new Set([nodeKey, configuredName, fullName]);
553
- return this.model.bones.find((bone) => candidates.has(bone.name));
554
- }
555
- findAutoVisemeJawBinding() {
556
- const candidates = [
557
- this.profile.auToBones[103]?.find(isRotationBoneBinding),
558
- this.profile.auToBones[26]?.find(isRotationBoneBinding)
559
- ].filter((binding) => !!binding);
560
- return candidates.find((binding) => !!this.findBoneDescriptor(binding.node)) ?? candidates[0] ?? null;
561
- }
562
- getActiveVisemeJawAmount() {
563
- const jawAmounts = getVisemeJawAmounts(this.profile) ?? [];
564
- let jawAmount = 0;
565
- for (let index = 0; index < this.visemeValues.length; index += 1) {
566
- const value = clamp01(this.visemeValues[index] ?? 0);
567
- if (value <= 1e-6) continue;
568
- const jawScale = this.visemeJawScales[index] ?? 1;
569
- if (Math.abs(jawScale) <= 1e-6) continue;
570
- jawAmount = Math.max(jawAmount, (jawAmounts[index] ?? 0) * value * jawScale);
571
- }
572
- return jawAmount;
573
- }
574
- getCompositeAxisValueForNode(nodeKey, axisConfig) {
575
- return getCompositeAxisValue(axisConfig, (auId) => this.getEffectiveBoneAUValue(auId, nodeKey));
576
- }
577
- getEffectiveBoneAUValue(auId, nodeKey) {
578
- const rawValue = clamp01(this.auValues[auId] ?? 0);
579
- if (rawValue <= 1e-6) return 0;
580
- const binding = this.profile.auToBones[auId]?.find((candidate) => candidate.node === nodeKey) ?? null;
581
- if (!binding?.side) return rawValue;
582
- return rawValue * getSideScale(this.auBalances[auId] ?? 0, binding.side);
583
- }
584
- getAUMixWeight(auId) {
585
- return this.mixWeights[auId] ?? this.profile.auMixDefaults?.[auId] ?? 1;
586
- }
587
- isMixedAU(auId) {
588
- const morphs = this.profile.auToMorphs[auId];
589
- const hasMorphs = !!(morphs?.left?.length || morphs?.right?.length || morphs?.center?.length);
590
- return !!(hasMorphs && this.profile.auToBones[auId]?.length);
591
- }
592
- };
593
- function resolveMorphTargetByName(targets, key, profile) {
594
- const prefix = profile.morphPrefix || "";
595
- const suffix = profile.morphSuffix || "";
596
- const fullName = prefix + key + suffix;
597
- const exact = targets.find((target) => target.name === fullName);
598
- if (exact) return exact;
599
- const suffixRegex = profile.suffixPattern ? new RegExp(profile.suffixPattern) : null;
600
- if (!suffixRegex) return void 0;
601
- return targets.find((target) => {
602
- if (!target.name.startsWith(fullName)) return false;
603
- const candidateSuffix = target.name.slice(fullName.length);
604
- return candidateSuffix === "" || suffixRegex.test(candidateSuffix);
605
- });
606
- }
607
- function computeSideValues(base, balance) {
608
- const b = clampBalance(balance ?? 0);
609
- if (b === 0) return { left: base, right: base };
610
- if (b < 0) return { left: base, right: base * (1 + b) };
611
- return { left: base * (1 - b), right: base };
612
- }
613
- function getSideScale(balance, side) {
614
- if (side !== "left" && side !== "right") return 1;
615
- const b = clampBalance(balance);
616
- if (side === "left") return b > 0 ? 1 - b : 1;
617
- return b < 0 ? 1 + b : 1;
618
- }
619
- function addVec3(base, offset) {
620
- return {
621
- x: (base?.x ?? 0) + offset.x,
622
- y: (base?.y ?? 0) + offset.y,
623
- z: (base?.z ?? 0) + offset.z
624
- };
625
- }
626
- function upsertBoneWrite(writes, boneId, transform) {
627
- const existingIndex = writes.findIndex((write) => write.boneId === boneId);
628
- if (existingIndex >= 0) {
629
- const existing = writes[existingIndex];
630
- writes[existingIndex] = {
631
- ...existing,
632
- transform: {
633
- ...existing.transform,
634
- ...transform
635
- }
636
- };
637
- return;
638
- }
639
- writes.push({
640
- boneId,
641
- transform,
642
- mode: "absolute",
643
- space: "local"
644
- });
645
- }
646
- function quatFromChannel(channel, radians) {
647
- if (channel === "rx") return quatFromAxis({ x: 1, y: 0, z: 0 }, radians);
648
- if (channel === "ry") return quatFromAxis({ x: 0, y: 1, z: 0 }, radians);
649
- return quatFromAxis({ x: 0, y: 0, z: 1 }, radians);
650
- }
651
- function quatFromAxis(axis, radians) {
652
- const half = radians / 2;
653
- const s = Math.sin(half);
654
- return normalizeQuat({
655
- x: axis.x * s,
656
- y: axis.y * s,
657
- z: axis.z * s,
658
- w: Math.cos(half)
659
- });
660
- }
661
- function multiplyQuat(a, b) {
662
- return normalizeQuat({
663
- x: a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
664
- y: a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
665
- z: a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
666
- w: a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z
667
- });
668
- }
669
- function normalizeQuat(q) {
670
- const len = Math.hypot(q.x, q.y, q.z, q.w);
671
- if (len <= 1e-12) return identityQuat;
672
- return {
673
- x: q.x / len,
674
- y: q.y / len,
675
- z: q.z / len,
676
- w: q.w / len
677
- };
678
- }
679
- function deg2rad(degrees) {
680
- return degrees * Math.PI / 180;
681
- }
682
- function clamp01(value) {
683
- if (!Number.isFinite(value)) return 0;
684
- return value < 0 ? 0 : value > 1 ? 1 : value;
685
- }
686
- function clampSigned(value) {
687
- if (!Number.isFinite(value)) return 0;
688
- return value < -1 ? -1 : value > 1 ? 1 : value;
689
- }
690
- function clampBalance(value) {
691
- if (!Number.isFinite(value)) return 0;
692
- return Math.max(-1, Math.min(1, value));
693
- }
694
- function morphWriteKey(meshId, morphTargetId) {
695
- return `${meshId}:${morphTargetId}`;
696
- }
697
-
698
188
  // src/core/WasmRuntimeCore.ts
699
189
  var WasmRuntimeCore = class {
700
190
  constructor(options) {
701
191
  __publicField(this, "wasm");
702
192
  __publicField(this, "core");
193
+ __publicField(this, "allowEmptyBindings");
703
194
  __publicField(this, "profile");
704
195
  __publicField(this, "model");
705
196
  this.wasm = options.wasm;
706
197
  this.profile = options.profile;
707
198
  this.model = options.model;
199
+ this.allowEmptyBindings = options.allowEmptyBindings ?? false;
708
200
  const RuntimeCtor = options.wasm.RuntimeCore;
709
201
  if (!RuntimeCtor) {
710
202
  throw new Error("Embody Wasm module does not export RuntimeCore");
@@ -723,6 +215,24 @@ var WasmRuntimeCore = class {
723
215
  setAU(id, value, balance = 0) {
724
216
  this.core.set_au(id >>> 0, value, balance);
725
217
  }
218
+ setContinuum(negativeAU, positiveAU, value, balance = 0) {
219
+ this.core.set_continuum(negativeAU >>> 0, positiveAU >>> 0, value, balance);
220
+ }
221
+ transitionAU(id, to, durationMs, balance = Number.NaN) {
222
+ this.core.transition_au(id >>> 0, to, durationMs, balance);
223
+ }
224
+ transitionViseme(visemeIndex, to, durationMs, jawScale = 1) {
225
+ this.core.transition_viseme(visemeIndex >>> 0, to, durationMs, jawScale);
226
+ }
227
+ update(deltaSeconds) {
228
+ return this.core.update(deltaSeconds);
229
+ }
230
+ activeTransitionCount() {
231
+ return this.core.active_transition_count();
232
+ }
233
+ clearTransitions() {
234
+ this.core.clear_transitions();
235
+ }
726
236
  getAU(id) {
727
237
  return this.core.get_au(id >>> 0);
728
238
  }
@@ -758,7 +268,13 @@ var WasmRuntimeCore = class {
758
268
  };
759
269
  }
760
270
  reloadBindings() {
761
- this.core.configure_with_profile(JSON.stringify(this.profile), JSON.stringify(this.model));
271
+ const profileJson = JSON.stringify(this.profile);
272
+ const modelJson = JSON.stringify(this.model);
273
+ if (this.allowEmptyBindings) {
274
+ this.core.configure(profileJson, modelJson);
275
+ } else {
276
+ this.core.configure_with_profile(profileJson, modelJson);
277
+ }
762
278
  }
763
279
  };
764
280
  function unpackBoneFrameDelta(values) {
@@ -802,6 +318,6 @@ function unpackMorphFrameDelta(values) {
802
318
  return writes;
803
319
  }
804
320
 
805
- export { MESH_PROPORTIONS_FIELDS, MESH_PROPORTIONS_STRIDE, TEMPLATE_SKELETON_FIT_METADATA_KIND, TEMPLATE_SKELETON_FIT_METADATA_VERSION, TEMPLATE_SKELETON_FIT_SOLUTION_FIELDS, TEMPLATE_SKELETON_FIT_SOLUTION_STRIDE, TEMPLATE_SKELETON_FIT_STATUSES, TEMPLATE_SKELETON_FIT_TRANSFORM_FIELDS, TEMPLATE_SKELETON_FIT_TRANSFORM_STRIDE, TEMPLATE_SKELETON_FIT_VERTICAL_ANCHORS, TEMPLATE_SKELETON_FIT_VERTICAL_AXES, TsClipCompiler, TsRuntimeCore, WasmRuntimeCore, composeTemplateSkeletonFitTransform, isTemplateSkeletonFitStatus, numericArrayToNumbers, unpackBoneFrameDelta, unpackMorphFrameDelta, validateTemplateSkeletonFitMetadata };
321
+ export { MESH_PROPORTIONS_FIELDS, MESH_PROPORTIONS_STRIDE, TEMPLATE_SKELETON_FIT_METADATA_KIND, TEMPLATE_SKELETON_FIT_METADATA_VERSION, TEMPLATE_SKELETON_FIT_SOLUTION_FIELDS, TEMPLATE_SKELETON_FIT_SOLUTION_STRIDE, TEMPLATE_SKELETON_FIT_STATUSES, TEMPLATE_SKELETON_FIT_TRANSFORM_FIELDS, TEMPLATE_SKELETON_FIT_TRANSFORM_STRIDE, TEMPLATE_SKELETON_FIT_VERTICAL_ANCHORS, TEMPLATE_SKELETON_FIT_VERTICAL_AXES, TsClipCompiler, WasmRuntimeCore, composeTemplateSkeletonFitTransform, isTemplateSkeletonFitStatus, numericArrayToNumbers, unpackBoneFrameDelta, unpackMorphFrameDelta, validateTemplateSkeletonFitMetadata };
806
322
  //# sourceMappingURL=core.js.map
807
323
  //# sourceMappingURL=core.js.map