@nowline/export-pdf
v0.2.5
Published
Nowline PDF exporter — vector PDF via PDFKit + svg-to-pdfkit
Downloads
672
Readme
@nowline/export-pdf
Vector PDF export for Nowline roadmaps. Uses
pdfkit for the document and
@kittl/svg-to-pdfkit
to embed the renderer's SVG as a PDF page.
License: Apache 2.0
Part of: lolay/nowline monorepo
Spec: specs/handoffs/m2c.md § 4
Install
pnpm add @nowline/export-pdf @nowline/export-core @nowline/rendererUsage
import { exportPdf } from '@nowline/export-pdf';
const pdf = await exportPdf(inputs, svg, {
pageSize: 'letter', // preset name, "WxHunit" custom, or "content"
orientation: 'auto', // 'portrait' | 'landscape' | 'auto'
marginPt: 36, // points (¼ inch). Use parseLength() for in/mm/cm.
fonts, // ResolvedFontPair from @nowline/export-core
});
// `pdf` is a Uint8Array of PDF bytes.Options
| Option | Default | Notes |
|----------------|--------------------------------------|-------|
| pageSize | 'letter' | Preset name (letter, legal, tabloid, ledger, a1–a5, b3–b5), 'content' for auto-fit, or WxHunit for custom (e.g., 8.5x11in, 210x297mm). |
| orientation | 'auto' | 'portrait', 'landscape', or 'auto'. Auto picks the shorter-edge orientation that lets the model fit at ≥ 1:1. |
| marginPt | 36 (½ inch) | Margin in PDF points on every side. The CLI parses --margin 0.5in via @nowline/export-core's unit converter. |
| fonts | resolveFonts() | Pre-resolved sans/mono pair. If omitted, the exporter calls the resolver itself. |
| title | roadmap title or 'Nowline Roadmap' | PDF Info /Title. |
| compress | true | PDFKit compress option. Set false to make the raw PDF byte stream readable for tests. |
A roadmap whose content box exceeds (page − 2 × margin) at 1:1 is scaled
uniformly down to fit; we never scale up. This keeps a tiny roadmap
small on a Letter page rather than bloating it.
Determinism
PDF determinism is fragile by default — most PDF libraries embed
new Date(), random /ID arrays, and timestamp-derived stream filters.
This exporter pins every source of variation:
info.CreationDateandinfo.ModDatecome frominputs.today(UTC), never fromnew Date(). The CLI propagates--todayto both the layout and the PDF metadata.pdfVersion: '1.7'pins the PDF spec.Producer/Creatorare explicit, version-pinned strings./IDis auto-generated by PDFKit frominfoonly (PDFKit ≥ 0.13), so a fixedCreationDateyields a stable ID array.- Fonts are registered by name with explicit byte buffers — glyph subsets
are byte-identical across hosts when the same
ResolvedFontPairis used.
The pdfjs round-trip test (test/export-pdf.test.ts) loads the output
back via pdfjs-dist and asserts that page count, dimensions, and visible
text match the source roadmap.
Why embed SVG instead of walking PositionedRoadmap directly?
The original spec called for a per-emitter walk of PositionedRoadmap to
PDFKit primitives. We reuse the SVG renderer instead and embed its output
via svg-to-pdfkit. Trade-offs:
- Pros: every visual feature the SVG renderer ever supports works in PDF for free; no double-implementation; ~150 LOC in this package vs. ~1500 LOC for a parallel emitter; PDF stays in lock-step with SVG even as the renderer evolves (m4 themes, m4 partials, etc.).
- Cons: bugs in
svg-to-pdfkitshow up as PDF rendering bugs; we pin the version (@kittl/svg-to-pdfkit, the actively-maintained fork) and treat any divergence from the SVG as a bug.
The trade-off is documented in
specs/handoffs/m2c.md § 4.
License
Apache-2.0. Bundles the @kittl/svg-to-pdfkit and pdfkit runtime
dependencies (also Apache / MIT).
