短影音把「67」手勢變成可以看的表演,但大多數影片無法讓觀眾自己量一次。2026 年我想做的是相反的東西:一個 URL、20 秒、立刻知道自己這次算不算數。這篇是開發紀錄,不是產品文案。數字與常數都對得上現在網站上的客戶端。
動機:從「看別人甩」變成「自己量」
手勢挑戰的傳播路徑很短:看 → 模仿 → 再拍。缺的是第三步的可重複測量。手機 App 商店有進入門檻;純鍵盤連擊又跟「67」肢體無關。瀏覽器剛好夾在中間:有相機、有 WebGL、使用者已經在用 Chrome 或 Safari。所以產品決策從第一天就是:免安裝、鏡頭可關、鍵盤當後備、單局短到不會變成體能課。
20 秒不是隨便選的。更長會讓熱節流與疲勞主導分數;更短則連擊視窗(2 秒)還沒穩定。這個長度也適合教室或辦公室「站起來動一下」——細節寫在 20 秒課間/工間。
技術棧(實際出貨,不是願望清單)
| 層 | 選擇 | 為什麼 |
|---|---|---|
| 手部估測 | MediaPipe Tasks Vision 0.10.14(jsDelivr)+ 本機 hand_landmarker.task | 不必自訓模型,瀏覽器就能跑 21 點 |
| 遊戲邏輯 | Vanilla JS 模組(app.js) | 少依賴、可直接對常數除錯 |
| 畫面 | HTML5 Canvas 鏡像預覽 + 骨架 overlay | 玩家看得見模型「以為手在哪」 |
| 排行榜 | Firebase Cloud Firestore(可選提交) | 只存呼號與成績欄位,不是影片 |
| 託管 | Vercel、PWA manifest、Service Worker | 靜態站、可加到主畫面 |
有一份實驗用的 pinch_detector.py 還留在倉庫裡:那是早期用捏合手勢當輸入的草稿,後來放棄,因為「67」的本體是上下交替,不是捏合。公開這件事是為了誠實——產品有死掉的分支,不是一篇完美敘事。
HandTracker:真正在數次數的東西
MediaPipe 只給座標。次數是我自己寫的振盪器。每隻手一個 tracker,掌心 Y 先做低通:
smoothedY = smoothedY × 0.35 + palmY × 0.65
0.65 的新樣本權重偏「跟手走」,否則高速甩會覺得延遲;0.35 的記憶用來壓單幀抖動。方向翻轉且位移超過 handSize × 0.33 才算一次。手掌太小會把門檻 clamp 在正規化 0.06,避免遠距離噪聲刷次數。
這組數字是玩測出來的,不是論文最優解。肩膀大開合看起來很猛,但手容易飛出畫面,模型中途重抓,分數反而低。最後建議玩家:手腕驅動、手掌朝鏡頭、振幅夠跨門檻就好。
為什麼按鍵是 6 與 7
這是雙關,不是人體工學論文。主鍵盤上 6、7 相鄰,可用兩指交替。計分表與鏡頭模式共用:一旦 registerRep() 被叫到,10/20/35/60 與 RPS 帶完全一樣。這讓「練習節奏」可遷移,但絕對分數不該跨模式比誰比較快。見 鍵盤 vs 鏡頭。
失敗過的做法
- 用雲端視覺 API:延遲、成本、隱私都過不了關。放棄。
- 只認單手:「67」是交替。單手高速會變成作弊捷徑。
- 固定像素振幅:坐遠的人永遠跨不過門檻。改成相對手掌大小。
- 大量薄 SEO 文:AdSense 以「缺乏價值的內容」退回。後來把重複短文 301 合併成長文。本篇就是那個教訓的產物。
隱私是產品功能,不是附錄
計次不需要把鏡頭畫面送到我的伺服器。推論在分頁裡跑。排行榜若提交,欄位是呼號、分數、次數、速度、模式、時間戳。拒絕相機仍然能玩鍵盤。完整法律文字在 隱私權政策;給家長與 IT 的操作說明在 鏡頭權限與隱私。
還會改什麼、不會改什麼
會改的:燈光教學、無障礙說明、瀏覽器差異、計分解釋寫得更清楚。不會為了「看起來比較科學」去假裝這是臨床測驗。這是街機式的迷因測量器,加上一份對得上原始碼的說明書。
英文補充:the shipping client uses MediaPipe Hand Landmarker in-browser, a peak–valley detector with EMA 0.35/0.65 and amplitude handSize × 0.33, a 20-second round, and combo bands at 3.5 / 6.0 / 8.5 RPS over a 2-second window. Keyboard 6/7 shares scoring after a rep is accepted. Leaderboard writes are optional and do not include video.