@omote/core 0.5.2 → 0.5.3
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.d.mts +4 -18
- package/dist/index.d.ts +4 -18
- package/dist/index.js +78 -95
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +78 -95
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -761,80 +761,6 @@ var A2EProcessor = class {
|
|
|
761
761
|
}
|
|
762
762
|
};
|
|
763
763
|
|
|
764
|
-
// src/inference/BlendshapeSmoother.ts
|
|
765
|
-
var NUM_BLENDSHAPES = 52;
|
|
766
|
-
var BlendshapeSmoother = class {
|
|
767
|
-
constructor(config) {
|
|
768
|
-
/** Whether any target has been set */
|
|
769
|
-
this._hasTarget = false;
|
|
770
|
-
this.halflife = config?.halflife ?? 0.06;
|
|
771
|
-
this.values = new Float32Array(NUM_BLENDSHAPES);
|
|
772
|
-
this.velocities = new Float32Array(NUM_BLENDSHAPES);
|
|
773
|
-
this.targets = new Float32Array(NUM_BLENDSHAPES);
|
|
774
|
-
}
|
|
775
|
-
/** Whether a target frame has been set (false until first setTarget call) */
|
|
776
|
-
get hasTarget() {
|
|
777
|
-
return this._hasTarget;
|
|
778
|
-
}
|
|
779
|
-
/**
|
|
780
|
-
* Set new target frame from inference output.
|
|
781
|
-
* Springs will converge toward these values on subsequent update() calls.
|
|
782
|
-
*/
|
|
783
|
-
setTarget(frame) {
|
|
784
|
-
this.targets.set(frame);
|
|
785
|
-
this._hasTarget = true;
|
|
786
|
-
}
|
|
787
|
-
/**
|
|
788
|
-
* Advance all 52 springs by `dt` seconds and return the smoothed frame.
|
|
789
|
-
*
|
|
790
|
-
* Call this every render frame (e.g., inside requestAnimationFrame).
|
|
791
|
-
* Returns the internal values buffer — do NOT mutate the returned array.
|
|
792
|
-
*
|
|
793
|
-
* @param dt - Time step in seconds (e.g., 1/60 for 60fps)
|
|
794
|
-
* @returns Smoothed blendshape values (Float32Array of 52)
|
|
795
|
-
*/
|
|
796
|
-
update(dt) {
|
|
797
|
-
if (!this._hasTarget) {
|
|
798
|
-
return this.values;
|
|
799
|
-
}
|
|
800
|
-
if (this.halflife <= 0) {
|
|
801
|
-
this.values.set(this.targets);
|
|
802
|
-
this.velocities.fill(0);
|
|
803
|
-
return this.values;
|
|
804
|
-
}
|
|
805
|
-
const damping = Math.LN2 / this.halflife;
|
|
806
|
-
const eydt = Math.exp(-damping * dt);
|
|
807
|
-
for (let i = 0; i < NUM_BLENDSHAPES; i++) {
|
|
808
|
-
const j0 = this.values[i] - this.targets[i];
|
|
809
|
-
const j1 = this.velocities[i] + j0 * damping;
|
|
810
|
-
this.values[i] = eydt * (j0 + j1 * dt) + this.targets[i];
|
|
811
|
-
this.velocities[i] = eydt * (this.velocities[i] - j1 * damping * dt);
|
|
812
|
-
this.values[i] = Math.max(0, Math.min(1, this.values[i]));
|
|
813
|
-
}
|
|
814
|
-
return this.values;
|
|
815
|
-
}
|
|
816
|
-
/**
|
|
817
|
-
* Decay all spring targets to neutral (0).
|
|
818
|
-
*
|
|
819
|
-
* Call when inference stalls (no new frames for threshold duration).
|
|
820
|
-
* The springs will smoothly close the mouth / relax the face over
|
|
821
|
-
* the halflife period rather than freezing.
|
|
822
|
-
*/
|
|
823
|
-
decayToNeutral() {
|
|
824
|
-
this.targets.fill(0);
|
|
825
|
-
}
|
|
826
|
-
/**
|
|
827
|
-
* Reset all state (values, velocities, targets).
|
|
828
|
-
* Call when starting a new playback session.
|
|
829
|
-
*/
|
|
830
|
-
reset() {
|
|
831
|
-
this.values.fill(0);
|
|
832
|
-
this.velocities.fill(0);
|
|
833
|
-
this.targets.fill(0);
|
|
834
|
-
this._hasTarget = false;
|
|
835
|
-
}
|
|
836
|
-
};
|
|
837
|
-
|
|
838
764
|
// src/telemetry/exporters/console.ts
|
|
839
765
|
var ConsoleExporter = class {
|
|
840
766
|
constructor(options = {}) {
|
|
@@ -2891,16 +2817,11 @@ var FullFacePipeline = class extends EventEmitter {
|
|
|
2891
2817
|
this.lastNewFrameTime = 0;
|
|
2892
2818
|
this.lastKnownLamFrame = null;
|
|
2893
2819
|
this.staleWarningEmitted = false;
|
|
2894
|
-
// Frame loop timing (for dt calculation)
|
|
2895
|
-
this.lastFrameLoopTime = 0;
|
|
2896
2820
|
// Diagnostic logging counter
|
|
2897
2821
|
this.frameLoopCount = 0;
|
|
2898
2822
|
const sampleRate = options.sampleRate ?? 16e3;
|
|
2899
2823
|
this.profile = options.profile ?? {};
|
|
2900
2824
|
this.staleThresholdMs = options.staleThresholdMs ?? 2e3;
|
|
2901
|
-
this.smoother = new BlendshapeSmoother({
|
|
2902
|
-
halflife: options.smoothingHalflife ?? 0.06
|
|
2903
|
-
});
|
|
2904
2825
|
const isCpuModel = options.lam.modelId === "wav2arkit_cpu";
|
|
2905
2826
|
const chunkSize = options.chunkSize ?? options.lam.chunkSize ?? 16e3;
|
|
2906
2827
|
const chunkAccumulationMs = chunkSize / sampleRate * 1e3;
|
|
@@ -2983,9 +2904,7 @@ var FullFacePipeline = class extends EventEmitter {
|
|
|
2983
2904
|
this.lastNewFrameTime = 0;
|
|
2984
2905
|
this.lastKnownLamFrame = null;
|
|
2985
2906
|
this.staleWarningEmitted = false;
|
|
2986
|
-
this.lastFrameLoopTime = 0;
|
|
2987
2907
|
this.frameLoopCount = 0;
|
|
2988
|
-
this.smoother.reset();
|
|
2989
2908
|
this.scheduler.warmup();
|
|
2990
2909
|
this.startFrameLoop();
|
|
2991
2910
|
this.startMonitoring();
|
|
@@ -3020,22 +2939,16 @@ var FullFacePipeline = class extends EventEmitter {
|
|
|
3020
2939
|
/**
|
|
3021
2940
|
* Start frame animation loop
|
|
3022
2941
|
*
|
|
3023
|
-
*
|
|
3024
|
-
*
|
|
3025
|
-
*
|
|
3026
|
-
* to neutral when inference stalls.
|
|
2942
|
+
* Polls A2EProcessor at render rate (60fps) for the latest inference frame
|
|
2943
|
+
* matching the current AudioContext time. Between inference batches (~30fps
|
|
2944
|
+
* bursts), getFrameForTime() holds the last frame.
|
|
3027
2945
|
*/
|
|
3028
2946
|
startFrameLoop() {
|
|
3029
|
-
this.lastFrameLoopTime = 0;
|
|
3030
2947
|
const updateFrame = () => {
|
|
3031
|
-
const now = performance.now() / 1e3;
|
|
3032
|
-
const dt = this.lastFrameLoopTime > 0 ? now - this.lastFrameLoopTime : 1 / 60;
|
|
3033
|
-
this.lastFrameLoopTime = now;
|
|
3034
2948
|
this.frameLoopCount++;
|
|
3035
2949
|
const currentTime = this.scheduler.getCurrentTime();
|
|
3036
2950
|
const lamFrame = this.processor.getFrameForTime(currentTime);
|
|
3037
2951
|
if (lamFrame && lamFrame !== this.lastKnownLamFrame) {
|
|
3038
|
-
this.smoother.setTarget(lamFrame);
|
|
3039
2952
|
this.lastNewFrameTime = performance.now();
|
|
3040
2953
|
this.lastKnownLamFrame = lamFrame;
|
|
3041
2954
|
this.staleWarningEmitted = false;
|
|
@@ -3055,17 +2968,15 @@ var FullFacePipeline = class extends EventEmitter {
|
|
|
3055
2968
|
currentTime: currentTime.toFixed(3),
|
|
3056
2969
|
playbackEndTime: this.scheduler.getPlaybackEndTime().toFixed(3),
|
|
3057
2970
|
queuedFrames: this.processor.queuedFrameCount,
|
|
3058
|
-
hasTarget: this.smoother.hasTarget,
|
|
3059
2971
|
playbackStarted: this.playbackStarted,
|
|
3060
2972
|
msSinceNewFrame: this.lastNewFrameTime > 0 ? Math.round(performance.now() - this.lastNewFrameTime) : -1,
|
|
3061
2973
|
processorFill: this.processor.fillLevel.toFixed(2)
|
|
3062
2974
|
});
|
|
3063
2975
|
}
|
|
3064
2976
|
if (this.playbackStarted && this.lastNewFrameTime > 0 && performance.now() - this.lastNewFrameTime > this.staleThresholdMs) {
|
|
3065
|
-
this.smoother.decayToNeutral();
|
|
3066
2977
|
if (!this.staleWarningEmitted) {
|
|
3067
2978
|
this.staleWarningEmitted = true;
|
|
3068
|
-
logger4.warn("A2E stalled \u2014
|
|
2979
|
+
logger4.warn("A2E stalled \u2014 no new inference frames", {
|
|
3069
2980
|
staleDurationMs: Math.round(performance.now() - this.lastNewFrameTime),
|
|
3070
2981
|
queuedFrames: this.processor.queuedFrameCount
|
|
3071
2982
|
});
|
|
@@ -3104,12 +3015,10 @@ var FullFacePipeline = class extends EventEmitter {
|
|
|
3104
3015
|
await this.scheduler.cancelAll(fadeOutMs);
|
|
3105
3016
|
this.coalescer.reset();
|
|
3106
3017
|
this.processor.reset();
|
|
3107
|
-
this.smoother.reset();
|
|
3108
3018
|
this.playbackStarted = false;
|
|
3109
3019
|
this.lastNewFrameTime = 0;
|
|
3110
3020
|
this.lastKnownLamFrame = null;
|
|
3111
3021
|
this.staleWarningEmitted = false;
|
|
3112
|
-
this.lastFrameLoopTime = 0;
|
|
3113
3022
|
this.emit("playback_complete", void 0);
|
|
3114
3023
|
}
|
|
3115
3024
|
/**
|
|
@@ -6995,6 +6904,80 @@ var A2EWithFallback = class {
|
|
|
6995
6904
|
}
|
|
6996
6905
|
};
|
|
6997
6906
|
|
|
6907
|
+
// src/inference/BlendshapeSmoother.ts
|
|
6908
|
+
var NUM_BLENDSHAPES = 52;
|
|
6909
|
+
var BlendshapeSmoother = class {
|
|
6910
|
+
constructor(config) {
|
|
6911
|
+
/** Whether any target has been set */
|
|
6912
|
+
this._hasTarget = false;
|
|
6913
|
+
this.halflife = config?.halflife ?? 0.06;
|
|
6914
|
+
this.values = new Float32Array(NUM_BLENDSHAPES);
|
|
6915
|
+
this.velocities = new Float32Array(NUM_BLENDSHAPES);
|
|
6916
|
+
this.targets = new Float32Array(NUM_BLENDSHAPES);
|
|
6917
|
+
}
|
|
6918
|
+
/** Whether a target frame has been set (false until first setTarget call) */
|
|
6919
|
+
get hasTarget() {
|
|
6920
|
+
return this._hasTarget;
|
|
6921
|
+
}
|
|
6922
|
+
/**
|
|
6923
|
+
* Set new target frame from inference output.
|
|
6924
|
+
* Springs will converge toward these values on subsequent update() calls.
|
|
6925
|
+
*/
|
|
6926
|
+
setTarget(frame) {
|
|
6927
|
+
this.targets.set(frame);
|
|
6928
|
+
this._hasTarget = true;
|
|
6929
|
+
}
|
|
6930
|
+
/**
|
|
6931
|
+
* Advance all 52 springs by `dt` seconds and return the smoothed frame.
|
|
6932
|
+
*
|
|
6933
|
+
* Call this every render frame (e.g., inside requestAnimationFrame).
|
|
6934
|
+
* Returns the internal values buffer — do NOT mutate the returned array.
|
|
6935
|
+
*
|
|
6936
|
+
* @param dt - Time step in seconds (e.g., 1/60 for 60fps)
|
|
6937
|
+
* @returns Smoothed blendshape values (Float32Array of 52)
|
|
6938
|
+
*/
|
|
6939
|
+
update(dt) {
|
|
6940
|
+
if (!this._hasTarget) {
|
|
6941
|
+
return this.values;
|
|
6942
|
+
}
|
|
6943
|
+
if (this.halflife <= 0) {
|
|
6944
|
+
this.values.set(this.targets);
|
|
6945
|
+
this.velocities.fill(0);
|
|
6946
|
+
return this.values;
|
|
6947
|
+
}
|
|
6948
|
+
const damping = Math.LN2 / this.halflife;
|
|
6949
|
+
const eydt = Math.exp(-damping * dt);
|
|
6950
|
+
for (let i = 0; i < NUM_BLENDSHAPES; i++) {
|
|
6951
|
+
const j0 = this.values[i] - this.targets[i];
|
|
6952
|
+
const j1 = this.velocities[i] + j0 * damping;
|
|
6953
|
+
this.values[i] = eydt * (j0 + j1 * dt) + this.targets[i];
|
|
6954
|
+
this.velocities[i] = eydt * (this.velocities[i] - j1 * damping * dt);
|
|
6955
|
+
this.values[i] = Math.max(0, Math.min(1, this.values[i]));
|
|
6956
|
+
}
|
|
6957
|
+
return this.values;
|
|
6958
|
+
}
|
|
6959
|
+
/**
|
|
6960
|
+
* Decay all spring targets to neutral (0).
|
|
6961
|
+
*
|
|
6962
|
+
* Call when inference stalls (no new frames for threshold duration).
|
|
6963
|
+
* The springs will smoothly close the mouth / relax the face over
|
|
6964
|
+
* the halflife period rather than freezing.
|
|
6965
|
+
*/
|
|
6966
|
+
decayToNeutral() {
|
|
6967
|
+
this.targets.fill(0);
|
|
6968
|
+
}
|
|
6969
|
+
/**
|
|
6970
|
+
* Reset all state (values, velocities, targets).
|
|
6971
|
+
* Call when starting a new playback session.
|
|
6972
|
+
*/
|
|
6973
|
+
reset() {
|
|
6974
|
+
this.values.fill(0);
|
|
6975
|
+
this.velocities.fill(0);
|
|
6976
|
+
this.targets.fill(0);
|
|
6977
|
+
this._hasTarget = false;
|
|
6978
|
+
}
|
|
6979
|
+
};
|
|
6980
|
+
|
|
6998
6981
|
// src/animation/audioEnergy.ts
|
|
6999
6982
|
function calculateRMS(samples) {
|
|
7000
6983
|
if (samples.length === 0) return 0;
|