@brandsystem/mcp 0.3.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 (223) hide show
  1. package/README.md +515 -0
  2. package/bin/brandsystem-mcp.mjs +2 -0
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +20 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/lib/brand-dir.d.ts +56 -0
  8. package/dist/lib/brand-dir.d.ts.map +1 -0
  9. package/dist/lib/brand-dir.js +270 -0
  10. package/dist/lib/brand-dir.js.map +1 -0
  11. package/dist/lib/color-namer.d.ts +28 -0
  12. package/dist/lib/color-namer.d.ts.map +1 -0
  13. package/dist/lib/color-namer.js +155 -0
  14. package/dist/lib/color-namer.js.map +1 -0
  15. package/dist/lib/confidence.d.ts +19 -0
  16. package/dist/lib/confidence.d.ts.map +1 -0
  17. package/dist/lib/confidence.js +66 -0
  18. package/dist/lib/confidence.js.map +1 -0
  19. package/dist/lib/content-scorer.d.ts +38 -0
  20. package/dist/lib/content-scorer.d.ts.map +1 -0
  21. package/dist/lib/content-scorer.js +571 -0
  22. package/dist/lib/content-scorer.js.map +1 -0
  23. package/dist/lib/css-parser.d.ts +45 -0
  24. package/dist/lib/css-parser.d.ts.map +1 -0
  25. package/dist/lib/css-parser.js +330 -0
  26. package/dist/lib/css-parser.js.map +1 -0
  27. package/dist/lib/dtcg-compiler.d.ts +7 -0
  28. package/dist/lib/dtcg-compiler.d.ts.map +1 -0
  29. package/dist/lib/dtcg-compiler.js +89 -0
  30. package/dist/lib/dtcg-compiler.js.map +1 -0
  31. package/dist/lib/interaction-policy-compiler.d.ts +40 -0
  32. package/dist/lib/interaction-policy-compiler.d.ts.map +1 -0
  33. package/dist/lib/interaction-policy-compiler.js +60 -0
  34. package/dist/lib/interaction-policy-compiler.js.map +1 -0
  35. package/dist/lib/logo-extractor.d.ts +49 -0
  36. package/dist/lib/logo-extractor.d.ts.map +1 -0
  37. package/dist/lib/logo-extractor.js +384 -0
  38. package/dist/lib/logo-extractor.js.map +1 -0
  39. package/dist/lib/report-html.d.ts +20 -0
  40. package/dist/lib/report-html.d.ts.map +1 -0
  41. package/dist/lib/report-html.js +938 -0
  42. package/dist/lib/report-html.js.map +1 -0
  43. package/dist/lib/response.d.ts +20 -0
  44. package/dist/lib/response.d.ts.map +1 -0
  45. package/dist/lib/response.js +54 -0
  46. package/dist/lib/response.js.map +1 -0
  47. package/dist/lib/runtime-compiler.d.ts +60 -0
  48. package/dist/lib/runtime-compiler.d.ts.map +1 -0
  49. package/dist/lib/runtime-compiler.js +96 -0
  50. package/dist/lib/runtime-compiler.js.map +1 -0
  51. package/dist/lib/svg-resolver.d.ts +21 -0
  52. package/dist/lib/svg-resolver.d.ts.map +1 -0
  53. package/dist/lib/svg-resolver.js +115 -0
  54. package/dist/lib/svg-resolver.js.map +1 -0
  55. package/dist/lib/url-validator.d.ts +11 -0
  56. package/dist/lib/url-validator.d.ts.map +1 -0
  57. package/dist/lib/url-validator.js +93 -0
  58. package/dist/lib/url-validator.js.map +1 -0
  59. package/dist/lib/version.d.ts +2 -0
  60. package/dist/lib/version.d.ts.map +1 -0
  61. package/dist/lib/version.js +19 -0
  62. package/dist/lib/version.js.map +1 -0
  63. package/dist/lib/vim-generator.d.ts +13 -0
  64. package/dist/lib/vim-generator.d.ts.map +1 -0
  65. package/dist/lib/vim-generator.js +718 -0
  66. package/dist/lib/vim-generator.js.map +1 -0
  67. package/dist/resources/brand-resources.d.ts +4 -0
  68. package/dist/resources/brand-resources.d.ts.map +1 -0
  69. package/dist/resources/brand-resources.js +34 -0
  70. package/dist/resources/brand-resources.js.map +1 -0
  71. package/dist/schemas/brand-config.d.ts +28 -0
  72. package/dist/schemas/brand-config.d.ts.map +1 -0
  73. package/dist/schemas/brand-config.js +11 -0
  74. package/dist/schemas/brand-config.js.map +1 -0
  75. package/dist/schemas/brand-runtime.d.ts +251 -0
  76. package/dist/schemas/brand-runtime.d.ts.map +1 -0
  77. package/dist/schemas/brand-runtime.js +54 -0
  78. package/dist/schemas/brand-runtime.js.map +1 -0
  79. package/dist/schemas/core-identity.d.ts +302 -0
  80. package/dist/schemas/core-identity.d.ts.map +1 -0
  81. package/dist/schemas/core-identity.js +51 -0
  82. package/dist/schemas/core-identity.js.map +1 -0
  83. package/dist/schemas/index.d.ts +11 -0
  84. package/dist/schemas/index.d.ts.map +1 -0
  85. package/dist/schemas/index.js +11 -0
  86. package/dist/schemas/index.js.map +1 -0
  87. package/dist/schemas/interaction-policy.d.ts +150 -0
  88. package/dist/schemas/interaction-policy.d.ts.map +1 -0
  89. package/dist/schemas/interaction-policy.js +34 -0
  90. package/dist/schemas/interaction-policy.js.map +1 -0
  91. package/dist/schemas/messaging.d.ts +776 -0
  92. package/dist/schemas/messaging.d.ts.map +1 -0
  93. package/dist/schemas/messaging.js +68 -0
  94. package/dist/schemas/messaging.js.map +1 -0
  95. package/dist/schemas/needs-clarification.d.ts +62 -0
  96. package/dist/schemas/needs-clarification.d.ts.map +1 -0
  97. package/dist/schemas/needs-clarification.js +13 -0
  98. package/dist/schemas/needs-clarification.js.map +1 -0
  99. package/dist/schemas/strategy.d.ts +537 -0
  100. package/dist/schemas/strategy.d.ts.map +1 -0
  101. package/dist/schemas/strategy.js +71 -0
  102. package/dist/schemas/strategy.js.map +1 -0
  103. package/dist/schemas/tokens.d.ts +35 -0
  104. package/dist/schemas/tokens.d.ts.map +1 -0
  105. package/dist/schemas/tokens.js +15 -0
  106. package/dist/schemas/tokens.js.map +1 -0
  107. package/dist/schemas/visual-identity.d.ts +224 -0
  108. package/dist/schemas/visual-identity.d.ts.map +1 -0
  109. package/dist/schemas/visual-identity.js +42 -0
  110. package/dist/schemas/visual-identity.js.map +1 -0
  111. package/dist/server.d.ts +3 -0
  112. package/dist/server.d.ts.map +1 -0
  113. package/dist/server.js +75 -0
  114. package/dist/server.js.map +1 -0
  115. package/dist/tools/brand-audit-content.d.ts +3 -0
  116. package/dist/tools/brand-audit-content.d.ts.map +1 -0
  117. package/dist/tools/brand-audit-content.js +116 -0
  118. package/dist/tools/brand-audit-content.js.map +1 -0
  119. package/dist/tools/brand-audit-drift.d.ts +3 -0
  120. package/dist/tools/brand-audit-drift.d.ts.map +1 -0
  121. package/dist/tools/brand-audit-drift.js +301 -0
  122. package/dist/tools/brand-audit-drift.js.map +1 -0
  123. package/dist/tools/brand-audit.d.ts +3 -0
  124. package/dist/tools/brand-audit.d.ts.map +1 -0
  125. package/dist/tools/brand-audit.js +129 -0
  126. package/dist/tools/brand-audit.js.map +1 -0
  127. package/dist/tools/brand-build-journey.d.ts +3 -0
  128. package/dist/tools/brand-build-journey.d.ts.map +1 -0
  129. package/dist/tools/brand-build-journey.js +312 -0
  130. package/dist/tools/brand-build-journey.js.map +1 -0
  131. package/dist/tools/brand-build-matrix.d.ts +3 -0
  132. package/dist/tools/brand-build-matrix.d.ts.map +1 -0
  133. package/dist/tools/brand-build-matrix.js +525 -0
  134. package/dist/tools/brand-build-matrix.js.map +1 -0
  135. package/dist/tools/brand-build-personas.d.ts +3 -0
  136. package/dist/tools/brand-build-personas.d.ts.map +1 -0
  137. package/dist/tools/brand-build-personas.js +436 -0
  138. package/dist/tools/brand-build-personas.js.map +1 -0
  139. package/dist/tools/brand-build-themes.d.ts +3 -0
  140. package/dist/tools/brand-build-themes.d.ts.map +1 -0
  141. package/dist/tools/brand-build-themes.js +476 -0
  142. package/dist/tools/brand-build-themes.js.map +1 -0
  143. package/dist/tools/brand-check-compliance.d.ts +3 -0
  144. package/dist/tools/brand-check-compliance.d.ts.map +1 -0
  145. package/dist/tools/brand-check-compliance.js +243 -0
  146. package/dist/tools/brand-check-compliance.js.map +1 -0
  147. package/dist/tools/brand-clarify.d.ts +21 -0
  148. package/dist/tools/brand-clarify.d.ts.map +1 -0
  149. package/dist/tools/brand-clarify.js +497 -0
  150. package/dist/tools/brand-clarify.js.map +1 -0
  151. package/dist/tools/brand-compile-messaging.d.ts +3 -0
  152. package/dist/tools/brand-compile-messaging.d.ts.map +1 -0
  153. package/dist/tools/brand-compile-messaging.js +759 -0
  154. package/dist/tools/brand-compile-messaging.js.map +1 -0
  155. package/dist/tools/brand-compile.d.ts +3 -0
  156. package/dist/tools/brand-compile.d.ts.map +1 -0
  157. package/dist/tools/brand-compile.js +182 -0
  158. package/dist/tools/brand-compile.js.map +1 -0
  159. package/dist/tools/brand-deepen-identity.d.ts +3 -0
  160. package/dist/tools/brand-deepen-identity.d.ts.map +1 -0
  161. package/dist/tools/brand-deepen-identity.js +483 -0
  162. package/dist/tools/brand-deepen-identity.js.map +1 -0
  163. package/dist/tools/brand-export.d.ts +17 -0
  164. package/dist/tools/brand-export.d.ts.map +1 -0
  165. package/dist/tools/brand-export.js +730 -0
  166. package/dist/tools/brand-export.js.map +1 -0
  167. package/dist/tools/brand-extract-figma.d.ts +3 -0
  168. package/dist/tools/brand-extract-figma.d.ts.map +1 -0
  169. package/dist/tools/brand-extract-figma.js +174 -0
  170. package/dist/tools/brand-extract-figma.js.map +1 -0
  171. package/dist/tools/brand-extract-messaging.d.ts +3 -0
  172. package/dist/tools/brand-extract-messaging.d.ts.map +1 -0
  173. package/dist/tools/brand-extract-messaging.js +620 -0
  174. package/dist/tools/brand-extract-messaging.js.map +1 -0
  175. package/dist/tools/brand-extract-web.d.ts +3 -0
  176. package/dist/tools/brand-extract-web.d.ts.map +1 -0
  177. package/dist/tools/brand-extract-web.js +477 -0
  178. package/dist/tools/brand-extract-web.js.map +1 -0
  179. package/dist/tools/brand-feedback.d.ts +3 -0
  180. package/dist/tools/brand-feedback.d.ts.map +1 -0
  181. package/dist/tools/brand-feedback.js +366 -0
  182. package/dist/tools/brand-feedback.js.map +1 -0
  183. package/dist/tools/brand-ingest-assets.d.ts +3 -0
  184. package/dist/tools/brand-ingest-assets.d.ts.map +1 -0
  185. package/dist/tools/brand-ingest-assets.js +233 -0
  186. package/dist/tools/brand-ingest-assets.js.map +1 -0
  187. package/dist/tools/brand-init.d.ts +3 -0
  188. package/dist/tools/brand-init.d.ts.map +1 -0
  189. package/dist/tools/brand-init.js +66 -0
  190. package/dist/tools/brand-init.js.map +1 -0
  191. package/dist/tools/brand-preflight.d.ts +3 -0
  192. package/dist/tools/brand-preflight.d.ts.map +1 -0
  193. package/dist/tools/brand-preflight.js +608 -0
  194. package/dist/tools/brand-preflight.js.map +1 -0
  195. package/dist/tools/brand-report.d.ts +3 -0
  196. package/dist/tools/brand-report.d.ts.map +1 -0
  197. package/dist/tools/brand-report.js +154 -0
  198. package/dist/tools/brand-report.js.map +1 -0
  199. package/dist/tools/brand-runtime.d.ts +3 -0
  200. package/dist/tools/brand-runtime.d.ts.map +1 -0
  201. package/dist/tools/brand-runtime.js +37 -0
  202. package/dist/tools/brand-runtime.js.map +1 -0
  203. package/dist/tools/brand-set-logo.d.ts +3 -0
  204. package/dist/tools/brand-set-logo.d.ts.map +1 -0
  205. package/dist/tools/brand-set-logo.js +170 -0
  206. package/dist/tools/brand-set-logo.js.map +1 -0
  207. package/dist/tools/brand-start.d.ts +3 -0
  208. package/dist/tools/brand-start.d.ts.map +1 -0
  209. package/dist/tools/brand-start.js +686 -0
  210. package/dist/tools/brand-start.js.map +1 -0
  211. package/dist/tools/brand-status.d.ts +3 -0
  212. package/dist/tools/brand-status.d.ts.map +1 -0
  213. package/dist/tools/brand-status.js +175 -0
  214. package/dist/tools/brand-status.js.map +1 -0
  215. package/dist/tools/brand-write.d.ts +3 -0
  216. package/dist/tools/brand-write.d.ts.map +1 -0
  217. package/dist/tools/brand-write.js +442 -0
  218. package/dist/tools/brand-write.js.map +1 -0
  219. package/dist/types/index.d.ts +331 -0
  220. package/dist/types/index.d.ts.map +1 -0
  221. package/dist/types/index.js +52 -0
  222. package/dist/types/index.js.map +1 -0
  223. package/package.json +60 -0
@@ -0,0 +1,718 @@
1
+ import { cleanColorName as cleanColorNameShared } from "./color-namer.js";
2
+ /**
3
+ * Generate a Visual Identity Manifest (VIM) markdown document
4
+ * from compiled brand data (Session 1 core identity + Session 2 visual identity).
5
+ */
6
+ export function generateVIM(config, identity, visual) {
7
+ const lines = [];
8
+ lines.push(`# ${config.client_name} Visual Identity Manifest v1.0`);
9
+ lines.push("");
10
+ lines.push(`> Generated by brandsystem.app — ${new Date().toISOString().split("T")[0]}`);
11
+ lines.push("");
12
+ // --- 1. Color System ---
13
+ lines.push("## 1. Color System");
14
+ lines.push("");
15
+ lines.push(renderColorPrimitives(identity));
16
+ lines.push(renderSemanticMapping(identity));
17
+ lines.push(renderThemeModes(identity));
18
+ // --- 2. Typography ---
19
+ lines.push("## 2. Typography");
20
+ lines.push("");
21
+ lines.push(renderTypeStack(identity));
22
+ lines.push(renderTypeUsage(identity));
23
+ // --- 3. Composition ---
24
+ lines.push("## 3. Composition");
25
+ lines.push("");
26
+ lines.push(renderSpatialPhilosophy(visual));
27
+ lines.push(renderNegativeSpace(visual));
28
+ lines.push(renderGridLayout(visual));
29
+ // --- 4. Visual Language ---
30
+ lines.push("## 4. Visual Language");
31
+ lines.push("");
32
+ lines.push(renderPatternSystem(visual));
33
+ lines.push(renderIllustrationLanguage(visual));
34
+ lines.push(renderPhotographyDirection(visual));
35
+ lines.push(renderSignatureMoves(visual));
36
+ // --- 5. Logo Usage ---
37
+ lines.push("## 5. Logo Usage");
38
+ lines.push("");
39
+ lines.push(renderLockupRules(identity));
40
+ lines.push(renderAssetReference(identity));
41
+ // --- 6. Compliance Rules ---
42
+ lines.push("## 6. Compliance Rules");
43
+ lines.push("");
44
+ lines.push(renderAntiPatternsHard(visual));
45
+ lines.push(renderAntiPatternsSoft(visual));
46
+ lines.push(renderAutomatedChecks());
47
+ return lines.join("\n");
48
+ }
49
+ /**
50
+ * Generate a System Integration Guide with real values from the brand data.
51
+ * The output is fully self-contained — it works when uploaded to any AI chat
52
+ * without the .brand/ directory present.
53
+ */
54
+ export function generateSystemIntegration(config, identity, visual, messaging) {
55
+ const lines = [];
56
+ lines.push("# System Integration Guide");
57
+ lines.push("");
58
+ lines.push(`> **This document is self-contained.** Upload it to any AI conversation and all brand rules will be applied. No additional files needed.`);
59
+ lines.push("");
60
+ lines.push(`> ${config.client_name} — generated by brandsystem.app`);
61
+ lines.push("");
62
+ // --- Quick Setup ---
63
+ lines.push("## Quick Setup (CLAUDE.md / .cursorrules)");
64
+ lines.push("");
65
+ lines.push("Paste the following block into your AI assistant configuration:");
66
+ lines.push("");
67
+ lines.push("```");
68
+ lines.push(renderQuickSetupBlock(config, identity, visual, messaging));
69
+ lines.push("```");
70
+ lines.push("");
71
+ // --- Session Start Protocol ---
72
+ lines.push("## Session Start Protocol");
73
+ lines.push("");
74
+ lines.push("1. Apply ALL rules in this document to any visual or written output.");
75
+ lines.push("2. For visual content: use the exact colors, fonts, and logo above. Check anti-patterns before delivering.");
76
+ lines.push("3. For written content: use the voice rules, anchor vocabulary, and never-say list below.");
77
+ lines.push("4. If you have access to the brandsystem MCP (brand_status tool), run it for the latest data.");
78
+ lines.push("");
79
+ // --- Common Pain Points ---
80
+ lines.push("## Common Pain Points");
81
+ lines.push("");
82
+ lines.push(renderPainPoints(identity, visual));
83
+ // --- Voice & Messaging (inline if provided) ---
84
+ if (messaging) {
85
+ lines.push(renderVoiceMessagingSection(messaging));
86
+ }
87
+ return lines.join("\n");
88
+ }
89
+ // ---------------------------------------------------------------------------
90
+ // Section renderers — Color
91
+ // ---------------------------------------------------------------------------
92
+ function renderColorPrimitives(identity) {
93
+ const lines = [];
94
+ lines.push("### 1a. Primitives");
95
+ lines.push("");
96
+ if (identity.colors.length === 0) {
97
+ lines.push(stub("colors", "brand_extract_web or brand_extract_figma"));
98
+ return lines.join("\n") + "\n";
99
+ }
100
+ const assigned = identity.colors.filter((c) => c.role !== "unknown");
101
+ const unassigned = identity.colors.filter((c) => c.role === "unknown");
102
+ lines.push("| Name | Hex | Role | Confidence |");
103
+ lines.push("|------|-----|------|------------|");
104
+ for (const c of assigned) {
105
+ lines.push(`| ${cleanColorName(c)} | \`${c.value}\` | ${c.role} | ${c.confidence} |`);
106
+ }
107
+ if (unassigned.length > 0) {
108
+ lines.push("");
109
+ lines.push("**Unassigned colors** — use `brand_clarify` to assign roles:");
110
+ lines.push("");
111
+ for (const c of unassigned) {
112
+ lines.push(`- \`${c.value}\` (${c.confidence} confidence, via ${c.source})`);
113
+ }
114
+ }
115
+ lines.push("");
116
+ return lines.join("\n") + "\n";
117
+ }
118
+ function renderSemanticMapping(identity) {
119
+ const lines = [];
120
+ lines.push("### 1b. Semantic Mapping");
121
+ lines.push("");
122
+ if (identity.colors.length === 0) {
123
+ lines.push(stub("semantic color mapping", "brand_extract_web or brand_extract_figma"));
124
+ return lines.join("\n") + "\n";
125
+ }
126
+ const assigned = identity.colors.filter((c) => c.role !== "unknown");
127
+ const byRole = groupBy(assigned, (c) => c.role);
128
+ for (const [role, colors] of Object.entries(byRole)) {
129
+ lines.push(`**${capitalize(role)}**`);
130
+ for (const c of colors) {
131
+ lines.push(`- \`${c.value}\` — ${cleanColorName(c)}`);
132
+ }
133
+ lines.push("");
134
+ }
135
+ return lines.join("\n") + "\n";
136
+ }
137
+ function renderThemeModes(identity) {
138
+ const lines = [];
139
+ lines.push("### 1c. Theme Modes");
140
+ lines.push("");
141
+ const hasSurface = identity.colors.some((c) => c.role === "surface");
142
+ const hasText = identity.colors.some((c) => c.role === "text");
143
+ if (!hasSurface && !hasText) {
144
+ lines.push(stub("theme modes", "brand_deepen_identity to define dark/light variants"));
145
+ return lines.join("\n") + "\n";
146
+ }
147
+ lines.push("Theme mapping is derived from surface and text color tokens.");
148
+ lines.push("");
149
+ if (hasSurface) {
150
+ const surfaces = identity.colors.filter((c) => c.role === "surface");
151
+ lines.push("**Surface colors:**");
152
+ for (const s of surfaces) {
153
+ lines.push(`- \`${s.value}\` — ${cleanColorName(s)}`);
154
+ }
155
+ lines.push("");
156
+ }
157
+ if (hasText) {
158
+ const texts = identity.colors.filter((c) => c.role === "text");
159
+ lines.push("**Text colors:**");
160
+ for (const t of texts) {
161
+ lines.push(`- \`${t.value}\` — ${cleanColorName(t)}`);
162
+ }
163
+ lines.push("");
164
+ }
165
+ return lines.join("\n") + "\n";
166
+ }
167
+ // ---------------------------------------------------------------------------
168
+ // Section renderers — Typography
169
+ // ---------------------------------------------------------------------------
170
+ function renderTypeStack(identity) {
171
+ const lines = [];
172
+ lines.push("### 2a. Type Stack");
173
+ lines.push("");
174
+ if (identity.typography.length === 0) {
175
+ lines.push(stub("typography", "brand_extract_web or brand_extract_figma"));
176
+ return lines.join("\n") + "\n";
177
+ }
178
+ lines.push("| Name | Family | Weight | Size | Confidence |");
179
+ lines.push("|------|--------|--------|------|------------|");
180
+ for (const t of identity.typography) {
181
+ lines.push(`| ${t.name} | ${t.family} | ${t.weight ?? "—"} | ${t.size ?? "—"} | ${t.confidence} |`);
182
+ }
183
+ lines.push("");
184
+ return lines.join("\n") + "\n";
185
+ }
186
+ function renderTypeUsage(identity) {
187
+ const lines = [];
188
+ lines.push("### 2b. Usage");
189
+ lines.push("");
190
+ if (identity.typography.length === 0) {
191
+ lines.push(stub("typography usage", "brand_extract_web or brand_extract_figma"));
192
+ return lines.join("\n") + "\n";
193
+ }
194
+ // Categorize by name/weight convention
195
+ const headings = identity.typography.filter((t) => /heading|display|title|h[1-6]/i.test(t.name) ||
196
+ /bold|semibold|black|heavy/i.test(t.name) ||
197
+ /bold|semibold|black|heavy/i.test(t.family) ||
198
+ (t.weight !== undefined && t.weight >= 600));
199
+ const body = identity.typography.filter((t) => !headings.includes(t) &&
200
+ (/body|paragraph|text|caption|base|regular|book/i.test(t.name) ||
201
+ /grotesk|sans$/i.test(t.family) ||
202
+ (t.weight !== undefined && t.weight >= 300 && t.weight <= 500)));
203
+ const mono = identity.typography.filter((t) => /mono|code|consolas|courier/i.test(t.name) || /mono|code/i.test(t.family));
204
+ const ui = identity.typography.filter((t) => !headings.includes(t) &&
205
+ !body.includes(t) &&
206
+ !mono.includes(t) &&
207
+ /inter|system|ui|roboto/i.test(t.family));
208
+ const other = identity.typography.filter((t) => !headings.includes(t) && !body.includes(t) && !mono.includes(t) && !ui.includes(t));
209
+ if (headings.length > 0) {
210
+ lines.push("**Headings:** " + headings.map((t) => `${t.family}`).join(", "));
211
+ }
212
+ if (body.length > 0) {
213
+ lines.push("**Body:** " + body.map((t) => `${t.family}`).join(", "));
214
+ }
215
+ if (mono.length > 0) {
216
+ lines.push("**Monospace:** " + mono.map((t) => `${t.family}`).join(", "));
217
+ }
218
+ if (ui.length > 0) {
219
+ lines.push("**UI/System:** " + ui.map((t) => `${t.family}`).join(", "));
220
+ }
221
+ if (other.length > 0) {
222
+ lines.push("**Other:** " + other.map((t) => `${t.family}`).join(", "));
223
+ }
224
+ if (headings.length === 0 && body.length === 0 && mono.length === 0 && ui.length === 0 && other.length === 0) {
225
+ lines.push("Run extraction tools to categorize font usage.");
226
+ }
227
+ lines.push("");
228
+ return lines.join("\n") + "\n";
229
+ }
230
+ // ---------------------------------------------------------------------------
231
+ // Section renderers — Composition
232
+ // ---------------------------------------------------------------------------
233
+ function renderSpatialPhilosophy(visual) {
234
+ const lines = [];
235
+ lines.push("### 3a. Spatial Philosophy");
236
+ lines.push("");
237
+ if (!visual.composition) {
238
+ lines.push(stub("composition", "brand_deepen_identity"));
239
+ return lines.join("\n") + "\n";
240
+ }
241
+ lines.push(`**Energy:** ${visual.composition.energy}`);
242
+ lines.push(`**Layout preference:** ${visual.composition.layout_preference}`);
243
+ lines.push("");
244
+ return lines.join("\n") + "\n";
245
+ }
246
+ function renderNegativeSpace(visual) {
247
+ const lines = [];
248
+ lines.push("### 3b. Negative Space");
249
+ lines.push("");
250
+ if (!visual.composition) {
251
+ lines.push(stub("negative space rules", "brand_deepen_identity"));
252
+ return lines.join("\n") + "\n";
253
+ }
254
+ lines.push(`**Rule:** ${visual.composition.negative_space}`);
255
+ lines.push("");
256
+ lines.push("This is a measurable constraint. Automated preflight checks negative space ratio.");
257
+ lines.push("");
258
+ return lines.join("\n") + "\n";
259
+ }
260
+ function renderGridLayout(visual) {
261
+ const lines = [];
262
+ lines.push("### 3c. Grid & Layout");
263
+ lines.push("");
264
+ if (!visual.composition) {
265
+ lines.push(stub("grid system", "brand_deepen_identity"));
266
+ return lines.join("\n") + "\n";
267
+ }
268
+ lines.push(`**Grid:** ${visual.composition.grid}`);
269
+ lines.push("");
270
+ return lines.join("\n") + "\n";
271
+ }
272
+ // ---------------------------------------------------------------------------
273
+ // Section renderers — Visual Language
274
+ // ---------------------------------------------------------------------------
275
+ function renderPatternSystem(visual) {
276
+ const lines = [];
277
+ lines.push("### 4a. Pattern System");
278
+ lines.push("");
279
+ if (!visual.patterns) {
280
+ lines.push(stub("patterns", "brand_deepen_identity", "patterns questions"));
281
+ return lines.join("\n") + "\n";
282
+ }
283
+ lines.push(`**Type:** ${visual.patterns.type}`);
284
+ lines.push(`**Usage:** ${visual.patterns.usage}`);
285
+ if (visual.patterns.assets.length > 0) {
286
+ lines.push("**Assets:**");
287
+ for (const a of visual.patterns.assets) {
288
+ lines.push(`- \`${a}\``);
289
+ }
290
+ }
291
+ lines.push("");
292
+ return lines.join("\n") + "\n";
293
+ }
294
+ function renderIllustrationLanguage(visual) {
295
+ const lines = [];
296
+ lines.push("### 4b. Illustration Language");
297
+ lines.push("");
298
+ if (!visual.illustration) {
299
+ lines.push(stub("illustration language", "brand_deepen_identity", "illustration questions"));
300
+ return lines.join("\n") + "\n";
301
+ }
302
+ lines.push(`**Style:** ${visual.illustration.style}`);
303
+ lines.push(`**Function:** ${visual.illustration.function}`);
304
+ if (visual.illustration.assets.length > 0) {
305
+ lines.push("**Assets:**");
306
+ for (const a of visual.illustration.assets) {
307
+ lines.push(`- \`${a}\``);
308
+ }
309
+ }
310
+ lines.push("");
311
+ return lines.join("\n") + "\n";
312
+ }
313
+ function renderPhotographyDirection(visual) {
314
+ const lines = [];
315
+ lines.push("### 4c. Photography Direction");
316
+ lines.push("");
317
+ if (!visual.photography) {
318
+ lines.push(stub("photography direction", "brand_deepen_identity", "photography questions"));
319
+ return lines.join("\n") + "\n";
320
+ }
321
+ lines.push(`**Style:** ${visual.photography.style}`);
322
+ if (visual.photography.anti_patterns.length > 0) {
323
+ lines.push("**Avoid:**");
324
+ for (const ap of visual.photography.anti_patterns) {
325
+ lines.push(`- ${ap}`);
326
+ }
327
+ }
328
+ lines.push("");
329
+ return lines.join("\n") + "\n";
330
+ }
331
+ function renderSignatureMoves(visual) {
332
+ const lines = [];
333
+ lines.push("### 4d. Signature Moves");
334
+ lines.push("");
335
+ if (!visual.signature) {
336
+ lines.push(stub("signature moves", "brand_deepen_identity", "signature questions"));
337
+ return lines.join("\n") + "\n";
338
+ }
339
+ lines.push(`**Description:** ${visual.signature.description}`);
340
+ if (visual.signature.elements.length > 0) {
341
+ lines.push("**Elements:**");
342
+ for (const el of visual.signature.elements) {
343
+ lines.push(`- ${el}`);
344
+ }
345
+ }
346
+ lines.push("");
347
+ return lines.join("\n") + "\n";
348
+ }
349
+ // ---------------------------------------------------------------------------
350
+ // Section renderers — Logo
351
+ // ---------------------------------------------------------------------------
352
+ function renderLockupRules(identity) {
353
+ const lines = [];
354
+ lines.push("### 5a. Lockup Rules");
355
+ lines.push("");
356
+ if (identity.logo.length === 0) {
357
+ lines.push(stub("logo lockup rules", "brand_extract_web or brand_extract_figma"));
358
+ return lines.join("\n") + "\n";
359
+ }
360
+ const types = identity.logo.map((l) => l.type);
361
+ const hasWordmark = types.includes("wordmark");
362
+ const hasLogomark = types.includes("logomark");
363
+ if (hasWordmark && hasLogomark) {
364
+ lines.push("Both wordmark and logomark are available.");
365
+ lines.push("**Rule:** Use wordmark OR logomark in a composition — never both together.");
366
+ }
367
+ else if (hasWordmark) {
368
+ lines.push("Wordmark available. No logomark on file.");
369
+ }
370
+ else if (hasLogomark) {
371
+ lines.push("Logomark available. No wordmark on file.");
372
+ }
373
+ lines.push("");
374
+ lines.push("Always use the actual SVG/PNG asset files. Never approximate logos with CSS shapes or fonts.");
375
+ lines.push("");
376
+ return lines.join("\n") + "\n";
377
+ }
378
+ function renderAssetReference(identity) {
379
+ const lines = [];
380
+ lines.push("### 5b. Asset Reference");
381
+ lines.push("");
382
+ if (identity.logo.length === 0) {
383
+ lines.push(stub("logo assets", "brand_extract_web or brand_extract_figma"));
384
+ return lines.join("\n") + "\n";
385
+ }
386
+ for (const logo of identity.logo) {
387
+ lines.push(`**${capitalize(logo.type)}** (source: ${logo.source}, confidence: ${logo.confidence})`);
388
+ for (const v of logo.variants) {
389
+ const filePath = v.file?.startsWith("logo/") ? v.file : `logo/${v.file}`;
390
+ const ref = v.file ? `\`.brand/assets/${filePath}\`` : v.inline_svg ? "inline SVG" : "data URI";
391
+ lines.push(`- ${v.name}: ${ref}`);
392
+ }
393
+ lines.push("");
394
+ }
395
+ return lines.join("\n") + "\n";
396
+ }
397
+ // ---------------------------------------------------------------------------
398
+ // Section renderers — Compliance
399
+ // ---------------------------------------------------------------------------
400
+ function renderAntiPatternsHard(visual) {
401
+ const lines = [];
402
+ lines.push("### 6a. Anti-Patterns (Hard Stops)");
403
+ lines.push("");
404
+ const hardRules = visual.anti_patterns.filter((ap) => ap.severity === "hard");
405
+ if (hardRules.length === 0) {
406
+ lines.push(stub("hard-stop anti-patterns", "brand_deepen_identity", "anti-pattern questions"));
407
+ return lines.join("\n") + "\n";
408
+ }
409
+ for (const rule of hardRules) {
410
+ const pfRef = rule.preflight_id ? ` (preflight: \`${rule.preflight_id}\`)` : "";
411
+ lines.push(`- **${rule.rule}**${pfRef}`);
412
+ }
413
+ lines.push("");
414
+ return lines.join("\n") + "\n";
415
+ }
416
+ function renderAntiPatternsSoft(visual) {
417
+ const lines = [];
418
+ lines.push("### 6b. Soft Guidelines");
419
+ lines.push("");
420
+ const softRules = visual.anti_patterns.filter((ap) => ap.severity === "soft");
421
+ if (softRules.length === 0) {
422
+ lines.push(stub("soft guidelines", "brand_deepen_identity", "anti-pattern questions"));
423
+ return lines.join("\n") + "\n";
424
+ }
425
+ for (const rule of softRules) {
426
+ const pfRef = rule.preflight_id ? ` (preflight: \`${rule.preflight_id}\`)` : "";
427
+ lines.push(`- ${rule.rule}${pfRef}`);
428
+ }
429
+ lines.push("");
430
+ return lines.join("\n") + "\n";
431
+ }
432
+ function renderAutomatedChecks() {
433
+ const lines = [];
434
+ lines.push("### 6c. Automated Checks");
435
+ lines.push("");
436
+ lines.push("Run `brand_preflight` against any HTML, CSS, or design file to validate compliance.");
437
+ lines.push("The preflight tool checks color usage, typography, logo rules, and anti-patterns automatically.");
438
+ lines.push("");
439
+ return lines.join("\n") + "\n";
440
+ }
441
+ // ---------------------------------------------------------------------------
442
+ // System Integration helpers
443
+ // ---------------------------------------------------------------------------
444
+ function renderQuickSetupBlock(config, identity, visual, messaging) {
445
+ const lines = [];
446
+ lines.push(`# ${config.client_name} Brand System`);
447
+ lines.push("");
448
+ // Colors — only show assigned roles, skip unknowns
449
+ const assignedColors = identity.colors.filter((c) => c.role !== "unknown");
450
+ if (assignedColors.length > 0) {
451
+ lines.push("## Colors");
452
+ lines.push("Use ONLY these colors:");
453
+ for (const c of assignedColors) {
454
+ lines.push(`- ${capitalize(c.role)}: ${c.value}`);
455
+ }
456
+ lines.push("");
457
+ }
458
+ // Typography
459
+ if (identity.typography.length > 0) {
460
+ lines.push("## Typography");
461
+ const families = [...new Set(identity.typography.map((t) => t.family))];
462
+ for (const fam of families) {
463
+ const entries = identity.typography.filter((t) => t.family === fam);
464
+ const weights = entries
465
+ .filter((e) => e.weight !== undefined)
466
+ .map((e) => e.weight)
467
+ .join(", ");
468
+ lines.push(`- ${fam}${weights ? ` (weights: ${weights})` : ""}`);
469
+ }
470
+ lines.push("");
471
+ }
472
+ // Logo — embed SVG inline if available
473
+ if (identity.logo.length > 0) {
474
+ lines.push("## Logo");
475
+ lines.push("ALWAYS use this exact SVG for the logo. NEVER type the company name in a font.");
476
+ lines.push("");
477
+ const firstLogo = identity.logo[0];
478
+ const firstVariant = firstLogo?.variants[0];
479
+ if (firstVariant?.inline_svg) {
480
+ lines.push("```svg");
481
+ lines.push(firstVariant.inline_svg);
482
+ lines.push("```");
483
+ lines.push("");
484
+ lines.push("For dark backgrounds, set all path fills to #ffffff.");
485
+ if (firstVariant.data_uri) {
486
+ lines.push(`For \`<img>\` tags, use this data URI: ${firstVariant.data_uri}`);
487
+ }
488
+ lines.push("");
489
+ }
490
+ const types = identity.logo.map((l) => l.type);
491
+ if (types.includes("wordmark") && types.includes("logomark")) {
492
+ lines.push("Use wordmark OR logomark — never both in the same composition.");
493
+ lines.push("");
494
+ }
495
+ }
496
+ // Anti-patterns
497
+ const hardRules = visual.anti_patterns.filter((ap) => ap.severity === "hard");
498
+ if (hardRules.length > 0) {
499
+ lines.push("## Anti-Patterns (NEVER do these)");
500
+ for (const rule of hardRules) {
501
+ lines.push(`- ${rule.rule}`);
502
+ }
503
+ lines.push("");
504
+ }
505
+ const softRules = visual.anti_patterns.filter((ap) => ap.severity === "soft");
506
+ if (softRules.length > 0) {
507
+ lines.push("## Soft Guidelines (avoid unless justified)");
508
+ for (const rule of softRules) {
509
+ lines.push(`- ${rule.rule}`);
510
+ }
511
+ lines.push("");
512
+ }
513
+ // Composition
514
+ if (visual.composition) {
515
+ lines.push("## Composition");
516
+ lines.push(`- Energy: ${visual.composition.energy}`);
517
+ lines.push(`- Negative space: ${visual.composition.negative_space}`);
518
+ lines.push(`- Layout: ${visual.composition.layout_preference}`);
519
+ lines.push(`- Grid: ${visual.composition.grid}`);
520
+ lines.push("");
521
+ }
522
+ // Signature
523
+ if (visual.signature) {
524
+ lines.push("## Signature Moves");
525
+ lines.push(`${visual.signature.description}`);
526
+ for (const el of visual.signature.elements) {
527
+ lines.push(`- ${el}`);
528
+ }
529
+ lines.push("");
530
+ }
531
+ // Voice & Messaging (inline in quick setup block too)
532
+ if (messaging) {
533
+ if (messaging.voice) {
534
+ const v = messaging.voice;
535
+ lines.push("## Voice Rules");
536
+ lines.push("");
537
+ if (v.tone.descriptors.length > 0) {
538
+ lines.push(`Tone: ${v.tone.descriptors.join(", ")}`);
539
+ }
540
+ if (v.tone.register) {
541
+ lines.push(`Register: ${v.tone.register}`);
542
+ }
543
+ if (v.tone.never_sounds_like) {
544
+ lines.push(`Never sounds like: ${v.tone.never_sounds_like}`);
545
+ }
546
+ lines.push("");
547
+ if (v.vocabulary.anchor.length > 0) {
548
+ lines.push("Anchor Terms (ALWAYS use these):");
549
+ for (const t of v.vocabulary.anchor) {
550
+ const reason = t.reason ? ` — ${t.reason}` : "";
551
+ lines.push(`- Use "${t.use}" not "${t.not}"${reason}`);
552
+ }
553
+ lines.push("");
554
+ }
555
+ if (v.vocabulary.never_say.length > 0) {
556
+ lines.push("Never Say:");
557
+ for (const t of v.vocabulary.never_say) {
558
+ const reason = t.reason ? ` — ${t.reason}` : "";
559
+ lines.push(`- ${t.word}${reason}`);
560
+ }
561
+ lines.push("");
562
+ }
563
+ lines.push("Conventions:");
564
+ lines.push(`- Person: ${v.tone.conventions.person}`);
565
+ lines.push(`- Oxford comma: ${v.tone.conventions.oxford_comma ? "yes" : "no"}`);
566
+ lines.push(`- Target sentence length: ${v.tone.conventions.sentence_length} words`);
567
+ lines.push("");
568
+ }
569
+ }
570
+ lines.push("## Validation");
571
+ lines.push("Run `brand_preflight` before delivering any visual output.");
572
+ return lines.join("\n");
573
+ }
574
+ function renderPainPoints(identity, visual) {
575
+ const lines = [];
576
+ // --- Logo approximation ---
577
+ lines.push("### Logo approximation");
578
+ lines.push("");
579
+ lines.push("**Problem:** AI tools often approximate logos with CSS or icon fonts.");
580
+ if (identity.logo.length > 0) {
581
+ const firstVariant = identity.logo[0]?.variants[0];
582
+ if (firstVariant?.inline_svg) {
583
+ lines.push("**Fix:** Use the SVG embedded above in the Logo section. For web, use the `<symbol>` + `<use>` pattern so `currentColor` inheritance works.");
584
+ }
585
+ else {
586
+ lines.push("**Fix:** Always read the actual SVG file and use its path data. For web, use the `<symbol>` + `<use>` pattern so `currentColor` inheritance works.");
587
+ }
588
+ }
589
+ else {
590
+ lines.push("**Fix:** Always read the actual SVG file and use its path data. For web, use the `<symbol>` + `<use>` pattern so `currentColor` inheritance works.");
591
+ }
592
+ lines.push("");
593
+ // --- Wrong colors ---
594
+ lines.push("### Wrong colors");
595
+ lines.push("");
596
+ lines.push("**Problem:** AI tools guess colors instead of using exact brand tokens.");
597
+ const assignedColors = identity.colors.filter((c) => c.role !== "unknown");
598
+ if (assignedColors.length > 0) {
599
+ lines.push("**Fix:** Use ONLY these colors:");
600
+ for (const c of assignedColors) {
601
+ lines.push(`- ${capitalize(c.role)}: ${c.value}`);
602
+ }
603
+ }
604
+ else {
605
+ lines.push("**Fix:** Use the exact color values listed in the Colors section above.");
606
+ }
607
+ lines.push("");
608
+ // --- Generic output ---
609
+ lines.push("### Generic output");
610
+ lines.push("");
611
+ lines.push("**Problem:** Output is technically correct but not distinctive — misses the brand's visual personality.");
612
+ if (visual.signature) {
613
+ lines.push(`**Fix:** Apply these signature moves: ${visual.signature.elements.join("; ")}.`);
614
+ }
615
+ else {
616
+ lines.push("**Fix:** Run `brand_deepen_identity` to define signature moves that make the brand distinctive.");
617
+ }
618
+ if (visual.composition) {
619
+ lines.push(`Remember: composition energy is "${visual.composition.energy}" with ${visual.composition.negative_space} negative space.`);
620
+ }
621
+ lines.push("");
622
+ return lines.join("\n");
623
+ }
624
+ // ---------------------------------------------------------------------------
625
+ // Voice & Messaging renderer (for self-contained integration doc)
626
+ // ---------------------------------------------------------------------------
627
+ function renderVoiceMessagingSection(messaging) {
628
+ const lines = [];
629
+ lines.push("## Voice & Messaging");
630
+ lines.push("");
631
+ if (messaging.perspective) {
632
+ lines.push("### Perspective");
633
+ lines.push(`- **Worldview:** ${messaging.perspective.worldview}`);
634
+ lines.push(`- **Tension:** ${messaging.perspective.tension}`);
635
+ lines.push(`- **Positioning:** ${messaging.perspective.positioning}`);
636
+ if (messaging.perspective.one_liner) {
637
+ lines.push(`- **One-liner:** ${messaging.perspective.one_liner}`);
638
+ }
639
+ lines.push("");
640
+ }
641
+ if (messaging.voice) {
642
+ const v = messaging.voice;
643
+ lines.push("### Voice Rules");
644
+ lines.push("");
645
+ if (v.tone.descriptors.length > 0) {
646
+ lines.push(`**Tone:** ${v.tone.descriptors.join(", ")}`);
647
+ }
648
+ if (v.tone.register) {
649
+ lines.push(`**Register:** ${v.tone.register}`);
650
+ }
651
+ if (v.tone.never_sounds_like) {
652
+ lines.push(`**Never sounds like:** ${v.tone.never_sounds_like}`);
653
+ }
654
+ lines.push("");
655
+ if (v.vocabulary.anchor.length > 0) {
656
+ lines.push("**Anchor Terms (ALWAYS use these):**");
657
+ for (const t of v.vocabulary.anchor) {
658
+ const reason = t.reason ? ` — ${t.reason}` : "";
659
+ lines.push(`- Use "${t.use}" not "${t.not}"${reason}`);
660
+ }
661
+ lines.push("");
662
+ }
663
+ if (v.vocabulary.never_say.length > 0) {
664
+ lines.push("**Never Say:**");
665
+ for (const t of v.vocabulary.never_say) {
666
+ const reason = t.reason ? ` — ${t.reason}` : "";
667
+ lines.push(`- ${t.word}${reason}`);
668
+ }
669
+ lines.push("");
670
+ }
671
+ lines.push("**Conventions:**");
672
+ lines.push(`- Person: ${v.tone.conventions.person}`);
673
+ lines.push(`- Oxford comma: ${v.tone.conventions.oxford_comma ? "yes" : "no"}`);
674
+ lines.push(`- Target sentence length: ${v.tone.conventions.sentence_length} words`);
675
+ lines.push("");
676
+ if (v.ai_ism_detection.patterns.length > 0) {
677
+ lines.push("**AI-ism Detection (flag and rewrite):**");
678
+ for (const p of v.ai_ism_detection.patterns.slice(0, 10)) {
679
+ lines.push(`- "${p}"`);
680
+ }
681
+ if (v.ai_ism_detection.patterns.length > 10) {
682
+ lines.push(`- ... and ${v.ai_ism_detection.patterns.length - 10} more patterns`);
683
+ }
684
+ lines.push("");
685
+ }
686
+ }
687
+ if (messaging.brand_story) {
688
+ lines.push("### Brand Story");
689
+ lines.push(`> ${messaging.brand_story.tagline}`);
690
+ lines.push("");
691
+ }
692
+ return lines.join("\n");
693
+ }
694
+ // ---------------------------------------------------------------------------
695
+ // Utilities
696
+ // ---------------------------------------------------------------------------
697
+ function stub(section, tool, topic) {
698
+ const topicSuffix = topic ? ` and answer the ${topic}` : "";
699
+ return `**Status: Not yet defined.**\nRun \`${tool}\`${topicSuffix} to populate this section.\n`;
700
+ }
701
+ function capitalize(s) {
702
+ return s.charAt(0).toUpperCase() + s.slice(1);
703
+ }
704
+ /** Generate a clean, human-readable color name from extracted data */
705
+ function cleanColorName(color) {
706
+ return cleanColorNameShared(color);
707
+ }
708
+ function groupBy(arr, keyFn) {
709
+ const result = {};
710
+ for (const item of arr) {
711
+ const key = keyFn(item);
712
+ if (!result[key])
713
+ result[key] = [];
714
+ result[key].push(item);
715
+ }
716
+ return result;
717
+ }
718
+ //# sourceMappingURL=vim-generator.js.map