@codexo/exojs 0.15.1 → 0.15.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/exo.iife.js CHANGED
@@ -419,8 +419,10 @@ var Exo = (function (exports) {
419
419
  this._onStart?.();
420
420
  }
421
421
  this._elapsed += deltaSeconds;
422
- // Clamp to duration for this cycle.
423
- if (this._elapsed >= this._duration) {
422
+ // Clamp to duration for this cycle, remembering the overshoot so it can
423
+ // carry into the next repeat cycle below.
424
+ const overflow = this._elapsed - this._duration;
425
+ if (overflow >= 0) {
424
426
  this._elapsed = this._duration;
425
427
  }
426
428
  // Apply interpolation.
@@ -438,8 +440,8 @@ var Exo = (function (exports) {
438
440
  if (this._yoyo) {
439
441
  this._direction = this._direction === 1 ? -1 : 1;
440
442
  }
441
- // Reset elapsed for next cycle; carry overflow.
442
- const overflow = this._elapsed - this._duration;
443
+ // Reset elapsed for next cycle; carry the overshoot (at most one
444
+ // extra cycle per update call).
443
445
  this._elapsed = overflow > 0 ? Math.min(overflow, this._duration) : 0;
444
446
  // Apply progress for any overflow.
445
447
  if (overflow > 0) {
@@ -4821,9 +4823,19 @@ var Exo = (function (exports) {
4821
4823
  this._registered.set('master', this.master);
4822
4824
  this._registered.set('music', this.music);
4823
4825
  this._registered.set('sound', this.sound);
4824
- onAudioContextReady.add(() => {
4825
- this.onUnlock.dispatch();
4826
- });
4826
+ if (isAudioContextReady()) {
4827
+ // The shared context is already running — this manager was constructed
4828
+ // after the one-shot ready signal fired (e.g. a second Application in
4829
+ // the same process; the buses above would otherwise consume the signal
4830
+ // before this handler registers). Dispatch the unlock on a microtask so
4831
+ // subscribers registered right after construction still observe it.
4832
+ queueMicrotask(() => this.onUnlock.dispatch());
4833
+ }
4834
+ else {
4835
+ onAudioContextReady.add(() => {
4836
+ this.onUnlock.dispatch();
4837
+ });
4838
+ }
4827
4839
  }
4828
4840
  /**
4829
4841
  * When `true`, the master bus is muted while `document.hidden` is true.
@@ -13133,9 +13145,18 @@ var Exo = (function (exports) {
13133
13145
  existing._refreshBrowserGamepad(browserGamepad);
13134
13146
  }
13135
13147
  }
13136
- for (const [browserIndex, pad] of [...this.gamepadsByBrowserIndex.entries()]) {
13137
- if (!seenBrowserIndices.has(browserIndex)) {
13138
- this.gamepadsByBrowserIndex.delete(browserIndex);
13148
+ // Two pads can vanish in the same poll, and the compact strategy's shift
13149
+ // re-points map entries while this loop runs — so resolve each browser
13150
+ // index against the LIVE map at dispatch time instead of a pre-loop
13151
+ // entries snapshot (a stale pad reference would disconnect the wrong,
13152
+ // already-repurposed slot and leave a ghost `connected` pad behind).
13153
+ for (const browserIndex of [...this.gamepadsByBrowserIndex.keys()]) {
13154
+ if (seenBrowserIndices.has(browserIndex)) {
13155
+ continue;
13156
+ }
13157
+ const pad = this.gamepadsByBrowserIndex.get(browserIndex);
13158
+ this.gamepadsByBrowserIndex.delete(browserIndex);
13159
+ if (pad !== undefined) {
13139
13160
  this.handleGamepadDisconnect(pad);
13140
13161
  }
13141
13162
  }
@@ -34374,6 +34395,13 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
34374
34395
  * instead if you need to await completion.
34375
34396
  */
34376
34397
  backgroundLoad() {
34398
+ // Start a fresh progress batch only when idle; a re-entrant call while the
34399
+ // queue is draining extends the running batch instead (mirrors the
34400
+ // accounting in _loadSingleBackground).
34401
+ if (this._backgroundQueue.length === 0 && this._backgroundActive === 0) {
34402
+ this._backgroundLoaded = 0;
34403
+ this._backgroundTotal = 0;
34404
+ }
34377
34405
  for (const [type, entries] of this._manifest) {
34378
34406
  for (const [alias, entry] of entries) {
34379
34407
  if (this._hasResource(type, alias))
@@ -34381,16 +34409,17 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
34381
34409
  const key = this._key(type, alias);
34382
34410
  if (this._inFlight.has(key))
34383
34411
  continue;
34412
+ if (this._isQueuedInBackground(type, alias))
34413
+ continue;
34384
34414
  this._backgroundQueue.push({
34385
34415
  type,
34386
34416
  alias,
34387
34417
  path: entry.path,
34388
34418
  options: entry.options,
34389
34419
  });
34420
+ this._backgroundTotal++;
34390
34421
  }
34391
34422
  }
34392
- this._backgroundTotal = this._backgroundQueue.length;
34393
- this._backgroundLoaded = 0;
34394
34423
  this._drainBackground();
34395
34424
  }
34396
34425
  /**
@@ -35149,7 +35178,16 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
35149
35178
  if (leftPrototype !== rightPrototype) {
35150
35179
  return false;
35151
35180
  }
35152
- if (leftPrototype !== Object.prototype && leftPrototype !== null) {
35181
+ // Same-prototype instances compare structurally by their own enumerable
35182
+ // keys — the registerManifest contract allows deeply-equal options of any
35183
+ // shared class, not just plain objects. Built-ins whose state is NOT
35184
+ // carried in enumerable own keys need explicit handling: Dates compare by
35185
+ // timestamp; other exotic containers stay reference-only (Object.is above)
35186
+ // so two distinct-but-similar instances never count as equivalent.
35187
+ if (left instanceof Date) {
35188
+ return left.getTime() === right.getTime();
35189
+ }
35190
+ if (left instanceof Map || left instanceof Set || left instanceof RegExp || left instanceof ArrayBuffer || ArrayBuffer.isView(left)) {
35153
35191
  return false;
35154
35192
  }
35155
35193
  const leftObject = left;
@@ -39645,6 +39683,8 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
39645
39683
  gamepadSlotStrategy: inputOptions.gamepadSlotStrategy ?? defaultInputSettings.gamepadSlotStrategy,
39646
39684
  pointerDistanceThreshold: inputOptions.pointerDistanceThreshold ?? defaultInputSettings.pointerDistanceThreshold,
39647
39685
  },
39686
+ ...(appSettings.seed !== undefined && { seed: appSettings.seed }),
39687
+ ...(appSettings.fixedTimeStep !== undefined && { fixedTimeStep: appSettings.fixedTimeStep }),
39648
39688
  };
39649
39689
  // Capture extension snapshot before constructing extension-sensitive subsystems.
39650
39690
  this._snapshot = appSettings.extensions === undefined ? getGlobalSnapshotInternal() : buildSnapshot([...(appSettings.extensions ?? [])]);
@@ -40210,8 +40250,8 @@ fn fragmentMain(input: VertexOutput) -> @location(0) vec4<f32> {
40210
40250
  }
40211
40251
 
40212
40252
  const buildInfo = Object.freeze({
40213
- version: "0.15.1",
40214
- revision: "6f825a8",
40253
+ version: "0.15.2",
40254
+ revision: "e3df957",
40215
40255
  development: false,
40216
40256
  });
40217
40257