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@v4to a mutable tag. Pin to a commit SHA. - Medium — No
permissionsblock 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-credentialsnot disabled on checkout in CI. - Low — No
timeout-minuteson 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.