rig-play 1.11.1 → 1.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +213 -9
- package/dist/index.js.map +1 -1
- package/dist/player.d.ts +10 -7
- package/dist/player.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8777,6 +8777,116 @@ function applySetToPose(view, raw, set) {
|
|
|
8777
8777
|
clips
|
|
8778
8778
|
};
|
|
8779
8779
|
}
|
|
8780
|
+
const SEEK_FINE_STEP_LIMIT = 4096;
|
|
8781
|
+
const SEEK_COARSE_STRIDE = 8;
|
|
8782
|
+
const SEEK_EXACT_LIMIT = 1024;
|
|
8783
|
+
function capturePhysicsContext(ctx) {
|
|
8784
|
+
const states = /* @__PURE__ */ new Map();
|
|
8785
|
+
for (const [name, s] of ctx.states) states.set(name, { ...s });
|
|
8786
|
+
return {
|
|
8787
|
+
phase: ctx.phase,
|
|
8788
|
+
time: ctx.time,
|
|
8789
|
+
last: ctx.last,
|
|
8790
|
+
loop: ctx.loop,
|
|
8791
|
+
env: ctx.env,
|
|
8792
|
+
states
|
|
8793
|
+
};
|
|
8794
|
+
}
|
|
8795
|
+
function restorePhysicsContext(ctx, snap) {
|
|
8796
|
+
ctx.phase = snap.phase;
|
|
8797
|
+
ctx.time = snap.time;
|
|
8798
|
+
ctx.last = snap.last;
|
|
8799
|
+
if (snap.loop === void 0) delete ctx.loop;
|
|
8800
|
+
else ctx.loop = snap.loop;
|
|
8801
|
+
if (snap.env === void 0) delete ctx.env;
|
|
8802
|
+
else ctx.env = snap.env;
|
|
8803
|
+
ctx.states.clear();
|
|
8804
|
+
for (const [name, s] of snap.states) ctx.states.set(name, { ...s });
|
|
8805
|
+
}
|
|
8806
|
+
function captureStepperState(stepper) {
|
|
8807
|
+
if ("first" in stepper) {
|
|
8808
|
+
const internal2 = stepper;
|
|
8809
|
+
return {
|
|
8810
|
+
kind: "track",
|
|
8811
|
+
steps: internal2.steps,
|
|
8812
|
+
latest: internal2.latest,
|
|
8813
|
+
refused: internal2.refused,
|
|
8814
|
+
trackTime: internal2.track.trackTime,
|
|
8815
|
+
last: internal2.track.last,
|
|
8816
|
+
ctx: capturePhysicsContext(internal2.track.ctx)
|
|
8817
|
+
};
|
|
8818
|
+
}
|
|
8819
|
+
const internal = stepper;
|
|
8820
|
+
const entry = internal.mixer.tracks[0] ?? null;
|
|
8821
|
+
return {
|
|
8822
|
+
kind: "tracks",
|
|
8823
|
+
started: internal.started,
|
|
8824
|
+
steps: internal.steps,
|
|
8825
|
+
time: internal.time,
|
|
8826
|
+
refused: internal.refused,
|
|
8827
|
+
animationsChanged: internal.mixer.animationsChanged,
|
|
8828
|
+
propertyIds: new Map(internal.mixer.propertyIds),
|
|
8829
|
+
entry: entry === null ? null : {
|
|
8830
|
+
delay: entry.delay,
|
|
8831
|
+
trackTime: entry.trackTime,
|
|
8832
|
+
trackLast: entry.trackLast,
|
|
8833
|
+
nextTrackLast: entry.nextTrackLast,
|
|
8834
|
+
trackEnd: entry.trackEnd,
|
|
8835
|
+
animationLast: entry.animationLast,
|
|
8836
|
+
nextAnimationLast: entry.nextAnimationLast,
|
|
8837
|
+
mixTime: entry.mixTime,
|
|
8838
|
+
mixDuration: entry.mixDuration,
|
|
8839
|
+
totalAlpha: entry.totalAlpha,
|
|
8840
|
+
alpha: entry.alpha,
|
|
8841
|
+
additive: entry.additive,
|
|
8842
|
+
keepHold: entry.keepHold,
|
|
8843
|
+
timelineMode: [...entry.timelineMode],
|
|
8844
|
+
timelineHoldMix: [...entry.timelineHoldMix],
|
|
8845
|
+
timelinesRotation: [...entry.timelinesRotation]
|
|
8846
|
+
},
|
|
8847
|
+
ctx: capturePhysicsContext(internal.path.ctx)
|
|
8848
|
+
};
|
|
8849
|
+
}
|
|
8850
|
+
function restoreStepperState(stepper, snap) {
|
|
8851
|
+
if (snap.kind === "track") {
|
|
8852
|
+
const internal2 = stepper;
|
|
8853
|
+
internal2.steps = snap.steps;
|
|
8854
|
+
internal2.latest = snap.latest;
|
|
8855
|
+
internal2.refused = snap.refused;
|
|
8856
|
+
internal2.track.trackTime = snap.trackTime;
|
|
8857
|
+
internal2.track.last = snap.last;
|
|
8858
|
+
restorePhysicsContext(internal2.track.ctx, snap.ctx);
|
|
8859
|
+
return;
|
|
8860
|
+
}
|
|
8861
|
+
const internal = stepper;
|
|
8862
|
+
internal.started = snap.started;
|
|
8863
|
+
internal.steps = snap.steps;
|
|
8864
|
+
internal.time = snap.time;
|
|
8865
|
+
internal.refused = snap.refused;
|
|
8866
|
+
internal.mixer.animationsChanged = snap.animationsChanged;
|
|
8867
|
+
internal.mixer.propertyIds.clear();
|
|
8868
|
+
for (const [k, v] of snap.propertyIds) internal.mixer.propertyIds.set(k, v);
|
|
8869
|
+
const entry = internal.mixer.tracks[0] ?? null;
|
|
8870
|
+
if (entry !== null && snap.entry !== null) {
|
|
8871
|
+
entry.delay = snap.entry.delay;
|
|
8872
|
+
entry.trackTime = snap.entry.trackTime;
|
|
8873
|
+
entry.trackLast = snap.entry.trackLast;
|
|
8874
|
+
entry.nextTrackLast = snap.entry.nextTrackLast;
|
|
8875
|
+
entry.trackEnd = snap.entry.trackEnd;
|
|
8876
|
+
entry.animationLast = snap.entry.animationLast;
|
|
8877
|
+
entry.nextAnimationLast = snap.entry.nextAnimationLast;
|
|
8878
|
+
entry.mixTime = snap.entry.mixTime;
|
|
8879
|
+
entry.mixDuration = snap.entry.mixDuration;
|
|
8880
|
+
entry.totalAlpha = snap.entry.totalAlpha;
|
|
8881
|
+
entry.alpha = snap.entry.alpha;
|
|
8882
|
+
entry.additive = snap.entry.additive;
|
|
8883
|
+
entry.keepHold = snap.entry.keepHold;
|
|
8884
|
+
entry.timelineMode = [...snap.entry.timelineMode];
|
|
8885
|
+
entry.timelineHoldMix = [...snap.entry.timelineHoldMix];
|
|
8886
|
+
entry.timelinesRotation = [...snap.entry.timelinesRotation];
|
|
8887
|
+
}
|
|
8888
|
+
restorePhysicsContext(internal.path.ctx, snap.ctx);
|
|
8889
|
+
}
|
|
8780
8890
|
class RigPlayer {
|
|
8781
8891
|
/**
|
|
8782
8892
|
* The renderer this player draws through — its knobs and counters are the
|
|
@@ -8831,6 +8941,7 @@ class RigPlayer {
|
|
|
8831
8941
|
/** The un-overridden pose from the track/tracks (or setup pose when `setSet` is called before `play`). */
|
|
8832
8942
|
rawPose = null;
|
|
8833
8943
|
setup = null;
|
|
8944
|
+
seekCache = null;
|
|
8834
8945
|
setList;
|
|
8835
8946
|
setsByName;
|
|
8836
8947
|
activeSet = null;
|
|
@@ -8928,6 +9039,7 @@ class RigPlayer {
|
|
|
8928
9039
|
const alpha = options.alpha ?? 1;
|
|
8929
9040
|
const additive = options.additive ?? false;
|
|
8930
9041
|
this.paused = false;
|
|
9042
|
+
this.clearSeekCache();
|
|
8931
9043
|
const plain = track === 0 && mix === 0 && alpha === 1 && !additive;
|
|
8932
9044
|
if (!plain) this.beyondBase = true;
|
|
8933
9045
|
if (this.tracks === null && plain && !this.trackMode) {
|
|
@@ -8956,6 +9068,7 @@ class RigPlayer {
|
|
|
8956
9068
|
queue(name, options = {}) {
|
|
8957
9069
|
const track = options.track ?? 0;
|
|
8958
9070
|
this.beyondBase = true;
|
|
9071
|
+
this.clearSeekCache();
|
|
8959
9072
|
const tracks = this.compose();
|
|
8960
9073
|
tracks.addAnimation(track, name, { loop: options.loop ?? true, mixDuration: options.mix ?? 0, delay: options.delay ?? 0, alpha: options.alpha ?? 1, additive: options.additive ?? false });
|
|
8961
9074
|
this.trackCount = Math.max(this.trackCount, track + 1);
|
|
@@ -8968,6 +9081,7 @@ class RigPlayer {
|
|
|
8968
9081
|
*/
|
|
8969
9082
|
clear(track = 0, options = {}) {
|
|
8970
9083
|
this.beyondBase = true;
|
|
9084
|
+
this.clearSeekCache();
|
|
8971
9085
|
const tracks = this.compose();
|
|
8972
9086
|
tracks.setEmptyAnimation(track, options.mix ?? 0);
|
|
8973
9087
|
this.trackCount = Math.max(this.trackCount, track + 1);
|
|
@@ -8981,6 +9095,7 @@ class RigPlayer {
|
|
|
8981
9095
|
*/
|
|
8982
9096
|
queueClear(track = 0, options = {}) {
|
|
8983
9097
|
this.beyondBase = true;
|
|
9098
|
+
this.clearSeekCache();
|
|
8984
9099
|
const tracks = this.compose();
|
|
8985
9100
|
tracks.addEmptyAnimation(track, options.mix ?? 0, options.delay ?? 0);
|
|
8986
9101
|
this.trackCount = Math.max(this.trackCount, track + 1);
|
|
@@ -8995,6 +9110,7 @@ class RigPlayer {
|
|
|
8995
9110
|
*/
|
|
8996
9111
|
setAlpha(track, alpha) {
|
|
8997
9112
|
this.beyondBase = true;
|
|
9113
|
+
this.clearSeekCache();
|
|
8998
9114
|
const tracks = this.compose();
|
|
8999
9115
|
tracks.setAlpha(track, alpha);
|
|
9000
9116
|
this.setRawPose(tracks.step(0));
|
|
@@ -9025,6 +9141,7 @@ class RigPlayer {
|
|
|
9025
9141
|
*/
|
|
9026
9142
|
compose() {
|
|
9027
9143
|
if (this.tracks !== null) return this.tracks;
|
|
9144
|
+
this.clearSeekCache();
|
|
9028
9145
|
const tracks = openTracks(this.view, { reset: "animation", adjust: this.adjustHook, clock: physicsClockStep });
|
|
9029
9146
|
const single = this.track;
|
|
9030
9147
|
const time = single?.trackTime ?? 0;
|
|
@@ -9061,8 +9178,10 @@ class RigPlayer {
|
|
|
9061
9178
|
environment(environment) {
|
|
9062
9179
|
if (environment === null) {
|
|
9063
9180
|
this.env = null;
|
|
9181
|
+
this.clearSeekCache();
|
|
9064
9182
|
this.stepper()?.setEnvironment(DEFAULT_ENVIRONMENT);
|
|
9065
9183
|
} else if (environment !== void 0) {
|
|
9184
|
+
this.clearSeekCache();
|
|
9066
9185
|
const live = this.stepper();
|
|
9067
9186
|
if (live) {
|
|
9068
9187
|
live.setEnvironment(environment);
|
|
@@ -9101,20 +9220,99 @@ class RigPlayer {
|
|
|
9101
9220
|
this.paused = false;
|
|
9102
9221
|
}
|
|
9103
9222
|
/**
|
|
9104
|
-
* Moves a single animation on track 0 to `time`:
|
|
9105
|
-
*
|
|
9106
|
-
*
|
|
9107
|
-
* on the way are not fired.
|
|
9108
|
-
*
|
|
9109
|
-
* queue was asked for — so after any
|
|
9110
|
-
* player forward instead.
|
|
9223
|
+
* Moves a single animation on track 0 to `time`: snapshot-backed deterministic
|
|
9224
|
+
* seek (#141) that produces the exact pose and physics state of reopening at 0
|
|
9225
|
+
* and stepping forward in `seekStep` increments (the last one shorter) until
|
|
9226
|
+
* `time` is reached. Events and completes crossed on the way are not fired.
|
|
9227
|
+
* It has a meaning for one animation on one track only — the player cannot
|
|
9228
|
+
* replay when a mix, a second track or a queue was asked for — so after any
|
|
9229
|
+
* of those it refuses by name; step the player forward instead.
|
|
9111
9230
|
*/
|
|
9112
9231
|
seek(time) {
|
|
9113
9232
|
if (this.animation === null) throw new Error("seek before play: no animation is open");
|
|
9114
9233
|
if (!(time >= 0) || !Number.isFinite(time)) throw new Error(`seek time must be a finite time at or above 0, got ${String(time)}`);
|
|
9115
9234
|
if (this.beyondBase) throw new Error("seek is defined for a single animation on track 0; after a mix, another track, a queue or a clear the player cannot replay to a time — step it forward with frame/advance instead");
|
|
9116
|
-
this.
|
|
9117
|
-
this.
|
|
9235
|
+
const cache = this.ensureSeekCache();
|
|
9236
|
+
const stepper = this.tracks ?? this.track;
|
|
9237
|
+
const exactHit = cache.exact.get(time);
|
|
9238
|
+
if (exactHit !== void 0) {
|
|
9239
|
+
restoreStepperState(stepper, exactHit.state);
|
|
9240
|
+
this.rawPose = exactHit.rawPose;
|
|
9241
|
+
this.pose = exactHit.pose;
|
|
9242
|
+
return;
|
|
9243
|
+
}
|
|
9244
|
+
const steps = Math.floor(time / this.seekStep);
|
|
9245
|
+
while (cache.frontierSteps < steps) {
|
|
9246
|
+
const raw = cache.frontier.step(this.seekStep);
|
|
9247
|
+
cache.frontierSteps++;
|
|
9248
|
+
if (cache.frontierSteps <= SEEK_FINE_STEP_LIMIT || cache.frontierSteps % SEEK_COARSE_STRIDE === 0) {
|
|
9249
|
+
cache.grid.set(cache.frontierSteps, {
|
|
9250
|
+
state: captureStepperState(cache.frontier),
|
|
9251
|
+
rawPose: raw
|
|
9252
|
+
});
|
|
9253
|
+
}
|
|
9254
|
+
}
|
|
9255
|
+
const gridHit = cache.grid.get(steps);
|
|
9256
|
+
if (gridHit !== void 0) {
|
|
9257
|
+
restoreStepperState(stepper, gridHit.state);
|
|
9258
|
+
this.rawPose = gridHit.rawPose;
|
|
9259
|
+
} else {
|
|
9260
|
+
const baseStep = steps - steps % SEEK_COARSE_STRIDE;
|
|
9261
|
+
const baseSnap = cache.grid.get(baseStep);
|
|
9262
|
+
restoreStepperState(stepper, baseSnap.state);
|
|
9263
|
+
this.rawPose = baseSnap.rawPose;
|
|
9264
|
+
for (let i = baseStep; i < steps; i++) this.rawPose = stepper.step(this.seekStep);
|
|
9265
|
+
}
|
|
9266
|
+
const rest = time - stepper.trackTime;
|
|
9267
|
+
if (rest > 0) this.rawPose = stepper.step(rest);
|
|
9268
|
+
if (this.rawPose !== null) this.setRawPose(this.rawPose);
|
|
9269
|
+
if (this.rawPose !== null && this.pose !== null) {
|
|
9270
|
+
if (cache.exact.size >= SEEK_EXACT_LIMIT) {
|
|
9271
|
+
const oldest = cache.exact.keys().next().value;
|
|
9272
|
+
if (oldest !== void 0) cache.exact.delete(oldest);
|
|
9273
|
+
}
|
|
9274
|
+
cache.exact.set(time, {
|
|
9275
|
+
state: captureStepperState(stepper),
|
|
9276
|
+
rawPose: this.rawPose,
|
|
9277
|
+
pose: this.pose
|
|
9278
|
+
});
|
|
9279
|
+
}
|
|
9280
|
+
}
|
|
9281
|
+
clearSeekCache() {
|
|
9282
|
+
this.seekCache = null;
|
|
9283
|
+
}
|
|
9284
|
+
ensureSeekCache() {
|
|
9285
|
+
const mode = this.tracks !== null ? "tracks" : "track";
|
|
9286
|
+
if (this.seekCache !== null && this.seekCache.mode === mode) {
|
|
9287
|
+
return this.seekCache;
|
|
9288
|
+
}
|
|
9289
|
+
if (this.tracks === null && this.track === null) {
|
|
9290
|
+
this.reopen();
|
|
9291
|
+
}
|
|
9292
|
+
let frontier;
|
|
9293
|
+
let firstPose;
|
|
9294
|
+
if (mode === "tracks") {
|
|
9295
|
+
const tracks = openTracks(this.view, { reset: "animation", adjust: this.adjustHook, clock: physicsClockStep });
|
|
9296
|
+
tracks.setAnimation(0, this.animation, { loop: this.loop, mixDuration: 0 });
|
|
9297
|
+
firstPose = tracks.start();
|
|
9298
|
+
this.applyEnvironment(tracks);
|
|
9299
|
+
frontier = tracks;
|
|
9300
|
+
} else {
|
|
9301
|
+
const track = openTrack(this.view, this.animation, { loop: this.loop, reset: "animation", adjust: this.adjustHook, clock: physicsClockStep });
|
|
9302
|
+
firstPose = track.first;
|
|
9303
|
+
this.applyEnvironment(track);
|
|
9304
|
+
frontier = track;
|
|
9305
|
+
}
|
|
9306
|
+
const grid = /* @__PURE__ */ new Map();
|
|
9307
|
+
grid.set(0, { state: captureStepperState(frontier), rawPose: firstPose });
|
|
9308
|
+
this.seekCache = {
|
|
9309
|
+
mode,
|
|
9310
|
+
frontier,
|
|
9311
|
+
frontierSteps: 0,
|
|
9312
|
+
grid,
|
|
9313
|
+
exact: /* @__PURE__ */ new Map()
|
|
9314
|
+
};
|
|
9315
|
+
return this.seekCache;
|
|
9118
9316
|
}
|
|
9119
9317
|
/** Whatever is open, opened again with track 0's animation as `play` last set it, at pose 0: the single track, or the tracks under `tracks: true`. */
|
|
9120
9318
|
reopen() {
|
|
@@ -9217,6 +9415,7 @@ class RigPlayer {
|
|
|
9217
9415
|
this.source = frameSource(view, this.read.parsed);
|
|
9218
9416
|
this.skinName = name;
|
|
9219
9417
|
this.setup = null;
|
|
9418
|
+
this.clearSeekCache();
|
|
9220
9419
|
if (this.animation !== null && (this.track !== null || this.tracks !== null)) {
|
|
9221
9420
|
const time = this.time;
|
|
9222
9421
|
this.reopen();
|
|
@@ -9259,6 +9458,7 @@ class RigPlayer {
|
|
|
9259
9458
|
}
|
|
9260
9459
|
if (name === null) {
|
|
9261
9460
|
this.activeSet = null;
|
|
9461
|
+
this.clearSeekCache();
|
|
9262
9462
|
const base2 = this.rawPose ?? (this.setup ?? (this.setup = poseRawSetup(this.view)));
|
|
9263
9463
|
this.rawPose = base2;
|
|
9264
9464
|
this.pose = base2;
|
|
@@ -9271,6 +9471,7 @@ class RigPlayer {
|
|
|
9271
9471
|
);
|
|
9272
9472
|
}
|
|
9273
9473
|
this.activeSet = found;
|
|
9474
|
+
this.clearSeekCache();
|
|
9274
9475
|
const base = this.rawPose ?? (this.setup ?? (this.setup = poseRawSetup(this.view)));
|
|
9275
9476
|
this.rawPose = base;
|
|
9276
9477
|
this.pose = applySetToPose(this.view, base, found);
|
|
@@ -9320,6 +9521,7 @@ class RigPlayer {
|
|
|
9320
9521
|
set adjust(fn) {
|
|
9321
9522
|
if (fn !== null && typeof fn !== "function") throw new Error(`adjust must be a function or null, got ${typeof fn}`);
|
|
9322
9523
|
this.adjustFn = fn;
|
|
9524
|
+
this.clearSeekCache();
|
|
9323
9525
|
this.repose();
|
|
9324
9526
|
}
|
|
9325
9527
|
/**
|
|
@@ -9330,6 +9532,7 @@ class RigPlayer {
|
|
|
9330
9532
|
* changed, then `draw`. Nothing before `play`.
|
|
9331
9533
|
*/
|
|
9332
9534
|
repose() {
|
|
9535
|
+
this.clearSeekCache();
|
|
9333
9536
|
const stepper = this.tracks ?? this.track;
|
|
9334
9537
|
if (stepper === null || this.pose === null) return;
|
|
9335
9538
|
this.setRawPose(stepper.step(0));
|
|
@@ -9422,6 +9625,7 @@ class RigPlayer {
|
|
|
9422
9625
|
/** Removes the renderer's elements and hands its GPU pages back. The assets stay the caller's. */
|
|
9423
9626
|
dispose() {
|
|
9424
9627
|
this.renderer.dispose();
|
|
9628
|
+
this.clearSeekCache();
|
|
9425
9629
|
this.tracks = null;
|
|
9426
9630
|
this.track = null;
|
|
9427
9631
|
this.pose = null;
|