diff --git a/public/favicon.png b/public/favicon.png deleted file mode 100644 index 7e6f5eb..0000000 Binary files a/public/favicon.png and /dev/null differ diff --git a/public/index.html b/public/index.html index 6296fab..4b692ad 100644 --- a/public/index.html +++ b/public/index.html @@ -7,7 +7,7 @@ Svelte app - + diff --git a/src/game/cameraControl.js b/src/game/cameraControl.js index e896ebc..c588045 100644 --- a/src/game/cameraControl.js +++ b/src/game/cameraControl.js @@ -1,91 +1,89 @@ -import { FaceDetector, FilesetResolver } from '@mediapipe/tasks-vision'; +import { FaceLandmarker, FilesetResolver } from '@mediapipe/tasks-vision'; export const cameraInput = { left: false, right: false, active: false, - zone: 'center', - x: 0.5 + zone: 'center' }; let video; -let faceDetector; +let faceLandmarker; +let lastTime = 0; -// 🔥 NARROW CENTER ZONE: -// 0.48 and 0.52 means the center is only 4% of the screen width. -// Adjust these if it's still too hard to trigger movement. -const LEFT_THRESHOLD = 0.48; -const RIGHT_THRESHOLD = 0.52; +const DETECTION_INTERVAL = 60; export async function initCameraControl() { - if (cameraInput.active) return video; + if (cameraInput.active) + return video; video = document.createElement('video'); video.autoplay = true; video.playsInline = true; video.muted = true; + // Set low resolution and frame rate for better performance const stream = await navigator.mediaDevices.getUserMedia({ - video: { - width: 160, - height: 120, - frameRate: { ideal: 20 } // Slightly higher for faster reaction + video: { + width: { ideal: 160 }, + height: { ideal: 120 }, + frameRate: { ideal: 30 } } }); video.srcObject = stream; + //load models for face landmark detection const vision = await FilesetResolver.forVisionTasks( 'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/wasm' ); - - faceDetector = await FaceDetector.createFromOptions(vision, { + faceLandmarker = await FaceLandmarker.createFromOptions(vision, { baseOptions: { - modelAssetPath: `https://storage.googleapis.com/mediapipe-models/face_detector/blaze_face_short_range/float16/1/blaze_face_short_range.task`, - delegate: 'GPU' + modelAssetPath: + 'https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/latest/face_landmarker.task', }, - runningMode: 'VIDEO' - }); - - video.addEventListener('loadeddata', () => { - cameraInput.active = true; - startDetectionLoop(); + runningMode: 'VIDEO', + numFaces: 1 }); + cameraInput.active = true; return video; } -function startDetectionLoop() { - const detect = (now) => { - const result = faceDetector.detectForVideo(video, now); +export function updateCameraControl() { + const now = performance.now(); - if (result.detections.length > 0) { - const box = result.detections[0].boundingBox; - // Calculate raw center point (0 to 1) - const rawX = (box.originX + box.width / 2) / 160; - - cameraInput.x = rawX; + // Limit detection frequency to improve performance + if (now - lastTime < DETECTION_INTERVAL) + return; + lastTime = now; - // INSTANT LOGIC (No smoothing) - if (rawX < LEFT_THRESHOLD) { - updateZones(false, true, 'right'); // Mirrored: Face on left of cam = move right - } else if (rawX > RIGHT_THRESHOLD) { - updateZones(true, false, 'left'); // Mirrored: Face on right of cam = move left - } else { - updateZones(false, false, 'center'); - } - } else { - updateZones(false, false, 'center'); - } + if (!faceLandmarker || !video || video.readyState < 2) + return; - video.requestVideoFrameCallback(detect); - }; + const result = faceLandmarker.detectForVideo(video, now); - video.requestVideoFrameCallback(detect); -} + // If no face is detected, reset to center + if (!result.faceLandmarks.length) { + cameraInput.left = false; + cameraInput.right = false; + cameraInput.zone = 'center'; + return; + } -function updateZones(l, r, z) { - cameraInput.left = l; - cameraInput.right = r; - cameraInput.zone = z; + // look at the nose and determine zone + const x = result.faceLandmarks[0][1].x; + if (x < 0.4) { + cameraInput.left = false; + cameraInput.right = true; + cameraInput.zone = 'right'; + } else if (x > 0.6) { + cameraInput.left = true; + cameraInput.right = false; + cameraInput.zone = 'left'; + } else { + cameraInput.left = false; + cameraInput.right = false; + cameraInput.zone = 'center'; + } } \ No newline at end of file diff --git a/src/game/constants.js b/src/game/constants.js index 01d6a88..fa36be8 100644 --- a/src/game/constants.js +++ b/src/game/constants.js @@ -16,4 +16,4 @@ export const PLAT_TYPE = { MOVING: 'moving', SPRING: 'spring', ONE_TIME: 'one-time' -}; +}; \ No newline at end of file