@map-gesture-controls/ol
v0.1.3
Published
Control OpenLayers maps with hand gestures via MediaPipe
Maintainers
Readme
@map-gesture-controls/ol
Control OpenLayers maps with hand gestures. No mouse, no touch, no backend. Point your webcam, make a fist to pan, show two open hands to zoom. Powered by MediaPipe hand-tracking running entirely in the browser. Your camera feed never leaves the device.
Demo
Try it live at sanderdesnaijer.github.io/map-gesture-controls
Install
npm install @map-gesture-controls/ol olQuick start
import Map from 'ol/Map.js';
import View from 'ol/View.js';
import TileLayer from 'ol/layer/Tile.js';
import OSM from 'ol/source/OSM.js';
import { fromLonLat } from 'ol/proj.js';
import { GestureMapController } from '@map-gesture-controls/ol';
import '@map-gesture-controls/ol/style.css';
const map = new Map({
target: 'map',
layers: [new TileLayer({ source: new OSM() })],
view: new View({ center: fromLonLat([0, 0]), zoom: 2 }),
});
const controller = new GestureMapController({ map });
// Must be called from a user interaction (e.g. button click) for webcam permission
await controller.start();
// Later, to tear down:
controller.stop();How it works
- Webcam capture -
GestureControlleropens the camera and feeds each frame to MediaPipe Hand Landmarker, returning 21 3D landmarks per hand. - Gesture classification -
GestureStateMachineclassifies frames in real time: one closed fist means pan, two open palms means zoom, anything else is idle. Dwell timers and grace periods prevent accidental triggers. - Map integration -
OpenLayersGestureInteractiontranslates hand movement deltas intool/Mappan offsets and zoom adjustments, with dead-zone filtering and exponential smoothing for a natural feel.
Gestures
| Gesture | How to perform | Map action | | --- | --- | --- | | Pan | Make a fist with one hand, move it around | Drags the map | | Zoom | Show two open palms, move hands apart or together | Zooms in or out | | Idle | Any other hand position | Map stays still |
Configuration
All options are optional. Defaults work well out of the box.
const controller = new GestureMapController({
map,
webcam: {
position: 'top-left', // overlay corner position
width: 240,
height: 180,
opacity: 0.7,
},
tuning: {
panScale: 3.0, // higher = faster panning
zoomScale: 2.0, // higher = faster zooming
actionDwellMs: 80, // ms before confirming a gesture
releaseGraceMs: 150, // ms grace period after gesture ends
},
debug: true, // log gesture state to console
});See the full configuration reference in the documentation.
Exports
This package re-exports the entire @map-gesture-controls/core API, so you only need one import. On top of core, it adds:
| Export | Type | Description |
| --- | --- | --- |
| GestureMapController | Class | High-level controller that wires gesture detection to an OpenLayers map |
| OpenLayersGestureInteraction | Class | Low-level OL interaction for custom setups |
| GestureMapControllerConfig | Type | Configuration interface |
Use cases
- Museum and exhibit kiosks - visitors explore maps without touching a shared screen
- Accessibility - hands-free map navigation for users with limited mobility
- Live presentations - control a projected map from across the room
- Public displays - touchless interaction in medical, retail, or transit environments
Requirements
- OpenLayers 10.x (
olas a peer dependency) - A modern browser with WebGL,
getUserMedia, and WASM support - Chrome 111+, Edge 111+, Firefox 115+, Safari 17+
Related packages
| Package | Description |
| --- | --- |
| @map-gesture-controls/core | Map-agnostic gesture detection engine (included in this package) |
Documentation
Full docs, live demos, and API reference at sanderdesnaijer.github.io/map-gesture-controls
Privacy
All gesture processing runs locally in the browser. No video data is sent to any server. MediaPipe WASM and model files are loaded from public CDNs.
License
MIT
