Hand-tracking pinch

핸드 트래킹 핀치

Reading a thumb-and-index-finger tap via cameras and treating it as "confirm selection" — controller-free input.

Also known as: Pinch gestureIndirect input
···
html
<div class="pw"><div class="target" id="pt"></div></div>
<div class="hand"><div class="tip th" id="th"></div><div class="tip ix" id="ix"></div><div class="lk" id="lk"></div></div>
css
body{background:radial-gradient(circle at 50% 30%,#1c2038,#0a0a12 70%)}
.pw{position:absolute;inset:0;display:grid;place-items:center}
.target{width:clamp(60px,20vmin,90px);height:clamp(60px,20vmin,90px);border-radius:50%;
  background:rgba(255,255,255,.08);border:2px solid rgba(255,255,255,.25);
  display:grid;place-items:center;transition:transform .15s,background .15s,border-color .15s}
.target.hit{transform:scale(.88);background:var(--accent);border-color:var(--accent)}
.hand{position:absolute;left:0;top:0;width:100%;height:100%;pointer-events:none}
.tip{position:absolute;width:14px;height:14px;border-radius:50%;background:#ffd7a8;box-shadow:0 0 0 4px rgba(255,215,168,.2)}
.lk{position:absolute;height:2px;background:rgba(255,215,168,.5);transform-origin:left center}
js
const target=document.getElementById('pt');
const th=document.getElementById('th'), ix=document.getElementById('ix'), lk=document.getElementById('lk');
function place(el,x,y){ el.style.left=x+'px'; el.style.top=y+'px'; el.style.transform='translate(-50%,-50%)'; }
function link(x1,y1,x2,y2){
  const dx=x2-x1, dy=y2-y1, d=Math.hypot(dx,dy), a=Math.atan2(dy,dx);
  lk.style.width=d+'px'; lk.style.left=x1+'px'; lk.style.top=y1+'px'; lk.style.transform='rotate('+a+'rad)';
}
let t=0;
function frame(){
  t+=0.03;
  const cx=innerWidth*0.28, cy=innerHeight*0.66;
  const pinch=(Math.sin(t)+1)/2;
  const gap=26*(1-pinch)+2;
  const x1=cx-gap*0.5, y1=cy-10, x2=cx+gap*0.5, y2=cy+10;
  place(th,x1,y1); place(ix,x2,y2); link(x1,y1,x2,y2);
  target.classList.toggle('hit', pinch>0.92);
  requestAnimationFrame(frame);
}
frame();

Hand-tracking headsets follow finger joint positions with nothing held in the hand. The most common gesture is the pinch — touching thumb tip to index fingertip — which stands in for a mouse click.

What makes a pinch distinct is that it's indirect input. Your hand doesn't need to be anywhere near the on-screen button — gaze decides what's being selected, and the hand can pinch comfortably near your lap. That means UI far across the room can be operated without ever reaching for it.

The demo repeats a thumb-and-index pair closing together (pinch) and pulling apart, and the on-screen target reacts the moment the pinch closes. On a real device, whatever gaze was resting on gets confirmed at that same instant.

When to use

Always pair it with gaze hover. The hand never needs to be at the actual UI location — that is the key contrast with direct touch.