simple-movement-detector 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +139 -0
- package/index.d.ts +83 -0
- package/index.js +171 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Mikhail Gorbunov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# simple-movement-detector
|
|
2
|
+
|
|
3
|
+
 [](https://www.npmjs.com/package/simple-movement-detector) [](LICENSE)
|
|
4
|
+
|
|
5
|
+
A zero-dependency browser library that calls your callback when the webcam detects movement.
|
|
6
|
+
|
|
7
|
+
- Zero dependencies
|
|
8
|
+
- One function: `detectMovement(onMovement, config)`
|
|
9
|
+
- ~3 KB, no build step, no WebAssembly, no Web Workers
|
|
10
|
+
- ES module + TypeScript definitions
|
|
11
|
+
|
|
12
|
+
```js
|
|
13
|
+
import { detectMovement } from 'simple-movement-detector';
|
|
14
|
+
|
|
15
|
+
const stop = detectMovement((snapshot) => {
|
|
16
|
+
console.log('Movement detected!', snapshot);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
stop();
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Try the demo
|
|
23
|
+
|
|
24
|
+
- [Full demo](https://web-detect-movement.vercel.app/demo/demo.html) — with config controls, presets, and diff visualization
|
|
25
|
+
- [Minimal demo](https://web-detect-movement.vercel.app/demo/minimal-demo.html) — the smallest possible usage
|
|
26
|
+
- [Spy on your dog](https://web-detect-movement.vercel.app/demo/spy-on-your-dog.html) — records video on movement, downloads after 15s of stillness
|
|
27
|
+
|
|
28
|
+
## When to use it
|
|
29
|
+
|
|
30
|
+
You want a callback when something moves in front of the camera. You don't need a sensitivity matrix, a motion grid, or a per-frame diff image. Common use cases:
|
|
31
|
+
|
|
32
|
+
- Spy on your dog
|
|
33
|
+
- Turn on a light / trigger an action when someone walks into frame
|
|
34
|
+
- Send a snapshot to your server when motion is detected
|
|
35
|
+
- Build a simple security cam, doorbell, or presence detector in the browser
|
|
36
|
+
|
|
37
|
+
### When to use something else
|
|
38
|
+
|
|
39
|
+
If you need **motion analysis** — where motion happened, how much, a per-frame matrix for interactive visualizers — use [Diffy.js](https://github.com/maniart/diffyjs)
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
### 1. Install
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
npm install simple-movement-detector
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2. Detect movement
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
import { detectMovement } from 'simple-movement-detector';
|
|
53
|
+
|
|
54
|
+
const stop = detectMovement((snapshot) => {
|
|
55
|
+
// snapshot is a PNG data URL of the frame where motion was detected
|
|
56
|
+
fetch('/alert', { method: 'POST', body: snapshot });
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
stop();
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 3. (Optional) Tune sensitivity
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
// Catches even tiny motion — a hand waving, a curtain moving
|
|
66
|
+
detectMovement(onMovement, { threshold: 0.02, pixelThreshold: 15, interval: 500 });
|
|
67
|
+
|
|
68
|
+
// The default — a dog walking through frame
|
|
69
|
+
detectMovement(onMovement, { threshold: 0.1, pixelThreshold: 30, interval: 1000 });
|
|
70
|
+
|
|
71
|
+
// Only fires on big motion — a person walking across the frame
|
|
72
|
+
detectMovement(onMovement, { threshold: 0.25, pixelThreshold: 50, interval: 1000 });
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Without a bundler
|
|
76
|
+
|
|
77
|
+
```html
|
|
78
|
+
<script type="module">
|
|
79
|
+
import { detectMovement } from 'https://esm.sh/simple-movement-detector';
|
|
80
|
+
|
|
81
|
+
detectMovement((snapshot) => {
|
|
82
|
+
document.getElementById('img').src = snapshot;
|
|
83
|
+
});
|
|
84
|
+
</script>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Also available via [jsdelivr](https://cdn.jsdelivr.net/npm/simple-movement-detector/+esm) and [unpkg](https://unpkg.com/simple-movement-detector/index.js).
|
|
88
|
+
|
|
89
|
+
## Configuration
|
|
90
|
+
|
|
91
|
+
All options are optional.
|
|
92
|
+
|
|
93
|
+
| Option | Type | Default | Description |
|
|
94
|
+
|--------|------|---------|-------------|
|
|
95
|
+
| `threshold` | `number` | `0.1` | Fraction of pixels (0-1) that must change to trigger. `0.1` = 10%. |
|
|
96
|
+
| `pixelThreshold` | `number` | `30` | Per-pixel avg RGB diff (0-255) for a pixel to count as "changed". Filters camera noise. |
|
|
97
|
+
| `interval` | `number` | `1000` | Milliseconds between checks. |
|
|
98
|
+
| `width` | `number` | `320` | Capture width. Smaller is faster. |
|
|
99
|
+
| `height` | `number` | `240` | Capture height. Smaller is faster. |
|
|
100
|
+
| `videoElement` | `HTMLVideoElement` | — | Existing `<video>` with a stream. If omitted, webcam is launched. |
|
|
101
|
+
| `debugCanvas` | `HTMLCanvasElement` | — | Canvas to draw the diff onto (changed pixels in red). Off by default. |
|
|
102
|
+
|
|
103
|
+
## How it works
|
|
104
|
+
|
|
105
|
+
Every `interval` ms, the library draws the webcam frame to an offscreen canvas and reads the pixels. Each pixel is compared to the previous frame: if the avg RGB diff exceeds `pixelThreshold`, it counts as changed. If changed pixels exceed `threshold * width * height`, `onMovement` fires with a PNG snapshot.
|
|
106
|
+
|
|
107
|
+
Frame buffers are `Uint8ClampedArray` in memory — no `<img>` elements, no PNG encode/decode per frame. The only PNG encode happens when motion is detected.
|
|
108
|
+
|
|
109
|
+
## Browser requirements
|
|
110
|
+
|
|
111
|
+
- Modern browser with `getUserMedia` (Chrome, Firefox, Safari, Edge)
|
|
112
|
+
- **HTTPS or localhost** — camera access is blocked on insecure origins
|
|
113
|
+
- iOS Safari needs `playsinline` (handled automatically)
|
|
114
|
+
|
|
115
|
+
## Common issues
|
|
116
|
+
|
|
117
|
+
### Camera does not start
|
|
118
|
+
|
|
119
|
+
`getUserMedia` only works on `https://` or `http://localhost`. `file://` won't work.
|
|
120
|
+
|
|
121
|
+
### Too many false positives
|
|
122
|
+
|
|
123
|
+
Increase `pixelThreshold` (try 40-50) or `threshold` (try 0.2).
|
|
124
|
+
|
|
125
|
+
### Motion is detected too late
|
|
126
|
+
|
|
127
|
+
Decrease `interval` (try 250ms). Smaller intervals use more CPU.
|
|
128
|
+
|
|
129
|
+
### Motion is never detected
|
|
130
|
+
|
|
131
|
+
Decrease `pixelThreshold` (try 15-20) or `threshold` (try 0.02-0.05). If you pass your own `videoElement`, make sure it has a live `srcObject`.
|
|
132
|
+
|
|
133
|
+
### I want to see what the detector sees
|
|
134
|
+
|
|
135
|
+
Pass a `debugCanvas` in the config. Changed pixels are painted red, unchanged black, every tick.
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
MIT
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for detectMovement.
|
|
3
|
+
*/
|
|
4
|
+
export interface DetectMovementConfig {
|
|
5
|
+
/**
|
|
6
|
+
* Fraction of pixels that must change (0-1) to trigger a movement event.
|
|
7
|
+
* 0.1 means 10% of pixels must differ significantly from the previous frame.
|
|
8
|
+
* @default 0.1
|
|
9
|
+
*/
|
|
10
|
+
threshold?: number;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Per-pixel average RGB difference (0-255) for a single pixel to count as "changed".
|
|
14
|
+
* Filters out camera noise. 30 means a pixel must differ by ~30 in average RGB.
|
|
15
|
+
* @default 30
|
|
16
|
+
*/
|
|
17
|
+
pixelThreshold?: number;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Milliseconds between motion checks.
|
|
21
|
+
* @default 1000
|
|
22
|
+
*/
|
|
23
|
+
interval?: number;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Capture width in pixels. Smaller is faster.
|
|
27
|
+
* @default 320
|
|
28
|
+
*/
|
|
29
|
+
width?: number;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Capture height in pixels. Smaller is faster.
|
|
33
|
+
* @default 240
|
|
34
|
+
*/
|
|
35
|
+
height?: number;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Optional existing `<video>` element already playing a camera stream.
|
|
39
|
+
* If omitted, the webcam is launched automatically via getUserMedia.
|
|
40
|
+
*/
|
|
41
|
+
videoElement?: HTMLVideoElement;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Optional canvas to draw the diff visualization onto (changed pixels in red).
|
|
45
|
+
* Off by default — only allocated when provided, to avoid wasted work.
|
|
46
|
+
*/
|
|
47
|
+
debugCanvas?: HTMLCanvasElement;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Callback invoked when movement is detected.
|
|
52
|
+
* @param snapshot - A PNG data URL of the frame where motion was detected.
|
|
53
|
+
*/
|
|
54
|
+
export type OnMovement = (snapshot: string) => void;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Zero-dependency browser motion detection.
|
|
58
|
+
*
|
|
59
|
+
* Calls `onMovement` with a PNG snapshot whenever the webcam detects movement
|
|
60
|
+
* above the configured threshold. Returns a `stop` function to clean up.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```js
|
|
64
|
+
* import { detectMovement } from 'simple-movement-detector';
|
|
65
|
+
*
|
|
66
|
+
* const stop = detectMovement((snapshot) => {
|
|
67
|
+
* console.log('Movement detected!', snapshot);
|
|
68
|
+
* });
|
|
69
|
+
*
|
|
70
|
+
* // later:
|
|
71
|
+
* stop();
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* @param onMovement - Called with a PNG data URL of the triggering frame.
|
|
75
|
+
* @param config - Optional configuration. All fields have sensible defaults.
|
|
76
|
+
* @returns A `stop` function. Call it to stop detection, clear the interval, and release the camera.
|
|
77
|
+
*/
|
|
78
|
+
export declare function detectMovement(
|
|
79
|
+
onMovement: OnMovement,
|
|
80
|
+
config?: DetectMovementConfig
|
|
81
|
+
): () => void;
|
|
82
|
+
|
|
83
|
+
export default detectMovement;
|
package/index.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* simple-movement-detector
|
|
3
|
+
* Zero-dependency browser motion detection. Calls your callback when the webcam sees movement.
|
|
4
|
+
*
|
|
5
|
+
* @param {function(string): void} onMovement - Called with a PNG data URL of the frame where motion was detected.
|
|
6
|
+
* @param {object} [config]
|
|
7
|
+
* @param {number} [config.threshold=0.1] - Fraction of pixels that must change (0-1) to trigger movement.
|
|
8
|
+
* @param {number} [config.pixelThreshold=30] - Per-pixel average RGB diff (0-255) for a pixel to count as "changed".
|
|
9
|
+
* @param {number} [config.interval=1000] - Milliseconds between motion checks.
|
|
10
|
+
* @param {number} [config.width=320] - Capture width in pixels.
|
|
11
|
+
* @param {number} [config.height=240] - Capture height in pixels.
|
|
12
|
+
* @param {HTMLVideoElement} [config.videoElement] - Optional existing <video> element with a stream. If omitted, the webcam is launched.
|
|
13
|
+
* @param {HTMLCanvasElement} [config.debugCanvas] - Optional canvas to draw the diff visualization onto. Off by default.
|
|
14
|
+
* @returns {function(): void} stop - Call to stop detection, clear the interval, and stop the camera track if we launched it.
|
|
15
|
+
*/
|
|
16
|
+
export function detectMovement(onMovement, config = {}) {
|
|
17
|
+
if (typeof onMovement !== 'function') {
|
|
18
|
+
throw new TypeError('detectMovement: onMovement callback is required');
|
|
19
|
+
}
|
|
20
|
+
if (typeof window === 'undefined' || !navigator || !navigator.mediaDevices) {
|
|
21
|
+
throw new Error('detectMovement must be used in a browser with getUserMedia support');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const width = config.width || 320;
|
|
25
|
+
const height = config.height || 240;
|
|
26
|
+
const interval = config.interval ?? 1000;
|
|
27
|
+
const pixelThreshold = config.pixelThreshold ?? 30;
|
|
28
|
+
const imageThreshold = config.threshold ?? 0.1;
|
|
29
|
+
|
|
30
|
+
if (imageThreshold < 0 || imageThreshold > 1) {
|
|
31
|
+
throw new RangeError('detectMovement: threshold must be between 0 and 1');
|
|
32
|
+
}
|
|
33
|
+
if (pixelThreshold < 0 || pixelThreshold > 255) {
|
|
34
|
+
throw new RangeError('detectMovement: pixelThreshold must be between 0 and 255');
|
|
35
|
+
}
|
|
36
|
+
const changedPixelsRequired = Math.floor(width * height * imageThreshold);
|
|
37
|
+
|
|
38
|
+
// Capture canvas (video -> pixels). Never attached to the DOM.
|
|
39
|
+
const captureCanvas = document.createElement('canvas');
|
|
40
|
+
captureCanvas.width = width;
|
|
41
|
+
captureCanvas.height = height;
|
|
42
|
+
const captureCtx = captureCanvas.getContext('2d', { willReadFrequently: true });
|
|
43
|
+
|
|
44
|
+
// Optional debug canvas for diff visualization. Only allocated if user passes one.
|
|
45
|
+
const debugCanvas = config.debugCanvas || null;
|
|
46
|
+
const debugCtx = debugCanvas
|
|
47
|
+
? debugCanvas.getContext('2d')
|
|
48
|
+
: null;
|
|
49
|
+
|
|
50
|
+
// Two in-memory frame buffers. No <img>, no data URLs, no codec round-trips.
|
|
51
|
+
// ponytail: Uint8ClampedArray views over ImageData.data; we diff these directly.
|
|
52
|
+
let prevFrame = null; // Uint8ClampedArray, length width*height*4
|
|
53
|
+
let currFrame = null; // Uint8ClampedArray, length width*height*4
|
|
54
|
+
|
|
55
|
+
const video = config.videoElement || document.createElement('video');
|
|
56
|
+
// iOS Safari requires these attributes to autoplay a camera stream inline.
|
|
57
|
+
video.setAttribute('autoplay', '');
|
|
58
|
+
video.setAttribute('muted', '');
|
|
59
|
+
video.setAttribute('playsinline', '');
|
|
60
|
+
video.setAttribute('width', String(width));
|
|
61
|
+
video.setAttribute('height', String(height));
|
|
62
|
+
|
|
63
|
+
let timerId = null;
|
|
64
|
+
let launchedStream = null;
|
|
65
|
+
let stopped = false;
|
|
66
|
+
|
|
67
|
+
const stop = () => {
|
|
68
|
+
if (stopped) return;
|
|
69
|
+
stopped = true;
|
|
70
|
+
if (timerId !== null) {
|
|
71
|
+
clearInterval(timerId);
|
|
72
|
+
timerId = null;
|
|
73
|
+
}
|
|
74
|
+
if (launchedStream) {
|
|
75
|
+
launchedStream.getTracks().forEach((t) => t.stop());
|
|
76
|
+
launchedStream = null;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const check = () => {
|
|
81
|
+
if (stopped || video.readyState < 2) return; // not enough data to draw yet
|
|
82
|
+
|
|
83
|
+
// Capture current frame into currFrame.
|
|
84
|
+
captureCtx.drawImage(video, 0, 0, width, height);
|
|
85
|
+
const imageData = captureCtx.getImageData(0, 0, width, height);
|
|
86
|
+
currFrame = imageData.data;
|
|
87
|
+
|
|
88
|
+
// Need two frames to diff. First frame just primes prevFrame.
|
|
89
|
+
if (prevFrame === null) {
|
|
90
|
+
prevFrame = new Uint8ClampedArray(currFrame); // copy
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const data1 = prevFrame;
|
|
95
|
+
const data2 = currFrame;
|
|
96
|
+
let changedPixels = 0;
|
|
97
|
+
|
|
98
|
+
// Diff loop. Stepping by 4 over RGBA bytes.
|
|
99
|
+
// ponytail: plain for-loop over a typed array is the fastest portable option;
|
|
100
|
+
// no SIMD/WebAssembly — keeps the zero-dep, no-build promise. Ceiling: 320*240=76.8k px per tick,
|
|
101
|
+
// trivial at 1Hz. Upgrade path: Web Worker if interval drops below ~100ms.
|
|
102
|
+
for (let i = 0; i < data2.length; i += 4) {
|
|
103
|
+
const rDiff = Math.abs(data1[i] - data2[i]);
|
|
104
|
+
const gDiff = Math.abs(data1[i + 1] - data2[i + 1]);
|
|
105
|
+
const bDiff = Math.abs(data1[i + 2] - data2[i + 2]);
|
|
106
|
+
if ((rDiff + gDiff + bDiff) / 3 > pixelThreshold) {
|
|
107
|
+
changedPixels++;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Optional debug visualization: paint changed pixels red, others black.
|
|
112
|
+
if (debugCtx) {
|
|
113
|
+
const diffImageData = debugCtx.createImageData(width, height);
|
|
114
|
+
const diffData = diffImageData.data;
|
|
115
|
+
for (let i = 0; i < data2.length; i += 4) {
|
|
116
|
+
const rDiff = Math.abs(data1[i] - data2[i]);
|
|
117
|
+
const gDiff = Math.abs(data1[i + 1] - data2[i + 1]);
|
|
118
|
+
const bDiff = Math.abs(data1[i + 2] - data2[i + 2]);
|
|
119
|
+
const changed = (rDiff + gDiff + bDiff) / 3 > pixelThreshold;
|
|
120
|
+
diffData[i] = changed ? 255 : 0;
|
|
121
|
+
diffData[i + 1] = 0;
|
|
122
|
+
diffData[i + 2] = 0;
|
|
123
|
+
diffData[i + 3] = 255;
|
|
124
|
+
}
|
|
125
|
+
debugCtx.putImageData(diffImageData, 0, 0);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Roll currFrame into prevFrame for the next tick (copy, since currFrame is a view
|
|
129
|
+
// into a reused ImageData buffer that getImageData may overwrite).
|
|
130
|
+
prevFrame.set(currFrame);
|
|
131
|
+
|
|
132
|
+
if (changedPixels > changedPixelsRequired) {
|
|
133
|
+
// Hand the caller a PNG snapshot of the frame that triggered.
|
|
134
|
+
// This is the only data-URL encode in the whole pipeline, and only fires on motion.
|
|
135
|
+
onMovement(captureCanvas.toDataURL('image/png'));
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const startPolling = () => {
|
|
140
|
+
if (timerId !== null) return;
|
|
141
|
+
timerId = setInterval(check, interval);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
if (config.videoElement && config.videoElement.srcObject) {
|
|
145
|
+
// Caller provided an already-streaming <video>. Just poll.
|
|
146
|
+
startPolling();
|
|
147
|
+
} else {
|
|
148
|
+
// Launch the webcam ourselves. Side effect lives here, not in the diff loop.
|
|
149
|
+
navigator.mediaDevices
|
|
150
|
+
.getUserMedia({ video: true, audio: false })
|
|
151
|
+
.then((stream) => {
|
|
152
|
+
if (stopped) {
|
|
153
|
+
// User called stop() before the camera permission resolved. Clean up.
|
|
154
|
+
stream.getTracks().forEach((t) => t.stop());
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
launchedStream = stream;
|
|
158
|
+
video.srcObject = stream;
|
|
159
|
+
video.play();
|
|
160
|
+
startPolling();
|
|
161
|
+
})
|
|
162
|
+
.catch((err) => {
|
|
163
|
+
stop();
|
|
164
|
+
throw err;
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return stop;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export default detectMovement;
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "simple-movement-detector",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"description": "A zero-dependency browser library that calls your callback when the webcam detects movement",
|
|
6
|
+
"author": "Mikhail Gorbunov <toplenboren@gmail.com>",
|
|
7
|
+
"main": "index.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./index.js",
|
|
11
|
+
"default": "./index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"types": "index.d.ts",
|
|
15
|
+
"files": [
|
|
16
|
+
"index.js",
|
|
17
|
+
"index.d.ts",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"release": "clean-pkg-json && npm publish"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"motion-detection",
|
|
26
|
+
"movement",
|
|
27
|
+
"webcam",
|
|
28
|
+
"camera",
|
|
29
|
+
"browser",
|
|
30
|
+
"zero-dependency",
|
|
31
|
+
"getUserMedia"
|
|
32
|
+
],
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/toplenboren/simple-movement-detector.git"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"clean-pkg-json": "^1.2.1"
|
|
40
|
+
}
|
|
41
|
+
}
|