From d0be7a68be8b63a2ce1efff02ffdff70e94c718c Mon Sep 17 00:00:00 2001 From: Hugo Palma <45242291+hugopalma17@users.noreply.github.com> Date: Tue, 10 Mar 2026 21:46:16 -0300 Subject: [PATCH] =?UTF-8?q?Add=20sspdf=20partner-built=20plugin=20?= =?UTF-8?q?=E2=80=94=20PDF=20document=20generation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PDF generation plugin for reports, tear sheets, invoices, and branded deliverables. Renders directly via jsPDF with deterministic math-first layout — no LibreOffice, no headless browsers. Includes 2 skills (document generation, theme creation), 2 commands (/generate-pdf, /create-theme), native tables with page-break header repetition, and embedded chart rendering. --- .../sspdf/.claude-plugin/plugin.json | 11 + partner-built/sspdf/README.md | 73 +++++++ partner-built/sspdf/commands/create-theme.md | 49 +++++ partner-built/sspdf/commands/generate-pdf.md | 52 +++++ .../skills/sspdf-theme-generator/SKILL.md | 147 ++++++++++++++ partner-built/sspdf/skills/sspdf/SKILL.md | 192 ++++++++++++++++++ 6 files changed, 524 insertions(+) create mode 100644 partner-built/sspdf/.claude-plugin/plugin.json create mode 100644 partner-built/sspdf/README.md create mode 100644 partner-built/sspdf/commands/create-theme.md create mode 100644 partner-built/sspdf/commands/generate-pdf.md create mode 100644 partner-built/sspdf/skills/sspdf-theme-generator/SKILL.md create mode 100644 partner-built/sspdf/skills/sspdf/SKILL.md diff --git a/partner-built/sspdf/.claude-plugin/plugin.json b/partner-built/sspdf/.claude-plugin/plugin.json new file mode 100644 index 00000000..5d1ee79b --- /dev/null +++ b/partner-built/sspdf/.claude-plugin/plugin.json @@ -0,0 +1,11 @@ +{ + "name": "sspdf", + "version": "1.0.0", + "description": "Generate publication-ready PDF documents — financial reports, tear sheets, invoices, and branded deliverables — directly from Claude with deterministic, math-first rendering. No LibreOffice, no browser, no pixel nudging.", + "author": { + "name": "Hugo Palma" + }, + "repository": "https://github.com/hugopalma17/sspdf", + "license": "Apache-2.0", + "keywords": ["pdf", "document-generation", "financial-reports", "invoices", "charts", "tables"] +} \ No newline at end of file diff --git a/partner-built/sspdf/README.md b/partner-built/sspdf/README.md new file mode 100644 index 00000000..1773d186 --- /dev/null +++ b/partner-built/sspdf/README.md @@ -0,0 +1,73 @@ +# sspdf — PDF Generation Plugin + +Generate publication-ready PDF documents directly from Claude — financial reports, tear sheets, invoices, articles, and branded deliverables — with deterministic, math-first rendering. + +## What This Plugin Does + +This plugin gives Claude the ability to produce PDF documents from natural language descriptions. Instead of generating HTML and converting it, or relying on LibreOffice, sspdf renders PDFs directly via jsPDF with precise mathematical layout. The output is deterministic: same input, same PDF, every time. + +The engine separates content from styling completely. A **source** JSON describes what to render (text, tables, charts, dividers, blocks). A **theme** JS file controls how it looks (fonts, colors, spacing, page geometry). Claude builds both from a description and renders the final PDF. + +## Skills + +| Skill | What It Does | +|-------|-------------| +| `sspdf` | Builds source JSON and renders PDF documents. Knows all operation types (text, tables, charts, rows, bullets, blocks, quotes, dividers) and the complete rendering pipeline. | +| `sspdf-theme-generator` | Creates custom theme files from brand specs. Knows the full label property schema — page config, text styling, spacing, containers, table formatting, dividers. | + +## Commands + +| Command | Description | +|---------|-------------| +| `/generate-pdf` | Generate a PDF from a natural language description | +| `/create-theme` | Create a custom theme from brand specifications | + +## What It Can Render + +- **Text** — wrapped paragraphs, headings, captions with full font/style control +- **Tables** — column alignment, alternating row shading, borders, header repetition on page breaks +- **Charts** — bar, line, pie, stacked bar, grouped bar — rendered as embedded images via canvas +- **Rows** — left/right aligned pairs (ideal for invoice line items, key-value data) +- **Blocks** — grouped content with background, border, and keep-together pagination +- **Quotes** — blockquotes with optional attribution +- **Bullets** — custom markers with wrapped text +- **Page templates** — repeating headers and footers with `{{page}}` token +- **Hidden text** — invisible text layer for ATS keyword injection + +Built-in themes: `default`, `editorial`, `newsprint`, `corporate`, `ceremony`, `program`, `financial`. + +## Installation + +```bash +npm install h17-sspdf +``` + +Requires Node.js and the `canvas` native addon (automatically installed as a dependency). + +## Quick Start + +```bash +# CLI +npx h17-sspdf -s source.json -t financial -o output/report.pdf + +# Programmatic +const { renderDocument } = require("h17-sspdf"); +renderDocument({ source, theme, outputPath: "output/report.pdf" }); +``` + +## Why sspdf + +- **No LibreOffice** — Renders PDFs directly via jsPDF. No headless browsers, no OS-level dependencies beyond Node.js. +- **Deterministic** — Math-first layout engine. Same input produces identical output on any machine. +- **Charts and tables out of the box** — Native table operation with page-break header repetition. Chart plugin renders bar, line, pie charts as embedded images. +- **Content/style separation** — Source JSON never contains colors, fonts, or sizes. The theme controls all visual decisions. Swap themes without touching content. +- **Pagination built in** — Automatic page breaks, keep-together blocks, orphan prevention, header/footer templates. + +## Requirements + +- Node.js 18+ +- npm (for h17-sspdf package installation) + +## License + +[Apache License 2.0](../../LICENSE) diff --git a/partner-built/sspdf/commands/create-theme.md b/partner-built/sspdf/commands/create-theme.md new file mode 100644 index 00000000..c033f348 --- /dev/null +++ b/partner-built/sspdf/commands/create-theme.md @@ -0,0 +1,49 @@ +--- +description: Create a custom sspdf theme from brand specs — colors, fonts, and document type +argument-hint: " (e.g. 'navy headers, Helvetica, financial tear sheet')" +--- + +# Create Theme + +> This command uses the sspdf engine (`h17-sspdf` npm package). See the **sspdf-theme-generator** skill for the full property reference. + +Create a custom theme file for the sspdf PDF engine from brand specifications. + +## Workflow + +### 1. Gather Brand Specs + +Ask the user for: +- Primary and accent colors +- Font preferences (built-in: helvetica, courier, times — or TTF for custom) +- Document type the theme targets +- Any reference materials or existing brand guidelines + +### 2. Read Documentation + +```bash +SSPDF_DIR=$(node -e "console.log(require.resolve('h17-sspdf').replace('/index.js',''))") +cat $SSPDF_DIR/DOCUMENTATION.md +``` + +Read the Theme section for the complete property reference. + +### 3. Study Existing Themes + +```bash +ls $SSPDF_DIR/examples/themes/ +``` + +Read at least one theme to match conventions. + +### 4. Generate Theme + +Write a `.js` file exporting a valid theme object with all required labels fully specified. See the **sspdf-theme-generator** skill for the schema, rules, and label property reference. + +### 5. Test Render + +If the user has a source JSON ready: + +```bash +npx h17-sspdf -s -t -o output/test.pdf +``` diff --git a/partner-built/sspdf/commands/generate-pdf.md b/partner-built/sspdf/commands/generate-pdf.md new file mode 100644 index 00000000..5acd1978 --- /dev/null +++ b/partner-built/sspdf/commands/generate-pdf.md @@ -0,0 +1,52 @@ +--- +description: Generate a PDF document from a description — invoices, reports, tear sheets, articles, or any printable deliverable +argument-hint: " (e.g. 'quarterly earnings summary for AAPL', 'invoice for $7,250')" +--- + +# Generate PDF + +> This command uses the sspdf engine (`h17-sspdf` npm package) to render PDF documents. No external dependencies beyond Node.js and the canvas native addon. + +Generate a publication-ready PDF from a natural language description. Builds the source JSON, selects or creates a theme, and renders the output. + +See the **sspdf** skill for the full operation reference and rendering workflow. + +## Workflow + +### 1. Determine the Document + +Ask the user what they need if not already clear from the argument. Identify: +- Document type (report, invoice, tear sheet, article, program, etc.) +- Content to include +- Any brand preferences (colors, fonts) + +### 2. Read Documentation + +```bash +SSPDF_DIR=$(node -e "console.log(require.resolve('h17-sspdf').replace('/index.js',''))") +cat $SSPDF_DIR/DOCUMENTATION.md +``` + +### 3. Select or Create Theme + +Check built-in themes: `default`, `editorial`, `newsprint`, `corporate`, `ceremony`, `program`, `financial`. + +```bash +ls $SSPDF_DIR/examples/themes/ +``` + +If none fits, create a custom theme using the **sspdf-theme-generator** skill. + +### 4. Build Source JSON + +Construct the source JSON with operations matching the document structure. Every label must exist in the chosen theme. + +### 5. Render + +```bash +npx h17-sspdf -s -t -o output/.pdf +``` + +### 6. Verify + +Confirm the PDF exists and open it for the user. diff --git a/partner-built/sspdf/skills/sspdf-theme-generator/SKILL.md b/partner-built/sspdf/skills/sspdf-theme-generator/SKILL.md new file mode 100644 index 00000000..6d850112 --- /dev/null +++ b/partner-built/sspdf/skills/sspdf-theme-generator/SKILL.md @@ -0,0 +1,147 @@ +--- +name: sspdf-theme-generator +description: Generate custom sspdf theme files from brand specs — colors, fonts, and document type. Use when asked to create a theme, style a document, or design a PDF layout for sspdf. +--- + +# sspdf Theme Generator + +Generate theme files for the sspdf PDF engine. A theme is a JS object that controls every visual decision in a document — page geometry, baseline state, and label styles. Themes produced here work on first render. + +## Setup + +Verify h17-sspdf is installed: + +```bash +npx h17-sspdf --help +``` + +If this fails, install it: + +```bash +npm install h17-sspdf +``` + +## How It Works + +The sspdf engine takes two inputs: a theme (styling rules) and a source (content). The theme controls page geometry, baseline state, and label styles. The source references labels by name. If a label is missing, the engine throws. + +Resolve the package location: + +```bash +SSPDF_DIR=$(node -e "console.log(require.resolve('h17-sspdf').replace('/index.js',''))") +``` + +## Required Reading + +Before generating a theme, always read the documentation: + +```bash +cat $SSPDF_DIR/DOCUMENTATION.md +``` + +Read the full Theme section (page config, labels, customFonts, layout). This is your source of truth for every property name, type, and constraint. + +Also check existing themes for patterns: + +```bash +ls $SSPDF_DIR/examples/themes/ +``` + +Read at least one existing theme to match the project's conventions. + +## Theme Structure + +```js +module.exports = { + name: "Theme Name", + + page: { + format: "a4", // only a4 + orientation: "portrait", // or "landscape" + unit: "mm", // only mm + compress: true, + + // margins + marginTopMm: 20, + marginBottomMm: 20, + marginLeftMm: 18, + marginRightMm: 18, + + // background + backgroundColor: [255, 255, 255], + + // baseline text state (required, every property) + defaultText: { + fontFamily: "helvetica", + fontStyle: "normal", + fontSize: 10, + color: [0, 0, 0], + lineHeight: 1.2, + }, + + // baseline stroke state (required) + defaultStroke: { + color: [0, 0, 0], + lineWidth: 0.2, + lineCap: "butt", + lineJoin: "miter", + }, + + // baseline fill (required) + defaultFillColor: [255, 255, 255], + }, + + labels: { + // every label the source JSON will reference + }, +}; +``` + +## Rules + +1. Every label is self-contained. No inheritance between labels. If a label needs `fontFamily`, write `fontFamily`. +2. Colors are always `[R, G, B]` arrays, 0-255. +3. Only `"a4"` format and `"mm"` units are supported. The engine throws on anything else. +4. The `page` section must include `defaultText`, `defaultStroke`, and `defaultFillColor`, all fully specified. These reset after every operation to prevent style leaks. +5. Label names are arbitrary strings. Use a dot-namespace convention: `invoice.title`, `report.body`, `news.headline`. +6. Built-in font families: `helvetica`, `courier`, `times`. For anything else, embed TTF via `customFonts`. +7. Table labels need `cellPaddingMm`, border properties, and optionally `altRowColor`. Use the shared constants pattern from existing theme files if the document includes tables. +8. Do not hardcode positions or sizes in labels that belong in the source JSON. + +## Label Property Quick Reference + +**Text labels:** `fontFamily`, `fontStyle`, `fontSize`, `color`, `lineHeight`, `lineHeightMm`, `align`, `textTransform` + +**Spacing:** `marginTopMm`, `marginTopPx`, `marginBottomMm`, `marginBottomPx` + +**Padding:** `paddingMm`, `paddingPx`, `paddingTopMm`, `paddingBottomMm`, `paddingLeftMm`, `paddingRightMm` (and Px variants) + +**Container:** `backgroundColor`, `borderWidthMm`, `borderColor`, `borderRadiusMm` + +**Left border accent:** `leftBorder: { color, widthMm, gapMm, heightMm, topOffsetMm }` + +**Divider labels:** `color`, `lineWidth`, `opacity`, `dashPattern`, spacing props + +**Bullet marker:** `fontFamily`, `fontStyle`, `fontSize`, `color`, `lineHeight`, `marker` + +**Spacer labels:** `spaceMm`, `spacePx` + +**Table cell labels:** `fontFamily`, `fontStyle`, `fontSize`, `color`, `lineHeight`, `cellPaddingMm`, `backgroundColor`, `altRowColor`, `borderColor`, `borderTopMm`, `borderBottomMm`, `borderLeftMm`, `borderRightMm`, per-edge color overrides + +## Workflow + +1. Read `DOCUMENTATION.md` for the full property reference. +2. Read at least one existing theme in `examples/themes/` for conventions. +3. Ask the user what document type they need (or infer from context). +4. Identify every visual element the document will have. Each one needs a label. +5. Generate the theme file with all labels fully specified. +6. If the document uses tables, read an existing theme with tables and use the shared constants pattern. +7. Write the file to the specified path. + +## Verification + +If the user has a source JSON ready, render it: + +```bash +npx h17-sspdf -s -t -o output/test.pdf +``` diff --git a/partner-built/sspdf/skills/sspdf/SKILL.md b/partner-built/sspdf/skills/sspdf/SKILL.md new file mode 100644 index 00000000..216b0008 --- /dev/null +++ b/partner-built/sspdf/skills/sspdf/SKILL.md @@ -0,0 +1,192 @@ +--- +name: sspdf +description: Generate PDF documents with the sspdf engine — invoices, reports, tear sheets, articles, and branded deliverables. Use when asked to create, render, or generate a PDF, or any printable document. Deterministic math-first rendering with native tables, charts, and page-break logic. +--- + +# sspdf Document Generator + +Generate PDF documents using the sspdf engine. Build the source JSON, pick or generate the right theme, and render the output. One invoke, one PDF. + +## Setup + +Verify h17-sspdf is installed: + +```bash +npx h17-sspdf --help +``` + +If this fails, install it: + +```bash +npm install h17-sspdf +``` + +The `canvas` npm package (native C++ addon) is the only dependency. If canvas fails to build, the user needs build tools (`python3`, `make`, `g++`/`clang`) and Cairo headers. See the canvas npm page for platform-specific instructions. + +## How It Works + +The sspdf engine takes two inputs: a **theme** (styling) and a **source** (content as JSON). The source contains only content and structural intent — no colors, no sizes, no positions. The theme controls every visual decision via labels. The core does the math. + +Resolve the package location: + +```bash +SSPDF_DIR=$(node -e "console.log(require.resolve('h17-sspdf').replace('/index.js',''))") +``` + +## Required Reading + +Before generating any document, always read the documentation: + +```bash +cat $SSPDF_DIR/DOCUMENTATION.md +``` + +Read the full Source section for operation types, field requirements, and patterns. Read the Theme section if you need to create or modify a theme. + +Check available themes and source examples: + +```bash +ls $SSPDF_DIR/examples/themes/ +ls $SSPDF_DIR/examples/sources/ +``` + +## Operation Types + +- `text` — wrapped text paragraphs (supports string arrays for multiple paragraphs) +- `row` — two values on one line, left-aligned and right-aligned +- `bullet` — marker character + wrapped text (supports arrays) +- `divider` — horizontal line +- `spacer` — vertical space +- `hiddenText` — invisible text for ATS keyword injection +- `quote` — blockquote with optional attribution +- `block` — groups children, optional container background/border, `keepTogether` +- `section` — groups children, allows page breaks inside (keepTogether defaults false) +- `table` — data table with header, per-column alignment, alternating rows, borders +- `chart` — bar, line, pie, stacked bar, grouped bar charts rendered as embedded images + +Read DOCUMENTATION.md for field details on each type. + +## Source JSON Structure + +```json +{ + "pageTemplates": { + "header": [ /* operations */ ], + "footer": [ /* operations */ ], + "headerHeightMm": 12, + "footerHeightMm": 10 + }, + "operations": [ + { "type": "text", "label": "doc.title", "text": "Document Title" }, + { "type": "divider", "label": "doc.rule" }, + { "type": "text", "label": "doc.body", "text": ["Paragraph one.", "Paragraph two."] } + ] +} +``` + +The `{{page}}` token in any text value resolves to the current page number. + +## Table Operations + +Tables are first-class. Define columns with width and alignment, provide rows as string arrays. + +```json +{ + "type": "table", + "label": "report.table.cell", + "headerLabel": "report.table.header", + "columns": [ + { "header": "Item", "width": "50%", "align": "left" }, + { "header": "Amount", "width": "50%", "align": "right" } + ], + "rows": [ + ["Widget A", "$1,200.00"], + ["Widget B", "$800.00"] + ] +} +``` + +Column widths: `"30%"` (percentage), `35` (fixed mm), or omitted (auto-divide). Headers re-draw on page breaks. + +## Rules + +1. Every `label` in the source must exist in the theme. If using an existing theme, read it first to know what labels are available. +2. The source never says how to render. No colors, no sizes, no font names in the JSON. Only content and label references. +3. Use `keepWithNext` on headings to prevent orphaning. Use `block` with `keepTogether` for cards or grouped content. +4. Use `section` for logical grouping without forcing everything onto one page. +5. Prefer text arrays over repeating the same operation for multiple paragraphs. +6. Table `rows` must match `columns` length. Each cell is a string. + +## Workflow + +1. Read `DOCUMENTATION.md` for the full operation reference. +2. Determine what document the user needs. +3. Check `examples/themes/` for an existing theme that fits. If none fits, generate one using the sspdf-theme-generator skill. +4. Build the source JSON with the correct operations and labels. +5. Write the source JSON file. +6. Render the PDF. + +## Rendering + +### CLI (simplest) + +```bash +npx h17-sspdf -s my-source.json -t default -o output/my-doc.pdf +``` + +Built-in themes: `default`, `editorial`, `newsprint`, `corporate`, `ceremony`, `program`, `financial`. + +Custom theme file: + +```bash +npx h17-sspdf -s my-source.json -t ./my-custom-theme.js -o output/custom.pdf +``` + +The CLI auto-detects chart operations and pre-renders them. No extra setup needed. + +### Programmatic + +```js +const { renderDocument } = require("h17-sspdf"); +const theme = require("h17-sspdf/examples/themes/theme-default"); +const source = require("./my-source.json"); + +renderDocument({ source, theme, outputPath: "output/my-doc.pdf" }); +``` + +### With charts (async, programmatic only) + +```js +const { renderDocument, registerPlugin, plugins } = require("h17-sspdf"); + +registerPlugin("chart", plugins.chart); + +async function main() { + const chartOp = { type: "chart", chartType: "bar", data: { ... }, widthMm: 160, heightMm: 90 }; + await plugins.chart.preRender(chartOp); + + renderDocument({ + source: { operations: [ chartOp ] }, + theme, + outputPath: "output/chart.pdf", + }); +} + +main(); +``` + +Note: the CLI handles chart pre-rendering automatically. The programmatic API requires manual pre-rendering. + +## Verification + +After rendering, confirm the PDF exists and open it for the user: + +```bash +ls -la output/my-doc.pdf +open output/my-doc.pdf +``` + +If something fails, check: +- All labels referenced in the source exist in the theme +- Table columns array is non-empty, rows array exists +- h17-sspdf is installed (`npx h17-sspdf --help`)