Structure
Minimal manifest
A variable theme is built around a JSON manifest containing a stable identifier, metadata and the variables block.
{
"id": "ocean",
"name": "Ocean",
"description": "Deep blue palette",
"author": "Jane Doe",
"version": "1.0",
"type": "variables",
"variables": {
"--bg": "#0a1628",
"--bg2": "#0d1f3c",
"--bg3": "#152849",
"--border": "#1e3a5f",
"--text": "#cdd9e5",
"--text2": "#7d9ab5",
"--accent": "#39c5cf",
"--accent2": "#1a9aa4",
"--green": "#26a641",
"--red": "#f85149",
"--yellow": "#e3b341",
"--purple": "#bc8cff"
}
}
Supported tokens
Required and optional variables
| Variable | Main role | Status |
|---|---|---|
--bg, --bg2, --bg3 | Primary, secondary and tertiary backgrounds | Required |
--border | Borders and separators | Required |
--text, --text2 | Primary and secondary text | Required |
--accent, --accent2 | Links, focus states and active states | Required |
--green, --red, --yellow, --purple | States and complementary accents | Required |
--font-mono, --font-sans | Shell fonts | Optional |
--radius, --shadow | Radius and shadow tokens | Optional |
The shell default values live in public/assets/app.css. A variable theme only replaces these tokens, it does not modify HTML structure.
Validation
Rules enforced by the engine
idmust be 1 to 32 characters long and only usea-z, digits, dashes and underscores.nameis required, whiledescriptionandauthorare length-limited.versiononly accepts a short format based on letters, digits, dots, underscores and dashes.- CSS values are filtered to reject unsafe
@import,javascript:,expression, HTML tags and dangerous characters.
Validation is centralized in
src/ThemeManager.php. When in doubt about a token or format, that is the right file to inspect before shipping.Iteration
Recommended workflow
- Create a minimal manifest with all required variables.
- Check baseline contrast on the sidebar, cards and form states.
- Add optional variables afterward to align typography and density.
- Move to an
advancedtheme only if the need goes beyond tokens.