add-theme-property
Checklist for adding or changing a field on ThemeConfig (a new design token, per-mode setting, or export option) end to end — schema, defaults, store + history, CSS apply, export, editor UI, AI, and t
SKILL.md.claude/skills/add-theme-property/SKILL.md
GitHubAdd a theme property: $ARGUMENTS
ThemeConfig is persisted in users' cookies, stored in saved presets, exported as JSON, generated by AI, and synced into the preview iframe. A change must work for all of them, including old data that lacks the new field.
Work through every step. Say explicitly when a step doesn't apply.
- Shared constants: if the property has a fixed value set (palettes, shades, fonts, ranges), add it to
shared/constants/theme.tsso app, server, and AI prompt share it. - Types + schema (
app/types/theme.ts): add the field toThemeConfig. InrawThemeSchema, make it.optional()and fill it inThemeConfigSchema.transform()(usually mirroring the light-mode value fordark*fields). Existing cookies and presets must still parse. - Defaults (
app/utils/defaults.ts): add the value toDEFAULT_THEME(and to the light/dark override defaults if it's a token override). - Presets (
app/utils/presets.ts): built-in presets are full configs, so either add the field to each preset or rely on the schema transform, and make sureloadPresetstill validates. - Store (
app/stores/theme.ts): add asetXForMode(mode, value)setter that mutatesconfig.valuethen calls_pushHistory(). Continuous inputs (sliders, drags) also get a visual setter without history, committed once at the end. Add it to the returned API. - Apply (
app/composables/useThemeApply.ts→app/utils/cssGenerator.ts): semantic palette names go toappConfig.ui.colors; everything else is a CSS variable in:root/.dark. Output must still passisCleanCSS; sanitize free-form values withsanitizeCSSValue. - Export (
app/composables/useThemeExport.ts,generateExportCSS): include the property in the CSS and app-config output where relevant (JSON export is automatic). - Editor UI (
app/components/editor/): a leaf control takingmodelValueand emitting updates, wired inEditorPanelviauseThemeModeAccessorsso it edits the current color mode. - AI: if the model should choose it, extend
aiThemeSchemainserver/api/ai/generate.post.ts,buildThemeConfiginserver/utils/aiResponseBuilder.ts, and describe it inserver/utils/aiSystemPrompt.ts(value lists come from shared constants). - Docs: update
app/data/help.mdand any learn article describing the editor's controls. - Tests:
tests/unit/types/theme.test.ts: the schema accepts old configs without the field and fills the default.tests/unit/stores/theme.test.ts: the setter updates the right mode, pushes history, and undo/redo work.tests/unit/utils/cssGenerator.test.ts/useThemeExport.test.ts: the variable/export output.
- Verify:
/dev-workflow full, then check the preview updates live and survives a reload (/run-app).