Move your hand.Move the Web.

手を動かすだけで、Webはもっと自由になる。

A touchless interaction library for JavaScript & React.JavaScript・Reactのための非接触インタラクションライブラリ。
Your camera · Your device · Your space映像は端末内だけで処理されます

Move your mouse to stir the field. Enable hand tracking to take control.

LIVE DEMO · PUBLISHED PACKAGE公開npmパッケージで動作中 npm install air-cursor air-cursor@2.0.0 ↗ GitHub ↗

Try it. Then build with it.試して、そのままあなたのアプリへ。

Your next click
could be touchless.
次のクリックを、
触れずに。

Enable your camera. Point at the button, bring your thumb to your fingertips, hold briefly, then release your thumb to click. A mouse works here too.カメラを開始し、ボタンにポインターを合わせます。親指を指先に合わせて少し保持し、親指を離すとクリック。マウスでも試せます。

Camera starts only when you choose.カメラはボタンを押すまで起動しません。

A real button. A real event.いつものボタン。同じイベント。

Your first click is the beginning.最初のクリックから、はじまる。

A little movement. A new way in.手の動きから、新しい体験へ。

Your hands.
The whole web.
その手で、
Webを動かす。

A webcam, a browser, and you. Try it here, then bring the same gestures to your own interface.必要なのはWebカメラとブラウザだけ。ここで試した操作を、そのままあなたのインターフェースへ。

  1. Start with your cameraカメラを開始

    Press Start above and allow camera access. Face a light source and keep your whole hand in the camera preview.上の「開始」を押し、カメラを許可します。明るい場所で、プレビューに手全体が映るようにしてください。

  2. Point, then click指を合わせて操作

    Join your right index and middle fingertips to move the pointer. Bring in your thumb, hold briefly, then release to click; keep holding to drag.右手の人差し指と中指を合わせて移動。親指も合わせて少し保持し、離すとクリック。保持したまま動かすとドラッグできます。

  3. Make yourself at homeいつものUIで試す

    Explore the gesture guide and live demo below. Press Stop whenever you are done to release the camera.下のジェスチャーガイドとデモで、スクロールや範囲選択も体験できます。終了時は「停止」でカメラをオフに。

Camera access needs HTTPS or localhost. The model downloads on first use; video is processed on your device.カメラにはHTTPSまたはlocalhostが必要です。初回はモデルをダウンロードし、映像は端末内で処理します。

Gestures

Five gestures. Two hands.5つの操作。2つの手。

RIGHT HAND右手
Index and middle fingertips together

Pointerポインター

Join your index and middle fingertips. Move your hand to point.人差し指と中指の先を合わせ、手を動かしてポインターを操作します。

RIGHT HAND右手
Pointer gesture with thumb open Thumb joins the pointer gesture

Click & dragクリック・ドラッグ

From Pointer, bring in your thumb, hold briefly, then release it to click. Keep the three fingertips together to drag.親指を合わせて少し保持し、離すとクリック。3本を合わせたまま動かすとドラッグします。

RIGHT HAND右手
Thumb and index finger pinched with other fingers open

Grab & scrollつかんでスクロール

Pinch thumb and index only, keeping the other fingers apart. Move to scroll the page.他の指を離したまま親指と人差し指だけをつまみ、手を動かしてスクロールします。

LEFT + RIGHT HAND左手+右手
Both thumb-and-index pinches meeting at one point Hands spread to opposite corners to frame a screenshot

Select a screenshot areaスクリーンショット範囲を選択

Meet both pinches at one point, then spread to opposite corners. Open both hands to freeze the selection, then pinch once with each hand to capture it. Wait without confirming to cancel.両手のつまみを一点で合わせ、対角方向へ広げます。両手を開いて範囲を固定し、左右それぞれでもう一度つまむと撮影します。確定せず待つと解除されます。

LEFT + RIGHT HAND左手+右手
Left hand closed into a fist Right hand click gesture RIGHT CLICK右クリック

Right click modifier右クリック修飾

Hold your left hand in a fist, then click with your right hand. The click becomes a right click.左手を握ったまま右手でクリックすると、右クリックとして送出されます。

Product-ready demo

Your existing interface, now touchless.

These panels listen the way ordinary application code listens — not the way a demo would be written to flatter a gesture library. Start the camera above and work through them. Your mouse drives them too, so you can compare.

A plain div

Not a button, not a link. Just <div onClick> — the case a tag whitelist can never reach.

Click me
0

Hover

Driven by pointerenter and pointerleave, the events tooltips and menus rely on.

Point at me

Right click

Make a fist with your off hand, then click. Fires a real contextmenu.

Right click me
0

Drag

Pinch and hold, then move. A pointerdown → pointermove → pointerup sequence.

0%

Nested scroll

Grab inside the panel and the panel scrolls, not the page.

    Region capture

    Pinch with both hands to frame an area, open them, then tap once with each hand. Wait without confirming to cancel. The crop lands here, and the result is reported next to your hands.

    Nothing framed yet
    0

    Install

    One install. A new input.

    npm install air-cursorView package ↗npmで見る ↗

    The component renders a start button and handles the consent step and camera preview. Once a visitor grants access, the rest of your page becomes operable by hand — you change nothing else.

    // React
    import AirCursor from 'air-cursor';
    
    export default function App() {
      return <AirCursor />;
    }

    The engine has no React dependency, so plain JavaScript, Vue and Svelte are all first-class. The individual pieces — VirtualPointer, GrabScroller, TwoHandRecognizer, OneEuroFilter — are exported too, if you want your own mapping.

    // anything else
    import { AirCursorEngine } from 'air-cursor';
    
    const engine = new AirCursorEngine({
      video: document.querySelector('video'),
      // The same lightweight settings as this demo
      inferenceFps: 24,
      hands: { modelComplexity: 0 },
      camera: { width: 480, height: 360 },
      onState: (s) => console.log(s?.mode),
    });
    await engine.start();

    Built for your web stack

    Real pointer events. No custom interaction layer.

    Most webcam gesture libraries find an element with elementFromPoint and dispatch a single click. That covers buttons and links and nothing else. AirCursor synthesizes what a real pointing device produces, so behaviour that depends on the sequence works — including in Radix, MUI and every pointer-based drag library, which listen on pointerdown rather than click.

    InteractionEvents emitted
    Hoverpointerout → pointerleave → pointerover → pointerenter
    Movepointermove, mousemove
    Clickpointerdown → mousedown → pointerup → mouseup → click
    Right clickpointerdown{button:2} → pointerup → contextmenu
    Dragpointerdown → pointermove… → pointerup, captured to the press target

    Steady enough to aim with

    Pointer position runs through a One Euro filter, which smooths hard when the hand is still and barely at all when it moves fast. Gesture booleans use separate enter and exit thresholds plus a hold window, so a hand resting on a threshold cannot chatter and poses passing through on the way somewhere else do not fire.

    Every threshold is measured in hand units — wrist to middle-finger knuckle — so a gesture reads the same close to the camera or across the room.

    Smooth even when tracking stutters

    Inference and actuation are separated. MediaPipe runs at whatever rate the CPU allows and that rate fluctuates; scrolling, cursor movement and physics run on requestAnimationFrame instead.

    The galaxy runs in a rendering worker where supported. While the camera is active, the page lowers rendering cost to leave more room for hand interaction.

    Known limits

    What a synthetic pointer cannot do.

    These are properties of the browser platform, not gaps waiting to be filled. They are listed here rather than discovered later.

    FAQ

    Before you build.導入する前に。

    How do I add hand tracking to a React app?Reactアプリへハンドトラッキングを追加するには?

    Run npm install air-cursor, import AirCursor, and render <AirCursor />. Visitors start the camera themselves. Your existing click and pointer handlers receive the gesture events.npm install air-cursor で導入し、AirCursorをimportして <AirCursor /> を配置します。利用者がカメラを開始すると、既存のクリック・ポインターハンドラへイベントが届きます。

    Can I use it with vanilla JavaScript?通常のJavaScriptでも使えますか?

    Yes. Import AirCursorEngine from the same package and pass a video element. The engine works without a React UI. This demo uses that public engine API; the code above shows the setup.同じパッケージから AirCursorEngine をimportし、video要素を渡します。エンジンはReactのUIなしでも利用でき、このデモも同じ公開APIを使っています。設定例は上の導入コードをご覧ください。

    Does the camera video leave my device?カメラ映像は外部へ送信されますか?

    Hand tracking runs in the browser. Video and hand landmarks are not uploaded. The first start downloads the MediaPipe model; self-hosting its assets is supported through mediapipeBasePath.手の認識はブラウザ内で行い、映像や手の座標を送信しません。初回起動ではMediaPipeモデルをダウンロードします。mediapipeBasePath でモデルを自分のサーバーから配信することもできます。

    How do I cite AirCursor?AirCursorを引用するには?

    Copy the BibTeX entry below for your paper or project. Citation is appreciated and optional. Include the version you used, and link to the repository so others can reproduce your work.下のBibTeXをコピーして論文やプロジェクトにお使いください。引用は任意ですが、していただけると幸いです。再現できるよう、使ったバージョンとリポジトリへのリンクを記載してください。

    Citation

    Using it in something?

    AirCursor is MIT licensed, so you are free to use it however you like. If it ends up in a product, a paper or a project you publish, a citation is appreciated.

    Install from npm ↗npmから導入 ↗Build freely. Credit the tool.自由に作る。使ったツールを引用する。
    @software{ishikawa2026aircursor,
      author  = {Ishikawa, Ritsuki},
      title   = {{AirCursor}: A Touchless Pointer for the Web},
      year    = {2026},
      version = {2.0.0},
      url     = {https://github.com/ritsuki-i/AirCursor}
    }