@heylemon/lemonade 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/package.json +1 -1
- package/skills/docx/SKILL.md +595 -22
- package/skills/docx/references/templates.md +669 -33
- package/skills/docx/scripts/create_doc.py +289 -52
- package/skills/docx/scripts/validate.py +237 -0
- package/skills/docx/scripts/validate_doc.py +103 -22
- package/skills/pptx/SKILL.md +169 -12
- package/skills/pptx/editing.md +270 -0
- package/skills/pptx/pptxgenjs.md +624 -0
- package/skills/pptx/references/spec-format.md +106 -31
- package/skills/pptx/scripts/create_pptx.js +419 -186
- package/skills/xlsx/SKILL.md +502 -14
- package/skills/xlsx/references/spec-format.md +238 -40
- package/skills/xlsx/scripts/create_xlsx.py +130 -54
- package/skills/xlsx/scripts/recalc.py +157 -147
- package/skills/xlsx/scripts/validate_xlsx.py +31 -6
package/dist/build-info.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
3c0c2fd2a7ea5c555231422230609ed18d2ba0fc3505ef930a0a92cb6a91760e
|
package/package.json
CHANGED
package/skills/docx/SKILL.md
CHANGED
|
@@ -1,37 +1,610 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
3
|
-
description: "Create professional, polished
|
|
4
|
-
license: Proprietary. LICENSE.txt has complete terms
|
|
2
|
+
name: pro-docs
|
|
3
|
+
description: "Create professional, polished documents — reports, memos, proposals, briefs, and letters — with consistent formatting, proper typography, and clear structure. Use this skill whenever the user wants to create a document, report, memo, proposal, brief, letter, write-up, analysis, or any structured written deliverable. Also trigger when someone says 'write me a report', 'create a document', 'draft a memo', 'make this look professional', or needs any written output that should look polished and ready to share with stakeholders."
|
|
5
4
|
---
|
|
6
5
|
|
|
7
|
-
# Pro Docs
|
|
6
|
+
# Pro Docs — Professional Document Creation
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
Create polished, production-ready documents using docx-js, the clean standards-compliant Node.js library for producing .docx files. This skill writes bespoke code for each request rather than using JSON templates — you have full control over the document API.
|
|
10
9
|
|
|
11
|
-
##
|
|
10
|
+
## Quick Reference
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
| Task | Approach | Tool |
|
|
13
|
+
|------|----------|------|
|
|
14
|
+
| **Create new document** | Write docx-js code using Document, Packer, Paragraph, TextRun, Table | Node.js + docx-js |
|
|
15
|
+
| **Read/analyze existing** | Unzip → read document.xml or use pandoc for content extraction | unzip or pandoc |
|
|
16
|
+
| **Edit existing file** | Unzip → modify XML → repack into .docx | unzip + JSZip |
|
|
17
|
+
| **Validate output** | Check XML, fonts, structure, paragraphs | `python scripts/validate.py` |
|
|
18
|
+
| **Visual QA** | Convert to PDF then to images | soffice + pdftoppm |
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Creating New Documents with docx-js
|
|
23
|
+
|
|
24
|
+
### Setup & Imports
|
|
25
|
+
|
|
26
|
+
```javascript
|
|
27
|
+
const { Document, Packer, Paragraph, TextRun, Table, TableCell, WidthType,
|
|
28
|
+
BorderStyle, UnderlineType, PageBreak, Header, Footer } = require("docx");
|
|
29
|
+
const fs = require("fs");
|
|
30
|
+
|
|
31
|
+
// Create a new document
|
|
32
|
+
const doc = new Document({
|
|
33
|
+
sections: [
|
|
34
|
+
{
|
|
35
|
+
children: [
|
|
36
|
+
// Add paragraphs, tables, etc. here
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Write to file
|
|
43
|
+
Packer.toBuffer(doc).then(buffer => {
|
|
44
|
+
fs.writeFileSync("output.docx", buffer);
|
|
45
|
+
console.log("Document created: output.docx");
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Page Size & Margins
|
|
50
|
+
|
|
51
|
+
Use US Letter (8.5 x 11 inches). docx-js works in **DXA units** (twentieths of a point):
|
|
52
|
+
- 1 inch = 1440 DXA
|
|
53
|
+
- US Letter = 12240 x 15840 DXA
|
|
54
|
+
- Standard margins: 1 inch (1440 DXA) on sides, 0.8 inches (1152 DXA) top/bottom
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
const doc = new Document({
|
|
58
|
+
sections: [
|
|
59
|
+
{
|
|
60
|
+
properties: {
|
|
61
|
+
page: {
|
|
62
|
+
margins: {
|
|
63
|
+
top: 1152, // 0.8 inches
|
|
64
|
+
bottom: 1152,
|
|
65
|
+
left: 1440, // 1 inch
|
|
66
|
+
right: 1440
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
children: [ /* content */ ]
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
For landscape, swap width/height but pass the document normally — docx-js handles orientation internally.
|
|
77
|
+
|
|
78
|
+
### Typography Scale
|
|
79
|
+
|
|
80
|
+
Establish a consistent hierarchy. All sizes in half-points (pt * 2):
|
|
81
|
+
|
|
82
|
+
```javascript
|
|
83
|
+
const TYPOGRAPHY = {
|
|
84
|
+
title: 52, // 26pt — document title
|
|
85
|
+
subtitle: 28, // 14pt — subtitle
|
|
86
|
+
h1: 36, // 18pt — major sections
|
|
87
|
+
h2: 28, // 14pt — subsections
|
|
88
|
+
h3: 24, // 12pt — sub-subsections
|
|
89
|
+
body: 22, // 11pt — normal text
|
|
90
|
+
small: 18, // 9pt — captions, footers
|
|
91
|
+
caption: 16 // 8pt — figure captions
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const COLORS = {
|
|
95
|
+
primary: "1B3A5C", // Dark navy for headings
|
|
96
|
+
accent: "2E86AB", // Teal for highlights
|
|
97
|
+
lightAccent: "E8F4F8", // Light teal for backgrounds
|
|
98
|
+
text: "2C3E50", // Dark gray for body
|
|
99
|
+
muted: "7F8C8D" // Light gray for secondary text
|
|
100
|
+
};
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Creating Headings with Styles
|
|
104
|
+
|
|
105
|
+
Override built-in heading styles to ensure they appear in TOC. Use `outlineLevel` to control Table of Contents depth:
|
|
106
|
+
|
|
107
|
+
```javascript
|
|
108
|
+
new Paragraph({
|
|
109
|
+
text: "Section Title",
|
|
110
|
+
heading: HeadingLevel.HEADING_1,
|
|
111
|
+
outlineLevel: 0, // Appears in TOC
|
|
112
|
+
style: "Heading1",
|
|
113
|
+
run: {
|
|
114
|
+
bold: true,
|
|
115
|
+
size: TYPOGRAPHY.h1,
|
|
116
|
+
color: COLORS.primary,
|
|
117
|
+
font: "Arial"
|
|
118
|
+
},
|
|
119
|
+
spacing: { before: 480, after: 160 } // 12pt before, 4pt after
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
new Paragraph({
|
|
123
|
+
text: "Subsection",
|
|
124
|
+
heading: HeadingLevel.HEADING_2,
|
|
125
|
+
outlineLevel: 1,
|
|
126
|
+
style: "Heading2",
|
|
127
|
+
run: { size: TYPOGRAPHY.h2, color: COLORS.primary },
|
|
128
|
+
spacing: { before: 360, after: 120 }
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Lists: Never Use Unicode Bullets
|
|
133
|
+
|
|
134
|
+
CRITICAL: Never manually insert bullet characters like •, ◦, ▪. Use the list APIs:
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
// Bullet list (unordered)
|
|
138
|
+
new Paragraph({
|
|
139
|
+
text: "First bullet point",
|
|
140
|
+
bullet: {
|
|
141
|
+
level: 0
|
|
142
|
+
},
|
|
143
|
+
run: { size: TYPOGRAPHY.body }
|
|
144
|
+
}),
|
|
145
|
+
new Paragraph({
|
|
146
|
+
text: "Second bullet point",
|
|
147
|
+
bullet: { level: 0 },
|
|
148
|
+
run: { size: TYPOGRAPHY.body }
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
// Numbered list
|
|
152
|
+
new Paragraph({
|
|
153
|
+
text: "First step",
|
|
154
|
+
numbering: {
|
|
155
|
+
level: 0,
|
|
156
|
+
instance: 0 // Different instance for each numbered list
|
|
157
|
+
},
|
|
158
|
+
run: { size: TYPOGRAPHY.body }
|
|
159
|
+
}),
|
|
160
|
+
new Paragraph({
|
|
161
|
+
text: "Second step",
|
|
162
|
+
numbering: { level: 0, instance: 0 },
|
|
163
|
+
run: { size: TYPOGRAPHY.body }
|
|
164
|
+
})
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Tables: Dual Width Rules (CRITICAL)
|
|
168
|
+
|
|
169
|
+
Tables MUST specify width in two places. Always use `WidthType.DXA`, never PERCENTAGE:
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
new Table({
|
|
173
|
+
width: {
|
|
174
|
+
size: 100,
|
|
175
|
+
type: WidthType.PERCENTAGE // Table width = 100% of content area
|
|
176
|
+
},
|
|
177
|
+
rows: [
|
|
178
|
+
new TableRow({
|
|
179
|
+
children: [
|
|
180
|
+
new TableCell({
|
|
181
|
+
width: { size: 2000, type: WidthType.DXA }, // Individual cell width in DXA
|
|
182
|
+
children: [ new Paragraph("Header 1") ]
|
|
183
|
+
}),
|
|
184
|
+
new TableCell({
|
|
185
|
+
width: { size: 2500, type: WidthType.DXA },
|
|
186
|
+
children: [ new Paragraph("Header 2") ]
|
|
187
|
+
}),
|
|
188
|
+
new TableCell({
|
|
189
|
+
width: { size: 2000, type: WidthType.DXA },
|
|
190
|
+
children: [ new Paragraph("Header 3") ]
|
|
191
|
+
})
|
|
192
|
+
]
|
|
193
|
+
}),
|
|
194
|
+
// Data rows follow
|
|
195
|
+
new TableRow({
|
|
196
|
+
children: [
|
|
197
|
+
new TableCell({
|
|
198
|
+
width: { size: 2000, type: WidthType.DXA },
|
|
199
|
+
shading: { fill: "E8F4F8", type: ShadingType.CLEAR },
|
|
200
|
+
children: [ new Paragraph("Data 1") ]
|
|
201
|
+
}),
|
|
202
|
+
// ... more cells
|
|
203
|
+
]
|
|
204
|
+
})
|
|
205
|
+
]
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Cell widths must sum to total table width. 6.5 inches of content (8.5 - 2 margins) = ~9360 DXA.
|
|
210
|
+
|
|
211
|
+
### Cell Shading (Background Colors)
|
|
212
|
+
|
|
213
|
+
Use `ShadingType.CLEAR`, never SOLID:
|
|
214
|
+
|
|
215
|
+
```javascript
|
|
216
|
+
new TableCell({
|
|
217
|
+
shading: {
|
|
218
|
+
fill: "1B3A5C", // Hex color
|
|
219
|
+
type: ShadingType.CLEAR // CRITICAL: use CLEAR
|
|
220
|
+
},
|
|
221
|
+
children: [ /* cell content */ ]
|
|
222
|
+
})
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Headers & Footers with Page Numbers
|
|
226
|
+
|
|
227
|
+
```javascript
|
|
228
|
+
const doc = new Document({
|
|
229
|
+
sections: [
|
|
230
|
+
{
|
|
231
|
+
properties: {
|
|
232
|
+
page: { /* margin config */ }
|
|
233
|
+
},
|
|
234
|
+
children: [ /* content */ ],
|
|
235
|
+
header: {
|
|
236
|
+
children: [
|
|
237
|
+
new Paragraph({
|
|
238
|
+
text: "Company Name",
|
|
239
|
+
alignment: AlignmentType.RIGHT,
|
|
240
|
+
run: { size: TYPOGRAPHY.small, color: COLORS.muted }
|
|
241
|
+
})
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
footer: {
|
|
245
|
+
children: [
|
|
246
|
+
new Paragraph({
|
|
247
|
+
text: "Page ",
|
|
248
|
+
alignment: AlignmentType.CENTER,
|
|
249
|
+
children: [
|
|
250
|
+
new PageNumber(), // Inserts page number
|
|
251
|
+
new TextRun(" of "),
|
|
252
|
+
new PageBreakCount()
|
|
253
|
+
]
|
|
254
|
+
})
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
]
|
|
259
|
+
});
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Images (type parameter is REQUIRED)
|
|
263
|
+
|
|
264
|
+
Always include `type` when adding images:
|
|
265
|
+
|
|
266
|
+
```javascript
|
|
267
|
+
new Paragraph({
|
|
268
|
+
children: [
|
|
269
|
+
new ImageRun({
|
|
270
|
+
data: fs.readFileSync("image.png"),
|
|
271
|
+
transformation: {
|
|
272
|
+
width: 400,
|
|
273
|
+
height: 300
|
|
274
|
+
},
|
|
275
|
+
type: "image/png" // CRITICAL: PNG, JPG, GIF, etc.
|
|
276
|
+
})
|
|
277
|
+
]
|
|
278
|
+
})
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Page Breaks (Must Be Inside Paragraph)
|
|
282
|
+
|
|
283
|
+
CRITICAL: PageBreak must always be inside a Paragraph, never standalone:
|
|
284
|
+
|
|
285
|
+
```javascript
|
|
286
|
+
// Correct
|
|
287
|
+
new Paragraph({
|
|
288
|
+
children: [ new PageBreak() ]
|
|
289
|
+
}),
|
|
290
|
+
|
|
291
|
+
// Wrong — this will fail
|
|
292
|
+
new PageBreak()
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Table of Contents
|
|
296
|
+
|
|
297
|
+
docx-js can't generate TOC fields directly, but you can add placeholder text that users update in Word:
|
|
298
|
+
|
|
299
|
+
```javascript
|
|
300
|
+
new Paragraph({
|
|
301
|
+
text: "Table of Contents",
|
|
302
|
+
style: "Heading2",
|
|
303
|
+
run: { bold: true, size: TYPOGRAPHY.h2, color: COLORS.primary }
|
|
304
|
+
}),
|
|
305
|
+
new Paragraph({
|
|
306
|
+
text: "[Right-click to update Table of Contents in Word]",
|
|
307
|
+
run: { italic: true, color: COLORS.muted }
|
|
308
|
+
}),
|
|
309
|
+
new Paragraph({ children: [new PageBreak()] })
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Or use a more sophisticated approach with field codes (requires XML manipulation).
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## Critical Rules for docx-js
|
|
317
|
+
|
|
318
|
+
**DO:**
|
|
319
|
+
- Set page size explicitly (use US Letter dimensions)
|
|
320
|
+
- For landscape: still pass standard margins, docx-js handles rotation
|
|
321
|
+
- Create separate Paragraph objects for each paragraph (never use \n)
|
|
322
|
+
- Use List APIs for bullets/numbers (never hardcode • or -)
|
|
323
|
+
- Always include `type` parameter on ImageRun
|
|
324
|
+
- Set both table width AND individual cell widths in DXA
|
|
325
|
+
- Use `ShadingType.CLEAR` for cell backgrounds
|
|
326
|
+
- Use `HeadingLevel.HEADING_1`, etc., with `outlineLevel` for TOC
|
|
327
|
+
- Override heading styles with explicit `style: "Heading1"` properties
|
|
328
|
+
- Set `spacing.before` and `spacing.after` explicitly on headings
|
|
329
|
+
|
|
330
|
+
**DON'T:**
|
|
331
|
+
- Use newlines (\n) — create separate Paragraphs instead
|
|
332
|
+
- Mix WidthType.PERCENTAGE and WidthType.DXA on different table cells
|
|
333
|
+
- Omit `type` on ImageRun (causes runtime errors)
|
|
334
|
+
- Use unicode bullet characters manually
|
|
335
|
+
- Put PageBreak outside a Paragraph
|
|
336
|
+
- Forget cell width specifications (columns collapse)
|
|
337
|
+
- Use `ShadingType.SOLID` (use CLEAR)
|
|
338
|
+
- Assume A4 page size (always set explicitly to US Letter)
|
|
339
|
+
- Mix font styles — stick to 2 fonts (heading + body)
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Writing Quality Rules
|
|
344
|
+
|
|
345
|
+
Even if the code is perfect, content matters. Follow these principles:
|
|
346
|
+
|
|
347
|
+
### Structure
|
|
348
|
+
- **Answer first, support second.** Executive summaries at the top with conclusions. Don't bury decisions in 10 pages of analysis.
|
|
349
|
+
- **One idea per paragraph.** If you see two points in one paragraph, split them.
|
|
350
|
+
- **Action headings, not topic headings.** Not "Q3 Revenue" but "Q3 Revenue Missed Target by 22%." Headings should complete the thought.
|
|
351
|
+
- **Three key points.** Group arguments into sets of three — it's how working memory works.
|
|
352
|
+
|
|
353
|
+
### Clarity
|
|
354
|
+
- **Short words over long.** Use "help" not "facilitate," "about" not "approximately," "use" not "utilize."
|
|
355
|
+
- **Active voice.** "We recommend" not "it is recommended." "Sales grew" not "growth was achieved."
|
|
356
|
+
- **Quantify.** "43% growth" not "significant growth." "3 weeks" not "soon."
|
|
357
|
+
- **Cut filler.** "In order to" → "to." "At this point in time" → "now." "Due to the fact that" → "because."
|
|
358
|
+
- **No weasel words.** Remove "arguably," "somewhat," "it could be said that."
|
|
359
|
+
|
|
360
|
+
### Tables
|
|
361
|
+
- Use tables for comparisons, timelines, structured data — not for prose.
|
|
362
|
+
- Every table needs clear headers.
|
|
363
|
+
- Keep tables under 7 columns (split wider tables).
|
|
364
|
+
- Include units in headers ("Revenue ($M)") not in every cell.
|
|
365
|
+
|
|
366
|
+
### Callouts
|
|
367
|
+
- Use callouts for key decisions, critical warnings, or bottom-line takeaways.
|
|
368
|
+
- Maximum one per major section — if everything is highlighted, nothing stands out.
|
|
369
|
+
- Format as a highlighted paragraph with accent left border and light background.
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Design Guidance
|
|
374
|
+
|
|
375
|
+
### Color Palettes
|
|
376
|
+
|
|
377
|
+
**Professional (Default):**
|
|
378
|
+
- Primary: #1B3A5C (dark navy)
|
|
379
|
+
- Accent: #2E86AB (teal)
|
|
380
|
+
- Light accent: #E8F4F8 (pale teal)
|
|
381
|
+
- Text: #2C3E50 (charcoal)
|
|
382
|
+
|
|
383
|
+
**Modern Tech:**
|
|
384
|
+
- Primary: #0F3460 (deep blue)
|
|
385
|
+
- Accent: #16213E (dark blue)
|
|
386
|
+
- Light accent: #E0E7FF (pale blue)
|
|
387
|
+
|
|
388
|
+
**Corporate:**
|
|
389
|
+
- Primary: #1a1a2e (very dark blue)
|
|
390
|
+
- Accent: #d62828 (red accent)
|
|
391
|
+
- Light accent: #f7f7f7 (light gray)
|
|
392
|
+
|
|
393
|
+
### Font Pairing
|
|
394
|
+
|
|
395
|
+
Stick to **two fonts maximum**:
|
|
396
|
+
- **Headings & body:** Arial or Calibri (clean, professional)
|
|
397
|
+
- **Luxury documents:** Georgia (headings) + Garamond (body)
|
|
398
|
+
- **Technical:** Consolas or Courier for code samples, Arial for prose
|
|
399
|
+
|
|
400
|
+
Always verify fonts are installed on target systems. Arial and Calibri render everywhere.
|
|
401
|
+
|
|
402
|
+
### When to Use Callouts
|
|
403
|
+
|
|
404
|
+
- Executive summary conclusions
|
|
405
|
+
- Budget figures in proposals
|
|
406
|
+
- Critical deadlines or warnings
|
|
407
|
+
- Key decisions needed from stakeholders
|
|
408
|
+
- Not: every recommendation (overuse kills impact)
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## QA & Validation Process
|
|
413
|
+
|
|
414
|
+
### 1. Create & Validate
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
# Write docx-js code, run it
|
|
418
|
+
node create-report.js
|
|
419
|
+
|
|
420
|
+
# Validate the output
|
|
421
|
+
python scripts/validate.py report.docx
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
The validator checks:
|
|
425
|
+
- XML well-formedness (can be opened in Word)
|
|
426
|
+
- Font consistency (warns if > 3 fonts)
|
|
427
|
+
- Paragraph length (warns if > 500 chars)
|
|
428
|
+
- Empty headings
|
|
429
|
+
- Manual bullet characters (should use List APIs)
|
|
430
|
+
|
|
431
|
+
### 2. Visual Check (PDF Conversion)
|
|
432
|
+
|
|
433
|
+
```bash
|
|
434
|
+
# Convert to PDF
|
|
435
|
+
soffice --headless --convert-to pdf report.docx
|
|
436
|
+
|
|
437
|
+
# Convert to images for inspection (150 DPI, JPEG)
|
|
438
|
+
pdftoppm -jpeg -r 150 report.pdf page
|
|
439
|
+
|
|
440
|
+
# View: page-1.jpg, page-2.jpg, etc.
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### 3. Fix & Re-validate
|
|
444
|
+
|
|
445
|
+
If the validator reports issues or the PDF looks off:
|
|
446
|
+
1. Fix the docx-js code
|
|
447
|
+
2. Re-run to regenerate .docx
|
|
448
|
+
3. Re-validate with `validate.py`
|
|
449
|
+
4. Re-convert to PDF if visual issues
|
|
450
|
+
|
|
451
|
+
Iterate until both validation passes and visual output looks polished.
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## Template Patterns by Document Type
|
|
456
|
+
|
|
457
|
+
### Report Structure (Most Flexible)
|
|
458
|
+
|
|
459
|
+
```javascript
|
|
460
|
+
[
|
|
461
|
+
titleSection(), // Title, date, author
|
|
462
|
+
tocSection(), // Table of Contents
|
|
463
|
+
execSummary(), // 2-3 paragraphs: findings, conclusions, recs upfront
|
|
464
|
+
background(), // Brief context only
|
|
465
|
+
keyFindings(), // 3 major findings with supporting data
|
|
466
|
+
recommendations(), // Numbered action items with owners + timeline
|
|
467
|
+
nextSteps(), // Action table with owners and due dates
|
|
468
|
+
appendices() // Supporting details, raw data
|
|
469
|
+
]
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Memo (1-2 pages max)
|
|
473
|
+
|
|
474
|
+
```javascript
|
|
475
|
+
[
|
|
476
|
+
titleSection(),
|
|
477
|
+
purpose(), // One sentence: why this memo exists
|
|
478
|
+
background(), // 2-3 sentences of context
|
|
479
|
+
recommendation(), // Proposal + rationale + callout with ask
|
|
480
|
+
supportingDetails(), // Evidence
|
|
481
|
+
nextSteps() // Bulleted actions with owners
|
|
482
|
+
]
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### Proposal (Pitch to client)
|
|
486
|
+
|
|
487
|
+
```javascript
|
|
488
|
+
[
|
|
489
|
+
titleSection(), // With client name
|
|
490
|
+
executiveSummary(), // Problem + solution + why us
|
|
491
|
+
understandingChallenge(), // Show you understand their pain
|
|
492
|
+
proposedSolution(), // What you'll do + how it's different
|
|
493
|
+
approachTimeline(), // Table: phases, activities, dates
|
|
494
|
+
investment(), // Pricing table
|
|
495
|
+
whyUs(), // Credentials, relevant projects
|
|
496
|
+
nextSteps() // Call to action
|
|
497
|
+
]
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
### Brief (1-pager)
|
|
501
|
+
|
|
502
|
+
```javascript
|
|
503
|
+
[
|
|
504
|
+
titleSection(),
|
|
505
|
+
objective(), // One sentence
|
|
506
|
+
context(), // 2-3 sentences
|
|
507
|
+
keyPoints(), // Bulleted (3 max)
|
|
508
|
+
constraints(), // Budget, timeline, scope
|
|
509
|
+
successCriteria(), // How we measure success
|
|
510
|
+
decisionNeeded() // Callout: specific ask + deadline
|
|
511
|
+
]
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
---
|
|
515
|
+
|
|
516
|
+
## Common Customizations
|
|
517
|
+
|
|
518
|
+
### Landscape Orientation
|
|
519
|
+
|
|
520
|
+
Swap dimensions but keep same margin structure:
|
|
521
|
+
|
|
522
|
+
```javascript
|
|
523
|
+
const doc = new Document({
|
|
524
|
+
sections: [
|
|
525
|
+
{
|
|
526
|
+
properties: {
|
|
527
|
+
page: {
|
|
528
|
+
// Landscape = wide table spreads, timelines, etc.
|
|
529
|
+
margins: {
|
|
530
|
+
top: 1152, bottom: 1152, left: 1440, right: 1440
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
},
|
|
534
|
+
children: [ /* wide tables */ ]
|
|
535
|
+
}
|
|
536
|
+
]
|
|
537
|
+
});
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### Cover Page
|
|
541
|
+
|
|
542
|
+
Add a dedicated section with large title, logo, date:
|
|
543
|
+
|
|
544
|
+
```javascript
|
|
545
|
+
new Paragraph({
|
|
546
|
+
text: "PROJECT PROPOSAL",
|
|
547
|
+
alignment: AlignmentType.CENTER,
|
|
548
|
+
spacing: { before: 2880, after: 240 }, // 2 inches before
|
|
549
|
+
run: { size: TYPOGRAPHY.title, bold: true, color: COLORS.primary }
|
|
550
|
+
}),
|
|
551
|
+
new Paragraph({
|
|
552
|
+
text: "Prepared for Acme Corp",
|
|
553
|
+
alignment: AlignmentType.CENTER,
|
|
554
|
+
run: { size: TYPOGRAPHY.subtitle, color: COLORS.muted }
|
|
555
|
+
}),
|
|
556
|
+
new Paragraph({ children: [new PageBreak()] })
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### Header with Company Branding
|
|
560
|
+
|
|
561
|
+
```javascript
|
|
562
|
+
section.header = {
|
|
563
|
+
children: [
|
|
564
|
+
new Paragraph({
|
|
565
|
+
text: "Company Name — Confidential",
|
|
566
|
+
alignment: AlignmentType.RIGHT,
|
|
567
|
+
run: { size: TYPOGRAPHY.small, color: COLORS.muted }
|
|
568
|
+
})
|
|
569
|
+
]
|
|
570
|
+
};
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
---
|
|
574
|
+
|
|
575
|
+
## Dependencies
|
|
20
576
|
|
|
21
577
|
```bash
|
|
22
|
-
|
|
23
|
-
|
|
578
|
+
npm install docx
|
|
579
|
+
npm install fs # Built-in Node.js
|
|
24
580
|
```
|
|
25
581
|
|
|
26
|
-
|
|
582
|
+
For validation:
|
|
583
|
+
```bash
|
|
584
|
+
pip install python-docx --break-system-packages # For validate.py
|
|
585
|
+
```
|
|
27
586
|
|
|
587
|
+
For visual QA:
|
|
28
588
|
```bash
|
|
29
|
-
|
|
589
|
+
sudo apt-get install libreoffice poppler-utils # soffice, pdftoppm
|
|
30
590
|
```
|
|
31
591
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
592
|
+
---
|
|
593
|
+
|
|
594
|
+
## Troubleshooting
|
|
595
|
+
|
|
596
|
+
**Document won't open in Word:** XML malformed. Check for unclosed tags, invalid characters. Run `validate.py` to check structure.
|
|
597
|
+
|
|
598
|
+
**Tables look misaligned:** Missing cell widths or inconsistent width types. Ensure every cell has `width: { size: X, type: WidthType.DXA }`.
|
|
599
|
+
|
|
600
|
+
**Page breaks in wrong place:** PageBreak must be inside Paragraph. `new Paragraph({ children: [new PageBreak()] })`.
|
|
601
|
+
|
|
602
|
+
**Fonts not rendering:** Arial/Calibri are safest. If using specialty fonts, ensure they're installed on target system.
|
|
603
|
+
|
|
604
|
+
**TOC not generating:** docx-js doesn't support field codes natively. Use placeholder text or manually update in Word after opening.
|
|
605
|
+
|
|
606
|
+
---
|
|
607
|
+
|
|
608
|
+
## Example: Simple Report
|
|
609
|
+
|
|
610
|
+
See `references/templates.md` for full template examples with code.
|