Repository navigation
Making a Theme
- Copy
template/tothemes/<your-id>/(id= lowercase kebab-case, must match the folder name). - Rename the
[data-theme='template']selector andmanifest.idto your id. - Recolour the tokens (see Design-Tokens — the simplest path), and/or add your own selectors and animations. Unused optional tokens can be trimmed.
- 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. - Validate locally — it must print
PASS:npm install node scripts/validate-theme.mjs themes/<your-id>
- 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.
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/-
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.
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.
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/mainThe 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.
By submitting a theme you agree it's contributed under the repository's MIT License.
- Theme-Anatomy — what goes in the folder
- Design-Tokens — the full token surface
- Validator & CI — exactly what gets checked and why
-
Local-Assets — shipping images/fonts instead of
data:URIs - FAQ — recurring mistakes and how to avoid them