vmprint CLI

Package: @vmprint/cli · Install: npm install -g @vmprint/cli

The JSON → PDF command-line interface for VMPrint.

The CLI is more than a convenience wrapper. It serves four distinct roles, and understanding them clarifies what the tool is actually for.

Development companion

When working on the layout engine — adding a feature, fixing a rendering bug, tuning typography — you need to run real documents through the pipeline and see the result immediately. The CLI gives you that loop without any build step:

npm run dev --prefix cli -- --input document.json --output out.pdf

Change engine code. Re-run. Inspect the PDF. The CLI's source-mode dev command uses a dedicated local TypeScript config to resolve the engine and contracts directly from workspace source. --profile-layout measures and prints the layout pipeline duration, which is useful when evaluating the performance impact of engine changes.

Experiment bench

The --font-manager flag accepts any JS module that exports a default class implementing the FontManager interface. Testing a new font manager against real documents requires exactly one flag — no integration scaffolding, no test harness:

vmprint --input document.json --output out.pdf --font-manager ./my-font-manager.js

The module is loaded with import() at runtime. You can develop and iterate on a font manager entirely through the CLI before integrating it anywhere else.

Reference design

The CLI is approximately 225 lines of TypeScript. It demonstrates the complete, correct pattern for integrating VMPrint: load a source document, normalize the authored AST into the engine-ready form, configure the engine runtime, wait for fonts, paginate, render, handle the output stream. If you’re embedding VMPrint into a larger application, the CLI source is the clearest available example of how to do it.

Production batch processing

The CLI works as a production pipeline. Write a driver script that generates DocumentInput JSON and shells out to vmprint, or use the --render-from-layout flag to separate the layout and rendering passes across processes or machines:


Key Capabilities

Layout stream — the output of layout, before rendering

vmprint --input document.json --output out.pdf --emit-layout
# Writes: out.layout.json

--emit-layout writes the full Page[] as annotated JSON after layout completes and before rendering begins. Each page contains every box, its absolute position, its type, its text content, and glyph-level positioning data.

The layout stream is serializable, diffable, and re-renderable. It is the basis of VMPrint’s own regression test infrastructure — snapshot it, change something, diff it. --omit-glyphs drops per-character positioning data for smaller output; --quantize rounds coordinates to three decimal places for stable diffs.

Render from layout — skip the layout pass entirely

vmprint --render-from-layout out.layout.json --output out.pdf

--render-from-layout bypasses the layout engine and renders directly from a saved layout stream. This separates the two pipeline stages physically: layout once, render many times; cache layout results server-side and re-render on demand; move rendering to a different process, machine, or runtime.

Overlay system

vmprint --input document.json --output out.pdf --overlay ./watermark.js

The overlay system lets you draw before and after page content without touching the document. If --overlay is omitted, the CLI looks for a sidecar file automatically: if the input is document.json, it checks for document.overlay.mjs, .js, .cjs, or .ts alongside the input and loads it silently if found.

The overlay module exports an object with a backdrop() method, an overlay() method, or both. Both receive the page geometry and the full box tree from the layout pass. Pages include header and footer region boxes alongside standard page content if defined in the document.

// document.overlay.mjs — loaded automatically alongside document.json
export default {
  overlay(page, ctx) {
    ctx.save();
    ctx.opacity(0.07);
    ctx.fillColor('#000000');
    ctx.font('Helvetica', 64);
    ctx.translate(page.width / 2, page.height / 2);
    ctx.rotate(-45);
    ctx.text('DRAFT', -100, -32);
    ctx.restore();
  }
};

See Overlay System for the full interface reference.


What Ships Bundled

The CLI uses @vmprint/context-pdf for PDF output and @vmprint/local-fonts for font loading. Both can be replaced without rebuilding or forking.

To produce a PDF using only the 14 standard PDF fonts with no embedded font data:

vmprint --input document.json --output out.pdf --font-manager @vmprint/standard-fonts

Custom font manager classes must be the default export of their module and implement the FontManager interface from @vmprint/contracts. Custom contexts can be integrated programmatically — see the standalone contexts repository.


Options Reference

Flag Description
--input <file> Input DocumentInput JSON file
--output <file> Output PDF path
--render-from-layout <file> Render from a saved layout stream, skipping the layout pass
--emit-layout Write the layout stream to <output>.layout.json after layout
--omit-glyphs Omit per-character glyph positioning from the layout stream
--quantize Round layout coordinates to 3 decimal places (stable diffs)
--font-manager <module> Path or package name of a custom FontManager implementation
--overlay <module> Path to an overlay module (backdrop/overlay hooks)
--debug Render debug overlay: page margins, zone bounds, box labels
--profile-layout Print layout pipeline timing after completion