Repository navigation
Validator & CI
theme.css is free-form CSS — the validate workflow does not police your design, only a small safety floor. Quality and taste are handled by maintainer review.
Run it locally before you push:
npm install
node scripts/validate-theme.mjs themes/<your-id> # one theme
node scripts/validate-theme.mjs # every theme
It must print PASS.
-
No network. No
@import, and everyurl()must be an inlineurl(data:...)URI or a localurl(assets/...)path (see Local-Assets). Themes never touch the network. -
No scripts. No
expression(),javascript:,-moz-binding, or<style>/<script>breakout. -
No
@property. It would register a global custom property that could clash with other themes or the app. -
Namespaced animations. Every
@keyframesname must start with<id>-, so animations from different themes never collide. -
Size cap.
theme.cssmust be ≤ 256 KB.
If a PR edits a theme that's already published without bumping manifest.version, the validate check fails. See Registry & Versioning and Making-a-Theme#updating-a-theme-thats-already-published.
- Paths must resolve under
assets/only — no leading/, no.., no backslashes, no remote URLs. - Allowed types:
.webp .png .jpg .jpeg .gif .avif .svg .woff2 .woff. - Budgets: 1 MB per file, 4 MB per theme, 32 files max (over 1.5 MB total warns).
- SVGs are scanned for
<script>, inlineon…=handlers,<foreignObject>,javascript:, and external references — flagged content is rejected. - Ship only files your CSS actually references; unreferenced files produce a warning.
Full detail: Local-Assets.
You don't need to resize, crop, or convert your screenshot — CI optimises thumbnail.png/.jpg into a thumbnail.webp automatically on merge. It just needs to be 16:9-ish (aspect ratio 1.5–1.85), at least 1280×720, and ≤ 6 MB as submitted.
Once validate passes and a maintainer has done a quick visual look, the PR can be merged. registry.json regenerates automatically from every theme's manifest.json — it's never edited by hand, and a local run (npm run registry) mirrors what CI does.