@viji-dev/core 0.6.2 → 0.7.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.
package/dist/index.d.ts CHANGED
@@ -1111,15 +1111,25 @@ declare interface FaceBlendshapes {
1111
1111
  }
1112
1112
 
1113
1113
  /**
1114
- * One detected face produced by the video CV pipeline. Always carries `id`,
1115
- * `bounds`, `center`, and `confidence`; the rest is populated only when the
1116
- * matching CV feature is enabled (face mesh for `landmarks` and `headPose`,
1117
- * emotion detection for `expressions` and `blendshapes`).
1114
+ * One detected face produced by the video CV pipeline. Each field is
1115
+ * populated only by its source model; fields whose source model is not
1116
+ * enabled read as `null` so the absence is loud rather than silent. Enable
1117
+ * the relevant `enable*` verb on `viji.video.cv` to populate each group:
1118
+ *
1119
+ * - `bounds`, `center`, `confidence`: populated by `enableFaceDetection(true)`.
1120
+ * - `landmarks`: populated by `enableFaceMesh(true)` (empty array otherwise).
1121
+ * - `headPose`: populated by `enableFaceMesh(true)`.
1122
+ * - `blendshapes`, `expressions`: populated by `enableEmotionDetection(true)`.
1123
+ *
1124
+ * If a field is `null`, call the corresponding `enable*` verb on
1125
+ * `viji.video.cv` to populate it. Each active CV feature consumes its own
1126
+ * WebGL context for MediaPipe; enabling many at once on lower-end hardware
1127
+ * can hit context limits.
1118
1128
  */
1119
1129
  export declare interface FaceData {
1120
1130
  /** Index-based face identifier (`0`, `1`, …). Stable within a single frame, may change between frames. */
1121
1131
  id: number;
1122
- /** Bounding box, all components normalized to 0..1 of the source frame. */
1132
+ /** Bounding box, all components normalized to 0..1 of the source frame. `null` unless face detection is enabled. */
1123
1133
  bounds: {
1124
1134
  /** Left edge of the face bounding box, normalized 0..1. */
1125
1135
  x: number;
@@ -1129,16 +1139,16 @@ export declare interface FaceData {
1129
1139
  width: number;
1130
1140
  /** Height of the face bounding box, normalized 0..1. */
1131
1141
  height: number;
1132
- };
1133
- /** Center of the bounding box, normalized 0..1. */
1142
+ } | null;
1143
+ /** Center of the bounding box, normalized 0..1. `null` unless face detection is enabled. */
1134
1144
  center: {
1135
1145
  /** Horizontal center of the face, normalized 0..1. */
1136
1146
  x: number;
1137
1147
  /** Vertical center of the face, normalized 0..1. */
1138
1148
  y: number;
1139
- };
1140
- /** Detection confidence in 0..1. */
1141
- confidence: number;
1149
+ } | null;
1150
+ /** Detection confidence in 0..1. `null` unless face detection is enabled. */
1151
+ confidence: number | null;
1142
1152
  /** 468 normalized face mesh landmarks when face mesh is enabled; empty array otherwise. */
1143
1153
  landmarks: {
1144
1154
  /** Horizontal landmark coordinate, normalized 0..1. */
@@ -1148,7 +1158,16 @@ export declare interface FaceData {
1148
1158
  /** Optional depth (relative). */
1149
1159
  z?: number;
1150
1160
  }[];
1151
- /** Seven expression confidence scores in 0..1. All zero unless emotion detection is enabled. */
1161
+ /** Estimated head rotation in degrees. `null` unless face mesh is enabled. */
1162
+ headPose: {
1163
+ /** Up/down rotation in degrees (-90..90). Positive = head looking up, negative = looking down. */
1164
+ pitch: number;
1165
+ /** Left/right rotation in degrees (-90..90). Positive = head turned to the subject's right, negative = to the left. */
1166
+ yaw: number;
1167
+ /** Tilt rotation in degrees (-180..180). Positive = head tilted to the subject's right (right ear toward right shoulder). */
1168
+ roll: number;
1169
+ } | null;
1170
+ /** Seven expression confidence scores in 0..1. `null` unless emotion detection is enabled. */
1152
1171
  expressions: {
1153
1172
  /** Confidence (0..1) of a neutral expression. */
1154
1173
  neutral: number;
@@ -1164,18 +1183,9 @@ export declare interface FaceData {
1164
1183
  disgusted: number;
1165
1184
  /** Confidence (0..1) of a fearful expression. */
1166
1185
  fearful: number;
1167
- };
1168
- /** Estimated head rotation. All zero unless face mesh is enabled. */
1169
- headPose: {
1170
- /** Up/down rotation in degrees (-90..90). Positive = head looking up, negative = looking down. */
1171
- pitch: number;
1172
- /** Left/right rotation in degrees (-90..90). Positive = head turned to the subject's right, negative = to the left. */
1173
- yaw: number;
1174
- /** Tilt rotation in degrees (-180..180). Positive = head tilted to the subject's right (right ear toward right shoulder). */
1175
- roll: number;
1176
- };
1177
- /** 52 ARKit-compatible facial muscle coefficients. All zero unless emotion detection is enabled. */
1178
- blendshapes: FaceBlendshapes;
1186
+ } | null;
1187
+ /** 52 ARKit-compatible facial muscle coefficients. `null` unless emotion detection is enabled. */
1188
+ blendshapes: FaceBlendshapes | null;
1179
1189
  }
1180
1190
 
1181
1191
  declare interface FrameRateInfo {
@@ -1699,6 +1709,107 @@ export declare type Resolution = {
1699
1709
  height: number;
1700
1710
  };
1701
1711
 
1712
+ /**
1713
+ * Structured scene console envelope surfaced via `VijiCore.onSceneConsole`.
1714
+ *
1715
+ * Only artist `console.*` calls reach this listener (the wrapper is injected
1716
+ * as a function argument on the scene IIFE; engine code uses `globalThis.console`
1717
+ * and is not surfaced). The wrapper calls the real `console[level](...args)`
1718
+ * first before forwarding, so DevTools output is preserved.
1719
+ *
1720
+ * Arguments are pre-stringified in the worker with cycle-safe depth-bounded
1721
+ * inspection, a per-argument byte cap (`consoleArgMaxBytes`), and an argument
1722
+ * count cap (`consoleMaxArgsPerCall`). High-cardinality logs are rate-limited
1723
+ * by `consoleMaxUniqueSignaturesPerSecond`.
1724
+ */
1725
+ export declare interface SceneConsoleMessage {
1726
+ /** Console method invoked. */
1727
+ level: 'log' | 'info' | 'warn' | 'error';
1728
+ /** Stringified arguments. Each entry is bounded by `consoleArgMaxBytes`. */
1729
+ args: string[];
1730
+ /** Stable hash of `level` and the stringified arguments, used for coalescing. */
1731
+ signatureHash: string;
1732
+ /** Number of occurrences of this signature accumulated in the current window. */
1733
+ count: number;
1734
+ /** Millisecond timestamp of the first occurrence of this signature in the current window. */
1735
+ firstSeenAt: number;
1736
+ /** Millisecond timestamp of the most recent occurrence. */
1737
+ lastSeenAt: number;
1738
+ /**
1739
+ * Source location of the `console.*` call site in artist-source coordinates.
1740
+ * Captured via `new Error().stack` inside the wrapper. Absent when stack
1741
+ * frame parsing fails.
1742
+ */
1743
+ sourceLocation?: SceneSourceLocation;
1744
+ }
1745
+
1746
+ /**
1747
+ * Discriminator for scene runtime errors surfaced via `onSceneRuntimeError`.
1748
+ *
1749
+ * - `SCENE_CODE_ERROR`: thrown during `setSceneCode` parse/eval (native, P5).
1750
+ * - `RENDER_ERROR`: synchronous throw inside the artist's `render()` function.
1751
+ * - `UNCAUGHT_ERROR`: caught by the worker's `self.onerror` (async / RAF / setTimeout).
1752
+ * - `UNHANDLED_REJECTION`: caught by the worker's `unhandledrejection` handler.
1753
+ * - `SHADER_COMPILE_ERROR`: GLSL compile failure (shader mode).
1754
+ * - `P5_INIT_ERROR`: failure during P5 mode initialization (e.g. missing `render`).
1755
+ * - `ENGINE_INTERNAL`: engine path with no artist attribution.
1756
+ */
1757
+ export declare type SceneErrorCode = 'SCENE_CODE_ERROR' | 'RENDER_ERROR' | 'UNCAUGHT_ERROR' | 'UNHANDLED_REJECTION' | 'SHADER_COMPILE_ERROR' | 'P5_INIT_ERROR' | 'ENGINE_INTERNAL';
1758
+
1759
+ /**
1760
+ * Structured scene runtime error envelope surfaced via `VijiCore.onSceneRuntimeError`.
1761
+ *
1762
+ * Identical signatures are coalesced inside the worker: the first occurrence in
1763
+ * a window fires with `count: 1`, subsequent occurrences increment `count`, and
1764
+ * a trailing rollup fires at window close if more than one occurrence was seen.
1765
+ *
1766
+ * The host-side `console.error('Scene error:', data)` tee continues to fire
1767
+ * alongside the listener (never silenced based on listener presence).
1768
+ */
1769
+ export declare interface SceneRuntimeError {
1770
+ /** Error message, equivalent to `Error.message`. */
1771
+ message: string;
1772
+ /** Raw V8 stack trace, when available. Not resolved to artist-source coordinates. */
1773
+ stack?: string;
1774
+ /**
1775
+ * Attribution: `'scene'` when at least one stack frame originates in the
1776
+ * artist's compiled scene IIFE; `'engine'` otherwise.
1777
+ */
1778
+ source: 'scene' | 'engine';
1779
+ /**
1780
+ * Lifecycle phase: `'init'` before the first successful render frame
1781
+ * completes; `'render'` afterwards.
1782
+ */
1783
+ phase: 'init' | 'render';
1784
+ /** Error code; see `SceneErrorCode`. */
1785
+ code: SceneErrorCode;
1786
+ /** Stable hash of `message` and the first artist stack frame, used for coalescing. */
1787
+ signatureHash: string;
1788
+ /** Number of occurrences of this signature accumulated in the current window. */
1789
+ count: number;
1790
+ /** Millisecond timestamp of the first occurrence of this signature in the current window. */
1791
+ firstSeenAt: number;
1792
+ /** Millisecond timestamp of the most recent occurrence. */
1793
+ lastSeenAt: number;
1794
+ /**
1795
+ * Source location resolved to artist-source coordinates when available.
1796
+ * Absent when no artist stack frame is found (engine errors), when shader
1797
+ * compile logs lack column info, or when sourcemap resolution fails.
1798
+ */
1799
+ sourceLocation?: SceneSourceLocation;
1800
+ }
1801
+
1802
+ /**
1803
+ * Resolved source location in artist-source coordinates. `line` is 1-based and
1804
+ * matches the artist's authored TypeScript / GLSL line numbers. `column` is
1805
+ * 1-based when present; absent when sourcemap resolution failed or the source
1806
+ * is GLSL (which doesn't reliably emit column information in compile logs).
1807
+ */
1808
+ export declare interface SceneSourceLocation {
1809
+ line: number;
1810
+ column?: number;
1811
+ }
1812
+
1702
1813
  /**
1703
1814
  * Per-pixel person/background segmentation mask. Mask dimensions reflect the
1704
1815
  * ML model's output and may differ from the source video frame.
@@ -2267,7 +2378,7 @@ declare type TrackingState = 'TRACKING' | 'LOCKED' | 'BREAKDOWN' | 'LOST';
2267
2378
  /** Returned by `on*` listener registration calls; invoke to unsubscribe. */
2268
2379
  export declare type Unsubscribe = () => void;
2269
2380
 
2270
- export declare const VERSION = "0.5.7";
2381
+ export declare const VERSION = "0.7.4";
2271
2382
 
2272
2383
  /**
2273
2384
  * Real-time video API: drawable frame, dimensions, and the source-side
@@ -2376,35 +2487,73 @@ export declare interface VideoCVAPI {
2376
2487
  /** Body segmentation mask, or `null` when segmentation is off. */
2377
2488
  segmentation: SegmentationData | null;
2378
2489
  /**
2379
- * Toggle face detection (bounding box, center, confidence, id).
2490
+ * Toggle face detection. Populates `face.bounds`, `face.center`,
2491
+ * `face.confidence` on each detected face. Independent of face mesh and
2492
+ * emotion detection.
2493
+ *
2494
+ * Safe to call from module scope as well as from inside `render()`. The
2495
+ * verb is idempotent and reference-counted; per-frame calls inside
2496
+ * `render()` (the canonical toggle-gated pattern) are cheap.
2497
+ *
2380
2498
  * @returns Resolves once the underlying pipeline has finished switching.
2381
2499
  */
2382
2500
  enableFaceDetection(enabled: boolean): Promise<void>;
2383
2501
  /**
2384
- * Toggle 468-point face mesh + head pose (`pitch`, `yaw`, `roll`). Implies
2385
- * face detection.
2502
+ * Toggle 468-point face mesh and computed head pose (`pitch`, `yaw`,
2503
+ * `roll`). Populates `face.landmarks` and `face.headPose` on the face
2504
+ * entry. Does NOT populate `face.bounds` / `face.center` / `face.confidence`
2505
+ * — those are produced only by face detection. Enable both if you need
2506
+ * both, or compute bounds from `face.landmarks` min/max yourself.
2507
+ *
2508
+ * Safe to call from module scope as well as from inside `render()`. The
2509
+ * verb is idempotent and reference-counted.
2510
+ *
2386
2511
  * @returns Resolves once the pipeline has finished switching.
2387
2512
  */
2388
2513
  enableFaceMesh(enabled: boolean): Promise<void>;
2389
2514
  /**
2390
2515
  * Toggle 7 expressions + 52 ARKit blendshape coefficients on each face.
2391
- * Implies face mesh.
2516
+ * Populates `face.blendshapes` and `face.expressions`. Internally requires
2517
+ * the face landmarker model (loads it alongside `enableFaceMesh` if both
2518
+ * are enabled; loads it on its own otherwise so `face.landmarks` and
2519
+ * `face.headPose` are also populated). Does NOT populate
2520
+ * `face.bounds` / `face.center` / `face.confidence` — enable face
2521
+ * detection for those.
2522
+ *
2523
+ * Safe to call from module scope as well as from inside `render()`. The
2524
+ * verb is idempotent and reference-counted.
2525
+ *
2392
2526
  * @returns Resolves once the pipeline has finished switching.
2393
2527
  */
2394
2528
  enableEmotionDetection(enabled: boolean): Promise<void>;
2395
2529
  /**
2396
- * Toggle 21-point hand landmarks + ML-classified gesture confidences for up
2397
- * to two hands.
2530
+ * Toggle 21-point hand landmarks and ML-classified gesture confidences
2531
+ * for up to two hands. Populates `viji.video.cv.hands[]` with `landmarks`,
2532
+ * `palm`, `bounds` (computed from landmarks), and `gestures`.
2533
+ *
2534
+ * Safe to call from module scope as well as from inside `render()`. The
2535
+ * verb is idempotent and reference-counted.
2536
+ *
2398
2537
  * @returns Resolves once the pipeline has finished switching.
2399
2538
  */
2400
2539
  enableHandTracking(enabled: boolean): Promise<void>;
2401
2540
  /**
2402
2541
  * Toggle 33-point BlazePose body landmarks (face / torso / arms / legs).
2542
+ * Populates `viji.video.cv.pose`.
2543
+ *
2544
+ * Safe to call from module scope as well as from inside `render()`. The
2545
+ * verb is idempotent and reference-counted.
2546
+ *
2403
2547
  * @returns Resolves once the pipeline has finished switching.
2404
2548
  */
2405
2549
  enablePoseDetection(enabled: boolean): Promise<void>;
2406
2550
  /**
2407
- * Toggle per-pixel person/background segmentation mask.
2551
+ * Toggle per-pixel person/background segmentation mask. Populates
2552
+ * `viji.video.cv.segmentation`.
2553
+ *
2554
+ * Safe to call from module scope as well as from inside `render()`. The
2555
+ * verb is idempotent and reference-counted.
2556
+ *
2408
2557
  * @returns Resolves once the pipeline has finished switching.
2409
2558
  */
2410
2559
  enableBodySegmentation(enabled: boolean): Promise<void>;
@@ -2633,6 +2782,8 @@ export declare class VijiCore {
2633
2782
  private parameterErrorListeners;
2634
2783
  private capabilitiesChangeListeners;
2635
2784
  private stateImportErrorListeners;
2785
+ private sceneRuntimeErrorListeners;
2786
+ private sceneConsoleListeners;
2636
2787
  private stats;
2637
2788
  constructor(config: VijiCoreConfig);
2638
2789
  /**
@@ -2928,6 +3079,42 @@ export declare class VijiCore {
2928
3079
  */
2929
3080
  onStateImportError(listener: (error: StateImportError) => void): Unsubscribe;
2930
3081
  private fireStateImportError;
3082
+ /**
3083
+ * Listen for scene runtime errors surfaced by the worker. Errors caused by
3084
+ * the artist's scene code (`SCENE_CODE_ERROR`, `RENDER_ERROR`,
3085
+ * `SHADER_COMPILE_ERROR`, `P5_INIT_ERROR`, plus async / unhandled-rejection
3086
+ * paths originating in the scene) are coalesced on the worker side: identical
3087
+ * signatures within `VijiCoreConfig.errorCoalescingWindowMs` (default 1s)
3088
+ * collapse to a single leading-edge listener call plus an optional trailing
3089
+ * rollup with the final `count`.
3090
+ *
3091
+ * The legacy `console.error('Worker error:', data)` host log continues to
3092
+ * fire alongside this listener (tee semantics, never silenced).
3093
+ *
3094
+ * @returns Unsubscribe function. Call to remove the listener.
3095
+ */
3096
+ onSceneRuntimeError(listener: (error: SceneRuntimeError) => void): Unsubscribe;
3097
+ private fireSceneRuntimeError;
3098
+ /**
3099
+ * Listen for `console.*` calls made from the artist's scene code. The
3100
+ * worker injects a wrapped `console` as an additional function-argument
3101
+ * binding to the artist's IIFE; the wrapper calls the real `console[level]`
3102
+ * first (preserving DevTools output) and then forwards a coalesced, bounded
3103
+ * envelope through this listener.
3104
+ *
3105
+ * Coalescing window: `VijiCoreConfig.consoleCoalescingWindowMs` (default 1s).
3106
+ * Argument bounds: `consoleArgMaxBytes` (default 512B per arg),
3107
+ * `consoleMaxArgsPerCall` (default 8 args). Rate cap on distinct signatures:
3108
+ * `consoleMaxUniqueSignaturesPerSecond` (default 32).
3109
+ *
3110
+ * Only the four forwarded levels (`log`, `info`, `warn`, `error`) reach
3111
+ * this listener. Other console methods (`debug`, `trace`, `dir`, `group`,
3112
+ * etc.) pass through to the real console unchanged but are not surfaced.
3113
+ *
3114
+ * @returns Unsubscribe function. Call to remove the listener.
3115
+ */
3116
+ onSceneConsole(listener: (message: SceneConsoleMessage) => void): Unsubscribe;
3117
+ private fireSceneConsole;
2931
3118
  /**
2932
3119
  * Notify parameter change listeners
2933
3120
  */
@@ -3406,6 +3593,34 @@ export declare interface VijiCoreConfig {
3406
3593
  _rh?: number;
3407
3594
  /** Called when the scene is visually live (render loop running, branding applied) but before audio/video/WASM setup completes. */
3408
3595
  onRenderStart?: () => void;
3596
+ /**
3597
+ * Coalescing window in milliseconds for `onSceneRuntimeError` listener. Identical signatures
3598
+ * within the window collapse into a single host-side message with an incremented `count`.
3599
+ * Default: `1000`.
3600
+ */
3601
+ errorCoalescingWindowMs?: number;
3602
+ /**
3603
+ * Coalescing window in milliseconds for `onSceneConsole` listener. Identical signatures
3604
+ * within the window collapse into a single host-side message with an incremented `count`.
3605
+ * Default: `1000`.
3606
+ */
3607
+ consoleCoalescingWindowMs?: number;
3608
+ /**
3609
+ * Per-argument byte cap for `onSceneConsole` payloads. Arguments longer than this are
3610
+ * truncated with a `…[truncated]` marker. Default: `512`.
3611
+ */
3612
+ consoleArgMaxBytes?: number;
3613
+ /**
3614
+ * Maximum arguments per `console.*` call forwarded through `onSceneConsole`. Excess arguments
3615
+ * are dropped. Default: `8`.
3616
+ */
3617
+ consoleMaxArgsPerCall?: number;
3618
+ /**
3619
+ * Rate cap on distinct console signatures forwarded per second. Excess unique signatures
3620
+ * are dropped with a single synthetic "console suppressed: high frequency" envelope per
3621
+ * overflow window. Default: `32`.
3622
+ */
3623
+ consoleMaxUniqueSignaturesPerSecond?: number;
3409
3624
  }
3410
3625
 
3411
3626
  export declare class VijiCoreError extends Error {
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-DfAcgMbB.js";
1
+ import { A as a, V as i, a as s, b as e } from "./index-DmQ5U_50.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.6.2",
3
+ "version": "0.7.4",
4
4
  "description": "Universal execution engine for Viji Creative scenes",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -51,6 +51,7 @@
51
51
  "prebuild": "node scripts/prebuild-clean.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
+ "lint:ai-prompts-drift": "node scripts/lint-ai-prompts-drift.mjs",
54
55
  "dev": "vite build --watch",
55
56
  "integration": "vite --config integration-example/vite.config.ts",
56
57
  "test": "vitest",