@viji-dev/core 0.5.2 → 0.5.3
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 +1 -1
- package/dist/artist-global.d.ts +1 -1
- package/dist/docs-api.js +16 -16
- package/dist/{essentia-wasm.web-DE6gem4m.js → essentia-wasm.web-CPrFAj59.js} +2 -2
- package/dist/{essentia-wasm.web-DE6gem4m.js.map → essentia-wasm.web-CPrFAj59.js.map} +1 -1
- package/dist/{index-B8LJ9m47.js → index-Bhq4eJe_.js} +66 -46
- package/dist/{index-B8LJ9m47.js.map → index-Bhq4eJe_.js.map} +1 -1
- package/dist/index.d.ts +36 -16
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/docs-api.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const docsApi = {
|
|
2
2
|
"version": "1.1.0",
|
|
3
|
-
"coreVersion": "0.5.
|
|
4
|
-
"generatedAt": "2026-05-
|
|
3
|
+
"coreVersion": "0.5.3",
|
|
4
|
+
"generatedAt": "2026-05-07T10:18:06.592Z",
|
|
5
5
|
"navigation": [
|
|
6
6
|
{
|
|
7
7
|
"id": "getting-started",
|
|
@@ -3025,7 +3025,7 @@ export const docsApi = {
|
|
|
3025
3025
|
{
|
|
3026
3026
|
"type": "live-example",
|
|
3027
3027
|
"title": "Video with Face Detection",
|
|
3028
|
-
"sceneCode": "const useFace = viji.toggle(false, { label: 'Face Detection', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n const w = viji.width;\n const h = viji.height;\n\n ctx.fillStyle = '#111';\n ctx.fillRect(0, 0, w, h);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n ctx.fillStyle = '#555';\n ctx.font = `${Math.min(w, h) * 0.04}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.fillText('Waiting for video...', w / 2, h / 2);\n return;\n }\n\n if (useFace.value) viji.video.cv.enableFaceDetection(true);\n else viji.video.cv.enableFaceDetection(false);\n\n const v = videoFit(viji, 'contain');\n ctx.globalAlpha = 0.6;\n ctx.drawImage(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n ctx.globalAlpha = 1.0;\n\n viji.video.cv.faces.forEach(face => {\n const bx = v.x + face.bounds.x * v.width;\n const by = v.y + face.bounds.y * v.height;\n const bw = face.bounds.width * v.width;\n const bh = face.bounds.height * v.height;\n\n ctx.strokeStyle = '#4ecdc4';\n ctx.lineWidth = 2;\n ctx.strokeRect(bx, by, bw, bh);\n\n ctx.fillStyle = '#4ecdc4';\n ctx.font = `${Math.min(w, h) * 0.03}px sans-serif`;\n ctx.textAlign = 'left';\n ctx.fillText('Face #' + face.id + ' (' + (face.confidence * 100).toFixed(0) + '%)', bx, by - 6);\n });\n}\n",
|
|
3028
|
+
"sceneCode": "const useFace = viji.toggle(false, { label: 'Face Detection', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction cvHint(ctx, viji, label) {\n const s = Math.min(viji.width, viji.height);\n const t = (Math.sin(viji.time * 3) + 1) / 2;\n const bandH = s * 0.18;\n const bandY = (viji.height - bandH) / 2;\n ctx.fillStyle = `rgba(255, 200, 0, ${0.85 + t * 0.15})`;\n ctx.fillRect(0, bandY, viji.width, bandH);\n ctx.fillStyle = '#111';\n ctx.font = `bold ${s * 0.045}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(`Enable \"${label}\" in parameters`, viji.width / 2, viji.height / 2);\n ctx.textBaseline = 'alphabetic';\n}\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n const w = viji.width;\n const h = viji.height;\n\n ctx.fillStyle = '#111';\n ctx.fillRect(0, 0, w, h);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n ctx.fillStyle = '#555';\n ctx.font = `${Math.min(w, h) * 0.04}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.fillText('Waiting for video...', w / 2, h / 2);\n return;\n }\n\n if (useFace.value) viji.video.cv.enableFaceDetection(true);\n else viji.video.cv.enableFaceDetection(false);\n\n const v = videoFit(viji, 'contain');\n ctx.globalAlpha = 0.6;\n ctx.drawImage(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n ctx.globalAlpha = 1.0;\n\n if (!useFace.value) {\n cvHint(ctx, viji, 'Face Detection');\n return;\n }\n\n viji.video.cv.faces.forEach(face => {\n const bx = v.x + face.bounds.x * v.width;\n const by = v.y + face.bounds.y * v.height;\n const bw = face.bounds.width * v.width;\n const bh = face.bounds.height * v.height;\n\n ctx.strokeStyle = '#4ecdc4';\n ctx.lineWidth = 2;\n ctx.strokeRect(bx, by, bw, bh);\n\n ctx.fillStyle = '#4ecdc4';\n ctx.font = `${Math.min(w, h) * 0.03}px sans-serif`;\n ctx.textAlign = 'left';\n ctx.fillText('Face #' + face.id + ' (' + (face.confidence * 100).toFixed(0) + '%)', bx, by - 6);\n });\n}\n",
|
|
3029
3029
|
"sceneFile": "video-overview.scene.js",
|
|
3030
3030
|
"capabilities": {
|
|
3031
3031
|
"video": true
|
|
@@ -3198,7 +3198,7 @@ export const docsApi = {
|
|
|
3198
3198
|
{
|
|
3199
3199
|
"type": "live-example",
|
|
3200
3200
|
"title": "Face Detection",
|
|
3201
|
-
"sceneCode": "const useFace = viji.toggle(false, { label: 'Face Detection', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n const w = viji.width;\n const h = viji.height;\n\n ctx.fillStyle = '#111';\n ctx.fillRect(0, 0, w, h);\n\n if (useFace.value) viji.video.cv.enableFaceDetection(true);\n else viji.video.cv.enableFaceDetection(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n ctx.fillStyle = '#555';\n ctx.font = `${Math.min(w, h) * 0.04}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.fillText('Waiting for video...', w / 2, h / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n ctx.drawImage(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n\n viji.video.cv.faces.forEach(face => {\n const bx = v.x + face.bounds.x * v.width;\n const by = v.y + face.bounds.y * v.height;\n const bw = face.bounds.width * v.width;\n const bh = face.bounds.height * v.height;\n\n ctx.strokeStyle = '#4ecdc4';\n ctx.lineWidth = 2;\n ctx.strokeRect(bx, by, bw, bh);\n\n ctx.fillStyle = '#4ecdc4';\n ctx.beginPath();\n ctx.arc(v.x + face.center.x * v.width, v.y + face.center.y * v.height, 4, 0, Math.PI * 2);\n ctx.fill();\n\n ctx.font = `${Math.min(w, h) * 0.025}px sans-serif`;\n ctx.textAlign = 'left';\n ctx.fillText('Face #' + face.id + ' (' + (face.confidence * 100).toFixed(0) + '%)', bx, by - 6);\n });\n}\n",
|
|
3201
|
+
"sceneCode": "const useFace = viji.toggle(false, { label: 'Face Detection', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction cvHint(ctx, viji, label) {\n const s = Math.min(viji.width, viji.height);\n const t = (Math.sin(viji.time * 3) + 1) / 2;\n const bandH = s * 0.18;\n const bandY = (viji.height - bandH) / 2;\n ctx.fillStyle = `rgba(255, 200, 0, ${0.85 + t * 0.15})`;\n ctx.fillRect(0, bandY, viji.width, bandH);\n ctx.fillStyle = '#111';\n ctx.font = `bold ${s * 0.045}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(`Enable \"${label}\" in parameters`, viji.width / 2, viji.height / 2);\n ctx.textBaseline = 'alphabetic';\n}\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n const w = viji.width;\n const h = viji.height;\n\n ctx.fillStyle = '#111';\n ctx.fillRect(0, 0, w, h);\n\n if (useFace.value) viji.video.cv.enableFaceDetection(true);\n else viji.video.cv.enableFaceDetection(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n ctx.fillStyle = '#555';\n ctx.font = `${Math.min(w, h) * 0.04}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.fillText('Waiting for video...', w / 2, h / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n ctx.drawImage(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n\n if (!useFace.value) {\n cvHint(ctx, viji, 'Face Detection');\n return;\n }\n\n viji.video.cv.faces.forEach(face => {\n const bx = v.x + face.bounds.x * v.width;\n const by = v.y + face.bounds.y * v.height;\n const bw = face.bounds.width * v.width;\n const bh = face.bounds.height * v.height;\n\n ctx.strokeStyle = '#4ecdc4';\n ctx.lineWidth = 2;\n ctx.strokeRect(bx, by, bw, bh);\n\n ctx.fillStyle = '#4ecdc4';\n ctx.beginPath();\n ctx.arc(v.x + face.center.x * v.width, v.y + face.center.y * v.height, 4, 0, Math.PI * 2);\n ctx.fill();\n\n ctx.font = `${Math.min(w, h) * 0.025}px sans-serif`;\n ctx.textAlign = 'left';\n ctx.fillText('Face #' + face.id + ' (' + (face.confidence * 100).toFixed(0) + '%)', bx, by - 6);\n });\n}\n",
|
|
3202
3202
|
"sceneFile": "face-detection-demo.scene.js",
|
|
3203
3203
|
"capabilities": {
|
|
3204
3204
|
"video": true
|
|
@@ -3254,7 +3254,7 @@ export const docsApi = {
|
|
|
3254
3254
|
{
|
|
3255
3255
|
"type": "live-example",
|
|
3256
3256
|
"title": "Face Mesh",
|
|
3257
|
-
"sceneCode": "const useMesh = viji.toggle(false, { label: 'Face Mesh', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n const w = viji.width;\n const h = viji.height;\n\n ctx.fillStyle = '#111';\n ctx.fillRect(0, 0, w, h);\n\n if (useMesh.value) viji.video.cv.enableFaceMesh(true);\n else viji.video.cv.enableFaceMesh(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n ctx.fillStyle = '#555';\n ctx.font = `${Math.min(w, h) * 0.04}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.fillText('Waiting for video...', w / 2, h / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n ctx.globalAlpha = 0.4;\n ctx.drawImage(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n ctx.globalAlpha = 1.0;\n\n viji.video.cv.faces.forEach(face => {\n if (face.landmarks.length === 0) return;\n\n ctx.fillStyle = 'rgba(69, 183, 209, 0.7)';\n face.landmarks.forEach(pt => {\n ctx.beginPath();\n ctx.arc(v.x + pt.x * v.width, v.y + pt.y * v.height, 1, 0, Math.PI * 2);\n ctx.fill();\n });\n\n const fontSize = Math.min(w, h) * 0.025;\n ctx.fillStyle = '#fff';\n ctx.font = `${fontSize}px sans-serif`;\n ctx.textAlign = 'left';\n const hp = face.headPose;\n ctx.fillText(\n face.landmarks.length + ' landmarks | Pitch: ' + hp.pitch.toFixed(1) +\n ' Yaw: ' + hp.yaw.toFixed(1) + ' Roll: ' + hp.roll.toFixed(1),\n w * 0.03, h - fontSize * 0.8\n );\n });\n}\n",
|
|
3257
|
+
"sceneCode": "const useMesh = viji.toggle(false, { label: 'Face Mesh', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction cvHint(ctx, viji, label) {\n const s = Math.min(viji.width, viji.height);\n const t = (Math.sin(viji.time * 3) + 1) / 2;\n const bandH = s * 0.18;\n const bandY = (viji.height - bandH) / 2;\n ctx.fillStyle = `rgba(255, 200, 0, ${0.85 + t * 0.15})`;\n ctx.fillRect(0, bandY, viji.width, bandH);\n ctx.fillStyle = '#111';\n ctx.font = `bold ${s * 0.045}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(`Enable \"${label}\" in parameters`, viji.width / 2, viji.height / 2);\n ctx.textBaseline = 'alphabetic';\n}\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n const w = viji.width;\n const h = viji.height;\n\n ctx.fillStyle = '#111';\n ctx.fillRect(0, 0, w, h);\n\n if (useMesh.value) viji.video.cv.enableFaceMesh(true);\n else viji.video.cv.enableFaceMesh(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n ctx.fillStyle = '#555';\n ctx.font = `${Math.min(w, h) * 0.04}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.fillText('Waiting for video...', w / 2, h / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n ctx.globalAlpha = 0.4;\n ctx.drawImage(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n ctx.globalAlpha = 1.0;\n\n if (!useMesh.value) {\n cvHint(ctx, viji, 'Face Mesh');\n return;\n }\n\n viji.video.cv.faces.forEach(face => {\n if (face.landmarks.length === 0) return;\n\n ctx.fillStyle = 'rgba(69, 183, 209, 0.7)';\n face.landmarks.forEach(pt => {\n ctx.beginPath();\n ctx.arc(v.x + pt.x * v.width, v.y + pt.y * v.height, 1, 0, Math.PI * 2);\n ctx.fill();\n });\n\n const fontSize = Math.min(w, h) * 0.025;\n ctx.fillStyle = '#fff';\n ctx.font = `${fontSize}px sans-serif`;\n ctx.textAlign = 'left';\n const hp = face.headPose;\n ctx.fillText(\n face.landmarks.length + ' landmarks | Pitch: ' + hp.pitch.toFixed(1) +\n ' Yaw: ' + hp.yaw.toFixed(1) + ' Roll: ' + hp.roll.toFixed(1),\n w * 0.03, h - fontSize * 0.8\n );\n });\n}\n",
|
|
3258
3258
|
"sceneFile": "face-mesh-demo.scene.js",
|
|
3259
3259
|
"capabilities": {
|
|
3260
3260
|
"video": true
|
|
@@ -3305,7 +3305,7 @@ export const docsApi = {
|
|
|
3305
3305
|
{
|
|
3306
3306
|
"type": "live-example",
|
|
3307
3307
|
"title": "Emotion Detection",
|
|
3308
|
-
"sceneCode": "const useEmotion = viji.toggle(false, { label: 'Emotion Detection', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n const w = viji.width;\n const h = viji.height;\n\n ctx.fillStyle = '#111';\n ctx.fillRect(0, 0, w, h);\n\n if (useEmotion.value) {\n viji.video.cv.enableEmotionDetection(true);\n } else {\n viji.video.cv.enableEmotionDetection(false);\n }\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n ctx.fillStyle = '#555';\n ctx.font = `${Math.min(w, h) * 0.04}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.fillText('Waiting for video...', w / 2, h / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n ctx.globalAlpha = 0.4;\n ctx.drawImage(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n ctx.globalAlpha = 1.0;\n\n const face = viji.video.cv.faces[0];\n if (!face) return;\n\n const expr = face.expressions;\n const labels = ['neutral', 'happy', 'sad', 'angry', 'surprised', 'disgusted', 'fearful'];\n const values = [expr.neutral, expr.happy, expr.sad, expr.angry, expr.surprised, expr.disgusted, expr.fearful];\n const colors = ['#888', '#4CAF50', '#2196F3', '#f44336', '#FF9800', '#9C27B0', '#607D8B'];\n\n const barH = h * 0.04;\n const barW = w * 0.3;\n const x = w * 0.65;\n let y = h * 0.12;\n const fontSize = barH * 0.7;\n\n ctx.font = `${fontSize}px sans-serif`;\n labels.forEach((label, i) => {\n ctx.fillStyle = '#aaa';\n ctx.textAlign = 'right';\n ctx.fillText(label, x - 8, y + barH * 0.75);\n\n ctx.fillStyle = '#222';\n ctx.fillRect(x, y, barW, barH);\n\n ctx.fillStyle = colors[i];\n ctx.fillRect(x, y, barW * values[i], barH);\n\n ctx.fillStyle = '#ddd';\n ctx.textAlign = 'left';\n ctx.fillText((values[i] * 100).toFixed(0) + '%', x + barW + 6, y + barH * 0.75);\n\n y += barH * 1.8;\n });\n}\n",
|
|
3308
|
+
"sceneCode": "const useEmotion = viji.toggle(false, { label: 'Emotion Detection', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction cvHint(ctx, viji, label) {\n const s = Math.min(viji.width, viji.height);\n const t = (Math.sin(viji.time * 3) + 1) / 2;\n const bandH = s * 0.18;\n const bandY = (viji.height - bandH) / 2;\n ctx.fillStyle = `rgba(255, 200, 0, ${0.85 + t * 0.15})`;\n ctx.fillRect(0, bandY, viji.width, bandH);\n ctx.fillStyle = '#111';\n ctx.font = `bold ${s * 0.045}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(`Enable \"${label}\" in parameters`, viji.width / 2, viji.height / 2);\n ctx.textBaseline = 'alphabetic';\n}\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n const w = viji.width;\n const h = viji.height;\n\n ctx.fillStyle = '#111';\n ctx.fillRect(0, 0, w, h);\n\n if (useEmotion.value) {\n viji.video.cv.enableEmotionDetection(true);\n } else {\n viji.video.cv.enableEmotionDetection(false);\n }\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n ctx.fillStyle = '#555';\n ctx.font = `${Math.min(w, h) * 0.04}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.fillText('Waiting for video...', w / 2, h / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n ctx.globalAlpha = 0.4;\n ctx.drawImage(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n ctx.globalAlpha = 1.0;\n\n if (!useEmotion.value) {\n cvHint(ctx, viji, 'Emotion Detection');\n return;\n }\n\n const face = viji.video.cv.faces[0];\n if (!face) return;\n\n const expr = face.expressions;\n const labels = ['neutral', 'happy', 'sad', 'angry', 'surprised', 'disgusted', 'fearful'];\n const values = [expr.neutral, expr.happy, expr.sad, expr.angry, expr.surprised, expr.disgusted, expr.fearful];\n const colors = ['#888', '#4CAF50', '#2196F3', '#f44336', '#FF9800', '#9C27B0', '#607D8B'];\n\n const barH = h * 0.04;\n const barW = w * 0.3;\n const x = w * 0.65;\n let y = h * 0.12;\n const fontSize = barH * 0.7;\n\n ctx.font = `${fontSize}px sans-serif`;\n labels.forEach((label, i) => {\n ctx.fillStyle = '#aaa';\n ctx.textAlign = 'right';\n ctx.fillText(label, x - 8, y + barH * 0.75);\n\n ctx.fillStyle = '#222';\n ctx.fillRect(x, y, barW, barH);\n\n ctx.fillStyle = colors[i];\n ctx.fillRect(x, y, barW * values[i], barH);\n\n ctx.fillStyle = '#ddd';\n ctx.textAlign = 'left';\n ctx.fillText((values[i] * 100).toFixed(0) + '%', x + barW + 6, y + barH * 0.75);\n\n y += barH * 1.8;\n });\n}\n",
|
|
3309
3309
|
"sceneFile": "emotion-detection-demo.scene.js",
|
|
3310
3310
|
"capabilities": {
|
|
3311
3311
|
"video": true
|
|
@@ -3351,7 +3351,7 @@ export const docsApi = {
|
|
|
3351
3351
|
{
|
|
3352
3352
|
"type": "live-example",
|
|
3353
3353
|
"title": "Hand Tracking",
|
|
3354
|
-
"sceneCode": "const useHands = viji.toggle(false, { label: 'Hand Tracking', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n const w = viji.width;\n const h = viji.height;\n\n ctx.fillStyle = '#111';\n ctx.fillRect(0, 0, w, h);\n\n if (useHands.value) viji.video.cv.enableHandTracking(true);\n else viji.video.cv.enableHandTracking(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n ctx.fillStyle = '#555';\n ctx.font = `${Math.min(w, h) * 0.04}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.fillText('Waiting for video...', w / 2, h / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n ctx.globalAlpha = 0.4;\n ctx.drawImage(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n ctx.globalAlpha = 1.0;\n\n viji.video.cv.hands.forEach(hand => {\n const color = hand.handedness === 'left' ? '#ff9ff3' : '#54a0ff';\n\n ctx.fillStyle = color;\n hand.landmarks.forEach(pt => {\n ctx.beginPath();\n ctx.arc(v.x + pt.x * v.width, v.y + pt.y * v.height, 3, 0, Math.PI * 2);\n ctx.fill();\n });\n\n ctx.beginPath();\n ctx.arc(v.x + hand.palm.x * v.width, v.y + hand.palm.y * v.height, 8, 0, Math.PI * 2);\n ctx.strokeStyle = color;\n ctx.lineWidth = 2;\n ctx.stroke();\n\n const g = hand.gestures;\n const names = ['fist', 'openPalm', 'peace', 'thumbsUp', 'thumbsDown', 'pointing', 'iLoveYou'];\n const vals = [g.fist, g.openPalm, g.peace, g.thumbsUp, g.thumbsDown, g.pointing, g.iLoveYou];\n\n const barW = w * 0.12;\n const barH = h * 0.02;\n let bx = v.x + hand.bounds.x * v.width;\n let by = v.y + (hand.bounds.y + hand.bounds.height) * v.height + 8;\n const fontSize = barH * 0.9;\n ctx.font = `${fontSize}px sans-serif`;\n\n names.forEach((name, i) => {\n ctx.fillStyle = '#aaa';\n ctx.textAlign = 'right';\n ctx.fillText(name, bx + barW * 0.6 - 4, by + barH * 0.85);\n\n ctx.fillStyle = '#333';\n ctx.fillRect(bx + barW * 0.6, by, barW * 0.4, barH);\n ctx.fillStyle = color;\n ctx.fillRect(bx + barW * 0.6, by, barW * 0.4 * vals[i], barH);\n\n by += barH * 1.5;\n });\n });\n}\n",
|
|
3354
|
+
"sceneCode": "const useHands = viji.toggle(false, { label: 'Hand Tracking', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction cvHint(ctx, viji, label) {\n const s = Math.min(viji.width, viji.height);\n const t = (Math.sin(viji.time * 3) + 1) / 2;\n const bandH = s * 0.18;\n const bandY = (viji.height - bandH) / 2;\n ctx.fillStyle = `rgba(255, 200, 0, ${0.85 + t * 0.15})`;\n ctx.fillRect(0, bandY, viji.width, bandH);\n ctx.fillStyle = '#111';\n ctx.font = `bold ${s * 0.045}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(`Enable \"${label}\" in parameters`, viji.width / 2, viji.height / 2);\n ctx.textBaseline = 'alphabetic';\n}\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n const w = viji.width;\n const h = viji.height;\n\n ctx.fillStyle = '#111';\n ctx.fillRect(0, 0, w, h);\n\n if (useHands.value) viji.video.cv.enableHandTracking(true);\n else viji.video.cv.enableHandTracking(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n ctx.fillStyle = '#555';\n ctx.font = `${Math.min(w, h) * 0.04}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.fillText('Waiting for video...', w / 2, h / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n ctx.globalAlpha = 0.4;\n ctx.drawImage(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n ctx.globalAlpha = 1.0;\n\n if (!useHands.value) {\n cvHint(ctx, viji, 'Hand Tracking');\n return;\n }\n\n viji.video.cv.hands.forEach(hand => {\n const color = hand.handedness === 'left' ? '#ff9ff3' : '#54a0ff';\n\n ctx.fillStyle = color;\n hand.landmarks.forEach(pt => {\n ctx.beginPath();\n ctx.arc(v.x + pt.x * v.width, v.y + pt.y * v.height, 3, 0, Math.PI * 2);\n ctx.fill();\n });\n\n ctx.beginPath();\n ctx.arc(v.x + hand.palm.x * v.width, v.y + hand.palm.y * v.height, 8, 0, Math.PI * 2);\n ctx.strokeStyle = color;\n ctx.lineWidth = 2;\n ctx.stroke();\n\n const g = hand.gestures;\n const names = ['fist', 'openPalm', 'peace', 'thumbsUp', 'thumbsDown', 'pointing', 'iLoveYou'];\n const vals = [g.fist, g.openPalm, g.peace, g.thumbsUp, g.thumbsDown, g.pointing, g.iLoveYou];\n\n const barW = w * 0.12;\n const barH = h * 0.02;\n let bx = v.x + hand.bounds.x * v.width;\n let by = v.y + (hand.bounds.y + hand.bounds.height) * v.height + 8;\n const fontSize = barH * 0.9;\n ctx.font = `${fontSize}px sans-serif`;\n\n names.forEach((name, i) => {\n ctx.fillStyle = '#aaa';\n ctx.textAlign = 'right';\n ctx.fillText(name, bx + barW * 0.6 - 4, by + barH * 0.85);\n\n ctx.fillStyle = '#333';\n ctx.fillRect(bx + barW * 0.6, by, barW * 0.4, barH);\n ctx.fillStyle = color;\n ctx.fillRect(bx + barW * 0.6, by, barW * 0.4 * vals[i], barH);\n\n by += barH * 1.5;\n });\n });\n}\n",
|
|
3355
3355
|
"sceneFile": "hand-tracking-demo.scene.js",
|
|
3356
3356
|
"capabilities": {
|
|
3357
3357
|
"video": true
|
|
@@ -3397,7 +3397,7 @@ export const docsApi = {
|
|
|
3397
3397
|
{
|
|
3398
3398
|
"type": "live-example",
|
|
3399
3399
|
"title": "Pose Detection",
|
|
3400
|
-
"sceneCode": "const usePose = viji.toggle(false, { label: 'Pose Detection', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n const w = viji.width;\n const h = viji.height;\n\n ctx.fillStyle = '#111';\n ctx.fillRect(0, 0, w, h);\n\n if (usePose.value) viji.video.cv.enablePoseDetection(true);\n else viji.video.cv.enablePoseDetection(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n ctx.fillStyle = '#555';\n ctx.font = `${Math.min(w, h) * 0.04}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.fillText('Waiting for video...', w / 2, h / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n ctx.globalAlpha = 0.4;\n ctx.drawImage(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n ctx.globalAlpha = 1.0;\n\n const pose = viji.video.cv.pose;\n if (!pose) return;\n\n ctx.fillStyle = '#ff6b6b';\n pose.landmarks.forEach(pt => {\n if (pt.visibility > 0.5) {\n ctx.beginPath();\n ctx.arc(v.x + pt.x * v.width, v.y + pt.y * v.height, 4, 0, Math.PI * 2);\n ctx.fill();\n }\n });\n\n ctx.strokeStyle = '#ff6b6b';\n ctx.lineWidth = 2;\n const drawGroup = (group) => {\n if (group.length < 2) return;\n ctx.beginPath();\n ctx.moveTo(v.x + group[0].x * v.width, v.y + group[0].y * v.height);\n for (let i = 1; i < group.length; i++) {\n ctx.lineTo(v.x + group[i].x * v.width, v.y + group[i].y * v.height);\n }\n ctx.stroke();\n };\n\n ctx.strokeStyle = '#ff9ff3';\n drawGroup(pose.leftArm);\n ctx.strokeStyle = '#54a0ff';\n drawGroup(pose.rightArm);\n ctx.strokeStyle = '#ff9ff3';\n drawGroup(pose.leftLeg);\n ctx.strokeStyle = '#54a0ff';\n drawGroup(pose.rightLeg);\n ctx.strokeStyle = '#feca57';\n drawGroup(pose.torso);\n\n ctx.fillStyle = '#fff';\n ctx.font = `${Math.min(w, h) * 0.025}px sans-serif`;\n ctx.textAlign = 'left';\n ctx.fillText('Confidence: ' + (pose.confidence * 100).toFixed(0) + '%', w * 0.03, h - Math.min(w, h) * 0.03);\n}\n",
|
|
3400
|
+
"sceneCode": "const usePose = viji.toggle(false, { label: 'Pose Detection', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction cvHint(ctx, viji, label) {\n const s = Math.min(viji.width, viji.height);\n const t = (Math.sin(viji.time * 3) + 1) / 2;\n const bandH = s * 0.18;\n const bandY = (viji.height - bandH) / 2;\n ctx.fillStyle = `rgba(255, 200, 0, ${0.85 + t * 0.15})`;\n ctx.fillRect(0, bandY, viji.width, bandH);\n ctx.fillStyle = '#111';\n ctx.font = `bold ${s * 0.045}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(`Enable \"${label}\" in parameters`, viji.width / 2, viji.height / 2);\n ctx.textBaseline = 'alphabetic';\n}\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n const w = viji.width;\n const h = viji.height;\n\n ctx.fillStyle = '#111';\n ctx.fillRect(0, 0, w, h);\n\n if (usePose.value) viji.video.cv.enablePoseDetection(true);\n else viji.video.cv.enablePoseDetection(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n ctx.fillStyle = '#555';\n ctx.font = `${Math.min(w, h) * 0.04}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.fillText('Waiting for video...', w / 2, h / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n ctx.globalAlpha = 0.4;\n ctx.drawImage(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n ctx.globalAlpha = 1.0;\n\n if (!usePose.value) {\n cvHint(ctx, viji, 'Pose Detection');\n return;\n }\n\n const pose = viji.video.cv.pose;\n if (!pose) return;\n\n ctx.fillStyle = '#ff6b6b';\n pose.landmarks.forEach(pt => {\n if (pt.visibility > 0.5) {\n ctx.beginPath();\n ctx.arc(v.x + pt.x * v.width, v.y + pt.y * v.height, 4, 0, Math.PI * 2);\n ctx.fill();\n }\n });\n\n ctx.strokeStyle = '#ff6b6b';\n ctx.lineWidth = 2;\n const drawGroup = (group) => {\n if (group.length < 2) return;\n ctx.beginPath();\n ctx.moveTo(v.x + group[0].x * v.width, v.y + group[0].y * v.height);\n for (let i = 1; i < group.length; i++) {\n ctx.lineTo(v.x + group[i].x * v.width, v.y + group[i].y * v.height);\n }\n ctx.stroke();\n };\n\n ctx.strokeStyle = '#ff9ff3';\n drawGroup(pose.leftArm);\n ctx.strokeStyle = '#54a0ff';\n drawGroup(pose.rightArm);\n ctx.strokeStyle = '#ff9ff3';\n drawGroup(pose.leftLeg);\n ctx.strokeStyle = '#54a0ff';\n drawGroup(pose.rightLeg);\n ctx.strokeStyle = '#feca57';\n drawGroup(pose.torso);\n\n ctx.fillStyle = '#fff';\n ctx.font = `${Math.min(w, h) * 0.025}px sans-serif`;\n ctx.textAlign = 'left';\n ctx.fillText('Confidence: ' + (pose.confidence * 100).toFixed(0) + '%', w * 0.03, h - Math.min(w, h) * 0.03);\n}\n",
|
|
3401
3401
|
"sceneFile": "pose-detection-demo.scene.js",
|
|
3402
3402
|
"capabilities": {
|
|
3403
3403
|
"video": true
|
|
@@ -3448,7 +3448,7 @@ export const docsApi = {
|
|
|
3448
3448
|
{
|
|
3449
3449
|
"type": "live-example",
|
|
3450
3450
|
"title": "Body Segmentation",
|
|
3451
|
-
"sceneCode": "const useSeg = viji.toggle(false, { label: 'Body Segmentation', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n const w = viji.width;\n const h = viji.height;\n\n ctx.fillStyle = '#111';\n ctx.fillRect(0, 0, w, h);\n\n if (useSeg.value) viji.video.cv.enableBodySegmentation(true);\n else viji.video.cv.enableBodySegmentation(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n ctx.fillStyle = '#555';\n ctx.font = `${Math.min(w, h) * 0.04}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.fillText('Waiting for video...', w / 2, h / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n const frameToShow = viji.video.cv.analysedFrame ?? viji.video.currentFrame;\n ctx.drawImage(frameToShow, v.x, v.y, v.width, v.height);\n\n const seg = viji.video.cv.segmentation;\n if (!seg) return;\n\n let personPixels = 0;\n for (let i = 0; i < seg.mask.length; i++) {\n if (seg.mask[i] > 0) personPixels++;\n }\n const personRatio = personPixels / seg.mask.length;\n\n if (personRatio > 0.05) {\n ctx.shadowBlur = 30 * personRatio;\n ctx.shadowColor = `hsl(${170 + personRatio * 60}, 80%, 60%)`;\n ctx.strokeStyle = `hsla(${170 + personRatio * 60}, 80%, 60%, 0.6)`;\n ctx.lineWidth = 4;\n ctx.strokeRect(v.x, v.y, v.width, v.height);\n ctx.shadowBlur = 0;\n }\n\n const fontSize = Math.min(w, h) * 0.03;\n ctx.fillStyle = 'rgba(0,0,0,0.5)';\n ctx.fillRect(0, h - fontSize * 2, w, fontSize * 2);\n ctx.fillStyle = '#fff';\n ctx.font = `${fontSize}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.fillText(\n 'Person: ' + (personRatio * 100).toFixed(0) + '% | Mask: ' + seg.width + 'x' + seg.height,\n w / 2, h - fontSize * 0.5\n );\n}\n",
|
|
3451
|
+
"sceneCode": "const useSeg = viji.toggle(false, { label: 'Body Segmentation', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction cvHint(ctx, viji, label) {\n const s = Math.min(viji.width, viji.height);\n const t = (Math.sin(viji.time * 3) + 1) / 2;\n const bandH = s * 0.18;\n const bandY = (viji.height - bandH) / 2;\n ctx.fillStyle = `rgba(255, 200, 0, ${0.85 + t * 0.15})`;\n ctx.fillRect(0, bandY, viji.width, bandH);\n ctx.fillStyle = '#111';\n ctx.font = `bold ${s * 0.045}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(`Enable \"${label}\" in parameters`, viji.width / 2, viji.height / 2);\n ctx.textBaseline = 'alphabetic';\n}\n\nfunction render(viji) {\n const ctx = viji.useContext('2d');\n const w = viji.width;\n const h = viji.height;\n\n ctx.fillStyle = '#111';\n ctx.fillRect(0, 0, w, h);\n\n if (useSeg.value) viji.video.cv.enableBodySegmentation(true);\n else viji.video.cv.enableBodySegmentation(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n ctx.fillStyle = '#555';\n ctx.font = `${Math.min(w, h) * 0.04}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.fillText('Waiting for video...', w / 2, h / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n const frameToShow = viji.video.cv.analysedFrame ?? viji.video.currentFrame;\n ctx.drawImage(frameToShow, v.x, v.y, v.width, v.height);\n\n if (!useSeg.value) {\n cvHint(ctx, viji, 'Body Segmentation');\n return;\n }\n\n const seg = viji.video.cv.segmentation;\n if (!seg) return;\n\n let personPixels = 0;\n for (let i = 0; i < seg.mask.length; i++) {\n if (seg.mask[i] > 0) personPixels++;\n }\n const personRatio = personPixels / seg.mask.length;\n\n if (personRatio > 0.05) {\n ctx.shadowBlur = 30 * personRatio;\n ctx.shadowColor = `hsl(${170 + personRatio * 60}, 80%, 60%)`;\n ctx.strokeStyle = `hsla(${170 + personRatio * 60}, 80%, 60%, 0.6)`;\n ctx.lineWidth = 4;\n ctx.strokeRect(v.x, v.y, v.width, v.height);\n ctx.shadowBlur = 0;\n }\n\n const fontSize = Math.min(w, h) * 0.03;\n ctx.fillStyle = 'rgba(0,0,0,0.5)';\n ctx.fillRect(0, h - fontSize * 2, w, fontSize * 2);\n ctx.fillStyle = '#fff';\n ctx.font = `${fontSize}px sans-serif`;\n ctx.textAlign = 'center';\n ctx.fillText(\n 'Person: ' + (personRatio * 100).toFixed(0) + '% | Mask: ' + seg.width + 'x' + seg.height,\n w / 2, h - fontSize * 0.5\n );\n}\n",
|
|
3452
3452
|
"sceneFile": "body-segmentation-demo.scene.js",
|
|
3453
3453
|
"capabilities": {
|
|
3454
3454
|
"video": true
|
|
@@ -5775,7 +5775,7 @@ export const docsApi = {
|
|
|
5775
5775
|
{
|
|
5776
5776
|
"type": "live-example",
|
|
5777
5777
|
"title": "Video with Face Detection",
|
|
5778
|
-
"sceneCode": "// @renderer p5\n\nconst useFace = viji.toggle(false, { label: 'Face Detection', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction render(viji, p5) {\n p5.background(17);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n p5.fill(100);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(Math.min(viji.width, viji.height) * 0.04);\n p5.text('Waiting for video...', viji.width / 2, viji.height / 2);\n return;\n }\n\n if (useFace.value) viji.video.cv.enableFaceDetection(true);\n else viji.video.cv.enableFaceDetection(false);\n\n const v = videoFit(viji, 'contain');\n p5.tint(255, 150);\n p5.image(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n p5.noTint();\n\n viji.video.cv.faces.forEach(face => {\n const bx = v.x + face.bounds.x * v.width;\n const by = v.y + face.bounds.y * v.height;\n const bw = face.bounds.width * v.width;\n const bh = face.bounds.height * v.height;\n\n p5.noFill();\n p5.stroke(78, 205, 196);\n p5.strokeWeight(2);\n p5.rect(bx, by, bw, bh);\n\n p5.noStroke();\n p5.fill(78, 205, 196);\n p5.textSize(Math.min(viji.width, viji.height) * 0.025);\n p5.textAlign(p5.LEFT, p5.BOTTOM);\n p5.text('Face #' + face.id + ' (' + (face.confidence * 100).toFixed(0) + '%)', bx, by - 4);\n });\n}\n",
|
|
5778
|
+
"sceneCode": "// @renderer p5\n\nconst useFace = viji.toggle(false, { label: 'Face Detection', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction cvHint(viji, p5, label) {\n const s = Math.min(viji.width, viji.height);\n const t = (p5.sin(viji.time * 3) + 1) / 2;\n const bandH = s * 0.18;\n const bandY = (viji.height - bandH) / 2;\n p5.noStroke();\n p5.fill(255, 200, 0, (0.85 + t * 0.15) * 255);\n p5.rect(0, bandY, viji.width, bandH);\n p5.fill(17);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(s * 0.045);\n p5.textStyle(p5.BOLD);\n p5.text(`Enable \"${label}\" in parameters`, viji.width / 2, viji.height / 2);\n p5.textStyle(p5.NORMAL);\n}\n\nfunction render(viji, p5) {\n p5.background(17);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n p5.fill(100);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(Math.min(viji.width, viji.height) * 0.04);\n p5.text('Waiting for video...', viji.width / 2, viji.height / 2);\n return;\n }\n\n if (useFace.value) viji.video.cv.enableFaceDetection(true);\n else viji.video.cv.enableFaceDetection(false);\n\n const v = videoFit(viji, 'contain');\n p5.tint(255, 150);\n p5.image(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n p5.noTint();\n\n if (!useFace.value) {\n cvHint(viji, p5, 'Face Detection');\n return;\n }\n\n viji.video.cv.faces.forEach(face => {\n const bx = v.x + face.bounds.x * v.width;\n const by = v.y + face.bounds.y * v.height;\n const bw = face.bounds.width * v.width;\n const bh = face.bounds.height * v.height;\n\n p5.noFill();\n p5.stroke(78, 205, 196);\n p5.strokeWeight(2);\n p5.rect(bx, by, bw, bh);\n\n p5.noStroke();\n p5.fill(78, 205, 196);\n p5.textSize(Math.min(viji.width, viji.height) * 0.025);\n p5.textAlign(p5.LEFT, p5.BOTTOM);\n p5.text('Face #' + face.id + ' (' + (face.confidence * 100).toFixed(0) + '%)', bx, by - 4);\n });\n}\n",
|
|
5779
5779
|
"sceneFile": "video-overview.scene.js",
|
|
5780
5780
|
"capabilities": {
|
|
5781
5781
|
"video": true
|
|
@@ -5933,7 +5933,7 @@ export const docsApi = {
|
|
|
5933
5933
|
{
|
|
5934
5934
|
"type": "live-example",
|
|
5935
5935
|
"title": "Face Detection",
|
|
5936
|
-
"sceneCode": "// @renderer p5\n\nconst useFace = viji.toggle(false, { label: 'Face Detection', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction render(viji, p5) {\n p5.background(17);\n\n if (useFace.value) viji.video.cv.enableFaceDetection(true);\n else viji.video.cv.enableFaceDetection(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n p5.fill(100);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(Math.min(viji.width, viji.height) * 0.04);\n p5.text('Waiting for video...', viji.width / 2, viji.height / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n p5.image(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n\n viji.video.cv.faces.forEach(face => {\n const bx = v.x + face.bounds.x * v.width;\n const by = v.y + face.bounds.y * v.height;\n const bw = face.bounds.width * v.width;\n const bh = face.bounds.height * v.height;\n\n p5.noFill();\n p5.stroke(78, 205, 196);\n p5.strokeWeight(2);\n p5.rect(bx, by, bw, bh);\n\n p5.noStroke();\n p5.fill(78, 205, 196);\n p5.circle(v.x + face.center.x * v.width, v.y + face.center.y * v.height, 8);\n\n p5.textSize(Math.min(viji.width, viji.height) * 0.025);\n p5.textAlign(p5.LEFT, p5.BOTTOM);\n p5.text('Face #' + face.id + ' (' + (face.confidence * 100).toFixed(0) + '%)', bx, by - 4);\n });\n}\n",
|
|
5936
|
+
"sceneCode": "// @renderer p5\n\nconst useFace = viji.toggle(false, { label: 'Face Detection', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction cvHint(viji, p5, label) {\n const s = Math.min(viji.width, viji.height);\n const t = (p5.sin(viji.time * 3) + 1) / 2;\n const bandH = s * 0.18;\n const bandY = (viji.height - bandH) / 2;\n p5.noStroke();\n p5.fill(255, 200, 0, (0.85 + t * 0.15) * 255);\n p5.rect(0, bandY, viji.width, bandH);\n p5.fill(17);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(s * 0.045);\n p5.textStyle(p5.BOLD);\n p5.text(`Enable \"${label}\" in parameters`, viji.width / 2, viji.height / 2);\n p5.textStyle(p5.NORMAL);\n}\n\nfunction render(viji, p5) {\n p5.background(17);\n\n if (useFace.value) viji.video.cv.enableFaceDetection(true);\n else viji.video.cv.enableFaceDetection(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n p5.fill(100);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(Math.min(viji.width, viji.height) * 0.04);\n p5.text('Waiting for video...', viji.width / 2, viji.height / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n p5.image(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n\n if (!useFace.value) {\n cvHint(viji, p5, 'Face Detection');\n return;\n }\n\n viji.video.cv.faces.forEach(face => {\n const bx = v.x + face.bounds.x * v.width;\n const by = v.y + face.bounds.y * v.height;\n const bw = face.bounds.width * v.width;\n const bh = face.bounds.height * v.height;\n\n p5.noFill();\n p5.stroke(78, 205, 196);\n p5.strokeWeight(2);\n p5.rect(bx, by, bw, bh);\n\n p5.noStroke();\n p5.fill(78, 205, 196);\n p5.circle(v.x + face.center.x * v.width, v.y + face.center.y * v.height, 8);\n\n p5.textSize(Math.min(viji.width, viji.height) * 0.025);\n p5.textAlign(p5.LEFT, p5.BOTTOM);\n p5.text('Face #' + face.id + ' (' + (face.confidence * 100).toFixed(0) + '%)', bx, by - 4);\n });\n}\n",
|
|
5937
5937
|
"sceneFile": "face-detection-demo.scene.js",
|
|
5938
5938
|
"capabilities": {
|
|
5939
5939
|
"video": true
|
|
@@ -5979,7 +5979,7 @@ export const docsApi = {
|
|
|
5979
5979
|
{
|
|
5980
5980
|
"type": "live-example",
|
|
5981
5981
|
"title": "Face Mesh",
|
|
5982
|
-
"sceneCode": "// @renderer p5\n\nconst useMesh = viji.toggle(false, { label: 'Face Mesh', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction render(viji, p5) {\n p5.background(17);\n\n if (useMesh.value) viji.video.cv.enableFaceMesh(true);\n else viji.video.cv.enableFaceMesh(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n p5.fill(100);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(Math.min(viji.width, viji.height) * 0.04);\n p5.text('Waiting for video...', viji.width / 2, viji.height / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n p5.tint(255, 100);\n p5.image(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n p5.noTint();\n\n viji.video.cv.faces.forEach(face => {\n if (face.landmarks.length === 0) return;\n\n p5.noStroke();\n p5.fill(69, 183, 209, 180);\n face.landmarks.forEach(pt => {\n p5.circle(v.x + pt.x * v.width, v.y + pt.y * v.height, 2);\n });\n\n const hp = face.headPose;\n p5.fill(255);\n p5.textSize(Math.min(viji.width, viji.height) * 0.025);\n p5.textAlign(p5.LEFT, p5.BOTTOM);\n p5.text(\n face.landmarks.length + ' landmarks | Pitch: ' + hp.pitch.toFixed(1) +\n ' Yaw: ' + hp.yaw.toFixed(1) + ' Roll: ' + hp.roll.toFixed(1),\n viji.width * 0.03, viji.height - 10\n );\n });\n}\n",
|
|
5982
|
+
"sceneCode": "// @renderer p5\n\nconst useMesh = viji.toggle(false, { label: 'Face Mesh', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction cvHint(viji, p5, label) {\n const s = Math.min(viji.width, viji.height);\n const t = (p5.sin(viji.time * 3) + 1) / 2;\n const bandH = s * 0.18;\n const bandY = (viji.height - bandH) / 2;\n p5.noStroke();\n p5.fill(255, 200, 0, (0.85 + t * 0.15) * 255);\n p5.rect(0, bandY, viji.width, bandH);\n p5.fill(17);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(s * 0.045);\n p5.textStyle(p5.BOLD);\n p5.text(`Enable \"${label}\" in parameters`, viji.width / 2, viji.height / 2);\n p5.textStyle(p5.NORMAL);\n}\n\nfunction render(viji, p5) {\n p5.background(17);\n\n if (useMesh.value) viji.video.cv.enableFaceMesh(true);\n else viji.video.cv.enableFaceMesh(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n p5.fill(100);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(Math.min(viji.width, viji.height) * 0.04);\n p5.text('Waiting for video...', viji.width / 2, viji.height / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n p5.tint(255, 100);\n p5.image(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n p5.noTint();\n\n if (!useMesh.value) {\n cvHint(viji, p5, 'Face Mesh');\n return;\n }\n\n viji.video.cv.faces.forEach(face => {\n if (face.landmarks.length === 0) return;\n\n p5.noStroke();\n p5.fill(69, 183, 209, 180);\n face.landmarks.forEach(pt => {\n p5.circle(v.x + pt.x * v.width, v.y + pt.y * v.height, 2);\n });\n\n const hp = face.headPose;\n p5.fill(255);\n p5.textSize(Math.min(viji.width, viji.height) * 0.025);\n p5.textAlign(p5.LEFT, p5.BOTTOM);\n p5.text(\n face.landmarks.length + ' landmarks | Pitch: ' + hp.pitch.toFixed(1) +\n ' Yaw: ' + hp.yaw.toFixed(1) + ' Roll: ' + hp.roll.toFixed(1),\n viji.width * 0.03, viji.height - 10\n );\n });\n}\n",
|
|
5983
5983
|
"sceneFile": "face-mesh-demo.scene.js",
|
|
5984
5984
|
"capabilities": {
|
|
5985
5985
|
"video": true
|
|
@@ -6030,7 +6030,7 @@ export const docsApi = {
|
|
|
6030
6030
|
{
|
|
6031
6031
|
"type": "live-example",
|
|
6032
6032
|
"title": "Emotion Detection",
|
|
6033
|
-
"sceneCode": "// @renderer p5\n\nconst useEmotion = viji.toggle(false, { label: 'Emotion Detection', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction render(viji, p5) {\n p5.background(17);\n\n if (useEmotion.value) viji.video.cv.enableEmotionDetection(true);\n else viji.video.cv.enableEmotionDetection(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n p5.fill(100);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(Math.min(viji.width, viji.height) * 0.04);\n p5.text('Waiting for video...', viji.width / 2, viji.height / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n p5.tint(255, 100);\n p5.image(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n p5.noTint();\n\n const face = viji.video.cv.faces[0];\n if (!face) return;\n\n const expr = face.expressions;\n const labels = ['neutral', 'happy', 'sad', 'angry', 'surprised', 'disgusted', 'fearful'];\n const values = [expr.neutral, expr.happy, expr.sad, expr.angry, expr.surprised, expr.disgusted, expr.fearful];\n const colors = [[136,136,136], [76,175,80], [33,150,243], [244,67,54], [255,152,0], [156,39,176], [96,125,139]];\n\n const barH = viji.height * 0.04;\n const barW = viji.width * 0.3;\n const x = viji.width * 0.65;\n let y = viji.height * 0.12;\n const fontSize = barH * 0.7;\n\n p5.textSize(fontSize);\n p5.noStroke();\n\n labels.forEach((label, i) => {\n p5.fill(170);\n p5.textAlign(p5.RIGHT, p5.CENTER);\n p5.text(label, x - 8, y + barH / 2);\n\n p5.fill(34);\n p5.rect(x, y, barW, barH);\n p5.fill(colors[i][0], colors[i][1], colors[i][2]);\n p5.rect(x, y, barW * values[i], barH);\n\n p5.fill(220);\n p5.textAlign(p5.LEFT, p5.CENTER);\n p5.text((values[i] * 100).toFixed(0) + '%', x + barW + 6, y + barH / 2);\n\n y += barH * 1.8;\n });\n}\n",
|
|
6033
|
+
"sceneCode": "// @renderer p5\n\nconst useEmotion = viji.toggle(false, { label: 'Emotion Detection', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction cvHint(viji, p5, label) {\n const s = Math.min(viji.width, viji.height);\n const t = (p5.sin(viji.time * 3) + 1) / 2;\n const bandH = s * 0.18;\n const bandY = (viji.height - bandH) / 2;\n p5.noStroke();\n p5.fill(255, 200, 0, (0.85 + t * 0.15) * 255);\n p5.rect(0, bandY, viji.width, bandH);\n p5.fill(17);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(s * 0.045);\n p5.textStyle(p5.BOLD);\n p5.text(`Enable \"${label}\" in parameters`, viji.width / 2, viji.height / 2);\n p5.textStyle(p5.NORMAL);\n}\n\nfunction render(viji, p5) {\n p5.background(17);\n\n if (useEmotion.value) viji.video.cv.enableEmotionDetection(true);\n else viji.video.cv.enableEmotionDetection(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n p5.fill(100);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(Math.min(viji.width, viji.height) * 0.04);\n p5.text('Waiting for video...', viji.width / 2, viji.height / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n p5.tint(255, 100);\n p5.image(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n p5.noTint();\n\n if (!useEmotion.value) {\n cvHint(viji, p5, 'Emotion Detection');\n return;\n }\n\n const face = viji.video.cv.faces[0];\n if (!face) return;\n\n const expr = face.expressions;\n const labels = ['neutral', 'happy', 'sad', 'angry', 'surprised', 'disgusted', 'fearful'];\n const values = [expr.neutral, expr.happy, expr.sad, expr.angry, expr.surprised, expr.disgusted, expr.fearful];\n const colors = [[136,136,136], [76,175,80], [33,150,243], [244,67,54], [255,152,0], [156,39,176], [96,125,139]];\n\n const barH = viji.height * 0.04;\n const barW = viji.width * 0.3;\n const x = viji.width * 0.65;\n let y = viji.height * 0.12;\n const fontSize = barH * 0.7;\n\n p5.textSize(fontSize);\n p5.noStroke();\n\n labels.forEach((label, i) => {\n p5.fill(170);\n p5.textAlign(p5.RIGHT, p5.CENTER);\n p5.text(label, x - 8, y + barH / 2);\n\n p5.fill(34);\n p5.rect(x, y, barW, barH);\n p5.fill(colors[i][0], colors[i][1], colors[i][2]);\n p5.rect(x, y, barW * values[i], barH);\n\n p5.fill(220);\n p5.textAlign(p5.LEFT, p5.CENTER);\n p5.text((values[i] * 100).toFixed(0) + '%', x + barW + 6, y + barH / 2);\n\n y += barH * 1.8;\n });\n}\n",
|
|
6034
6034
|
"sceneFile": "emotion-detection-demo.scene.js",
|
|
6035
6035
|
"capabilities": {
|
|
6036
6036
|
"video": true
|
|
@@ -6076,7 +6076,7 @@ export const docsApi = {
|
|
|
6076
6076
|
{
|
|
6077
6077
|
"type": "live-example",
|
|
6078
6078
|
"title": "Hand Tracking",
|
|
6079
|
-
"sceneCode": "// @renderer p5\n\nconst useHands = viji.toggle(false, { label: 'Hand Tracking', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction render(viji, p5) {\n p5.background(17);\n\n if (useHands.value) viji.video.cv.enableHandTracking(true);\n else viji.video.cv.enableHandTracking(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n p5.fill(100);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(Math.min(viji.width, viji.height) * 0.04);\n p5.text('Waiting for video...', viji.width / 2, viji.height / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n p5.tint(255, 100);\n p5.image(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n p5.noTint();\n\n viji.video.cv.hands.forEach(hand => {\n const col = hand.handedness === 'left' ? [255, 159, 243] : [84, 160, 255];\n\n p5.noStroke();\n p5.fill(col[0], col[1], col[2]);\n hand.landmarks.forEach(pt => {\n p5.circle(v.x + pt.x * v.width, v.y + pt.y * v.height, 6);\n });\n\n p5.noFill();\n p5.stroke(col[0], col[1], col[2]);\n p5.strokeWeight(2);\n p5.circle(v.x + hand.palm.x * v.width, v.y + hand.palm.y * v.height, 16);\n\n const g = hand.gestures;\n const gestures = [\n ['fist', g.fist], ['open', g.openPalm], ['peace', g.peace],\n ['thumbsUp', g.thumbsUp], ['pointing', g.pointing]\n ];\n const top = gestures.reduce((a, b) => b[1] > a[1] ? b : a);\n if (top[1] > 0.5) {\n p5.noStroke();\n p5.fill(255);\n p5.textSize(Math.min(viji.width, viji.height) * 0.03);\n p5.textAlign(p5.CENTER, p5.BOTTOM);\n p5.text(top[0], v.x + hand.palm.x * v.width, v.y + hand.bounds.y * v.height - 6);\n }\n });\n}\n",
|
|
6079
|
+
"sceneCode": "// @renderer p5\n\nconst useHands = viji.toggle(false, { label: 'Hand Tracking', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction cvHint(viji, p5, label) {\n const s = Math.min(viji.width, viji.height);\n const t = (p5.sin(viji.time * 3) + 1) / 2;\n const bandH = s * 0.18;\n const bandY = (viji.height - bandH) / 2;\n p5.noStroke();\n p5.fill(255, 200, 0, (0.85 + t * 0.15) * 255);\n p5.rect(0, bandY, viji.width, bandH);\n p5.fill(17);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(s * 0.045);\n p5.textStyle(p5.BOLD);\n p5.text(`Enable \"${label}\" in parameters`, viji.width / 2, viji.height / 2);\n p5.textStyle(p5.NORMAL);\n}\n\nfunction render(viji, p5) {\n p5.background(17);\n\n if (useHands.value) viji.video.cv.enableHandTracking(true);\n else viji.video.cv.enableHandTracking(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n p5.fill(100);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(Math.min(viji.width, viji.height) * 0.04);\n p5.text('Waiting for video...', viji.width / 2, viji.height / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n p5.tint(255, 100);\n p5.image(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n p5.noTint();\n\n if (!useHands.value) {\n cvHint(viji, p5, 'Hand Tracking');\n return;\n }\n\n viji.video.cv.hands.forEach(hand => {\n const col = hand.handedness === 'left' ? [255, 159, 243] : [84, 160, 255];\n\n p5.noStroke();\n p5.fill(col[0], col[1], col[2]);\n hand.landmarks.forEach(pt => {\n p5.circle(v.x + pt.x * v.width, v.y + pt.y * v.height, 6);\n });\n\n p5.noFill();\n p5.stroke(col[0], col[1], col[2]);\n p5.strokeWeight(2);\n p5.circle(v.x + hand.palm.x * v.width, v.y + hand.palm.y * v.height, 16);\n\n const g = hand.gestures;\n const gestures = [\n ['fist', g.fist], ['open', g.openPalm], ['peace', g.peace],\n ['thumbsUp', g.thumbsUp], ['pointing', g.pointing]\n ];\n const top = gestures.reduce((a, b) => b[1] > a[1] ? b : a);\n if (top[1] > 0.5) {\n p5.noStroke();\n p5.fill(255);\n p5.textSize(Math.min(viji.width, viji.height) * 0.03);\n p5.textAlign(p5.CENTER, p5.BOTTOM);\n p5.text(top[0], v.x + hand.palm.x * v.width, v.y + hand.bounds.y * v.height - 6);\n }\n });\n}\n",
|
|
6080
6080
|
"sceneFile": "hand-tracking-demo.scene.js",
|
|
6081
6081
|
"capabilities": {
|
|
6082
6082
|
"video": true
|
|
@@ -6117,7 +6117,7 @@ export const docsApi = {
|
|
|
6117
6117
|
{
|
|
6118
6118
|
"type": "live-example",
|
|
6119
6119
|
"title": "Pose Detection",
|
|
6120
|
-
"sceneCode": "// @renderer p5\n\nconst usePose = viji.toggle(false, { label: 'Pose Detection', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction render(viji, p5) {\n p5.background(17);\n\n if (usePose.value) viji.video.cv.enablePoseDetection(true);\n else viji.video.cv.enablePoseDetection(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n p5.fill(100);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(Math.min(viji.width, viji.height) * 0.04);\n p5.text('Waiting for video...', viji.width / 2, viji.height / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n p5.tint(255, 100);\n p5.image(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n p5.noTint();\n\n const pose = viji.video.cv.pose;\n if (!pose) return;\n\n p5.noStroke();\n p5.fill(255, 107, 107);\n pose.landmarks.forEach(pt => {\n if (pt.visibility > 0.5) {\n p5.circle(v.x + pt.x * v.width, v.y + pt.y * v.height, 8);\n }\n });\n\n p5.strokeWeight(2);\n p5.noFill();\n const drawGroup = (group, col) => {\n if (group.length < 2) return;\n p5.stroke(col[0], col[1], col[2]);\n p5.beginShape();\n group.forEach(pt => p5.vertex(v.x + pt.x * v.width, v.y + pt.y * v.height));\n p5.endShape();\n };\n\n drawGroup(pose.leftArm, [255, 159, 243]);\n drawGroup(pose.rightArm, [84, 160, 255]);\n drawGroup(pose.leftLeg, [255, 159, 243]);\n drawGroup(pose.rightLeg, [84, 160, 255]);\n drawGroup(pose.torso, [254, 202, 87]);\n\n p5.noStroke();\n p5.fill(255);\n p5.textSize(Math.min(viji.width, viji.height) * 0.025);\n p5.textAlign(p5.LEFT, p5.BOTTOM);\n p5.text('Confidence: ' + (pose.confidence * 100).toFixed(0) + '%', viji.width * 0.03, viji.height - 10);\n}\n",
|
|
6120
|
+
"sceneCode": "// @renderer p5\n\nconst usePose = viji.toggle(false, { label: 'Pose Detection', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction cvHint(viji, p5, label) {\n const s = Math.min(viji.width, viji.height);\n const t = (p5.sin(viji.time * 3) + 1) / 2;\n const bandH = s * 0.18;\n const bandY = (viji.height - bandH) / 2;\n p5.noStroke();\n p5.fill(255, 200, 0, (0.85 + t * 0.15) * 255);\n p5.rect(0, bandY, viji.width, bandH);\n p5.fill(17);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(s * 0.045);\n p5.textStyle(p5.BOLD);\n p5.text(`Enable \"${label}\" in parameters`, viji.width / 2, viji.height / 2);\n p5.textStyle(p5.NORMAL);\n}\n\nfunction render(viji, p5) {\n p5.background(17);\n\n if (usePose.value) viji.video.cv.enablePoseDetection(true);\n else viji.video.cv.enablePoseDetection(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n p5.fill(100);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(Math.min(viji.width, viji.height) * 0.04);\n p5.text('Waiting for video...', viji.width / 2, viji.height / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n p5.tint(255, 100);\n p5.image(viji.video.currentFrame, v.x, v.y, v.width, v.height);\n p5.noTint();\n\n if (!usePose.value) {\n cvHint(viji, p5, 'Pose Detection');\n return;\n }\n\n const pose = viji.video.cv.pose;\n if (!pose) return;\n\n p5.noStroke();\n p5.fill(255, 107, 107);\n pose.landmarks.forEach(pt => {\n if (pt.visibility > 0.5) {\n p5.circle(v.x + pt.x * v.width, v.y + pt.y * v.height, 8);\n }\n });\n\n p5.strokeWeight(2);\n p5.noFill();\n const drawGroup = (group, col) => {\n if (group.length < 2) return;\n p5.stroke(col[0], col[1], col[2]);\n p5.beginShape();\n group.forEach(pt => p5.vertex(v.x + pt.x * v.width, v.y + pt.y * v.height));\n p5.endShape();\n };\n\n drawGroup(pose.leftArm, [255, 159, 243]);\n drawGroup(pose.rightArm, [84, 160, 255]);\n drawGroup(pose.leftLeg, [255, 159, 243]);\n drawGroup(pose.rightLeg, [84, 160, 255]);\n drawGroup(pose.torso, [254, 202, 87]);\n\n p5.noStroke();\n p5.fill(255);\n p5.textSize(Math.min(viji.width, viji.height) * 0.025);\n p5.textAlign(p5.LEFT, p5.BOTTOM);\n p5.text('Confidence: ' + (pose.confidence * 100).toFixed(0) + '%', viji.width * 0.03, viji.height - 10);\n}\n",
|
|
6121
6121
|
"sceneFile": "pose-detection-demo.scene.js",
|
|
6122
6122
|
"capabilities": {
|
|
6123
6123
|
"video": true
|
|
@@ -6163,7 +6163,7 @@ export const docsApi = {
|
|
|
6163
6163
|
{
|
|
6164
6164
|
"type": "live-example",
|
|
6165
6165
|
"title": "Body Segmentation",
|
|
6166
|
-
"sceneCode": "// @renderer p5\n\nconst useSeg = viji.toggle(false, { label: 'Body Segmentation', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction render(viji, p5) {\n p5.background(17);\n\n if (useSeg.value) viji.video.cv.enableBodySegmentation(true);\n else viji.video.cv.enableBodySegmentation(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n p5.fill(100);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(Math.min(viji.width, viji.height) * 0.04);\n p5.text('Waiting for video...', viji.width / 2, viji.height / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n const frameToShow = viji.video.cv.analysedFrame ?? viji.video.currentFrame;\n p5.image(frameToShow, v.x, v.y, v.width, v.height);\n\n const seg = viji.video.cv.segmentation;\n if (!seg) return;\n\n let personPixels = 0;\n for (let i = 0; i < seg.mask.length; i++) {\n if (seg.mask[i] > 0) personPixels++;\n }\n const personRatio = personPixels / seg.mask.length;\n\n if (personRatio > 0.05) {\n p5.noFill();\n p5.stroke(78, 205, 196, 150);\n p5.strokeWeight(4);\n p5.rect(v.x, v.y, v.width, v.height);\n }\n\n const fontSize = Math.min(viji.width, viji.height) * 0.03;\n p5.noStroke();\n p5.fill(0, 128);\n p5.rect(0, viji.height - fontSize * 2, viji.width, fontSize * 2);\n p5.fill(255);\n p5.textSize(fontSize);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.text(\n 'Person: ' + (personRatio * 100).toFixed(0) + '% | Mask: ' + seg.width + 'x' + seg.height,\n viji.width / 2, viji.height - fontSize\n );\n}\n",
|
|
6166
|
+
"sceneCode": "// @renderer p5\n\nconst useSeg = viji.toggle(false, { label: 'Body Segmentation', category: 'video' });\n\nfunction videoFit(viji, mode = 'cover') {\n const vw = viji.video.frameWidth, vh = viji.video.frameHeight;\n const w = viji.width, h = viji.height;\n if (!vw || !vh) return { x: 0, y: 0, width: 0, height: 0 };\n const scale = mode === 'cover' ? Math.max(w / vw, h / vh) : Math.min(w / vw, h / vh);\n const dw = vw * scale, dh = vh * scale;\n return { x: (w - dw) / 2, y: (h - dh) / 2, width: dw, height: dh };\n}\n\nfunction cvHint(viji, p5, label) {\n const s = Math.min(viji.width, viji.height);\n const t = (p5.sin(viji.time * 3) + 1) / 2;\n const bandH = s * 0.18;\n const bandY = (viji.height - bandH) / 2;\n p5.noStroke();\n p5.fill(255, 200, 0, (0.85 + t * 0.15) * 255);\n p5.rect(0, bandY, viji.width, bandH);\n p5.fill(17);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(s * 0.045);\n p5.textStyle(p5.BOLD);\n p5.text(`Enable \"${label}\" in parameters`, viji.width / 2, viji.height / 2);\n p5.textStyle(p5.NORMAL);\n}\n\nfunction render(viji, p5) {\n p5.background(17);\n\n if (useSeg.value) viji.video.cv.enableBodySegmentation(true);\n else viji.video.cv.enableBodySegmentation(false);\n\n if (!viji.video.isConnected || !viji.video.currentFrame) {\n p5.fill(100);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.textSize(Math.min(viji.width, viji.height) * 0.04);\n p5.text('Waiting for video...', viji.width / 2, viji.height / 2);\n return;\n }\n\n const v = videoFit(viji, 'contain');\n const frameToShow = viji.video.cv.analysedFrame ?? viji.video.currentFrame;\n p5.image(frameToShow, v.x, v.y, v.width, v.height);\n\n if (!useSeg.value) {\n cvHint(viji, p5, 'Body Segmentation');\n return;\n }\n\n const seg = viji.video.cv.segmentation;\n if (!seg) return;\n\n let personPixels = 0;\n for (let i = 0; i < seg.mask.length; i++) {\n if (seg.mask[i] > 0) personPixels++;\n }\n const personRatio = personPixels / seg.mask.length;\n\n if (personRatio > 0.05) {\n p5.noFill();\n p5.stroke(78, 205, 196, 150);\n p5.strokeWeight(4);\n p5.rect(v.x, v.y, v.width, v.height);\n }\n\n const fontSize = Math.min(viji.width, viji.height) * 0.03;\n p5.noStroke();\n p5.fill(0, 128);\n p5.rect(0, viji.height - fontSize * 2, viji.width, fontSize * 2);\n p5.fill(255);\n p5.textSize(fontSize);\n p5.textAlign(p5.CENTER, p5.CENTER);\n p5.text(\n 'Person: ' + (personRatio * 100).toFixed(0) + '% | Mask: ' + seg.width + 'x' + seg.height,\n viji.width / 2, viji.height - fontSize\n );\n}\n",
|
|
6167
6167
|
"sceneFile": "body-segmentation-demo.scene.js",
|
|
6168
6168
|
"capabilities": {
|
|
6169
6169
|
"video": true
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as getDefaultExportFromCjs } from "./index-
|
|
1
|
+
import { g as getDefaultExportFromCjs } from "./index-Bhq4eJe_.js";
|
|
2
2
|
function _mergeNamespaces(n, m) {
|
|
3
3
|
for (var i = 0; i < m.length; i++) {
|
|
4
4
|
const e = m[i];
|
|
@@ -5693,4 +5693,4 @@ const essentiaWasm_web$1 = /* @__PURE__ */ _mergeNamespaces({
|
|
|
5693
5693
|
export {
|
|
5694
5694
|
essentiaWasm_web$1 as e
|
|
5695
5695
|
};
|
|
5696
|
-
//# sourceMappingURL=essentia-wasm.web-
|
|
5696
|
+
//# sourceMappingURL=essentia-wasm.web-CPrFAj59.js.map
|