Create professional, studio-grade PDF documents with bold editorial design quality. Use this skill whenever the user asks for a high-quality PDF, professional book, manual, playbook, report, ebook, whitepaper, or any multi-page document that needs magazine-quality layout. Also trigger when: "make it look professional", "studio grade", "publication quality", "book layout", "editorial design", or any request to transform markdown/text content into a beautifully designed PDF. This skill handles everything from single-page reports to full 300+ page books with cover pages, table of contents, styled code blocks, chapter openers, headers/footers, and custom typography. Do NOT use for simple PDF merging, splitting, or form-filling — those are basic PDF tasks.
77
97%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
This skill creates publication-quality PDF documents using Python's ReportLab library with custom typography, bold editorial design, and professional layout. The output rivals what you'd expect from a professional design studio or publishing house.
What this skill produces:
1. Read this SKILL.md (you're doing it now)
2. Understand the user's content and desired style
3. Install dependencies (see below)
4. Read references/DESIGN-SYSTEM.md for the full design system
5. Use scripts/pdf_builder.py as your base template
6. Customize colors, fonts, and layout to match the request
7. Build the PDF and deliverCRITICAL — Install these FIRST before any PDF generation:
pip install reportlab --break-system-packagesReportLab is the only required dependency. It's pre-installed in most environments but always verify.
Optional (for reading existing PDFs or advanced features):
pip install pypdf pdfplumber --break-system-packagesThis skill bundles professional fonts in assets/fonts/. The core font stack is:
| Role | Font | Fallback |
|---|---|---|
| Display / Headings | BigShoulders-Bold | Helvetica-Bold |
| Body Text | Lora (Regular/Bold/Italic) | Times-Roman |
| UI / Labels | InstrumentSans (Regular/Bold/Italic) | Helvetica |
| Code | JetBrainsMono (Regular/Bold) | Courier |
Font Registration Pattern:
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfbase.pdfmetrics import registerFontFamily
FONT_DIR = "./assets/fonts" # Adjust to your skill path
# Register individual fonts
pdfmetrics.registerFont(TTFont("Lora", f"{FONT_DIR}/Lora-Regular.ttf"))
pdfmetrics.registerFont(TTFont("Lora-Bold", f"{FONT_DIR}/Lora-Bold.ttf"))
pdfmetrics.registerFont(TTFont("Lora-Italic", f"{FONT_DIR}/Lora-Italic.ttf"))
pdfmetrics.registerFont(TTFont("Lora-BoldItalic", f"{FONT_DIR}/Lora-BoldItalic.ttf"))
# Register family so <b> and <i> tags work in Paragraphs
registerFontFamily('Lora',
normal='Lora', bold='Lora-Bold',
italic='Lora-Italic', boldItalic='Lora-BoldItalic')If bundled fonts are not available, fall back to ReportLab built-ins (Helvetica, Times-Roman, Courier). The design will still work — just less distinctive.
Every document needs exactly this palette:
C_BLACK = HexColor("#0A0A0A") # Primary text
C_DARK_GRAY = HexColor("#2D2D2D") # Body text
C_MID_GRAY = HexColor("#6B6B6B") # Secondary text
C_LIGHT_GRAY = HexColor("#E8E8E8") # Rules and borders
C_PALE = HexColor("#F5F5F3") # Alternate row backgrounds
C_WHITE = HexColor("#FFFFFF") # Page background
C_ACCENT = HexColor("#FF3D00") # Primary accent (customize per project)
C_CODE_BG = HexColor("#1E1E2E") # Dark code block background
C_CODE_TEXT = HexColor("#CDD6F4") # Code text colorSwap C_ACCENT to match the project's brand. Good options:
#FF3D00 — Bold red-orange (default, editorial)#0066FF — Corporate blue#00BFA5 — Teal/crypto#7C3AED — Purple/tech#F59E0B — Amber/warmPAGE_W, PAGE_H = letter # 612 x 792 points
MARGIN_LEFT = 1.0 * inch # 72pt
MARGIN_RIGHT = 1.0 * inch
MARGIN_TOP = 1.0 * inch
MARGIN_BOTTOM = 1.0 * inch
# Content area: 468pt wide × 636pt tallDisplay (cover title): 38pt BigShoulders-Bold
Chapter number: 72pt BigShoulders-Bold
Chapter title: 30pt BigShoulders-Bold
H2 sections: 20pt BigShoulders-Bold
H3 subsections: 13pt InstrumentSans-Bold
Body text: 10.5pt Lora, 16pt leading
Code blocks: 8pt JetBrainsMono, 11.5pt leading
Headers/footers: 7.5pt InstrumentSansEvery studio-grade PDF follows this structure:
Drawn entirely by the page template's onPage callback — no flowables needed.
Custom Flowable subclass that draws:
Read references/DESIGN-SYSTEM.md for complete implementation code. The essential custom flowables are:
| Flowable | Purpose |
|---|---|
HorizontalRule | Styled separator line |
AccentBar | Bold colored bar for visual breaks |
CodeBlock | Dark-background code with syntax coloring |
ChapterOpener | Large chapter number + title layout |
SetChapterAction | Invisible — updates header/footer state |
The parser converts markdown content into ReportLab flowables. It handles:
**bold** and *italic* → <b> and <i> tags`inline code` → font-switched spansCRITICAL: Inline Formatting Safety
When converting markdown inline formatting to ReportLab XML, you MUST:
This prevents nested XML tag conflicts that crash ReportLab. See the format_inline() function in scripts/pdf_builder.py.
Use BaseDocTemplate with multiple PageTemplate objects:
doc = BaseDocTemplate(output_path, pagesize=letter, ...)
doc.addPageTemplates([
PageTemplate(id='cover', frames=[frame], onPage=draw_cover),
PageTemplate(id='toc', frames=[frame], onPage=draw_toc_chrome),
PageTemplate(id='chapter', frames=[frame], onPage=draw_chapter_chrome),
])Switch between templates using NextPageTemplate('template_id') flowables.
Headers must show the CURRENT chapter title, not the last one processed. Use a SetChapterAction flowable:
class SetChapterAction(Flowable):
def __init__(self, template_obj, chapter_text, chapter_num):
Flowable.__init__(self)
self.template = template_obj
self.chapter_text = chapter_text
self.chapter_num = chapter_num
self.width = 0
self.height = 0
def wrap(self, aW, aH): return (0, 0)
def draw(self):
self.template.current_chapter = self.chapter_text
self.template.current_chapter_num = self.chapter_numInsert this flowable at the start of each chapter, AFTER the PageBreak.
1. Register fonts
2. Define color palette
3. Create ParagraphStyles dict
4. Create page template handler class
5. Create BaseDocTemplate with cover/toc/chapter templates
6. Build story array:
a. Cover page spacer + NextPageTemplate('toc') + PageBreak
b. TOC heading + chapter list table rows
c. For each chapter file:
- NextPageTemplate('chapter') + PageBreak
- SetChapterAction flowable
- Parse markdown → flowables
- Extend story
7. doc.build(story)
8. Copy to output directory1. Register fonts
2. Define color palette
3. Same style setup but simpler templates (cover + body only)
4. Build story:
a. Cover spacer + PageBreak
b. Parse content → flowables
5. doc.build(story)Problem: ReportLab crashes with "saw instead of expected "
Cause: Markdown with **text with code inside** creates overlapping XML tags
Fix: Always extract code spans and links BEFORE processing bold/italic
Problem: LayoutError: Flowable too large on page
Cause: A Spacer or Flowable exceeds the frame's available height
Fix: Never use Spacer(1, PAGE_H) — use Spacer(1, 1) for cover pages since the cover is drawn by onPage callback
Problem: Header shows "Chapter 18" on every page
Cause: Setting template.current_chapter in the build loop only sets the final value
Fix: Use SetChapterAction flowable to update state during rendering
Problem: Special characters appear as solid rectangles
Cause: The registered TTF font doesn't contain those glyphs
Fix: Use ReportLab's <sub> and <super> tags instead of Unicode subscripts/superscripts. For other special chars, verify glyph coverage or use a different font.
Problem: <b>text</b> doesn't render bold
Cause: Font family not registered
Fix: Use registerFontFamily() after registering individual font weights
Corporate / Conservative:
#0066FF (blue)Tech / Modern:
#7C3AED (purple)Crypto / Web3:
#00BFA5 (teal) or #FFB300 (gold)Minimal / Clean:
#000000 (just black).ttf files in assets/fonts/pdfmetrics.registerFont()registerFontFamily()Good free font sources: Google Fonts (fonts.google.com)
studio-pdf/
├── SKILL.md ← You are here
├── references/
│ └── DESIGN-SYSTEM.md ← Full code for all components
├── scripts/
│ └── pdf_builder.py ← Complete working template script
└── assets/
└── fonts/ ← Bundled TTF fonts
├── BigShoulders-Bold.ttf
├── BigShoulders-Regular.ttf
├── Lora-Regular.ttf
├── Lora-Bold.ttf
├── Lora-Italic.ttf
├── Lora-BoldItalic.ttf
├── InstrumentSans-Regular.ttf
├── InstrumentSans-Bold.ttf
├── InstrumentSans-Italic.ttf
├── InstrumentSans-BoldItalic.ttf
├── JetBrainsMono-Regular.ttf
├── JetBrainsMono-Bold.ttf
├── CrimsonPro-Regular.ttf
├── CrimsonPro-Bold.ttf
└── CrimsonPro-Italic.ttfWhen to read what:
references/DESIGN-SYSTEM.md — when you need the full component codescripts/pdf_builder.py — copy and customize as your starting pointteeclaw/phorm-nft
02adecb
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.