Files
firefox-theme/README.md
T
devandClaude Opus 5.5 f1b98696be
ci / check (push) Successful in 23s
release / release (push) Successful in 2m38s
feat: tsuki Firefox theme for Nova (157+)
Adaptive light/dark static theme generated from @tsuki/tokens, plus an
optional userChrome.css layer (IBM Plex, tsuki radii, shu accent) that
overrides Nova's design tokens. Self-hosted via AMO unlisted signing and
Gitea releases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 09:25:52 +05:30

3.6 KiB
Raw Blame History

@tsuki/firefox-theme

tsuki for Firefox 157+ (Nova). One adaptive theme: kami (paper) when your system is light, sumi (ink) when it's dark, with shu marking the active tab, loading state, and focused address bar.

Two layers:

  • Theme (tsuki-<version>.xpi) — colors only. Signed by Mozilla, self-hosted on Gitea, updates automatically.
  • userChrome.css (optional) — what the theme API can't reach: IBM Plex Sans, tsuki corner radii (4/6/8px instead of Nova's 12–24px), and shu in place of Nova's violet for focus rings, links, and primary buttons.

Both are generated from @tsuki/tokens. No hex values are written by hand.

Install

Theme

Download tsuki-<version>.xpi from the latest release and open it in Firefox. Firefox checks updates.json in this repo for new versions.

userChrome.css

  1. Open about:config and set toolkit.legacyUserProfileCustomizations.stylesheets to true.
  2. Open about:support and click Open Folder next to Profile Folder.
  3. Unzip tsuki-userchrome-<version>.zip from the release and copy the contents of its userChrome/ folder into a chrome/ folder in your profile, giving you chrome/userChrome.css and chrome/tsuki-fonts/.
  4. Restart Firefox.

If you already have a userChrome.css, paste tsuki's at the top of yours and keep the tsuki-fonts/ folder next to it.

The overrides target Nova's design tokens (--border-radius-*, --color-accent-primary, --focus-outline-color), not element selectors, so they should survive most Firefox updates. Mozilla doesn't support userChrome.css, though, and a future release may rename these tokens.

Design notes

  • No gradients. Nova encourages gradient themes. tsuki doesn't use them, and the tests fail on any gradient or images in the output.
  • Selected tab = toolbar. Both are kami-0 / sumi-100, so the active tab reads as one sheet with the toolbar. Separation comes from color, not shadow.
  • Dead Nova keys are omitted: ntp_text, sidebar_highlight, sidebar_highlight_text.
  • Contrast is tested: text pairs ≥ 4.5:1, icons and accent marks ≥ 3:1, in both modes.

To change a color, edit src/mapping.ts.

Develop

pnpm install
pnpm build        # dist/theme, dist/userChrome, updates.json
pnpm test
pnpm lint         # web-ext lint (self-hosted rules)
pnpm start        # Firefox with the theme + userChrome, light
pnpm start:dark   # same, forced dark

pnpm start uses a throwaway profile in .preview-profile/, not your own.

Test checklist (Mozilla's for Nova)

Horizontal and vertical tabs · sidebar closed / open / expand-on-hover · compact density · private window · light and dark · hover states on tabs and toolbar buttons.

Releasing

Release Firefox only installs Mozilla-signed add-ons, so "self-hosted" means signed through AMO's unlisted channel (not published on addons.mozilla.org), then distributed from Gitea.

One-time setup:

  1. Create AMO API credentials at https://addons.mozilla.org/developers/addon/api/key/.
  2. Add repo secrets: AMO_JWT_ISSUER, AMO_JWT_SECRET, NPM_TOKEN (registry read), RELEASE_TOKEN (Gitea token with repo write).
  3. The repo must be public: Firefox fetches updates.json and the XPI without auth.

Cut a release:

npm version <patch|minor|major> --no-git-tag-version
pnpm build                       # regenerates updates.json for the new version
git commit -am "release: vX.Y.Z"
git tag vX.Y.Z
git push --follow-tags

CI verifies updates.json is committed for the tag, signs the XPI, and attaches it and the userChrome zip to a Gitea release.