ShellTint colours Firefox from your desktop shell. It reads the Material You palette that DankMaterialShell, Caelestia, Noctalia, end-4's illogical-impulse or matugen generated, themes the browser toolbar with it, and restyles more than 130 websites (YouTube, GitHub, X, Reddit, Wikipedia and others) using Catppuccin's userstyles recoloured with your palette. When the shell changes theme, the browser and open tabs follow within seconds, without a reload.
It also runs in Chromium-based browsers (Chromium, Chrome, Brave, Vivaldi, Edge, Helium) for everything except the toolbar colours, which need Firefox's theme API.
ShellTint has two parts: the browser extension, and a small local helper (a native messaging host) that reads your shell's colour files and builds the website styles.
- Toolbar, tabs, address bar and menus take the shell's colours (tonal or vivid style).
- Catppuccin userstyles for 130+ sites, recompiled with your palette on every theme change — only the ones you actually visit, so a theme change costs about a second.
- Light and dark follow the shell, or can be forced.
- Pause styling per site from the toolbar popup, or turn it off everywhere; the button counts the styles in use.
- Style your own self-hosted SearXNG, Homepage, boringproxy and OpenMediaVault.
- Your own CSS per site, with syntax highlighting and suggestions; settings and styles back up to a zip.
- Detects the shell automatically; any matugen output works as a fallback.
- Collects no data.
shell colour file ShellTint helper (native host, Python)
(DMS, Caelestia, Noctalia, ──watch──▶ normalises roles, light/dark
end-4, matugen file) │
▼
~/.cache/shelltint/palette.json
│
▼
builder (Node): Catppuccin userstyles
recompiled with the palette
│
▼
~/.cache/shelltint/userstyles/current/
│
browser extension ◀──native messaging──┘
├─ browser.theme → toolbar colours
└─ scripting.insertCSS → per-site CSS in matching tabs
- Firefox 140 or newer, or a browser on a 140+ base: Zen, LibreWolf, Floorp, Waterfox.
- Linux.
- Python 3.8+.
- Node.js 18+ with npm (a system package or nvm both work).
- curl.
- flock, from util-linux.
- One supported shell (see Supported colour sources) or a matugen output file.
- The extension's "Access your data for all websites" permission. Firefox may ask for it after install; ShellTint's Overview page shows a button if it is missing. Without it no website can be styled.
Fedora:
sudo dnf install python3 nodejs npm curl util-linuxDebian/Ubuntu:
sudo apt install python3 nodejs npm curl util-linuxArch:
sudo pacman -S python nodejs npm curl util-linux-
Install the extension from addons.mozilla.org: https://addons.mozilla.org/firefox/addon/shelltint/
-
Install the helper:
git clone https://github.com/Jazzmedo/ShellTint cd ShellTint ./scripts/install.shIt copies the helper to
~/.local/share/shelltint, installs the builder's npm dependencies, registers the native messaging manifest, detects your shell and builds the website styles once. -
Restart the browser, then open ShellTint (toolbar button → settings) and check the Overview page.
- Download
shelltint-<version>-chromium.zipfrom the latest release and unzip it to a folder you'll keep. - Open
chrome://extensions(Brave:brave://extensions), turn on Developer mode, choose Load unpacked and pick that folder. Its ID should bepaiglabcdaphmocanlbnikkipilidmfk. - Install the helper as in step 2 above, then restart the browser.
Website styles, My styles and backup work as in Firefox. Toolbar colours are Firefox-only: Chromium has no API for an extension to recolour the browser. For a similar result, choose Settings → Appearance → GTK in Chromium, which follows your GTK theme, so a matugen-coloured GTK theme matches your shell.
| Flag | Effect |
|---|---|
--prefix DIR |
Install the helper to DIR instead of ~/.local/share/shelltint. |
--no-build |
Skip the first style build; it runs when the browser connects. |
--dry-run |
Print what would be done and change nothing. |
--with-matugen-hook |
Print a matugen config snippet that rebuilds styles while the browser is closed. Your matugen config is not edited. |
The native messaging manifest goes to ~/.mozilla/native-messaging-hosts/shelltint.json, which Firefox, Zen and Floorp read. LibreWolf, Waterfox and Flatpak browser folders get a copy only if they already exist. Chromium-based browsers get theirs in NativeMessagingHosts inside their config folder (~/.config/chromium, ~/.config/google-chrome, ~/.config/BraveSoftware/Brave-Browser, ~/.config/vivaldi, ~/.config/microsoft-edge, ~/.config/net.imput.helium), again only when that folder exists; the list is in scripts/chromium-browsers.sh.
| Source | File | Light / dark |
|---|---|---|
| DankMaterialShell | ~/.cache/DankMaterialShell/dms-colors.json |
isLightMode in ~/.local/state/DankMaterialShell/session.json |
| Caelestia | ${XDG_STATE_HOME:-~/.local/state}/caelestia/scheme.json |
the file's mode field |
| Noctalia v4 | ${NOCTALIA_CONFIG_DIR:-~/.config/noctalia/}colors.json |
colorSchemes.darkMode in settings.json |
| Noctalia v5 | ~/.cache/shelltint/sources/noctalia.json, written by a user template (below) |
the template's mode |
| end-4 illogical-impulse | ${XDG_STATE_HOME:-~/.local/state}/quickshell/user/generated/colors.json |
inferred: dark when the background is dark |
| Matugen file | any JSON or CSS-variables file you choose | the file's mode / is_dark, else inferred |
Notes:
- Noctalia v4 only exports 16 roles. ShellTint derives the missing container and surface levels from them, and lists that as a warning on the Overview page.
- The matugen file source accepts flat JSON (
{"primary": "#..."}),{"mode": ..., "colors": {...}}, matugen's nested{"colors": {"primary": {"dark": ..., "light": ..., "default": ...}}}, or CSS variables. Accepted names include--primary,--mg-primary,--md-sys-color-primary,primaryand camelCase such assurfaceContainerHigh.
With the source set to Auto, ShellTint uses the first one whose file exists and parses, in this order:
dms → caelestia → noctalia → end4 → matugen
To use a different one, open ShellTint → Colours and pick the source. For a matugen file, choose "Matugen file", enter the path and press Check.
This template writes every colour plus the mode, in a format the matugen file source reads. It was rendered with matugen 4.2.0 in both modes: the output is valid JSON, {{ mode }} renders as lowercase dark / light, and the loop emits all 50 roles.
Save as ~/.config/matugen/templates/shelltint.json:
{
"mode": "{{ mode }}",
"is_dark": <* if {{ is_dark_mode }} *>true<* else *>false<* endif *>,
"colors": {<* for name, value in colors *>
"{{ name }}": "{{ value.default.hex }}"<* if not {{ loop.last }} *>,<* endif *><* endfor *>
}
}
Add to ~/.config/matugen/config.toml:
[templates.shelltint]
input_path = '~/.config/matugen/templates/shelltint.json'
output_path = '~/.cache/shelltint/sources/matugen.json'Then in ShellTint → Colours choose "Matugen file" with the path ~/.cache/shelltint/sources/matugen.json.
Noctalia v5 no longer writes a palette file. Add a user template that writes one. Not tested on this machine; Noctalia's template syntax is matugen-style, so the template above should work unchanged.
[theme.templates.user.shelltint]
input_path = "~/.config/noctalia/templates/shelltint.json"
output_path = "~/.cache/shelltint/sources/noctalia.json"Copy the matugen template above to ~/.config/noctalia/templates/shelltint.json. The Noctalia source picks the file up automatically.
| Setting | Values | Default | Where |
|---|---|---|---|
paletteSource |
auto, dms, caelestia, noctalia, end4, matugen |
auto |
Colours |
customPalettePath |
path to a JSON or CSS file | empty | Colours (Matugen file) |
mode |
follow, dark, light |
follow |
Colours |
toolbarTheming |
on / off | on | Overview, popup |
toolbarStyle |
tonal, vivid |
tonal |
Colours |
websiteStyling |
on / off | on | Overview, Websites, popup |
disabledSites |
site list | empty | popup; managed under Websites → Paused sites |
siteInstances |
site id → one hostname or URL per line | empty | Websites → Self-hosted sites |
autoCheckUpdates |
on / off | on | Maintenance |
A paused site covers its subdomains: pausing youtube.com also pauses m.youtube.com.
Four Catppuccin styles are written for software you host yourself, so upstream
can only name a placeholder address (homepage.example.com). Put your own
address under Websites → Self-hosted sites and that style starts applying:
| Style | Notes |
|---|---|
| SearXNG | |
| Homepage | Already matches any host starting homepage., e.g. homepage.home.local. |
| boringproxy | |
| OpenMediaVault |
A line is a hostname (subdomains included) or a full URL to style only that path. To change how one of them looks, write your own CSS for it under My styles.
Homepage needs one extra piece. It paints the page with
html { background-color: rgb(var(--bg-color)) }, an r g b triplet, and the
Catppuccin style puts a hex colour there — an invalid rgb(), which the browser
drops, leaving Homepage's stock slate behind the themed cards. Paste
docs/styles/homepage.css into a new style under
My styles to set the colour directly and match the rest of the desktop.
Write your own CSS for any site, like Stylus. Open ShellTint → My styles → New style, or click the toolbar button on a site and choose "New style for this site".
-
Sites: one per line. A hostname such as
example.comcovers its subdomains, a URL such ashttps://example.com/forum/covers only pages under it, and*means every site. Lines starting with#are comments. -
CSS: plain CSS, applied after the Catppuccin style so your rules win ties. Use
!importantwhere a site's own CSS is more specific. -
Replace the Catppuccin style: turn on "Turn off the Catppuccin style on these sites" to use only your CSS there.
-
Shell colours: every style can use the palette as variables, and pages update when the shell changes theme:
body { background: var(--shelltint-surface) !important; color: var(--shelltint-on-surface) !important; } a { color: var(--shelltint-primary) !important; }
Material roles are
--shelltint-<role>(primary,on-primary,primary-container,secondary,tertiary,error,surface,on-surface,surface-container,surface-container-high,outlineand more). Once website styles are built, Catppuccin's recoloured slots are available too, as--shelltint-ctp-<slot>(base,mantle,crust,text,mauve,blueand so on). The editor lists them all with swatches. -
Editor: CSS is syntax-highlighted, and suggestions for properties, common values and the
--shelltint-*variables pop up as you type (Ctrl+Space opens them anywhere). ↑/↓ pick, Enter or Tab accepts, Esc closes. -
Backup: Maintenance → Back up to zip saves your settings and every style, each as its own
.cssfile. Restore from zip adds the styles in the backup, replaces those you still have with the backed-up version, keeps the rest, and applies the backed-up settings. -
Styles are stored in the extension and work even when the helper isn't running. Pausing a site or turning off website styling also turns off your styles there.
-
While the browser runs, the helper watches the active source's files. When they change and settle, it writes a new palette, recolours the toolbar and rebuilds the website styles in the background. Open tabs switch to the new styles without a reload.
-
When the browser connects, the helper checks Catppuccin for new userstyles, at most once every 10 minutes (turn off with
autoCheckUpdates). -
To rebuild while the browser is closed, add ShellTint's hook to matugen (print the snippet with
./scripts/install.sh --with-matugen-hook):post_hook = '~/.local/share/shelltint/builder/scripts/matugen-hook.sh'
-
Manual: ShellTint → Maintenance → Rebuild styles now, or Check Catppuccin for updates.
Helper not connected
- Check that
~/.mozilla/native-messaging-hosts/shelltint.jsonexists and itspathpoints at an existing, executableshelltint_host.py. - Check that
python3is on your PATH. - Restart the browser after installing the helper.
- Flatpak and Snap browsers run sandboxed. They need the manifest inside their sandbox and may not be able to start the helper at all; a native package is recommended.
Zen: never create ~/.zen. Zen treats that folder as its profile folder and opens an empty profile. Zen reads native messaging manifests from ~/.mozilla/native-messaging-hosts, which the installer already covers.
No source detected
- Open ShellTint → Colours; the detected-sources list shows each file ShellTint looked for and why it was rejected.
- Make sure the shell has generated a palette at least once (change the wallpaper or theme).
- Otherwise use the Matugen file source.
Some styles failed or a site looks wrong
- Build output is in
~/.cache/shelltint/build.log. Failed styles are also listed under Websites. - Pause the site from the popup.
Reset the website styles
rm -rf ~/.cache/shelltint/userstylesThen use Maintenance → Rebuild styles now.
./scripts/uninstall.sh # helper and native messaging manifests
./scripts/uninstall.sh --purge # also ~/.cache/shelltint and ~/.config/shelltintThen remove the extension from about:addons.
ShellTint collects no data and sends nothing anywhere. The extension talks only to the local helper. The helper's only network access is downloading Catppuccin's public userstyles:
- https://github.com/catppuccin/userstyles/releases/download/all-userstyles-export/import.json
- https://userstyles.catppuccin.com/lib/std/v1.less
| Permission | Why |
|---|---|
nativeMessaging |
Talk to the local helper that reads the shell's colour files and serves the compiled CSS. |
theme |
Colour the toolbar, tabs and menus. |
scripting + access to all websites |
Insert the site CSS into pages that a style matches. |
webNavigation |
Notice navigations and frames, so styles apply early and follow in-page navigation. |
storage |
Keep your settings. |
node --test "builder/test/*.test.mjs"
python3 -m unittest discover -s host/tests
./scripts/package.sh # web-ext lint + Firefox zip, Chromium build (dist/chromium) and zip
./release.sh --dry-run # tests and package only; ./release.sh tags, pushes and publishes a GitHub releaseTo add a colour source, see docs/adapters.md. The helper protocol is in docs/protocol.md.
- ShellTint by Jazzmedo.
- Based on MatugenFox by Ubaid, MIT.
- Website styles from Catppuccin userstyles, MIT.
- Compiled with less and postcss.
MIT. See LICENSE.