agentman-docx-style

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.

designv2.0.07 views8 uses
docxdocx-jsjavascriptwordbrand-guidelinesdesign-systemagentmanequity-research

Skill Instructions

# 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

Included Files

  • SKILL.md(13.3 KB)
  • _archive/skill-package.zip(12.9 KB)

Ready to use this skill?

Try it now in your favorite AI, or set up MCP for persistent access.