A complete, single‑page HTML application that turns your PC’s USB webcam into a feature‑rich CCTV system. It runs entirely in your browser, with no server or external dependencies – just open the file and start recording.
- Live Webcam Feed – View your camera in real time.
- Motion Detection – Adjustable sensitivity threshold with visual indicator and sound alerts.
- Three Recording Modes:
- Continuous Loop – Records in segments; oldest footage is automatically overwritten when storage is full.
- Motion Detection – Records only when motion occurs, with configurable pre‑record (buffer) and post‑record durations.
- Clip & Snap – Captures JPEG snapshots at a fixed interval (e.g., every 1 second).
- Sound Alerts – Play a sound on motion detection (built‑in beep or upload your own MP3/WAV/OGG file).
- Local Storage & Playback – All recordings are saved in the browser’s IndexedDB. Browse, play, download, or delete footage from the built‑in gallery.
- Favorites – Mark important clips as favourites to prevent them from being overwritten.
- Storage Management – Set a maximum storage limit (in GB) and choose the overwrite policy (oldest, ask, or stop when full).
- Video Quality Control – Choose between Low (480p), Medium (720p), or High (1080p) resolution.
- Persistent Settings – All preferences are stored locally and survive page reloads.
- Keyboard Shortcuts –
Spaceto start/stop recording,Mto toggle motion detection,Escto close panels.
- Download the
index.htmlfile (or copy the entire code into a new HTML file). - Open it in a modern browser (Chrome, Edge, Firefox, or Opera).
- Grant camera permissions when prompted.
- The live feed will appear. Use the control bar at the bottom to start recording, toggle motion detection, or take a snapshot.
- Continuous Loop: Records indefinitely. Segments are saved every 60 seconds. When the storage limit is reached, the oldest non‑favourite clips are removed.
- Motion Detection: Recording starts when motion is detected (based on the threshold). The clip includes the configured number of seconds before and after the motion event.
- Clip & Snap: Instead of video, the system saves JPEG images at the chosen interval. Ideal for low‑storage or time‑lapse scenarios.
- Click the Gallery button (📂) in the top right.
- Browse thumbnails of all recordings (video or image).
- Use the search bar to filter by name.
- Toggle the Favourites filter to show only protected clips.
- For each item, you can:
- Play the video (or view the image) in a modal.
- Mark as favourite (⭐) – prevents automatic overwriting.
- Download the file to your device.
- Delete it permanently.
Access all configurable options via the Settings button (⚙️) in the header.
| Setting | Description |
|---|---|
| Motion Detection Threshold | Sensitivity (1–20). Higher values require more pixel change to trigger motion. |
| Sound Alert | Enable/disable the audio alert. Upload a custom MP3/WAV/OGG file and adjust volume. |
| Recording Mode | Choose between Continuous, Motion Detection, or Clip & Snap. |
| Pre‑/Post‑record (Motion mode) | Seconds of video to include before and after a motion event. |
| Video Quality | Low (640×480), Medium (1280×720), or High (1920×1080). |
| Storage Limit | Maximum space (in GB) the app may use. |
| Overwrite Policy | What to do when storage is full: overwrite oldest, ask the user, or stop recording. |
| Snap Interval (Snap mode) | Time between snapshots (in seconds). |
| Snapshot Quality | JPEG compression level (70–100%). |
All settings are saved automatically.
Space– Start / Stop recordingM– Toggle motion detection on/offEsc– Close any open panel (Settings, Gallery, Playback)
The application is a single HTML file containing embedded CSS and JavaScript. It uses:
- WebRTC (
getUserMedia) – to capture the webcam stream. - MediaRecorder API – to record video in WebM format (VP9/Opus).
- Canvas 2D – for motion detection (frame differencing) and snapshot generation.
- IndexedDB – for persistent storage of video blobs and metadata.
- Web Audio API – for generating and playing alert sounds.
Each recording is stored as an object in IndexedDB with the following structure:
{
id: string, // unique identifier
type: 'video' | 'image', // media type
mode: 'continuous' | 'motion' | 'snap', // recording mode
timestamp: number, // Date.now() at creation
blob: Blob, // the actual video/webm or image/jpeg data
size: number, // blob size in bytes
favorite: boolean, // protected from overwrite
name: string, // human‑readable label
dataUrl?: string // (for images) base64 data URL for preview
}- When a new recording is added, the total storage usage is checked.
- If the limit is exceeded, the
overwritePolicydetermines the action:'oldest'– deletes the oldest non‑favourite recordings until enough space is freed.'ask'– prompts the user before deleting anything.'stop'– aborts the recording and shows an alert.
- Each frame is converted to grayscale and compared with the previous frame.
- The average absolute pixel difference is computed (downsampled for performance).
- If the average difference exceeds the threshold, motion is flagged.
- A cooldown period prevents repeated triggers within the same event.
- The default sound is a 800 Hz sine beep.
- Users can upload a custom audio file (MP3, WAV, OGG). The file is read as a base64 Data URL and decoded via the Web Audio API.
- The volume is controlled by a gain node.
- Motion detection runs on
requestAnimationFrameand samples only every 4th pixel to reduce CPU load. - Video recording uses a 1‑second timeslice to generate manageable chunks.
- For the Continuous mode, recordings are assembled into 60‑second segments to keep file sizes reasonable.
- The gallery renders thumbnails using object URLs; these are revoked when no longer needed.
- Requires a browser that supports:
getUserMedia(WebRTC)MediaRecorderwithvideo/webm;codecs=vp9,opus(Chrome, Edge, Firefox)- IndexedDB
- ES6+ (classes, arrow functions, async/await)
- Web Audio API (for sound)
- Tested on Chrome 90+, Edge 90+, Firefox 88+, Opera 76+.
- Not supported on Safari (older versions may lack VP9 support for MediaRecorder).
- To add a new recording format, modify the
MediaRecordermimeType and update the blob handling. - For cloud backup, integrate with the Storage Access API or add a sync button that uploads recordings to a remote server.
- To add more sophisticated motion detection (e.g., object tracking), replace the frame‑differencing logic with a TensorFlow.js model.
Because the entire application is contained in a single HTML file, there is no traditional folder structure. However, the code is organised into logical sections:
- HTML – main layout, panels, and controls.
- CSS – fully responsive dark theme with custom scrollbars.
- JavaScript – divided into:
- DOM references and state
- IndexedDB helpers
- Settings management
- Webcam and motion detection
- Recording and snapshot logic
- Gallery and playback
- UI event binding
- Initialisation
None – all code is vanilla JavaScript. No external libraries, frameworks, or CDN resources are required.
You can tweak several constants at the top of the JavaScript section:
DB_NAME– IndexedDB database name.DB_VERSION– database version (increase on schema changes).STORE_NAME– object store name.MAX_CHUNK_SECONDS– timeslice for MediaRecorder (default 1 second).DEFAULT_SETTINGS– default values for all user preferences.
- Performance – Motion detection can be CPU‑intensive on low‑power devices. Lower the resolution or increase the downsampling step to improve performance.
- Audio – The MediaRecorder does not capture audio from the microphone (only video). This is intentional for simplicity.
- Safari – On macOS, Safari may not support the VP9 codec; you can change the mimeType to
'video/mp4'(if supported) or fallback to'video/webm;codecs=vp8'. - Storage – IndexedDB quotas vary by browser (typically ~50% of free disk space). The app enforces its own limit, but the browser may still prevent further writes.
- Add motion‑zone masking (ignore specific areas).
- Support for multiple cameras.
- Export recordings to external drives via the File System Access API.
- Push notifications or email alerts on motion.
- Time‑lapse mode with video output from snapshots.
- Dark/light theme toggle.
- Multi‑language support.
This project is provided as‑is under the MIT License. You are free to use, modify, and distribute it for personal or commercial purposes. Attribution is appreciated but not required.
Built with ❤️ using the Web Platform. Special thanks to the developers of the MediaRecorder, WebRTC, and IndexedDB standards.
Enjoy your personal CCTV system! 🎥