# AirDesk Web Starter 0.1.0

Add hand-friendly controls to an existing app without running another camera model.

**This is a UI starter kit, not a hand-tracking SDK.** AirDesk for Windows performs local hand recognition and sends ordinary desktop mouse/keyboard input. Your app receives its usual input events. This optional, dependency-free helper maps explicitly labelled buttons to your application's named actions. It does not detect AirDesk, distinguish a hand from a mouse, expose landmarks or open the camera.

## Choose the smallest integration

| Your project | Recommended starting point |
| --- | --- |
| No-code app or kiosk | Keep normal buttons and your builder's existing click workflows. Install AirDesk on the Windows device; no SDK or page script is required. |
| Low-code / custom HTML | Adapt `examples/embed.html`. Use the helper only if your page needs named action events. |
| JavaScript / full-stack | Use `airdesk.js` and its TypeScript declarations, or simply keep existing click handlers. Route business actions through your existing authenticated backend. |
| React | Copy `examples/ReactExample.tsx` into your React project, with the module, declarations and optional stylesheet beside it. |

The desktop runtime is a separate download from [AirDesk](https://airdesk-preview.seelenbinder.chatgpt.site). The helper can be tried with mouse/keyboard on a modern browser without installing the runtime. Actual hand control requires the Windows app, a working camera, explicit **Start control**, and suitable visibility/lighting. Other operating systems and embedded wearable cameras are not currently supported by the desktop runtime.

## Run the working example

1. Extract this ZIP.
2. With Node.js 22 or later installed, run `node serve.mjs` in the extracted folder. No npm install is needed to run the example.
3. Open the printed local URL, normally `http://127.0.0.1:5174`.
4. Use **Next step**, **Back** and **Start again**. Mouse/keyboard work immediately. For hand input, run AirDesk separately and choose **Start control**.

The server serves only the five example files on loopback. It has no API, proxy, upload or backend. Stop it with Ctrl+C. If that port is occupied, set the `PORT` environment variable to another port. You can instead use your existing static development server. ES modules should be served over HTTP(S), not opened as `file://` files.

## Copy into your app

```html
<section id="viewer" data-airdesk>
  <button type="button" data-airdesk-action="next">Next page</button>
</section>
<script type="module">
  import { AIRDESK_EVENT, mountAirDesk } from "/airdesk/airdesk.js";
  const root = document.querySelector("#viewer");
  root.addEventListener(AIRDESK_EVENT, ({ detail }) => {
    if (detail.action === "next") {
      // Call your existing page-navigation handler here.
    }
  });
  const dispose = mountAirDesk(root);
  // On SPA unmount: dispose(), and remove your action listener.
</script>
```

Host `airdesk.js`, `airdesk.d.ts` and optional `airdesk.css` under your own application's `/airdesk/` directory, or adapt the import paths. Self-hosting avoids a dependency on the promotional site. The downloadable HTML example includes working page state, not just a placeholder handler. `airdesk.css` is opt-in under `[data-airdesk]`; override its documented CSS variables to fit your brand. It does not restyle the rest of your application.

**Use either your existing click handler or the named action event to perform an operation. Do not invoke the same operation from both.** AirDesk supplies point-and-pause clicking already: a second dwell timer on the page would cause delays or duplicate actions. Ordinary scrolling, right-click and drag/drop remain the responsibility of the underlying app/browser; this small helper does not synthesize those gestures.

## Event contract

- `mountAirDesk(root: HTMLElement)` mounts one delegated click listener and returns an idempotent cleanup function. Importing the module is safe during server rendering; mounting must happen on the client.
- Native `<button type="button" data-airdesk-action="next">` controls emit a bubbling `airdesk:action` CustomEvent from the button, with immutable detail `{ version: 1, action: "next", value: null }`.
- Optional `data-airdesk-value` is a string of at most 256 characters. Action names must match `/^[a-z][a-z0-9:_-]{0,63}$/`. Invalid attributes are ignored. Pass an opaque record identifier, never secrets or personal information.
- Native mouse, keyboard and touch activation follow the browser's normal click path. No custom key listener, gesture timer, input injection, telemetry, storage or network is added. This event is **not evidence** of a hand, user identity or authorization.
- Disabled buttons, disabled fieldsets, `aria-disabled="true"` ancestors and inert content are ignored. Native buttons retain their built-in keyboard behavior. Do not replace them with clickable divs.
- New buttons inserted inside the mounted root work automatically. Controls outside it are unaffected. Mounting the same root twice returns the existing cleanup, rather than adding another listener. Use one lifecycle owner per root.
- A nested mounted root emits only once. Its event still bubbles normally: a parent application listener should check which surface it owns before handling nested events. Iframes and shadow roots are separate integration surfaces; this helper does not cross them.
- Cleanup removes the adapter only, not your own application listeners. React's example removes both and supports the normal Strict Mode mount/cleanup cycle.

## No-code and low-code recipes

**No-code first:** create large, visibly labelled native buttons in your builder, then attach its normal click workflow, such as Next reference, Select category or Open details. AirDesk operates those existing controls. Keep mouse/keyboard available. You do not need to detect hand gestures in the builder, and there is no official AirDesk plugin to install.

**Webflow:** use normal button/link workflows first. If your plan/editor permits a custom HTML embed, host the helper/styles yourself and adapt `examples/embed.html`; it uses a JavaScript module. Test the actual published page, since editor/embed policies vary. See [Webflow's custom-code instructions](https://help.webflow.com/hc/en-us/articles/33961332238611-Custom-code-embed).

**Bubble:** use ordinary button click workflows first. Its HTML element or custom page code can add scripts when needed; adapt the example to your page's lifecycle and unique element IDs. Connecting a custom event back to a builder-specific workflow is your integration's responsibility, not a supplied Bubble plugin. See [Bubble's JavaScript guidance](https://manual.bubble.io/help-guides/getting-started/transitioning-to-bubble-from/javascript).

**n8n / Make / Zapier or another automation service:** trigger your existing authenticated workflow through your application backend or the builder's server-side action. This kit does not install a connector or send webhooks. Never place a secret webhook URL or service credential in a public embed. These are suggested integration patterns, not platform-certified integrations or platform account tests.

## Full-stack boundary

Treat an AirDesk click exactly like any other untrusted browser request. Your existing server owns authentication, authorization for the selected record, CSRF protection, action allowlists, payload validation, rate limits and idempotency. Prefer a fixed endpoint and explicit domain action to forwarding arbitrary action names into commands.

For example: a button emits `reference:next` → your existing client navigation handler advances the reference locally. If recording a completed inspection is needed, present an explicit **Confirm** step, then use your existing authenticated API to validate and save it. A pointer event alone must not approve purchases, machinery movement or safety-critical work. Show pending/success/error state, prevent duplicate submissions, and retry only with the same operation identifier after an uncertain response.

The kit deliberately contains no generic webhook relay or unauthenticated localhost control server. That keeps secrets, business rules and permissions in their existing source of truth. The runtime is not medically certified assistive technology or an industrial safety system.

## Practical acceptance checklist

- Begin with 56px targets and 12px gaps (the optional stylesheet defaults), stable placement and a short list of actions. Test with the actual user rather than treating these sizes as certification.
- Keep ordinary mouse/keyboard behavior and visible focus. Do not make hover the only path to an action. Use normal labels and status feedback.
- Test point-and-pause, scrolling, pickup/release, accidental movement, tracking loss and recovery on the intended hardware. Gloves, lighting, camera position and fatigue can change results.
- Choose **Practice** in AirDesk to learn gestures; practice does not operate the page. Choose **Start control** only when ready to control it. Ctrl+Alt+Space pauses AirDesk.
- Do not add another camera model, duplicate dwell timer or application-wide listener. Keep this integration scoped to the relevant component.
- Verify backend failure/retry and confirmation flows before accepting consequential actions. No recognition-accuracy, latency or accessibility compliance guarantee is implied.

## Version, testing and permission

The current event contract is version 1; the starter kit is 0.1.0 and the separately distributed desktop app is 0.9.2. Pin and self-host the kit in production. `SHA256SUMS.txt` covers the distributed files; the website also publishes the ZIP checksum. Type declarations and examples are included.

To rerun DOM tests, use `npm ci --ignore-scripts` then `npm test`. jsdom is a development-only dependency; no dependency is loaded by the browser module. Tests cover real DOM event dispatch, scoping, invalid/disabled controls, repeat mount/cleanup, dynamic elements, nested roots and the example workflow. DOM emulation does not establish physical hand accuracy, browser keyboard activation, wearable compatibility or operation inside third-party builders.

You may adapt and distribute the **new integration kit** under `LICENSE.txt`, including in commercial applications. This does not publish or license the private AirDesk engine. No npm package, official platform plugin, paid support, raw-pose API or embedded tracking SDK is claimed.
