@nguyenphp/antigravity-marketing 1.0.18 → 1.0.19

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 (127) hide show
  1. package/README.md +186 -78
  2. package/package.json +4 -3
  3. package/templates/.agent/skills/marketing-report-expert/SKILL.md +70 -0
  4. package/templates/.agent/skills/minimax-docx/LICENSE +21 -0
  5. package/templates/.agent/skills/minimax-docx/SKILL.md +274 -0
  6. package/templates/.agent/skills/minimax-docx/assets/styles/academic_styles.xml +250 -0
  7. package/templates/.agent/skills/minimax-docx/assets/styles/corporate_styles.xml +284 -0
  8. package/templates/.agent/skills/minimax-docx/assets/styles/default_styles.xml +449 -0
  9. package/templates/.agent/skills/minimax-docx/assets/xsd/aesthetic-rules.xsd +470 -0
  10. package/templates/.agent/skills/minimax-docx/assets/xsd/business-rules.xsd +130 -0
  11. package/templates/.agent/skills/minimax-docx/assets/xsd/common-types.xsd +159 -0
  12. package/templates/.agent/skills/minimax-docx/assets/xsd/wml-subset.xsd +589 -0
  13. package/templates/.agent/skills/minimax-docx/references/cjk_typography.md +357 -0
  14. package/templates/.agent/skills/minimax-docx/references/cjk_university_template_guide.md +184 -0
  15. package/templates/.agent/skills/minimax-docx/references/comments_guide.md +191 -0
  16. package/templates/.agent/skills/minimax-docx/references/design_good_bad_examples.md +829 -0
  17. package/templates/.agent/skills/minimax-docx/references/design_principles.md +819 -0
  18. package/templates/.agent/skills/minimax-docx/references/openxml_element_order.md +308 -0
  19. package/templates/.agent/skills/minimax-docx/references/openxml_encyclopedia_part1.md +4061 -0
  20. package/templates/.agent/skills/minimax-docx/references/openxml_encyclopedia_part2.md +2820 -0
  21. package/templates/.agent/skills/minimax-docx/references/openxml_encyclopedia_part3.md +3381 -0
  22. package/templates/.agent/skills/minimax-docx/references/openxml_namespaces.md +82 -0
  23. package/templates/.agent/skills/minimax-docx/references/openxml_units.md +72 -0
  24. package/templates/.agent/skills/minimax-docx/references/scenario_a_create.md +284 -0
  25. package/templates/.agent/skills/minimax-docx/references/scenario_b_edit_content.md +295 -0
  26. package/templates/.agent/skills/minimax-docx/references/scenario_c_apply_template.md +456 -0
  27. package/templates/.agent/skills/minimax-docx/references/track_changes_guide.md +200 -0
  28. package/templates/.agent/skills/minimax-docx/references/troubleshooting.md +506 -0
  29. package/templates/.agent/skills/minimax-docx/references/typography_guide.md +294 -0
  30. package/templates/.agent/skills/minimax-docx/references/xsd_validation_guide.md +158 -0
  31. package/templates/.agent/skills/minimax-docx/scripts/doc_to_docx.sh +40 -0
  32. package/templates/.agent/skills/minimax-docx/scripts/docx_preview.sh +37 -0
  33. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Cli/MiniMaxAIDocx.Cli.csproj +19 -0
  34. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Cli/Program.cs +18 -0
  35. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/AnalyzeCommand.cs +147 -0
  36. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/ApplyTemplateCommand.cs +322 -0
  37. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/CreateCommand.cs +324 -0
  38. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/DiffCommand.cs +155 -0
  39. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/EditContentCommand.cs +487 -0
  40. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/FixOrderCommand.cs +108 -0
  41. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/MergeRunsCommand.cs +122 -0
  42. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Commands/ValidateCommand.cs +107 -0
  43. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/MiniMaxAIDocx.Core.csproj +15 -0
  44. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/CommentSynchronizer.cs +169 -0
  45. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/ElementOrder.cs +80 -0
  46. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/NamespaceConstants.cs +42 -0
  47. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/RunMerger.cs +81 -0
  48. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/StyleAnalyzer.cs +81 -0
  49. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/TrackChangesHelper.cs +99 -0
  50. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/OpenXml/UnitConverter.cs +23 -0
  51. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples.cs +1832 -0
  52. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch1.cs +910 -0
  53. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch2.cs +999 -0
  54. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch3.cs +1048 -0
  55. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/AestheticRecipeSamples_Batch4.cs +1038 -0
  56. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/CharacterFormattingSamples.cs +1020 -0
  57. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/DocumentCreationSamples.cs +1121 -0
  58. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/FieldAndTocSamples.cs +624 -0
  59. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/FootnoteAndCommentSamples.cs +675 -0
  60. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/HeaderFooterSamples.cs +838 -0
  61. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ImageSamples.cs +917 -0
  62. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ListAndNumberingSamples.cs +826 -0
  63. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/ParagraphFormattingSamples.cs +1199 -0
  64. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/StyleSystemSamples.cs +1487 -0
  65. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/TableSamples.cs +1163 -0
  66. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Samples/TrackChangesSamples.cs +595 -0
  67. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/CjkHelper.cs +39 -0
  68. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/FontDefaults.cs +24 -0
  69. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Typography/PageSizes.cs +20 -0
  70. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/BusinessRuleValidator.cs +224 -0
  71. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/GateCheckValidator.cs +148 -0
  72. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/ValidationResult.cs +23 -0
  73. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.Core/Validation/XsdValidator.cs +69 -0
  74. package/templates/.agent/skills/minimax-docx/scripts/dotnet/MiniMaxAIDocx.slnx +4 -0
  75. package/templates/.agent/skills/minimax-docx/scripts/env_check.sh +196 -0
  76. package/templates/.agent/skills/minimax-docx/scripts/setup.ps1 +274 -0
  77. package/templates/.agent/skills/minimax-docx/scripts/setup.sh +504 -0
  78. package/templates/.agent/skills/minimax-multimodal-toolkit/SKILL.md +359 -0
  79. package/templates/.agent/skills/minimax-pdf/README.md +222 -0
  80. package/templates/.agent/skills/minimax-pdf/SKILL.md +201 -0
  81. package/templates/.agent/skills/minimax-pdf/design/design.md +381 -0
  82. package/templates/.agent/skills/minimax-pdf/scripts/cover.py +1579 -0
  83. package/templates/.agent/skills/minimax-pdf/scripts/fill_inspect.py +200 -0
  84. package/templates/.agent/skills/minimax-pdf/scripts/fill_write.py +242 -0
  85. package/templates/.agent/skills/minimax-pdf/scripts/make.sh +491 -0
  86. package/templates/.agent/skills/minimax-pdf/scripts/merge.py +112 -0
  87. package/templates/.agent/skills/minimax-pdf/scripts/palette.py +559 -0
  88. package/templates/.agent/skills/minimax-pdf/scripts/reformat_parse.py +374 -0
  89. package/templates/.agent/skills/minimax-pdf/scripts/render_body.py +1055 -0
  90. package/templates/.agent/skills/minimax-pdf/scripts/render_cover.cjs +111 -0
  91. package/templates/.agent/skills/minimax-xlsx/SKILL.md +138 -0
  92. package/templates/.agent/skills/minimax-xlsx/references/create.md +691 -0
  93. package/templates/.agent/skills/minimax-xlsx/references/edit.md +684 -0
  94. package/templates/.agent/skills/minimax-xlsx/references/fix.md +37 -0
  95. package/templates/.agent/skills/minimax-xlsx/references/format.md +768 -0
  96. package/templates/.agent/skills/minimax-xlsx/references/ooxml-cheatsheet.md +231 -0
  97. package/templates/.agent/skills/minimax-xlsx/references/read-analyze.md +97 -0
  98. package/templates/.agent/skills/minimax-xlsx/references/validate.md +772 -0
  99. package/templates/.agent/skills/minimax-xlsx/scripts/formula_check.py +422 -0
  100. package/templates/.agent/skills/minimax-xlsx/scripts/libreoffice_recalc.py +248 -0
  101. package/templates/.agent/skills/minimax-xlsx/scripts/shared_strings_builder.py +163 -0
  102. package/templates/.agent/skills/minimax-xlsx/scripts/style_audit.py +575 -0
  103. package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_add_column.py +395 -0
  104. package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_insert_row.py +274 -0
  105. package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_pack.py +87 -0
  106. package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_reader.py +362 -0
  107. package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_shift_rows.py +396 -0
  108. package/templates/.agent/skills/minimax-xlsx/scripts/xlsx_unpack.py +130 -0
  109. package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/[Content_Types].xml +9 -0
  110. package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/_rels/.rels +6 -0
  111. package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/xl/_rels/workbook.xml.rels +19 -0
  112. package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/xl/sharedStrings.xml +33 -0
  113. package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/xl/styles.xml +160 -0
  114. package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/xl/workbook.xml +30 -0
  115. package/templates/.agent/skills/minimax-xlsx/templates/minimal_xlsx/xl/worksheets/sheet1.xml +70 -0
  116. package/templates/.agent/skills/pptx-generator/SKILL.md +249 -0
  117. package/templates/.agent/skills/pptx-generator/references/design-system.md +392 -0
  118. package/templates/.agent/skills/pptx-generator/references/editing.md +162 -0
  119. package/templates/.agent/skills/pptx-generator/references/pitfalls.md +112 -0
  120. package/templates/.agent/skills/pptx-generator/references/pptxgenjs.md +420 -0
  121. package/templates/.agent/skills/pptx-generator/references/slide-types.md +413 -0
  122. package/templates/.agent/skills/tutorial-video-expert/SKILL.md +88 -0
  123. package/templates/.agent/skills/ui-ux-pro-max/SKILL.md +170 -585
  124. package/templates/.agent/skills/vision-analysis/SKILL.md +174 -0
  125. package/templates/.agent/workflows/analyze.md +3 -0
  126. package/templates/.agent/workflows/brand-report.md +44 -0
  127. package/templates/.agent/workflows/report.md +49 -0
@@ -0,0 +1,559 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ palette.py — Infer design tokens from document metadata.
4
+
5
+ Usage:
6
+ python3 palette.py --title "AI Trends 2025" --type report --out tokens.json
7
+ python3 palette.py --title "John Doe Resume" --type resume --out tokens.json
8
+ python3 palette.py --meta meta.json --out tokens.json
9
+
10
+ Outputs tokens.json consumed by all downstream scripts.
11
+ Cover fonts are loaded via Google Fonts @import in the cover HTML (no local caching).
12
+ Body fonts always use ReportLab system fonts (Times-Bold / Helvetica).
13
+ Exit codes: 0 success, 1 bad args, 3 write error
14
+ """
15
+
16
+ import argparse
17
+ import json
18
+ import sys
19
+
20
+ # ── Palette library ────────────────────────────────────────────────────────────
21
+ # Each entry: cover colors + cover_pattern + mood
22
+ PALETTES = {
23
+ "report": {
24
+ # Charcoal blue-grey cover; muted steel blue accent — authoritative, not flashy
25
+ "cover_bg": "#1B2A38",
26
+ "accent": "#3B6D8A",
27
+ "accent_lt": "#E6EFF5",
28
+ "text_light": "#EDE9E2",
29
+ "page_bg": "#FAFAF8",
30
+ "dark": "#1A1E24",
31
+ "body_text": "#2C2C30",
32
+ "muted": "#7A7A84",
33
+ "cover_pattern": "fullbleed",
34
+ "mood": "authoritative",
35
+ },
36
+ "proposal": {
37
+ # Dark charcoal cover; slate grey-blue accent — confident, understated
38
+ "cover_bg": "#22272E",
39
+ "accent": "#4E6070",
40
+ "accent_lt": "#EAECEE",
41
+ "text_light": "#EDE9E2",
42
+ "page_bg": "#FAFAF7",
43
+ "dark": "#18191E",
44
+ "body_text": "#28282E",
45
+ "muted": "#7A7870",
46
+ "cover_pattern": "split",
47
+ "mood": "confident",
48
+ },
49
+ "resume": {
50
+ # White; deep navy accent — clean and unambiguous
51
+ "cover_bg": "#FFFFFF",
52
+ "accent": "#1C3557",
53
+ "accent_lt": "#E8EEF5",
54
+ "text_light": "#FFFFFF",
55
+ "page_bg": "#FFFFFF",
56
+ "dark": "#111111",
57
+ "body_text": "#222222",
58
+ "muted": "#888888",
59
+ "cover_pattern": "typographic",
60
+ "mood": "clean",
61
+ },
62
+ "portfolio": {
63
+ # Near-black charcoal; cool slate grey accent — subdued professional
64
+ "cover_bg": "#191C20",
65
+ "accent": "#6A7A88",
66
+ "accent_lt": "#EAECEE",
67
+ "text_light": "#EDE9E4",
68
+ "page_bg": "#F8F8F8",
69
+ "dark": "#18191E",
70
+ "body_text": "#28282E",
71
+ "muted": "#8A8A96",
72
+ "cover_pattern": "atmospheric",
73
+ "mood": "expressive",
74
+ },
75
+ "academic": {
76
+ # Warm white; classic navy accent — scholarly standard
77
+ "cover_bg": "#F5F4F0",
78
+ "accent": "#2A436A",
79
+ "accent_lt": "#E6EBF4",
80
+ "text_light": "#FFFFFF",
81
+ "page_bg": "#F5F4F0",
82
+ "dark": "#1A1A28",
83
+ "body_text": "#1E1E2A",
84
+ "muted": "#686877",
85
+ "cover_pattern": "typographic",
86
+ "mood": "scholarly",
87
+ },
88
+ "general": {
89
+ # Dark slate; muted steel accent — neutral, no-nonsense
90
+ "cover_bg": "#1F2329",
91
+ "accent": "#4A6070",
92
+ "accent_lt": "#E6EAEC",
93
+ "text_light": "#EEEBE5",
94
+ "page_bg": "#F8F6F2",
95
+ "dark": "#1A1A1A",
96
+ "body_text": "#2C2C2C",
97
+ "muted": "#888888",
98
+ "cover_pattern": "fullbleed",
99
+ "mood": "neutral",
100
+ },
101
+ # ── Extended types — each uses a distinct new cover pattern ─────────────────
102
+ "minimal": {
103
+ # Warm off-white; dark neutral grey — truly restrained, no color signal
104
+ "cover_bg": "#F7F6F4",
105
+ "accent": "#4A4A4A",
106
+ "accent_lt": "#EBEBEA",
107
+ "text_light": "#F7F6F4",
108
+ "page_bg": "#F7F6F4",
109
+ "dark": "#111111",
110
+ "body_text": "#222222",
111
+ "muted": "#999999",
112
+ "cover_pattern": "minimal",
113
+ "mood": "restrained",
114
+ },
115
+ "stripe": {
116
+ # Near-black; charcoal slate accent — structured, no-nonsense
117
+ "cover_bg": "#1E222A",
118
+ "accent": "#4A5568",
119
+ "accent_lt": "#EAECEE",
120
+ "text_light": "#FFFFFF",
121
+ "page_bg": "#F8F8F7",
122
+ "dark": "#0E1117",
123
+ "body_text": "#262630",
124
+ "muted": "#888898",
125
+ "cover_pattern": "stripe",
126
+ "mood": "bold",
127
+ },
128
+ "diagonal": {
129
+ # Deep navy; muted slate-blue accent — dignified, controlled
130
+ "cover_bg": "#1A2535",
131
+ "accent": "#3D5A72",
132
+ "accent_lt": "#E4EBF0",
133
+ "text_light": "#EEF0F5",
134
+ "page_bg": "#F8FAFC",
135
+ "dark": "#0F1A2A",
136
+ "body_text": "#1E2C3A",
137
+ "muted": "#7A8A96",
138
+ "cover_pattern": "diagonal",
139
+ "mood": "dynamic",
140
+ },
141
+ "frame": {
142
+ # Warm parchment; dark muted brown — classical, formal
143
+ "cover_bg": "#F5F2EC",
144
+ "accent": "#5C4A38",
145
+ "accent_lt": "#EAE5DE",
146
+ "text_light": "#F5F2EC",
147
+ "page_bg": "#F5F2EC",
148
+ "dark": "#2A1E14",
149
+ "body_text": "#2C2018",
150
+ "muted": "#9A8A78",
151
+ "cover_pattern": "frame",
152
+ "mood": "classical",
153
+ },
154
+ "editorial": {
155
+ # White; deep burgundy accent — editorial weight without the shout
156
+ "cover_bg": "#FFFFFF",
157
+ "accent": "#7A2B36",
158
+ "accent_lt": "#EEE4E5",
159
+ "text_light": "#FFFFFF",
160
+ "page_bg": "#FFFFFF",
161
+ "dark": "#0A0A0A",
162
+ "body_text": "#1A1A1A",
163
+ "muted": "#777777",
164
+ "cover_pattern": "editorial",
165
+ "mood": "editorial",
166
+ },
167
+ # ── New patterns (v2) ────────────────────────────────────────────────────────
168
+ "magazine": {
169
+ # Warm linen; deep navy accent — formal publication standard
170
+ "cover_bg": "#F0EEE9",
171
+ "accent": "#1C3557",
172
+ "accent_lt": "#E4EBF3",
173
+ "text_light": "#FFFFFF",
174
+ "page_bg": "#F0EEE9",
175
+ "dark": "#0D1A2B",
176
+ "body_text": "#2A2A2A",
177
+ "muted": "#888888",
178
+ "cover_pattern": "magazine",
179
+ "mood": "magazine",
180
+ },
181
+ "darkroom": {
182
+ # Deep navy; muted steel-blue accent — premium, controlled
183
+ "cover_bg": "#151C27",
184
+ "accent": "#3D5A7A",
185
+ "accent_lt": "#E2EBF2",
186
+ "text_light": "#EDE9E2",
187
+ "page_bg": "#F7F7F5",
188
+ "dark": "#0A1018",
189
+ "body_text": "#2C2C2C",
190
+ "muted": "#8A9AB0",
191
+ "cover_pattern": "darkroom",
192
+ "mood": "darkroom",
193
+ },
194
+ "terminal": {
195
+ # Near-black; forest green accent — technical, serious (not neon)
196
+ "cover_bg": "#0D1117",
197
+ "accent": "#3D7A5C",
198
+ "accent_lt": "#E2EEE8",
199
+ "text_light": "#E6EDF3",
200
+ "page_bg": "#F8F8F6",
201
+ "dark": "#010409",
202
+ "body_text": "#2C2C2C",
203
+ "muted": "#5A7A6A",
204
+ "cover_pattern": "terminal",
205
+ "mood": "terminal",
206
+ },
207
+ "poster": {
208
+ # White; near-black accent sidebar — stark, unambiguous
209
+ "cover_bg": "#FFFFFF",
210
+ "accent": "#0A0A0A",
211
+ "accent_lt": "#EBEBEA",
212
+ "text_light": "#FFFFFF",
213
+ "page_bg": "#FFFFFF",
214
+ "dark": "#0A0A0A",
215
+ "body_text": "#1A1A1A",
216
+ "muted": "#888888",
217
+ "cover_pattern": "poster",
218
+ "mood": "poster",
219
+ },
220
+ }
221
+
222
+ # ── Font pairs — CSS names for cover HTML, ReportLab names for body ─────────────
223
+ # cover uses Google Fonts via @import (no local disk caching needed)
224
+ # body always uses system fonts via ReportLab
225
+ FONT_PAIRS = {
226
+ "authoritative": {
227
+ "display_css": "Playfair Display",
228
+ "body_css": "IBM Plex Sans",
229
+ "gfonts_import": "https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700;900&family=IBM+Plex+Sans:ital,wght@0,400;0,600;1,400&display=swap",
230
+ "display_rl": "Times-Bold",
231
+ "body_rl": "Helvetica",
232
+ "body_b_rl": "Helvetica-Bold",
233
+ },
234
+ "confident": {
235
+ "display_css": "Syne",
236
+ "body_css": "Nunito Sans",
237
+ "gfonts_import": "https://fonts.googleapis.com/css2?family=Syne:wght@600;800&family=Nunito+Sans:wght@400;600;700&display=swap",
238
+ "display_rl": "Times-Bold",
239
+ "body_rl": "Helvetica",
240
+ "body_b_rl": "Helvetica-Bold",
241
+ },
242
+ "clean": {
243
+ "display_css": "DM Serif Display",
244
+ "body_css": "DM Sans",
245
+ "gfonts_import": "https://fonts.googleapis.com/css2?family=DM+Serif+Display&family=DM+Sans:wght@300;400;500&display=swap",
246
+ "display_rl": "Times-Bold",
247
+ "body_rl": "Helvetica",
248
+ "body_b_rl": "Helvetica-Bold",
249
+ },
250
+ "expressive": {
251
+ "display_css": "Fraunces",
252
+ "body_css": "Inter",
253
+ "gfonts_import": "https://fonts.googleapis.com/css2?family=Fraunces:ital,wght@0,700;0,900;1,900&family=Inter:wght@300;400;500&display=swap",
254
+ "display_rl": "Times-Bold",
255
+ "body_rl": "Helvetica",
256
+ "body_b_rl": "Helvetica-Bold",
257
+ },
258
+ "scholarly": {
259
+ "display_css": "EB Garamond",
260
+ "body_css": "Source Sans 3",
261
+ "gfonts_import": "https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400;0,700;1,400&family=Source+Sans+3:wght@400;600&display=swap",
262
+ "display_rl": "Times-Bold",
263
+ "body_rl": "Helvetica",
264
+ "body_b_rl": "Helvetica-Bold",
265
+ },
266
+ "neutral": {
267
+ "display_css": "Outfit",
268
+ "body_css": "Outfit",
269
+ "gfonts_import": "https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;700;900&display=swap",
270
+ "display_rl": "Times-Bold",
271
+ "body_rl": "Helvetica",
272
+ "body_b_rl": "Helvetica-Bold",
273
+ },
274
+ "restrained": {
275
+ "display_css": "Cormorant Garamond",
276
+ "body_css": "Jost",
277
+ "gfonts_import": "https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,600;1,300&family=Jost:wght@300;400;500&display=swap",
278
+ "display_rl": "Times-Bold",
279
+ "body_rl": "Helvetica",
280
+ "body_b_rl": "Helvetica-Bold",
281
+ },
282
+ "bold": {
283
+ "display_css": "Barlow Condensed",
284
+ "body_css": "Barlow",
285
+ "gfonts_import": "https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@700;900&family=Barlow:wght@400;500;600&display=swap",
286
+ "display_rl": "Times-Bold",
287
+ "body_rl": "Helvetica",
288
+ "body_b_rl": "Helvetica-Bold",
289
+ },
290
+ "dynamic": {
291
+ "display_css": "Montserrat",
292
+ "body_css": "Montserrat",
293
+ "gfonts_import": "https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,300;0,700;0,900;1,400&display=swap",
294
+ "display_rl": "Times-Bold",
295
+ "body_rl": "Helvetica",
296
+ "body_b_rl": "Helvetica-Bold",
297
+ },
298
+ "classical": {
299
+ "display_css": "Cormorant",
300
+ "body_css": "Crimson Pro",
301
+ "gfonts_import": "https://fonts.googleapis.com/css2?family=Cormorant:ital,wght@0,400;0,700;1,400&family=Crimson+Pro:wght@400;600&display=swap",
302
+ "display_rl": "Times-Bold",
303
+ "body_rl": "Helvetica",
304
+ "body_b_rl": "Helvetica-Bold",
305
+ },
306
+ "editorial": {
307
+ "display_css": "Bebas Neue",
308
+ "body_css": "Libre Franklin",
309
+ "gfonts_import": (
310
+ "https://fonts.googleapis.com/css2?family=Bebas+Neue"
311
+ "&family=Libre+Franklin:ital,wght@0,400;0,700;1,400&display=swap"
312
+ ),
313
+ "display_rl": "Times-Bold",
314
+ "body_rl": "Helvetica",
315
+ "body_b_rl": "Helvetica-Bold",
316
+ },
317
+ # ── New moods (v2) ───────────────────────────────────────────────────────────
318
+ "magazine": {
319
+ "display_css": "Playfair Display",
320
+ "body_css": "EB Garamond",
321
+ "gfonts_import": (
322
+ "https://fonts.googleapis.com/css2?family=Playfair+Display"
323
+ ":ital,wght@0,700;0,900;1,700"
324
+ "&family=EB+Garamond:ital,wght@0,400;0,600;1,400&display=swap"
325
+ ),
326
+ "display_rl": "Times-Bold",
327
+ "body_rl": "Helvetica",
328
+ "body_b_rl": "Helvetica-Bold",
329
+ },
330
+ "darkroom": {
331
+ "display_css": "Playfair Display",
332
+ "body_css": "EB Garamond",
333
+ "gfonts_import": (
334
+ "https://fonts.googleapis.com/css2?family=Playfair+Display"
335
+ ":ital,wght@0,700;0,900;1,700"
336
+ "&family=EB+Garamond:ital,wght@0,400;0,600;1,400&display=swap"
337
+ ),
338
+ "display_rl": "Times-Bold",
339
+ "body_rl": "Helvetica",
340
+ "body_b_rl": "Helvetica-Bold",
341
+ },
342
+ "terminal": {
343
+ "display_css": "Space Mono",
344
+ "body_css": "Space Mono",
345
+ "gfonts_import": (
346
+ "https://fonts.googleapis.com/css2?family=Space+Mono"
347
+ ":ital,wght@0,400;0,700;1,400&display=swap"
348
+ ),
349
+ "display_rl": "Courier-Bold",
350
+ "body_rl": "Courier",
351
+ "body_b_rl": "Courier-Bold",
352
+ },
353
+ "poster": {
354
+ "display_css": "Barlow Condensed",
355
+ "body_css": "Courier Prime",
356
+ "gfonts_import": (
357
+ "https://fonts.googleapis.com/css2?family=Barlow+Condensed"
358
+ ":wght@700;900"
359
+ "&family=Courier+Prime:ital,wght@0,400;0,700;1,400&display=swap"
360
+ ),
361
+ "display_rl": "Times-Bold",
362
+ "body_rl": "Courier",
363
+ "body_b_rl": "Courier-Bold",
364
+ },
365
+ }
366
+
367
+ SYSTEM_FALLBACK = {
368
+ "display_css": "Georgia",
369
+ "body_css": "Arial",
370
+ "gfonts_import": "",
371
+ "display_rl": "Times-Bold",
372
+ "body_rl": "Helvetica",
373
+ "body_b_rl": "Helvetica-Bold",
374
+ }
375
+
376
+
377
+ # ── Colour helpers ──────────────────────────────────────────────────────────────
378
+ def _hex_to_rgb(h: str) -> tuple:
379
+ h = h.lstrip("#")
380
+ return int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)
381
+
382
+
383
+ def _lighten(hex_color: str, factor: float = 0.09) -> str:
384
+ """Blend hex_color toward white (factor = accent weight, 0=white, 1=full color)."""
385
+ r, g, b = _hex_to_rgb(hex_color)
386
+ return "#{:02X}{:02X}{:02X}".format(
387
+ round(r * factor + 255 * (1 - factor)),
388
+ round(g * factor + 255 * (1 - factor)),
389
+ round(b * factor + 255 * (1 - factor)),
390
+ )
391
+
392
+
393
+ # ── Token assembly ─────────────────────────────────────────────────────────────
394
+ def build_tokens(
395
+ title: str,
396
+ doc_type: str,
397
+ author: str = "",
398
+ date: str = "",
399
+ accent_override: str = "",
400
+ cover_bg_override: str = "",
401
+ ) -> dict:
402
+ palette = PALETTES.get(doc_type, PALETTES["general"]).copy()
403
+ mood = palette["mood"]
404
+ font_pair = FONT_PAIRS.get(mood, SYSTEM_FALLBACK)
405
+
406
+ # Apply caller-supplied overrides before token assembly
407
+ if accent_override:
408
+ palette["accent"] = accent_override
409
+ palette["accent_lt"] = _lighten(accent_override, 0.09)
410
+ if cover_bg_override:
411
+ palette["cover_bg"] = cover_bg_override
412
+
413
+ # ── Font Vietnamese Support (Detect System Fonts) ────────────────────────
414
+ # Standard PDF fonts (Helvetica/Times) do not support Vietnamese characters.
415
+ # We try to find a system TTF font that typically supports Vietnamese.
416
+ import os
417
+ font_paths = {}
418
+ vn_body_font = font_pair["body_rl"]
419
+ vn_body_b_font = font_pair["body_b_rl"]
420
+
421
+ # Try standard Mac/Linux paths for Arial or similar
422
+ possible_paths = [
423
+ # Mac
424
+ "/System/Library/Fonts/Supplemental/Arial.ttf",
425
+ "/System/Library/Fonts/Supplemental/Arial Bold.ttf",
426
+ "/Library/Fonts/Arial.ttf",
427
+ # Windows (if ever used)
428
+ "C:\\Windows\\Fonts\\arial.ttf",
429
+ "C:\\Windows\\Fonts\\arialbd.ttf",
430
+ # Linux
431
+ "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
432
+ "/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf",
433
+ ]
434
+
435
+ found_regular = None
436
+ found_bold = None
437
+ for p in possible_paths:
438
+ if os.path.exists(p):
439
+ if "Bold" in p or "arialbd" in p:
440
+ if not found_bold: found_bold = p
441
+ else:
442
+ if not found_regular: found_regular = p
443
+
444
+ if found_regular:
445
+ font_paths["VNSans"] = found_regular
446
+ vn_body_font = "VNSans"
447
+ if found_bold:
448
+ font_paths["VNSans-Bold"] = found_bold
449
+ vn_body_b_font = "VNSans-Bold"
450
+
451
+ tokens = {
452
+ # Identity
453
+ "title": title,
454
+ "author": author,
455
+ "date": date,
456
+ "doc_type": doc_type,
457
+
458
+ # Palette
459
+ "cover_bg": palette["cover_bg"],
460
+ "accent": palette["accent"],
461
+ "accent_lt": palette["accent_lt"],
462
+ "text_light": palette["text_light"],
463
+ "page_bg": palette["page_bg"],
464
+ "dark": palette["dark"],
465
+ "body_text": palette["body_text"],
466
+ "muted": palette["muted"],
467
+ "cover_pattern": palette["cover_pattern"],
468
+ "mood": mood,
469
+
470
+ # Typography — CSS names for cover HTML (loaded via Google Fonts @import)
471
+ "font_display": font_pair["display_css"],
472
+ "font_body": font_pair["body_css"],
473
+ "gfonts_import": font_pair["gfonts_import"],
474
+
475
+ # Typography — ReportLab system font names for body pages
476
+ "font_display_rl": vn_body_font,
477
+ "font_body_rl": vn_body_font,
478
+ "font_body_b_rl": vn_body_b_font,
479
+
480
+ # Legacy keys (kept so render_body.py's register_fonts is a no-op)
481
+ "font_heading": vn_body_font,
482
+ "font_body_b": vn_body_b_font,
483
+ "font_paths": font_paths,
484
+
485
+ # Type scale (pt)
486
+ "size_display": 54,
487
+ "size_h1": 22,
488
+ "size_h2": 15,
489
+ "size_h3": 11.5,
490
+ "size_body": 10.5,
491
+ "size_caption": 8.5,
492
+ "size_meta": 8,
493
+
494
+ # Layout (pt, 1cm ≈ 28.35pt)
495
+ "margin_left": 79, # 2.8cm
496
+ "margin_right": 79,
497
+ "margin_top": 79,
498
+ "margin_bottom": 71, # 2.5cm
499
+ "section_gap": 26,
500
+ "para_gap": 8,
501
+ "line_gap": 17,
502
+ }
503
+ return tokens
504
+
505
+
506
+ # ── CLI ───────────────────────────────────────────────────────────────────────
507
+ def main():
508
+ parser = argparse.ArgumentParser(description="Generate design tokens from document metadata")
509
+ parser.add_argument("--title", default="Untitled Document")
510
+ parser.add_argument("--type", default="general",
511
+ choices=list(PALETTES.keys()),
512
+ help="Document type: " + ", ".join(PALETTES.keys()))
513
+ parser.add_argument("--author", default="")
514
+ parser.add_argument("--date", default="")
515
+ parser.add_argument("--meta", help="JSON file with title/type/author/date keys")
516
+ parser.add_argument("--accent", default="",
517
+ help="Override accent colour (hex, e.g. #2D6A8F). "
518
+ "accent_lt is auto-derived by lightening toward white.")
519
+ parser.add_argument("--cover-bg", default="",
520
+ help="Override cover background colour (hex).")
521
+ parser.add_argument("--out", default="tokens.json")
522
+ args = parser.parse_args()
523
+
524
+ if args.meta:
525
+ try:
526
+ with open(args.meta) as f:
527
+ meta = json.load(f)
528
+ args.title = meta.get("title", args.title)
529
+ args.type = meta.get("type", args.type)
530
+ args.author = meta.get("author", args.author)
531
+ args.date = meta.get("date", args.date)
532
+ except Exception as e:
533
+ print(json.dumps({"status": "error", "error": str(e)}), file=sys.stderr)
534
+ sys.exit(1)
535
+
536
+ tokens = build_tokens(
537
+ args.title, args.type, args.author, args.date,
538
+ accent_override=args.accent,
539
+ cover_bg_override=getattr(args, "cover_bg", ""),
540
+ )
541
+
542
+ try:
543
+ with open(args.out, "w") as f:
544
+ json.dump(tokens, f, indent=2)
545
+ except Exception as e:
546
+ print(json.dumps({"status": "error", "error": str(e)}), file=sys.stderr)
547
+ sys.exit(3)
548
+
549
+ print(json.dumps({
550
+ "status": "ok",
551
+ "out": args.out,
552
+ "mood": tokens["mood"],
553
+ "pattern": tokens["cover_pattern"],
554
+ "fonts": f'{tokens["font_display"]} / {tokens["font_body"]}',
555
+ }))
556
+
557
+
558
+ if __name__ == "__main__":
559
+ main()