Skip to content
feralcreativePublic

About

Converts Markdown and HTML files to PDFs with token replacement, styling, and content processing features.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

{{PROJECT_NAME}}

Converts Markdown and HTML files to PDFs with token replacement, styling, and content processing features.

What it does

  • Converts Markdown and HTML to PDF using Chrome/Puppeteer
  • Replaces tokens like {{DATE}} and {{DEVELOPER_NAME}}
  • Applies Inter font styling and consistent layout
  • Handles PDF-only content sections
  • Supports page breaks and special formatting
  • Works on macOS, Linux, and Windows

Quick start

# Install dependencies
npm install

# Convert files
node bin/2pdf.js README.md           # converts README.md to README.pdf
node bin/2pdf.js document.md         # converts any markdown file
node bin/2pdf.js webpage.html        # converts HTML files too
node bin/2pdf.js file.md -o out.pdf  # custom output name

File types supported

Markdown files (.md)

  • Always uses 2pdf's Inter font styling and layout
  • Supports all markdown features (headers, lists, code blocks, etc.)
  • Token replacement and special content features

HTML files (.html, .htm)

  • With existing CSS: Preserves your styles (internal, external, inline)
  • Without CSS: Falls back to 2pdf's default styling
  • Token replacement works the same way
  • Color theming injects CSS custom properties

Core features

Token replacement

Insert dynamic content using {{TOKEN_NAME}} placeholders:

# {{PROJECT_NAME}} Documentation

**Version:** {{PROJECT_VERSION}}
**Generated:** {{DATE}} by {{DEVELOPER_NAME}}

Automatic tokens (always available)

  • {{DATE}} - Current date (2024-01-15)
  • {{DATE_LONG}} - Current date (January 15, 2024)
  • {{TIME}} - Current time (14:30)
  • {{YEAR}}, {{MONTH}}, {{DAY}} - Date components
  • {{TIMEZONE}} - Current timezone (PST, EST, UTC, etc.)
  • {{USERNAME}}, {{HOSTNAME}} - System info
  • {{PROJECT_NAME}} - Auto-generated from directory name

Custom tokens from config file

Create 2pdf.config with your own tokens:

DEVELOPER_NAME=John Doe
PROJECT_VERSION=2.1.0
COMPANY_NAME=Acme Corp

Special content features

1. PDF-only content

Content that only appears in the PDF:

<!-- PDF ONLY This text only appears in the PDF version -->

2. Page breaks

Force a new page:

Content here...

<!-- PAGE-BREAK -->

Content on next page...

3. Live site shields

Style a paragraph as a compact badge:

<!-- live-site-shield -->

Live Site: https://example.com

Live Site: https://example.com

4. Text highlighting

Inline highlighting

Highlight important text using either HTML <mark> tags or the ==highlight== syntax:

This is <mark>highlighted text using HTML</mark> in a sentence.

This is ==highlighted text using double equals== in a sentence.

Both syntaxes produce identical results and work inline within paragraphs, headers, lists, and other text elements.

Block highlighting

Highlight entire sections (headers, paragraphs, lists, etc.) using the <highlight> tag:

<highlight>

### Section Title

This entire section is highlighted with a background color.

- List item 1
- List item 2
- List item 3

You can include multiple paragraphs, lists, headers, and other elements.

</highlight>
Important notes about <highlight>:
  • It's a custom HTML element that won't render in standard markdown preview
  • It will be properly styled in the generated PDF
  • Use blank lines before and after the opening/closing tags for proper markdown parsing
  • Headers inside highlight blocks maintain their theme colors
  • You can nest inline highlighting (<mark> or ==text==) inside block highlights

Custom highlight color

<!-- highlight-color: #e3f2fd -->

This text will be ==highlighted in light blue== instead of the default color.

<highlight>

This entire block will also use the light blue background.

</highlight>

The default highlight color is #ffffad (light yellow), but you can customize it per document using the <!-- highlight-color: --> setting. This applies to both inline (<mark>, ==text==) and block (<highlight>) highlighting.

5. Headers (H1-H6)

All headers use the Inter font family and are styled with specific colors, sizes, and formatting:

H1 - Main Title

  • Font size: 2.5rem (largest)
  • Font weight: 300 (light)
  • Color: Primary theme color (--theme-color-primary)
  • Horizontal rule: Yes - thin line below in primary theme color
  • Use for: Document title, major section dividers

H2 - Major Sections

  • Font size: 1.75rem
  • Font weight: 600 (semi-bold)
  • Color: Primary theme color (--theme-color-primary)
  • Horizontal rule: Yes - thin line below in primary theme color
  • Use for: Main sections, chapter headings

H3 - Subsections

  • Font size: 1.4rem
  • Font weight: 600 (semi-bold)
  • Color: Secondary theme color (--theme-color-secondary)
  • Horizontal rule: Yes - thin gray line (#aaa)
  • Use for: Subsections within major sections

H4 - Minor Headings

  • Font size: 1.25rem
  • Font weight: 600 (semi-bold)
  • Color: Secondary theme color (--theme-color-secondary)
  • Horizontal rule: No
  • Use for: Smaller subsections, topic headings

H5 - Small Headings

  • Font size: 1rem (same as body text)
  • Font weight: 800 (extra bold)
  • Color: Primary theme color (--theme-color-primary)
  • Horizontal rule: No
  • Use for: Minor topics, list section headers

H6 - Smallest Headings

  • Font size: 0.7rem (smaller than body text)
  • Font weight: 800 (extra bold)
  • Color: Primary theme color (--theme-color-primary)
  • Text transform: UPPERCASE
  • Horizontal rule: No
  • Use for: Labels, metadata headers, fine print sections

Color customization

Headers use theme colors that can be customized per document:

<!-- theme-color-primary: #1976d2 -->
<!-- theme-color-secondary: #388e3c -->
  • Primary color affects H1, H2, H5, H6
  • Secondary color affects H3, H4

6. Table of Contents with PDF Navigation

Create a markdown table of contents with links that work in PDFs:

## Table of Contents

- [Introduction](#introduction)
- [Getting Started](#getting-started)
  - [Installation](#installation)
  - [Configuration](#configuration)
- [Usage](#usage)

## Introduction

Your introduction content here...

## Getting Started

### Installation

Installation steps...

etc.

When converted to PDF, all links in the table of contents become clickable internal links that jump to the corresponding sections. PDF viewers will navigate to the correct page automatically.

How it works

  • Headers are automatically assigned unique IDs (e.g., # Introduction → id="introduction")
  • Markdown links like [Introduction](#introduction) are converted to HTML anchor links
  • PDF viewers recognize these internal links and allow navigation between pages

Multi-Column Layouts

For long tables of contents or lists, you can display them in multiple columns:

Two Columns:
## Table of Contents

<!-- two-columns -->

- [Introduction](#introduction)
- [Getting Started](#getting-started)
- [Installation](#installation)
- [Configuration](#configuration)
- [Usage](#usage)
- [Advanced Features](#advanced-features)
- [Troubleshooting](#troubleshooting)
- [FAQ](#faq)

<!-- /two-columns -->
Three Columns:
<!-- three-columns -->

- [Item 1](#item-1)
- [Item 2](#item-2)
- [Item 3](#item-3)
- [Item 4](#item-4)
- [Item 5](#item-5)
- [Item 6](#item-6)
- [Item 7](#item-7)
- [Item 8](#item-8)
- [Item 9](#item-9)

<!-- /three-columns -->
Four Columns:
<!-- four-columns -->

- [Item 1](#item-1)
- [Item 2](#item-2)
- [Item 3](#item-3)
- [Item 4](#item-4)
- [Item 5](#item-5)
- [Item 6](#item-6)
- [Item 7](#item-7)
- [Item 8](#item-8)

<!-- /four-columns -->

The content between the opening and closing tags will be displayed in the specified number of columns with a subtle divider line between them.

Manual Column Breaks:

You can force content to break to the next column using <!-- column-break -->:

<!-- three-columns -->

- [Item 1](#item-1)
- [Item 2](#item-2)
- [Item 3](#item-3)

<!-- column-break -->

- [Item 4](#item-4)
- [Item 5](#item-5)
- [Item 6](#item-6)

<!-- column-break -->

- [Item 7](#item-7)
- [Item 8](#item-8)
- [Item 9](#item-9)

<!-- /three-columns -->

This ensures content is distributed exactly as you want across the columns.

7. Table column widths

Control table column widths with HTML comments:

Example 1

<!-- col-widths: 30% 70% -->

| Name | Description                                 |
| ---- | ------------------------------------------- |
| Item | Long description text that needs more space |
Name Description
Item Long description text that needs more space

Example 2

<!-- col-widths: 100px 200px 50% -->

| ID  | Name | Notes      |
| --- | ---- | ---------- |
| 1   | Test | Some notes |
ID Name Notes
1 Test Some notes

8. Table font size

Override body-size for a single table. Place <!-- table-size: ... --> immediately before the table — it applies only to the next table, so you can use it multiple times throughout a document.

<!-- table-size: 1em 0.75em -->

| Name | Description    |
| ---- | -------------- |
| Item | Body at 0.75em |
  • Two values: first is header (th) size, second is body (td) size
  • One value applies to both: <!-- table-size: 0.85em -->
  • Stackable with col-widths:
<!-- col-widths: 30% 70% -->
<!-- table-size: 0.9em 0.75em -->

| Name | Description |
| ---- | ----------- |
| Item | Long text   |

9. Table column alignment

Control table column alignment using standard markdown syntax with colons in the separator row:

  • :--- = left aligned (default)
  • :---: = center aligned
  • ---: = right aligned

Left aligned (default)

| Name | Description  |
| ---- | ------------ |
| Item | Left aligned |

Center aligned

| Name | Status |
| :--: | :----: |
| Item | Active |

Right aligned

| Quantity |  Price |
| -------: | -----: |
|      100 | $50.00 |

Mixed alignment

| Name      |  Status  |   Price |
| :-------- | :------: | ------: |
| Product A |  Active  |  $99.99 |
| Product B | Inactive | $149.99 |

You can combine alignment with column widths:

<!-- col-widths: 30% 40% 30% -->

| Name   | Description    |  Price |
| :----- | :------------- | -----: |
| Item 1 | Left aligned   | $10.00 |
| Item 2 | Center aligned | $20.00 |

10. Image width

Override the width of a single image. Place <!-- img-width: ... --> immediately before the image — it applies only to the next image, so you can use it multiple times throughout a document.

<!-- img-width: 150px -->

![Diagram](images/diagram.png)
  • Any CSS length is accepted: 150px, 50%, 4in, 12em, etc.
  • Images never overflow the page — the global max-width: 100% still applies, so a width larger than the content area is clamped.
  • Standard markdown image syntax (![alt](path)) is supported; the comment applies to whichever image follows it. Images without a preceding comment render at their native size (capped to the content width).

11. Code block font size

Override the text size of a single code block. Place <!-- code-size: ... --> immediately before the block — it applies only to the next code block, so you can use it as many times as you like in one document.

<!-- code-size: 1.4em -->

```js
const scaledUp = true;
```
  • Any CSS length is accepted: 1.4em, 0.6em, 11px, 9pt, etc.
  • The value is relative to body text, the same way table-size works. The unstyled default for code blocks is 0.75em, so 1.4em is noticeably larger and 0.6em noticeably smaller.
  • Applies to fenced and indented code blocks. Inline code (`like this`) is never affected — only the block that follows the comment.
  • Blocks without a preceding comment keep the default size.

12. Header rules

H1, H2, and H3 get a hairline rule beneath them by default. Place <!-- rule: off --> on the line below a heading to drop that heading's rule.

## Section Without A Rule
<!-- rule: off -->

Body copy.
  • This is the only comment that targets the element above it — every other per-element tag (table-size, img-width, code-size) applies to what follows. A blank line between the heading and the comment is fine either way.
  • off, none, no, false, and hide all turn the rule off.
  • <!-- rule: on --> does the reverse: it adds a rule to a heading that has none (H4-H6), drawn in the heading's own color.
  • Applies to one heading per comment, so use it as many times as you like. Headings without a comment keep the default.
  • Markdown input only. HTML input keeps whatever its own CSS says.

Document styling

Set theme colors, text colors, and font sizes directly in your document:

<!-- filename: custom-output-name.pdf -->
<!-- theme-color: #ff6b35 -->
<!-- theme-color-primary: #1434cb -->
<!-- theme-color-secondary: #27ae60 -->
<!-- body-color: #2c3e50 -->
<!-- link-color: #3498db -->
<!-- link-underline: off -->
<!-- highlight-color: #ffff00 -->
<!-- font-size: 1.2em -->
<!-- header-size: 1.3em -->
<!-- body-size: 0.9em -->
<!-- page-numbers: on -->
<!-- watermark: DRAFT -->

# Your Document Title

Content with custom styling...

Output filename

  • filename: Custom PDF output filename (report.pdf, my-document.pdf)
    • If empty or missing, defaults to input filename
    • CLI -o option takes priority over this setting

Color options

  • theme-color: Primary theme - headers, blockquotes, inline code (#ff6b35, #1434cb, #27ae60)
  • theme-color-primary: Primary accent color for specific elements
  • theme-color-secondary: Secondary accent color for specific elements
  • body-color: All body text, paragraphs, lists (#2c3e50, #333333)
  • link-color: Hyperlinks (#3498db, #e74c3c)
  • highlight-color: Text highlighting background color (#ffff00, #00ff00, #ff6b35)

Text decoration

  • link-underline: on or off - controls link underlines

Font sizing

  • font-size: Root font size (1.2em, 14px, 16px)
  • header-size: All headers scale from this (1.3em, 1.1em)
  • body-size: Paragraphs, lists, tables (0.9em, 1.1em)
  • line-height: Line spacing for all text (1.2em, 1.5, 18px)
  • paragraph-spacing: Margin above/below paragraphs (0.8em, 12px, 1rem)
  • header-spacing: Margin above/below headers, scales by level (1em, 16px)
    • H1 has no top margin (abuts page margin)
    • Headers after page breaks have no top margin
    • Spacing scales: H2(1.0×), H3(0.9×), H4(0.75×), H5(0.6×), H6(0.5×)
  • list-item-spacing: Margin above/below each list item (0.2em, 0.5em, 8px)

Page features

  • page-numbers: on, off, X, or X of Y - controls footer page numbering
  • disclosure: Brief text for center footer (e.g., Internal Use Only, CONFIDENTIAL)
  • watermark: on (or DRAFT), off, or any custom text - stamps a large diagonal watermark across every page
    • on/true/yes renders DRAFT; off/false/no/none disables it
    • Any other value is used verbatim, e.g. <!-- watermark: NOT FOR DISTRIBUTION -->
    • Drawn over the content in the theme-color-primary color faded to 5% (falls back to theme-color), and scaled down automatically for longer strings
    • Ignored for .html input that carries its own CSS (same as logo)
  • logo: Filename (or absolute path) for a logo image displayed at the top of the document
    • Bare filenames resolve to public/assets/images/ inside the 2pdf install
    • Embedded as a base64 data URI so the PDF stays portable
    • Example: <!-- logo: logo-feral.svg -->

Output features

  • sequential-output: on or off - enables versioned output filenames
  • version-number: XX.YY format - auto-increments with each PDF generation
  • file-date: BEFORE, AFTER, or OFF - stamps the output filename with a UTC timestamp
    • Format: YYMMDDTHHMMZ (e.g. 260514T2227Z)
    • BEFORE prepends: 260514T2227Z-document.pdf
    • AFTER appends: document-260514T2227Z.pdf
    • Applies on top of any other filename source (CLI -o, filename, or sequential version)

Footer Layout

When page numbers are enabled, the footer has three sections:

Left: Document title (from H1) | Date (DD MMM YYYY format) Center: Disclosure text (uppercase, optional) Right: Page numbers (X or X of Y format)

<!-- page-numbers: X -->
<!-- disclosure: Internal Use Only -->

# My Document Title

Results in footer: My Document Title | 25 Dec 2024 | INTERNAL USE ONLY | 1

Sequential Output

Automatically version your PDF outputs with incremental version numbers:

<!-- sequential-output: on -->
<!-- version-number: 00.00 -->

# My Document

How it works

  1. First run: Outputs my-document-v00.00.pdf, updates version to 00.01
  2. Second run: Outputs my-document-v00.01.pdf, updates version to 00.02
  3. Continues: 00.02 → 00.03 → ... → 00.99 → 01.00 → 01.01

Version format: XX.YY (major.minor, 00-99 each) Auto-increment: Source file is automatically updated with new version Filename: document-vXX.YY.pdf format

Advanced options

Color theming

Customize header and accent colors with the --color flag:

# Predefined colors (from config file)
node bin/2pdf.js doc.md --color blue
node bin/2pdf.js doc.md --color corporate

# Custom hex colors
node bin/2pdf.js doc.md --color 1434cb
node bin/2pdf.js doc.md --color "#ff6b35"

Add predefined colors to your 2pdf.config:

COLOR_BLUE=#1434cb
COLOR_RED=#e74c3c
COLOR_GREEN=#27ae60
COLOR_CORPORATE=#2c3e50
COLOR_ORANGE=#ff6b35

Single-page mode

Generate PDFs as one continuous page instead of multiple US Letter pages:

node bin/2pdf.js file.md --single-page
node bin/2pdf.js file.md --single-page --color blue

This is perfect for:

  • Web page captures
  • Long documents that look better as continuous scrolls
  • Documents with content that shouldn't be split across pages

Other options

node bin/2pdf.js file.md -s custom.css  # custom CSS file
node bin/2pdf.js file.md --debug        # keep temp files
node bin/2pdf.js file.md --verbose      # detailed output

Quick reference

Special comments for enhanced formatting

<!-- ── Content layout ── -->
<!-- PDF ONLY Content only in PDF -->
<!-- PAGE-BREAK -->
<!-- live-site-shield -->
<!-- col-widths: 30% 70% -->
<!-- table-size: 1em 0.75em -->
<!-- img-width: 150px -->
<!-- code-size: 1.4em -->
<!-- rule: off -->
<!-- two-columns -->
<!-- /two-columns -->
<!-- three-columns -->
<!-- /three-columns -->
<!-- four-columns -->
<!-- /four-columns -->
<!-- column-break -->

<!-- ── Output file ── -->
<!-- filename: custom-output.pdf -->
<!-- file-date: AFTER -->
<!-- sequential-output: on -->
<!-- version-number: 00.00 -->

<!-- ── Colors ── -->
<!-- theme-color-primary: #880088 -->
<!-- theme-color-secondary: #666666 -->
<!-- body-color: #222222 -->
<!-- link-color: #0000ff -->
<!-- link-underline: off -->
<!-- highlight-color: #ffff00 -->

<!-- ── Typography ── -->
<!-- font-size: 1.2em -->
<!-- header-size: 1.3em -->
<!-- body-size: 0.9em -->
<!-- line-height: 1.2em -->
<!-- paragraph-spacing: 0.8em -->
<!-- header-spacing: 1em -->
<!-- list-item-spacing: 0.3em -->

<!-- ── Page features ── -->
<!-- logo: logo-feral.svg -->
<!-- page-numbers: X of Y -->
<!-- disclosure: Internal Use Only -->
<!-- watermark: DRAFT -->

# Text Highlighting

Inline: Use <mark>HTML mark tags</mark> or ==double equals syntax==.

Block: Use <highlight>custom tag</highlight> for entire sections.

Configuration

Config file format

Create 2pdf.config with key=value pairs:

# Project info
PROJECT_VERSION=2.1.0
DEVELOPER_NAME=Jane Smith
COMPANY_NAME=Acme Corp

# Color themes
COLOR_BRAND=#1434cb
COLOR_ACCENT=#ff6b35

# Custom content
FOOTER_TEXT=Generated on {{DATE}} by {{DEVELOPER_NAME}}

Config file locations

2pdf searches for 2pdf.config in this order:

  1. Same directory as the input file
  2. Current working directory
  3. 2pdf installation directory
  4. config/ subdirectory in any of the above

Token processing details

  • Multiple passes: Tokens can reference other tokens
  • Case sensitive: {{NAME}} ≠ {{name}}
  • No whitespace: Use {{TOKEN}}, not {{ TOKEN }}
  • Nested replacement: GREETING=Hello {{USERNAME}} works
  • Missing tokens: Left unchanged for debugging

Example workflow

# 1. Create config file
echo "PROJECT_VERSION=2.1.0" > 2pdf.config
echo "DEVELOPER_NAME=Jane Smith" >> 2pdf.config

# 2. Use in markdown
echo "# Project v{{PROJECT_VERSION}} by {{DEVELOPER_NAME}}" > doc.md

# 3. Convert
node bin/2pdf.js doc.md

# Result: "Project v2.1.0 by Jane Smith" in the PDF

License

© {{YEAR}} {{COMPANY_NAME}} • MIT License

About

Converts Markdown and HTML files to PDFs with token replacement, styling, and content processing features.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages