Skip to content
farthestmagePublic

About

Chrome extension (MV3) that covers blocked sites with a full-screen overlay. React + TypeScript, Vite, GitHub Actions CI.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

BLOCKIX

A browser extension that keeps a list of sites you don't want to visit and covers them with a full-screen, undismissable blurred overlay the moment a tab lands there. The page still loads behind the blur — this is a cover, not a redirect — which is what keeps the whole feature to one content script, with no background service worker and no navigation-interception permissions.

The overlay, the popup, and an on-page theme picker all share one user-selected theme (a plain white default, plus 188 palettes lifted from Monkeytype), and the overlay can optionally play looping CRT static behind its wordmark.

Requirements

  • Node.js ^20.19.0 || >=22.12.0 — run nvm use to pick up the pinned version in .nvmrc.
  • A Chromium-based browser (Chrome, Edge, Brave, Arc, …) to load the extension in.

See COMPATIBILITY.md for exact versions this is built and tested against, including the browser-side CSS feature that sets the real minimum Chromium version.

Getting started

git clone https://github.com/farthestmage/EXTENSION_BLOCKER.git
cd EXTENSION_BLOCKER
nvm use          # or otherwise switch to a Node version in package.json#engines
npm install
npm run dev

Then, in Chrome:

  1. Go to chrome://extensions.
  2. Turn on Developer mode (top right).
  3. Click Load unpacked and select the dist/ folder this repo builds to.

npm run dev rebuilds dist/ on save; the extension picks up most changes after a manual reload from chrome://extensions (a content-script change also needs the affected tab reloaded).

Production build

npm run build

Type-checks (tsc -b), builds to dist/, and zips it to release/crx-extension-blocker-<version>.zip — the artifact you'd upload to the Chrome Web Store or hand to someone to load unpacked.

Project structure

manifest.config.ts      MV3 manifest (name/version pulled from package.json)
vite.config.ts          Vite + @crxjs/vite-plugin + zip-pack wiring
src/
  content/
    main.ts             The overlay: shadow root, blocking logic, CRT paint,
                         background media, message listener for the picker
    picker.ts            The theme picker as it renders on the page (lazy-loaded)
  popup/
    App.tsx              Toolbar popup: block list, add/remove/enable, theme menu
    ThemePicker.tsx       React fallback picker, used only where a content
                          script can't be reached (chrome://, Web Store, …)
  lib/
    storage.ts            Block list persistence (chrome.storage.local)
    match.ts               Hostname normalization + blocked-host matching
    theme.ts                Active theme persistence + color/contrast helpers
    media.ts                 Paths/volume/opacity for the optional CRT footage
    tokens.css, crt.css       Shared design tokens and the CRT effect layer
    picker.css                One stylesheet shared by both theme pickers
  constants/themes/        Generated palette data — see below, don't hand-edit
scripts/
  gen-themes.mjs           Regenerates src/constants/themes/ from Monkeytype
  prep-media.sh            Turns raw footage into the two files the overlay loads
  yt-download.py           Optional helper to fetch that raw footage

For the why behind these choices (why an overlay and not a redirect, why a closed shadow root, why the CRT effect is built the way it is, the animation rules, etc.) see CLAUDE.md — it's the living architecture doc for this project, not just Claude-specific instructions.

Theming

Themes live in src/constants/themes/: one <name>.ts + one <name>.css per palette, generated — not hand-edited — from Monkeytype's own theme table at a pinned commit:

node scripts/gen-themes.mjs

This wipes and regenerates the whole directory, so a palette Monkeytype removes upstream doesn't leave a stale file behind.

Overlay background media (optional)

The blocked-site overlay can play a looping CRT-static video behind the wordmark, with a matching hiss underneath it. Both files are gitignored, so a fresh clone builds and runs fine without them — the overlay simply renders without the footage, exactly as it did before the feature existed.

To enable it, drop your own files at:

public/media/blockix-static.mp4   # muted, looping, object-fit: cover
public/media/blockix-static.mp3   # looping, pre-cut to its own loop point

Requirements:

  • The mp4 must have no audio track. The mp3 owns the sound, which is what lets the two loop at different lengths. H.264 / yuv420p, 1080p30 or smaller.
  • The mp3 must already be cut to its loop point. Playback restarts at 0 and never seeks, so any intro you leave in replays every cycle.
  • Keep both small. Static is incompressible noise; a long 1080p clip runs to hundreds of MB and would ship in the release .zip.

bash scripts/prep-media.sh produces both from raw captures in scripts/downloads/ (fetch those with scripts/yt-download.py):

brew install ffmpeg
pip install yt-dlp
bash scripts/prep-media.sh                 # uses the default source filenames
bash scripts/prep-media.sh in.mp3 in.mp4   # or bring your own

Paths, loop volume, and the per-theme opacity live in src/lib/media.ts; the styling lives with the other CRT strata in src/lib/crt.css under .crt-media.

Branching

  • main — stable, released.
  • dev — day-to-day development; branch new work off here.
  • dev merges into main to publish a release.

Credits

License

MIT.

About

Chrome extension (MV3) that covers blocked sites with a full-screen overlay. React + TypeScript, Vite, GitHub Actions CI.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages