Hands-free scrolling for YouTube Shorts, Instagram Reels, TikTok, and vertical video feeds.
Lazy Scroll is a Chrome Manifest V3 extension that turns webcam hand gestures into feed actions. It runs the bundled MediaPipe hand model locally, shows a small on-page control, and only activates on URLs in your allow-list.
- Control vertical feeds without touching the keyboard or mouse.
- Works with YouTube Shorts, Instagram Reels, TikTok, and custom vertical feed pages.
- Uses local MediaPipe Tasks Vision assets from
vendor/; no CDN is required at runtime. - Lets you stop camera tracking from the overlay at any time.
- Routes swipes into comments when comments are open, instead of accidentally moving the main reel.
- Draggable on-page overlay with a built-in gesture cheat sheet (the
?button), a position that persists, and a live "watching" pulse. - Adjustable gesture sensitivity (Low / Medium / High), a configurable seek step, and a master on/off switch in the popup.
- Popup allow-list with one-click Add current page support.
- Ships with Playwright coverage for gestures, settings, overlay behavior, local integration, packaged extension startup, and MediaPipe loading.
| Gesture | Action |
|---|---|
| Point with index finger and swipe up | Next reel or feed item |
| Point with index finger and swipe down | Previous reel or feed item |
| Hold two fingers up or down | Continuous scroll in that direction |
| Hold open palm | Open comments |
| Close palm into fist | Close comments |
| Hold pinky finger up | Like or unlike the active reel |
| Pinch thumb and index, slide right | Seek video forward |
| Pinch thumb and index, slide left | Seek video backward |
When a comments panel is open, swipe gestures scroll the comments surface first. Lazy Scroll looks for nested comments scrollers too, which helps with Instagram-style drawers and dialogs.
- Hand detection runs locally in the browser with the bundled model in
vendor/models/hand_landmarker.task. - The extension requests camera access only after you click Start in the overlay.
- The overlay now has a Stop button so you can immediately stop the camera stream.
- Hand landmarks travel from the tracker frame to the content script over a private
MessageChannel, not public window messages. - The extension stores only your allowed site URL list and gesture settings in
chrome.storage.local, plus the overlay's last position in the page'slocalStorage. - The manifest uses
storageandactiveTab;activeTabpowers Add current page in the popup. - The content script is injected broadly so custom sites can be supported, but the app mounts only when the current URL matches your allow-list.
- Run dependencies once:
npm install- Open
chrome://extensions. - Turn on Developer mode.
- Click Load unpacked.
- Select this project folder.
- Open a supported page such as:
https://www.youtube.com/shorts
https://www.instagram.com/reel
https://www.instagram.com/reels
https://www.tiktok.com
- Click Start in the Lazy Scroll overlay and allow camera access.
The same unpacked extension flow works in Microsoft Edge and other Chromium browsers. Firefox is not supported by this MV3 build.
Open the extension popup from the browser toolbar. The popup has two parts.
Tracking
- Master on/off switch (top right) to enable or pause gestures everywhere without editing the allow-list.
- Gesture sensitivity: Low (fewer accidental triggers), Medium (balanced default), or High (quick and responsive). This tunes swipe/pinch thresholds and cooldowns.
- Seek step: how many seconds a pinch-slide jumps the video (1–30s, default 5).
- Auto-open the gesture guide so the on-page cheat sheet is expanded by default.
Setting changes apply to open allowed tabs immediately — no reload needed.
Allowed pages
- click Add current page to add a smart URL prefix for the active tab
- edit allowed URLs manually
- click Save
- click Reset to restore the defaults
Allowed entries can be exact prefixes, domains, or wildcards:
https://www.youtube.com/shorts
https://www.instagram.com/reel
https://www.tiktok.com
example.com
https://*.demo.test/watch/*
Run the full suite:
npm testExpected result:
25 passed
Useful focused commands:
npm run test:unit
npm run test:e2e
npm run test:extension
npm run auditThe tests start a local server on http://127.0.0.1:4173 and exercise the extension against local pages in test-pages/.
background.js Default allow-list and settings setup plus migrations
content.js URL + enabled gate, route watcher, app mount/unmount, live settings sync
popup.html/css/js Toolbar popup: settings panel and site allow-list editor
manifest.json Chrome MV3 extension manifest
src/app.js Overlay, recognizer, provider, and adapter coordinator
src/gesture-recognizer.js Landmark-to-action gesture recognition (tunable thresholds)
src/mediapipe-provider.js Tracker frame/popup lifecycle and private message channel
src/hand-frame.js Camera startup and MediaPipe hand tracking
src/site-adapter.js YouTube/Instagram/TikTok/page action adapter (configurable seek)
src/site-config.js Allow-list defaults, matching, and current-page suggestions
src/settings.js User settings defaults, sensitivity presets, load/save
src/overlay.js Draggable Start/Stop/status widget with gesture guide
test-pages/ Local vertical feed and extension test pages
tests/ Playwright unit, settings, overlay, integration, and extension tests
vendor/ Bundled MediaPipe runtime, wasm, and hand model
icons/ Extension icons used by Chrome and this README
After loading the extension:
- Confirm the overlay appears only on allowed URLs, and not when the master switch is off.
- Click the
?button and confirm the gesture guide opens; drag the bar and confirm it stays where you drop it after a reload. - Click Start and wait for Watching gestures (the status dot pulses green).
- Swipe up for next and down for previous.
- Hold pinky up and confirm Like or Unlike toggles.
- Hold open palm and confirm comments open.
- Swipe while comments are open and confirm only comments move.
- Close your palm into a fist and confirm comments close.
- Pinch-slide left and right to seek by your configured seek step.
- Change sensitivity or the seek step in the popup and confirm the open tab reacts without a reload.
- Click Stop and confirm the overlay returns to Start.
- If the overlay does not appear, add the page in the popup or click Reset to restore defaults.
- If Start fails, check that camera permission is allowed for the site.
- If Instagram opens a small camera tracker window, keep it open while using gestures.
- If hand detection is unreliable, improve lighting and keep one hand centered in the webcam frame.
- If a site changes its DOM, update selectors in
src/site-adapter.jsand add a local regression test.
lazy commit for today
ISC

