Skip to content

About

Hover a thumbnail to expand the image or play the video beside your cursor. Chrome + Firefox, Manifest V3.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Hoverglass

Chrome Web Store Firefox Add-on

A lightweight browser extension that expands an image or video next to your cursor when you hover over its thumbnail — and plays YouTube/Twitch videos inline on hover. Works in Chromium (Chrome/Edge/Brave) and Firefox from a single Manifest V3 codebase.

Hovering a thumbnail expands the full-size image beside the cursor

Features

  • Hover to expand — the full-size media appears beside the cursor and follows it, repositioning to stay on screen.
  • Hover to play video — hovering a YouTube or Twitch link/thumbnail opens an autoplaying, muted player; direct .mp4/.webm/.gif media plays too.
  • Reddit videos & galleries — hovering a v.redd.it post plays the video; hovering a gallery post shows it with an image count, and the arrow keys step through it.
  • Center to inspect — press the pin key (default Space) to sticky-center the preview for a focused look. Press again to close.
  • PiP / free-flow — press the PiP key (default P) to detach the preview into a floating window you can drag to move and keep on-screen while you scroll and browse the page underneath. Switching in from center or hover is seamless (no reload). Close it with the close key or by pressing the PiP key again.
  • Zoom, pan & resize — + / - zoom in both center and PiP; drag the bottom-right corner to resize. In center mode the scroll wheel zooms, and once you're zoomed in past the viewport, moving the cursor pans around the image so you can inspect any part. A hover preview is dismissed on scroll; under a PiP the page scrolls normally.
  • Close — press the close key (default Esc), or click outside the preview (except in PiP, so page clicks keep working).
  • Right-click to save — right-click an image/video preview to download it.
  • Smart resolution — generic heuristics (srcset, wrapping <a> links, lazy-load data-* attributes, CSS background-image), plus a data-driven rule set (shipped as editable defaults) covering YouTube, Twitch, Twitter/X, Imgur, and Wikimedia/Wikipedia. The resolver itself is site-agnostic; all host knowledge lives in rules. (Reddit videos/galleries are the one exception — they need async post-JSON fetching and shadow DOM traversal, so they stay in a dedicated resolver.)
Detached picture-in-picture Zoomed in to inspect
The preview detached into a floating window in the corner while the page scrolls behind it The preview zoomed large, filling most of the window

Build from source

Install from the Chrome Web Store or Firefox Add-ons if you just want to use it. To build it yourself:

npm install
npm run build      # outputs the loadable extension to dist/
npm run watch      # rebuild on change during development

Icons are checked in under src/icons/.

Load the extension

Chromium: go to chrome://extensions, enable Developer mode, click Load unpacked, and select the dist/ folder. (Enable Allow access to file URLs to test with test/fixtures.html.)

Firefox: go to about:debugging#/runtime/this-firefox, click Load Temporary Add-on, and select dist/manifest.json.

Development

The bundle is built with esbuild; formatting, linting, and unit tests use Prettier, ESLint, and Vitest.

npm run check       # format check + lint + typecheck + tests — run before pushing
npm run format      # apply Prettier (format:check to only verify)
npm run lint        # ESLint (lint:fix to autofix)
npm run typecheck   # tsc --noEmit
npm run test        # Vitest unit tests (test:watch to watch)

A Husky pre-commit hook runs Prettier and ESLint on staged files via lint-staged, so committed code stays formatted and lint-clean.

Settings

Click the toolbar icon for the settings popup. Configurable: the pin, PiP, and close keys (click a button and press any key to rebind), close-on-click-outside, keep-PiP- across-navigation, hover delay, minimum image size, and video previews. The close key is always bound, so the preview can never become impossible to dismiss. Zoom (+/-) and drag-to-resize are fixed defaults. Changes apply live to open tabs.

PiP persistence across in-page navigation depends on how the site rebuilds its DOM, not on this extension; a full page reload always resets it.

Custom rules

Custom rules are the resolution engine: the built-in site behavior ships as the default rule set, and you can edit it. Each rule rewrites the URL a preview resolves to; rules match in order and the first hit wins.

Because the toolbar popup closes when it loses focus (which makes pasting awkward), the rule editor lives in the full settings tab: the popup shows an Edit custom rules in a tab → button that opens it. In the tab, click + Add rule to add a card and fill in its fields.

Field Meaning
host Domain of the media URL to match (includes subdomains), e.g. youtube.com.
match Regex tested against the full URL. Anchor it (^…$) to rewrite the whole URL.
replace Replacement string; $1, $2, … are capture groups; {{host}} is the page's host.
type Auto infers from the result URL; or force Image, Video, or Frame.
pageHost Optional: only apply on pages of this host. Used to give a site page-specific behavior.
disable Optional: when a match hits, suppress the preview entirely (no replace needed).

The match/replace follow JavaScript String.replace semantics. pageHost, {{host}}, and disable handle the cases that need to know where you are:

  • On youtube.com the embed player can't run (YouTube blocks embedding itself, error 152-4) and can't be worked around, so a page-scoped disable rule suppresses the preview there and lets YouTube's own hover autoplay take over. Off YouTube, the nocookie embed player is used.
  • Twitch's parent={{host}} requirement is filled from the page host.

You can add your own disable rules to stop previews on any site that annoys you. Export / Import save and load the rule set as JSON, and Reset to default restores the shipped set.

Testing

Unit tests (Vitest, npm test) cover the pure logic — safe URL parsing, the rule engine and default rules (YouTube on/off site, Twitch, image CDNs), rule parsing/validation, key-label formatting, and a resolveTarget matrix that exercises each popular site and media type end-to-end against DOM fixtures. Layout and zoom behavior depends on real element geometry, so verify those manually in the browser.

For manual testing, open test/fixtures.html for offline samples covering each resolution path (anchor-wrapped, data-src, srcset, background-image), plus network-dependent sections for video files, live site rules, and YouTube/Twitch embeds.

Note on embedded players: YouTube/Twitch previews are shown in an <iframe>, so a page's Content-Security-Policy can block them on some third-party sites.

YouTube refuses to render its /embed/ player inside a youtube.com page (it fails with "video unavailable", error 152-4) and there is no way around it — with a youtube.com referrer it returns 152, without one it returns 153. So on youtube.com the preview is suppressed (a page-scoped disable rule) and YouTube's own hover autoplay takes over; off YouTube the nocookie embed player is used. This is expressed entirely with default rules — see DEFAULT_RULES in src/settings.ts.

Project layout

src/
  manifest.json         Cross-browser MV3 manifest
  api.ts                browser/chrome wrapper + message types
  settings.ts           Settings + DEFAULT_RULES (the built-in rule set) + storage
  background.ts         Cross-origin download & fetch handler
  content/
    index.ts            Hover detection & event wiring
    resolver.ts         Generic candidate collection + rule engine (no site logic)
    reddit.ts           Reddit video & gallery resolution (async; the one exception)
    url.ts              Safe URL-parsing helper
    viewer.ts           Shadow-DOM preview (image / video / iframe)
  options/              Options page
build.mjs               esbuild bundler
test/                   Vitest unit tests + fixtures.html

License

MIT

About

Hover a thumbnail to expand the image or play the video beside your cursor. Chrome + Firefox, Manifest V3.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages