@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.d.mts
CHANGED
|
@@ -587,18 +587,7 @@ interface FullFacePipelineOptions {
|
|
|
587
587
|
/** Per-character expression weight scaling */
|
|
588
588
|
profile?: ExpressionProfile;
|
|
589
589
|
/**
|
|
590
|
-
*
|
|
591
|
-
* Controls how quickly blendshapes converge to inference targets.
|
|
592
|
-
* Lower = snappier but more jittery. Higher = smoother but laggy.
|
|
593
|
-
* Set to 0 to disable smoothing (raw frame pass-through).
|
|
594
|
-
*
|
|
595
|
-
* Default: 0.06 (60ms)
|
|
596
|
-
*/
|
|
597
|
-
smoothingHalflife?: number;
|
|
598
|
-
/**
|
|
599
|
-
* Time in ms with no new inference frames before decaying to neutral.
|
|
600
|
-
* When exceeded, spring targets are set to 0 and the face smoothly
|
|
601
|
-
* relaxes rather than freezing on the last frame.
|
|
590
|
+
* Time in ms with no new inference frames before logging a stale warning.
|
|
602
591
|
*
|
|
603
592
|
* Must be larger than the inter-batch gap (chunkSize/sampleRate + inference time).
|
|
604
593
|
* Default: 2000
|
|
@@ -646,7 +635,6 @@ declare class FullFacePipeline extends EventEmitter<FullFacePipelineEvents> {
|
|
|
646
635
|
private scheduler;
|
|
647
636
|
private coalescer;
|
|
648
637
|
private processor;
|
|
649
|
-
private smoother;
|
|
650
638
|
private playbackStarted;
|
|
651
639
|
private monitorInterval;
|
|
652
640
|
private frameAnimationId;
|
|
@@ -654,7 +642,6 @@ declare class FullFacePipeline extends EventEmitter<FullFacePipelineEvents> {
|
|
|
654
642
|
private lastKnownLamFrame;
|
|
655
643
|
private staleWarningEmitted;
|
|
656
644
|
private readonly staleThresholdMs;
|
|
657
|
-
private lastFrameLoopTime;
|
|
658
645
|
private frameLoopCount;
|
|
659
646
|
private profile;
|
|
660
647
|
constructor(options: FullFacePipelineOptions);
|
|
@@ -694,10 +681,9 @@ declare class FullFacePipeline extends EventEmitter<FullFacePipelineEvents> {
|
|
|
694
681
|
/**
|
|
695
682
|
* Start frame animation loop
|
|
696
683
|
*
|
|
697
|
-
*
|
|
698
|
-
*
|
|
699
|
-
*
|
|
700
|
-
* to neutral when inference stalls.
|
|
684
|
+
* Polls A2EProcessor at render rate (60fps) for the latest inference frame
|
|
685
|
+
* matching the current AudioContext time. Between inference batches (~30fps
|
|
686
|
+
* bursts), getFrameForTime() holds the last frame.
|
|
701
687
|
*/
|
|
702
688
|
private startFrameLoop;
|
|
703
689
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -587,18 +587,7 @@ interface FullFacePipelineOptions {
|
|
|
587
587
|
/** Per-character expression weight scaling */
|
|
588
588
|
profile?: ExpressionProfile;
|
|
589
589
|
/**
|
|
590
|
-
*
|
|
591
|
-
* Controls how quickly blendshapes converge to inference targets.
|
|
592
|
-
* Lower = snappier but more jittery. Higher = smoother but laggy.
|
|
593
|
-
* Set to 0 to disable smoothing (raw frame pass-through).
|
|
594
|
-
*
|
|
595
|
-
* Default: 0.06 (60ms)
|
|
596
|
-
*/
|
|
597
|
-
smoothingHalflife?: number;
|
|
598
|
-
/**
|
|
599
|
-
* Time in ms with no new inference frames before decaying to neutral.
|
|
600
|
-
* When exceeded, spring targets are set to 0 and the face smoothly
|
|
601
|
-
* relaxes rather than freezing on the last frame.
|
|
590
|
+
* Time in ms with no new inference frames before logging a stale warning.
|
|
602
591
|
*
|
|
603
592
|
* Must be larger than the inter-batch gap (chunkSize/sampleRate + inference time).
|
|
604
593
|
* Default: 2000
|
|
@@ -646,7 +635,6 @@ declare class FullFacePipeline extends EventEmitter<FullFacePipelineEvents> {
|
|
|
646
635
|
private scheduler;
|
|
647
636
|
private coalescer;
|
|
648
637
|
private processor;
|
|
649
|
-
private smoother;
|
|
650
638
|
private playbackStarted;
|
|
651
639
|
private monitorInterval;
|
|
652
640
|
private frameAnimationId;
|
|
@@ -654,7 +642,6 @@ declare class FullFacePipeline extends EventEmitter<FullFacePipelineEvents> {
|
|
|
654
642
|
private lastKnownLamFrame;
|
|
655
643
|
private staleWarningEmitted;
|
|
656
644
|
private readonly staleThresholdMs;
|
|
657
|
-
private lastFrameLoopTime;
|
|
658
645
|
private frameLoopCount;
|
|
659
646
|
private profile;
|
|
660
647
|
constructor(options: FullFacePipelineOptions);
|
|
@@ -694,10 +681,9 @@ declare class FullFacePipeline extends EventEmitter<FullFacePipelineEvents> {
|
|
|
694
681
|
/**
|
|
695
682
|
* Start frame animation loop
|
|
696
683
|
*
|
|
697
|
-
*
|
|
698
|
-
*
|
|
699
|
-
*
|
|
700
|
-
* to neutral when inference stalls.
|
|
684
|
+
* Polls A2EProcessor at render rate (60fps) for the latest inference frame
|
|
685
|
+
* matching the current AudioContext time. Between inference batches (~30fps
|
|
686
|
+
* bursts), getFrameForTime() holds the last frame.
|
|
701
687
|
*/
|
|
702
688
|
private startFrameLoop;
|
|
703
689
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1171,80 +1171,6 @@ var A2EProcessor = class {
|
|
|
1171
1171
|
}
|
|
1172
1172
|
};
|
|
1173
1173
|
|
|
1174
|
-
// src/inference/BlendshapeSmoother.ts
|
|
1175
|
-
var NUM_BLENDSHAPES = 52;
|
|
1176
|
-
var BlendshapeSmoother = class {
|
|
1177
|
-
constructor(config) {
|
|
1178
|
-
/** Whether any target has been set */
|
|
1179
|
-
this._hasTarget = false;
|
|
1180
|
-
this.halflife = config?.halflife ?? 0.06;
|
|
1181
|
-
this.values = new Float32Array(NUM_BLENDSHAPES);
|
|
1182
|
-
this.velocities = new Float32Array(NUM_BLENDSHAPES);
|
|
1183
|
-
this.targets = new Float32Array(NUM_BLENDSHAPES);
|
|
1184
|
-
}
|
|
1185
|
-
/** Whether a target frame has been set (false until first setTarget call) */
|
|
1186
|
-
get hasTarget() {
|
|
1187
|
-
return this._hasTarget;
|
|
1188
|
-
}
|
|
1189
|
-
/**
|
|
1190
|
-
* Set new target frame from inference output.
|
|
1191
|
-
* Springs will converge toward these values on subsequent update() calls.
|
|
1192
|
-
*/
|
|
1193
|
-
setTarget(frame) {
|
|
1194
|
-
this.targets.set(frame);
|
|
1195
|
-
this._hasTarget = true;
|
|
1196
|
-
}
|
|
1197
|
-
/**
|
|
1198
|
-
* Advance all 52 springs by `dt` seconds and return the smoothed frame.
|
|
1199
|
-
*
|
|
1200
|
-
* Call this every render frame (e.g., inside requestAnimationFrame).
|
|
1201
|
-
* Returns the internal values buffer — do NOT mutate the returned array.
|
|
1202
|
-
*
|
|
1203
|
-
* @param dt - Time step in seconds (e.g., 1/60 for 60fps)
|
|
1204
|
-
* @returns Smoothed blendshape values (Float32Array of 52)
|
|
1205
|
-
*/
|
|
1206
|
-
update(dt) {
|
|
1207
|
-
if (!this._hasTarget) {
|
|
1208
|
-
return this.values;
|
|
1209
|
-
}
|
|
1210
|
-
if (this.halflife <= 0) {
|
|
1211
|
-
this.values.set(this.targets);
|
|
1212
|
-
this.velocities.fill(0);
|
|
1213
|
-
return this.values;
|
|
1214
|
-
}
|
|
1215
|
-
const damping = Math.LN2 / this.halflife;
|
|
1216
|
-
const eydt = Math.exp(-damping * dt);
|
|
1217
|
-
for (let i = 0; i < NUM_BLENDSHAPES; i++) {
|
|
1218
|
-
const j0 = this.values[i] - this.targets[i];
|
|
1219
|
-
const j1 = this.velocities[i] + j0 * damping;
|
|
1220
|
-
this.values[i] = eydt * (j0 + j1 * dt) + this.targets[i];
|
|
1221
|
-
this.velocities[i] = eydt * (this.velocities[i] - j1 * damping * dt);
|
|
1222
|
-
this.values[i] = Math.max(0, Math.min(1, this.values[i]));
|
|
1223
|
-
}
|
|
1224
|
-
return this.values;
|
|
1225
|
-
}
|
|
1226
|
-
/**
|
|
1227
|
-
* Decay all spring targets to neutral (0).
|
|
1228
|
-
*
|
|
1229
|
-
* Call when inference stalls (no new frames for threshold duration).
|
|
1230
|
-
* The springs will smoothly close the mouth / relax the face over
|
|
1231
|
-
* the halflife period rather than freezing.
|
|
1232
|
-
*/
|
|
1233
|
-
decayToNeutral() {
|
|
1234
|
-
this.targets.fill(0);
|
|
1235
|
-
}
|
|
1236
|
-
/**
|
|
1237
|
-
* Reset all state (values, velocities, targets).
|
|
1238
|
-
* Call when starting a new playback session.
|
|
1239
|
-
*/
|
|
1240
|
-
reset() {
|
|
1241
|
-
this.values.fill(0);
|
|
1242
|
-
this.velocities.fill(0);
|
|
1243
|
-
this.targets.fill(0);
|
|
1244
|
-
this._hasTarget = false;
|
|
1245
|
-
}
|
|
1246
|
-
};
|
|
1247
|
-
|
|
1248
1174
|
// src/telemetry/exporters/console.ts
|
|
1249
1175
|
var ConsoleExporter = class {
|
|
1250
1176
|
constructor(options = {}) {
|
|
@@ -3301,16 +3227,11 @@ var FullFacePipeline = class extends EventEmitter {
|
|
|
3301
3227
|
this.lastNewFrameTime = 0;
|
|
3302
3228
|
this.lastKnownLamFrame = null;
|
|
3303
3229
|
this.staleWarningEmitted = false;
|
|
3304
|
-
// Frame loop timing (for dt calculation)
|
|
3305
|
-
this.lastFrameLoopTime = 0;
|
|
3306
3230
|
// Diagnostic logging counter
|
|
3307
3231
|
this.frameLoopCount = 0;
|
|
3308
3232
|
const sampleRate = options.sampleRate ?? 16e3;
|
|
3309
3233
|
this.profile = options.profile ?? {};
|
|
3310
3234
|
this.staleThresholdMs = options.staleThresholdMs ?? 2e3;
|
|
3311
|
-
this.smoother = new BlendshapeSmoother({
|
|
3312
|
-
halflife: options.smoothingHalflife ?? 0.06
|
|
3313
|
-
});
|
|
3314
3235
|
const isCpuModel = options.lam.modelId === "wav2arkit_cpu";
|
|
3315
3236
|
const chunkSize = options.chunkSize ?? options.lam.chunkSize ?? 16e3;
|
|
3316
3237
|
const chunkAccumulationMs = chunkSize / sampleRate * 1e3;
|
|
@@ -3393,9 +3314,7 @@ var FullFacePipeline = class extends EventEmitter {
|
|
|
3393
3314
|
this.lastNewFrameTime = 0;
|
|
3394
3315
|
this.lastKnownLamFrame = null;
|
|
3395
3316
|
this.staleWarningEmitted = false;
|
|
3396
|
-
this.lastFrameLoopTime = 0;
|
|
3397
3317
|
this.frameLoopCount = 0;
|
|
3398
|
-
this.smoother.reset();
|
|
3399
3318
|
this.scheduler.warmup();
|
|
3400
3319
|
this.startFrameLoop();
|
|
3401
3320
|
this.startMonitoring();
|
|
@@ -3430,22 +3349,16 @@ var FullFacePipeline = class extends EventEmitter {
|
|
|
3430
3349
|
/**
|
|
3431
3350
|
* Start frame animation loop
|
|
3432
3351
|
*
|
|
3433
|
-
*
|
|
3434
|
-
*
|
|
3435
|
-
*
|
|
3436
|
-
* to neutral when inference stalls.
|
|
3352
|
+
* Polls A2EProcessor at render rate (60fps) for the latest inference frame
|
|
3353
|
+
* matching the current AudioContext time. Between inference batches (~30fps
|
|
3354
|
+
* bursts), getFrameForTime() holds the last frame.
|
|
3437
3355
|
*/
|
|
3438
3356
|
startFrameLoop() {
|
|
3439
|
-
this.lastFrameLoopTime = 0;
|
|
3440
3357
|
const updateFrame = () => {
|
|
3441
|
-
const now = performance.now() / 1e3;
|
|
3442
|
-
const dt = this.lastFrameLoopTime > 0 ? now - this.lastFrameLoopTime : 1 / 60;
|
|
3443
|
-
this.lastFrameLoopTime = now;
|
|
3444
3358
|
this.frameLoopCount++;
|
|
3445
3359
|
const currentTime = this.scheduler.getCurrentTime();
|
|
3446
3360
|
const lamFrame = this.processor.getFrameForTime(currentTime);
|
|
3447
3361
|
if (lamFrame && lamFrame !== this.lastKnownLamFrame) {
|
|
3448
|
-
this.smoother.setTarget(lamFrame);
|
|
3449
3362
|
this.lastNewFrameTime = performance.now();
|
|
3450
3363
|
this.lastKnownLamFrame = lamFrame;
|
|
3451
3364
|
this.staleWarningEmitted = false;
|
|
@@ -3465,17 +3378,15 @@ var FullFacePipeline = class extends EventEmitter {
|
|
|
3465
3378
|
currentTime: currentTime.toFixed(3),
|
|
3466
3379
|
playbackEndTime: this.scheduler.getPlaybackEndTime().toFixed(3),
|
|
3467
3380
|
queuedFrames: this.processor.queuedFrameCount,
|
|
3468
|
-
hasTarget: this.smoother.hasTarget,
|
|
3469
3381
|
playbackStarted: this.playbackStarted,
|
|
3470
3382
|
msSinceNewFrame: this.lastNewFrameTime > 0 ? Math.round(performance.now() - this.lastNewFrameTime) : -1,
|
|
3471
3383
|
processorFill: this.processor.fillLevel.toFixed(2)
|
|
3472
3384
|
});
|
|
3473
3385
|
}
|
|
3474
3386
|
if (this.playbackStarted && this.lastNewFrameTime > 0 && performance.now() - this.lastNewFrameTime > this.staleThresholdMs) {
|
|
3475
|
-
this.smoother.decayToNeutral();
|
|
3476
3387
|
if (!this.staleWarningEmitted) {
|
|
3477
3388
|
this.staleWarningEmitted = true;
|
|
3478
|
-
logger4.warn("A2E stalled \u2014
|
|
3389
|
+
logger4.warn("A2E stalled \u2014 no new inference frames", {
|
|
3479
3390
|
staleDurationMs: Math.round(performance.now() - this.lastNewFrameTime),
|
|
3480
3391
|
queuedFrames: this.processor.queuedFrameCount
|
|
3481
3392
|
});
|
|
@@ -3514,12 +3425,10 @@ var FullFacePipeline = class extends EventEmitter {
|
|
|
3514
3425
|
await this.scheduler.cancelAll(fadeOutMs);
|
|
3515
3426
|
this.coalescer.reset();
|
|
3516
3427
|
this.processor.reset();
|
|
3517
|
-
this.smoother.reset();
|
|
3518
3428
|
this.playbackStarted = false;
|
|
3519
3429
|
this.lastNewFrameTime = 0;
|
|
3520
3430
|
this.lastKnownLamFrame = null;
|
|
3521
3431
|
this.staleWarningEmitted = false;
|
|
3522
|
-
this.lastFrameLoopTime = 0;
|
|
3523
3432
|
this.emit("playback_complete", void 0);
|
|
3524
3433
|
}
|
|
3525
3434
|
/**
|
|
@@ -7405,6 +7314,80 @@ var A2EWithFallback = class {
|
|
|
7405
7314
|
}
|
|
7406
7315
|
};
|
|
7407
7316
|
|
|
7317
|
+
// src/inference/BlendshapeSmoother.ts
|
|
7318
|
+
var NUM_BLENDSHAPES = 52;
|
|
7319
|
+
var BlendshapeSmoother = class {
|
|
7320
|
+
constructor(config) {
|
|
7321
|
+
/** Whether any target has been set */
|
|
7322
|
+
this._hasTarget = false;
|
|
7323
|
+
this.halflife = config?.halflife ?? 0.06;
|
|
7324
|
+
this.values = new Float32Array(NUM_BLENDSHAPES);
|
|
7325
|
+
this.velocities = new Float32Array(NUM_BLENDSHAPES);
|
|
7326
|
+
this.targets = new Float32Array(NUM_BLENDSHAPES);
|
|
7327
|
+
}
|
|
7328
|
+
/** Whether a target frame has been set (false until first setTarget call) */
|
|
7329
|
+
get hasTarget() {
|
|
7330
|
+
return this._hasTarget;
|
|
7331
|
+
}
|
|
7332
|
+
/**
|
|
7333
|
+
* Set new target frame from inference output.
|
|
7334
|
+
* Springs will converge toward these values on subsequent update() calls.
|
|
7335
|
+
*/
|
|
7336
|
+
setTarget(frame) {
|
|
7337
|
+
this.targets.set(frame);
|
|
7338
|
+
this._hasTarget = true;
|
|
7339
|
+
}
|
|
7340
|
+
/**
|
|
7341
|
+
* Advance all 52 springs by `dt` seconds and return the smoothed frame.
|
|
7342
|
+
*
|
|
7343
|
+
* Call this every render frame (e.g., inside requestAnimationFrame).
|
|
7344
|
+
* Returns the internal values buffer — do NOT mutate the returned array.
|
|
7345
|
+
*
|
|
7346
|
+
* @param dt - Time step in seconds (e.g., 1/60 for 60fps)
|
|
7347
|
+
* @returns Smoothed blendshape values (Float32Array of 52)
|
|
7348
|
+
*/
|
|
7349
|
+
update(dt) {
|
|
7350
|
+
if (!this._hasTarget) {
|
|
7351
|
+
return this.values;
|
|
7352
|
+
}
|
|
7353
|
+
if (this.halflife <= 0) {
|
|
7354
|
+
this.values.set(this.targets);
|
|
7355
|
+
this.velocities.fill(0);
|
|
7356
|
+
return this.values;
|
|
7357
|
+
}
|
|
7358
|
+
const damping = Math.LN2 / this.halflife;
|
|
7359
|
+
const eydt = Math.exp(-damping * dt);
|
|
7360
|
+
for (let i = 0; i < NUM_BLENDSHAPES; i++) {
|
|
7361
|
+
const j0 = this.values[i] - this.targets[i];
|
|
7362
|
+
const j1 = this.velocities[i] + j0 * damping;
|
|
7363
|
+
this.values[i] = eydt * (j0 + j1 * dt) + this.targets[i];
|
|
7364
|
+
this.velocities[i] = eydt * (this.velocities[i] - j1 * damping * dt);
|
|
7365
|
+
this.values[i] = Math.max(0, Math.min(1, this.values[i]));
|
|
7366
|
+
}
|
|
7367
|
+
return this.values;
|
|
7368
|
+
}
|
|
7369
|
+
/**
|
|
7370
|
+
* Decay all spring targets to neutral (0).
|
|
7371
|
+
*
|
|
7372
|
+
* Call when inference stalls (no new frames for threshold duration).
|
|
7373
|
+
* The springs will smoothly close the mouth / relax the face over
|
|
7374
|
+
* the halflife period rather than freezing.
|
|
7375
|
+
*/
|
|
7376
|
+
decayToNeutral() {
|
|
7377
|
+
this.targets.fill(0);
|
|
7378
|
+
}
|
|
7379
|
+
/**
|
|
7380
|
+
* Reset all state (values, velocities, targets).
|
|
7381
|
+
* Call when starting a new playback session.
|
|
7382
|
+
*/
|
|
7383
|
+
reset() {
|
|
7384
|
+
this.values.fill(0);
|
|
7385
|
+
this.velocities.fill(0);
|
|
7386
|
+
this.targets.fill(0);
|
|
7387
|
+
this._hasTarget = false;
|
|
7388
|
+
}
|
|
7389
|
+
};
|
|
7390
|
+
|
|
7408
7391
|
// src/animation/audioEnergy.ts
|
|
7409
7392
|
function calculateRMS(samples) {
|
|
7410
7393
|
if (samples.length === 0) return 0;
|