Agentman brand styling for DOCX report generation using docx-js (JavaScript). Use when generating ANY Word document report. Provides mandatory color constants, table styling helpers, paragraph style builders, and a pre-generation checklist. Ensures every DOCX uses the Agentman warm terracotta/charcoal palette with Inter for headings and Calibri for body text.
# Agentman DOCX Style Guide (JavaScript / docx-js)
## When to Use
Load this skill **before writing any DOCX generation code** using `docx-js`. This skill provides the complete Agentman brand implementation for Word document output.
**The brand identity is quiet confidence** — charcoal suits, not fire trucks. Carbon and warm neutrals do the heavy lifting. Terracotta appears as a rare, deliberate accent.
## STOP — Read Before Writing Any Code
Before writing a SINGLE line of DOCX generation code, you MUST:
1. Define ALL color constants below as the first lines of your script
2. Set document metadata — creator, title, company
3. Display author on page 1 immediately after the report title
4. NEVER let Word default styles bleed through — override every heading, body text, and table style
5. NEVER use default heading colors — Word defaults are blue/black, not Agentman charcoal
6. NEVER use ShadingType.SOLID — always ShadingType.CLEAR to prevent black backgrounds
7. Always use WidthType.DXA — never WidthType.PERCENTAGE (breaks in Google Docs)
8. **Inter for headings and document title. Calibri for everything else.**
## Font Strategy
**Two fonts. One rule: Inter for headings, Calibri for everything else.**
| Font | Elements | Why |
|------|----------|-----|
| **Inter** | Document title, H1, H2, H3 | Geometric, modern — stronger visual anchor; matches brand's editorial posture |
| **Calibri** | Body text, tables, footer, captions, stat blocks | Universally available, renders consistently without embedding |
Inter must be installed on the generating machine or embedded in the output. Download from https://fonts.google.com/specimen/Inter (free, OFL license).
**Never substitute** Inter headings with Calibri, Arial, or Helvetica. If Inter is unavailable, log a warning and fall back to Calibri — do not silently use a different font.
## Visual Weight Distribution
- 70% Carbon/Charcoal (141413, 292322, 3D3735) — the backbone
- 20% Warm Neutrals (F0EEE6, F6EAE6, E3DACC, FAF9F5, FFFFFF) — warmth without color
- 10% Terracotta Accent (CC785C, D97757, A65945) — sparingly, max 3 per section
## Color Constants
```javascript
const fs = require("fs");
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
Header, Footer, AlignmentType, HeadingLevel, BorderStyle, WidthType,
ShadingType, VerticalAlign, PageNumber, PageBreak } = require("docx");
// Font constants
const FONT_HEADING = "Inter"; // H1, H2, H3, document title
const FONT_BODY = "Calibri"; // All other text
// Primary Brand (Terracotta) — use sparingly, max 3 per section
const AGENTMAN_800 = "703B2D"; // Badge text
const AGENTMAN_700 = "8B4A38"; // Cover accent
const AGENTMAN_600 = "A65945"; // Negative emphasis
const AGENTMAN_500 = "CC785C"; // PRIMARY ACCENT — stat numbers, table header text
const AGENTMAN_400 = "D97757"; // Highlight/caution
const AGENTMAN_200 = "E6A890"; // Badge borders
const AGENTMAN_150 = "E3DACC"; // Table borders, separators
const AGENTMAN_100 = "F6EAE6"; // Table header fill
const AGENTMAN_75 = "F0EEE6"; // Highlight row bg, callout blocks
const AGENTMAN_50 = "FAF9F5"; // Alternate row bg (cream)
// Text Colors (Charcoal) — 70% of visual weight
const CHARCOAL_950 = "141413"; // PRIMARY BODY TEXT
const CHARCOAL_900 = "292322"; // Section titles, cover title
const CHARCOAL_800 = "3D3735"; // Secondary text
// Neutral (Slate)
const SLATE_600 = "475569"; // Metric labels
const SLATE_500 = "64748B"; // Footer, muted captions
```
## Standard Borders
```javascript
const BRAND_BORDER = { style: BorderStyle.SINGLE, size: 1, color: AGENTMAN_150 };
const BRAND_BORDERS = { top: BRAND_BORDER, bottom: BRAND_BORDER, left: BRAND_BORDER, right: BRAND_BORDER };
const NO_BORDER = { style: BorderStyle.NONE, size: 0, color: "FFFFFF" };
const NO_BORDERS = { top: NO_BORDER, bottom: NO_BORDER, left: NO_BORDER, right: NO_BORDER };
const TERRACOTTA_BOTTOM_BORDER = { bottom: { style: BorderStyle.SINGLE, size: 6, color: AGENTMAN_500, space: 1 } };
```
## Document Setup
```javascript
const PAGE_WIDTH = 12240; // 8.5in DXA (CRITICAL: docx-js defaults to A4)
const PAGE_HEIGHT = 15840; // 11in DXA
const PAGE_MARGIN = 1080; // 0.75in
const CONTENT_WIDTH = PAGE_WIDTH - (PAGE_MARGIN * 2); // 10080
function createAgentmanDoc(reportTitle, sections) {
return new Document({
creator: "Agentman Equity Research Assistant",
title: `Agentman — ${reportTitle}`,
company: "Agentman (Chain of Agents, Inc.)",
styles: {
default: { document: { run: { font: FONT_BODY, size: 22, color: CHARCOAL_950 } } },
paragraphStyles: [
{ id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal", quickFormat: true,
run: { size: 48, bold: true, font: FONT_HEADING, color: CHARCOAL_900 },
paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0 } },
{ id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal", quickFormat: true,
run: { size: 36, bold: true, font: FONT_HEADING, color: CHARCOAL_900 },
paragraph: { spacing: { before: 180, after: 180 }, outlineLevel: 1 } },
{ id: "Heading3", name: "Heading 3", basedOn: "Normal", next: "Normal", quickFormat: true,
run: { size: 28, bold: true, font: FONT_HEADING, color: CHARCOAL_900 },
paragraph: { spacing: { before: 120, after: 120 }, outlineLevel: 2 } },
],
},
sections,
});
}
const SECTION_PROPS = {
page: { size: { width: PAGE_WIDTH, height: PAGE_HEIGHT },
margin: { top: PAGE_MARGIN, bottom: PAGE_MARGIN, left: PAGE_MARGIN, right: PAGE_MARGIN } },
};
```
## Cover Page
```javascript
function buildCoverPage(reportTitle, dateStr, subtitle) {
const today = dateStr || new Date().toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" });
const children = [
new Paragraph({ heading: HeadingLevel.HEADING_1, children: [
new TextRun({ text: `Agentman — ${reportTitle}`, font: FONT_HEADING, bold: true, size: 48, color: CHARCOAL_900 })
]}),
];
if (subtitle) children.push(new Paragraph({ spacing: { before: 40, after: 120 }, children: [
new TextRun({ text: subtitle, font: FONT_BODY, size: 26, color: SLATE_600 })
]}));
children.push(
new Paragraph({ spacing: { after: 60 }, children: [
new TextRun({ text: "Author: Agentman Equity Research Assistant", font: FONT_BODY, size: 22, color: SLATE_600 })
]}),
new Paragraph({ spacing: { after: 200 }, children: [
new TextRun({ text: `${today} | Data Source: Financial Modeling Prep`, font: FONT_BODY, size: 22, color: SLATE_600 })
]}),
terracottaRule()
);
return children;
}
```
## Helper Functions
```javascript
function terracottaRule(thickness = 18) {
return new Paragraph({ spacing: { before: 60, after: 120 }, border: { bottom: { style: BorderStyle.SINGLE, size: thickness, color: AGENTMAN_500, space: 1 } }, children: [] });
}
function sectionHeading(text, level = HeadingLevel.HEADING_2) {
return new Paragraph({ heading: level, border: TERRACOTTA_BOTTOM_BORDER, spacing: { before: 240, after: 120 }, children: [
new TextRun({ text, font: FONT_HEADING, bold: true, size: level === HeadingLevel.HEADING_2 ? 36 : 28, color: CHARCOAL_900 })
]});
}
function bodyText(text) { return new Paragraph({ spacing: { after: 120 }, children: [new TextRun({ text, font: FONT_BODY, size: 22, color: CHARCOAL_950 })] }); }
function secondaryText(text) { return new Paragraph({ spacing: { after: 80 }, children: [new TextRun({ text, font: FONT_BODY, size: 20, color: SLATE_600 })] }); }
```
## Table Styling
```javascript
function agentmanTable(headers, data, colWidths) {
const numCols = headers.length;
if (!colWidths) { const w = Math.floor(CONTENT_WIDTH / numCols); colWidths = Array(numCols).fill(w); colWidths[numCols - 1] = CONTENT_WIDTH - w * (numCols - 1); }
const cm = { top: 80, bottom: 80, left: 120, right: 120 };
const headerRow = new TableRow({ children: headers.map((h, i) => new TableCell({
borders: BRAND_BORDERS, width: { size: colWidths[i], type: WidthType.DXA },
shading: { fill: AGENTMAN_100, type: ShadingType.CLEAR }, margins: cm, verticalAlign: VerticalAlign.CENTER,
children: [new Paragraph({ alignment: AlignmentType.CENTER, children: [
new TextRun({ text: h, font: FONT_BODY, bold: true, size: 22, color: AGENTMAN_500 })
]})]
}))});
const bodyRows = data.map((row, ri) => new TableRow({ children: row.map((cell, ci) => new TableCell({
borders: BRAND_BORDERS, width: { size: colWidths[ci], type: WidthType.DXA },
shading: { fill: ri % 2 === 0 ? "FFFFFF" : AGENTMAN_50, type: ShadingType.CLEAR },
margins: cm, verticalAlign: VerticalAlign.CENTER,
children: [new Paragraph({ alignment: ci === 0 ? AlignmentType.LEFT : AlignmentType.CENTER, children: [
new TextRun({ text: String(cell), font: FONT_BODY, bold: ci === 0, size: 20, color: CHARCOAL_950 })
]})]
}))}));
return new Table({ width: { size: CONTENT_WIDTH, type: WidthType.DXA }, columnWidths: colWidths, rows: [headerRow, ...bodyRows] });
}
```
## Stat Block Layout (MANDATORY — Prevents Overlap)
CRITICAL: Never use stacked paragraphs for stat blocks. Always use a Table.
```javascript
function statRow(statPairs) {
const n = statPairs.length;
const colW = Math.floor(CONTENT_WIDTH / n);
const colWidths = Array(n).fill(colW);
colWidths[n - 1] = CONTENT_WIDTH - colW * (n - 1);
const numberRow = new TableRow({ children: statPairs.map(([value], i) => new TableCell({
borders: NO_BORDERS, width: { size: colWidths[i], type: WidthType.DXA }, verticalAlign: VerticalAlign.CENTER,
children: [new Paragraph({ alignment: AlignmentType.CENTER, spacing: { before: 100, after: 20 }, children: [
new TextRun({ text: value, font: FONT_BODY, bold: true, size: 56, color: AGENTMAN_500 })
]})]
}))});
const labelRow = new TableRow({ children: statPairs.map(([, label], i) => new TableCell({
borders: NO_BORDERS, width: { size: colWidths[i], type: WidthType.DXA }, verticalAlign: VerticalAlign.CENTER,
children: [new Paragraph({ alignment: AlignmentType.CENTER, spacing: { before: 0, after: 100 }, children: [
new TextRun({ text: label, font: FONT_BODY, size: 20, color: SLATE_600 })
]})]
}))});
return new Table({ width: { size: CONTENT_WIDTH, type: WidthType.DXA }, columnWidths: colWidths, rows: [numberRow, labelRow] });
}
```
## Callout Block
```javascript
function calloutBlock(heading, body) {
return new Table({ width: { size: CONTENT_WIDTH, type: WidthType.DXA }, columnWidths: [CONTENT_WIDTH],
rows: [new TableRow({ children: [new TableCell({
borders: BRAND_BORDERS, width: { size: CONTENT_WIDTH, type: WidthType.DXA },
shading: { fill: AGENTMAN_75, type: ShadingType.CLEAR }, margins: { top: 120, bottom: 120, left: 200, right: 200 },
children: [
new Paragraph({ children: [new TextRun({ text: heading, font: FONT_BODY, bold: true, size: 24, color: CHARCOAL_950 })] }),
new Paragraph({ spacing: { before: 60 }, children: [new TextRun({ text: body, font: FONT_BODY, size: 20, color: SLATE_600 })] }),
]
})]})],
});
}
```
## Footer and Disclaimer
```javascript
function agentmanFooter(dateStr) {
const today = dateStr || new Date().toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" });
return new Footer({ children: [new Paragraph({
border: { top: { style: BorderStyle.SINGLE, size: 3, color: AGENTMAN_500, space: 4 } },
alignment: AlignmentType.CENTER, children: [
new TextRun({ text: `Agentman Equity Research Assistant · ${today} · Data: FMP `, font: FONT_BODY, size: 16, color: SLATE_500 }),
new TextRun({ children: ["Page ", PageNumber.CURRENT], font: FONT_BODY, size: 16, color: SLATE_500 }),
]
})]});
}
function disclaimer() {
return [ new Paragraph({ children: [] }), terracottaRule(6),
new Paragraph({ alignment: AlignmentType.CENTER, children: [new TextRun({
text: "This Agentman research report is for informational purposes only and does not constitute personalized investment advice. Prepared by Agentman Equity Research Assistant.",
font: FONT_BODY, size: 16, italics: true, color: SLATE_500 })]})
];
}
```
## Key Rules
1. Stat blocks MUST use statRow() table layout — never stacked paragraphs
2. Always ShadingType.CLEAR — never ShadingType.SOLID
3. Always WidthType.DXA — never WidthType.PERCENTAGE
4. Set both columnWidths on Table AND width on each TableCell
5. Page size US Letter: width 12240, height 15840
6. Title must start with "Agentman —"
7. Terracotta budget: max 3 per section
8. **Inter (`FONT_HEADING`) on all headings (H1, H2, H3) and document title**
9. **Calibri (`FONT_BODY`) on ALL other TextRuns — body, tables, footer, stat blocks, captions**
10. Visual weight: 70% charcoal, 20% neutrals, 10% terracotta
11. Banned colors: green, amber, red, blue, navy, pure black, Word default blue, generic grays, gradients
Agentman brand styling for Markdown documents. Use when generating any .md file intended for rendered output (HTML, PDF, docs site, or Claude artifact). Provides structure conventions for raw Markdown
Agentman brand styling for PDF report generation. Use when generating ANY PDF report using reportlab, fpdf2, or weasyprint. Provides mandatory color constants, table styles, document setup, typography, page layout, and a pre-generation checklist. Ensures every PDF uses the Agentman warm terracotta/charcoal palette instead of generic library defaults. Load this skill BEFORE writing any PDF generation code.
PPTX-specific implementation reference for creating Agentman-branded presentations using pptxgenjs. Use when building any PowerPoint deck for Agentman or its clients. Provides slide layouts, typography mapping, card patterns, icon rendering, graphic generation prompts, and narrative structure specific to the presentation format. Requires agentman-styleguide as the canonical source for colors, voice/tone, and brand principles.
Try it now in your favorite AI, or set up MCP for persistent access.
Try Now
Or Set Up MCP