ui-ux-pro-max-cli 2.8.8

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 (160) hide show
  1. package/README.md +99 -0
  2. package/assets/data/_sync_all.py +414 -0
  3. package/assets/data/app-interface.csv +31 -0
  4. package/assets/data/charts.csv +26 -0
  5. package/assets/data/colors.csv +162 -0
  6. package/assets/data/design.csv +1776 -0
  7. package/assets/data/draft.csv +1779 -0
  8. package/assets/data/google-fonts.csv +1924 -0
  9. package/assets/data/icons.csv +106 -0
  10. package/assets/data/landing.csv +35 -0
  11. package/assets/data/products.csv +162 -0
  12. package/assets/data/react-performance.csv +45 -0
  13. package/assets/data/stacks/angular.csv +51 -0
  14. package/assets/data/stacks/astro.csv +54 -0
  15. package/assets/data/stacks/flutter.csv +53 -0
  16. package/assets/data/stacks/html-tailwind.csv +56 -0
  17. package/assets/data/stacks/javafx.csv +76 -0
  18. package/assets/data/stacks/jetpack-compose.csv +53 -0
  19. package/assets/data/stacks/laravel.csv +51 -0
  20. package/assets/data/stacks/nextjs.csv +53 -0
  21. package/assets/data/stacks/nuxt-ui.csv +71 -0
  22. package/assets/data/stacks/nuxtjs.csv +59 -0
  23. package/assets/data/stacks/react-native.csv +52 -0
  24. package/assets/data/stacks/react.csv +54 -0
  25. package/assets/data/stacks/shadcn.csv +61 -0
  26. package/assets/data/stacks/svelte.csv +54 -0
  27. package/assets/data/stacks/swiftui.csv +51 -0
  28. package/assets/data/stacks/threejs.csv +54 -0
  29. package/assets/data/stacks/vue.csv +50 -0
  30. package/assets/data/styles.csv +85 -0
  31. package/assets/data/typography.csv +74 -0
  32. package/assets/data/ui-reasoning.csv +162 -0
  33. package/assets/data/ux-guidelines.csv +100 -0
  34. package/assets/scripts/core.py +263 -0
  35. package/assets/scripts/design_system.py +1157 -0
  36. package/assets/scripts/search.py +114 -0
  37. package/assets/skills/banner-design/SKILL.md +196 -0
  38. package/assets/skills/banner-design/references/banner-sizes-and-styles.md +118 -0
  39. package/assets/skills/brand/SKILL.md +97 -0
  40. package/assets/skills/brand/references/approval-checklist.md +169 -0
  41. package/assets/skills/brand/references/asset-organization.md +157 -0
  42. package/assets/skills/brand/references/brand-guideline-template.md +140 -0
  43. package/assets/skills/brand/references/color-palette-management.md +186 -0
  44. package/assets/skills/brand/references/consistency-checklist.md +94 -0
  45. package/assets/skills/brand/references/logo-usage-rules.md +185 -0
  46. package/assets/skills/brand/references/messaging-framework.md +85 -0
  47. package/assets/skills/brand/references/typography-specifications.md +214 -0
  48. package/assets/skills/brand/references/update.md +118 -0
  49. package/assets/skills/brand/references/visual-identity.md +96 -0
  50. package/assets/skills/brand/references/voice-framework.md +88 -0
  51. package/assets/skills/brand/scripts/extract-colors.cjs +341 -0
  52. package/assets/skills/brand/scripts/inject-brand-context.cjs +349 -0
  53. package/assets/skills/brand/scripts/sync-brand-to-tokens.cjs +266 -0
  54. package/assets/skills/brand/scripts/validate-asset.cjs +387 -0
  55. package/assets/skills/brand/templates/brand-guidelines-starter.md +275 -0
  56. package/assets/skills/design/SKILL.md +313 -0
  57. package/assets/skills/design/data/cip/deliverables.csv +51 -0
  58. package/assets/skills/design/data/cip/industries.csv +21 -0
  59. package/assets/skills/design/data/cip/mockup-contexts.csv +21 -0
  60. package/assets/skills/design/data/cip/styles.csv +21 -0
  61. package/assets/skills/design/data/icon/styles.csv +16 -0
  62. package/assets/skills/design/data/logo/colors.csv +56 -0
  63. package/assets/skills/design/data/logo/industries.csv +56 -0
  64. package/assets/skills/design/data/logo/styles.csv +56 -0
  65. package/assets/skills/design/references/banner-sizes-and-styles.md +118 -0
  66. package/assets/skills/design/references/cip-deliverable-guide.md +95 -0
  67. package/assets/skills/design/references/cip-design.md +121 -0
  68. package/assets/skills/design/references/cip-prompt-engineering.md +84 -0
  69. package/assets/skills/design/references/cip-style-guide.md +68 -0
  70. package/assets/skills/design/references/design-routing.md +207 -0
  71. package/assets/skills/design/references/icon-design.md +122 -0
  72. package/assets/skills/design/references/logo-color-psychology.md +101 -0
  73. package/assets/skills/design/references/logo-design.md +92 -0
  74. package/assets/skills/design/references/logo-prompt-engineering.md +158 -0
  75. package/assets/skills/design/references/logo-style-guide.md +109 -0
  76. package/assets/skills/design/references/slides-copywriting-formulas.md +84 -0
  77. package/assets/skills/design/references/slides-create.md +4 -0
  78. package/assets/skills/design/references/slides-html-template.md +295 -0
  79. package/assets/skills/design/references/slides-layout-patterns.md +137 -0
  80. package/assets/skills/design/references/slides-strategies.md +94 -0
  81. package/assets/skills/design/references/slides.md +42 -0
  82. package/assets/skills/design/references/social-photos-design.md +329 -0
  83. package/assets/skills/design/scripts/cip/core.py +215 -0
  84. package/assets/skills/design/scripts/cip/generate.py +484 -0
  85. package/assets/skills/design/scripts/cip/render-html.py +424 -0
  86. package/assets/skills/design/scripts/cip/search.py +127 -0
  87. package/assets/skills/design/scripts/icon/generate.py +487 -0
  88. package/assets/skills/design/scripts/logo/core.py +175 -0
  89. package/assets/skills/design/scripts/logo/generate.py +362 -0
  90. package/assets/skills/design/scripts/logo/search.py +114 -0
  91. package/assets/skills/design-system/SKILL.md +244 -0
  92. package/assets/skills/design-system/data/slide-backgrounds.csv +11 -0
  93. package/assets/skills/design-system/data/slide-charts.csv +26 -0
  94. package/assets/skills/design-system/data/slide-color-logic.csv +14 -0
  95. package/assets/skills/design-system/data/slide-copy.csv +26 -0
  96. package/assets/skills/design-system/data/slide-layout-logic.csv +16 -0
  97. package/assets/skills/design-system/data/slide-layouts.csv +26 -0
  98. package/assets/skills/design-system/data/slide-strategies.csv +16 -0
  99. package/assets/skills/design-system/data/slide-typography.csv +15 -0
  100. package/assets/skills/design-system/references/component-specs.md +236 -0
  101. package/assets/skills/design-system/references/component-tokens.md +214 -0
  102. package/assets/skills/design-system/references/primitive-tokens.md +203 -0
  103. package/assets/skills/design-system/references/semantic-tokens.md +215 -0
  104. package/assets/skills/design-system/references/states-and-variants.md +241 -0
  105. package/assets/skills/design-system/references/tailwind-integration.md +251 -0
  106. package/assets/skills/design-system/references/token-architecture.md +224 -0
  107. package/assets/skills/design-system/scripts/embed-tokens.cjs +99 -0
  108. package/assets/skills/design-system/scripts/fetch-background.py +317 -0
  109. package/assets/skills/design-system/scripts/generate-slide.py +770 -0
  110. package/assets/skills/design-system/scripts/generate-tokens.cjs +205 -0
  111. package/assets/skills/design-system/scripts/html-token-validator.py +327 -0
  112. package/assets/skills/design-system/scripts/search-slides.py +218 -0
  113. package/assets/skills/design-system/scripts/slide-token-validator.py +35 -0
  114. package/assets/skills/design-system/scripts/slide_search_core.py +453 -0
  115. package/assets/skills/design-system/scripts/validate-tokens.cjs +251 -0
  116. package/assets/skills/design-system/templates/design-tokens-starter.json +143 -0
  117. package/assets/skills/slides/SKILL.md +40 -0
  118. package/assets/skills/slides/references/copywriting-formulas.md +84 -0
  119. package/assets/skills/slides/references/create.md +4 -0
  120. package/assets/skills/slides/references/html-template.md +295 -0
  121. package/assets/skills/slides/references/layout-patterns.md +137 -0
  122. package/assets/skills/slides/references/slide-strategies.md +94 -0
  123. package/assets/skills/ui-styling/LICENSE.txt +202 -0
  124. package/assets/skills/ui-styling/SKILL.md +324 -0
  125. package/assets/skills/ui-styling/references/canvas-design-system.md +320 -0
  126. package/assets/skills/ui-styling/references/shadcn-accessibility.md +471 -0
  127. package/assets/skills/ui-styling/references/shadcn-components.md +424 -0
  128. package/assets/skills/ui-styling/references/shadcn-theming.md +373 -0
  129. package/assets/skills/ui-styling/references/tailwind-customization.md +483 -0
  130. package/assets/skills/ui-styling/references/tailwind-responsive.md +382 -0
  131. package/assets/skills/ui-styling/references/tailwind-utilities.md +455 -0
  132. package/assets/skills/ui-styling/scripts/requirements.txt +17 -0
  133. package/assets/skills/ui-styling/scripts/shadcn_add.py +308 -0
  134. package/assets/skills/ui-styling/scripts/tailwind_config_gen.py +473 -0
  135. package/assets/skills/ui-styling/scripts/tests/coverage-ui.json +1 -0
  136. package/assets/skills/ui-styling/scripts/tests/requirements.txt +3 -0
  137. package/assets/skills/ui-styling/scripts/tests/test_shadcn_add.py +266 -0
  138. package/assets/skills/ui-styling/scripts/tests/test_tailwind_config_gen.py +336 -0
  139. package/assets/templates/base/quick-reference.md +297 -0
  140. package/assets/templates/base/skill-content.md +368 -0
  141. package/assets/templates/platforms/agent.json +21 -0
  142. package/assets/templates/platforms/augment.json +18 -0
  143. package/assets/templates/platforms/claude.json +21 -0
  144. package/assets/templates/platforms/codebuddy.json +21 -0
  145. package/assets/templates/platforms/codex.json +21 -0
  146. package/assets/templates/platforms/continue.json +21 -0
  147. package/assets/templates/platforms/copilot.json +21 -0
  148. package/assets/templates/platforms/cursor.json +21 -0
  149. package/assets/templates/platforms/droid.json +21 -0
  150. package/assets/templates/platforms/gemini.json +21 -0
  151. package/assets/templates/platforms/kilocode.json +21 -0
  152. package/assets/templates/platforms/kiro.json +21 -0
  153. package/assets/templates/platforms/opencode.json +21 -0
  154. package/assets/templates/platforms/qoder.json +21 -0
  155. package/assets/templates/platforms/roocode.json +21 -0
  156. package/assets/templates/platforms/trae.json +21 -0
  157. package/assets/templates/platforms/warp.json +18 -0
  158. package/assets/templates/platforms/windsurf.json +21 -0
  159. package/dist/index.js +10630 -0
  160. package/package.json +51 -0
@@ -0,0 +1,770 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Slide Generator - Generates HTML slides using design tokens
5
+ ALL styles MUST use CSS variables from design-tokens.css
6
+ NO hardcoded colors, fonts, or spacing allowed
7
+ """
8
+
9
+ import argparse
10
+ import json
11
+ from html import escape
12
+ from pathlib import Path
13
+ from datetime import datetime
14
+
15
+
16
+ def _e(value, default=''):
17
+ """HTML-escape a user-supplied value for safe embedding in HTML content."""
18
+ return escape(str(value if value is not None else default))
19
+
20
+
21
+ def _safe_url(url, default='#'):
22
+ """Validate and escape a URL for use in href attributes.
23
+
24
+ Only allows http://, https://, #, and / schemes to prevent
25
+ javascript: URI injection (CWE-79).
26
+ """
27
+ if url and str(url).strip().lower().startswith(('http://', 'https://', '#', '/')):
28
+ return escape(str(url), quote=True)
29
+ return default
30
+
31
+ # Paths
32
+ SCRIPT_DIR = Path(__file__).parent
33
+ DATA_DIR = SCRIPT_DIR.parent / "data"
34
+ TOKENS_CSS = Path(__file__).resolve().parents[4] / "assets" / "design-tokens.css"
35
+ TOKENS_JSON = Path(__file__).resolve().parents[4] / "assets" / "design-tokens.json"
36
+ OUTPUT_DIR = Path(__file__).resolve().parents[4] / "assets" / "designs" / "slides"
37
+
38
+ # ============ BRAND-COMPLIANT SLIDE TEMPLATE ============
39
+ # ALL values reference CSS variables from design-tokens.css
40
+
41
+ SLIDE_TEMPLATE = '''<!DOCTYPE html>
42
+ <html lang="en" data-theme="dark">
43
+ <head>
44
+ <meta charset="UTF-8">
45
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
46
+ <title>{title}</title>
47
+
48
+ <!-- Brand Fonts -->
49
+ <link rel="preconnect" href="https://fonts.googleapis.com">
50
+ <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet">
51
+
52
+ <!-- Design Tokens - SINGLE SOURCE OF TRUTH -->
53
+ <link rel="stylesheet" href="{tokens_css_path}">
54
+
55
+ <style>
56
+ /* ============================================
57
+ STRICT TOKEN USAGE - NO HARDCODED VALUES
58
+ All styles MUST use var(--token-name)
59
+ ============================================ */
60
+
61
+ * {{
62
+ margin: 0;
63
+ padding: 0;
64
+ box-sizing: border-box;
65
+ }}
66
+
67
+ html, body {{
68
+ width: 100%;
69
+ height: 100%;
70
+ }}
71
+
72
+ body {{
73
+ font-family: var(--typography-font-body);
74
+ background: var(--color-background);
75
+ color: var(--color-foreground);
76
+ line-height: var(--primitive-lineHeight-relaxed);
77
+ }}
78
+
79
+ /* Slide Container - 16:9 aspect ratio */
80
+ .slide-deck {{
81
+ width: 100%;
82
+ max-width: 1920px;
83
+ margin: 0 auto;
84
+ }}
85
+
86
+ .slide {{
87
+ width: 100%;
88
+ aspect-ratio: 16 / 9;
89
+ padding: var(--slide-padding);
90
+ background: var(--slide-bg);
91
+ display: flex;
92
+ flex-direction: column;
93
+ position: relative;
94
+ overflow: hidden;
95
+ }}
96
+
97
+ .slide + .slide {{
98
+ margin-top: var(--primitive-spacing-8);
99
+ }}
100
+
101
+ /* Background Variants */
102
+ .slide--surface {{
103
+ background: var(--slide-bg-surface);
104
+ }}
105
+
106
+ .slide--gradient {{
107
+ background: var(--slide-bg-gradient);
108
+ }}
109
+
110
+ .slide--glow::before {{
111
+ content: '';
112
+ position: absolute;
113
+ top: 50%;
114
+ left: 50%;
115
+ transform: translate(-50%, -50%);
116
+ width: 150%;
117
+ height: 150%;
118
+ background: var(--primitive-gradient-glow);
119
+ pointer-events: none;
120
+ }}
121
+
122
+ /* Typography - MUST use token fonts and sizes */
123
+ h1, h2, h3, h4, h5, h6 {{
124
+ font-family: var(--typography-font-heading);
125
+ font-weight: var(--primitive-fontWeight-bold);
126
+ line-height: var(--primitive-lineHeight-tight);
127
+ }}
128
+
129
+ .slide-title {{
130
+ font-size: var(--slide-title-size);
131
+ background: var(--primitive-gradient-primary);
132
+ -webkit-background-clip: text;
133
+ -webkit-text-fill-color: transparent;
134
+ background-clip: text;
135
+ }}
136
+
137
+ .slide-heading {{
138
+ font-size: var(--slide-heading-size);
139
+ color: var(--color-foreground);
140
+ }}
141
+
142
+ .slide-subheading {{
143
+ font-size: var(--primitive-fontSize-3xl);
144
+ color: var(--color-foreground-secondary);
145
+ font-weight: var(--primitive-fontWeight-medium);
146
+ }}
147
+
148
+ .slide-body {{
149
+ font-size: var(--slide-body-size);
150
+ color: var(--color-foreground-secondary);
151
+ max-width: 80ch;
152
+ }}
153
+
154
+ /* Brand Colors - Primary/Secondary/Accent */
155
+ .text-primary {{ color: var(--color-primary); }}
156
+ .text-secondary {{ color: var(--color-secondary); }}
157
+ .text-accent {{ color: var(--color-accent); }}
158
+ .text-muted {{ color: var(--color-foreground-muted); }}
159
+
160
+ .bg-primary {{ background: var(--color-primary); }}
161
+ .bg-secondary {{ background: var(--color-secondary); }}
162
+ .bg-accent {{ background: var(--color-accent); }}
163
+ .bg-surface {{ background: var(--color-surface); }}
164
+
165
+ /* Cards - Using component tokens */
166
+ .card {{
167
+ background: var(--card-bg);
168
+ border: 1px solid var(--card-border);
169
+ border-radius: var(--card-radius);
170
+ padding: var(--card-padding);
171
+ box-shadow: var(--card-shadow);
172
+ transition: border-color var(--primitive-duration-base) var(--primitive-easing-out);
173
+ }}
174
+
175
+ .card:hover {{
176
+ border-color: var(--card-border-hover);
177
+ }}
178
+
179
+ /* Buttons - Using component tokens */
180
+ .btn {{
181
+ display: inline-flex;
182
+ align-items: center;
183
+ justify-content: center;
184
+ padding: var(--button-primary-padding-y) var(--button-primary-padding-x);
185
+ border-radius: var(--button-primary-radius);
186
+ font-size: var(--button-primary-font-size);
187
+ font-weight: var(--button-primary-font-weight);
188
+ font-family: var(--typography-font-body);
189
+ text-decoration: none;
190
+ cursor: pointer;
191
+ border: none;
192
+ transition: all var(--primitive-duration-base) var(--primitive-easing-out);
193
+ }}
194
+
195
+ .btn-primary {{
196
+ background: var(--button-primary-bg);
197
+ color: var(--button-primary-fg);
198
+ box-shadow: var(--button-primary-shadow);
199
+ }}
200
+
201
+ .btn-primary:hover {{
202
+ background: var(--button-primary-bg-hover);
203
+ }}
204
+
205
+ .btn-secondary {{
206
+ background: transparent;
207
+ color: var(--color-primary);
208
+ border: 2px solid var(--color-primary);
209
+ }}
210
+
211
+ /* Layout Utilities */
212
+ .flex {{ display: flex; }}
213
+ .flex-col {{ flex-direction: column; }}
214
+ .items-center {{ align-items: center; }}
215
+ .justify-center {{ justify-content: center; }}
216
+ .justify-between {{ justify-content: space-between; }}
217
+ .gap-4 {{ gap: var(--primitive-spacing-4); }}
218
+ .gap-6 {{ gap: var(--primitive-spacing-6); }}
219
+ .gap-8 {{ gap: var(--primitive-spacing-8); }}
220
+
221
+ .grid {{ display: grid; }}
222
+ .grid-2 {{ grid-template-columns: repeat(2, 1fr); }}
223
+ .grid-3 {{ grid-template-columns: repeat(3, 1fr); }}
224
+ .grid-4 {{ grid-template-columns: repeat(4, 1fr); }}
225
+
226
+ .text-center {{ text-align: center; }}
227
+ .mt-auto {{ margin-top: auto; }}
228
+ .mb-4 {{ margin-bottom: var(--primitive-spacing-4); }}
229
+ .mb-6 {{ margin-bottom: var(--primitive-spacing-6); }}
230
+ .mb-8 {{ margin-bottom: var(--primitive-spacing-8); }}
231
+
232
+ /* Metric Cards */
233
+ .metric {{
234
+ text-align: center;
235
+ padding: var(--primitive-spacing-6);
236
+ }}
237
+
238
+ .metric-value {{
239
+ font-family: var(--typography-font-heading);
240
+ font-size: var(--primitive-fontSize-6xl);
241
+ font-weight: var(--primitive-fontWeight-bold);
242
+ background: var(--primitive-gradient-primary);
243
+ -webkit-background-clip: text;
244
+ -webkit-text-fill-color: transparent;
245
+ background-clip: text;
246
+ }}
247
+
248
+ .metric-label {{
249
+ font-size: var(--primitive-fontSize-lg);
250
+ color: var(--color-foreground-secondary);
251
+ margin-top: var(--primitive-spacing-2);
252
+ }}
253
+
254
+ /* Feature List */
255
+ .feature-item {{
256
+ display: flex;
257
+ align-items: flex-start;
258
+ gap: var(--primitive-spacing-4);
259
+ padding: var(--primitive-spacing-4) 0;
260
+ }}
261
+
262
+ .feature-icon {{
263
+ width: 48px;
264
+ height: 48px;
265
+ border-radius: var(--primitive-radius-lg);
266
+ background: var(--color-surface-elevated);
267
+ display: flex;
268
+ align-items: center;
269
+ justify-content: center;
270
+ color: var(--color-primary);
271
+ font-size: var(--primitive-fontSize-xl);
272
+ flex-shrink: 0;
273
+ }}
274
+
275
+ .feature-content h4 {{
276
+ font-size: var(--primitive-fontSize-xl);
277
+ color: var(--color-foreground);
278
+ margin-bottom: var(--primitive-spacing-2);
279
+ }}
280
+
281
+ .feature-content p {{
282
+ color: var(--color-foreground-secondary);
283
+ font-size: var(--primitive-fontSize-base);
284
+ }}
285
+
286
+ /* Testimonial */
287
+ .testimonial {{
288
+ background: var(--color-surface);
289
+ border-radius: var(--primitive-radius-xl);
290
+ padding: var(--primitive-spacing-8);
291
+ border-left: 4px solid var(--color-primary);
292
+ }}
293
+
294
+ .testimonial-quote {{
295
+ font-size: var(--primitive-fontSize-2xl);
296
+ color: var(--color-foreground);
297
+ font-style: italic;
298
+ margin-bottom: var(--primitive-spacing-6);
299
+ }}
300
+
301
+ .testimonial-author {{
302
+ font-size: var(--primitive-fontSize-lg);
303
+ color: var(--color-primary);
304
+ font-weight: var(--primitive-fontWeight-semibold);
305
+ }}
306
+
307
+ .testimonial-role {{
308
+ font-size: var(--primitive-fontSize-base);
309
+ color: var(--color-foreground-muted);
310
+ }}
311
+
312
+ /* Badge/Tag */
313
+ .badge {{
314
+ display: inline-block;
315
+ padding: var(--primitive-spacing-2) var(--primitive-spacing-4);
316
+ background: var(--color-surface-elevated);
317
+ border-radius: var(--primitive-radius-full);
318
+ font-size: var(--primitive-fontSize-sm);
319
+ color: var(--color-accent);
320
+ font-weight: var(--primitive-fontWeight-medium);
321
+ }}
322
+
323
+ /* Chart Container */
324
+ .chart-container {{
325
+ background: var(--color-surface);
326
+ border-radius: var(--primitive-radius-xl);
327
+ padding: var(--primitive-spacing-6);
328
+ height: 100%;
329
+ display: flex;
330
+ flex-direction: column;
331
+ }}
332
+
333
+ .chart-title {{
334
+ font-family: var(--typography-font-heading);
335
+ font-size: var(--primitive-fontSize-xl);
336
+ color: var(--color-foreground);
337
+ margin-bottom: var(--primitive-spacing-4);
338
+ }}
339
+
340
+ /* CSS-only Bar Chart */
341
+ .bar-chart {{
342
+ display: flex;
343
+ align-items: flex-end;
344
+ gap: var(--primitive-spacing-4);
345
+ height: 200px;
346
+ padding-top: var(--primitive-spacing-4);
347
+ }}
348
+
349
+ .bar {{
350
+ flex: 1;
351
+ background: var(--primitive-gradient-primary);
352
+ border-radius: var(--primitive-radius-md) var(--primitive-radius-md) 0 0;
353
+ position: relative;
354
+ min-width: 40px;
355
+ }}
356
+
357
+ .bar-label {{
358
+ position: absolute;
359
+ bottom: -30px;
360
+ left: 50%;
361
+ transform: translateX(-50%);
362
+ font-size: var(--primitive-fontSize-sm);
363
+ color: var(--color-foreground-muted);
364
+ white-space: nowrap;
365
+ }}
366
+
367
+ .bar-value {{
368
+ position: absolute;
369
+ top: -25px;
370
+ left: 50%;
371
+ transform: translateX(-50%);
372
+ font-size: var(--primitive-fontSize-sm);
373
+ color: var(--color-foreground);
374
+ font-weight: var(--primitive-fontWeight-semibold);
375
+ }}
376
+
377
+ /* Progress Bar */
378
+ .progress {{
379
+ height: 12px;
380
+ background: var(--color-surface-elevated);
381
+ border-radius: var(--primitive-radius-full);
382
+ overflow: hidden;
383
+ }}
384
+
385
+ .progress-fill {{
386
+ height: 100%;
387
+ background: var(--primitive-gradient-primary);
388
+ border-radius: var(--primitive-radius-full);
389
+ }}
390
+
391
+ /* Footer */
392
+ .slide-footer {{
393
+ margin-top: auto;
394
+ display: flex;
395
+ justify-content: space-between;
396
+ align-items: center;
397
+ padding-top: var(--primitive-spacing-6);
398
+ border-top: 1px solid var(--color-border);
399
+ color: var(--color-foreground-muted);
400
+ font-size: var(--primitive-fontSize-sm);
401
+ }}
402
+
403
+ /* Glow Effects */
404
+ .glow-coral {{
405
+ box-shadow: var(--primitive-shadow-glow-coral);
406
+ }}
407
+
408
+ .glow-purple {{
409
+ box-shadow: var(--primitive-shadow-glow-purple);
410
+ }}
411
+
412
+ .glow-mint {{
413
+ box-shadow: var(--primitive-shadow-glow-mint);
414
+ }}
415
+ </style>
416
+ </head>
417
+ <body>
418
+ <div class="slide-deck">
419
+ {slides_content}
420
+ </div>
421
+ </body>
422
+ </html>
423
+ '''
424
+
425
+
426
+ # ============ SLIDE GENERATORS ============
427
+
428
+ def generate_title_slide(data):
429
+ """Title slide with gradient headline"""
430
+ return f'''
431
+ <section class="slide slide--glow flex flex-col items-center justify-center text-center">
432
+ <div class="badge mb-6">{_e(data.get('badge', 'Pitch Deck'))}</div>
433
+ <h1 class="slide-title mb-6">{_e(data.get('title', 'Your Title Here'))}</h1>
434
+ <p class="slide-subheading mb-8">{_e(data.get('subtitle', 'Your compelling subtitle'))}</p>
435
+ <div class="flex gap-4">
436
+ <a href="#" class="btn btn-primary">{_e(data.get('cta', 'Get Started'))}</a>
437
+ <a href="#" class="btn btn-secondary">{_e(data.get('secondary_cta', 'Learn More'))}</a>
438
+ </div>
439
+ <div class="slide-footer">
440
+ <span>{_e(data.get('company', 'Company Name'))}</span>
441
+ <span>{_e(data.get('date', datetime.now().strftime('%B %Y')))}</span>
442
+ </div>
443
+ </section>
444
+ '''
445
+
446
+
447
+ def generate_problem_slide(data):
448
+ """Problem statement slide using PAS formula"""
449
+ return f'''
450
+ <section class="slide slide--surface">
451
+ <div class="badge mb-6">The Problem</div>
452
+ <h2 class="slide-heading mb-8">{_e(data.get('headline', 'The problem your audience faces'))}</h2>
453
+ <div class="grid grid-3 gap-8">
454
+ <div class="card">
455
+ <div class="text-primary" style="font-size: var(--primitive-fontSize-4xl); margin-bottom: var(--primitive-spacing-4);">01</div>
456
+ <h4 style="margin-bottom: var(--primitive-spacing-2); font-size: var(--primitive-fontSize-xl);">{_e(data.get('pain_1_title', 'Pain Point 1'))}</h4>
457
+ <p class="text-muted">{_e(data.get('pain_1_desc', 'Description of the first pain point'))}</p>
458
+ </div>
459
+ <div class="card">
460
+ <div class="text-secondary" style="font-size: var(--primitive-fontSize-4xl); margin-bottom: var(--primitive-spacing-4);">02</div>
461
+ <h4 style="margin-bottom: var(--primitive-spacing-2); font-size: var(--primitive-fontSize-xl);">{_e(data.get('pain_2_title', 'Pain Point 2'))}</h4>
462
+ <p class="text-muted">{_e(data.get('pain_2_desc', 'Description of the second pain point'))}</p>
463
+ </div>
464
+ <div class="card">
465
+ <div class="text-accent" style="font-size: var(--primitive-fontSize-4xl); margin-bottom: var(--primitive-spacing-4);">03</div>
466
+ <h4 style="margin-bottom: var(--primitive-spacing-2); font-size: var(--primitive-fontSize-xl);">{_e(data.get('pain_3_title', 'Pain Point 3'))}</h4>
467
+ <p class="text-muted">{_e(data.get('pain_3_desc', 'Description of the third pain point'))}</p>
468
+ </div>
469
+ </div>
470
+ <div class="slide-footer">
471
+ <span>{_e(data.get('company', 'Company Name'))}</span>
472
+ <span>{_e(data.get('page', '2'))}</span>
473
+ </div>
474
+ </section>
475
+ '''
476
+
477
+
478
+ def generate_solution_slide(data):
479
+ """Solution slide with feature highlights"""
480
+ return f'''
481
+ <section class="slide">
482
+ <div class="badge mb-6">The Solution</div>
483
+ <h2 class="slide-heading mb-8">{_e(data.get('headline', 'How we solve this'))}</h2>
484
+ <div class="flex gap-8" style="flex: 1;">
485
+ <div style="flex: 1;">
486
+ <div class="feature-item">
487
+ <div class="feature-icon">&#10003;</div>
488
+ <div class="feature-content">
489
+ <h4>{_e(data.get('feature_1_title', 'Feature 1'))}</h4>
490
+ <p>{_e(data.get('feature_1_desc', 'Description of feature 1'))}</p>
491
+ </div>
492
+ </div>
493
+ <div class="feature-item">
494
+ <div class="feature-icon">&#10003;</div>
495
+ <div class="feature-content">
496
+ <h4>{_e(data.get('feature_2_title', 'Feature 2'))}</h4>
497
+ <p>{_e(data.get('feature_2_desc', 'Description of feature 2'))}</p>
498
+ </div>
499
+ </div>
500
+ <div class="feature-item">
501
+ <div class="feature-icon">&#10003;</div>
502
+ <div class="feature-content">
503
+ <h4>{_e(data.get('feature_3_title', 'Feature 3'))}</h4>
504
+ <p>{_e(data.get('feature_3_desc', 'Description of feature 3'))}</p>
505
+ </div>
506
+ </div>
507
+ </div>
508
+ <div style="flex: 1;" class="card flex items-center justify-center">
509
+ <div class="text-center">
510
+ <div class="text-accent" style="font-size: 80px; margin-bottom: var(--primitive-spacing-4);">&#9670;</div>
511
+ <p class="text-muted">Product screenshot or demo</p>
512
+ </div>
513
+ </div>
514
+ </div>
515
+ <div class="slide-footer">
516
+ <span>{_e(data.get('company', 'Company Name'))}</span>
517
+ <span>{_e(data.get('page', '3'))}</span>
518
+ </div>
519
+ </section>
520
+ '''
521
+
522
+
523
+ def generate_metrics_slide(data):
524
+ """Traction/metrics slide with large numbers"""
525
+ metrics = data.get('metrics', [
526
+ {'value': '10K+', 'label': 'Active Users'},
527
+ {'value': '95%', 'label': 'Retention Rate'},
528
+ {'value': '3x', 'label': 'Revenue Growth'},
529
+ {'value': '$2M', 'label': 'ARR'}
530
+ ])
531
+
532
+ metrics_html = ''.join([f'''
533
+ <div class="card metric">
534
+ <div class="metric-value">{_e(m.get('value', ''))}</div>
535
+ <div class="metric-label">{_e(m.get('label', ''))}</div>
536
+ </div>
537
+ ''' for m in metrics[:4]])
538
+
539
+ return f'''
540
+ <section class="slide slide--surface slide--glow">
541
+ <div class="badge mb-6">Traction</div>
542
+ <h2 class="slide-heading mb-8 text-center">{_e(data.get('headline', 'Our Growth'))}</h2>
543
+ <div class="grid grid-4 gap-6" style="flex: 1; align-items: center;">
544
+ {metrics_html}
545
+ </div>
546
+ <div class="slide-footer">
547
+ <span>{_e(data.get('company', 'Company Name'))}</span>
548
+ <span>{_e(data.get('page', '4'))}</span>
549
+ </div>
550
+ </section>
551
+ '''
552
+
553
+
554
+ def generate_chart_slide(data):
555
+ """Chart slide with CSS bar chart"""
556
+ bars = data.get('bars', [
557
+ {'label': 'Q1', 'value': 40},
558
+ {'label': 'Q2', 'value': 60},
559
+ {'label': 'Q3', 'value': 80},
560
+ {'label': 'Q4', 'value': 100}
561
+ ])
562
+
563
+ bars_html = ''.join([f'''
564
+ <div class="bar" style="height: {int(b.get('value', 0))}%;">
565
+ <span class="bar-value">{_e(b.get('display', str(b.get('value', 0)) + '%'))}</span>
566
+ <span class="bar-label">{_e(b.get('label', ''))}</span>
567
+ </div>
568
+ ''' for b in bars])
569
+
570
+ return f'''
571
+ <section class="slide">
572
+ <div class="badge mb-6">{_e(data.get('badge', 'Growth'))}</div>
573
+ <h2 class="slide-heading mb-8">{_e(data.get('headline', 'Revenue Growth'))}</h2>
574
+ <div class="chart-container" style="flex: 1;">
575
+ <div class="chart-title">{_e(data.get('chart_title', 'Quarterly Revenue'))}</div>
576
+ <div class="bar-chart" style="flex: 1; padding-bottom: 40px;">
577
+ {bars_html}
578
+ </div>
579
+ </div>
580
+ <div class="slide-footer">
581
+ <span>{_e(data.get('company', 'Company Name'))}</span>
582
+ <span>{_e(data.get('page', '5'))}</span>
583
+ </div>
584
+ </section>
585
+ '''
586
+
587
+
588
+ def generate_testimonial_slide(data):
589
+ """Social proof slide"""
590
+ return f'''
591
+ <section class="slide slide--surface flex flex-col justify-center">
592
+ <div class="badge mb-6">What They Say</div>
593
+ <div class="testimonial" style="max-width: 900px;">
594
+ <p class="testimonial-quote">"{_e(data.get('quote', 'This product changed how we work. Incredible results.'))}"</p>
595
+ <p class="testimonial-author">{_e(data.get('author', 'Jane Doe'))}</p>
596
+ <p class="testimonial-role">{_e(data.get('role', 'CEO, Example Company'))}</p>
597
+ </div>
598
+ <div class="slide-footer">
599
+ <span>{_e(data.get('company', 'Company Name'))}</span>
600
+ <span>{_e(data.get('page', '6'))}</span>
601
+ </div>
602
+ </section>
603
+ '''
604
+
605
+
606
+ def generate_cta_slide(data):
607
+ """Closing CTA slide"""
608
+ return f'''
609
+ <section class="slide slide--gradient flex flex-col items-center justify-center text-center">
610
+ <h2 class="slide-heading mb-6" style="color: var(--color-foreground);">{_e(data.get('headline', 'Ready to get started?'))}</h2>
611
+ <p class="slide-body mb-8" style="color: rgba(255,255,255,0.8);">{_e(data.get('subheadline', 'Join thousands of teams already using our solution.'))}</p>
612
+ <div class="flex gap-4">
613
+ <a href="{_safe_url(data.get('cta_url', '#'))}" class="btn" style="background: var(--color-foreground); color: var(--color-primary);">{_e(data.get('cta', 'Start Free Trial'))}</a>
614
+ </div>
615
+ <div class="slide-footer" style="border-color: rgba(255,255,255,0.2); color: rgba(255,255,255,0.6);">
616
+ <span>{_e(data.get('contact', 'contact@example.com'))}</span>
617
+ <span>{_e(data.get('website', 'www.example.com'))}</span>
618
+ </div>
619
+ </section>
620
+ '''
621
+
622
+
623
+ # Slide type mapping
624
+ SLIDE_GENERATORS = {
625
+ 'title': generate_title_slide,
626
+ 'problem': generate_problem_slide,
627
+ 'solution': generate_solution_slide,
628
+ 'metrics': generate_metrics_slide,
629
+ 'traction': generate_metrics_slide,
630
+ 'chart': generate_chart_slide,
631
+ 'testimonial': generate_testimonial_slide,
632
+ 'cta': generate_cta_slide,
633
+ 'closing': generate_cta_slide
634
+ }
635
+
636
+
637
+ def generate_deck(slides_data, title="Pitch Deck"):
638
+ """Generate complete deck from slide data list"""
639
+ slides_html = ""
640
+ for slide in slides_data:
641
+ slide_type = slide.get('type', 'title')
642
+ generator = SLIDE_GENERATORS.get(slide_type)
643
+ if generator:
644
+ slides_html += generator(slide)
645
+ else:
646
+ print(f"Warning: Unknown slide type '{slide_type}'")
647
+
648
+ # Calculate relative path to tokens CSS
649
+ tokens_rel_path = "../../../assets/design-tokens.css"
650
+
651
+ return SLIDE_TEMPLATE.format(
652
+ title=escape(str(title)),
653
+ tokens_css_path=tokens_rel_path,
654
+ slides_content=slides_html
655
+ )
656
+
657
+
658
+ def main():
659
+ parser = argparse.ArgumentParser(description="Generate brand-compliant slides")
660
+ parser.add_argument("--json", "-j", help="JSON file with slide data")
661
+ parser.add_argument("--output", "-o", help="Output HTML file path")
662
+ parser.add_argument("--demo", action="store_true", help="Generate demo deck")
663
+
664
+ args = parser.parse_args()
665
+
666
+ if args.demo:
667
+ # Demo deck showcasing all slide types
668
+ demo_slides = [
669
+ {
670
+ 'type': 'title',
671
+ 'badge': 'Investor Deck 2024',
672
+ 'title': 'ClaudeKit Marketing',
673
+ 'subtitle': 'Your AI marketing team. Always on.',
674
+ 'cta': 'Join Waitlist',
675
+ 'secondary_cta': 'See Demo',
676
+ 'company': 'ClaudeKit',
677
+ 'date': 'December 2024'
678
+ },
679
+ {
680
+ 'type': 'problem',
681
+ 'headline': 'Marketing teams are drowning',
682
+ 'pain_1_title': 'Content Overload',
683
+ 'pain_1_desc': 'Need to produce 10x content with same headcount',
684
+ 'pain_2_title': 'Tool Fatigue',
685
+ 'pain_2_desc': '15+ tools that don\'t talk to each other',
686
+ 'pain_3_title': 'No Time to Think',
687
+ 'pain_3_desc': 'Strategy suffers when execution consumes all hours',
688
+ 'company': 'ClaudeKit',
689
+ 'page': '2'
690
+ },
691
+ {
692
+ 'type': 'solution',
693
+ 'headline': 'AI agents that actually get marketing',
694
+ 'feature_1_title': 'Content Creation',
695
+ 'feature_1_desc': 'Blog posts, social, email - all on brand, all on time',
696
+ 'feature_2_title': 'Campaign Management',
697
+ 'feature_2_desc': 'Multi-channel orchestration with one command',
698
+ 'feature_3_title': 'Analytics & Insights',
699
+ 'feature_3_desc': 'Real-time optimization without the spreadsheets',
700
+ 'company': 'ClaudeKit',
701
+ 'page': '3'
702
+ },
703
+ {
704
+ 'type': 'metrics',
705
+ 'headline': 'Early traction speaks volumes',
706
+ 'metrics': [
707
+ {'value': '500+', 'label': 'Beta Users'},
708
+ {'value': '85%', 'label': 'Weekly Active'},
709
+ {'value': '4.9', 'label': 'NPS Score'},
710
+ {'value': '50hrs', 'label': 'Saved/Week'}
711
+ ],
712
+ 'company': 'ClaudeKit',
713
+ 'page': '4'
714
+ },
715
+ {
716
+ 'type': 'chart',
717
+ 'badge': 'Revenue',
718
+ 'headline': 'Growing month over month',
719
+ 'chart_title': 'MRR Growth ($K)',
720
+ 'bars': [
721
+ {'label': 'Sep', 'value': 20, 'display': '$5K'},
722
+ {'label': 'Oct', 'value': 40, 'display': '$12K'},
723
+ {'label': 'Nov', 'value': 70, 'display': '$28K'},
724
+ {'label': 'Dec', 'value': 100, 'display': '$45K'}
725
+ ],
726
+ 'company': 'ClaudeKit',
727
+ 'page': '5'
728
+ },
729
+ {
730
+ 'type': 'testimonial',
731
+ 'quote': 'ClaudeKit replaced 3 tools and 2 contractors. Our content output tripled while costs dropped 60%.',
732
+ 'author': 'Sarah Chen',
733
+ 'role': 'Head of Marketing, TechStartup',
734
+ 'company': 'ClaudeKit',
735
+ 'page': '6'
736
+ },
737
+ {
738
+ 'type': 'cta',
739
+ 'headline': 'Ship campaigns while you sleep',
740
+ 'subheadline': 'Early access available. Limited spots.',
741
+ 'cta': 'Join the Waitlist',
742
+ 'contact': 'hello@claudekit.ai',
743
+ 'website': 'claudekit.ai'
744
+ }
745
+ ]
746
+
747
+ html = generate_deck(demo_slides, "ClaudeKit Marketing - Pitch Deck")
748
+
749
+ OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
750
+ output_path = OUTPUT_DIR / f"demo-pitch-{datetime.now().strftime('%y%m%d')}.html"
751
+ output_path.write_text(html, encoding='utf-8')
752
+ print(f"Demo deck generated: {output_path}")
753
+
754
+ elif args.json:
755
+ with open(args.json, 'r') as f:
756
+ data = json.load(f)
757
+
758
+ html = generate_deck(data.get('slides', []), data.get('title', 'Presentation'))
759
+
760
+ output_path = Path(args.output) if args.output else OUTPUT_DIR / f"deck-{datetime.now().strftime('%y%m%d-%H%M')}.html"
761
+ output_path.parent.mkdir(parents=True, exist_ok=True)
762
+ output_path.write_text(html, encoding='utf-8')
763
+ print(f"Deck generated: {output_path}")
764
+
765
+ else:
766
+ parser.print_help()
767
+
768
+
769
+ if __name__ == "__main__":
770
+ main()