@viji-dev/core 0.4.5 → 0.5.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/artist-dts-p5.js +1 -1
- package/dist/artist-dts.js +1 -1
- package/dist/artist-global-p5.d.ts +106 -48
- package/dist/artist-global.d.ts +106 -48
- package/dist/artist-jsdoc.d.ts +2 -6
- package/dist/assets/{viji.worker-D1yRmN8m.js → viji.worker-CWKkFyOs.js} +561 -168
- package/dist/assets/viji.worker-CWKkFyOs.js.map +1 -0
- package/dist/docs-api.js +9759 -9704
- package/dist/{essentia-wasm.web-BbdWO0Xs.js → essentia-wasm.web-CmPC-AKu.js} +2 -2
- package/dist/{essentia-wasm.web-BbdWO0Xs.js.map → essentia-wasm.web-CmPC-AKu.js.map} +1 -1
- package/dist/{index-DUg1Foui.js → index-Cp9G0z4E.js} +109 -11
- package/dist/index-Cp9G0z4E.js.map +1 -0
- package/dist/index.d.ts +106 -48
- package/dist/index.js +1 -1
- package/dist/shader-uniforms.js +10 -0
- package/package.json +98 -97
- package/dist/assets/viji.worker-D1yRmN8m.js.map +0 -1
- package/dist/index-DUg1Foui.js.map +0 -1
|
@@ -6,7 +6,7 @@ class VijiCoreError extends Error {
|
|
|
6
6
|
this.name = "VijiCoreError";
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
|
-
const inlineScriptCode = '"use strict";\n(() => {\n // src/iframe/protocol.ts\n var PROTOCOL_VERSION = 1;\n function collectTransferables(msg) {\n switch (msg.type) {\n case "init": {\n const m = msg;\n const out = [];\n if (m.data?.canvas) out.push(m.data.canvas);\n const wasm = m.data?.cvWasmFiles;\n if (wasm) {\n out.push(\n wasm.simdLoaderJs,\n wasm.simdBinary,\n wasm.nosimdLoaderJs,\n wasm.nosimdBinary\n );\n }\n return out;\n }\n case "video-canvas-setup": {\n const m = msg;\n return m.data?.offscreenCanvas ? [m.data.offscreenCanvas] : [];\n }\n case "video-frame-update": {\n const m = msg;\n return m.data?.imageBitmap ? [m.data.imageBitmap] : [];\n }\n case "video-frame-direct": {\n const m = msg;\n return m.data?.imageBitmap ? [m.data.imageBitmap] : [];\n }\n case "parameter-update": {\n const m = msg;\n return m.data?.transferList ?? [];\n }\n case "parameter-batch-update": {\n const m = msg;\n return m.data?.transferList ?? [];\n }\n case "audio-analysis-update": {\n const m = msg;\n const out = [];\n if (m.data?.frequencyData?.buffer) out.push(m.data.frequencyData.buffer);\n if (m.data?.waveformData?.buffer) out.push(m.data.waveformData.buffer);\n return out;\n }\n case "capture-frame-result":\n case "auto-capture-result": {\n const data = msg.data;\n return data?.bitmap ? [data.bitmap] : [];\n }\n default:\n return [];\n }\n }\n\n // src/iframe/inline-script.ts\n var hostOrigin = null;\n var hostWindow = null;\n var worker = null;\n var canvas = null;\n var domHandlersAttached = false;\n var sensorHandlersAttached = false;\n function whenDomReady() {\n if (document.readyState === "loading") {\n return new Promise((resolve) => {\n document.addEventListener("DOMContentLoaded", () => resolve(), {\n once: true\n });\n });\n }\n return Promise.resolve();\n }\n async function announceReady() {\n await whenDomReady();\n const msg = {\n type: "iframe-ready",\n protocolVersion: PROTOCOL_VERSION\n };\n window.parent.postMessage(msg, "*");\n }\n function installHostListener() {\n window.addEventListener("message", (event) => {\n if (event.source !== window.parent) return;\n if (hostOrigin === null) {\n hostOrigin = event.origin;\n hostWindow = window.parent;\n } else if (event.origin !== hostOrigin) {\n return;\n }\n handleHostMessage(event.data).catch((err) => {\n reportError(err);\n });\n });\n }\n function postToHost(msg, transfer = []) {\n if (hostOrigin === null || hostWindow === null) {\n return;\n }\n const targetOrigin = hostOrigin === "null" ? "*" : hostOrigin;\n hostWindow.postMessage(msg, targetOrigin, transfer);\n }\n function reportError(err) {\n const e = err;\n const msg = e?.stack ? {\n type: "iframe-error",\n message: e.message ?? String(err),\n stack: e.stack\n } : {\n type: "iframe-error",\n message: e?.message ?? String(err)\n };\n if (hostOrigin && hostWindow) {\n const targetOrigin = hostOrigin === "null" ? "*" : hostOrigin;\n hostWindow.postMessage(msg, targetOrigin);\n } else {\n window.parent.postMessage(msg, "*");\n }\n }\n async function handleHostMessage(msg) {\n switch (msg.type) {\n case "viji-bootstrap":\n await handleBootstrap(msg);\n return;\n case "viji-host-message":\n relayHostToWorker(msg.payload);\n return;\n case "viji-resize":\n handleResize(msg.width, msg.height);\n return;\n case "viji-enable-sensors":\n setSensorsEnabled(msg.enabled);\n return;\n case "viji-enable-interaction":\n setInteractionEnabled(msg.enabled);\n return;\n case "viji-terminate":\n handleTerminate();\n return;\n }\n }\n async function handleBootstrap(msg) {\n if (worker) {\n return;\n }\n canvas = document.createElement("canvas");\n canvas.id = "viji-canvas";\n canvas.width = msg.init.canvasWidth;\n canvas.height = msg.init.canvasHeight;\n canvas.style.width = "100%";\n canvas.style.height = "100%";\n canvas.style.display = "block";\n canvas.tabIndex = 0;\n canvas.style.outline = "none";\n document.body.appendChild(canvas);\n const offscreen = canvas.transferControlToOffscreen();\n const workerSource = arrayBufferToString(msg.workerCode);\n const workerDataUrl = "data:text/javascript;base64," + base64Encode(workerSource);\n worker = new Worker(workerDataUrl, {\n type: "module",\n credentials: "omit"\n });\n worker.onerror = (e) => {\n reportError(new Error(`Worker error: ${e.message ?? String(e)}`));\n };\n worker.onmessage = (event) => {\n relayWorkerToHost(event.data);\n };\n const initId = `init_${Date.now()}`;\n const initMsg = {\n type: "init",\n id: initId,\n timestamp: Date.now(),\n data: {\n canvas: offscreen,\n isHeadless: msg.init.isHeadless,\n sc: msg.init.sc,\n rh: msg.init.rh,\n cvWasmFiles: msg.wasmFiles\n }\n };\n const initResponse = waitForWorkerMessage((m) => {\n return m && m.type === "init-response" && m.id === initId;\n });\n worker.postMessage(initMsg, [\n offscreen,\n msg.wasmFiles.simdLoaderJs,\n msg.wasmFiles.simdBinary,\n msg.wasmFiles.nosimdLoaderJs,\n msg.wasmFiles.nosimdBinary\n ]);\n await initResponse;\n if (msg.init.allowInteraction && !msg.init.isHeadless) {\n setInteractionEnabled(true);\n }\n if (msg.init.allowSensors && !msg.init.isHeadless) {\n setSensorsEnabled(true);\n }\n if (canvas) {\n canvas.addEventListener("contextmenu", (e) => e.preventDefault());\n }\n postToHost({ type: "viji-ready" });\n }\n function arrayBufferToString(buf) {\n return new TextDecoder("utf-8").decode(buf);\n }\n function base64Encode(s) {\n const bytes = new TextEncoder().encode(s);\n let binary = "";\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);\n return btoa(binary);\n }\n function waitForWorkerMessage(predicate) {\n return new Promise((resolve, reject) => {\n if (!worker) {\n reject(new Error("worker not spawned"));\n return;\n }\n const w = worker;\n const onceListener = (event) => {\n if (predicate(event.data)) {\n w.removeEventListener("message", onceListener);\n resolve(event.data);\n }\n };\n w.addEventListener("message", onceListener);\n });\n }\n function relayHostToWorker(payload) {\n if (!worker || !payload) return;\n try {\n const transfer = collectTransferables(payload);\n worker.postMessage(payload, transfer);\n } catch (err) {\n reportError(err);\n }\n }\n function relayWorkerToHost(payload) {\n if (!payload) return;\n try {\n const transfer = collectTransferables(payload);\n postToHost(\n { type: "worker-message", payload },\n transfer\n );\n } catch (err) {\n reportError(err);\n }\n }\n function handleResize(width, height) {\n if (!worker) return;\n worker.postMessage({\n type: "resolution-update",\n id: `resize_${Date.now()}`,\n timestamp: Date.now(),\n data: {\n effectiveWidth: width,\n effectiveHeight: height,\n displayScale: 1\n }\n });\n }\n var isMouseInCanvas = false;\n function setInteractionEnabled(enabled) {\n if (enabled === domHandlersAttached) return;\n if (!canvas) return;\n if (enabled) {\n canvas.addEventListener("mousedown", handleMouseEvent, { passive: false });\n canvas.addEventListener("mousemove", handleMouseEvent, { passive: false });\n canvas.addEventListener("mouseup", handleMouseEvent, { passive: false });\n canvas.addEventListener("mouseenter", handleMouseEnter, { passive: false });\n canvas.addEventListener("mouseleave", handleMouseLeave, { passive: false });\n canvas.addEventListener("wheel", handleWheelEvent, { passive: false });\n canvas.addEventListener("touchstart", handleTouchEvent, { passive: false });\n canvas.addEventListener("touchmove", handleTouchEvent, { passive: false });\n canvas.addEventListener("touchend", handleTouchEvent, { passive: false });\n canvas.addEventListener("touchcancel", handleTouchEvent, { passive: false });\n document.addEventListener("keydown", handleKeyboardEvent, { passive: false });\n document.addEventListener("keyup", handleKeyboardEvent, { passive: false });\n canvas.addEventListener("mousedown", focusCanvas);\n canvas.addEventListener("touchstart", focusCanvas);\n domHandlersAttached = true;\n } else {\n canvas.removeEventListener("mousedown", handleMouseEvent);\n canvas.removeEventListener("mousemove", handleMouseEvent);\n canvas.removeEventListener("mouseup", handleMouseEvent);\n canvas.removeEventListener("mouseenter", handleMouseEnter);\n canvas.removeEventListener("mouseleave", handleMouseLeave);\n canvas.removeEventListener("wheel", handleWheelEvent);\n canvas.removeEventListener("touchstart", handleTouchEvent);\n canvas.removeEventListener("touchmove", handleTouchEvent);\n canvas.removeEventListener("touchend", handleTouchEvent);\n canvas.removeEventListener("touchcancel", handleTouchEvent);\n document.removeEventListener("keydown", handleKeyboardEvent);\n document.removeEventListener("keyup", handleKeyboardEvent);\n canvas.removeEventListener("mousedown", focusCanvas);\n canvas.removeEventListener("touchstart", focusCanvas);\n domHandlersAttached = false;\n }\n }\n function focusCanvas() {\n if (canvas) canvas.focus();\n }\n function dualRoute(workerType, data) {\n if (worker) {\n worker.postMessage({\n type: workerType,\n id: `${workerType}_${Date.now()}`,\n timestamp: Date.now(),\n data\n });\n }\n postToHost({\n type: "interaction-event",\n kind: workerType,\n data\n });\n }\n function handleMouseEvent(event) {\n if (!canvas) return;\n event.preventDefault();\n const rect = canvas.getBoundingClientRect();\n const x = (event.clientX - rect.left) * (canvas.width / rect.width);\n const y = (event.clientY - rect.top) * (canvas.height / rect.height);\n dualRoute("mouse-update", {\n x,\n y,\n buttons: event.buttons,\n deltaX: event.movementX || 0,\n deltaY: event.movementY || 0,\n wheelDeltaX: 0,\n wheelDeltaY: 0,\n isInCanvas: isMouseInCanvas,\n timestamp: performance.now()\n });\n }\n function handleMouseEnter(event) {\n isMouseInCanvas = true;\n handleMouseEvent(event);\n }\n function handleMouseLeave(event) {\n isMouseInCanvas = false;\n handleMouseEvent(event);\n }\n function handleWheelEvent(event) {\n if (!canvas) return;\n event.preventDefault();\n const rect = canvas.getBoundingClientRect();\n const x = (event.clientX - rect.left) * (canvas.width / rect.width);\n const y = (event.clientY - rect.top) * (canvas.height / rect.height);\n dualRoute("mouse-update", {\n x,\n y,\n buttons: event.buttons,\n deltaX: 0,\n deltaY: 0,\n wheelDeltaX: event.deltaX,\n wheelDeltaY: event.deltaY,\n isInCanvas: isMouseInCanvas,\n timestamp: performance.now()\n });\n }\n var KEY_PASSTHROUGH = /* @__PURE__ */ new Set([\n "Tab",\n "F1",\n "F2",\n "F3",\n "F4",\n "F5",\n "F11",\n "F12"\n ]);\n function handleKeyboardEvent(event) {\n if (!KEY_PASSTHROUGH.has(event.key)) {\n event.preventDefault();\n }\n dualRoute("keyboard-update", {\n type: event.type,\n key: event.key,\n code: event.code,\n keyCode: event.keyCode,\n shiftKey: event.shiftKey,\n ctrlKey: event.ctrlKey,\n altKey: event.altKey,\n metaKey: event.metaKey,\n timestamp: performance.now()\n });\n }\n function handleTouchEvent(event) {\n if (!canvas) return;\n event.preventDefault();\n const rect = canvas.getBoundingClientRect();\n const scaleX = canvas.width / rect.width;\n const scaleY = canvas.height / rect.height;\n const canvasW = canvas.width;\n const canvasH = canvas.height;\n const mapTouch = (t) => {\n const cx = (t.clientX - rect.left) * scaleX;\n const cy = (t.clientY - rect.top) * scaleY;\n return {\n identifier: t.identifier,\n clientX: cx,\n clientY: cy,\n radiusX: t.radiusX ?? 0,\n radiusY: t.radiusY ?? 0,\n rotationAngle: t.rotationAngle ?? 0,\n force: t.force ?? 0,\n isInCanvas: cx >= 0 && cx <= canvasW && cy >= 0 && cy <= canvasH\n };\n };\n const changedMap = /* @__PURE__ */ new Map();\n for (let i = 0; i < event.changedTouches.length; i++) {\n const t = event.changedTouches[i];\n changedMap.set(t.identifier, mapTouch(t));\n }\n const touches = Array.from(event.touches).map((t) => {\n return changedMap.get(t.identifier) ?? mapTouch(t);\n });\n if (event.type === "touchend" || event.type === "touchcancel") {\n const activeIds = new Set(touches.map((t) => t.identifier));\n for (const [id, mapped] of changedMap) {\n if (!activeIds.has(id)) {\n touches.push({ ...mapped, ended: true });\n }\n }\n }\n dualRoute("touch-update", {\n type: event.type,\n touches,\n timestamp: performance.now()\n });\n }\n function setSensorsEnabled(enabled) {\n if (enabled === sensorHandlersAttached) return;\n if (enabled) {\n window.addEventListener("devicemotion", handleDeviceMotion);\n window.addEventListener("deviceorientation", handleDeviceOrientation);\n sensorHandlersAttached = true;\n } else {\n window.removeEventListener("devicemotion", handleDeviceMotion);\n window.removeEventListener("deviceorientation", handleDeviceOrientation);\n sensorHandlersAttached = false;\n }\n }\n function handleDeviceMotion(event) {\n if (!event.acceleration && !event.accelerationIncludingGravity && !event.rotationRate) {\n return;\n }\n postToHost({\n type: "sensor-event",\n kind: "motion",\n data: {\n acceleration: event.acceleration ? {\n x: event.acceleration.x,\n y: event.acceleration.y,\n z: event.acceleration.z\n } : null,\n accelerationIncludingGravity: event.accelerationIncludingGravity ? {\n x: event.accelerationIncludingGravity.x,\n y: event.accelerationIncludingGravity.y,\n z: event.accelerationIncludingGravity.z\n } : null,\n rotationRate: event.rotationRate ? {\n alpha: event.rotationRate.alpha,\n beta: event.rotationRate.beta,\n gamma: event.rotationRate.gamma\n } : null,\n interval: event.interval || 16\n }\n });\n }\n function handleDeviceOrientation(event) {\n postToHost({\n type: "sensor-event",\n kind: "orientation",\n data: {\n alpha: event.alpha,\n beta: event.beta,\n gamma: event.gamma,\n absolute: event.absolute || false\n }\n });\n }\n function handleTerminate() {\n setInteractionEnabled(false);\n setSensorsEnabled(false);\n if (worker) {\n worker.terminate();\n worker = null;\n }\n }\n installHostListener();\n announceReady().catch((err) => reportError(err));\n window.addEventListener("error", (e) => {\n reportError(e.error ?? new Error(e.message));\n });\n window.addEventListener("unhandledrejection", (e) => {\n reportError(e.reason ?? new Error("Unhandled promise rejection"));\n });\n})();\n';
|
|
9
|
+
const inlineScriptCode = '"use strict";\n(() => {\n // src/iframe/protocol.ts\n var PROTOCOL_VERSION = 1;\n function collectTransferables(msg) {\n switch (msg.type) {\n case "init": {\n const m = msg;\n const out = [];\n if (m.data?.canvas) out.push(m.data.canvas);\n const wasm = m.data?.cvWasmFiles;\n if (wasm) {\n out.push(\n wasm.simdLoaderJs,\n wasm.simdBinary,\n wasm.nosimdLoaderJs,\n wasm.nosimdBinary\n );\n }\n if (m.data?.controlPort) out.push(m.data.controlPort);\n return out;\n }\n case "video-canvas-setup": {\n const m = msg;\n return m.data?.offscreenCanvas ? [m.data.offscreenCanvas] : [];\n }\n case "video-frame-update": {\n const m = msg;\n return m.data?.imageBitmap ? [m.data.imageBitmap] : [];\n }\n case "video-frame-direct": {\n const m = msg;\n return m.data?.imageBitmap ? [m.data.imageBitmap] : [];\n }\n case "parameter-update": {\n const m = msg;\n return m.data?.transferList ?? [];\n }\n case "parameter-batch-update": {\n const m = msg;\n return m.data?.transferList ?? [];\n }\n case "audio-analysis-update": {\n const m = msg;\n const out = [];\n if (m.data?.frequencyData?.buffer) out.push(m.data.frequencyData.buffer);\n if (m.data?.waveformData?.buffer) out.push(m.data.waveformData.buffer);\n return out;\n }\n case "capture-frame-result":\n case "auto-capture-result": {\n const data = msg.data;\n return data?.bitmap ? [data.bitmap] : [];\n }\n default:\n return [];\n }\n }\n\n // src/iframe/inline-script.ts\n var hostOrigin = null;\n var hostWindow = null;\n var worker = null;\n var workerBlobUrl = null;\n var canvas = null;\n var domHandlersAttached = false;\n var sensorHandlersAttached = false;\n function whenDomReady() {\n if (document.readyState === "loading") {\n return new Promise((resolve) => {\n document.addEventListener("DOMContentLoaded", () => resolve(), {\n once: true\n });\n });\n }\n return Promise.resolve();\n }\n async function announceReady() {\n await whenDomReady();\n const msg = {\n type: "iframe-ready",\n protocolVersion: PROTOCOL_VERSION,\n environment: {\n crossOriginIsolated: window.crossOriginIsolated,\n isSecureContext: window.isSecureContext,\n origin: self.origin\n }\n };\n window.parent.postMessage(msg, "*");\n }\n function installHostListener() {\n window.addEventListener("message", (event) => {\n if (event.source !== window.parent) return;\n if (hostOrigin === null) {\n hostOrigin = event.origin;\n hostWindow = window.parent;\n } else if (event.origin !== hostOrigin) {\n return;\n }\n handleHostMessage(event.data).catch((err) => {\n reportError(err);\n });\n });\n }\n function postToHost(msg, transfer = []) {\n if (hostOrigin === null || hostWindow === null) {\n return;\n }\n const targetOrigin = hostOrigin === "null" ? "*" : hostOrigin;\n hostWindow.postMessage(msg, targetOrigin, transfer);\n }\n function reportError(err) {\n const e = err;\n const msg = e?.stack ? {\n type: "iframe-error",\n message: e.message ?? String(err),\n stack: e.stack\n } : {\n type: "iframe-error",\n message: e?.message ?? String(err)\n };\n emitToHost(msg);\n }\n function reportWorkerOnError(e) {\n const msg = {\n type: "iframe-error",\n message: e.message ? `Worker error: ${e.message}` : "Worker error: (no detail \\u2014 likely cross-origin opacity)",\n ...e.error && e.error.stack ? { stack: e.error.stack } : {},\n ...e.filename ? { filename: e.filename } : {},\n ...e.lineno ? { lineno: e.lineno } : {},\n ...e.colno ? { colno: e.colno } : {}\n };\n emitToHost(msg);\n }\n function emitToHost(msg) {\n if (hostOrigin && hostWindow) {\n const targetOrigin = hostOrigin === "null" ? "*" : hostOrigin;\n hostWindow.postMessage(msg, targetOrigin);\n } else {\n window.parent.postMessage(msg, "*");\n }\n }\n async function handleHostMessage(msg) {\n switch (msg.type) {\n case "viji-bootstrap":\n await handleBootstrap(msg);\n return;\n case "viji-host-message":\n relayHostToWorker(msg.payload);\n return;\n case "viji-resize":\n handleResize(msg.width, msg.height);\n return;\n case "viji-enable-sensors":\n setSensorsEnabled(msg.enabled);\n return;\n case "viji-enable-interaction":\n setInteractionEnabled(msg.enabled);\n return;\n case "viji-terminate":\n handleTerminate();\n return;\n }\n }\n async function handleBootstrap(msg) {\n if (worker) {\n return;\n }\n canvas = document.createElement("canvas");\n canvas.id = "viji-canvas";\n canvas.width = msg.init.canvasWidth;\n canvas.height = msg.init.canvasHeight;\n canvas.style.width = "100%";\n canvas.style.height = "100%";\n canvas.style.display = "block";\n canvas.tabIndex = 0;\n canvas.style.outline = "none";\n document.body.appendChild(canvas);\n const offscreen = canvas.transferControlToOffscreen();\n workerBlobUrl = URL.createObjectURL(\n new Blob([msg.workerCode], { type: "application/javascript" })\n );\n worker = new Worker(workerBlobUrl, { type: "classic" });\n worker.onerror = (e) => {\n reportWorkerOnError(e);\n };\n worker.onmessage = (event) => {\n relayWorkerToHost(event.data);\n };\n const initId = `init_${Date.now()}`;\n const initMsg = {\n type: "init",\n id: initId,\n timestamp: Date.now(),\n data: {\n canvas: offscreen,\n isHeadless: msg.init.isHeadless,\n sc: msg.init.sc,\n rh: msg.init.rh,\n cvWasmFiles: msg.wasmFiles,\n controlPort: msg.controlPort\n }\n };\n const initResponse = waitForWorkerMessage((m) => {\n return m && m.type === "init-response" && m.id === initId;\n });\n worker.postMessage(initMsg, [\n offscreen,\n msg.wasmFiles.simdLoaderJs,\n msg.wasmFiles.simdBinary,\n msg.wasmFiles.nosimdLoaderJs,\n msg.wasmFiles.nosimdBinary,\n msg.controlPort\n ]);\n await initResponse;\n if (msg.init.allowInteraction && !msg.init.isHeadless) {\n setInteractionEnabled(true);\n }\n if (msg.init.allowSensors && !msg.init.isHeadless) {\n setSensorsEnabled(true);\n }\n if (canvas) {\n canvas.addEventListener("contextmenu", (e) => e.preventDefault());\n }\n postToHost({ type: "viji-ready" });\n }\n function waitForWorkerMessage(predicate) {\n return new Promise((resolve, reject) => {\n if (!worker) {\n reject(new Error("worker not spawned"));\n return;\n }\n const w = worker;\n const onceListener = (event) => {\n if (predicate(event.data)) {\n w.removeEventListener("message", onceListener);\n resolve(event.data);\n }\n };\n w.addEventListener("message", onceListener);\n });\n }\n function relayHostToWorker(payload) {\n if (!worker || !payload) return;\n try {\n const transfer = collectTransferables(payload);\n worker.postMessage(payload, transfer);\n } catch (err) {\n reportError(err);\n }\n }\n function relayWorkerToHost(payload) {\n if (!payload) return;\n try {\n const transfer = collectTransferables(payload);\n postToHost(\n { type: "worker-message", payload },\n transfer\n );\n } catch (err) {\n reportError(err);\n }\n }\n function handleResize(width, height) {\n if (!worker) return;\n worker.postMessage({\n type: "resolution-update",\n id: `resize_${Date.now()}`,\n timestamp: Date.now(),\n data: {\n effectiveWidth: width,\n effectiveHeight: height,\n displayScale: 1\n }\n });\n }\n var isMouseInCanvas = false;\n function setInteractionEnabled(enabled) {\n if (enabled === domHandlersAttached) return;\n if (!canvas) return;\n if (enabled) {\n canvas.addEventListener("mousedown", handleMouseEvent, { passive: false });\n canvas.addEventListener("mousemove", handleMouseEvent, { passive: false });\n canvas.addEventListener("mouseup", handleMouseEvent, { passive: false });\n canvas.addEventListener("mouseenter", handleMouseEnter, { passive: false });\n canvas.addEventListener("mouseleave", handleMouseLeave, { passive: false });\n canvas.addEventListener("wheel", handleWheelEvent, { passive: false });\n canvas.addEventListener("touchstart", handleTouchEvent, { passive: false });\n canvas.addEventListener("touchmove", handleTouchEvent, { passive: false });\n canvas.addEventListener("touchend", handleTouchEvent, { passive: false });\n canvas.addEventListener("touchcancel", handleTouchEvent, { passive: false });\n document.addEventListener("keydown", handleKeyboardEvent, { passive: false });\n document.addEventListener("keyup", handleKeyboardEvent, { passive: false });\n canvas.addEventListener("mousedown", focusCanvas);\n canvas.addEventListener("touchstart", focusCanvas);\n domHandlersAttached = true;\n } else {\n canvas.removeEventListener("mousedown", handleMouseEvent);\n canvas.removeEventListener("mousemove", handleMouseEvent);\n canvas.removeEventListener("mouseup", handleMouseEvent);\n canvas.removeEventListener("mouseenter", handleMouseEnter);\n canvas.removeEventListener("mouseleave", handleMouseLeave);\n canvas.removeEventListener("wheel", handleWheelEvent);\n canvas.removeEventListener("touchstart", handleTouchEvent);\n canvas.removeEventListener("touchmove", handleTouchEvent);\n canvas.removeEventListener("touchend", handleTouchEvent);\n canvas.removeEventListener("touchcancel", handleTouchEvent);\n document.removeEventListener("keydown", handleKeyboardEvent);\n document.removeEventListener("keyup", handleKeyboardEvent);\n canvas.removeEventListener("mousedown", focusCanvas);\n canvas.removeEventListener("touchstart", focusCanvas);\n domHandlersAttached = false;\n }\n }\n function focusCanvas() {\n if (canvas) canvas.focus();\n }\n function dualRoute(workerType, data) {\n if (worker) {\n worker.postMessage({\n type: workerType,\n id: `${workerType}_${Date.now()}`,\n timestamp: Date.now(),\n data\n });\n }\n postToHost({\n type: "interaction-event",\n kind: workerType,\n data\n });\n }\n function handleMouseEvent(event) {\n if (!canvas) return;\n event.preventDefault();\n const rect = canvas.getBoundingClientRect();\n const x = (event.clientX - rect.left) * (canvas.width / rect.width);\n const y = (event.clientY - rect.top) * (canvas.height / rect.height);\n dualRoute("mouse-update", {\n x,\n y,\n buttons: event.buttons,\n deltaX: event.movementX || 0,\n deltaY: event.movementY || 0,\n wheelDeltaX: 0,\n wheelDeltaY: 0,\n isInCanvas: isMouseInCanvas,\n timestamp: performance.now()\n });\n }\n function handleMouseEnter(event) {\n isMouseInCanvas = true;\n handleMouseEvent(event);\n }\n function handleMouseLeave(event) {\n isMouseInCanvas = false;\n handleMouseEvent(event);\n }\n function handleWheelEvent(event) {\n if (!canvas) return;\n event.preventDefault();\n const rect = canvas.getBoundingClientRect();\n const x = (event.clientX - rect.left) * (canvas.width / rect.width);\n const y = (event.clientY - rect.top) * (canvas.height / rect.height);\n dualRoute("mouse-update", {\n x,\n y,\n buttons: event.buttons,\n deltaX: 0,\n deltaY: 0,\n wheelDeltaX: event.deltaX,\n wheelDeltaY: event.deltaY,\n isInCanvas: isMouseInCanvas,\n timestamp: performance.now()\n });\n }\n var KEY_PASSTHROUGH = /* @__PURE__ */ new Set([\n "Tab",\n "F1",\n "F2",\n "F3",\n "F4",\n "F5",\n "F11",\n "F12"\n ]);\n function handleKeyboardEvent(event) {\n if (!KEY_PASSTHROUGH.has(event.key)) {\n event.preventDefault();\n }\n dualRoute("keyboard-update", {\n type: event.type,\n key: event.key,\n code: event.code,\n keyCode: event.keyCode,\n shiftKey: event.shiftKey,\n ctrlKey: event.ctrlKey,\n altKey: event.altKey,\n metaKey: event.metaKey,\n timestamp: performance.now()\n });\n }\n function handleTouchEvent(event) {\n if (!canvas) return;\n event.preventDefault();\n const rect = canvas.getBoundingClientRect();\n const scaleX = canvas.width / rect.width;\n const scaleY = canvas.height / rect.height;\n const canvasW = canvas.width;\n const canvasH = canvas.height;\n const mapTouch = (t) => {\n const cx = (t.clientX - rect.left) * scaleX;\n const cy = (t.clientY - rect.top) * scaleY;\n return {\n identifier: t.identifier,\n clientX: cx,\n clientY: cy,\n radiusX: t.radiusX ?? 0,\n radiusY: t.radiusY ?? 0,\n rotationAngle: t.rotationAngle ?? 0,\n force: t.force ?? 0,\n isInCanvas: cx >= 0 && cx <= canvasW && cy >= 0 && cy <= canvasH\n };\n };\n const changedMap = /* @__PURE__ */ new Map();\n for (let i = 0; i < event.changedTouches.length; i++) {\n const t = event.changedTouches[i];\n changedMap.set(t.identifier, mapTouch(t));\n }\n const touches = Array.from(event.touches).map((t) => {\n return changedMap.get(t.identifier) ?? mapTouch(t);\n });\n if (event.type === "touchend" || event.type === "touchcancel") {\n const activeIds = new Set(touches.map((t) => t.identifier));\n for (const [id, mapped] of changedMap) {\n if (!activeIds.has(id)) {\n touches.push({ ...mapped, ended: true });\n }\n }\n }\n dualRoute("touch-update", {\n type: event.type,\n touches,\n timestamp: performance.now()\n });\n }\n function setSensorsEnabled(enabled) {\n if (enabled === sensorHandlersAttached) return;\n if (enabled) {\n window.addEventListener("devicemotion", handleDeviceMotion);\n window.addEventListener("deviceorientation", handleDeviceOrientation);\n sensorHandlersAttached = true;\n } else {\n window.removeEventListener("devicemotion", handleDeviceMotion);\n window.removeEventListener("deviceorientation", handleDeviceOrientation);\n sensorHandlersAttached = false;\n }\n }\n function handleDeviceMotion(event) {\n if (!event.acceleration && !event.accelerationIncludingGravity && !event.rotationRate) {\n return;\n }\n postToHost({\n type: "sensor-event",\n kind: "motion",\n data: {\n acceleration: event.acceleration ? {\n x: event.acceleration.x,\n y: event.acceleration.y,\n z: event.acceleration.z\n } : null,\n accelerationIncludingGravity: event.accelerationIncludingGravity ? {\n x: event.accelerationIncludingGravity.x,\n y: event.accelerationIncludingGravity.y,\n z: event.accelerationIncludingGravity.z\n } : null,\n rotationRate: event.rotationRate ? {\n alpha: event.rotationRate.alpha,\n beta: event.rotationRate.beta,\n gamma: event.rotationRate.gamma\n } : null,\n interval: event.interval || 16\n }\n });\n }\n function handleDeviceOrientation(event) {\n postToHost({\n type: "sensor-event",\n kind: "orientation",\n data: {\n alpha: event.alpha,\n beta: event.beta,\n gamma: event.gamma,\n absolute: event.absolute || false\n }\n });\n }\n function handleTerminate() {\n setInteractionEnabled(false);\n setSensorsEnabled(false);\n if (worker) {\n worker.terminate();\n worker = null;\n }\n if (workerBlobUrl) {\n URL.revokeObjectURL(workerBlobUrl);\n workerBlobUrl = null;\n }\n }\n installHostListener();\n announceReady().catch((err) => reportError(err));\n window.addEventListener("error", (e) => {\n reportError(e.error ?? new Error(e.message));\n });\n window.addEventListener("unhandledrejection", (e) => {\n reportError(e.reason ?? new Error("Unhandled promise rejection"));\n });\n})();\n';
|
|
10
10
|
const IFRAME_ALLOW = "accelerometer; gyroscope; magnetometer; camera; microphone";
|
|
11
11
|
const OPAQUE_ORIGIN = "null";
|
|
12
12
|
function collectTransferables(msg) {
|
|
@@ -24,6 +24,7 @@ function collectTransferables(msg) {
|
|
|
24
24
|
wasm.nosimdBinary
|
|
25
25
|
);
|
|
26
26
|
}
|
|
27
|
+
if (m.data?.controlPort) out.push(m.data.controlPort);
|
|
27
28
|
return out;
|
|
28
29
|
}
|
|
29
30
|
case "video-canvas-setup": {
|
|
@@ -68,7 +69,8 @@ function collectBootstrapTransferables(msg) {
|
|
|
68
69
|
msg.wasmFiles.simdLoaderJs,
|
|
69
70
|
msg.wasmFiles.simdBinary,
|
|
70
71
|
msg.wasmFiles.nosimdLoaderJs,
|
|
71
|
-
msg.wasmFiles.nosimdBinary
|
|
72
|
+
msg.wasmFiles.nosimdBinary,
|
|
73
|
+
msg.controlPort
|
|
72
74
|
];
|
|
73
75
|
}
|
|
74
76
|
class IFrameManager {
|
|
@@ -103,6 +105,19 @@ class IFrameManager {
|
|
|
103
105
|
hostMessageListener = null;
|
|
104
106
|
workerMessageHandlers = [];
|
|
105
107
|
vijiReadyHandlers = [];
|
|
108
|
+
/**
|
|
109
|
+
* Direct host↔worker control channel. `port1` stays on the host side and is
|
|
110
|
+
* handed to `WorkerManager` via `getControlPort1()` after `viji-ready`;
|
|
111
|
+
* `port2` is shipped to the worker through the bootstrap envelope so all
|
|
112
|
+
* steady-state host↔worker traffic can bypass the per-frame iframe relay
|
|
113
|
+
* tax. The trust boundary is unchanged — the worker still inherits the
|
|
114
|
+
* iframe's opaque origin; the port is just a faster transport.
|
|
115
|
+
*
|
|
116
|
+
* Single-owner discipline: IFrameManager owns the channel lifecycle and
|
|
117
|
+
* closes `port1` on destroy. WorkerManager only borrows the port reference
|
|
118
|
+
* for its own listener (which it detaches without closing).
|
|
119
|
+
*/
|
|
120
|
+
controlChannel = null;
|
|
106
121
|
initiallyVisible;
|
|
107
122
|
/**
|
|
108
123
|
* Enable or disable debug logging
|
|
@@ -260,6 +275,35 @@ class IFrameManager {
|
|
|
260
275
|
onVijiReady(handler) {
|
|
261
276
|
this.vijiReadyHandlers.push(handler);
|
|
262
277
|
}
|
|
278
|
+
/**
|
|
279
|
+
* Create the host↔worker control channel and return the iframe-side end
|
|
280
|
+
* (`port2`) for inclusion in the bootstrap envelope. Idempotent: a second
|
|
281
|
+
* call returns the same `port2` (the underlying channel is created once
|
|
282
|
+
* per IFrameManager lifetime).
|
|
283
|
+
*
|
|
284
|
+
* Called by `WorkerManager.createWorker` while assembling the
|
|
285
|
+
* `HostBootstrapMessage` so the port hops host → iframe → worker as a
|
|
286
|
+
* transferable. The host-side `port1` is consumed via `getControlPort1()`
|
|
287
|
+
* after `viji-ready`.
|
|
288
|
+
*/
|
|
289
|
+
createControlChannel() {
|
|
290
|
+
if (!this.controlChannel) {
|
|
291
|
+
this.controlChannel = new MessageChannel();
|
|
292
|
+
}
|
|
293
|
+
return this.controlChannel.port2;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Returns the host-side end (`port1`) of the control channel created by
|
|
297
|
+
* `createControlChannel()`. WorkerManager grabs this after `viji-ready` to
|
|
298
|
+
* route per-frame traffic directly to the worker.
|
|
299
|
+
*
|
|
300
|
+
* Returns `null` if the channel was never created (e.g. legacy bootstrap
|
|
301
|
+
* shape) or has been torn down by `destroy()`. Callers should treat null
|
|
302
|
+
* as "stay on the iframe relay path" rather than as an error.
|
|
303
|
+
*/
|
|
304
|
+
getControlPort1() {
|
|
305
|
+
return this.controlChannel?.port1 ?? null;
|
|
306
|
+
}
|
|
263
307
|
// ========================================
|
|
264
308
|
// Host-side message dispatch
|
|
265
309
|
// ========================================
|
|
@@ -425,6 +469,13 @@ class IFrameManager {
|
|
|
425
469
|
} catch {
|
|
426
470
|
}
|
|
427
471
|
}
|
|
472
|
+
if (this.controlChannel) {
|
|
473
|
+
try {
|
|
474
|
+
this.controlChannel.port1.close();
|
|
475
|
+
} catch {
|
|
476
|
+
}
|
|
477
|
+
this.controlChannel = null;
|
|
478
|
+
}
|
|
428
479
|
if (this.hostMessageListener) {
|
|
429
480
|
window.removeEventListener("message", this.hostMessageListener);
|
|
430
481
|
this.hostMessageListener = null;
|
|
@@ -487,9 +538,15 @@ class IFrameManager {
|
|
|
487
538
|
* three.js, etc.) — the iframe is at an opaque origin so the
|
|
488
539
|
* imported scripts run with `Origin: null`
|
|
489
540
|
* worker-src blob: data:
|
|
490
|
-
* - the artist worker is spawned from a `
|
|
491
|
-
*
|
|
492
|
-
*
|
|
541
|
+
* - the artist worker is spawned from a `blob:` URL minted inside
|
|
542
|
+
* the iframe (loaded as a CLASSIC worker — see the comment in
|
|
543
|
+
* inline-script.ts above the `new Worker(...)` call for why
|
|
544
|
+
* this is the only spawn shape Chromium accepts under
|
|
545
|
+
* `COEP: credentialless` for the full-size viji bundle); the
|
|
546
|
+
* cv-tasks sub-worker (MediaPipe) is spawned from a `blob:`
|
|
547
|
+
* URL minted inside the artist worker. `data:` stays in the
|
|
548
|
+
* directive because it costs nothing and keeps the door open
|
|
549
|
+
* for future small workers.
|
|
493
550
|
* connect-src * blob: data:
|
|
494
551
|
* - `*` for any CORS-friendly URL (MediaPipe model CDN, artist
|
|
495
552
|
* data, public CDNs). The `*` wildcard only matches network
|
|
@@ -583,7 +640,7 @@ class IFrameManager {
|
|
|
583
640
|
}
|
|
584
641
|
}
|
|
585
642
|
}
|
|
586
|
-
const workerUrl = "" + new URL("assets/viji.worker-
|
|
643
|
+
const workerUrl = "" + new URL("assets/viji.worker-CWKkFyOs.js", import.meta.url).href;
|
|
587
644
|
const simdLoaderJs = new URL("assets/wasm/vision_wasm_internal.js", import.meta.url).href;
|
|
588
645
|
const simdBinary = new URL("assets/wasm/vision_wasm_internal.wasm", import.meta.url).href;
|
|
589
646
|
const nosimdLoaderJs = new URL("assets/wasm/vision_wasm_nosimd_internal.js", import.meta.url).href;
|
|
@@ -600,6 +657,19 @@ class WorkerManager {
|
|
|
600
657
|
isInitialized = false;
|
|
601
658
|
/** Bound worker-message handler so we can detach on destroy. */
|
|
602
659
|
onWorkerMessageBound = null;
|
|
660
|
+
/**
|
|
661
|
+
* Host-side end of the direct host↔worker MessageChannel (created by
|
|
662
|
+
* `IFrameManager.createControlChannel()` at bootstrap time, handed to us
|
|
663
|
+
* after `viji-ready`). Once non-null, `relayHostToWorker` posts on this
|
|
664
|
+
* port instead of through the iframe relay — one cross-process hop
|
|
665
|
+
* instead of two for every per-frame message.
|
|
666
|
+
*
|
|
667
|
+
* Single-owner discipline (docs/14, rule 5): IFrameManager owns the
|
|
668
|
+
* channel lifecycle and closes `port1` on destroy. WorkerManager only
|
|
669
|
+
* detaches its `onmessage` listener.
|
|
670
|
+
*/
|
|
671
|
+
controlPort = null;
|
|
672
|
+
onControlPortMessageBound = null;
|
|
603
673
|
/**
|
|
604
674
|
* Bootstraps the worker inside the iframe.
|
|
605
675
|
*
|
|
@@ -630,6 +700,7 @@ class WorkerManager {
|
|
|
630
700
|
]);
|
|
631
701
|
this.setupMessageHandling();
|
|
632
702
|
const res = this.iframeManager.getEffectiveResolution();
|
|
703
|
+
const controlPort2 = this.iframeManager.createControlChannel();
|
|
633
704
|
const bootstrap = {
|
|
634
705
|
type: "viji-bootstrap",
|
|
635
706
|
workerCode,
|
|
@@ -639,6 +710,7 @@ class WorkerManager {
|
|
|
639
710
|
nosimdLoaderJs: nosimdLoaderJs$1,
|
|
640
711
|
nosimdBinary: nosimdBinary$1
|
|
641
712
|
},
|
|
713
|
+
controlPort: controlPort2,
|
|
642
714
|
init: {
|
|
643
715
|
canvasWidth: res.width,
|
|
644
716
|
canvasHeight: res.height,
|
|
@@ -669,6 +741,14 @@ class WorkerManager {
|
|
|
669
741
|
collectBootstrapTransferables(bootstrap)
|
|
670
742
|
);
|
|
671
743
|
await vijiReady;
|
|
744
|
+
this.controlPort = this.iframeManager.getControlPort1();
|
|
745
|
+
if (this.controlPort && this.onWorkerMessageBound) {
|
|
746
|
+
const dispatcher = this.onWorkerMessageBound;
|
|
747
|
+
this.onControlPortMessageBound = (evt) => {
|
|
748
|
+
dispatcher(evt.data);
|
|
749
|
+
};
|
|
750
|
+
this.controlPort.onmessage = this.onControlPortMessageBound;
|
|
751
|
+
}
|
|
672
752
|
this.postMessage("set-scene-code", { sceneCode: this.sceneCode });
|
|
673
753
|
this.isInitialized = true;
|
|
674
754
|
} catch (error) {
|
|
@@ -720,8 +800,17 @@ class WorkerManager {
|
|
|
720
800
|
this.relayHostToWorker(message);
|
|
721
801
|
}
|
|
722
802
|
/**
|
|
723
|
-
* Sends a host-to-worker message
|
|
724
|
-
*
|
|
803
|
+
* Sends a host-to-worker message. Once the direct control channel is
|
|
804
|
+
* wired (after `viji-ready`), per-message traffic flows on `port1`
|
|
805
|
+
* directly to the worker — bypassing the iframe relay's per-frame cost.
|
|
806
|
+
* During the bootstrap window (before `viji-ready` fires) and any
|
|
807
|
+
* post-teardown call we fall back to the iframe relay path so init-time
|
|
808
|
+
* messages still reach the worker.
|
|
809
|
+
*
|
|
810
|
+
* Transferables are harvested via the centralized `collectTransferables`
|
|
811
|
+
* helper either way, and the `transferList` shim added by parameter
|
|
812
|
+
* messages is stripped before send (the worker has no use for it once
|
|
813
|
+
* the actual handles have been transferred).
|
|
725
814
|
*/
|
|
726
815
|
relayHostToWorker(message) {
|
|
727
816
|
if (!this.iframeManager.ready && !this.isInitialized) {
|
|
@@ -733,6 +822,10 @@ class WorkerManager {
|
|
|
733
822
|
try {
|
|
734
823
|
const transfer = collectTransferables(message);
|
|
735
824
|
const sanitized = stripTransferList(message);
|
|
825
|
+
if (this.controlPort) {
|
|
826
|
+
this.controlPort.postMessage(sanitized, transfer);
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
736
829
|
this.iframeManager.postEnvelope(
|
|
737
830
|
{ type: "viji-host-message", payload: sanitized },
|
|
738
831
|
transfer
|
|
@@ -773,6 +866,11 @@ class WorkerManager {
|
|
|
773
866
|
this.iframeManager.offWorkerMessage(this.onWorkerMessageBound);
|
|
774
867
|
this.onWorkerMessageBound = null;
|
|
775
868
|
}
|
|
869
|
+
if (this.controlPort && this.onControlPortMessageBound) {
|
|
870
|
+
this.controlPort.onmessage = null;
|
|
871
|
+
this.onControlPortMessageBound = null;
|
|
872
|
+
}
|
|
873
|
+
this.controlPort = null;
|
|
776
874
|
this.isInitialized = false;
|
|
777
875
|
} catch (error) {
|
|
778
876
|
console.warn("Error during worker cleanup:", error);
|
|
@@ -1799,7 +1897,7 @@ class EssentiaOnsetDetection {
|
|
|
1799
1897
|
this.initPromise = (async () => {
|
|
1800
1898
|
try {
|
|
1801
1899
|
const essentiaModule = await import("./essentia.js-core.es-DnrJE0uR.js");
|
|
1802
|
-
const wasmModule = await import("./essentia-wasm.web-
|
|
1900
|
+
const wasmModule = await import("./essentia-wasm.web-CmPC-AKu.js").then((n) => n.e);
|
|
1803
1901
|
const EssentiaClass = essentiaModule.Essentia || essentiaModule.default?.Essentia || essentiaModule.default;
|
|
1804
1902
|
let WASMModule = wasmModule.default || wasmModule.EssentiaWASM || wasmModule.default?.EssentiaWASM;
|
|
1805
1903
|
if (!WASMModule) {
|
|
@@ -10595,7 +10693,7 @@ class VijiCore {
|
|
|
10595
10693
|
}
|
|
10596
10694
|
}
|
|
10597
10695
|
}
|
|
10598
|
-
const VERSION = "0.
|
|
10696
|
+
const VERSION = "0.5.0";
|
|
10599
10697
|
export {
|
|
10600
10698
|
AudioSystem as A,
|
|
10601
10699
|
VERSION as V,
|
|
@@ -10603,4 +10701,4 @@ export {
|
|
|
10603
10701
|
VijiCoreError as b,
|
|
10604
10702
|
getDefaultExportFromCjs as g
|
|
10605
10703
|
};
|
|
10606
|
-
//# sourceMappingURL=index-
|
|
10704
|
+
//# sourceMappingURL=index-Cp9G0z4E.js.map
|