The Problem

Touchless interaction with web maps is limited to expensive hardware or proprietary SDKs. Standard mouse and touch controls exclude kiosk, exhibit, and accessibility use cases where users cannot or should not touch a screen. This library solves that with a browser-only, camera-based gesture layer.

What This Does

map-gesture-controls is a TypeScript monorepo that lets users pan, zoom, and rotate OpenLayers and Google Maps views using hand gestures detected via MediaPipe's in-browser WASM. Camera frames never leave the device.

The core logic lives in packages/map-gesture-core/src/, with framework-specific adapters in packages/ol-gesture-controls/ and packages/google-maps-gesture-controls/. The src/ directory contains a legacy copy of the core, likely pre-monorepo. docs/ holds a VitePress site with full API documentation.

How It Is Wired

Execution starts at GestureMapController.ts in each adapter package. The start method (line 75 in the Google Maps version) calls init, attachVideo, mount, and renderLoop — the latter is the hot path. renderLoop calls classifyGesture on each frame, which routes through dist, areAllFingersExtended, and areAllFingersCurled to determine the active gesture.

The GestureStateMachine (in packages/map-gesture-core/src/GestureStateMachine.ts) is the central hub: 13 functions and 5 classes, called from one other file. Its update method is invoked 21 times from the classifier's buildOutput, and transitionTo 14 times — these carry the widest blast radius. The GestureController.ts orchestrates lifecycle (start, stop, destroy), while WebcamOverlay.ts handles DOM mounting and video attachment.

The module graph shows no circular dependencies across 51 files and 66 edges. The types.ts files in both src/ and packages/map-gesture-core/src/ are stable hubs (8 importers each, zero outgoing edges), so changing gesture types will ripple widely.

How To Use It

git clone https://github.com/moses-y/map-gesture-controls
cd map-gesture-controls
npm install
npm run build

For OpenLayers: npm install @map-gesture-controls/ol ol, then import GestureMapController and pass an existing ol/Map instance. For Google Maps: npm install @map-gesture-controls/google-maps @googlemaps/js-api-loader. No environment variables are required; the .env.example is for demo keys. Webcam permission is mandatory.

Real-World Use

A museum kiosk running an OpenLayers exhibit map: instantiate GestureMapController with the map, request camera access, and visitors pan with a fist, zoom with a pinch, and rotate with both hands. The actionDwellMs (80ms) and releaseGraceMs (150ms) constants in packages/map-gesture-core/src/constants.ts are tunable per installation.

Code Health & Issues

Static analysis (not opinion) found:

  • High — Duplicated code: 617 repeated 6-line blocks across 43 files, concentrated in examples/demo-*-gmaps.ts. Extract shared helpers.
  • High — No LICENSE file at root, despite README claiming MIT. Redistribution rights are undefined.
  • High — CI pins googleapis/release-please-action@v4 to a mutable tag. Pin to a commit SHA.
  • Medium — No permissions block in .github/workflows/ci.yml; GITHUB_TOKEN inherits repo defaults.
  • Medium — No Dependabot/Renovate configured for 4 manifests.
  • Medium — No dependency vulnerability scan in CI.
  • Medium — Three GIFs over 5MB in docs/public/ (largest 24.5MB), bloating every clone.
  • Medium — persist-credentials not disabled on checkout in CI.
  • Low — No timeout-minutes on workflow jobs.

Tests exist (7 files) with coverage of classifiers and state machines.

The Bottom Line

Solid, well-structured library with a clean core/adapter split and zero circular dependencies. The duplicated demo code and missing license are real blockers for production use. Worth adopting if you need touchless map interaction and can accept the webcam requirement; the MIT claim in the README needs a license file to be legally enforceable.