שליטה במצלמה ומחוות

ממשק שנשלט במצלמה נראה מושלם בהדגמה ונשבר מול משתמש אמיתי: הסמן קופץ, אגרוף לא נרשם, והמערכת מפסיקה לזהות כשמסתובבים. ה-Skill מלמד את Claude את העובדה שגורמת לרוב הבאגים, שהעומק הוא הציר הלא אמין, ואת רשימת התקלות השקטות, ואיך לבדוק את הכול בלי לעמוד מול מצלמה. זהו Skill ל-Claude: תיקייה עם קובץ SKILL.md, שנטענת אוטומטית כשהמשימה מתאימה לתיאור שבראש הקובץ. בניגוד לפרומפט שמדביקים בכל פעם מחדש, Skill מותקן פעם אחת וממשיך לעבוד לבד.

קוד ואיכות · מצלמה · MediaPipe · מחוות · משחקים · דפדפן

מתי הוא נכנס לפעולה

---
name: camera-control
description: "Build and debug webcam-driven control: MediaPipe hand and pose tracking, gesture UI and body-controlled games. Covers why depth is the unreliable axis, the silent failures that pass every test, deciding contact or a hit from a camera, and verifying without standing in front of a lens. Use when a webcam controls an interface or a game, or when tracking breaks at a distance."
---

# שליטה במסך דרך המצלמה

הידע כאן נצבר מבניית מנוע מחוות אמיתי: שלושה משחקים על אותו מנוע: בנייה בצביטה, מרוץ בהגה דמיוני, ואיגרוף בגוף מלא. כל מלכודת שמתוארת כאן עלתה מחזור דיבוג שלם, וכולן עברו את כל הבדיקות לפני שהתגלו.

**המנוע הוא הנכס, לא המשחק.** תכננו את שכבת הידיים ושכבת הגוף כך שיעברו לפרויקט הבא.

---

## העובדה האחת שממנה נגזר הכל

**ציר העומק הוא הציר שמצלמה בודדת מעריכה הכי גרוע.** רוחב וגובה נקראים היטב. העומק נקרא רע.

זו לא הערת שוליים. כמעט כל באג במנוע הזה היה תוצאה של סמיכה על z, וכל תיקון היה דרך אחרת להוציא את z מההחלטה:

| מה נשבר | למה | הפתרון |
| --- | --- | --- |
| מדידת מרחק | רוחב כתפיים מוקרן מתכווץ בקוסינוס הפנייה | יחס מטרים-לפיקסלים ממקטעים קשיחים |
| זיהוי אגרוף | סף מוחלט על מתיחה, ומתיחה נדחסת | מרחק שהיד עברה מנקודת הקיפול שלה |
| כיוון האגרוף | נרמול וקטור עם רכיב קדימה מוקטן מסובב אותו הצידה | שחזור עומק מאורכי עצם קבועים |
| הפגיעה עצמה | הגעה לנפח תלת ממדי | חפיפה **על המסך** |

**הכלל המעשי:** לפני שאתם כותבים תנאי שמסתמך על z, שאלו אם אפשר לנסח אותו בשני הצירים האחרים. כמעט תמיד אפשר.

---

## שתי מערכות קואורדינטות, ולכל אחת שאלה משלה

MediaPipe מחזיר שתי רשימות נקודות, ושתיהן נחוצות:

**נורמליזציה למסך (0 עד 1):** "האם הגוף בפריים", "כמה גדול הוא נראה". כאן עושים **מראה פעם אחת**, בנקודת הקריאה, כדי שהשלד המצויר וכל בדיקות המסגור יסכימו על כיווניות אחת של העולם.

**עולם במטרים (מקור בין הירכיים):** "כמה היד נסעה", "באיזו מהירות". כאן **לא נוגעים**. הרשימה הזאת מתארת את הגוף, לא את התמונה.

בלבול בין השתיים הוא מקור שקט לבאגים, כי שתיהן מערך של נקודות עם x,y,z ואף אחת לא מתלוננת.

---

## מלכודות שעוברות את כל הבדיקות

כולן אומתו בפרויקט הזה. הפירוט המלא, כולל מספרים ותיקונים, ב-`references/traps.md`. קראו אותו כשמשהו לא מתנהג ואין הודעת שגיאה.

1. **רוחב מוקרן כמדד מרחק.** סיבוב גוף ב-45 מעלות מוריד 30 אחוז מהרוחב. המערכת אומרת שהשחקן צעד מטר אחורה. הוא רק עמד בעמידת איגרוף.

2. **beta של One Euro תלוי ביחידות.** העתקת beta מסמן במסך לאות במטרים לשנייה נותנת קבוע זמן של 92 אלפיות מול אגרוף של 120. המכות נמחקות.

3. **dt שלילי או ענק.** `1-exp(-k*dt)` הופך לאקסטרפולציה בורחת. לחסום dt משני הצדדים.

4. **handedness הפוך.** MediaPipe מניח קלט ממראה. זרם גולמי נותן תווית הפוכה, ו-`scaleX` ב-CSS לא מתקן את זה כי הוא משנה רק את התצוגה.

5. **לולאת rAF מתה בשקט.** חריגה אחת מקפיאה את המשחק לצמיתות על מסך ריק. `try/catch` סביב ה-tick, ולבדוק מול קבוע ה"אין גוף" **האמיתי** ולא מול אובייקט דומה שהמצאתם.

6. **מחווה שחולקת גפה עם שליטה רציפה.** כל מחווה ביד שמחזיקה הגה תטלטל את ההגה. ותנוחת מנוחה נקראת כמחווה.

7. **מתיחת זרוע לא מונוטונית בעומק דחוס.** אותו צלב: בעומק מלא 0.49→0.93 עולה יפה. בעומק 40 אחוז 0.50→**0.43**→**0.41**→0.72, כלומר הזרוע נקראת כמתקפלת לפני שהיא נפתחת.

8. **סף מוחלט על אות שהעומק דוחס.** אותה טעות כמו 7, בלבוש אחר. אם כתבתם `>= 0.85` על משהו שנגזר מ-z, בחרתם מרחק שבו הפיצ'ר מפסיק לעבוד בשקט.

9. **Vite מגיש מודול ישן.** אימות בדפדפן רץ על קוד שמחקתם. `curl` על המודול לפני שמסיקים, והפעלה מחדש ולא ריענון.

---

## חמישה כללי תכנון שעובדים

### למדוד את המשתמש, לא להניח
כל סף שנכתב מראש הוא ניחוש על גוף שלא ראיתם. המנוע מודד במקום: מרחק הייחוס מכויל בזמן בדיקת המרחב, אורכי העצם נלמדים כמקסימום שנצפה, ורצועת המתיחה של האגרוף נלמדת בחימום. אותו קוד עובד על גבוה ועל נמוך בלי פרמטר.

### היסטרזיס בכל מקום
שני ספים, אף פעם לא אחד. צביטה נסגרת ב-0.35 ונפתחת ב-0.45. בין השניים המצב לא משתנה. עם סף יחיד כל מצב בינארי מרצד בדיוק על הגבול, וזה נראה למשתמש כמו תקלה.

### להכריע על המסך
כשצריך להחליט "האם נגעת", למדוד חפיפה במסך ולא מרחק בעולם. זה בדיוק מה שהמשתמש רואה, ואין פער בין מה שנראה למה שקורה. ראו `references/hit-detection.md`.

### שער איטי ואמין, בנפרד מהחלטה מהירה
מרחק הוא אות איטי שנגזר מגודל הגוף בפריים, והוא אמין. כיוון הוא אות מהיר. להפריד: **הטווח קובע אם אתה יכול, הכיוון קובע במה פגעת.** ככה צעד קדימה ואחורה מקבל משמעות בלי להכניס את z להחלטת הפגיעה.

### לא לתלות את המשחק בנקודות שנעלמות
זה הבאג היקר ביותר בפרויקט. שורה אחת דרשה ששני הקרסוליים ייראו. היא חסמה **גם** את תחילת המשחק **וגם** את כיול המרחק, כך שהמשחק לא התחיל, ובמקביל כל חישובי הטווח רצו על ניחוש קשיח. קרסוליים, כפות רגליים ואצבעות נעלמות דרך קבע. לבנות על הליבה: אף, כתפיים, ירכיים.

---

## איך מאמתים את זה בלי לעמוד מול מצלמה

זה מה שהופך את העבודה הזאת מניחושים להנדסה. שתי שכבות, שתיהן ב-`references/verification.md`.

**בדיקות ללא מצלמה:** בונים שלד סינתטי **במטרים** ואז מקרינים אותו למסך. זה עולה עמוד טריגונומטריה וקונה את הדבר היחיד שחשוב: היכולת **לסובב** את הדמות ו**לדחוס את העומק** ולבדוק ששום דבר במורד הזרם לא מבחין. בדיקה שנכתבה ישירות בקואורדינטות מסך תעבור, ועדיין תגיד לבוקסר בעמידה אלכסונית שהוא צעד אחורה.

כל פיצ'ר חדש נבדק בשני עומקים, 100 אחוז ו-40 אחוז. לא רק ב-100.

**אימות בדפדפן:** לחשוף `feedBody(reading)` ו-`tick(now)` במצב דיבוג, ולהזין שלד סינתטי עם **שעון סינתטי** משלכם. זה עובד גם כשחלונית הדפדפן מוסתרת ו-rAF לא רץ, והוא דטרמיניסטי. בלי זה כל אימות דורש בן אדם מול עדשה.

**מה שאף בדיקה לא תגיד לכם:** אם זה מרגיש טוב. זו מדידה שרק אדם שעומד מול העדשה יכול לעשות, ותמיד צריך לומר את זה במפורש במקום להציג ירוק כהוכחה.

---

## קבצי עומק

| קובץ | מתי לקרוא |
| --- | --- |
| `references/traps.md` | משהו לא עובד ואין הודעת שגיאה. הקטלוג המלא עם מספרים ותיקונים |
| `references/hit-detection.md` | צריך להחליט "נגעת" או "תפסת" מול מצלמה. כולל למה מודל הקרן נפסל |
| `references/verification.md` | לבנות את מערך הבדיקות, הרמה חסרת המצלמה והנהג בדפדפן |
| `references/tuning.md` | טבלת הקבועים המכוילים עם ההסבר למה כל ערך הוא מה שהוא |

---

## אזהרה על ביצועים

מודל ה-pose הקל הוא 5.8MB, ה-holistic הוא 13.7MB. להעדיף את הקל אלא אם באמת צריך אצבעות, ולמדוד FPS בפועל על המכונה של המשתמש לפני שמחליטים. מנוע שרץ ב-12 פריימים לשנייה לא יזהה אגרוף של 120 אלפיות שנייה, ושום כיול לא יציל אותו.

איך מתקינים

  1. צרו תיקייה בשם camera-control בתוך ‎.claude/skills/‎ בפרויקט, או בתיקיית הבית לשימוש בכל הפרויקטים.
  2. שמרו בתוכה את הקובץ בשם SKILL.md.
  3. זהו. אין צורך להפעיל כלום, והוא ייטען לבד כשהמשימה תתאים לתיאור.