minerender 2.1.0-alpha.51 → 2.1.0-alpha.52

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.
@@ -8017,7 +8017,7 @@ var SceneStatsDisplay = class {
8017
8017
  }
8018
8018
  init() {
8019
8019
  this.statsContainer.classList.add("minerender-stats");
8020
- setInterval(() => {
8020
+ this.interval = setInterval(() => {
8021
8021
  for (let line of this.lines) {
8022
8022
  line.update();
8023
8023
  }
@@ -8026,6 +8026,13 @@ var SceneStatsDisplay = class {
8026
8026
  appendTo(el) {
8027
8027
  el.append(this.statsContainer);
8028
8028
  }
8029
+ dispose() {
8030
+ clearInterval(this.interval);
8031
+ this.interval = void 0;
8032
+ this.lines.length = 0;
8033
+ this.statsContainer.replaceChildren();
8034
+ this.statsContainer.remove();
8035
+ }
8029
8036
  add(line) {
8030
8037
  if (typeof line !== "undefined") {
8031
8038
  this.lines.push(line);
@@ -12273,7 +12280,10 @@ var Renderer = class _Renderer {
12273
12280
  constructor(options) {
12274
12281
  this._dirty = true;
12275
12282
  this._resizeListener = void 0;
12283
+ this._running = false;
12284
+ this._inAnimationLoop = false;
12276
12285
  this._disposed = false;
12286
+ this._frameCallbacks = /* @__PURE__ */ new Map();
12277
12287
  this._debugHelpers = [];
12278
12288
  this._eventDispatchers = /* @__PURE__ */ new Map();
12279
12289
  this._changeListener = () => {
@@ -12284,7 +12294,14 @@ var Renderer = class _Renderer {
12284
12294
  if (!Number.isFinite(pixelRatio) || pixelRatio <= 0) {
12285
12295
  throw new RangeError("render.pixelRatio must be a finite positive number");
12286
12296
  }
12287
- this._animationLoop = this.animate.bind(this);
12297
+ this._animationLoop = (time) => {
12298
+ this._inAnimationLoop = true;
12299
+ try {
12300
+ this.animate(time);
12301
+ } finally {
12302
+ this._inAnimationLoop = false;
12303
+ }
12304
+ };
12288
12305
  this._frameInterval = this.options.render.fpsLimit > 0 ? 1e3 / this.options.render.fpsLimit : void 0;
12289
12306
  this._scene = this.createScene();
12290
12307
  this._camera = this.createCamera();
@@ -12499,15 +12516,39 @@ var Renderer = class _Renderer {
12499
12516
  this._dirty = dirty;
12500
12517
  this.scene.dirty = dirty;
12501
12518
  }
12519
+ /**
12520
+ * Calls a synchronous animation update before each FPS-limited draw while started.
12521
+ * Subscriptions keep the scene drawing without manual dirty flags. Returns an unsubscribe function.
12522
+ * Registering the same callback twice has no effect. Image exports do not invoke callbacks.
12523
+ */
12524
+ onFrame(callback) {
12525
+ if (this._disposed) return () => {
12526
+ };
12527
+ const subscription = this._frameCallbacks.get(callback) ?? {};
12528
+ this._frameCallbacks.set(callback, subscription);
12529
+ return () => {
12530
+ if (this._frameCallbacks.get(callback) === subscription) this._frameCallbacks.delete(callback);
12531
+ };
12532
+ }
12502
12533
  start() {
12503
12534
  if (this._disposed) return;
12504
12535
  this.stop();
12505
- this.renderer.setAnimationLoop(this._animationLoop);
12536
+ this._running = true;
12537
+ if (!this._inAnimationLoop) this.renderer.setAnimationLoop(this._animationLoop);
12506
12538
  }
12507
12539
  stop() {
12508
12540
  if (this._disposed) return;
12509
- this.renderer.setAnimationLoop(null);
12541
+ this._running = false;
12542
+ if (this._inAnimationLoop) {
12543
+ queueMicrotask(() => {
12544
+ this.renderer.setAnimationLoop(null);
12545
+ if (this._running) this.renderer.setAnimationLoop(this._animationLoop);
12546
+ });
12547
+ } else {
12548
+ this.renderer.setAnimationLoop(null);
12549
+ }
12510
12550
  this._nextFrameTime = void 0;
12551
+ for (const subscription of this._frameCallbacks.values()) subscription.previous = void 0;
12511
12552
  }
12512
12553
  /**
12513
12554
  * Stops rendering and releases owned resources. Repeated calls have no effect, and a disposed
@@ -12518,6 +12559,7 @@ var Renderer = class _Renderer {
12518
12559
  if (this._disposed) return;
12519
12560
  this.stop();
12520
12561
  this._disposed = true;
12562
+ this._frameCallbacks.clear();
12521
12563
  if (this._resizeListener) {
12522
12564
  window.removeEventListener("resize", this._resizeListener);
12523
12565
  this._resizeListener = void 0;
@@ -12552,18 +12594,25 @@ var Renderer = class _Renderer {
12552
12594
  this.renderer.forceContextLoss();
12553
12595
  }
12554
12596
  animate(t = performance.now()) {
12555
- if (this._disposed) return;
12597
+ if (!this._running) return;
12556
12598
  if (this._controls?.enabled) {
12557
12599
  this._controls.update();
12558
12600
  }
12559
- if (this._disposed) return;
12560
- if (!this.dirty && !this.options.render.renderAlways) return;
12601
+ if (!this._running) return;
12602
+ if (!this.dirty && !this.options.render.renderAlways && !this._frameCallbacks.size) return;
12561
12603
  const interval = this._frameInterval;
12562
12604
  if (interval) {
12563
12605
  const next = this._nextFrameTime;
12564
12606
  if (next !== void 0 && t + 0.1 < next) return;
12565
12607
  this._nextFrameTime = next !== void 0 && t - next < interval ? next + interval : t + interval;
12566
12608
  }
12609
+ for (const [callback, subscription] of [...this._frameCallbacks]) {
12610
+ if (this._frameCallbacks.get(callback) !== subscription) continue;
12611
+ const previous = subscription.previous;
12612
+ subscription.previous = t;
12613
+ callback({ time: t / 1e3, delta: previous === void 0 ? 0 : (t - previous) / 1e3 });
12614
+ if (!this._running) return;
12615
+ }
12567
12616
  this.drawFrame();
12568
12617
  }
12569
12618
  drawFrame() {