@viji-dev/core 0.9.0 → 0.11.0

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
@@ -422,6 +422,16 @@ export declare class AudioSystem {
422
422
  * Tags with streamIndex and conditionally includes beat data (main channel only).
423
423
  */
424
424
  private sendChannelResults;
425
+ /**
426
+ * Deliver an analysis message to one sink with PER-SINK typed-array
427
+ * copies. The host→worker relay transfers `frequencyData`/`waveformData`
428
+ * buffers (zero-copy receive, `collectTransferables` case
429
+ * 'audio-analysis-update') — posting the same message object to N sinks
430
+ * would let the first post DETACH the buffers and starve every other
431
+ * sink (and the replay cache). One copy per sink per analysis frame is
432
+ * the unavoidable cost of a transfer-per-receiver delivery.
433
+ */
434
+ private deliverAnalysisMessage;
425
435
  /**
426
436
  * Register a result-delivery sink (one per attached core's worker) and
427
437
  * replay current state to it in FIFO order: the latest main-channel
@@ -453,6 +463,41 @@ export declare class AudioSystem {
453
463
  * context alive in `Pending activities` and leaks ~4 MB per cycle.
454
464
  */
455
465
  resetAudioState(): Promise<void>;
466
+ private sourceFedIndices;
467
+ /**
468
+ * Register a source-fed device channel (no MediaStream). Emits the
469
+ * `audio-stream-setup` identity to all sinks and starts the staleness
470
+ * timer. Idempotent.
471
+ */
472
+ addDeviceAnalysisChannel(streamIndex: number, deviceId: string): void;
473
+ /**
474
+ * Feed a controller analysis packet into a source-fed channel. Instant
475
+ * values pass through; the smoothed companions are derived host-side via
476
+ * the channel's envelope followers to absorb network packet bunching
477
+ * (§3.9 light smoothing). Missing `frequencyData`/`waveform` surface as
478
+ * empty arrays (the controller omits them unless the scene reads them).
479
+ */
480
+ feedDeviceAnalysis(streamIndex: number, payload: {
481
+ volume?: {
482
+ current?: number;
483
+ peak?: number;
484
+ };
485
+ bands?: {
486
+ low?: number;
487
+ lowMid?: number;
488
+ mid?: number;
489
+ highMid?: number;
490
+ high?: number;
491
+ };
492
+ spectral?: {
493
+ brightness?: number;
494
+ flatness?: number;
495
+ };
496
+ frequencyData?: Uint8Array;
497
+ waveformData?: Float32Array;
498
+ }): void;
499
+ /** Remove a source-fed device channel (sends a disconnected state). */
500
+ removeDeviceAnalysisChannel(streamIndex: number): void;
456
501
  /**
457
502
  * Add an additional audio stream (lightweight analysis, no beat detection).
458
503
  * When `meta` is provided, the stream identity is recorded and an
@@ -996,6 +1041,59 @@ export declare type CVFeatureKey = typeof CV_FEATURE_KEYS[number];
996
1041
  */
997
1042
  declare type CVFrameRateMode = 'full' | 'half' | 'quarter' | 'eighth';
998
1043
 
1044
+ /**
1045
+ * A controller-produced analysis packet ingested via
1046
+ * {@link VijiCore.setDeviceAnalysis} (remote analysis, Phase 3). The
1047
+ * controller analyzes its own device's audio/camera and ships results — no
1048
+ * media track for the analyzed signal crosses the wire.
1049
+ *
1050
+ * - `kind: 'audio'` — surfaces on `viji.devices[n].audio`. `payload` carries
1051
+ * instant `volume`/`bands`/`spectral`; the host derives the smoothed
1052
+ * companions and absorbs network jitter. Omit `frequencyData`/`waveform`
1053
+ * unless the device scene reads them (they are ~9 KB each).
1054
+ * - `kind: 'cv'` — surfaces on `viji.devices[n].video.cv` (requires the
1055
+ * device video track to be sent for display — the CV surface carrier).
1056
+ * `payload` carries dequantized `faces`/`hands`/`pose` in the same shapes
1057
+ * as `viji.video.cv`. Segmentation is excluded in v1.
1058
+ *
1059
+ * `seq` is a monotonic per-(device,kind) counter for latest-wins ordering on
1060
+ * an unreliable channel (every packet carries absolute values, so drops are
1061
+ * harmless). `captureTs` is the capture timestamp of the analyzed media.
1062
+ */
1063
+ export declare type DeviceAnalysisPacket = {
1064
+ kind: 'audio';
1065
+ seq?: number;
1066
+ captureTs?: number;
1067
+ payload: {
1068
+ volume?: {
1069
+ current?: number;
1070
+ peak?: number;
1071
+ };
1072
+ bands?: {
1073
+ low?: number;
1074
+ lowMid?: number;
1075
+ mid?: number;
1076
+ highMid?: number;
1077
+ high?: number;
1078
+ };
1079
+ spectral?: {
1080
+ brightness?: number;
1081
+ flatness?: number;
1082
+ };
1083
+ frequencyData?: Uint8Array;
1084
+ waveformData?: Float32Array;
1085
+ };
1086
+ } | {
1087
+ kind: 'cv';
1088
+ seq?: number;
1089
+ captureTs?: number;
1090
+ payload: {
1091
+ faces?: FaceData[];
1092
+ hands?: HandData[];
1093
+ pose?: PoseData | null;
1094
+ };
1095
+ };
1096
+
999
1097
  /**
1000
1098
  * Device motion data sourced from the platform's `DeviceMotionEvent`. All
1001
1099
  * accelerations are in metres per second squared (m/s²); rotation rates are
@@ -2692,7 +2790,7 @@ declare type TrackingState = 'TRACKING' | 'LOCKED' | 'BREAKDOWN' | 'LOST';
2692
2790
  /** Returned by `on*` listener registration calls; invoke to unsubscribe. */
2693
2791
  export declare type Unsubscribe = () => void;
2694
2792
 
2695
- export declare const VERSION = "0.9.0";
2793
+ export declare const VERSION = "0.11.0";
2696
2794
 
2697
2795
  /**
2698
2796
  * Real-time video API: drawable frame, dimensions, and the source-side
@@ -2741,11 +2839,12 @@ export declare interface VideoAPI {
2741
2839
  * outputs (the analysed frame and its detection / segmentation results) with
2742
2840
  * the verbs that activate the underlying MediaPipe pipelines.
2743
2841
  *
2744
- * Available only on the main video stream (`viji.video.cv`). Additional
2745
- * streams (`viji.videoStreams[i].cv`) and device videos
2746
- * (`viji.devices[i].video.cv`) do not run CV; their `cv` surface exists for
2747
- * API consistency but the data fields stay at their empty defaults and the
2748
- * `enable*` verbs are no-ops.
2842
+ * Available on the main video stream (`viji.video.cv`) and on additional
2843
+ * streams (`viji.videoStreams[i].cv`) — same surface, same verbs, activated
2844
+ * per stream. `analysedFrame` is populated on the MAIN stream only; on other
2845
+ * streams it stays `null` (use `currentFrame`). Device videos
2846
+ * (`viji.devices[i].video.cv`) do not run CV yet; their `cv` surface exists
2847
+ * for API consistency with the data fields at their empty defaults.
2749
2848
  */
2750
2849
  export declare interface VideoCVAPI {
2751
2850
  /**
@@ -3079,6 +3178,7 @@ export declare class VijiCore {
3079
3178
  private sceneRenderer;
3080
3179
  private sceneCapabilities;
3081
3180
  private sceneP5CanvasMode?;
3181
+ private sceneConsumesAnalysedFrame;
3082
3182
  private sceneContextType?;
3083
3183
  private parametersInitialized;
3084
3184
  private parameterListeners;
@@ -3088,6 +3188,7 @@ export declare class VijiCore {
3088
3188
  private stateImportErrorListeners;
3089
3189
  private sceneRuntimeErrorListeners;
3090
3190
  private sceneConsoleListeners;
3191
+ private deviceCVRequestListeners;
3091
3192
  private stats;
3092
3193
  private performanceSnapshotListeners;
3093
3194
  private capabilityTransitionListeners;
@@ -3501,8 +3602,14 @@ export declare class VijiCore {
3501
3602
  */
3502
3603
  setFrameRate(mode: FrameRateMode): Promise<void>;
3503
3604
  /**
3504
- * Sets the CV processing frame rate mode (relative to scene frame rate)
3505
- * @param mode - CV processing rate: 'full', 'half', 'quarter', or 'eighth' of scene rate
3605
+ * Sets the CV processing frame rate mode, relative to the **video stream
3606
+ * delivery rate** (the capture's ~30 fps), not the scene render rate —
3607
+ * with shared engines, attached scenes may render at different rates, so
3608
+ * the capture rate is the only coherent base.
3609
+ *
3610
+ * Engine-level write: visible to ALL cores sharing this core's media
3611
+ * engines (same rule as the stream mutators).
3612
+ * @param mode - CV processing rate: 'full', 'half', 'quarter', or 'eighth' of the capture rate
3506
3613
  */
3507
3614
  setCVFrameRate(mode: CVFrameRateMode): Promise<void>;
3508
3615
  /**
@@ -3604,6 +3711,51 @@ export declare class VijiCore {
3604
3711
  */
3605
3712
  private get audioEngine();
3606
3713
  private ensureAudioEngine;
3714
+ /**
3715
+ * Host-side video control namespace. The `cv` sub-namespace lets host
3716
+ * code (as opposed to scene code) drive CV on the main video stream —
3717
+ * the controller use case: a scene-less headless core analyzing its
3718
+ * local camera and shipping results onward.
3719
+ */
3720
+ readonly video: {
3721
+ cv: {
3722
+ /**
3723
+ * Enable or disable a CV feature on the main video stream from the
3724
+ * host side. The host acts as one more consumer of the shared CV
3725
+ * engine: inference runs the union of all consumers' desired sets,
3726
+ * and host results arrive via {@link onResults} filtered to the
3727
+ * host-enabled features.
3728
+ *
3729
+ * Engine-level write: the underlying inference is visible to ALL
3730
+ * cores sharing this core's media engines (scenes still only receive
3731
+ * features they enabled themselves).
3732
+ *
3733
+ * @param feature - The CV feature to toggle
3734
+ * @param enabled - Whether the feature should run
3735
+ */
3736
+ enable: (feature: CVFeature, enabled: boolean) => void;
3737
+ /**
3738
+ * Subscribe to CV results on the host side, filtered to the features
3739
+ * enabled via {@link enable}. Fires once per completed inference with
3740
+ * the same result shapes the artist API exposes
3741
+ * (`faces`/`hands`/`pose`/`segmentation`).
3742
+ *
3743
+ * Engine-level: one listener registry per shared engine group —
3744
+ * subscribe once per app.
3745
+ *
3746
+ * @returns Unsubscribe function. Call to remove the listener.
3747
+ */
3748
+ onResults: (listener: (update: {
3749
+ streamIndex: number;
3750
+ results: {
3751
+ faces?: FaceData[];
3752
+ hands?: HandData[];
3753
+ pose?: PoseData | null;
3754
+ segmentation?: SegmentationData | null;
3755
+ };
3756
+ }) => void) => Unsubscribe;
3757
+ };
3758
+ };
3607
3759
  readonly audio: {
3608
3760
  /**
3609
3761
  * Beat control namespace
@@ -3911,6 +4063,13 @@ export declare class VijiCore {
3911
4063
  * Gets current performance statistics
3912
4064
  */
3913
4065
  getStats(): PerformanceStats;
4066
+ /**
4067
+ * Merge the shared CV engine's main-stream processing stats into
4068
+ * `stats.cv`. The cv block is absent until CV state exists (no engine, or
4069
+ * no features ever requested on the main stream) — same shape consumers
4070
+ * saw when the worker produced it.
4071
+ */
4072
+ private mergeCVStats;
3914
4073
  /**
3915
4074
  * Pauses the scene render loop — stops the worker from rendering. Intended to
3916
4075
  * be driven from the host on `document.hidden`, so a hidden tab doesn't keep
@@ -3991,7 +4150,8 @@ export declare class VijiCore {
3991
4150
  */
3992
4151
  removeExternalDevice(deviceId: string): void;
3993
4152
  /**
3994
- * Get list of connected external devices (for host UI)
4153
+ * Get list of connected external devices (for host UI). Engine-scoped:
4154
+ * identical for every core sharing this core's media engines.
3995
4155
  * @returns Array of device metadata with id, name, and array index
3996
4156
  */
3997
4157
  getConnectedDevices(): Array<{
@@ -3999,6 +4159,32 @@ export declare class VijiCore {
3999
4159
  name: string;
4000
4160
  index: number;
4001
4161
  }>;
4162
+ /**
4163
+ * Ingest a controller-produced analysis packet for a registered device
4164
+ * (remote analysis, Phase 3). `kind:'audio'` surfaces on
4165
+ * `viji.devices[n].audio`; `kind:'cv'` surfaces on
4166
+ * `viji.devices[n].video.cv` (requires the device video track to be sent
4167
+ * for display — the CV surface carrier). Latest-wins by `seq`; unknown
4168
+ * devices / malformed packets are dropped silently. Engine-level: visible
4169
+ * to all cores sharing this core's media engines.
4170
+ *
4171
+ * @param deviceId Registered device identifier
4172
+ * @param packet `{ kind, seq?, captureTs?, payload }`
4173
+ */
4174
+ setDeviceAnalysis(deviceId: string, packet: DeviceAnalysisPacket): void;
4175
+ /**
4176
+ * Listen for device CV feature requests. Fires when a host scene toggles a
4177
+ * CV feature on a device stream (`viji.devices[n].video.cv.enableX`) —
4178
+ * device CV is always remote, so the app must relay this to the device's
4179
+ * controller over its own transport (the controller runs the inference and
4180
+ * ships results back via {@link setDeviceAnalysis}). The core never owns
4181
+ * the transport.
4182
+ *
4183
+ * Engine-level: one registry per shared engine group — subscribe once.
4184
+ * @returns Unsubscribe function.
4185
+ */
4186
+ onDeviceCVRequest(listener: (deviceId: string, feature: CVFeature, enabled: boolean) => void): Unsubscribe;
4187
+ private fireDeviceCVRequest;
4002
4188
  /**
4003
4189
  * Set video stream for an external device
4004
4190
  * Device camera will appear in viji.devices[].video
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as s, C as o, I as E, V as i, a as A, b as C } from "./index-CAx7Pxyl.js";
1
+ import { A as s, C as o, I as E, V as i, a as A, b as C } from "./index-Dfhuv8fL.js";
2
2
  export {
3
3
  s as AudioSystem,
4
4
  o as CV_FEATURE_KEYS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viji-dev/core",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "Universal execution engine for Viji Creative scenes",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -50,7 +50,7 @@
50
50
  "scripts": {
51
51
  "prebuild": "node scripts/prebuild-clean.mjs && node scripts/sync-version.mjs",
52
52
  "version": "npm run build && git add -A",
53
- "build": "vite build && node scripts/copy-tasks-assets.mjs && node scripts/build-artist-types.mjs && node scripts/build-docs-api.mjs",
53
+ "build": "vite build && node scripts/copy-tasks-assets.mjs && node scripts/build-artist-types.mjs && node scripts/lint-artist-types-drift.mjs && node scripts/build-docs-api.mjs",
54
54
  "build:docs": "node scripts/build-docs-api.mjs",
55
55
  "lint:ai-prompts-drift": "node scripts/lint-ai-prompts-drift.mjs",
56
56
  "dev": "node scripts/sync-version.mjs && vite build --watch",