feat: tsuki Firefox theme for Nova (157+)
ci / check (push) Successful in 23s
release / release (push) Successful in 2m38s

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>
This commit is contained in:
dev
2026-10-01 09:25:52 +05:30
co-authored by Claude Opus 5.5
commit f1b98696be
15 changed files with 4251 additions and 0 deletions
+75
View File
@@ -0,0 +1,75 @@
# @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`](https://git.d-v.cc/tsuki/tokens). No hex values are written by hand.
## Install
### Theme
Download `tsuki-<version>.xpi` from the [latest release](https://git.d-v.cc/tsuki/firefox-theme/releases) 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`](src/mapping.ts).
## Develop
```bash
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:
```bash
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.