Control your browser with your eyes. EyeSense uses MediaPipe Face Mesh to detect blinks in real-time via your webcam and fires a mouse click at your cursor position โ all processed locally in the browser, with zero data leaving your device.
eye-blink-extension/
โโโ manifest.json # Chrome Extension MV3 config
โโโ background.js # Service worker โ orchestrates start/stop, tab tracking
โโโ content.js # Injected into active tab โ webcam, MediaPipe, blink logic
โโโ popup.html # Extension popup UI
โโโ popup.css # Popup styles (dark cyberpunk theme)
โโโ popup.js # Popup logic โ settings, stats polling, calibration
โโโ styles-injected.css # CSS injected into tracked tab (overlay, badge, flash)
โโโ icons/
โโโ icon16.png
โโโ icon48.png
โโโ icon128.png
sequenceDiagram
participant U as User
participant C as Camera
participant S as System
participant AI as Eye Model
participant UI as Display
loop Real-Time Tracking
U->>C: Look or move eyes
C->>S: Capture frame
S->>AI: Process frame
AI-->>S: Return eye position
S->>S: Analyze attention
S->>UI: Update state
UI-->>U: Show focus or alert
end
-
Download / clone this folder to your computer.
-
Open Chrome and navigate to:
chrome://extensions -
Enable Developer Mode (toggle in the top-right corner).
-
Click "Load unpacked" and select the
eye-blink-extension/folder. -
The EyeSense icon will appear in your Chrome toolbar.
- Navigate to any regular webpage (not
chrome://pages). - Click the EyeSense icon in the toolbar โ popup opens.
- Click "Start Tracking" โ Chrome will ask for webcam permission; allow it.
- A small webcam overlay appears in the bottom-right of the page showing your face mesh.
- Blink deliberately (hold ~2 frames) to trigger a click at your cursor position.
- Click "Stop Tracking" to disable.
EAR is a single number that describes how "open" an eye is, derived from 6 landmark points:
p2 p3
p1 ยท ยท p4
p6 p5
EAR = (||p2โp6|| + ||p3โp5||) / (2 รใฐใค ||p1โp4||)
- Eye open: EAR โ 0.25โ0.32
- Eye blinking: EAR drops below ~0.21
- Eye closed: EAR < 0.15
Frame N: EAR < threshold โ blink_counter++
Frame N+1: EAR < threshold โ blink_counter++ (= 2 frames, threshold met)
Frame N+2: EAR >= threshold โ BLINK CONFIRMED โ fire click, reset counter
The "Confirm Frames" setting controls how many consecutive closed-eye frames are needed before a blink is registered. Higher values reduce false positives from lighting changes.
| Setting | Default | Description |
|---|---|---|
| Blink Sensitivity (EAR threshold) | 0.21 | Eye must fall below this EAR to count as a blink. Lower = more sensitive. |
| Confirm Frames | 2 | Consecutive low-EAR frames needed to confirm a blink. Higher = more deliberate. |
| Click Cooldown | 600ms | Minimum time between clicks. Prevents rapid-fire accidents. |
| Show Overlay | On | Shows the face mesh landmark canvas in the page corner. |
| Sound Feedback | Off | Plays a short beep when a click is fired. |
- Start Tracking first.
- Open settings โ click "Run Calibration".
- Look at the screen normally for 3 seconds (keep eyes open, don't blink).
- The extension measures your personal baseline EAR and sets the threshold to 75% of that value โ tuned to your eyes and lighting.
| Permission | Why it's needed |
|---|---|
activeTab |
To know which tab to inject the tracker into |
scripting |
To inject content.js and styles-injected.css into the active tab |
storage |
To persist your settings across sessions |
<all_urls> (host permission) |
To allow script injection on any website |
Webcam (getUserMedia) |
Requested at runtime by the content script โ used only for face detection, never recorded or transmitted |
Privacy: All face/eye processing happens in your browser using MediaPipe's WASM model. No video frames, landmarks, or personal data are ever sent to any server.
[Webcam] โ MediaPipe FaceMesh โ landmarks[]
โ
computeEAR(landmarks)
โ
avgEAR < threshold?
โ
consecutiveBlinks >= blinkFrames?
โ
simulateClick(mouseX, mouseY)
โ
MouseEvent dispatched on DOM element
popup.js โโSTART_TRACKINGโโโบ background.js
โ scripting.executeScript(content.js)
โ tabs.sendMessage(INIT_TRACKER)
โผ
content.js (active tab)
โ
โ BLINK_DETECTED โ background.js (badge flash)
โ GET_STATS โ popup.js (live EAR/counts)
| Problem | Solution |
|---|---|
| "Cannot inject into this page" | Navigate to a regular https:// website first |
| Webcam permission denied | Click the camera icon in Chrome's address bar and allow access |
| No face detected | Improve lighting; face the camera directly |
| Too many accidental clicks | Increase Confirm Frames to 3โ4; increase Click Cooldown |
| Blinks not registering | Run Calibration; or manually lower the EAR threshold slider |
| Overlay not visible | Check "Show Overlay" is enabled in settings |
- Gaze Tracking: MediaPipe's
refineLandmarks: trueexposes iris landmarks (indices 468โ477). The iris center can be mapped to screen coordinates via affine transform for cursor control. - Wink detection: Compute EAR for left and right eyes independently โ a left wink vs. right wink could trigger different actions.
- Double-blink for right-click: Track inter-blink timing; two blinks within 400ms โ
contextmenuevent. - Head-nod scrolling: Track the vertical position of the nose tip across frames to detect nods โ scroll events.
- Offscreen document: Move the webcam + MediaPipe into a Chrome Offscreen Document (MV3 API) to avoid injecting a visible overlay into the page.
- WASM caching: Cache the MediaPipe
.wasmand.binmodel files using a service worker cache for faster startup.
- Chrome Extension Manifest V3
- MediaPipe Face Mesh 0.4 (loaded from CDN, runs as WASM in the browser)
- Vanilla JavaScript (no build step required)
- HTML5 Canvas for landmark rendering
- Web Audio API for click sound feedback
MIT โ free to use, modify, and distribute.