@viji-dev/core 0.8.2 → 0.8.4

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.
@@ -536,7 +536,7 @@ class DB {
536
536
  }
537
537
  }
538
538
  }
539
- const hB = "" + new URL("assets/viji.worker-DA2oBrZW.js", import.meta.url).href, RB = new URL("assets/wasm/vision_wasm_internal.js", import.meta.url).href, wB = new URL("assets/wasm/vision_wasm_internal.wasm", import.meta.url).href, sB = new URL("assets/wasm/vision_wasm_nosimd_internal.js", import.meta.url).href, FB = new URL("assets/wasm/vision_wasm_nosimd_internal.wasm", import.meta.url).href;
539
+ const hB = "" + new URL("assets/viji.worker-BQ4vNMJ0.js", import.meta.url).href, RB = new URL("assets/wasm/vision_wasm_internal.js", import.meta.url).href, wB = new URL("assets/wasm/vision_wasm_internal.wasm", import.meta.url).href, sB = new URL("assets/wasm/vision_wasm_nosimd_internal.js", import.meta.url).href, FB = new URL("assets/wasm/vision_wasm_nosimd_internal.wasm", import.meta.url).href;
540
540
  class kB {
541
541
  constructor(A, B, I) {
542
542
  this.iframeManager = A, this.sceneCode = B, this.init = I;
@@ -1520,7 +1520,7 @@ class lB {
1520
1520
  if (!this.isInitialized)
1521
1521
  return this.initPromise ? this.initPromise : (this.initPromise = (async () => {
1522
1522
  try {
1523
- const A = await import("./essentia.js-core.es-CC_3Ap1i.js"), B = await import("./essentia-wasm.web-CT-b--JV.js").then((g) => g.e), I = A.Essentia || A.default?.Essentia || A.default;
1523
+ const A = await import("./essentia.js-core.es-CC_3Ap1i.js"), B = await import("./essentia-wasm.web-H69T-_AQ.js").then((g) => g.e), I = A.Essentia || A.default?.Essentia || A.default;
1524
1524
  let Q = B.default || B.EssentiaWASM || B.default?.EssentiaWASM;
1525
1525
  if (!Q)
1526
1526
  throw new Error("WASM module not found - check essentia-wasm.web.js export");
@@ -7051,6 +7051,8 @@ class K {
7051
7051
  performanceSnapshotListeners = /* @__PURE__ */ new Set();
7052
7052
  capabilityTransitionListeners = /* @__PURE__ */ new Set();
7053
7053
  capabilityReportingEnabled = !1;
7054
+ // Render-loop pause state (host-driven; see pauseRenderLoop()).
7055
+ renderLoopPaused = !1;
7054
7056
  constructor(A) {
7055
7057
  this.validateConfig(A), this.instanceId = `viji-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, this.isHeadless = !A.hostContainer, this.config = {
7056
7058
  ...A,
@@ -7181,7 +7183,7 @@ class K {
7181
7183
  }
7182
7184
  ), this.setupCommunication(), await this.workerManager.createWorker(), this.isDestroyed)
7183
7185
  throw new S("Initialization cancelled", "INITIALIZATION_CANCELLED");
7184
- this.capabilityReportingEnabled && this.workerManager.postMessage("enable-capability-reporting", { enabled: !0 });
7186
+ this.capabilityReportingEnabled && this.workerManager.postMessage("enable-capability-reporting", { enabled: !0 }), this.renderLoopPaused && this.workerManager.postMessage("set-render-loop-paused", { paused: !0 });
7185
7187
  try {
7186
7188
  this.config.onRenderStart?.();
7187
7189
  } catch (B) {
@@ -8532,16 +8534,53 @@ class K {
8532
8534
  throw new S("IFrame manager not available", "MANAGER_NOT_READY");
8533
8535
  return this.stats;
8534
8536
  }
8537
+ /**
8538
+ * Pauses the scene render loop — stops the worker from rendering. Intended to
8539
+ * be driven from the host on `document.hidden`, so a hidden tab doesn't keep
8540
+ * rasterizing a heavy scene (which otherwise pegs the GPU and causes a freeze
8541
+ * on return).
8542
+ *
8543
+ * Only the rendering stops. The scene clock keeps running on real wall-clock,
8544
+ * and audio analysis, video/audio streams, CV, parameters and all scene state
8545
+ * keep running too — so audio you can still hear is still analyzed. On
8546
+ * {@link resumeRenderLoop}, `viji.time` reflects the **real** elapsed time
8547
+ * (including the hidden duration) and the first frame's `viji.deltaTime` is the
8548
+ * **real** time-away gap. (That gap can be large; the scene sees true time, not
8549
+ * a frozen clock.) Idempotent.
8550
+ *
8551
+ * For a live compositor *source* feeding a visible mixer, do NOT pause it
8552
+ * while its own tab is hidden — it must keep rendering. Pause is per-core and
8553
+ * host-controlled.
8554
+ */
8555
+ pauseRenderLoop() {
8556
+ this.renderLoopPaused || (this.renderLoopPaused = !0, this.workerManager?.postMessage("set-render-loop-paused", { paused: !0 }));
8557
+ }
8558
+ /**
8559
+ * Resumes the scene render loop after {@link pauseRenderLoop} (e.g. on the tab
8560
+ * becoming visible). The scene resumes on real wall-clock time, so the first
8561
+ * frame's `viji.deltaTime` is the elapsed time-away gap. Idempotent.
8562
+ */
8563
+ resumeRenderLoop() {
8564
+ this.renderLoopPaused && (this.renderLoopPaused = !1, this.workerManager?.postMessage("set-render-loop-paused", { paused: !1 }));
8565
+ }
8566
+ /** Whether the render loop is currently paused (see {@link pauseRenderLoop}). */
8567
+ isRenderLoopPaused() {
8568
+ return this.renderLoopPaused;
8569
+ }
8535
8570
  /**
8536
8571
  * Runs an on-demand fenced benchmark: the worker renders `frameCount` frames,
8537
- * fencing each with `gl.finish()` to capture fence-accurate CPU + GPU time
8538
- * per frame, and resolves with the collected samples. The scene advances
8539
- * normally; steady-state perf reporting is suppressed for the run.
8572
+ * fencing each to capture fence-accurate CPU + GPU time per frame, and
8573
+ * resolves with the collected samples. The scene advances normally;
8574
+ * steady-state perf reporting is suppressed for the run.
8575
+ *
8576
+ * The per-frame fence is WebGL `gl.finish()` for shader/WebGL scenes and
8577
+ * `getImageData()` (raster flush) for 2D-canvas scenes, so `gpuMs` is
8578
+ * populated for both (`null` only with no drawable context).
8540
8579
  *
8541
8580
  * Use only on a scene NOT serving as a live compositor source/mixer —
8542
- * per-frame `gl.finish()` would stutter the mixer output (enforced below).
8581
+ * the per-frame fence would stutter the mixer output (enforced below).
8543
8582
  * In-session `frameIntervalMs` includes the fence stall (session-relative);
8544
- * use `cpuMs` + `gpuMs` for cost. `gpuMs` is `null` for 2D-canvas scenes.
8583
+ * use `cpuMs` + `gpuMs` for cost.
8545
8584
  * `frameCount: 1` is the generic single-frame measurement.
8546
8585
  *
8547
8586
  * @param frameCount - Number of frames to benchmark (>= 1)
@@ -8713,7 +8752,7 @@ function DI(h) {
8713
8752
  expectedVersion: 1
8714
8753
  } : typeof A.senderTime != "number" ? { code: "invalid-field", details: "senderTime must be a number", field: "senderTime" } : null;
8715
8754
  }
8716
- const hI = "0.8.0";
8755
+ const hI = "0.8.3";
8717
8756
  export {
8718
8757
  yA as A,
8719
8758
  hI as V,
@@ -8721,4 +8760,4 @@ export {
8721
8760
  S as b,
8722
8761
  PB as g
8723
8762
  };
8724
- //# sourceMappingURL=index-Cql_oWX9.js.map
8763
+ //# sourceMappingURL=index-DF_IFS3A.js.map
package/dist/index.d.ts CHANGED
@@ -1256,9 +1256,11 @@ export declare interface FramePerfSample {
1256
1256
  /** CPU time spent dispatching the render for this frame (ms). */
1257
1257
  cpuMs: number;
1258
1258
  /**
1259
- * GPU time for this frame in ms, or `null` when unavailable. Always `null`
1260
- * in steady state; populated only by `runFencedBenchmark()` (and `null`
1261
- * there for 2D-canvas scenes).
1259
+ * Fence-accurate downstream frame time in ms, or `null` when unavailable.
1260
+ * Always `null` in steady state. Populated only by `runFencedBenchmark()`:
1261
+ * WebGL scenes via `gl.finish()` (GPU drain), 2D-canvas scenes via
1262
+ * `getImageData()` (raster flush). `null` only when there is no drawable
1263
+ * context or readback fails.
1262
1264
  */
1263
1265
  gpuMs: number | null;
1264
1266
  /** Interval since the previous rendered frame (ms). Session-relative under benchmark. */
@@ -1269,6 +1271,16 @@ export declare interface FramePerfSample {
1269
1271
 
1270
1272
  declare interface FrameRateInfo {
1271
1273
  mode: FrameRateMode;
1274
+ /**
1275
+ * Best-effort display refresh rate in Hz, detected once at init by averaging
1276
+ * 60 `requestAnimationFrame` intervals.
1277
+ *
1278
+ * **Not reliable under load** — if the page is already GPU-stressed during
1279
+ * initialization, throttled rAFs inflate the interval and deflate the value
1280
+ * (e.g. 10 Hz on a 60 Hz monitor), and it is never re-measured. rAF cadence
1281
+ * cannot recover the true refresh post-load. **Do not derive performance
1282
+ * thresholds from this** — prefer an absolute FPS target.
1283
+ */
1272
1284
  screenRefreshRate: number;
1273
1285
  effectiveRefreshRate: number;
1274
1286
  }
@@ -2642,7 +2654,7 @@ declare type TrackingState = 'TRACKING' | 'LOCKED' | 'BREAKDOWN' | 'LOST';
2642
2654
  /** Returned by `on*` listener registration calls; invoke to unsubscribe. */
2643
2655
  export declare type Unsubscribe = () => void;
2644
2656
 
2645
- export declare const VERSION = "0.8.0";
2657
+ export declare const VERSION = "0.8.3";
2646
2658
 
2647
2659
  /**
2648
2660
  * Real-time video API: drawable frame, dimensions, and the source-side
@@ -3055,6 +3067,7 @@ export declare class VijiCore {
3055
3067
  private performanceSnapshotListeners;
3056
3068
  private capabilityTransitionListeners;
3057
3069
  private capabilityReportingEnabled;
3070
+ private renderLoopPaused;
3058
3071
  constructor(config: VijiCoreConfig);
3059
3072
  /**
3060
3073
  * Capture current scene frame
@@ -3799,16 +3812,47 @@ export declare class VijiCore {
3799
3812
  * Gets current performance statistics
3800
3813
  */
3801
3814
  getStats(): PerformanceStats;
3815
+ /**
3816
+ * Pauses the scene render loop — stops the worker from rendering. Intended to
3817
+ * be driven from the host on `document.hidden`, so a hidden tab doesn't keep
3818
+ * rasterizing a heavy scene (which otherwise pegs the GPU and causes a freeze
3819
+ * on return).
3820
+ *
3821
+ * Only the rendering stops. The scene clock keeps running on real wall-clock,
3822
+ * and audio analysis, video/audio streams, CV, parameters and all scene state
3823
+ * keep running too — so audio you can still hear is still analyzed. On
3824
+ * {@link resumeRenderLoop}, `viji.time` reflects the **real** elapsed time
3825
+ * (including the hidden duration) and the first frame's `viji.deltaTime` is the
3826
+ * **real** time-away gap. (That gap can be large; the scene sees true time, not
3827
+ * a frozen clock.) Idempotent.
3828
+ *
3829
+ * For a live compositor *source* feeding a visible mixer, do NOT pause it
3830
+ * while its own tab is hidden — it must keep rendering. Pause is per-core and
3831
+ * host-controlled.
3832
+ */
3833
+ pauseRenderLoop(): void;
3834
+ /**
3835
+ * Resumes the scene render loop after {@link pauseRenderLoop} (e.g. on the tab
3836
+ * becoming visible). The scene resumes on real wall-clock time, so the first
3837
+ * frame's `viji.deltaTime` is the elapsed time-away gap. Idempotent.
3838
+ */
3839
+ resumeRenderLoop(): void;
3840
+ /** Whether the render loop is currently paused (see {@link pauseRenderLoop}). */
3841
+ isRenderLoopPaused(): boolean;
3802
3842
  /**
3803
3843
  * Runs an on-demand fenced benchmark: the worker renders `frameCount` frames,
3804
- * fencing each with `gl.finish()` to capture fence-accurate CPU + GPU time
3805
- * per frame, and resolves with the collected samples. The scene advances
3806
- * normally; steady-state perf reporting is suppressed for the run.
3844
+ * fencing each to capture fence-accurate CPU + GPU time per frame, and
3845
+ * resolves with the collected samples. The scene advances normally;
3846
+ * steady-state perf reporting is suppressed for the run.
3847
+ *
3848
+ * The per-frame fence is WebGL `gl.finish()` for shader/WebGL scenes and
3849
+ * `getImageData()` (raster flush) for 2D-canvas scenes, so `gpuMs` is
3850
+ * populated for both (`null` only with no drawable context).
3807
3851
  *
3808
3852
  * Use only on a scene NOT serving as a live compositor source/mixer —
3809
- * per-frame `gl.finish()` would stutter the mixer output (enforced below).
3853
+ * the per-frame fence would stutter the mixer output (enforced below).
3810
3854
  * In-session `frameIntervalMs` includes the fence stall (session-relative);
3811
- * use `cpuMs` + `gpuMs` for cost. `gpuMs` is `null` for 2D-canvas scenes.
3855
+ * use `cpuMs` + `gpuMs` for cost.
3812
3856
  * `frameCount: 1` is the generic single-frame measurement.
3813
3857
  *
3814
3858
  * @param frameCount - Number of frames to benchmark (>= 1)
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as a, V as i, a as s, b as e } from "./index-Cql_oWX9.js";
1
+ import { A as a, V as i, a as s, b as e } from "./index-DF_IFS3A.js";
2
2
  export {
3
3
  a as AudioSystem,
4
4
  i as VERSION,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viji-dev/core",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
4
4
  "description": "Universal execution engine for Viji Creative scenes",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -48,11 +48,11 @@
48
48
  "README.md"
49
49
  ],
50
50
  "scripts": {
51
- "prebuild": "node scripts/prebuild-clean.mjs",
51
+ "prebuild": "node scripts/prebuild-clean.mjs && node scripts/sync-version.mjs",
52
52
  "build": "vite build && node scripts/copy-tasks-assets.mjs && node scripts/build-artist-types.mjs && node scripts/build-docs-api.mjs",
53
53
  "build:docs": "node scripts/build-docs-api.mjs",
54
54
  "lint:ai-prompts-drift": "node scripts/lint-ai-prompts-drift.mjs",
55
- "dev": "vite build --watch",
55
+ "dev": "node scripts/sync-version.mjs && vite build --watch",
56
56
  "integration": "vite --config integration-example/vite.config.ts",
57
57
  "test": "vitest",
58
58
  "test:coverage": "vitest --coverage",