@trishchuk/coolors-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +39 -0
- package/.env +2 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +73 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +71 -0
- package/.github/pull_request_template.md +97 -0
- package/.github/workflows/ci.yml +127 -0
- package/.github/workflows/deploy-docs.yml +56 -0
- package/.github/workflows/release.yml +99 -0
- package/.mcp.json +12 -0
- package/.prettierignore +1 -0
- package/CLAUDE.md +201 -0
- package/DOCUMENTATION.md +274 -0
- package/GEMINI.md +54 -0
- package/LICENSE +21 -0
- package/README.md +401 -0
- package/demo/content_based_color.png +0 -0
- package/demo/music-player.html +621 -0
- package/demo/podcast-player.html +903 -0
- package/dist/bin/coolors-mcp.d.ts +1 -0
- package/dist/bin/coolors-mcp.js +154 -0
- package/dist/bin/coolors-mcp.js.map +1 -0
- package/dist/bin/server.d.ts +1 -0
- package/dist/bin/server.js +3292 -0
- package/dist/bin/server.js.map +1 -0
- package/dist/chunk-IQ7NN26V.js +114 -0
- package/dist/chunk-IQ7NN26V.js.map +1 -0
- package/dist/chunk-P3ARRKLS.js +1214 -0
- package/dist/chunk-P3ARRKLS.js.map +1 -0
- package/dist/color/index.d.ts +716 -0
- package/dist/color/index.js +153 -0
- package/dist/color/index.js.map +1 -0
- package/dist/coolors-mcp.d.ts +136 -0
- package/dist/coolors-mcp.js +7 -0
- package/dist/coolors-mcp.js.map +1 -0
- package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js +93 -0
- package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js.map +7 -0
- package/docs/.vitepress/cache/deps/_metadata.json +127 -0
- package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js +9 -0
- package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js.map +7 -0
- package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js +12683 -0
- package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js.map +7 -0
- package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js +9719 -0
- package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js.map +7 -0
- package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js +4710 -0
- package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js.map +7 -0
- package/docs/.vitepress/cache/deps/cytoscape.js +30278 -0
- package/docs/.vitepress/cache/deps/cytoscape.js.map +7 -0
- package/docs/.vitepress/cache/deps/dayjs.js +285 -0
- package/docs/.vitepress/cache/deps/dayjs.js.map +7 -0
- package/docs/.vitepress/cache/deps/debug.js +468 -0
- package/docs/.vitepress/cache/deps/debug.js.map +7 -0
- package/docs/.vitepress/cache/deps/package.json +3 -0
- package/docs/.vitepress/cache/deps/prismjs.js +1466 -0
- package/docs/.vitepress/cache/deps/prismjs.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js +228 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js +142 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js +27 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js +65 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js +53 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js.map +7 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js +73 -0
- package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4507 -0
- package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +584 -0
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1146 -0
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1667 -0
- package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___minisearch.js +1814 -0
- package/docs/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
- package/docs/.vitepress/cache/deps/vue.js +344 -0
- package/docs/.vitepress/cache/deps/vue.js.map +7 -0
- package/docs/.vitepress/components/ClientGrid.vue +125 -0
- package/docs/.vitepress/components/CodeBlock.vue +231 -0
- package/docs/.vitepress/components/ConfigModal.vue +477 -0
- package/docs/.vitepress/components/DiagramModal.vue +528 -0
- package/docs/.vitepress/components/TroubleshootingModal.vue +472 -0
- package/docs/.vitepress/config.js +162 -0
- package/docs/.vitepress/theme/FundingLayout.vue +251 -0
- package/docs/.vitepress/theme/Layout.vue +134 -0
- package/docs/.vitepress/theme/components/AdBanner.vue +317 -0
- package/docs/.vitepress/theme/components/AdPlaceholder.vue +78 -0
- package/docs/.vitepress/theme/components/FundingEffects.vue +322 -0
- package/docs/.vitepress/theme/components/FundingHero.vue +345 -0
- package/docs/.vitepress/theme/components/SupportSection.vue +511 -0
- package/docs/.vitepress/theme/custom-app.css +339 -0
- package/docs/.vitepress/theme/custom.css +699 -0
- package/docs/.vitepress/theme/index.js +25 -0
- package/docs/README.md +198 -0
- package/docs/concepts/accessibility.md +473 -0
- package/docs/concepts/color-spaces.md +222 -0
- package/docs/concepts/distance-metrics.md +384 -0
- package/docs/concepts/hct.md +261 -0
- package/docs/concepts/image-analysis.md +396 -0
- package/docs/concepts/material-design.md +306 -0
- package/docs/concepts/theme-matching.md +399 -0
- package/docs/examples/basic-colors.md +490 -0
- package/docs/examples/creating-themes.md +898 -0
- package/docs/examples/css-refactoring.md +824 -0
- package/docs/examples/image-extraction.md +882 -0
- package/docs/getting-started.md +366 -0
- package/docs/index.md +190 -0
- package/docs/installation.md +157 -0
- package/docs/tools/README.md +234 -0
- package/docs/tools/accessibility.md +614 -0
- package/docs/tools/color-operations.md +374 -0
- package/docs/tools/image-extraction.md +624 -0
- package/docs/tools/material-design.md +347 -0
- package/docs/tools/theme-matching.md +552 -0
- package/eslint.config.ts +14 -0
- package/examples/theme-matching.md +113 -0
- package/jsr.json +7 -0
- package/mcp-config.json +8 -0
- package/note.md +35 -0
- package/package.json +122 -0
- package/research_results.md +53 -0
- package/src/bin/coolors-mcp.ts +194 -0
- package/src/bin/server.ts +61 -0
- package/src/color/__tests__/conversions-argb.test.ts +198 -0
- package/src/color/__tests__/extract-colors.test.ts +360 -0
- package/src/color/__tests__/image-utils.test.ts +242 -0
- package/src/color/__tests__/reference-colors.test.ts +278 -0
- package/src/color/__tests__/round-trip.test.ts +197 -0
- package/src/color/conversions.test.ts +402 -0
- package/src/color/conversions.ts +393 -0
- package/src/color/dislike/__tests__/dislike-analyzer.test.ts +248 -0
- package/src/color/dislike/dislike-analyzer.ts +114 -0
- package/src/color/extract-colors.ts +228 -0
- package/src/color/hct/__tests__/hct-class.test.ts +232 -0
- package/src/color/hct/harmonization.ts +204 -0
- package/src/color/hct/hct-class.ts +109 -0
- package/src/color/hct/hct-solver.ts +168 -0
- package/src/color/hct/index.ts +39 -0
- package/src/color/hct/tonal-palette.ts +211 -0
- package/src/color/hct/types.ts +88 -0
- package/src/color/image-utils.ts +79 -0
- package/src/color/index.ts +87 -0
- package/src/color/material-theme.ts +157 -0
- package/src/color/metrics.test.ts +276 -0
- package/src/color/metrics.ts +281 -0
- package/src/color/quantize/__tests__/quantizer_celebi.test.ts +195 -0
- package/src/color/quantize/lab_point_provider.ts +55 -0
- package/src/color/quantize/point_provider.ts +27 -0
- package/src/color/quantize/quantizer_celebi.ts +51 -0
- package/src/color/quantize/quantizer_celebi_test.ts +71 -0
- package/src/color/quantize/quantizer_map.ts +47 -0
- package/src/color/quantize/quantizer_wsmeans.ts +232 -0
- package/src/color/quantize/quantizer_wu.ts +472 -0
- package/src/color/score/__tests__/score.test.ts +224 -0
- package/src/color/score/score.ts +175 -0
- package/src/color/types.ts +151 -0
- package/src/color/utils/color_utils.ts +292 -0
- package/src/color/utils/math_utils.ts +145 -0
- package/src/color/utils.test.ts +403 -0
- package/src/color/utils.ts +315 -0
- package/src/constants.ts +5 -0
- package/src/coolors-mcp.ts +37 -0
- package/src/examples/addition.ts +333 -0
- package/src/examples/color-demo.ts +125 -0
- package/src/examples/custom-logger.ts +201 -0
- package/src/examples/oauth-server.ts +113 -0
- package/src/examples/session-context.ts +269 -0
- package/src/session.ts +116 -0
- package/src/theme/__tests__/matcher.test.ts +180 -0
- package/src/theme/__tests__/parser.test.ts +148 -0
- package/src/theme/__tests__/refactor.test.ts +224 -0
- package/src/theme/index.ts +34 -0
- package/src/theme/matcher.ts +395 -0
- package/src/theme/parser.ts +392 -0
- package/src/theme/refactor.ts +360 -0
- package/src/theme/types.ts +152 -0
- package/src/tools/__tests__/gradient-generator.test.ts +206 -0
- package/src/tools/__tests__/palette-with-locks.test.ts +109 -0
- package/src/tools/color-conversion.tool.ts +54 -0
- package/src/tools/color-distance.tool.ts +41 -0
- package/src/tools/colors.ts +31 -0
- package/src/tools/contrast-checker.tool.ts +37 -0
- package/src/tools/dislike-analyzer.tool.ts +247 -0
- package/src/tools/gradient-generator.tool.ts +250 -0
- package/src/tools/image-extraction.tools.ts +289 -0
- package/src/tools/index.ts +39 -0
- package/src/tools/material-theme.tools.ts +250 -0
- package/src/tools/palette-generator.tool.ts +135 -0
- package/src/tools/palette-with-locks.tool.ts +221 -0
- package/src/tools/registry.ts +142 -0
- package/src/tools/simple-tools.ts +37 -0
- package/src/tools/theme-matching.tools.ts +334 -0
- package/src/types.ts +182 -0
- package/src/utils.ts +22 -0
- package/tsconfig.json +8 -0
- package/vitest.config.js +15 -0
|
@@ -0,0 +1,898 @@
|
|
|
1
|
+
# Creating Themes Examples
|
|
2
|
+
|
|
3
|
+
Learn how to create comprehensive color themes using Material Design 3 principles and Coolors MCP's advanced theme generation tools.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### Generate from a Single Color
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
// Create a complete theme from one color
|
|
11
|
+
"Generate a Material Design theme from #6366f1"
|
|
12
|
+
|
|
13
|
+
// Result: Complete light and dark schemes with:
|
|
14
|
+
// - Primary, secondary, tertiary, neutral, error palettes
|
|
15
|
+
// - Surface colors with elevation levels
|
|
16
|
+
// - Semantic color roles
|
|
17
|
+
// - Accessible color pairs
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Generate from an Image
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
// Extract colors and create theme
|
|
24
|
+
"Generate a theme from this logo image"
|
|
25
|
+
|
|
26
|
+
// Process:
|
|
27
|
+
// 1. Extracts dominant colors using Celebi algorithm
|
|
28
|
+
// 2. Scores colors for UI suitability
|
|
29
|
+
// 3. Generates harmonious Material Design theme
|
|
30
|
+
// 4. Provides both light and dark modes
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Complete Theme Examples
|
|
34
|
+
|
|
35
|
+
### Brand Theme Creation
|
|
36
|
+
|
|
37
|
+
Starting with brand colors to create a full design system:
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
// Brand colors
|
|
41
|
+
const brandColors = {
|
|
42
|
+
primary: "#6366f1", // Indigo
|
|
43
|
+
secondary: "#ec4899", // Pink
|
|
44
|
+
accent: "#10b981" // Emerald
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Generate Material Design 3 theme
|
|
48
|
+
const theme = generateMaterialTheme({
|
|
49
|
+
sourceColor: brandColors.primary,
|
|
50
|
+
customColors: [
|
|
51
|
+
{ name: "brand", color: brandColors.primary },
|
|
52
|
+
{ name: "accent", color: brandColors.accent }
|
|
53
|
+
]
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Result structure
|
|
57
|
+
{
|
|
58
|
+
schemes: {
|
|
59
|
+
light: {
|
|
60
|
+
// Primary colors
|
|
61
|
+
primary: "#5256c9",
|
|
62
|
+
onPrimary: "#ffffff",
|
|
63
|
+
primaryContainer: "#e0e0ff",
|
|
64
|
+
onPrimaryContainer: "#070764",
|
|
65
|
+
|
|
66
|
+
// Secondary colors
|
|
67
|
+
secondary: "#5d5d72",
|
|
68
|
+
onSecondary: "#ffffff",
|
|
69
|
+
secondaryContainer: "#e2e0f9",
|
|
70
|
+
onSecondaryContainer: "#1a1b2e",
|
|
71
|
+
|
|
72
|
+
// Tertiary colors
|
|
73
|
+
tertiary: "#79536a",
|
|
74
|
+
onTertiary: "#ffffff",
|
|
75
|
+
tertiaryContainer: "#ffd8ec",
|
|
76
|
+
onTertiaryContainer: "#2e1125",
|
|
77
|
+
|
|
78
|
+
// Surface colors
|
|
79
|
+
surface: "#fffbff",
|
|
80
|
+
onSurface: "#1b1b1f",
|
|
81
|
+
surfaceVariant: "#e4e1ec",
|
|
82
|
+
onSurfaceVariant: "#46464f",
|
|
83
|
+
|
|
84
|
+
// Additional roles
|
|
85
|
+
outline: "#777680",
|
|
86
|
+
outlineVariant: "#c7c5d0",
|
|
87
|
+
shadow: "#000000",
|
|
88
|
+
scrim: "#000000",
|
|
89
|
+
inverseSurface: "#303034",
|
|
90
|
+
inverseOnSurface: "#f2eff4",
|
|
91
|
+
inversePrimary: "#bfc1ff"
|
|
92
|
+
},
|
|
93
|
+
dark: {
|
|
94
|
+
// Dark theme colors...
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
palettes: {
|
|
98
|
+
primary: { /* Tonal palette 0-100 */ },
|
|
99
|
+
secondary: { /* Tonal palette 0-100 */ },
|
|
100
|
+
tertiary: { /* Tonal palette 0-100 */ },
|
|
101
|
+
neutral: { /* Tonal palette 0-100 */ },
|
|
102
|
+
neutralVariant: { /* Tonal palette 0-100 */ },
|
|
103
|
+
error: { /* Tonal palette 0-100 */ }
|
|
104
|
+
},
|
|
105
|
+
customColors: [
|
|
106
|
+
{
|
|
107
|
+
name: "brand",
|
|
108
|
+
light: { /* Custom color light scheme */ },
|
|
109
|
+
dark: { /* Custom color dark scheme */ }
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Application Themes
|
|
116
|
+
|
|
117
|
+
#### SaaS Dashboard Theme
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
// Professional dashboard colors
|
|
121
|
+
const dashboardTheme = {
|
|
122
|
+
sourceColor: "#2563eb", // Blue
|
|
123
|
+
variant: "neutral", // Minimal color variation
|
|
124
|
+
contrastLevel: 0 // Standard contrast
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// Generated theme emphasizes:
|
|
128
|
+
// - Professional appearance
|
|
129
|
+
// - High readability
|
|
130
|
+
// - Clear hierarchy
|
|
131
|
+
// - Subtle color usage
|
|
132
|
+
|
|
133
|
+
const result = {
|
|
134
|
+
light: {
|
|
135
|
+
// Main UI
|
|
136
|
+
surface: "#fffbff",
|
|
137
|
+
surfaceContainer: "#f5f5f5",
|
|
138
|
+
surfaceContainerHigh: "#ebebeb",
|
|
139
|
+
|
|
140
|
+
// Navigation
|
|
141
|
+
primary: "#2563eb",
|
|
142
|
+
primaryContainer: "#dce4ff",
|
|
143
|
+
|
|
144
|
+
// Data visualization
|
|
145
|
+
chart1: "#2563eb",
|
|
146
|
+
chart2: "#10b981",
|
|
147
|
+
chart3: "#f59e0b",
|
|
148
|
+
chart4: "#ef4444",
|
|
149
|
+
|
|
150
|
+
// Status colors
|
|
151
|
+
success: "#10b981",
|
|
152
|
+
warning: "#f59e0b",
|
|
153
|
+
error: "#ef4444",
|
|
154
|
+
info: "#3b82f6"
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
#### E-commerce Theme
|
|
160
|
+
|
|
161
|
+
```javascript
|
|
162
|
+
// Vibrant shopping experience
|
|
163
|
+
const ecommerceTheme = {
|
|
164
|
+
sourceColor: "#ec4899", // Pink
|
|
165
|
+
variant: "vibrant", // Higher chroma
|
|
166
|
+
contrastLevel: 0.5 // Medium contrast
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// Features:
|
|
170
|
+
// - Engaging, energetic colors
|
|
171
|
+
// - Clear CTAs
|
|
172
|
+
// - Product emphasis
|
|
173
|
+
// - Sale/promotion support
|
|
174
|
+
|
|
175
|
+
const shopTheme = {
|
|
176
|
+
light: {
|
|
177
|
+
// Product cards
|
|
178
|
+
surface: "#fffbff",
|
|
179
|
+
surfaceVariant: "#ffeef6",
|
|
180
|
+
|
|
181
|
+
// CTAs
|
|
182
|
+
buyButton: "#ec4899",
|
|
183
|
+
onBuyButton: "#ffffff",
|
|
184
|
+
|
|
185
|
+
// Promotions
|
|
186
|
+
saleBadge: "#ef4444",
|
|
187
|
+
newBadge: "#10b981",
|
|
188
|
+
|
|
189
|
+
// Reviews
|
|
190
|
+
starActive: "#f59e0b",
|
|
191
|
+
starInactive: "#e5e7eb"
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
#### Music Player Theme
|
|
197
|
+
|
|
198
|
+
```javascript
|
|
199
|
+
// Dynamic album-based theming
|
|
200
|
+
async function createMusicTheme(albumArtUrl) {
|
|
201
|
+
// Extract colors from album art
|
|
202
|
+
const imageColors = await extractImageColors(albumArtUrl);
|
|
203
|
+
|
|
204
|
+
// Generate theme from dominant color
|
|
205
|
+
const theme = await generateThemeFromImage({
|
|
206
|
+
imageData: imageColors,
|
|
207
|
+
variant: "expressive", // Creative combinations
|
|
208
|
+
contrastLevel: 0
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
// Player background (dark for immersion)
|
|
213
|
+
playerBg: theme.dark.surface,
|
|
214
|
+
|
|
215
|
+
// Controls
|
|
216
|
+
playButton: theme.dark.primary,
|
|
217
|
+
controls: theme.dark.onSurface,
|
|
218
|
+
|
|
219
|
+
// Progress bar
|
|
220
|
+
progressBar: theme.dark.primary,
|
|
221
|
+
progressBg: theme.dark.surfaceVariant,
|
|
222
|
+
|
|
223
|
+
// Album info
|
|
224
|
+
artistName: theme.dark.onSurface,
|
|
225
|
+
songTitle: theme.dark.onSurfaceVariant,
|
|
226
|
+
|
|
227
|
+
// Visualizer colors
|
|
228
|
+
visualizer: [
|
|
229
|
+
theme.dark.primary,
|
|
230
|
+
theme.dark.secondary,
|
|
231
|
+
theme.dark.tertiary
|
|
232
|
+
]
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Design System Creation
|
|
238
|
+
|
|
239
|
+
#### Complete Design System
|
|
240
|
+
|
|
241
|
+
```javascript
|
|
242
|
+
// Foundation color
|
|
243
|
+
const systemFoundation = "#6366f1";
|
|
244
|
+
|
|
245
|
+
// Generate comprehensive system
|
|
246
|
+
const designSystem = {
|
|
247
|
+
// Core palettes
|
|
248
|
+
palettes: generateTonalPalettes(systemFoundation),
|
|
249
|
+
|
|
250
|
+
// Semantic colors
|
|
251
|
+
semantic: {
|
|
252
|
+
// Actions
|
|
253
|
+
action: {
|
|
254
|
+
primary: "#6366f1",
|
|
255
|
+
secondary: "#8b92ff",
|
|
256
|
+
disabled: "#c7c7c7"
|
|
257
|
+
},
|
|
258
|
+
|
|
259
|
+
// Feedback
|
|
260
|
+
feedback: {
|
|
261
|
+
success: "#10b981",
|
|
262
|
+
warning: "#f59e0b",
|
|
263
|
+
error: "#ef4444",
|
|
264
|
+
info: "#3b82f6"
|
|
265
|
+
},
|
|
266
|
+
|
|
267
|
+
// Content
|
|
268
|
+
content: {
|
|
269
|
+
primary: "#1f2937",
|
|
270
|
+
secondary: "#4b5563",
|
|
271
|
+
disabled: "#9ca3af",
|
|
272
|
+
inverse: "#ffffff"
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
|
|
276
|
+
// Component tokens
|
|
277
|
+
components: {
|
|
278
|
+
button: {
|
|
279
|
+
primary: {
|
|
280
|
+
bg: "palette.primary.500",
|
|
281
|
+
text: "white",
|
|
282
|
+
hover: "palette.primary.600",
|
|
283
|
+
active: "palette.primary.700"
|
|
284
|
+
},
|
|
285
|
+
secondary: {
|
|
286
|
+
bg: "palette.primary.100",
|
|
287
|
+
text: "palette.primary.700",
|
|
288
|
+
hover: "palette.primary.200",
|
|
289
|
+
active: "palette.primary.300"
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
|
|
293
|
+
input: {
|
|
294
|
+
bg: "white",
|
|
295
|
+
border: "palette.neutral.300",
|
|
296
|
+
text: "content.primary",
|
|
297
|
+
placeholder: "content.secondary",
|
|
298
|
+
focus: "palette.primary.500"
|
|
299
|
+
},
|
|
300
|
+
|
|
301
|
+
card: {
|
|
302
|
+
bg: "white",
|
|
303
|
+
border: "palette.neutral.200",
|
|
304
|
+
shadow: "0 1px 3px rgba(0,0,0,0.1)"
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Theme Variants
|
|
311
|
+
|
|
312
|
+
### Material Design 3 Variants
|
|
313
|
+
|
|
314
|
+
Each variant creates a different aesthetic:
|
|
315
|
+
|
|
316
|
+
```javascript
|
|
317
|
+
// TonalSpot (Default)
|
|
318
|
+
// Balanced, versatile theme
|
|
319
|
+
{
|
|
320
|
+
sourceColor: "#6366f1",
|
|
321
|
+
variant: "tonalSpot"
|
|
322
|
+
}
|
|
323
|
+
// Result: Subtle secondary/tertiary colors
|
|
324
|
+
|
|
325
|
+
// Fidelity
|
|
326
|
+
// Preserves brand color exactly
|
|
327
|
+
{
|
|
328
|
+
sourceColor: "#ff5722", // Brand orange
|
|
329
|
+
variant: "fidelity"
|
|
330
|
+
}
|
|
331
|
+
// Result: Primary palette matches brand precisely
|
|
332
|
+
|
|
333
|
+
// Vibrant
|
|
334
|
+
// Energetic, playful theme
|
|
335
|
+
{
|
|
336
|
+
sourceColor: "#6366f1",
|
|
337
|
+
variant: "vibrant"
|
|
338
|
+
}
|
|
339
|
+
// Result: Higher chroma throughout
|
|
340
|
+
|
|
341
|
+
// Expressive
|
|
342
|
+
// Creative, unexpected combinations
|
|
343
|
+
{
|
|
344
|
+
sourceColor: "#6366f1",
|
|
345
|
+
variant: "expressive"
|
|
346
|
+
}
|
|
347
|
+
// Result: Unique secondary/tertiary colors
|
|
348
|
+
|
|
349
|
+
// Neutral
|
|
350
|
+
// Professional, minimal color
|
|
351
|
+
{
|
|
352
|
+
sourceColor: "#6366f1",
|
|
353
|
+
variant: "neutral"
|
|
354
|
+
}
|
|
355
|
+
// Result: Grayed secondary colors
|
|
356
|
+
|
|
357
|
+
// Monochrome
|
|
358
|
+
// Single-hue theme
|
|
359
|
+
{
|
|
360
|
+
sourceColor: "#6366f1",
|
|
361
|
+
variant: "monochrome"
|
|
362
|
+
}
|
|
363
|
+
// Result: All colors from same hue family
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Contrast Levels
|
|
367
|
+
|
|
368
|
+
Adjust contrast for accessibility needs:
|
|
369
|
+
|
|
370
|
+
```javascript
|
|
371
|
+
// Standard contrast (WCAG AA)
|
|
372
|
+
const standard = {
|
|
373
|
+
sourceColor: "#6366f1",
|
|
374
|
+
contrastLevel: 0 // Default
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
// Medium contrast (Between AA and AAA)
|
|
378
|
+
const medium = {
|
|
379
|
+
sourceColor: "#6366f1",
|
|
380
|
+
contrastLevel: 0.5
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
// High contrast (WCAG AAA)
|
|
384
|
+
const high = {
|
|
385
|
+
sourceColor: "#6366f1",
|
|
386
|
+
contrastLevel: 1.0
|
|
387
|
+
};
|
|
388
|
+
|
|
389
|
+
// Results in different tone mappings:
|
|
390
|
+
// Standard: primary on primaryContainer = 4.5:1
|
|
391
|
+
// Medium: primary on primaryContainer = 7:1
|
|
392
|
+
// High: primary on primaryContainer = 10:1
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
## Dynamic Theming
|
|
396
|
+
|
|
397
|
+
### User Preference Based
|
|
398
|
+
|
|
399
|
+
```javascript
|
|
400
|
+
// Adapt to user preferences
|
|
401
|
+
function createUserTheme(preferences) {
|
|
402
|
+
const {
|
|
403
|
+
favoriteColor,
|
|
404
|
+
contrastNeeds, // "normal", "high", "maximum"
|
|
405
|
+
colorBlindness, // null, "protanopia", "deuteranopia", etc.
|
|
406
|
+
darkMode
|
|
407
|
+
} = preferences;
|
|
408
|
+
|
|
409
|
+
// Base theme
|
|
410
|
+
let theme = generateMaterialTheme({
|
|
411
|
+
sourceColor: favoriteColor,
|
|
412
|
+
contrastLevel: contrastNeeds === "high" ? 1.0 : 0
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
// Adjust for color blindness
|
|
416
|
+
if (colorBlindness) {
|
|
417
|
+
theme = adjustForColorBlindness(theme, colorBlindness);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Return appropriate scheme
|
|
421
|
+
return darkMode ? theme.schemes.dark : theme.schemes.light;
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Time-Based Themes
|
|
426
|
+
|
|
427
|
+
```javascript
|
|
428
|
+
// Change theme based on time of day
|
|
429
|
+
function getTimeBasedTheme() {
|
|
430
|
+
const hour = new Date().getHours();
|
|
431
|
+
|
|
432
|
+
if (hour < 6) {
|
|
433
|
+
// Night theme (very dark)
|
|
434
|
+
return {
|
|
435
|
+
sourceColor: "#1a1a2e",
|
|
436
|
+
variant: "monochrome",
|
|
437
|
+
scheme: "dark"
|
|
438
|
+
};
|
|
439
|
+
} else if (hour < 12) {
|
|
440
|
+
// Morning theme (bright, energetic)
|
|
441
|
+
return {
|
|
442
|
+
sourceColor: "#fbbf24",
|
|
443
|
+
variant: "vibrant",
|
|
444
|
+
scheme: "light"
|
|
445
|
+
};
|
|
446
|
+
} else if (hour < 18) {
|
|
447
|
+
// Afternoon theme (balanced)
|
|
448
|
+
return {
|
|
449
|
+
sourceColor: "#3b82f6",
|
|
450
|
+
variant: "tonalSpot",
|
|
451
|
+
scheme: "light"
|
|
452
|
+
};
|
|
453
|
+
} else {
|
|
454
|
+
// Evening theme (warm, relaxed)
|
|
455
|
+
return {
|
|
456
|
+
sourceColor: "#f97316",
|
|
457
|
+
variant: "neutral",
|
|
458
|
+
scheme: "dark"
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### Content-Aware Themes
|
|
465
|
+
|
|
466
|
+
```javascript
|
|
467
|
+
// Generate theme based on content
|
|
468
|
+
async function createContentTheme(contentType, contentData) {
|
|
469
|
+
switch (contentType) {
|
|
470
|
+
case 'article':
|
|
471
|
+
// Clean, readable theme
|
|
472
|
+
return {
|
|
473
|
+
sourceColor: "#1f2937",
|
|
474
|
+
variant: "neutral",
|
|
475
|
+
contrastLevel: 0.5
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
case 'gallery':
|
|
479
|
+
// Let images stand out
|
|
480
|
+
return {
|
|
481
|
+
sourceColor: contentData.dominantColor,
|
|
482
|
+
variant: "monochrome",
|
|
483
|
+
scheme: "dark"
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
case 'video':
|
|
487
|
+
// Dark, immersive theme
|
|
488
|
+
return {
|
|
489
|
+
sourceColor: "#0f172a",
|
|
490
|
+
variant: "monochrome",
|
|
491
|
+
scheme: "dark"
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
case 'product':
|
|
495
|
+
// Match product color
|
|
496
|
+
return generateThemeFromImage(contentData.productImage);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
## CSS Generation
|
|
502
|
+
|
|
503
|
+
### CSS Custom Properties
|
|
504
|
+
|
|
505
|
+
```javascript
|
|
506
|
+
// Generate CSS variables
|
|
507
|
+
const cssTheme = generateThemeCSS({
|
|
508
|
+
sourceColor: "#6366f1",
|
|
509
|
+
prefix: "theme",
|
|
510
|
+
includeTones: [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 95, 99, 100]
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// Output:
|
|
514
|
+
:root {
|
|
515
|
+
/* Primary palette */
|
|
516
|
+
--theme-primary-0: #000000;
|
|
517
|
+
--theme-primary-10: #00006e;
|
|
518
|
+
--theme-primary-20: #0001ac;
|
|
519
|
+
--theme-primary-30: #1e2bdb;
|
|
520
|
+
--theme-primary-40: #4046f4;
|
|
521
|
+
--theme-primary-50: #6366f1;
|
|
522
|
+
--theme-primary-60: #7f81ff;
|
|
523
|
+
--theme-primary-70: #9da0ff;
|
|
524
|
+
--theme-primary-80: #bcc0ff;
|
|
525
|
+
--theme-primary-90: #dee0ff;
|
|
526
|
+
--theme-primary-95: #eff0ff;
|
|
527
|
+
--theme-primary-99: #fffbff;
|
|
528
|
+
--theme-primary-100: #ffffff;
|
|
529
|
+
|
|
530
|
+
/* Secondary, tertiary, neutral, error palettes... */
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/* Dark mode overrides */
|
|
534
|
+
@media (prefers-color-scheme: dark) {
|
|
535
|
+
:root {
|
|
536
|
+
/* Dark scheme mappings */
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
### Tailwind Configuration
|
|
542
|
+
|
|
543
|
+
```javascript
|
|
544
|
+
// Generate Tailwind config from theme
|
|
545
|
+
function generateTailwindConfig(theme) {
|
|
546
|
+
return {
|
|
547
|
+
theme: {
|
|
548
|
+
extend: {
|
|
549
|
+
colors: {
|
|
550
|
+
primary: {
|
|
551
|
+
DEFAULT: theme.primary,
|
|
552
|
+
50: theme.palettes.primary[95],
|
|
553
|
+
100: theme.palettes.primary[90],
|
|
554
|
+
200: theme.palettes.primary[80],
|
|
555
|
+
300: theme.palettes.primary[70],
|
|
556
|
+
400: theme.palettes.primary[60],
|
|
557
|
+
500: theme.palettes.primary[50],
|
|
558
|
+
600: theme.palettes.primary[40],
|
|
559
|
+
700: theme.palettes.primary[30],
|
|
560
|
+
800: theme.palettes.primary[20],
|
|
561
|
+
900: theme.palettes.primary[10],
|
|
562
|
+
950: theme.palettes.primary[0]
|
|
563
|
+
},
|
|
564
|
+
surface: {
|
|
565
|
+
DEFAULT: theme.surface,
|
|
566
|
+
container: theme.surfaceContainer,
|
|
567
|
+
variant: theme.surfaceVariant
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
### Sass/SCSS Variables
|
|
577
|
+
|
|
578
|
+
```scss
|
|
579
|
+
// Generate Sass variables
|
|
580
|
+
$theme-primary: #6366f1;
|
|
581
|
+
$theme-on-primary: #ffffff;
|
|
582
|
+
$theme-primary-container: #e0e0ff;
|
|
583
|
+
$theme-on-primary-container: #070764;
|
|
584
|
+
|
|
585
|
+
// Mixin for component theming
|
|
586
|
+
@mixin apply-theme($role: 'surface') {
|
|
587
|
+
@if $role == 'primary' {
|
|
588
|
+
background: $theme-primary;
|
|
589
|
+
color: $theme-on-primary;
|
|
590
|
+
} @else if $role == 'primary-container' {
|
|
591
|
+
background: $theme-primary-container;
|
|
592
|
+
color: $theme-on-primary-container;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// Usage
|
|
597
|
+
.button-primary {
|
|
598
|
+
@include apply-theme('primary');
|
|
599
|
+
}
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
## Accessibility Considerations
|
|
603
|
+
|
|
604
|
+
### Ensuring Contrast
|
|
605
|
+
|
|
606
|
+
```javascript
|
|
607
|
+
// Validate theme accessibility
|
|
608
|
+
function validateThemeAccessibility(theme) {
|
|
609
|
+
const checks = [
|
|
610
|
+
// Text on backgrounds
|
|
611
|
+
{ fg: theme.onSurface, bg: theme.surface, min: 4.5 },
|
|
612
|
+
{ fg: theme.onPrimary, bg: theme.primary, min: 4.5 },
|
|
613
|
+
{ fg: theme.onSecondary, bg: theme.secondary, min: 4.5 },
|
|
614
|
+
|
|
615
|
+
// Interactive elements
|
|
616
|
+
{ fg: theme.primary, bg: theme.surface, min: 3.0 },
|
|
617
|
+
{ fg: theme.outline, bg: theme.surface, min: 3.0 }
|
|
618
|
+
];
|
|
619
|
+
|
|
620
|
+
const results = checks.map(check => {
|
|
621
|
+
const ratio = checkContrast(check.fg, check.bg);
|
|
622
|
+
return {
|
|
623
|
+
...check,
|
|
624
|
+
ratio,
|
|
625
|
+
passes: ratio >= check.min
|
|
626
|
+
};
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
return {
|
|
630
|
+
allPass: results.every(r => r.passes),
|
|
631
|
+
failures: results.filter(r => !r.passes)
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
### High Contrast Mode
|
|
637
|
+
|
|
638
|
+
```javascript
|
|
639
|
+
// Generate high contrast variant
|
|
640
|
+
function createHighContrastTheme(baseTheme) {
|
|
641
|
+
return {
|
|
642
|
+
...baseTheme,
|
|
643
|
+
// Maximize contrast
|
|
644
|
+
surface: "#ffffff",
|
|
645
|
+
onSurface: "#000000",
|
|
646
|
+
|
|
647
|
+
// Bold colors
|
|
648
|
+
primary: adjustTone(baseTheme.primary, 30),
|
|
649
|
+
onPrimary: "#ffffff",
|
|
650
|
+
|
|
651
|
+
// Strong outlines
|
|
652
|
+
outline: "#000000",
|
|
653
|
+
outlineVariant: "#424242",
|
|
654
|
+
|
|
655
|
+
// Remove subtle variations
|
|
656
|
+
surfaceVariant: "#ffffff",
|
|
657
|
+
surfaceContainer: "#ffffff"
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
### Color Blindness Support
|
|
663
|
+
|
|
664
|
+
```javascript
|
|
665
|
+
// Adjust theme for color blindness
|
|
666
|
+
function adjustForColorBlindness(theme, type) {
|
|
667
|
+
switch (type) {
|
|
668
|
+
case 'protanopia': // Red-blind
|
|
669
|
+
// Shift reds toward blue
|
|
670
|
+
return shiftProblemColors(theme, ['red'], 'blue');
|
|
671
|
+
|
|
672
|
+
case 'deuteranopia': // Green-blind
|
|
673
|
+
// Enhance red-blue distinction
|
|
674
|
+
return enhanceColorDistinction(theme, ['red', 'blue']);
|
|
675
|
+
|
|
676
|
+
case 'tritanopia': // Blue-blind
|
|
677
|
+
// Use red-green distinction
|
|
678
|
+
return shiftProblemColors(theme, ['blue'], 'green');
|
|
679
|
+
|
|
680
|
+
case 'achromatopsia': // Total color blindness
|
|
681
|
+
// Use only lightness variations
|
|
682
|
+
return createMonochromeTheme(theme);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
## Real-World Examples
|
|
688
|
+
|
|
689
|
+
### News Website
|
|
690
|
+
|
|
691
|
+
```javascript
|
|
692
|
+
// Serious, trustworthy appearance
|
|
693
|
+
const newsTheme = {
|
|
694
|
+
// Core colors
|
|
695
|
+
primary: "#1e40af", // Deep blue
|
|
696
|
+
secondary: "#dc2626", // Breaking news red
|
|
697
|
+
neutral: "#1f2937", // Text
|
|
698
|
+
|
|
699
|
+
// Sections
|
|
700
|
+
politics: "#1e40af",
|
|
701
|
+
business: "#059669",
|
|
702
|
+
sports: "#ea580c",
|
|
703
|
+
entertainment: "#9333ea",
|
|
704
|
+
technology: "#0891b2",
|
|
705
|
+
|
|
706
|
+
// UI elements
|
|
707
|
+
surface: "#ffffff",
|
|
708
|
+
surfaceRaised: "#f9fafb",
|
|
709
|
+
border: "#e5e7eb",
|
|
710
|
+
|
|
711
|
+
// Typography
|
|
712
|
+
headline: "#111827",
|
|
713
|
+
body: "#374151",
|
|
714
|
+
caption: "#6b7280"
|
|
715
|
+
};
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
### Social Media Platform
|
|
719
|
+
|
|
720
|
+
```javascript
|
|
721
|
+
// Friendly, engaging theme
|
|
722
|
+
const socialTheme = generateMaterialTheme({
|
|
723
|
+
sourceColor: "#3b82f6", // Facebook-like blue
|
|
724
|
+
customColors: [
|
|
725
|
+
{ name: "like", color: "#ef4444" }, // Red heart
|
|
726
|
+
{ name: "share", color: "#10b981" }, // Green share
|
|
727
|
+
{ name: "comment", color: "#6366f1" } // Blue comment
|
|
728
|
+
],
|
|
729
|
+
variant: "vibrant"
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
// Additional social elements
|
|
733
|
+
const socialElements = {
|
|
734
|
+
// User-generated content
|
|
735
|
+
userPost: socialTheme.surface,
|
|
736
|
+
userPostHover: socialTheme.surfaceVariant,
|
|
737
|
+
|
|
738
|
+
// Interactions
|
|
739
|
+
likeButton: "#ef4444",
|
|
740
|
+
likeButtonActive: "#dc2626",
|
|
741
|
+
|
|
742
|
+
// Status indicators
|
|
743
|
+
online: "#10b981",
|
|
744
|
+
away: "#f59e0b",
|
|
745
|
+
offline: "#6b7280"
|
|
746
|
+
};
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
### Educational Platform
|
|
750
|
+
|
|
751
|
+
```javascript
|
|
752
|
+
// Clear, focused learning environment
|
|
753
|
+
const eduTheme = {
|
|
754
|
+
// Subject colors
|
|
755
|
+
math: "#3b82f6", // Blue
|
|
756
|
+
science: "#10b981", // Green
|
|
757
|
+
literature: "#8b5cf6", // Purple
|
|
758
|
+
history: "#f59e0b", // Amber
|
|
759
|
+
arts: "#ec4899", // Pink
|
|
760
|
+
|
|
761
|
+
// Progress indicators
|
|
762
|
+
notStarted: "#e5e7eb",
|
|
763
|
+
inProgress: "#fbbf24",
|
|
764
|
+
completed: "#10b981",
|
|
765
|
+
|
|
766
|
+
// Difficulty levels
|
|
767
|
+
beginner: "#10b981",
|
|
768
|
+
intermediate: "#3b82f6",
|
|
769
|
+
advanced: "#7c3aed",
|
|
770
|
+
expert: "#dc2626"
|
|
771
|
+
};
|
|
772
|
+
```
|
|
773
|
+
|
|
774
|
+
## Theme Testing
|
|
775
|
+
|
|
776
|
+
### Visual Testing
|
|
777
|
+
|
|
778
|
+
```javascript
|
|
779
|
+
// Generate theme preview
|
|
780
|
+
function previewTheme(theme) {
|
|
781
|
+
const preview = {
|
|
782
|
+
// Color swatches
|
|
783
|
+
swatches: Object.entries(theme).map(([name, color]) => ({
|
|
784
|
+
name,
|
|
785
|
+
color,
|
|
786
|
+
hex: color,
|
|
787
|
+
rgb: hexToRgb(color),
|
|
788
|
+
hsl: hexToHsl(color)
|
|
789
|
+
})),
|
|
790
|
+
|
|
791
|
+
// Sample components
|
|
792
|
+
components: {
|
|
793
|
+
button: generateButtonPreview(theme),
|
|
794
|
+
card: generateCardPreview(theme),
|
|
795
|
+
form: generateFormPreview(theme)
|
|
796
|
+
},
|
|
797
|
+
|
|
798
|
+
// Accessibility report
|
|
799
|
+
accessibility: validateThemeAccessibility(theme),
|
|
800
|
+
|
|
801
|
+
// Color harmony analysis
|
|
802
|
+
harmony: analyzeColorHarmony(theme)
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
return preview;
|
|
806
|
+
}
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
### Automated Testing
|
|
810
|
+
|
|
811
|
+
```javascript
|
|
812
|
+
// Test theme generation
|
|
813
|
+
describe('Theme Creation', () => {
|
|
814
|
+
test('generates accessible color pairs', () => {
|
|
815
|
+
const theme = generateMaterialTheme('#6366f1');
|
|
816
|
+
|
|
817
|
+
// Check primary colors
|
|
818
|
+
const ratio = getContrast(
|
|
819
|
+
theme.schemes.light.primary,
|
|
820
|
+
theme.schemes.light.onPrimary
|
|
821
|
+
);
|
|
822
|
+
expect(ratio).toBeGreaterThanOrEqual(4.5);
|
|
823
|
+
});
|
|
824
|
+
|
|
825
|
+
test('maintains brand color fidelity', () => {
|
|
826
|
+
const brand = '#ff5722';
|
|
827
|
+
const theme = generateMaterialTheme({
|
|
828
|
+
sourceColor: brand,
|
|
829
|
+
variant: 'fidelity'
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
const distance = colorDistance(brand, theme.schemes.light.primary);
|
|
833
|
+
expect(distance).toBeLessThan(5);
|
|
834
|
+
});
|
|
835
|
+
});
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
## Export Formats
|
|
839
|
+
|
|
840
|
+
### JSON Export
|
|
841
|
+
|
|
842
|
+
```javascript
|
|
843
|
+
// Export theme as JSON
|
|
844
|
+
const themeJson = {
|
|
845
|
+
version: "1.0.0",
|
|
846
|
+
name: "My Theme",
|
|
847
|
+
author: "Designer Name",
|
|
848
|
+
colors: theme,
|
|
849
|
+
metadata: {
|
|
850
|
+
created: new Date().toISOString(),
|
|
851
|
+
sourceColor: "#6366f1",
|
|
852
|
+
variant: "tonalSpot",
|
|
853
|
+
contrastLevel: 0
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
|
|
857
|
+
fs.writeFileSync('theme.json', JSON.stringify(themeJson, null, 2));
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
### Design Tokens
|
|
861
|
+
|
|
862
|
+
```javascript
|
|
863
|
+
// Export as design tokens
|
|
864
|
+
const tokens = {
|
|
865
|
+
color: {
|
|
866
|
+
primary: {
|
|
867
|
+
value: theme.primary,
|
|
868
|
+
type: "color"
|
|
869
|
+
},
|
|
870
|
+
onPrimary: {
|
|
871
|
+
value: theme.onPrimary,
|
|
872
|
+
type: "color"
|
|
873
|
+
}
|
|
874
|
+
},
|
|
875
|
+
spacing: {
|
|
876
|
+
small: { value: "8px", type: "dimension" },
|
|
877
|
+
medium: { value: "16px", type: "dimension" },
|
|
878
|
+
large: { value: "24px", type: "dimension" }
|
|
879
|
+
},
|
|
880
|
+
typography: {
|
|
881
|
+
heading: {
|
|
882
|
+
value: {
|
|
883
|
+
fontFamily: "Inter",
|
|
884
|
+
fontSize: "24px",
|
|
885
|
+
fontWeight: 600
|
|
886
|
+
},
|
|
887
|
+
type: "typography"
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
## Next Steps
|
|
894
|
+
|
|
895
|
+
- Explore [Image Extraction](./image-extraction.md) for dynamic theme generation
|
|
896
|
+
- Learn about [CSS Refactoring](./css-refactoring.md) to apply themes
|
|
897
|
+
- Read [Material Design Concepts](../concepts/material-design.md) for theory
|
|
898
|
+
- Check [Theme Matching Tools](../tools/theme-matching.md) for implementation
|