@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.
Files changed (197) hide show
  1. package/.claude/settings.local.json +39 -0
  2. package/.env +2 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +73 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.md +71 -0
  5. package/.github/pull_request_template.md +97 -0
  6. package/.github/workflows/ci.yml +127 -0
  7. package/.github/workflows/deploy-docs.yml +56 -0
  8. package/.github/workflows/release.yml +99 -0
  9. package/.mcp.json +12 -0
  10. package/.prettierignore +1 -0
  11. package/CLAUDE.md +201 -0
  12. package/DOCUMENTATION.md +274 -0
  13. package/GEMINI.md +54 -0
  14. package/LICENSE +21 -0
  15. package/README.md +401 -0
  16. package/demo/content_based_color.png +0 -0
  17. package/demo/music-player.html +621 -0
  18. package/demo/podcast-player.html +903 -0
  19. package/dist/bin/coolors-mcp.d.ts +1 -0
  20. package/dist/bin/coolors-mcp.js +154 -0
  21. package/dist/bin/coolors-mcp.js.map +1 -0
  22. package/dist/bin/server.d.ts +1 -0
  23. package/dist/bin/server.js +3292 -0
  24. package/dist/bin/server.js.map +1 -0
  25. package/dist/chunk-IQ7NN26V.js +114 -0
  26. package/dist/chunk-IQ7NN26V.js.map +1 -0
  27. package/dist/chunk-P3ARRKLS.js +1214 -0
  28. package/dist/chunk-P3ARRKLS.js.map +1 -0
  29. package/dist/color/index.d.ts +716 -0
  30. package/dist/color/index.js +153 -0
  31. package/dist/color/index.js.map +1 -0
  32. package/dist/coolors-mcp.d.ts +136 -0
  33. package/dist/coolors-mcp.js +7 -0
  34. package/dist/coolors-mcp.js.map +1 -0
  35. package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js +93 -0
  36. package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js.map +7 -0
  37. package/docs/.vitepress/cache/deps/_metadata.json +127 -0
  38. package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js +9 -0
  39. package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js.map +7 -0
  40. package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js +12683 -0
  41. package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js.map +7 -0
  42. package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js +9719 -0
  43. package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js.map +7 -0
  44. package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js +4710 -0
  45. package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js.map +7 -0
  46. package/docs/.vitepress/cache/deps/cytoscape.js +30278 -0
  47. package/docs/.vitepress/cache/deps/cytoscape.js.map +7 -0
  48. package/docs/.vitepress/cache/deps/dayjs.js +285 -0
  49. package/docs/.vitepress/cache/deps/dayjs.js.map +7 -0
  50. package/docs/.vitepress/cache/deps/debug.js +468 -0
  51. package/docs/.vitepress/cache/deps/debug.js.map +7 -0
  52. package/docs/.vitepress/cache/deps/package.json +3 -0
  53. package/docs/.vitepress/cache/deps/prismjs.js +1466 -0
  54. package/docs/.vitepress/cache/deps/prismjs.js.map +7 -0
  55. package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js +228 -0
  56. package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js.map +7 -0
  57. package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js +142 -0
  58. package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js.map +7 -0
  59. package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js +27 -0
  60. package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js.map +7 -0
  61. package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js +65 -0
  62. package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js.map +7 -0
  63. package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js +53 -0
  64. package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js.map +7 -0
  65. package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js +73 -0
  66. package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js.map +7 -0
  67. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4507 -0
  68. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  69. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +584 -0
  70. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  71. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1146 -0
  72. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
  73. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1667 -0
  74. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
  75. package/docs/.vitepress/cache/deps/vitepress___minisearch.js +1814 -0
  76. package/docs/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
  77. package/docs/.vitepress/cache/deps/vue.js +344 -0
  78. package/docs/.vitepress/cache/deps/vue.js.map +7 -0
  79. package/docs/.vitepress/components/ClientGrid.vue +125 -0
  80. package/docs/.vitepress/components/CodeBlock.vue +231 -0
  81. package/docs/.vitepress/components/ConfigModal.vue +477 -0
  82. package/docs/.vitepress/components/DiagramModal.vue +528 -0
  83. package/docs/.vitepress/components/TroubleshootingModal.vue +472 -0
  84. package/docs/.vitepress/config.js +162 -0
  85. package/docs/.vitepress/theme/FundingLayout.vue +251 -0
  86. package/docs/.vitepress/theme/Layout.vue +134 -0
  87. package/docs/.vitepress/theme/components/AdBanner.vue +317 -0
  88. package/docs/.vitepress/theme/components/AdPlaceholder.vue +78 -0
  89. package/docs/.vitepress/theme/components/FundingEffects.vue +322 -0
  90. package/docs/.vitepress/theme/components/FundingHero.vue +345 -0
  91. package/docs/.vitepress/theme/components/SupportSection.vue +511 -0
  92. package/docs/.vitepress/theme/custom-app.css +339 -0
  93. package/docs/.vitepress/theme/custom.css +699 -0
  94. package/docs/.vitepress/theme/index.js +25 -0
  95. package/docs/README.md +198 -0
  96. package/docs/concepts/accessibility.md +473 -0
  97. package/docs/concepts/color-spaces.md +222 -0
  98. package/docs/concepts/distance-metrics.md +384 -0
  99. package/docs/concepts/hct.md +261 -0
  100. package/docs/concepts/image-analysis.md +396 -0
  101. package/docs/concepts/material-design.md +306 -0
  102. package/docs/concepts/theme-matching.md +399 -0
  103. package/docs/examples/basic-colors.md +490 -0
  104. package/docs/examples/creating-themes.md +898 -0
  105. package/docs/examples/css-refactoring.md +824 -0
  106. package/docs/examples/image-extraction.md +882 -0
  107. package/docs/getting-started.md +366 -0
  108. package/docs/index.md +190 -0
  109. package/docs/installation.md +157 -0
  110. package/docs/tools/README.md +234 -0
  111. package/docs/tools/accessibility.md +614 -0
  112. package/docs/tools/color-operations.md +374 -0
  113. package/docs/tools/image-extraction.md +624 -0
  114. package/docs/tools/material-design.md +347 -0
  115. package/docs/tools/theme-matching.md +552 -0
  116. package/eslint.config.ts +14 -0
  117. package/examples/theme-matching.md +113 -0
  118. package/jsr.json +7 -0
  119. package/mcp-config.json +8 -0
  120. package/note.md +35 -0
  121. package/package.json +122 -0
  122. package/research_results.md +53 -0
  123. package/src/bin/coolors-mcp.ts +194 -0
  124. package/src/bin/server.ts +61 -0
  125. package/src/color/__tests__/conversions-argb.test.ts +198 -0
  126. package/src/color/__tests__/extract-colors.test.ts +360 -0
  127. package/src/color/__tests__/image-utils.test.ts +242 -0
  128. package/src/color/__tests__/reference-colors.test.ts +278 -0
  129. package/src/color/__tests__/round-trip.test.ts +197 -0
  130. package/src/color/conversions.test.ts +402 -0
  131. package/src/color/conversions.ts +393 -0
  132. package/src/color/dislike/__tests__/dislike-analyzer.test.ts +248 -0
  133. package/src/color/dislike/dislike-analyzer.ts +114 -0
  134. package/src/color/extract-colors.ts +228 -0
  135. package/src/color/hct/__tests__/hct-class.test.ts +232 -0
  136. package/src/color/hct/harmonization.ts +204 -0
  137. package/src/color/hct/hct-class.ts +109 -0
  138. package/src/color/hct/hct-solver.ts +168 -0
  139. package/src/color/hct/index.ts +39 -0
  140. package/src/color/hct/tonal-palette.ts +211 -0
  141. package/src/color/hct/types.ts +88 -0
  142. package/src/color/image-utils.ts +79 -0
  143. package/src/color/index.ts +87 -0
  144. package/src/color/material-theme.ts +157 -0
  145. package/src/color/metrics.test.ts +276 -0
  146. package/src/color/metrics.ts +281 -0
  147. package/src/color/quantize/__tests__/quantizer_celebi.test.ts +195 -0
  148. package/src/color/quantize/lab_point_provider.ts +55 -0
  149. package/src/color/quantize/point_provider.ts +27 -0
  150. package/src/color/quantize/quantizer_celebi.ts +51 -0
  151. package/src/color/quantize/quantizer_celebi_test.ts +71 -0
  152. package/src/color/quantize/quantizer_map.ts +47 -0
  153. package/src/color/quantize/quantizer_wsmeans.ts +232 -0
  154. package/src/color/quantize/quantizer_wu.ts +472 -0
  155. package/src/color/score/__tests__/score.test.ts +224 -0
  156. package/src/color/score/score.ts +175 -0
  157. package/src/color/types.ts +151 -0
  158. package/src/color/utils/color_utils.ts +292 -0
  159. package/src/color/utils/math_utils.ts +145 -0
  160. package/src/color/utils.test.ts +403 -0
  161. package/src/color/utils.ts +315 -0
  162. package/src/constants.ts +5 -0
  163. package/src/coolors-mcp.ts +37 -0
  164. package/src/examples/addition.ts +333 -0
  165. package/src/examples/color-demo.ts +125 -0
  166. package/src/examples/custom-logger.ts +201 -0
  167. package/src/examples/oauth-server.ts +113 -0
  168. package/src/examples/session-context.ts +269 -0
  169. package/src/session.ts +116 -0
  170. package/src/theme/__tests__/matcher.test.ts +180 -0
  171. package/src/theme/__tests__/parser.test.ts +148 -0
  172. package/src/theme/__tests__/refactor.test.ts +224 -0
  173. package/src/theme/index.ts +34 -0
  174. package/src/theme/matcher.ts +395 -0
  175. package/src/theme/parser.ts +392 -0
  176. package/src/theme/refactor.ts +360 -0
  177. package/src/theme/types.ts +152 -0
  178. package/src/tools/__tests__/gradient-generator.test.ts +206 -0
  179. package/src/tools/__tests__/palette-with-locks.test.ts +109 -0
  180. package/src/tools/color-conversion.tool.ts +54 -0
  181. package/src/tools/color-distance.tool.ts +41 -0
  182. package/src/tools/colors.ts +31 -0
  183. package/src/tools/contrast-checker.tool.ts +37 -0
  184. package/src/tools/dislike-analyzer.tool.ts +247 -0
  185. package/src/tools/gradient-generator.tool.ts +250 -0
  186. package/src/tools/image-extraction.tools.ts +289 -0
  187. package/src/tools/index.ts +39 -0
  188. package/src/tools/material-theme.tools.ts +250 -0
  189. package/src/tools/palette-generator.tool.ts +135 -0
  190. package/src/tools/palette-with-locks.tool.ts +221 -0
  191. package/src/tools/registry.ts +142 -0
  192. package/src/tools/simple-tools.ts +37 -0
  193. package/src/tools/theme-matching.tools.ts +334 -0
  194. package/src/types.ts +182 -0
  195. package/src/utils.ts +22 -0
  196. package/tsconfig.json +8 -0
  197. package/vitest.config.js +15 -0
@@ -0,0 +1,621 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Content-Based Color Demo - Music Player</title>
7
+ <style>
8
+ :root {
9
+ /* Material Design 3 - Light Theme (from teal seed color #0E7490) */
10
+ --md-sys-color-primary: #006d9e;
11
+ --md-sys-color-on-primary: #ffffff;
12
+ --md-sys-color-primary-container: #c0e9fb;
13
+ --md-sys-color-on-primary-container: #002851;
14
+
15
+ --md-sys-color-secondary: #3c6473;
16
+ --md-sys-color-on-secondary: #ffffff;
17
+ --md-sys-color-secondary-container: #c0e9fb;
18
+ --md-sys-color-on-secondary-container: #00202d;
19
+
20
+ --md-sys-color-tertiary: #5b5b82;
21
+ --md-sys-color-on-tertiary: #ffffff;
22
+ --md-sys-color-tertiary-container: #e1deff;
23
+ --md-sys-color-on-tertiary-container: #151839;
24
+
25
+ --md-sys-color-background: #f8fdff;
26
+ --md-sys-color-on-background: #181c1e;
27
+ --md-sys-color-surface: #f8fdff;
28
+ --md-sys-color-on-surface: #181c1e;
29
+ --md-sys-color-surface-variant: #d9e4e9;
30
+ --md-sys-color-on-surface-variant: #3f484c;
31
+
32
+ --md-sys-color-outline: #6f797d;
33
+ --md-sys-color-outline-variant: #bdc8cd;
34
+
35
+ /* Tonal variations for UI elements */
36
+ --md-sys-color-surface-container: #e8f4f9;
37
+ --md-sys-color-surface-container-high: #dfeef4;
38
+ --md-sys-color-surface-container-highest: #d9e4e9;
39
+ }
40
+
41
+ @media (prefers-color-scheme: dark) {
42
+ :root {
43
+ /* Material Design 3 - Dark Theme */
44
+ --md-sys-color-primary: #00d8ff;
45
+ --md-sys-color-on-primary: #003d6a;
46
+ --md-sys-color-primary-container: #005583;
47
+ --md-sys-color-on-primary-container: #32f5ff;
48
+
49
+ --md-sys-color-secondary: #a4cdde;
50
+ --md-sys-color-on-secondary: #063543;
51
+ --md-sys-color-secondary-container: #234c5a;
52
+ --md-sys-color-on-secondary-container: #c0e9fb;
53
+
54
+ --md-sys-color-tertiary: #c5c2ef;
55
+ --md-sys-color-on-tertiary: #2c2d50;
56
+ --md-sys-color-tertiary-container: #434369;
57
+ --md-sys-color-on-tertiary-container: #e1deff;
58
+
59
+ --md-sys-color-background: #0f1416;
60
+ --md-sys-color-on-background: #dee3e6;
61
+ --md-sys-color-surface: #181c1e;
62
+ --md-sys-color-on-surface: #dee3e6;
63
+ --md-sys-color-surface-variant: #3f484c;
64
+ --md-sys-color-on-surface-variant: #bdc8cd;
65
+
66
+ --md-sys-color-outline: #889297;
67
+ --md-sys-color-outline-variant: #3f484c;
68
+
69
+ --md-sys-color-surface-container: #1e2426;
70
+ --md-sys-color-surface-container-high: #272d30;
71
+ --md-sys-color-surface-container-highest: #323739;
72
+ }
73
+ }
74
+
75
+ * {
76
+ margin: 0;
77
+ padding: 0;
78
+ box-sizing: border-box;
79
+ }
80
+
81
+ body {
82
+ font-family:
83
+ -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu,
84
+ sans-serif;
85
+ background: var(--md-sys-color-background);
86
+ color: var(--md-sys-color-on-background);
87
+ min-height: 100vh;
88
+ display: flex;
89
+ justify-content: center;
90
+ align-items: center;
91
+ padding: 20px;
92
+ background: linear-gradient(
93
+ 135deg,
94
+ var(--md-sys-color-primary-container) 0%,
95
+ var(--md-sys-color-secondary-container) 100%
96
+ );
97
+ }
98
+
99
+ .phone-container {
100
+ width: 375px;
101
+ height: 812px;
102
+ background: var(--md-sys-color-surface);
103
+ border-radius: 40px;
104
+ box-shadow:
105
+ 0 20px 60px rgba(0, 0, 0, 0.3),
106
+ 0 0 0 1px var(--md-sys-color-outline-variant);
107
+ overflow: hidden;
108
+ position: relative;
109
+ }
110
+
111
+ .status-bar {
112
+ height: 44px;
113
+ padding: 0 24px;
114
+ display: flex;
115
+ justify-content: space-between;
116
+ align-items: center;
117
+ background: var(--md-sys-color-surface);
118
+ font-size: 14px;
119
+ font-weight: 600;
120
+ }
121
+
122
+ .status-icons {
123
+ display: flex;
124
+ gap: 6px;
125
+ }
126
+
127
+ .header {
128
+ height: 56px;
129
+ padding: 0 16px;
130
+ display: flex;
131
+ align-items: center;
132
+ gap: 16px;
133
+ background: var(--md-sys-color-surface);
134
+ border-bottom: 1px solid var(--md-sys-color-outline-variant);
135
+ }
136
+
137
+ .back-button {
138
+ width: 40px;
139
+ height: 40px;
140
+ border: none;
141
+ background: transparent;
142
+ color: var(--md-sys-color-on-surface);
143
+ cursor: pointer;
144
+ border-radius: 20px;
145
+ display: flex;
146
+ align-items: center;
147
+ justify-content: center;
148
+ transition: background 0.2s;
149
+ }
150
+
151
+ .back-button:hover {
152
+ background: var(--md-sys-color-surface-variant);
153
+ }
154
+
155
+ .header-title {
156
+ font-size: 20px;
157
+ font-weight: 500;
158
+ color: var(--md-sys-color-on-surface);
159
+ }
160
+
161
+ .content {
162
+ padding: 32px 24px;
163
+ display: flex;
164
+ flex-direction: column;
165
+ align-items: center;
166
+ gap: 32px;
167
+ height: calc(100% - 100px);
168
+ overflow-y: auto;
169
+ }
170
+
171
+ .album-container {
172
+ position: relative;
173
+ width: 280px;
174
+ height: 280px;
175
+ }
176
+
177
+ .album-art {
178
+ width: 100%;
179
+ height: 100%;
180
+ border-radius: 24px;
181
+ background: var(--md-sys-color-primary);
182
+ position: relative;
183
+ overflow: hidden;
184
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
185
+ }
186
+
187
+ .album-pattern {
188
+ position: absolute;
189
+ inset: 0;
190
+ display: grid;
191
+ grid-template-columns: repeat(12, 1fr);
192
+ grid-template-rows: repeat(12, 1fr);
193
+ gap: 3px;
194
+ padding: 20px;
195
+ }
196
+
197
+ .pattern-cell {
198
+ border-radius: 2px;
199
+ animation: pulse 3s ease-in-out infinite;
200
+ }
201
+
202
+ .pattern-cell:nth-child(3n) {
203
+ background: var(--md-sys-color-tertiary);
204
+ animation-delay: 0.1s;
205
+ }
206
+
207
+ .pattern-cell:nth-child(3n + 1) {
208
+ background: var(--md-sys-color-secondary);
209
+ animation-delay: 0.2s;
210
+ }
211
+
212
+ .pattern-cell:nth-child(3n + 2) {
213
+ background: var(--md-sys-color-primary-container);
214
+ animation-delay: 0.3s;
215
+ }
216
+
217
+ .pattern-cell:nth-child(5n) {
218
+ background: var(--md-sys-color-tertiary-container);
219
+ }
220
+
221
+ .pattern-cell:nth-child(7n) {
222
+ background: var(--md-sys-color-on-primary);
223
+ opacity: 0.8;
224
+ }
225
+
226
+ .pattern-cell:nth-child(11n) {
227
+ background: var(--md-sys-color-secondary-container);
228
+ }
229
+
230
+ @keyframes pulse {
231
+ 0%,
232
+ 100% {
233
+ opacity: 0.6;
234
+ transform: scale(0.95);
235
+ }
236
+ 50% {
237
+ opacity: 1;
238
+ transform: scale(1);
239
+ }
240
+ }
241
+
242
+ .track-info {
243
+ text-align: center;
244
+ width: 100%;
245
+ }
246
+
247
+ .track-title {
248
+ font-size: 28px;
249
+ font-weight: 600;
250
+ color: var(--md-sys-color-on-surface);
251
+ margin-bottom: 8px;
252
+ }
253
+
254
+ .track-artist {
255
+ font-size: 16px;
256
+ color: var(--md-sys-color-on-surface-variant);
257
+ }
258
+
259
+ .progress-container {
260
+ width: 100%;
261
+ }
262
+
263
+ .progress-bar {
264
+ width: 100%;
265
+ height: 4px;
266
+ background: var(--md-sys-color-surface-variant);
267
+ border-radius: 2px;
268
+ position: relative;
269
+ margin-bottom: 8px;
270
+ }
271
+
272
+ .progress-fill {
273
+ height: 100%;
274
+ width: 40%;
275
+ background: var(--md-sys-color-primary);
276
+ border-radius: 2px;
277
+ position: relative;
278
+ }
279
+
280
+ .progress-handle {
281
+ position: absolute;
282
+ right: -8px;
283
+ top: -6px;
284
+ width: 16px;
285
+ height: 16px;
286
+ background: var(--md-sys-color-primary);
287
+ border-radius: 50%;
288
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
289
+ }
290
+
291
+ .time-labels {
292
+ display: flex;
293
+ justify-content: space-between;
294
+ font-size: 12px;
295
+ color: var(--md-sys-color-on-surface-variant);
296
+ }
297
+
298
+ .controls {
299
+ display: flex;
300
+ align-items: center;
301
+ justify-content: center;
302
+ gap: 24px;
303
+ width: 100%;
304
+ }
305
+
306
+ .control-btn {
307
+ background: transparent;
308
+ border: none;
309
+ color: var(--md-sys-color-on-surface);
310
+ cursor: pointer;
311
+ display: flex;
312
+ align-items: center;
313
+ justify-content: center;
314
+ transition: transform 0.2s;
315
+ }
316
+
317
+ .control-btn:hover {
318
+ transform: scale(1.1);
319
+ }
320
+
321
+ .control-btn:active {
322
+ transform: scale(0.95);
323
+ }
324
+
325
+ .control-btn.small {
326
+ width: 32px;
327
+ height: 32px;
328
+ opacity: 0.7;
329
+ }
330
+
331
+ .control-btn.medium {
332
+ width: 48px;
333
+ height: 48px;
334
+ }
335
+
336
+ .control-btn.primary {
337
+ width: 72px;
338
+ height: 72px;
339
+ background: var(--md-sys-color-primary);
340
+ color: var(--md-sys-color-on-primary);
341
+ border-radius: 50%;
342
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
343
+ }
344
+
345
+ .volume-container {
346
+ width: 100%;
347
+ padding: 24px 0;
348
+ display: flex;
349
+ align-items: center;
350
+ gap: 16px;
351
+ }
352
+
353
+ .volume-icon {
354
+ color: var(--md-sys-color-on-surface-variant);
355
+ }
356
+
357
+ .volume-slider {
358
+ flex: 1;
359
+ height: 48px;
360
+ background: var(--md-sys-color-primary);
361
+ border-radius: 24px;
362
+ position: relative;
363
+ display: flex;
364
+ align-items: center;
365
+ }
366
+
367
+ .volume-fill {
368
+ height: 100%;
369
+ width: 70%;
370
+ background: var(--md-sys-color-on-primary);
371
+ border-radius: 24px;
372
+ opacity: 0.3;
373
+ }
374
+
375
+ /* Icons */
376
+ .icon {
377
+ width: 24px;
378
+ height: 24px;
379
+ fill: currentColor;
380
+ }
381
+
382
+ .icon.large {
383
+ width: 32px;
384
+ height: 32px;
385
+ }
386
+
387
+ /* Demo controls */
388
+ .demo-controls {
389
+ position: absolute;
390
+ bottom: 20px;
391
+ right: 20px;
392
+ display: flex;
393
+ flex-direction: column;
394
+ gap: 12px;
395
+ z-index: 10;
396
+ }
397
+
398
+ .theme-toggle {
399
+ padding: 12px 20px;
400
+ background: var(--md-sys-color-primary);
401
+ color: var(--md-sys-color-on-primary);
402
+ border: none;
403
+ border-radius: 20px;
404
+ cursor: pointer;
405
+ font-size: 14px;
406
+ font-weight: 500;
407
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
408
+ transition: transform 0.2s;
409
+ }
410
+
411
+ .theme-toggle:hover {
412
+ transform: translateY(-2px);
413
+ }
414
+
415
+ .theme-toggle:active {
416
+ transform: translateY(0);
417
+ }
418
+ </style>
419
+ </head>
420
+ <body>
421
+ <div class="phone-container">
422
+ <div class="status-bar">
423
+ <span>9:30</span>
424
+ <div class="status-icons">
425
+ <span>🔋</span>
426
+ <span>📶</span>
427
+ <span>📡</span>
428
+ </div>
429
+ </div>
430
+
431
+ <div class="header">
432
+ <button class="back-button">
433
+ <svg class="icon" viewBox="0 0 24 24">
434
+ <path
435
+ d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"
436
+ />
437
+ </svg>
438
+ </button>
439
+ <span class="header-title">Now playing</span>
440
+ </div>
441
+
442
+ <div class="content">
443
+ <div class="album-container">
444
+ <div class="album-art">
445
+ <div class="album-pattern">
446
+ <!-- Generate pattern cells -->
447
+ <script>
448
+ for (let i = 0; i < 144; i++) {
449
+ document.write('<div class="pattern-cell"></div>');
450
+ }
451
+ </script>
452
+ </div>
453
+ </div>
454
+ </div>
455
+
456
+ <div class="track-info">
457
+ <div class="track-title">Early Aughts</div>
458
+ <div class="track-artist">Song Histories Podcast</div>
459
+ </div>
460
+
461
+ <div class="progress-container">
462
+ <div class="progress-bar">
463
+ <div class="progress-fill">
464
+ <div class="progress-handle"></div>
465
+ </div>
466
+ </div>
467
+ <div class="time-labels">
468
+ <span>1:28</span>
469
+ <span>3:03</span>
470
+ </div>
471
+ </div>
472
+
473
+ <div class="controls">
474
+ <button class="control-btn small">
475
+ <svg class="icon" viewBox="0 0 24 24">
476
+ <path
477
+ d="M10.59 9.17L5.41 4 4 5.41l5.17 5.17 1.42-1.41zM14.5 4l2.04 2.04L4 18.59 5.41 20 17.96 7.46 20 9.5V4h-5.5zm.33 9.41l-1.41 1.41 3.13 3.13L14.5 20H20v-5.5l-2.04 2.04-3.13-3.13z"
478
+ />
479
+ </svg>
480
+ </button>
481
+
482
+ <button class="control-btn medium">
483
+ <svg class="icon large" viewBox="0 0 24 24">
484
+ <path d="M6 6h2v12H6zm3.5 6l8.5 6V6z" />
485
+ </svg>
486
+ </button>
487
+
488
+ <button class="control-btn primary">
489
+ <svg class="icon large" viewBox="0 0 24 24">
490
+ <path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
491
+ </svg>
492
+ </button>
493
+
494
+ <button class="control-btn medium">
495
+ <svg class="icon large" viewBox="0 0 24 24">
496
+ <path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z" />
497
+ </svg>
498
+ </button>
499
+
500
+ <button class="control-btn small">
501
+ <svg class="icon" viewBox="0 0 24 24">
502
+ <path
503
+ d="M7 7h10v3l4-4-4-4v3H5v6h2V7zm10 10H7v-3l-4 4 4 4v-3h12v-6h-2v4z"
504
+ />
505
+ </svg>
506
+ </button>
507
+ </div>
508
+
509
+ <div class="volume-container">
510
+ <svg class="icon volume-icon" viewBox="0 0 24 24">
511
+ <path
512
+ d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"
513
+ />
514
+ </svg>
515
+ <div class="volume-slider">
516
+ <div class="volume-fill"></div>
517
+ </div>
518
+ </div>
519
+ </div>
520
+ </div>
521
+
522
+ <div class="demo-controls">
523
+ <button class="theme-toggle" onclick="toggleTheme()">Toggle Theme</button>
524
+ <button class="theme-toggle" onclick="changeAlbumColors()">
525
+ Change Album
526
+ </button>
527
+ </div>
528
+
529
+ <script>
530
+ let darkMode = false;
531
+
532
+ function toggleTheme() {
533
+ darkMode = !darkMode;
534
+ if (darkMode) {
535
+ document.documentElement.style.colorScheme = "dark";
536
+ applyDarkTheme();
537
+ } else {
538
+ document.documentElement.style.colorScheme = "light";
539
+ applyLightTheme();
540
+ }
541
+ }
542
+
543
+ function applyLightTheme() {
544
+ const root = document.documentElement;
545
+ root.style.setProperty("--md-sys-color-primary", "#006d9e");
546
+ root.style.setProperty("--md-sys-color-on-primary", "#ffffff");
547
+ root.style.setProperty("--md-sys-color-primary-container", "#c0e9fb");
548
+ root.style.setProperty("--md-sys-color-secondary", "#3c6473");
549
+ root.style.setProperty("--md-sys-color-secondary-container", "#c0e9fb");
550
+ root.style.setProperty("--md-sys-color-tertiary", "#5b5b82");
551
+ root.style.setProperty("--md-sys-color-tertiary-container", "#e1deff");
552
+ root.style.setProperty("--md-sys-color-background", "#f8fdff");
553
+ root.style.setProperty("--md-sys-color-on-background", "#181c1e");
554
+ root.style.setProperty("--md-sys-color-surface", "#f8fdff");
555
+ root.style.setProperty("--md-sys-color-on-surface", "#181c1e");
556
+ root.style.setProperty("--md-sys-color-surface-variant", "#d9e4e9");
557
+ root.style.setProperty("--md-sys-color-on-surface-variant", "#3f484c");
558
+ }
559
+
560
+ function applyDarkTheme() {
561
+ const root = document.documentElement;
562
+ root.style.setProperty("--md-sys-color-primary", "#00d8ff");
563
+ root.style.setProperty("--md-sys-color-on-primary", "#003d6a");
564
+ root.style.setProperty("--md-sys-color-primary-container", "#005583");
565
+ root.style.setProperty("--md-sys-color-secondary", "#a4cdde");
566
+ root.style.setProperty("--md-sys-color-secondary-container", "#234c5a");
567
+ root.style.setProperty("--md-sys-color-tertiary", "#c5c2ef");
568
+ root.style.setProperty("--md-sys-color-tertiary-container", "#434369");
569
+ root.style.setProperty("--md-sys-color-background", "#0f1416");
570
+ root.style.setProperty("--md-sys-color-on-background", "#dee3e6");
571
+ root.style.setProperty("--md-sys-color-surface", "#181c1e");
572
+ root.style.setProperty("--md-sys-color-on-surface", "#dee3e6");
573
+ root.style.setProperty("--md-sys-color-surface-variant", "#3f484c");
574
+ root.style.setProperty("--md-sys-color-on-surface-variant", "#bdc8cd");
575
+ }
576
+
577
+ const albumThemes = [
578
+ {
579
+ name: "Ocean",
580
+ primary: "#006d9e",
581
+ secondary: "#3c6473",
582
+ tertiary: "#5b5b82",
583
+ },
584
+ {
585
+ name: "Sunset",
586
+ primary: "#d84315",
587
+ secondary: "#ff6e40",
588
+ tertiary: "#ffab00",
589
+ },
590
+ {
591
+ name: "Forest",
592
+ primary: "#2e7d32",
593
+ secondary: "#66bb6a",
594
+ tertiary: "#8bc34a",
595
+ },
596
+ {
597
+ name: "Purple Dream",
598
+ primary: "#6a1b9a",
599
+ secondary: "#ab47bc",
600
+ tertiary: "#ce93d8",
601
+ },
602
+ ];
603
+
604
+ let currentAlbum = 0;
605
+
606
+ function changeAlbumColors() {
607
+ currentAlbum = (currentAlbum + 1) % albumThemes.length;
608
+ const theme = albumThemes[currentAlbum];
609
+
610
+ const root = document.documentElement;
611
+ root.style.setProperty("--md-sys-color-primary", theme.primary);
612
+ root.style.setProperty("--md-sys-color-secondary", theme.secondary);
613
+ root.style.setProperty("--md-sys-color-tertiary", theme.tertiary);
614
+
615
+ // Update track info to match album
616
+ document.querySelector(".track-title").textContent =
617
+ theme.name + " Vibes";
618
+ }
619
+ </script>
620
+ </body>
621
+ </html>