Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Audience Mirror

Release License: MIT

A Chrome extension for presenting from a coffee-table setup: keep working on your laptop screen while a thin external display, facing the audience, shows a live mirror of the tab you're in — no cables, no screen-share overlays, no letting them see your other tabs.

Click the toolbar icon on the tab you're working in. It pops that tab into a separate, chrome-free window streaming a live, real-time copy. Drag that window onto the second display.

Install

The extension is not on the Chrome Web Store — it loads unpacked, which Chrome supports natively. Two ways to get the files:

Option A — download a release (recommended)

  1. Go to Releases and download audience-mirror-ext-vX.Y.Z.zip.
  2. Unzip it. You'll get a folder containing manifest.json.
  3. Open chrome://extensions in Chrome.
  4. Turn on Developer mode (top right).
  5. Click Load unpacked and select the unzipped folder.

Keep the unzipped folder where it is — Chrome loads the extension from that path on every startup. Deleting or moving it disables the extension.

Option B — clone the repo

git clone https://github.com/clue2solve/audience-mirror-ext.git

Then follow steps 3–5 above, selecting the extension/ folder inside the clone.

Either way, pin the icon to your toolbar for one-click access (puzzle-piece icon → pin).

To update, download the newer release and replace the folder's contents, then click the reload arrow on the extension's card in chrome://extensions.

Works on Chrome and Chromium-based browsers (Edge, Brave, Arc) recent enough to support Manifest V3 service workers and chrome.tabCapture.

Use

  1. Go to the tab you want the audience to see, on your laptop screen.
  2. Click the Audience Mirror toolbar icon (or Cmd+Shift+M on Mac, Ctrl+Shift+M elsewhere).
  3. With two displays connected, it automatically:
    • resizes your current window to match the external display's aspect ratio (as large as fits on your screen)
    • opens the mirror window sized to exactly cover the external display
  4. Drag the mirror window fully onto the external display if it doesn't land there on its own, then click Fullscreen (or press F).
  5. Keep working in your original tab — the mirror follows automatically, including navigation to new URLs within that tab.

Because both windows now share the same aspect ratio, the mirror should fill the display edge-to-edge with no letterboxing. Which display counts as "external" is whichever one your current window isn't on — with only one display connected, the resize step is skipped and it falls back to a plain 960×600 window. With three or more displays connected it picks the first one that isn't yours, which may not be the right guess.

If you still see black bars or don't want any part of the frame cropped, click Fill (or press C) to crop instead of letterbox — but with matched aspect ratios you shouldn't need it.

Clicking the icon again while the mirror is open just refocuses the existing mirror window instead of opening a second one.

Shortcuts

Key Where Action
Cmd+Shift+M / Ctrl+Shift+M Any tab Open or focus the mirror for the current tab
F Mirror window Toggle fullscreen
C Mirror window Toggle Fit (letterbox) / Fill (crop)

The Cmd+Shift+M binding can be changed at chrome://extensions/shortcuts.

How it works

chrome.tabCapture.getMediaStreamId() hands a stream id from the background service worker to the mirror window, which turns it into a MediaStream via getUserMedia and plays it in a <video> element. It's tab-level capture, so it follows in-tab navigation automatically — no custom event-relay code needed for clicks, typing, or scrolling.

Permissions requested, and why:

Permission Why
tabCapture Produce the live video stream of the source tab
activeTab Identify the tab you clicked the icon on
storage Remember your Fit/Fill preference
system.display Read display geometry to size both windows

Nothing leaves your machine — there is no network code, no analytics, and no remote endpoint anywhere in this extension.

Notes

  • Video only — no tab audio is captured, so there's no echo risk on a shared table.
  • To mirror a different tab, close the mirror window and click the icon again from that tab.
  • Capture stops automatically if the source tab closes; the mirror window shows "Source tab closed" rather than freezing on a stale frame.
  • Chrome refuses to capture chrome:// pages and the Web Store, so the mirror stays blank on those tabs.

Repo layout

extension/          the loadable extension
  manifest.json     MV3 manifest, permissions, keyboard shortcut
  background.js     service worker: window layout + stream handoff
  mirror.html/js/css  the mirror window
  icons/            toolbar and store icons
  make_icons.py     regenerates the PNG icons
.github/workflows/release.yml  tag → zipped GitHub Release

There is no build step — the source in extension/ is what Chrome loads. To hack on it, edit the files and hit reload on the extension card in chrome://extensions.

Contributing

Issues and pull requests are welcome. Keep changes scoped to the existing vanilla-JS, no-dependency setup, and add a CHANGELOG.md entry with user-visible behavior changes.

Releasing (maintainers)

  1. Bump version in extension/manifest.json and add a CHANGELOG.md entry.

  2. Commit, then tag and push:

    git tag v1.3.0
    git push origin main --tags

Pushing a tag matching v*.*.* triggers .github/workflows/release.yml, which zips the extension/ folder and publishes it as a GitHub Release with auto-generated notes.

License

MIT — see LICENSE.

About

Chrome extension: pop the current tab into a live mirror window you can drag onto an audience-facing display.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages