From b3bef5a1923ca1e40979edd2728fc61681bb5602 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 2 Apr 2026 05:09:39 +0000 Subject: [PATCH 1/2] Add camera-controlled Tetris game using MediaPipe Pose detection Single HTML file that uses laptop webcam + MediaPipe Pose to play Tetris with body gestures: raise left/right hand to move, both hands to rotate, squat to hard drop. Also supports full keyboard controls as fallback. https://claude.ai/code/session_013WPDpQAFbJ5CycF2VcsBkN --- camera-tetris.html | 719 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 719 insertions(+) create mode 100644 camera-tetris.html diff --git a/camera-tetris.html b/camera-tetris.html new file mode 100644 index 0000000..1b248e0 --- /dev/null +++ b/camera-tetris.html @@ -0,0 +1,719 @@ + + + + + +Camera Tetris - 体感俄罗斯方块 + + + +
+ + + +
+
SCORE: 0
+
LEVEL: 1
+
+
NEXT
+ +
+
+
+
← → Move
+
Rotate
+
Soft Drop
+
Space Hard Drop
+
P Pause
+
+
+
+

🎮 体感俄罗斯方块

+

Camera Tetris

+
+
🎥 Camera Mode: raise LEFT hand = move left, raise RIGHT hand = move right
+
🙌 Both hands up = rotate | 🏋️ Squat down = hard drop
+
⌨️ Keyboard: Arrow keys to move/rotate, Space to drop
+
+
+ + +
+ +
+
+

GAME OVER

+
+ +
+
+
+ + + + From 715b800a408700d53b4951dadcbe7024ff6a37b9 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 6 Apr 2026 10:02:54 +0000 Subject: [PATCH 2/2] Show visible camera permission errors and HTTPS/localhost requirement Previously getUserMedia failures were silent when opened via file://. Now displays a clear banner explaining the secure-context requirement and specific error (denied, not found, etc). https://claude.ai/code/session_013WPDpQAFbJ5CycF2VcsBkN --- camera-tetris.html | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/camera-tetris.html b/camera-tetris.html index 1b248e0..ad9af8c 100644 --- a/camera-tetris.html +++ b/camera-tetris.html @@ -195,13 +195,24 @@ .mode-btn:hover { opacity: 0.8; } #cameraStatus { position: absolute; - top: 50%; left: 50%; - transform: translate(-50%, -50%); - z-index: 5; - font-size: 18px; - color: #f00; + top: 20px; left: 50%; + transform: translateX(-50%); + z-index: 20; + font-size: 16px; + color: #fff; + background: rgba(200, 0, 0, 0.9); + padding: 12px 20px; + border-radius: 8px; + max-width: 90%; + text-align: center; display: none; } +#cameraStatus code { + background: rgba(0,0,0,0.5); + padding: 2px 6px; + border-radius: 4px; + font-size: 13px; +} @@ -284,6 +295,16 @@

GAME OVER

const poseCtx = poseCanvas.getContext('2d'); async function startCamera() { + const statusEl = document.getElementById('cameraStatus'); + if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { + const insecure = location.protocol !== 'https:' && location.hostname !== 'localhost' && location.hostname !== '127.0.0.1'; + statusEl.innerHTML = insecure + ? '⚠️ Camera requires HTTPS or localhost.
Open via python3 -m http.server then http://localhost:8000/camera-tetris.html' + : '⚠️ getUserMedia not supported in this browser'; + statusEl.style.display = 'block'; + useCamera = false; + return false; + } try { const stream = await navigator.mediaDevices.getUserMedia({ video: { width: { ideal: 1280 }, height: { ideal: 720 }, facingMode: 'user' } @@ -295,8 +316,12 @@

GAME OVER

return true; } catch (e) { console.warn('Camera not available:', e); - document.getElementById('cameraStatus').textContent = 'Camera not available - use keyboard'; - document.getElementById('cameraStatus').style.display = 'block'; + let msg = '⚠️ Camera error: ' + e.name; + if (e.name === 'NotAllowedError') msg = '⚠️ Camera permission denied. Allow it in browser settings and reload.'; + else if (e.name === 'NotFoundError') msg = '⚠️ No camera found on this device.'; + else if (location.protocol === 'file:') msg = '⚠️ file:// blocks camera. Serve via http://localhost instead.'; + statusEl.innerHTML = msg; + statusEl.style.display = 'block'; useCamera = false; return false; }