Conventions below are enforced by stylelint, tests, and git hooks.
npm ci # install dev tooling
npm run test:install # one-time: install the Chromium test browserThere is no build step for consumers — scripts/bundle.js concatenates core/
optional/intodist/bundles for maintainers.
npm run build # rebuild dist/ bundles
npm run watch # rebuild on change
npm run lint:css # stylelint (must pass)
npm run lint:css:fix # auto-fix
npm test # Playwright regression suite (light + dark)
npm run docs:tokens # regenerate docs/tokens.md from sourceBefore opening a PR: npm run lint:css && npm run build && npm test must pass,
and dist/ must be rebuilt and committed.
- Custom properties start with
--sf-; keyframes start withsf-. - Tokens, not literals. Every value in
base/layout/components/etc. goes throughvar(--sf-*). Colours useoklch()with relative colour syntax for derived values. - Layers. Every rule lives in its
@layer(seecore/layers.css). Keep selectors low-specificity (single class, element,:root). .sf-is-*is reserved for runtime state classes (theslashed.stateslayer) — never utilities or variants.- Public vs internal tokens. Label new tokens in the file header (PUBLIC / PUBLIC-ADVANCED / INTERNAL). Keep alias chains ≤2 indirections (3 nodes max); no duplicate/dangling/cyclic aliases.
- Scope of
base. Global base covers flow/inline text only. Rich blocks belong in.sf-prose; widgets and form controls are opt-in/component territory (see architecture.md).
- Any new
.sf-*or.sf-is-*class incore/*.cssmust appear indemo/index.html(tests/coverage.test.js). - Any new token must resolve in both themes (
tests/tokens.spec.js); tokens whose value isinheritgo in that file'sEXPECTED_EMPTYallowlist. - Add a focused assertion when you fix a bug.
Follow Conventional Commits — commitlint
runs via git hooks. CHANGELOG.md follows
Keep a Changelog.
CHANGELOG.md is maintained by hand; the release pipeline reads the matching
## [x.y.z] section.
- Move accumulated
## [Unreleased]entries under a new## [x.y.z] - YYYY-MM-DDheading; leave a fresh empty## [Unreleased]. - Run
npm run release(patch),npm run release:minor, ornpm run release:major. This bumpspackage.json, runsscripts/version-sync.js(propagates the version todocs/roadmap.md,docs/llm-guide.md, and the configurator package files), rebuilds bundles, commits, tags, and pushes. - The pushed tag triggers
release.yml(GitHub Release + dist assets) and re-aligns version references on main. Thedistbranch is published bypublish-dist.ymlon every push to main.
SLASHED rejects some additions (utility-class proliferation, a 7th brand colour, pre-compiled themes, decorative token bloat). Open an issue first for sizeable features.