Skip to content

Making a Theme

ImAsra edited this page Jul 29, 2026 · 1 revision

Making a Theme

Quick start

  1. Copy template/ to themes/<your-id>/ (id = lowercase kebab-case, must match the folder name).
  2. Rename the [data-theme='template'] selector and manifest.id to your id.
  3. Recolour the tokens (see Design-Tokens — the simplest path), and/or add your own selectors and animations. Unused optional tokens can be trimmed.
  4. Add a thumbnail.png/.jpg — a 16:9 screenshot of Psysonic with your theme applied, at least 1280×720. No screenshot yet? node scripts/make-thumbnail.mjs themes/<your-id>/thumbnail.png "#15171e" 1280 720.
  5. Validate locally — it must print PASS:
    npm install
    node scripts/validate-theme.mjs themes/<your-id>
  6. Open a pull request against main — one theme per PR, so each theme gets its own validation and visual review, and a problem with one never blocks the others from merging.

Live preview while you build

If you're running Psysonic from source, start it with:

npm run tauri:dev -- -- -- --theme-watch <path/to/theme.css>

OR

npm run tauri:dev -- -- -- --theme-watch <path/to/themes_folder/>

This hot-reloads your theme on every save and lets you switch between all checkout themes in Settings → Themes — no zip, no restart. Dev builds only. Pointing the --theme-watch to a themes folder is especially handy if you are working on multiple themes as any directory inside this folder will be watched

psysonic_themes/
└── themes/
    └── mythemes/
        ├── theme1/
        │   └── theme.css
        └── theme2/
            └── theme.css

Pointing --theme-watch to a directory containing multiple themes is especially useful during active development. Every subfolder within the target directory will be monitored automatically.

For example, to watch all themes in mythemes:

--theme-watch /psysonic_themes/themes/mythemes/

Naming & description

  • Display name (manifest.name): keep it short. If your theme is inspired by a brand, film, or game, a trademark-safe / altered name is fine and encouraged.
  • Description (manifest.description) is the store's search anchor — name the real inspiration here, e.g. Inspired by Winamp. Someone searching "Winamp" should find your theme.
  • Recolouring an existing open-source palette? Credit the palette and its author in the description, e.g. … — recolour of the Nord palette by arcticicestudio.
  • Descriptions are in English.

Updating a theme that's already published

Bump version in manifest.json (e.g. 1.0.1 → 1.0.2) whenever you change a theme that's already in the store. The in-app store detects updates by comparing versions, so a change shipped under the same version is never offered to users who already installed it. CI enforces this — a PR that edits a published theme without raising its version fails the validate check.

Consider adding a matching entry to the optional changelog object in manifest.json, keyed by the new version (plain X.Y.Z, no pre-release suffix), so users can see what changed in the store's What's new.

Keep update branches independent

Cut every update from an up-to-date main, and keep separate changes on separate branches — don't build one branch on top of another that hasn't merged yet. If you have two changes in flight for the same theme and the first one merges, a branch cut from the older main still carries that first change, so it comes back as a duplicate and the PR conflicts.

If your PR falls behind main, rebase onto it rather than merging main in, so the PR keeps only your changes:

git fetch origin
git rebase origin/main

After you open the PR

The validate workflow runs automatically. Once it's green and a maintainer has had a quick visual look, it can be merged. registry.json regenerates automatically on merge — see Registry & Versioning.

License

By submitting a theme you agree it's contributed under the repository's MIT License.

See also

Clone this wiki locally