@viji-dev/core 0.3.26 → 0.3.28
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/README.md +1 -1
- package/dist/artist-dts-p5.js +1 -1
- package/dist/artist-dts.js +1 -1
- package/dist/artist-global.d.ts +4 -1
- package/dist/artist-jsdoc.d.ts +3 -1
- package/dist/assets/{viji.worker-PAf0oIec.js → viji.worker-CdHkRwxI.js} +756 -88
- package/dist/assets/viji.worker-CdHkRwxI.js.map +1 -0
- package/dist/docs-api.js +104 -50
- package/dist/{essentia-wasm.web-1yXYrWJ5.js → essentia-wasm.web-CJ3YX7ue.js} +2 -2
- package/dist/{essentia-wasm.web-1yXYrWJ5.js.map → essentia-wasm.web-CJ3YX7ue.js.map} +1 -1
- package/dist/{index-B8BYfP9z.js → index-i7P2rHW8.js} +1475 -1202
- package/dist/index-i7P2rHW8.js.map +1 -0
- package/dist/index.d.ts +162 -91
- package/dist/index.js +1 -1
- package/dist/shader-uniforms.js +414 -49
- package/package.json +1 -1
- package/dist/assets/viji.worker-PAf0oIec.js.map +0 -1
- package/dist/index-B8BYfP9z.js.map +0 -1
|
@@ -1792,6 +1792,7 @@ class P5WorkerAdapter {
|
|
|
1792
1792
|
this.offscreenCanvas = offscreenCanvas;
|
|
1793
1793
|
this.setupFn = sceneCode.setup || null;
|
|
1794
1794
|
this.renderFn = sceneCode.render;
|
|
1795
|
+
this.p5CanvasMode = sceneCode.canvasMode === "webgl" ? "webgl" : "2d";
|
|
1795
1796
|
this.installMinimalShims();
|
|
1796
1797
|
}
|
|
1797
1798
|
p5Instance = null;
|
|
@@ -1804,6 +1805,7 @@ class P5WorkerAdapter {
|
|
|
1804
1805
|
imageParameterCache = /* @__PURE__ */ new Map();
|
|
1805
1806
|
// Track if P5.js's main canvas has been created
|
|
1806
1807
|
mainCanvasCreated = false;
|
|
1808
|
+
p5CanvasMode;
|
|
1807
1809
|
/**
|
|
1808
1810
|
* Initialize P5 instance after P5.js library is loaded
|
|
1809
1811
|
* This must be called after the P5 class is available
|
|
@@ -1816,7 +1818,15 @@ class P5WorkerAdapter {
|
|
|
1816
1818
|
new this.p5Class((p) => {
|
|
1817
1819
|
this.p5Instance = p;
|
|
1818
1820
|
p.setup = () => {
|
|
1819
|
-
|
|
1821
|
+
if (this.p5CanvasMode === "webgl") {
|
|
1822
|
+
p.createCanvas(
|
|
1823
|
+
this.offscreenCanvas.width,
|
|
1824
|
+
this.offscreenCanvas.height,
|
|
1825
|
+
p.WEBGL
|
|
1826
|
+
);
|
|
1827
|
+
} else {
|
|
1828
|
+
p.createCanvas(this.offscreenCanvas.width, this.offscreenCanvas.height);
|
|
1829
|
+
}
|
|
1820
1830
|
p.noLoop();
|
|
1821
1831
|
this.p5InternalSetupComplete = true;
|
|
1822
1832
|
resolve();
|
|
@@ -2052,8 +2062,8 @@ class P5WorkerAdapter {
|
|
|
2052
2062
|
height: bitmap.height
|
|
2053
2063
|
};
|
|
2054
2064
|
}
|
|
2055
|
-
if (Array.isArray(vijiAPI.
|
|
2056
|
-
for (const stream of vijiAPI.
|
|
2065
|
+
if (Array.isArray(vijiAPI.videoStreams)) {
|
|
2066
|
+
for (const stream of vijiAPI.videoStreams) {
|
|
2057
2067
|
if (stream?.currentFrame instanceof OffscreenCanvas) {
|
|
2058
2068
|
const canvas = stream.currentFrame;
|
|
2059
2069
|
stream.currentFrame = {
|
|
@@ -2379,12 +2389,14 @@ class ShaderWorkerAdapter {
|
|
|
2379
2389
|
this.gl = gl;
|
|
2380
2390
|
}
|
|
2381
2391
|
}
|
|
2382
|
-
static
|
|
2392
|
+
static MAX_VIDEO_STREAMS = 8;
|
|
2383
2393
|
// Maximum number of compositor input streams
|
|
2384
2394
|
static MAX_EXTERNAL_DEVICES = 8;
|
|
2385
2395
|
// Maximum number of external devices
|
|
2386
2396
|
static MAX_DEVICE_VIDEOS = 8;
|
|
2387
2397
|
// Maximum number of device video streams
|
|
2398
|
+
static MAX_AUDIO_STREAMS = 8;
|
|
2399
|
+
// Maximum number of additional audio streams
|
|
2388
2400
|
gl;
|
|
2389
2401
|
program = null;
|
|
2390
2402
|
uniformLocations = /* @__PURE__ */ new Map();
|
|
@@ -2404,7 +2416,7 @@ class ShaderWorkerAdapter {
|
|
|
2404
2416
|
segmentationTexture = null;
|
|
2405
2417
|
keyboardTexture = null;
|
|
2406
2418
|
// Multi-stream textures
|
|
2407
|
-
|
|
2419
|
+
videoStreamTextures = [];
|
|
2408
2420
|
// Device video textures
|
|
2409
2421
|
deviceTextures = new Array(ShaderWorkerAdapter.MAX_DEVICE_VIDEOS).fill(null);
|
|
2410
2422
|
// Accumulator state (CPU-side phase accumulators for smooth parameter-driven animation)
|
|
@@ -2692,31 +2704,31 @@ uniform vec2 u_videoResolution; // Video frame width and height in pixels
|
|
|
2692
2704
|
uniform float u_videoFrameRate; // Video frame rate in frames per second
|
|
2693
2705
|
|
|
2694
2706
|
// Multi-Stream Compositor Support (using individual uniforms due to WebGL 1.0 limitations)
|
|
2695
|
-
uniform int
|
|
2696
|
-
uniform sampler2D
|
|
2697
|
-
uniform sampler2D
|
|
2698
|
-
uniform sampler2D
|
|
2699
|
-
uniform sampler2D
|
|
2700
|
-
uniform sampler2D
|
|
2701
|
-
uniform sampler2D
|
|
2702
|
-
uniform sampler2D
|
|
2703
|
-
uniform sampler2D
|
|
2704
|
-
uniform vec2
|
|
2705
|
-
uniform vec2
|
|
2706
|
-
uniform vec2
|
|
2707
|
-
uniform vec2
|
|
2708
|
-
uniform vec2
|
|
2709
|
-
uniform vec2
|
|
2710
|
-
uniform vec2
|
|
2711
|
-
uniform vec2
|
|
2712
|
-
uniform bool
|
|
2713
|
-
uniform bool
|
|
2714
|
-
uniform bool
|
|
2715
|
-
uniform bool
|
|
2716
|
-
uniform bool
|
|
2717
|
-
uniform bool
|
|
2718
|
-
uniform bool
|
|
2719
|
-
uniform bool
|
|
2707
|
+
uniform int u_videoStreamCount; // Number of available compositor input streams (0-8)
|
|
2708
|
+
uniform sampler2D u_videoStream0; // Video stream 0 texture
|
|
2709
|
+
uniform sampler2D u_videoStream1; // Video stream 1 texture
|
|
2710
|
+
uniform sampler2D u_videoStream2; // Video stream 2 texture
|
|
2711
|
+
uniform sampler2D u_videoStream3; // Video stream 3 texture
|
|
2712
|
+
uniform sampler2D u_videoStream4; // Video stream 4 texture
|
|
2713
|
+
uniform sampler2D u_videoStream5; // Video stream 5 texture
|
|
2714
|
+
uniform sampler2D u_videoStream6; // Video stream 6 texture
|
|
2715
|
+
uniform sampler2D u_videoStream7; // Video stream 7 texture
|
|
2716
|
+
uniform vec2 u_videoStream0Resolution; // Video stream 0 resolution
|
|
2717
|
+
uniform vec2 u_videoStream1Resolution; // Video stream 1 resolution
|
|
2718
|
+
uniform vec2 u_videoStream2Resolution; // Video stream 2 resolution
|
|
2719
|
+
uniform vec2 u_videoStream3Resolution; // Video stream 3 resolution
|
|
2720
|
+
uniform vec2 u_videoStream4Resolution; // Video stream 4 resolution
|
|
2721
|
+
uniform vec2 u_videoStream5Resolution; // Video stream 5 resolution
|
|
2722
|
+
uniform vec2 u_videoStream6Resolution; // Video stream 6 resolution
|
|
2723
|
+
uniform vec2 u_videoStream7Resolution; // Video stream 7 resolution
|
|
2724
|
+
uniform bool u_videoStream0Connected; // Video stream 0 connection status
|
|
2725
|
+
uniform bool u_videoStream1Connected; // Video stream 1 connection status
|
|
2726
|
+
uniform bool u_videoStream2Connected; // Video stream 2 connection status
|
|
2727
|
+
uniform bool u_videoStream3Connected; // Video stream 3 connection status
|
|
2728
|
+
uniform bool u_videoStream4Connected; // Video stream 4 connection status
|
|
2729
|
+
uniform bool u_videoStream5Connected; // Video stream 5 connection status
|
|
2730
|
+
uniform bool u_videoStream6Connected; // Video stream 6 connection status
|
|
2731
|
+
uniform bool u_videoStream7Connected; // Video stream 7 connection status
|
|
2720
2732
|
|
|
2721
2733
|
// Device Video Support (device cameras)
|
|
2722
2734
|
uniform int u_deviceCount; // Number of device videos (0-8)
|
|
@@ -2745,6 +2757,81 @@ uniform bool u_device5Connected; // Device 5 connection status
|
|
|
2745
2757
|
uniform bool u_device6Connected; // Device 6 connection status
|
|
2746
2758
|
uniform bool u_device7Connected; // Device 7 connection status
|
|
2747
2759
|
|
|
2760
|
+
// Additional Audio Streams (lightweight analysis, no beat/FFT)
|
|
2761
|
+
uniform int u_audioStreamCount; // Number of additional audio streams (0-8)
|
|
2762
|
+
uniform bool u_audioStream0Connected; // Stream 0 connection status
|
|
2763
|
+
uniform float u_audioStream0Volume; // Stream 0 volume (0-1)
|
|
2764
|
+
uniform float u_audioStream0Low; // Stream 0 low band (0-1)
|
|
2765
|
+
uniform float u_audioStream0LowMid; // Stream 0 low-mid band (0-1)
|
|
2766
|
+
uniform float u_audioStream0Mid; // Stream 0 mid band (0-1)
|
|
2767
|
+
uniform float u_audioStream0HighMid; // Stream 0 high-mid band (0-1)
|
|
2768
|
+
uniform float u_audioStream0High; // Stream 0 high band (0-1)
|
|
2769
|
+
uniform float u_audioStream0Brightness; // Stream 0 spectral brightness (0-1)
|
|
2770
|
+
uniform float u_audioStream0Flatness; // Stream 0 spectral flatness (0-1)
|
|
2771
|
+
uniform bool u_audioStream1Connected;
|
|
2772
|
+
uniform float u_audioStream1Volume;
|
|
2773
|
+
uniform float u_audioStream1Low;
|
|
2774
|
+
uniform float u_audioStream1LowMid;
|
|
2775
|
+
uniform float u_audioStream1Mid;
|
|
2776
|
+
uniform float u_audioStream1HighMid;
|
|
2777
|
+
uniform float u_audioStream1High;
|
|
2778
|
+
uniform float u_audioStream1Brightness;
|
|
2779
|
+
uniform float u_audioStream1Flatness;
|
|
2780
|
+
uniform bool u_audioStream2Connected;
|
|
2781
|
+
uniform float u_audioStream2Volume;
|
|
2782
|
+
uniform float u_audioStream2Low;
|
|
2783
|
+
uniform float u_audioStream2LowMid;
|
|
2784
|
+
uniform float u_audioStream2Mid;
|
|
2785
|
+
uniform float u_audioStream2HighMid;
|
|
2786
|
+
uniform float u_audioStream2High;
|
|
2787
|
+
uniform float u_audioStream2Brightness;
|
|
2788
|
+
uniform float u_audioStream2Flatness;
|
|
2789
|
+
uniform bool u_audioStream3Connected;
|
|
2790
|
+
uniform float u_audioStream3Volume;
|
|
2791
|
+
uniform float u_audioStream3Low;
|
|
2792
|
+
uniform float u_audioStream3LowMid;
|
|
2793
|
+
uniform float u_audioStream3Mid;
|
|
2794
|
+
uniform float u_audioStream3HighMid;
|
|
2795
|
+
uniform float u_audioStream3High;
|
|
2796
|
+
uniform float u_audioStream3Brightness;
|
|
2797
|
+
uniform float u_audioStream3Flatness;
|
|
2798
|
+
uniform bool u_audioStream4Connected;
|
|
2799
|
+
uniform float u_audioStream4Volume;
|
|
2800
|
+
uniform float u_audioStream4Low;
|
|
2801
|
+
uniform float u_audioStream4LowMid;
|
|
2802
|
+
uniform float u_audioStream4Mid;
|
|
2803
|
+
uniform float u_audioStream4HighMid;
|
|
2804
|
+
uniform float u_audioStream4High;
|
|
2805
|
+
uniform float u_audioStream4Brightness;
|
|
2806
|
+
uniform float u_audioStream4Flatness;
|
|
2807
|
+
uniform bool u_audioStream5Connected;
|
|
2808
|
+
uniform float u_audioStream5Volume;
|
|
2809
|
+
uniform float u_audioStream5Low;
|
|
2810
|
+
uniform float u_audioStream5LowMid;
|
|
2811
|
+
uniform float u_audioStream5Mid;
|
|
2812
|
+
uniform float u_audioStream5HighMid;
|
|
2813
|
+
uniform float u_audioStream5High;
|
|
2814
|
+
uniform float u_audioStream5Brightness;
|
|
2815
|
+
uniform float u_audioStream5Flatness;
|
|
2816
|
+
uniform bool u_audioStream6Connected;
|
|
2817
|
+
uniform float u_audioStream6Volume;
|
|
2818
|
+
uniform float u_audioStream6Low;
|
|
2819
|
+
uniform float u_audioStream6LowMid;
|
|
2820
|
+
uniform float u_audioStream6Mid;
|
|
2821
|
+
uniform float u_audioStream6HighMid;
|
|
2822
|
+
uniform float u_audioStream6High;
|
|
2823
|
+
uniform float u_audioStream6Brightness;
|
|
2824
|
+
uniform float u_audioStream6Flatness;
|
|
2825
|
+
uniform bool u_audioStream7Connected;
|
|
2826
|
+
uniform float u_audioStream7Volume;
|
|
2827
|
+
uniform float u_audioStream7Low;
|
|
2828
|
+
uniform float u_audioStream7LowMid;
|
|
2829
|
+
uniform float u_audioStream7Mid;
|
|
2830
|
+
uniform float u_audioStream7HighMid;
|
|
2831
|
+
uniform float u_audioStream7High;
|
|
2832
|
+
uniform float u_audioStream7Brightness;
|
|
2833
|
+
uniform float u_audioStream7Flatness;
|
|
2834
|
+
|
|
2748
2835
|
// CV - Face Detection & Expressions
|
|
2749
2836
|
uniform int u_faceCount; // Number of detected faces (0-1)
|
|
2750
2837
|
uniform vec4 u_face0Bounds; // First face bounding box (x, y, width, height) normalized 0-1
|
|
@@ -2973,7 +3060,7 @@ ${error}`);
|
|
|
2973
3060
|
if (info) {
|
|
2974
3061
|
const location = gl.getUniformLocation(this.program, info.name);
|
|
2975
3062
|
this.uniformLocations.set(info.name, location);
|
|
2976
|
-
if (info.name.includes("
|
|
3063
|
+
if (info.name.includes("Stream") || info.name.includes("stream")) {
|
|
2977
3064
|
streamUniforms.push(info.name);
|
|
2978
3065
|
}
|
|
2979
3066
|
}
|
|
@@ -2993,8 +3080,11 @@ ${error}`);
|
|
|
2993
3080
|
this.textureUnits.set("u_video", this.nextTextureUnit++);
|
|
2994
3081
|
this.textureUnits.set("u_segmentationMask", this.nextTextureUnit++);
|
|
2995
3082
|
this.textureUnits.set("u_keyboard", this.nextTextureUnit++);
|
|
2996
|
-
for (let i = 0; i < ShaderWorkerAdapter.
|
|
2997
|
-
this.textureUnits.set(`
|
|
3083
|
+
for (let i = 0; i < ShaderWorkerAdapter.MAX_VIDEO_STREAMS; i++) {
|
|
3084
|
+
this.textureUnits.set(`u_videoStream${i}`, this.nextTextureUnit++);
|
|
3085
|
+
}
|
|
3086
|
+
for (let i = 0; i < ShaderWorkerAdapter.MAX_DEVICE_VIDEOS; i++) {
|
|
3087
|
+
this.textureUnits.set(`u_device${i}`, this.nextTextureUnit++);
|
|
2998
3088
|
}
|
|
2999
3089
|
if (this.backbufferEnabled) {
|
|
3000
3090
|
this.textureUnits.set("backbuffer", this.nextTextureUnit++);
|
|
@@ -3165,18 +3255,18 @@ ${error}`);
|
|
|
3165
3255
|
this.setUniform("u_videoResolution", "vec2", [0, 0]);
|
|
3166
3256
|
this.setUniform("u_videoFrameRate", "float", 0);
|
|
3167
3257
|
}
|
|
3168
|
-
const
|
|
3169
|
-
const
|
|
3170
|
-
this.setUniform("
|
|
3171
|
-
for (let i = 0; i < ShaderWorkerAdapter.
|
|
3172
|
-
const connectedUniform = `
|
|
3173
|
-
const resolutionUniform = `
|
|
3174
|
-
if (i <
|
|
3175
|
-
this.
|
|
3258
|
+
const videoStreams = viji.videoStreams || [];
|
|
3259
|
+
const videoStreamCount = Math.min(videoStreams.length, ShaderWorkerAdapter.MAX_VIDEO_STREAMS);
|
|
3260
|
+
this.setUniform("u_videoStreamCount", "int", videoStreamCount);
|
|
3261
|
+
for (let i = 0; i < ShaderWorkerAdapter.MAX_VIDEO_STREAMS; i++) {
|
|
3262
|
+
const connectedUniform = `u_videoStream${i}Connected`;
|
|
3263
|
+
const resolutionUniform = `u_videoStream${i}Resolution`;
|
|
3264
|
+
if (i < videoStreamCount && videoStreams[i]?.isConnected && videoStreams[i]?.currentFrame) {
|
|
3265
|
+
this.updateVideoStreamTexture(i, videoStreams[i].currentFrame);
|
|
3176
3266
|
this.setUniform(
|
|
3177
3267
|
resolutionUniform,
|
|
3178
3268
|
"vec2",
|
|
3179
|
-
[
|
|
3269
|
+
[videoStreams[i].frameWidth, videoStreams[i].frameHeight]
|
|
3180
3270
|
);
|
|
3181
3271
|
this.setUniform(connectedUniform, "bool", true);
|
|
3182
3272
|
} else {
|
|
@@ -3203,6 +3293,34 @@ ${error}`);
|
|
|
3203
3293
|
this.setUniform(connectedUniform, "bool", false);
|
|
3204
3294
|
}
|
|
3205
3295
|
}
|
|
3296
|
+
const audioStreams = viji.audioStreams || [];
|
|
3297
|
+
const audioStreamCount = Math.min(audioStreams.length, ShaderWorkerAdapter.MAX_AUDIO_STREAMS);
|
|
3298
|
+
this.setUniform("u_audioStreamCount", "int", audioStreamCount);
|
|
3299
|
+
for (let i = 0; i < ShaderWorkerAdapter.MAX_AUDIO_STREAMS; i++) {
|
|
3300
|
+
const prefix = `u_audioStream${i}`;
|
|
3301
|
+
if (i < audioStreamCount && audioStreams[i]?.isConnected) {
|
|
3302
|
+
const s = audioStreams[i];
|
|
3303
|
+
this.setUniform(`${prefix}Connected`, "bool", true);
|
|
3304
|
+
this.setUniform(`${prefix}Volume`, "float", s.volume?.current || 0);
|
|
3305
|
+
this.setUniform(`${prefix}Low`, "float", s.bands?.low || 0);
|
|
3306
|
+
this.setUniform(`${prefix}LowMid`, "float", s.bands?.lowMid || 0);
|
|
3307
|
+
this.setUniform(`${prefix}Mid`, "float", s.bands?.mid || 0);
|
|
3308
|
+
this.setUniform(`${prefix}HighMid`, "float", s.bands?.highMid || 0);
|
|
3309
|
+
this.setUniform(`${prefix}High`, "float", s.bands?.high || 0);
|
|
3310
|
+
this.setUniform(`${prefix}Brightness`, "float", s.spectral?.brightness || 0);
|
|
3311
|
+
this.setUniform(`${prefix}Flatness`, "float", s.spectral?.flatness || 0);
|
|
3312
|
+
} else {
|
|
3313
|
+
this.setUniform(`${prefix}Connected`, "bool", false);
|
|
3314
|
+
this.setUniform(`${prefix}Volume`, "float", 0);
|
|
3315
|
+
this.setUniform(`${prefix}Low`, "float", 0);
|
|
3316
|
+
this.setUniform(`${prefix}LowMid`, "float", 0);
|
|
3317
|
+
this.setUniform(`${prefix}Mid`, "float", 0);
|
|
3318
|
+
this.setUniform(`${prefix}HighMid`, "float", 0);
|
|
3319
|
+
this.setUniform(`${prefix}High`, "float", 0);
|
|
3320
|
+
this.setUniform(`${prefix}Brightness`, "float", 0);
|
|
3321
|
+
this.setUniform(`${prefix}Flatness`, "float", 0);
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
3206
3324
|
const faces = video.faces || [];
|
|
3207
3325
|
this.setUniform("u_faceCount", "int", faces.length);
|
|
3208
3326
|
if (faces.length > 0) {
|
|
@@ -3732,18 +3850,18 @@ ${error}`);
|
|
|
3732
3850
|
}
|
|
3733
3851
|
}
|
|
3734
3852
|
/**
|
|
3735
|
-
* Update compositor stream texture at specified index
|
|
3853
|
+
* Update compositor video stream texture at specified index
|
|
3736
3854
|
* Supports both OffscreenCanvas and ImageBitmap for zero-copy pipeline
|
|
3737
3855
|
*/
|
|
3738
|
-
|
|
3856
|
+
updateVideoStreamTexture(index, streamFrame) {
|
|
3739
3857
|
const gl = this.gl;
|
|
3740
|
-
const uniformName = `
|
|
3858
|
+
const uniformName = `u_videoStream${index}`;
|
|
3741
3859
|
const unit = this.textureUnits.get(uniformName);
|
|
3742
|
-
if (!this.
|
|
3743
|
-
this.
|
|
3860
|
+
if (!this.videoStreamTextures[index]) {
|
|
3861
|
+
this.videoStreamTextures[index] = gl.createTexture();
|
|
3744
3862
|
}
|
|
3745
3863
|
gl.activeTexture(gl.TEXTURE0 + unit);
|
|
3746
|
-
gl.bindTexture(gl.TEXTURE_2D, this.
|
|
3864
|
+
gl.bindTexture(gl.TEXTURE_2D, this.videoStreamTextures[index]);
|
|
3747
3865
|
const shouldFlip = streamFrame instanceof OffscreenCanvas;
|
|
3748
3866
|
if (shouldFlip) {
|
|
3749
3867
|
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
|
|
@@ -3781,7 +3899,8 @@ ${error}`);
|
|
|
3781
3899
|
}
|
|
3782
3900
|
const texture = this.deviceTextures[index];
|
|
3783
3901
|
if (!texture) return;
|
|
3784
|
-
const textureUnit =
|
|
3902
|
+
const textureUnit = this.textureUnits.get(`u_device${index}`);
|
|
3903
|
+
if (textureUnit === void 0) return;
|
|
3785
3904
|
this.gl.activeTexture(this.gl.TEXTURE0 + textureUnit);
|
|
3786
3905
|
this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
|
|
3787
3906
|
const shouldFlip = frame instanceof OffscreenCanvas;
|
|
@@ -3803,6 +3922,11 @@ ${error}`);
|
|
|
3803
3922
|
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
|
|
3804
3923
|
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
|
|
3805
3924
|
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
|
|
3925
|
+
const uniformName = `u_device${index}`;
|
|
3926
|
+
const location = this.uniformLocations.get(uniformName);
|
|
3927
|
+
if (location) {
|
|
3928
|
+
this.gl.uniform1i(location, textureUnit);
|
|
3929
|
+
}
|
|
3806
3930
|
if (frame instanceof ImageBitmap) {
|
|
3807
3931
|
frame.close();
|
|
3808
3932
|
}
|
|
@@ -3934,10 +4058,10 @@ ${error}`);
|
|
|
3934
4058
|
if (this.audioWaveformTexture) gl.deleteTexture(this.audioWaveformTexture);
|
|
3935
4059
|
if (this.videoTexture) gl.deleteTexture(this.videoTexture);
|
|
3936
4060
|
if (this.segmentationTexture) gl.deleteTexture(this.segmentationTexture);
|
|
3937
|
-
for (const texture of this.
|
|
4061
|
+
for (const texture of this.videoStreamTextures) {
|
|
3938
4062
|
if (texture) gl.deleteTexture(texture);
|
|
3939
4063
|
}
|
|
3940
|
-
this.
|
|
4064
|
+
this.videoStreamTextures = [];
|
|
3941
4065
|
for (const texture of this.deviceTextures) {
|
|
3942
4066
|
if (texture) gl.deleteTexture(texture);
|
|
3943
4067
|
}
|
|
@@ -3953,6 +4077,394 @@ ${error}`);
|
|
|
3953
4077
|
if (this.quadBuffer) gl.deleteBuffer(this.quadBuffer);
|
|
3954
4078
|
}
|
|
3955
4079
|
}
|
|
4080
|
+
const _PK = {
|
|
4081
|
+
kty: "EC",
|
|
4082
|
+
crv: "P-256",
|
|
4083
|
+
x: "6bkPbVZXx-c08blVs6qIwm0gfSRLS2nnf2Tsz19ggtM",
|
|
4084
|
+
y: "lhi486ASKQkS8TGbVee-FpdAu7qKaO3gad_4ScX8qJI"
|
|
4085
|
+
};
|
|
4086
|
+
const GRACE_SECONDS = 60;
|
|
4087
|
+
let _key = null;
|
|
4088
|
+
let _restricted = false;
|
|
4089
|
+
let _cache = null;
|
|
4090
|
+
let _expiry = 0;
|
|
4091
|
+
function _b64url(s) {
|
|
4092
|
+
const padded = s.replace(/-/g, "+").replace(/_/g, "/");
|
|
4093
|
+
const bin = atob(padded);
|
|
4094
|
+
const bytes = new Uint8Array(bin.length);
|
|
4095
|
+
for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
|
|
4096
|
+
return bytes;
|
|
4097
|
+
}
|
|
4098
|
+
async function init$1() {
|
|
4099
|
+
if (typeof crypto === "undefined" || !crypto.subtle) {
|
|
4100
|
+
_restricted = true;
|
|
4101
|
+
console.warn("[Viji] _SC: secure context required — restricted mode active");
|
|
4102
|
+
return;
|
|
4103
|
+
}
|
|
4104
|
+
try {
|
|
4105
|
+
_key = await crypto.subtle.importKey(
|
|
4106
|
+
"jwk",
|
|
4107
|
+
_PK,
|
|
4108
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
4109
|
+
false,
|
|
4110
|
+
["verify"]
|
|
4111
|
+
);
|
|
4112
|
+
} catch {
|
|
4113
|
+
_restricted = true;
|
|
4114
|
+
console.warn("[Viji] _SC: key import failed — restricted mode active");
|
|
4115
|
+
}
|
|
4116
|
+
}
|
|
4117
|
+
async function update(token) {
|
|
4118
|
+
if (_restricted || !_key) {
|
|
4119
|
+
_cache = null;
|
|
4120
|
+
_expiry = 0;
|
|
4121
|
+
return;
|
|
4122
|
+
}
|
|
4123
|
+
try {
|
|
4124
|
+
const parts = token.split(".");
|
|
4125
|
+
if (parts.length !== 3) throw new Error("malformed");
|
|
4126
|
+
const signingInput = new TextEncoder().encode(parts[0] + "." + parts[1]);
|
|
4127
|
+
const signature = _b64url(parts[2]);
|
|
4128
|
+
const valid = await crypto.subtle.verify(
|
|
4129
|
+
{ name: "ECDSA", hash: "SHA-256" },
|
|
4130
|
+
_key,
|
|
4131
|
+
signature.buffer,
|
|
4132
|
+
signingInput.buffer
|
|
4133
|
+
);
|
|
4134
|
+
if (!valid) throw new Error("invalid signature");
|
|
4135
|
+
const payload = JSON.parse(new TextDecoder().decode(_b64url(parts[1])));
|
|
4136
|
+
_cache = payload.c ?? {};
|
|
4137
|
+
_expiry = payload.e ?? 0;
|
|
4138
|
+
} catch {
|
|
4139
|
+
_cache = null;
|
|
4140
|
+
_expiry = 0;
|
|
4141
|
+
}
|
|
4142
|
+
}
|
|
4143
|
+
function get$1(key, defaultValue) {
|
|
4144
|
+
if (_restricted || !_cache) return defaultValue;
|
|
4145
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
4146
|
+
if (_expiry > 0 && _expiry + GRACE_SECONDS < now) {
|
|
4147
|
+
_cache = null;
|
|
4148
|
+
_expiry = 0;
|
|
4149
|
+
return defaultValue;
|
|
4150
|
+
}
|
|
4151
|
+
return typeof _cache[key] === "number" ? _cache[key] : defaultValue;
|
|
4152
|
+
}
|
|
4153
|
+
const FULL_W = 44, FULL_H = 74;
|
|
4154
|
+
const MINI_W = 44, MINI_H = 23;
|
|
4155
|
+
const STROKE_COLOR = "#F1F1F1";
|
|
4156
|
+
let _bufferFull = null;
|
|
4157
|
+
let _bufferMini = null;
|
|
4158
|
+
let _glTexFull = null;
|
|
4159
|
+
let _glTexMini = null;
|
|
4160
|
+
let _glProgram = null;
|
|
4161
|
+
let _glVbo = null;
|
|
4162
|
+
let _glVao = null;
|
|
4163
|
+
let _glInitFor = null;
|
|
4164
|
+
let _hint = 0;
|
|
4165
|
+
const VERT_SRC = `
|
|
4166
|
+
attribute vec2 a_pos;
|
|
4167
|
+
attribute vec2 a_uv;
|
|
4168
|
+
varying vec2 v_uv;
|
|
4169
|
+
void main() {
|
|
4170
|
+
v_uv = a_uv;
|
|
4171
|
+
gl_Position = vec4(a_pos, 0.0, 1.0);
|
|
4172
|
+
}`;
|
|
4173
|
+
const FRAG_SRC = `
|
|
4174
|
+
precision mediump float;
|
|
4175
|
+
uniform sampler2D u_tex;
|
|
4176
|
+
uniform float u_alpha;
|
|
4177
|
+
varying vec2 v_uv;
|
|
4178
|
+
void main() {
|
|
4179
|
+
gl_FragColor = texture2D(u_tex, v_uv) * u_alpha;
|
|
4180
|
+
}`;
|
|
4181
|
+
function renderFullLogo(ctx) {
|
|
4182
|
+
ctx.strokeStyle = STROKE_COLOR;
|
|
4183
|
+
ctx.lineCap = "round";
|
|
4184
|
+
ctx.lineWidth = 2.8;
|
|
4185
|
+
ctx.beginPath();
|
|
4186
|
+
ctx.moveTo(21.9991, 5);
|
|
4187
|
+
ctx.lineTo(5, 21.999);
|
|
4188
|
+
ctx.stroke();
|
|
4189
|
+
ctx.beginPath();
|
|
4190
|
+
ctx.moveTo(38.9981, 21.998);
|
|
4191
|
+
ctx.lineTo(21.999, 38.9971);
|
|
4192
|
+
ctx.stroke();
|
|
4193
|
+
ctx.beginPath();
|
|
4194
|
+
ctx.moveTo(38.9984, 5);
|
|
4195
|
+
ctx.lineTo(5, 38.9983);
|
|
4196
|
+
ctx.stroke();
|
|
4197
|
+
ctx.lineWidth = 3.5;
|
|
4198
|
+
ctx.beginPath();
|
|
4199
|
+
ctx.moveTo(5.00052, 5.00155);
|
|
4200
|
+
ctx.lineTo(5.00098, 5);
|
|
4201
|
+
ctx.stroke();
|
|
4202
|
+
ctx.beginPath();
|
|
4203
|
+
ctx.moveTo(38.9986, 38.9996);
|
|
4204
|
+
ctx.lineTo(38.999, 38.998);
|
|
4205
|
+
ctx.stroke();
|
|
4206
|
+
ctx.lineWidth = 2.8;
|
|
4207
|
+
ctx.lineJoin = "round";
|
|
4208
|
+
ctx.beginPath();
|
|
4209
|
+
ctx.moveTo(5.875, 53);
|
|
4210
|
+
ctx.lineTo(10.1417, 60);
|
|
4211
|
+
ctx.lineTo(13.875, 53);
|
|
4212
|
+
ctx.stroke();
|
|
4213
|
+
ctx.beginPath();
|
|
4214
|
+
ctx.moveTo(21, 53);
|
|
4215
|
+
ctx.lineTo(21, 60);
|
|
4216
|
+
ctx.stroke();
|
|
4217
|
+
ctx.beginPath();
|
|
4218
|
+
ctx.moveTo(38.125, 53);
|
|
4219
|
+
ctx.lineTo(38.125, 60);
|
|
4220
|
+
ctx.stroke();
|
|
4221
|
+
ctx.beginPath();
|
|
4222
|
+
ctx.moveTo(30, 53);
|
|
4223
|
+
ctx.lineTo(30, 62.1502);
|
|
4224
|
+
ctx.bezierCurveTo(30, 64.2764, 28.2764, 66, 26.1502, 66);
|
|
4225
|
+
ctx.lineTo(26, 66);
|
|
4226
|
+
ctx.stroke();
|
|
4227
|
+
}
|
|
4228
|
+
function renderMiniLogo(ctx) {
|
|
4229
|
+
ctx.strokeStyle = STROKE_COLOR;
|
|
4230
|
+
ctx.lineCap = "round";
|
|
4231
|
+
ctx.lineJoin = "round";
|
|
4232
|
+
ctx.lineWidth = 2.8;
|
|
4233
|
+
ctx.beginPath();
|
|
4234
|
+
ctx.moveTo(5.875, 5);
|
|
4235
|
+
ctx.lineTo(10.1417, 12);
|
|
4236
|
+
ctx.lineTo(13.875, 5);
|
|
4237
|
+
ctx.stroke();
|
|
4238
|
+
ctx.beginPath();
|
|
4239
|
+
ctx.moveTo(21, 5);
|
|
4240
|
+
ctx.lineTo(21, 12);
|
|
4241
|
+
ctx.stroke();
|
|
4242
|
+
ctx.beginPath();
|
|
4243
|
+
ctx.moveTo(38.125, 5);
|
|
4244
|
+
ctx.lineTo(38.125, 12);
|
|
4245
|
+
ctx.stroke();
|
|
4246
|
+
ctx.beginPath();
|
|
4247
|
+
ctx.moveTo(30, 5);
|
|
4248
|
+
ctx.lineTo(30, 14.1502);
|
|
4249
|
+
ctx.bezierCurveTo(30, 16.2764, 28.2764, 18, 26.1502, 18);
|
|
4250
|
+
ctx.lineTo(26, 18);
|
|
4251
|
+
ctx.stroke();
|
|
4252
|
+
}
|
|
4253
|
+
function init(_canvas) {
|
|
4254
|
+
try {
|
|
4255
|
+
_bufferFull = new OffscreenCanvas(FULL_W, FULL_H);
|
|
4256
|
+
const ctxFull = _bufferFull.getContext("2d");
|
|
4257
|
+
if (ctxFull) renderFullLogo(ctxFull);
|
|
4258
|
+
_bufferMini = new OffscreenCanvas(MINI_W, MINI_H);
|
|
4259
|
+
const ctxMini = _bufferMini.getContext("2d");
|
|
4260
|
+
if (ctxMini) renderMiniLogo(ctxMini);
|
|
4261
|
+
} catch (e) {
|
|
4262
|
+
console.warn("[Viji] overlay: init failed", e);
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
4265
|
+
function setRenderHint(h) {
|
|
4266
|
+
_hint = h;
|
|
4267
|
+
}
|
|
4268
|
+
function draw(canvas, ctx, gl, brandingMode, displayScale = 1) {
|
|
4269
|
+
if (brandingMode >= 2) return;
|
|
4270
|
+
if (!_bufferFull && !_bufferMini) return;
|
|
4271
|
+
const isMini = _hint === 1;
|
|
4272
|
+
const s = displayScale || 1;
|
|
4273
|
+
if (ctx) {
|
|
4274
|
+
draw2D(ctx, isMini, canvas.width, s);
|
|
4275
|
+
} else if (gl) {
|
|
4276
|
+
drawGL(gl, canvas, isMini, s);
|
|
4277
|
+
}
|
|
4278
|
+
}
|
|
4279
|
+
const GL_VERTEX_ARRAY_BINDING = 34229;
|
|
4280
|
+
function uploadTexture(gl, source) {
|
|
4281
|
+
if (!source) return null;
|
|
4282
|
+
const prevTexBinding = gl.getParameter(gl.TEXTURE_BINDING_2D);
|
|
4283
|
+
const prevFlipY = gl.getParameter(gl.UNPACK_FLIP_Y_WEBGL);
|
|
4284
|
+
const prevPremultiply = gl.getParameter(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL);
|
|
4285
|
+
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
|
|
4286
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 0);
|
|
4287
|
+
const tex = gl.createTexture();
|
|
4288
|
+
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
4289
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
4290
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
4291
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
4292
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
4293
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source);
|
|
4294
|
+
gl.bindTexture(gl.TEXTURE_2D, prevTexBinding);
|
|
4295
|
+
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, prevFlipY ? 1 : 0);
|
|
4296
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, prevPremultiply ? 1 : 0);
|
|
4297
|
+
return tex;
|
|
4298
|
+
}
|
|
4299
|
+
function initGL(gl) {
|
|
4300
|
+
if (_glInitFor === gl) return;
|
|
4301
|
+
_glInitFor = gl;
|
|
4302
|
+
_glTexFull = uploadTexture(gl, _bufferFull);
|
|
4303
|
+
_glTexMini = uploadTexture(gl, _bufferMini);
|
|
4304
|
+
const vs = gl.createShader(gl.VERTEX_SHADER);
|
|
4305
|
+
gl.shaderSource(vs, VERT_SRC);
|
|
4306
|
+
gl.compileShader(vs);
|
|
4307
|
+
const fs = gl.createShader(gl.FRAGMENT_SHADER);
|
|
4308
|
+
gl.shaderSource(fs, FRAG_SRC);
|
|
4309
|
+
gl.compileShader(fs);
|
|
4310
|
+
_glProgram = gl.createProgram();
|
|
4311
|
+
gl.attachShader(_glProgram, vs);
|
|
4312
|
+
gl.attachShader(_glProgram, fs);
|
|
4313
|
+
gl.linkProgram(_glProgram);
|
|
4314
|
+
gl.deleteShader(vs);
|
|
4315
|
+
gl.deleteShader(fs);
|
|
4316
|
+
if (!gl.getProgramParameter(_glProgram, gl.LINK_STATUS)) {
|
|
4317
|
+
console.warn("[Viji] overlay: shader link failed");
|
|
4318
|
+
_glProgram = null;
|
|
4319
|
+
return;
|
|
4320
|
+
}
|
|
4321
|
+
_glVbo = gl.createBuffer();
|
|
4322
|
+
const gl2 = gl;
|
|
4323
|
+
if (typeof gl2.createVertexArray === "function") {
|
|
4324
|
+
const prevVAO = gl.getParameter(GL_VERTEX_ARRAY_BINDING);
|
|
4325
|
+
const prevBuf = gl.getParameter(gl.ARRAY_BUFFER_BINDING);
|
|
4326
|
+
_glVao = gl2.createVertexArray();
|
|
4327
|
+
gl2.bindVertexArray(_glVao);
|
|
4328
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, _glVbo);
|
|
4329
|
+
const aPos = gl.getAttribLocation(_glProgram, "a_pos");
|
|
4330
|
+
const aUv = gl.getAttribLocation(_glProgram, "a_uv");
|
|
4331
|
+
gl.enableVertexAttribArray(aPos);
|
|
4332
|
+
gl.enableVertexAttribArray(aUv);
|
|
4333
|
+
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 16, 0);
|
|
4334
|
+
gl.vertexAttribPointer(aUv, 2, gl.FLOAT, false, 16, 8);
|
|
4335
|
+
gl2.bindVertexArray(prevVAO);
|
|
4336
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, prevBuf);
|
|
4337
|
+
}
|
|
4338
|
+
}
|
|
4339
|
+
function draw2D(ctx, mini, canvasW, s) {
|
|
4340
|
+
const buffer = mini ? _bufferMini : _bufferFull;
|
|
4341
|
+
if (!buffer) return;
|
|
4342
|
+
const drawW = (mini ? MINI_W : FULL_W) * s;
|
|
4343
|
+
const drawH = (mini ? MINI_H : FULL_H) * s;
|
|
4344
|
+
const x = mini ? Math.round((canvasW - drawW) / 2) : Math.round(48 * s);
|
|
4345
|
+
const y = Math.round((mini ? 52 : 48) * s);
|
|
4346
|
+
ctx.save();
|
|
4347
|
+
ctx.globalAlpha = 0.85;
|
|
4348
|
+
ctx.drawImage(buffer, x, y, drawW, drawH);
|
|
4349
|
+
ctx.restore();
|
|
4350
|
+
}
|
|
4351
|
+
function drawGL(gl, canvas, mini, s) {
|
|
4352
|
+
initGL(gl);
|
|
4353
|
+
if (!_glProgram || !_glVbo) return;
|
|
4354
|
+
const tex = mini ? _glTexMini : _glTexFull;
|
|
4355
|
+
if (!tex) return;
|
|
4356
|
+
const logoW = (mini ? MINI_W : FULL_W) * s;
|
|
4357
|
+
const logoH = (mini ? MINI_H : FULL_H) * s;
|
|
4358
|
+
const cw = canvas.width;
|
|
4359
|
+
const ch = canvas.height;
|
|
4360
|
+
const px = mini ? Math.round((cw - logoW) / 2) : Math.round(48 * s);
|
|
4361
|
+
const py = Math.round((mini ? 52 : 48) * s);
|
|
4362
|
+
const x0 = px / cw * 2 - 1;
|
|
4363
|
+
const y0 = 1 - (py + logoH) / ch * 2;
|
|
4364
|
+
const x1 = (px + logoW) / cw * 2 - 1;
|
|
4365
|
+
const y1 = 1 - py / ch * 2;
|
|
4366
|
+
const gl2 = gl;
|
|
4367
|
+
const hasVAO = _glVao && typeof gl2.bindVertexArray === "function";
|
|
4368
|
+
const prevProgram = gl.getParameter(gl.CURRENT_PROGRAM);
|
|
4369
|
+
const prevActiveTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
|
|
4370
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
4371
|
+
const prevTex0 = gl.getParameter(gl.TEXTURE_BINDING_2D);
|
|
4372
|
+
const prevArrayBuffer = gl.getParameter(gl.ARRAY_BUFFER_BINDING);
|
|
4373
|
+
const prevFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
|
|
4374
|
+
const prevViewport = gl.getParameter(gl.VIEWPORT);
|
|
4375
|
+
const prevBlend = gl.isEnabled(gl.BLEND);
|
|
4376
|
+
const prevBlendSrcRGB = gl.getParameter(gl.BLEND_SRC_RGB);
|
|
4377
|
+
const prevBlendDstRGB = gl.getParameter(gl.BLEND_DST_RGB);
|
|
4378
|
+
const prevBlendSrcAlpha = gl.getParameter(gl.BLEND_SRC_ALPHA);
|
|
4379
|
+
const prevBlendDstAlpha = gl.getParameter(gl.BLEND_DST_ALPHA);
|
|
4380
|
+
const prevBlendEqRGB = gl.getParameter(gl.BLEND_EQUATION_RGB);
|
|
4381
|
+
const prevBlendEqAlpha = gl.getParameter(gl.BLEND_EQUATION_ALPHA);
|
|
4382
|
+
const prevDepthTest = gl.isEnabled(gl.DEPTH_TEST);
|
|
4383
|
+
const prevScissorTest = gl.isEnabled(gl.SCISSOR_TEST);
|
|
4384
|
+
const prevStencilTest = gl.isEnabled(gl.STENCIL_TEST);
|
|
4385
|
+
const prevCullFace = gl.isEnabled(gl.CULL_FACE);
|
|
4386
|
+
const prevColorMask = gl.getParameter(gl.COLOR_WRITEMASK);
|
|
4387
|
+
const prevUnpackFlipY = gl.getParameter(gl.UNPACK_FLIP_Y_WEBGL);
|
|
4388
|
+
const prevVAO = hasVAO ? gl.getParameter(GL_VERTEX_ARRAY_BINDING) : null;
|
|
4389
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
4390
|
+
gl.viewport(0, 0, cw, ch);
|
|
4391
|
+
gl.useProgram(_glProgram);
|
|
4392
|
+
gl.enable(gl.BLEND);
|
|
4393
|
+
gl.blendEquation(gl.FUNC_ADD);
|
|
4394
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
4395
|
+
gl.disable(gl.DEPTH_TEST);
|
|
4396
|
+
gl.disable(gl.SCISSOR_TEST);
|
|
4397
|
+
gl.disable(gl.STENCIL_TEST);
|
|
4398
|
+
gl.disable(gl.CULL_FACE);
|
|
4399
|
+
gl.colorMask(true, true, true, true);
|
|
4400
|
+
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 0);
|
|
4401
|
+
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
4402
|
+
gl.uniform1i(gl.getUniformLocation(_glProgram, "u_tex"), 0);
|
|
4403
|
+
gl.uniform1f(gl.getUniformLocation(_glProgram, "u_alpha"), 0.85);
|
|
4404
|
+
const verts = new Float32Array([
|
|
4405
|
+
x0,
|
|
4406
|
+
y0,
|
|
4407
|
+
0,
|
|
4408
|
+
0,
|
|
4409
|
+
x1,
|
|
4410
|
+
y0,
|
|
4411
|
+
1,
|
|
4412
|
+
0,
|
|
4413
|
+
x0,
|
|
4414
|
+
y1,
|
|
4415
|
+
0,
|
|
4416
|
+
1,
|
|
4417
|
+
x0,
|
|
4418
|
+
y1,
|
|
4419
|
+
0,
|
|
4420
|
+
1,
|
|
4421
|
+
x1,
|
|
4422
|
+
y0,
|
|
4423
|
+
1,
|
|
4424
|
+
0,
|
|
4425
|
+
x1,
|
|
4426
|
+
y1,
|
|
4427
|
+
1,
|
|
4428
|
+
1
|
|
4429
|
+
]);
|
|
4430
|
+
if (hasVAO) {
|
|
4431
|
+
gl2.bindVertexArray(_glVao);
|
|
4432
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, _glVbo);
|
|
4433
|
+
gl.bufferData(gl.ARRAY_BUFFER, verts, gl.DYNAMIC_DRAW);
|
|
4434
|
+
} else {
|
|
4435
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, _glVbo);
|
|
4436
|
+
gl.bufferData(gl.ARRAY_BUFFER, verts, gl.DYNAMIC_DRAW);
|
|
4437
|
+
const aPos = gl.getAttribLocation(_glProgram, "a_pos");
|
|
4438
|
+
const aUv = gl.getAttribLocation(_glProgram, "a_uv");
|
|
4439
|
+
gl.enableVertexAttribArray(aPos);
|
|
4440
|
+
gl.enableVertexAttribArray(aUv);
|
|
4441
|
+
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 16, 0);
|
|
4442
|
+
gl.vertexAttribPointer(aUv, 2, gl.FLOAT, false, 16, 8);
|
|
4443
|
+
}
|
|
4444
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
4445
|
+
if (hasVAO) gl2.bindVertexArray(prevVAO);
|
|
4446
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, prevFramebuffer);
|
|
4447
|
+
gl.viewport(prevViewport[0], prevViewport[1], prevViewport[2], prevViewport[3]);
|
|
4448
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, prevArrayBuffer);
|
|
4449
|
+
gl.colorMask(prevColorMask[0], prevColorMask[1], prevColorMask[2], prevColorMask[3]);
|
|
4450
|
+
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, prevUnpackFlipY ? 1 : 0);
|
|
4451
|
+
if (prevScissorTest) gl.enable(gl.SCISSOR_TEST);
|
|
4452
|
+
else gl.disable(gl.SCISSOR_TEST);
|
|
4453
|
+
if (prevStencilTest) gl.enable(gl.STENCIL_TEST);
|
|
4454
|
+
else gl.disable(gl.STENCIL_TEST);
|
|
4455
|
+
if (prevCullFace) gl.enable(gl.CULL_FACE);
|
|
4456
|
+
else gl.disable(gl.CULL_FACE);
|
|
4457
|
+
if (prevDepthTest) gl.enable(gl.DEPTH_TEST);
|
|
4458
|
+
else gl.disable(gl.DEPTH_TEST);
|
|
4459
|
+
if (prevBlend) gl.enable(gl.BLEND);
|
|
4460
|
+
else gl.disable(gl.BLEND);
|
|
4461
|
+
gl.blendFuncSeparate(prevBlendSrcRGB, prevBlendDstRGB, prevBlendSrcAlpha, prevBlendDstAlpha);
|
|
4462
|
+
gl.blendEquationSeparate(prevBlendEqRGB, prevBlendEqAlpha);
|
|
4463
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
4464
|
+
gl.bindTexture(gl.TEXTURE_2D, prevTex0);
|
|
4465
|
+
gl.activeTexture(prevActiveTexture);
|
|
4466
|
+
gl.useProgram(prevProgram);
|
|
4467
|
+
}
|
|
3956
4468
|
class VijiWorkerRuntime {
|
|
3957
4469
|
canvas = null;
|
|
3958
4470
|
ctx = null;
|
|
@@ -3972,6 +4484,8 @@ class VijiWorkerRuntime {
|
|
|
3972
4484
|
// Shader adapter for shader mode
|
|
3973
4485
|
shaderAdapter = null;
|
|
3974
4486
|
rendererType = "native";
|
|
4487
|
+
_isHeadless = false;
|
|
4488
|
+
_displayScale = 1;
|
|
3975
4489
|
// Pending capture requests (queue to handle multiple simultaneous requests)
|
|
3976
4490
|
pendingCaptures = [];
|
|
3977
4491
|
/**
|
|
@@ -4027,6 +4541,11 @@ class VijiWorkerRuntime {
|
|
|
4027
4541
|
};
|
|
4028
4542
|
// Map deviceId → streamIndex for O(1) device video lookup
|
|
4029
4543
|
deviceVideoMap = /* @__PURE__ */ new Map();
|
|
4544
|
+
// Audio stream state management (mirroring video stream pattern)
|
|
4545
|
+
static AUDIO_ADDITIONAL_BASE = 1;
|
|
4546
|
+
static AUDIO_DEVICE_BASE = 100;
|
|
4547
|
+
audioStreamStates = /* @__PURE__ */ new Map();
|
|
4548
|
+
deviceAudioMap = /* @__PURE__ */ new Map();
|
|
4030
4549
|
// Video state is now managed by the worker-side VideoSystem
|
|
4031
4550
|
// Artist API object
|
|
4032
4551
|
viji = {
|
|
@@ -4124,7 +4643,9 @@ class VijiWorkerRuntime {
|
|
|
4124
4643
|
}
|
|
4125
4644
|
},
|
|
4126
4645
|
// Additional video streams (index 1+, no CV)
|
|
4127
|
-
|
|
4646
|
+
videoStreams: [],
|
|
4647
|
+
// Additional audio streams (lightweight analysis, no beat detection)
|
|
4648
|
+
audioStreams: [],
|
|
4128
4649
|
// Interaction APIs will be added during construction
|
|
4129
4650
|
mouse: {},
|
|
4130
4651
|
keyboard: {},
|
|
@@ -4195,7 +4716,7 @@ class VijiWorkerRuntime {
|
|
|
4195
4716
|
* Initialize P5.js mode
|
|
4196
4717
|
* Sets up P5 rendering with P5WorkerAdapter
|
|
4197
4718
|
*/
|
|
4198
|
-
async initP5Mode(setup, render) {
|
|
4719
|
+
async initP5Mode(setup, render, options) {
|
|
4199
4720
|
try {
|
|
4200
4721
|
this.rendererType = "p5";
|
|
4201
4722
|
this.debugLog("🎨 Initializing P5.js mode...");
|
|
@@ -4204,7 +4725,8 @@ class VijiWorkerRuntime {
|
|
|
4204
4725
|
this.viji,
|
|
4205
4726
|
{
|
|
4206
4727
|
setup,
|
|
4207
|
-
render
|
|
4728
|
+
render,
|
|
4729
|
+
canvasMode: options?.canvasMode === "webgl" ? "webgl" : "2d"
|
|
4208
4730
|
}
|
|
4209
4731
|
);
|
|
4210
4732
|
await this.p5Adapter.init();
|
|
@@ -4296,20 +4818,47 @@ class VijiWorkerRuntime {
|
|
|
4296
4818
|
if (this.videoSystems[0]) {
|
|
4297
4819
|
Object.assign(this.viji.video, this.videoSystems[0].getVideoAPI());
|
|
4298
4820
|
}
|
|
4299
|
-
this.
|
|
4821
|
+
this.updateVijiVideoStreams();
|
|
4300
4822
|
}
|
|
4301
4823
|
/**
|
|
4302
|
-
* Updates viji.
|
|
4824
|
+
* Updates viji.videoStreams from videoSystems array.
|
|
4303
4825
|
* Collects 'additional' MediaStreams first, then 'directFrame' injected frames.
|
|
4304
4826
|
* Excludes 'main' and 'device' streams (those go to viji.video and viji.devices[].video).
|
|
4305
4827
|
*/
|
|
4306
|
-
|
|
4828
|
+
updateVijiVideoStreams() {
|
|
4307
4829
|
const additional = this.videoSystems.filter((vs) => vs && vs.getStreamType() === "additional").map((vs) => vs.getVideoAPI());
|
|
4308
4830
|
const directFrames = this.videoSystems.filter((vs) => vs && vs.getStreamType() === "directFrame").map((vs) => vs.getVideoAPI());
|
|
4309
4831
|
const freshStreams = [...additional, ...directFrames];
|
|
4310
|
-
this.viji.
|
|
4832
|
+
this.viji.videoStreams.length = freshStreams.length;
|
|
4311
4833
|
for (let i = 0; i < freshStreams.length; i++) {
|
|
4312
|
-
this.viji.
|
|
4834
|
+
this.viji.videoStreams[i] = freshStreams[i];
|
|
4835
|
+
}
|
|
4836
|
+
}
|
|
4837
|
+
/**
|
|
4838
|
+
* Rebuilds viji.audioStreams from audioStreamStates.
|
|
4839
|
+
* Collects entries in the additional range (1-99), maps to AudioStreamAPI objects.
|
|
4840
|
+
*/
|
|
4841
|
+
updateVijiAudioStreams() {
|
|
4842
|
+
const entries = [];
|
|
4843
|
+
for (const [idx, state2] of this.audioStreamStates) {
|
|
4844
|
+
if (idx >= VijiWorkerRuntime.AUDIO_ADDITIONAL_BASE && idx < VijiWorkerRuntime.AUDIO_DEVICE_BASE) {
|
|
4845
|
+
entries.push({ index: idx, ...state2 });
|
|
4846
|
+
}
|
|
4847
|
+
}
|
|
4848
|
+
entries.sort((a, b) => a.index - b.index);
|
|
4849
|
+
this.viji.audioStreams.length = entries.length;
|
|
4850
|
+
for (let i = 0; i < entries.length; i++) {
|
|
4851
|
+
const s = entries[i];
|
|
4852
|
+
const freqData = s.frequencyData;
|
|
4853
|
+
const waveData = s.waveformData;
|
|
4854
|
+
this.viji.audioStreams[i] = {
|
|
4855
|
+
isConnected: s.isConnected,
|
|
4856
|
+
volume: s.volume,
|
|
4857
|
+
bands: s.bands,
|
|
4858
|
+
spectral: s.spectral,
|
|
4859
|
+
getFrequencyData: () => freqData,
|
|
4860
|
+
getWaveform: () => waveData
|
|
4861
|
+
};
|
|
4313
4862
|
}
|
|
4314
4863
|
}
|
|
4315
4864
|
// Send all parameters (from helper functions) to host
|
|
@@ -4353,6 +4902,9 @@ class VijiWorkerRuntime {
|
|
|
4353
4902
|
case "audio-analysis-update":
|
|
4354
4903
|
this.handleAudioAnalysisUpdate(message);
|
|
4355
4904
|
break;
|
|
4905
|
+
case "audio-stream-setup":
|
|
4906
|
+
this.handleAudioStreamSetup(message);
|
|
4907
|
+
break;
|
|
4356
4908
|
case "video-canvas-setup":
|
|
4357
4909
|
this.handleVideoCanvasSetup(message);
|
|
4358
4910
|
break;
|
|
@@ -4398,6 +4950,12 @@ class VijiWorkerRuntime {
|
|
|
4398
4950
|
case "capture-frame":
|
|
4399
4951
|
this.handleCaptureFrame(message);
|
|
4400
4952
|
break;
|
|
4953
|
+
case "sc-update":
|
|
4954
|
+
update(message.data.t);
|
|
4955
|
+
break;
|
|
4956
|
+
case "rh-update":
|
|
4957
|
+
setRenderHint(message.data.h);
|
|
4958
|
+
break;
|
|
4401
4959
|
}
|
|
4402
4960
|
};
|
|
4403
4961
|
}
|
|
@@ -4405,8 +4963,25 @@ class VijiWorkerRuntime {
|
|
|
4405
4963
|
try {
|
|
4406
4964
|
this.canvas = message.data.canvas;
|
|
4407
4965
|
this.viji.canvas = this.canvas;
|
|
4966
|
+
this._isHeadless = !!message.data.isHeadless;
|
|
4967
|
+
const origGetContext = this.canvas.getContext.bind(this.canvas);
|
|
4968
|
+
this.canvas.getContext = (type, attrs) => {
|
|
4969
|
+
const result = origGetContext(type, attrs);
|
|
4970
|
+
if (result) {
|
|
4971
|
+
if (type === "2d") {
|
|
4972
|
+
this.ctx = result;
|
|
4973
|
+
this.viji.ctx = this.ctx;
|
|
4974
|
+
} else if (type === "webgl" || type === "webgl2") {
|
|
4975
|
+
this.gl = result;
|
|
4976
|
+
this.viji.gl = this.gl;
|
|
4977
|
+
}
|
|
4978
|
+
}
|
|
4979
|
+
return result;
|
|
4980
|
+
};
|
|
4408
4981
|
this.viji.width = this.canvas.width;
|
|
4409
4982
|
this.viji.height = this.canvas.height;
|
|
4983
|
+
init$1();
|
|
4984
|
+
init(this.canvas);
|
|
4410
4985
|
this.startRenderLoop();
|
|
4411
4986
|
this.postMessage("init-response", {
|
|
4412
4987
|
id: message.id
|
|
@@ -4491,6 +5066,7 @@ class VijiWorkerRuntime {
|
|
|
4491
5066
|
}
|
|
4492
5067
|
this.viji.width = Math.round(message.data.effectiveWidth);
|
|
4493
5068
|
this.viji.height = Math.round(message.data.effectiveHeight);
|
|
5069
|
+
this._displayScale = message.data.displayScale ?? 1;
|
|
4494
5070
|
if (this.gl) {
|
|
4495
5071
|
this.gl.viewport(0, 0, this.viji.width, this.viji.height);
|
|
4496
5072
|
}
|
|
@@ -4510,8 +5086,8 @@ class VijiWorkerRuntime {
|
|
|
4510
5086
|
}
|
|
4511
5087
|
handleParameterBatchUpdate(message) {
|
|
4512
5088
|
if (message.data && message.data.updates) {
|
|
4513
|
-
for (const
|
|
4514
|
-
this.parameterSystem.updateParameterValue(
|
|
5089
|
+
for (const update2 of message.data.updates) {
|
|
5090
|
+
this.parameterSystem.updateParameterValue(update2.name, update2.value);
|
|
4515
5091
|
}
|
|
4516
5092
|
this.parameterSystem.markInitialValuesSynced();
|
|
4517
5093
|
this.debugLog("Parameter system initialized successfully");
|
|
@@ -4522,6 +5098,14 @@ class VijiWorkerRuntime {
|
|
|
4522
5098
|
}
|
|
4523
5099
|
handleAudioAnalysisUpdate(message) {
|
|
4524
5100
|
const d = message.data;
|
|
5101
|
+
const streamIndex = d.streamIndex ?? 0;
|
|
5102
|
+
if (streamIndex === 0) {
|
|
5103
|
+
this.handleMainAudioUpdate(d);
|
|
5104
|
+
} else {
|
|
5105
|
+
this.handleAdditionalAudioUpdate(streamIndex, d);
|
|
5106
|
+
}
|
|
5107
|
+
}
|
|
5108
|
+
handleMainAudioUpdate(d) {
|
|
4525
5109
|
const audio = this.viji.audio;
|
|
4526
5110
|
audio.isConnected = d.isConnected;
|
|
4527
5111
|
audio.volume.current = d.volume.current;
|
|
@@ -4537,30 +5121,78 @@ class VijiWorkerRuntime {
|
|
|
4537
5121
|
audio.bands.midSmoothed = d.bands.midSmoothed;
|
|
4538
5122
|
audio.bands.highMidSmoothed = d.bands.highMidSmoothed;
|
|
4539
5123
|
audio.bands.highSmoothed = d.bands.highSmoothed;
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
5124
|
+
if (d.beat) {
|
|
5125
|
+
audio.beat.kick = d.beat.kick;
|
|
5126
|
+
audio.beat.snare = d.beat.snare;
|
|
5127
|
+
audio.beat.hat = d.beat.hat;
|
|
5128
|
+
audio.beat.any = d.beat.any;
|
|
5129
|
+
audio.beat.kickSmoothed = d.beat.kickSmoothed;
|
|
5130
|
+
audio.beat.snareSmoothed = d.beat.snareSmoothed;
|
|
5131
|
+
audio.beat.hatSmoothed = d.beat.hatSmoothed;
|
|
5132
|
+
audio.beat.anySmoothed = d.beat.anySmoothed;
|
|
5133
|
+
const events = d.beat.events || [];
|
|
5134
|
+
if (events.length > 0) {
|
|
5135
|
+
audio.beat.triggers.kick = audio.beat.triggers.kick || events.some((e) => e.type === "kick");
|
|
5136
|
+
audio.beat.triggers.snare = audio.beat.triggers.snare || events.some((e) => e.type === "snare");
|
|
5137
|
+
audio.beat.triggers.hat = audio.beat.triggers.hat || events.some((e) => e.type === "hat");
|
|
5138
|
+
audio.beat.triggers.any = true;
|
|
5139
|
+
audio.beat.events.push(...events);
|
|
5140
|
+
}
|
|
5141
|
+
audio.beat.bpm = d.beat.bpm;
|
|
5142
|
+
audio.beat.confidence = d.beat.confidence;
|
|
5143
|
+
audio.beat.isLocked = d.beat.isLocked;
|
|
5144
|
+
}
|
|
4559
5145
|
audio.spectral.brightness = d.spectral.brightness;
|
|
4560
5146
|
audio.spectral.flatness = d.spectral.flatness;
|
|
4561
5147
|
this.audioFrequencyData = new Uint8Array(d.frequencyData);
|
|
4562
5148
|
this.audioWaveformData = d.waveformData ? new Float32Array(d.waveformData) : new Float32Array(0);
|
|
4563
5149
|
}
|
|
5150
|
+
handleAdditionalAudioUpdate(streamIndex, d) {
|
|
5151
|
+
const frequencyData = new Uint8Array(d.frequencyData);
|
|
5152
|
+
const waveformData = d.waveformData ? new Float32Array(d.waveformData) : new Float32Array(0);
|
|
5153
|
+
this.audioStreamStates.set(streamIndex, {
|
|
5154
|
+
isConnected: d.isConnected,
|
|
5155
|
+
volume: { ...d.volume },
|
|
5156
|
+
bands: { ...d.bands },
|
|
5157
|
+
spectral: { ...d.spectral },
|
|
5158
|
+
frequencyData,
|
|
5159
|
+
waveformData
|
|
5160
|
+
});
|
|
5161
|
+
this.updateVijiAudioStreams();
|
|
5162
|
+
}
|
|
5163
|
+
/**
|
|
5164
|
+
* Handles audio-stream-setup: registers stream type and device mapping.
|
|
5165
|
+
* Mirrors handleVideoCanvasSetup — two-phase protocol where setup establishes
|
|
5166
|
+
* the stream identity, and subsequent audio-analysis-update messages carry data.
|
|
5167
|
+
*/
|
|
5168
|
+
handleAudioStreamSetup(message) {
|
|
5169
|
+
const { streamIndex, streamType, deviceId } = message.data;
|
|
5170
|
+
switch (streamType) {
|
|
5171
|
+
case "additional":
|
|
5172
|
+
this.updateVijiAudioStreams();
|
|
5173
|
+
break;
|
|
5174
|
+
case "device":
|
|
5175
|
+
if (deviceId) {
|
|
5176
|
+
this.deviceAudioMap.set(deviceId, streamIndex);
|
|
5177
|
+
const device = this.viji.devices.find((d) => d.id === deviceId);
|
|
5178
|
+
if (device) {
|
|
5179
|
+
const audioState = this.audioStreamStates.get(streamIndex);
|
|
5180
|
+
if (audioState) {
|
|
5181
|
+
device.audio = {
|
|
5182
|
+
isConnected: audioState.isConnected,
|
|
5183
|
+
volume: audioState.volume,
|
|
5184
|
+
bands: audioState.bands,
|
|
5185
|
+
spectral: audioState.spectral,
|
|
5186
|
+
getFrequencyData: () => audioState.frequencyData,
|
|
5187
|
+
getWaveform: () => audioState.waveformData
|
|
5188
|
+
};
|
|
5189
|
+
}
|
|
5190
|
+
}
|
|
5191
|
+
}
|
|
5192
|
+
break;
|
|
5193
|
+
}
|
|
5194
|
+
this.debugLog(`Audio stream setup at index ${streamIndex}, type: ${streamType}${deviceId ? `, deviceId: ${deviceId}` : ""}`);
|
|
5195
|
+
}
|
|
4564
5196
|
/**
|
|
4565
5197
|
* Reset frame-scoped audio events (triggers + events array).
|
|
4566
5198
|
* Called after each render, mirroring interactionSystem.frameStart().
|
|
@@ -4613,6 +5245,9 @@ class VijiWorkerRuntime {
|
|
|
4613
5245
|
audio.spectral.flatness = 0;
|
|
4614
5246
|
this.audioFrequencyData = new Uint8Array(0);
|
|
4615
5247
|
this.audioWaveformData = new Float32Array(0);
|
|
5248
|
+
this.audioStreamStates.clear();
|
|
5249
|
+
this.deviceAudioMap.clear();
|
|
5250
|
+
this.viji.audioStreams.length = 0;
|
|
4616
5251
|
}
|
|
4617
5252
|
handleVideoCanvasSetup(message) {
|
|
4618
5253
|
const { streamIndex, streamType, deviceId } = message.data;
|
|
@@ -4633,7 +5268,7 @@ class VijiWorkerRuntime {
|
|
|
4633
5268
|
Object.assign(this.viji.video, videoSystem.getVideoAPI());
|
|
4634
5269
|
break;
|
|
4635
5270
|
case "additional":
|
|
4636
|
-
this.
|
|
5271
|
+
this.updateVijiVideoStreams();
|
|
4637
5272
|
break;
|
|
4638
5273
|
case "device":
|
|
4639
5274
|
if (deviceId) {
|
|
@@ -4724,7 +5359,7 @@ class VijiWorkerRuntime {
|
|
|
4724
5359
|
this.videoSystems[index].setDebugMode(this.debugMode);
|
|
4725
5360
|
this.videoSystems[index].initializeForDirectFrames(this.rendererType);
|
|
4726
5361
|
}
|
|
4727
|
-
this.
|
|
5362
|
+
this.updateVijiVideoStreams();
|
|
4728
5363
|
this.debugLog(`[Compositor] Prepared ${directFrameCount} direct frame slot(s)`);
|
|
4729
5364
|
}
|
|
4730
5365
|
handleVideoFrameDirect(message) {
|
|
@@ -4852,7 +5487,8 @@ class VijiWorkerRuntime {
|
|
|
4852
5487
|
renderFrame() {
|
|
4853
5488
|
if (!this.isRunning) return;
|
|
4854
5489
|
const currentTime = performance.now();
|
|
4855
|
-
this.
|
|
5490
|
+
this.updateVijiVideoStreams();
|
|
5491
|
+
this.updateVijiAudioStreams();
|
|
4856
5492
|
this.viji.fps = this.frameRateMode === "full" ? this.screenRefreshRate : this.screenRefreshRate / 2;
|
|
4857
5493
|
let shouldRender = true;
|
|
4858
5494
|
if (this.frameRateMode === "half") {
|
|
@@ -4920,6 +5556,10 @@ class VijiWorkerRuntime {
|
|
|
4920
5556
|
console.warn("[AutoCapture] Failed:", error);
|
|
4921
5557
|
}
|
|
4922
5558
|
}
|
|
5559
|
+
if (!this._isHeadless && this.canvas) {
|
|
5560
|
+
const brandingMode = get$1("b", 0);
|
|
5561
|
+
draw(this.canvas, this.ctx, this.gl, brandingMode, this._displayScale);
|
|
5562
|
+
}
|
|
4923
5563
|
}
|
|
4924
5564
|
this.reportPerformanceStats(currentTime);
|
|
4925
5565
|
this.interactionSystem.frameStart();
|
|
@@ -4952,17 +5592,29 @@ class VijiWorkerRuntime {
|
|
|
4952
5592
|
this.viji.device = this.deviceState.device;
|
|
4953
5593
|
const updatedDevices = this.deviceState.devices.map((deviceData) => {
|
|
4954
5594
|
const existingDevice = this.viji.devices.find((d) => d.id === deviceData.id);
|
|
5595
|
+
const videoStreamIndex = this.deviceVideoMap.get(deviceData.id);
|
|
5596
|
+
const videoSystem = videoStreamIndex !== void 0 ? this.videoSystems[videoStreamIndex] : void 0;
|
|
5597
|
+
const audioStreamIndex = this.deviceAudioMap.get(deviceData.id);
|
|
5598
|
+
const audioState = audioStreamIndex !== void 0 ? this.audioStreamStates.get(audioStreamIndex) : void 0;
|
|
5599
|
+
const audioAPI = audioState ? {
|
|
5600
|
+
isConnected: audioState.isConnected,
|
|
5601
|
+
volume: audioState.volume,
|
|
5602
|
+
bands: audioState.bands,
|
|
5603
|
+
spectral: audioState.spectral,
|
|
5604
|
+
getFrequencyData: () => audioState.frequencyData,
|
|
5605
|
+
getWaveform: () => audioState.waveformData
|
|
5606
|
+
} : null;
|
|
4955
5607
|
if (existingDevice) {
|
|
4956
5608
|
existingDevice.name = deviceData.name;
|
|
4957
5609
|
existingDevice.motion = deviceData.motion;
|
|
4958
5610
|
existingDevice.orientation = deviceData.orientation;
|
|
5611
|
+
if (audioAPI) existingDevice.audio = audioAPI;
|
|
4959
5612
|
return existingDevice;
|
|
4960
5613
|
} else {
|
|
4961
|
-
const streamIndex = this.deviceVideoMap.get(deviceData.id);
|
|
4962
|
-
const videoSystem = streamIndex !== void 0 ? this.videoSystems[streamIndex] : void 0;
|
|
4963
5614
|
return {
|
|
4964
5615
|
...deviceData,
|
|
4965
|
-
video: videoSystem ? videoSystem.getVideoAPI() : null
|
|
5616
|
+
video: videoSystem ? videoSystem.getVideoAPI() : null,
|
|
5617
|
+
audio: audioAPI
|
|
4966
5618
|
};
|
|
4967
5619
|
}
|
|
4968
5620
|
});
|
|
@@ -4991,6 +5643,21 @@ class SceneAnalyzer {
|
|
|
4991
5643
|
}
|
|
4992
5644
|
return "native";
|
|
4993
5645
|
}
|
|
5646
|
+
/**
|
|
5647
|
+
* P5 main-canvas mode from the renderer directive (only meaningful when
|
|
5648
|
+
* {@link detectRendererType} is `'p5'`).
|
|
5649
|
+
*
|
|
5650
|
+
* - `// @renderer p5` → 2D (default)
|
|
5651
|
+
* - `// @renderer p5 webgl` → WEBGL
|
|
5652
|
+
*/
|
|
5653
|
+
static detectP5CanvasMode(sceneCode) {
|
|
5654
|
+
if (/\/\/\s*@renderer\s+p5\s+webgl\b|\/\*\s*@renderer\s+p5\s+webgl\s*\*\//i.test(
|
|
5655
|
+
sceneCode
|
|
5656
|
+
)) {
|
|
5657
|
+
return "webgl";
|
|
5658
|
+
}
|
|
5659
|
+
return "2d";
|
|
5660
|
+
}
|
|
4994
5661
|
}
|
|
4995
5662
|
var ContextualKeyword;
|
|
4996
5663
|
(function(ContextualKeyword2) {
|
|
@@ -26312,6 +26979,7 @@ async function setSceneCode(sceneCode) {
|
|
|
26312
26979
|
await runtime.initShaderMode(sceneCode);
|
|
26313
26980
|
runtime.sendAllParametersToHost();
|
|
26314
26981
|
} else if (rendererType === "p5") {
|
|
26982
|
+
const p5CanvasMode = SceneAnalyzer.detectP5CanvasMode(sceneCode);
|
|
26315
26983
|
const jsCode = prepareSceneCode(sceneCode);
|
|
26316
26984
|
const functionBody = jsCode + '\nreturn { setup: typeof setup !== "undefined" ? setup : null, render: typeof render !== "undefined" ? render : null };';
|
|
26317
26985
|
const sceneFunction = new Function("viji", "p5", functionBody);
|
|
@@ -26319,7 +26987,7 @@ async function setSceneCode(sceneCode) {
|
|
|
26319
26987
|
if (!render) {
|
|
26320
26988
|
throw new Error("P5 mode requires a render(viji, p5) function");
|
|
26321
26989
|
}
|
|
26322
|
-
await runtime.initP5Mode(setup, render);
|
|
26990
|
+
await runtime.initP5Mode(setup, render, { canvasMode: p5CanvasMode });
|
|
26323
26991
|
runtime.sendAllParametersToHost();
|
|
26324
26992
|
} else {
|
|
26325
26993
|
const jsCode = prepareSceneCode(sceneCode);
|
|
@@ -26345,4 +27013,4 @@ async function setSceneCode(sceneCode) {
|
|
|
26345
27013
|
}
|
|
26346
27014
|
}
|
|
26347
27015
|
self.setSceneCode = setSceneCode;
|
|
26348
|
-
//# sourceMappingURL=viji.worker-
|
|
27016
|
+
//# sourceMappingURL=viji.worker-CdHkRwxI.js.map
|