VMPrintPreview Takes Center Stage
Most JavaScript PDF tools make you choose between two bad options: wrestle with print CSS until it breaks on page 2, or rewire your entire UI in JSX components just to get a rendered document. react-pdf is popular for a reason — it works — but it comes with a cost: a component model wrapped around a layout engine, dependencies all the way down, and no live preview that matches what you'll actually export.
VMPrint was built for the case where that tradeoff stops being acceptable. One layout pass. Live canvas preview. PDF, SVG, or server output — same session, same result. No React. No Chromium. No re-render surprises.
This release makes all of that visible in under ten seconds.
The preview demo is now the front door. The VMPrint homepage opens directly into the story, with the live preview demo embedded below it. Type Markdown, see the paginated layout update in real time, export a PDF. That's the pitch, and now it's the first thing you see.
New built-in style presets — Blueprint Atelier and Annual Report Two new presets that show what publication-grade layout actually looks like out of the box, not just functional defaults.
Better fit-to-page sizing and first-load behavior The preview now opens correctly sized on first load, and pages fit the viewport without manual adjustment.
Markdown image links now work in the browser demo Drop an image into your Markdown and it renders in the preview. Edge case, but an important one.
Drop-cap support in the Markdown pipeline Explicit drop-cap rendering via the transmuter layer.
Stronger social presence New Open Graph preview image, tightened SEO metadata, and clearer pathways from the homepage to docs, examples, and advanced layout samples.
The documentation has always described what VMPrint can do. This release lets you watch it do it.
If you've spent time fighting react-pdf's component model, or debugging print CSS page breaks at 11pm, VMPrint is worth five minutes of your time. The live demo runs in the browser, static, no install, and the code is right there in the page source.
- Homepage: https://cosmiciron.github.io/vmprint/
- Live preview demo: https://cosmiciron.github.io/vmprint/examples/preview/
- Advanced layout (AST + web fonts): https://cosmiciron.github.io/vmprint/examples/ast-to-canvas-webfonts/index.html
- Guides: https://cosmiciron.github.io/vmprint/guides/
VMPrint 1.0 — The Real Thing
I have been building toward this moment since the first experimental commits. VMPrint 1.0 is not an incremental update. It is the line in the sand that separates "something interesting is happening here" from "you can build real things with this."
At the core of VMPrint 1.0 is a ground-up reimagination of how a document layout engine works.
Most layout systems are glorified paginators — they march line by line through a document and hope for the best when things get complicated. VMPrint 1.0 replaces that model with something entirely different: a simulation runtime built around a spatial-temporal model of document layout.
The spatial-temporal layout engine is patent pending.
Instead of a linear pagination loop, the engine now operates as a simulation with explicit phases: placement, collision detection, physics, transitions, and lifecycle dispatch. Documents are settled, not merely paginated. Complex behaviors — keep-with-next, page reservations, column spanning, heading telemetry, nested continuations, live table-of-contents generation — emerge naturally from the simulation substrate rather than being bolted on as special cases.
The result is a layout engine capable of things that simply cannot be expressed in traditional paginators.
Previous releases were honest technology previews. The architecture was exploratory, the surface area was shifting, and I was candid that it was not yet the foundation you would build a product on.
That changes today.
VMPrint 1.0 is production-ready. The document model (AST 1.1) is stable. The layout contracts are locked. The regression suite covers 26 complex fixtures — multi-column flows, nested tables, nested stories, zone maps, column spans, RTL/bidi, drop caps, floats, live TOC, headers/footers, total-page footers, and more — and every one of them must pass deterministically on every build. You can depend on this.
The engine was rebuilt around an explicit simulation kernel with collaborator-based coordination. Speculative layout, rollback, and deterministic replay are now first-class capabilities. Simulation reports expose post-layout facts to downstream tooling without leaking engine internals. This is the architecture that makes ambitious documents possible.
Documents can now think. A post-settlement scripting runtime gives document blueprints direct access to lifecycle hooks, element messaging, receiver-oriented mutation, and structural replacement/insertion/deletion flows. Live reactive content — a table of contents that updates as pages reflow, a footer that knows the total page count — is no longer a trick. It is just scripting.
- Block-level floats for non-image content inside stories
- Column spanning via
properties.columnSpan— full-width breaks inside multi-column flows, exactly where you want them - Zone maps as a first-class layout primitive: bounded side-by-side regions with fully independent strip layout, perfect for sidebars, callouts, and complex editorial compositions
The document model was upgraded to AST 1.1. onLoad and onCreate now run as a formal blueprint preprocessing phase, before layout settlement begins. All fixtures, transmuters, and tooling have been updated consistently.
Loading beautiful typography in the browser used to mean fighting CORS, managing fetch timing, and hoping your font cache stayed warm. @vmprint/web-fonts handles all of it — remote font loading, optional persistent caching, and clean integration with the engine's font registration surface. Drop it into any browser-based VMPrint pipeline.
@vmprint/context-canvas builds SVG-backed page scenes and renders them directly into canvas targets. Feed it a Document AST and get a live, pixel-accurate preview of your layout running entirely in the browser — no server, no PDF round-trip, no waiting.
The best way to understand what VMPrint 1.0 can do is to see it running. I've included a set of self-contained static examples under /docs/examples that you can open directly in a browser — no build step, no server, no install:
| Example | What it shows |
|---|---|
ast-to-canvas-webfonts |
Document AST → canvas rendering with remote web fonts |
ast-to-pdf-webfonts |
Document AST → PDF generation with web fonts, in the browser |
ast-to-pdf |
Core AST-to-PDF pipeline, zero dependencies |
mkd-to-ast |
Markdown → VMPrint AST transmutation |
These are not toy demos. They are complete, production-weight pipelines running in a static HTML page. Fork them. Strip them down. Build your own renderer on top of them. They are yours.
VMPrint 1.0 is a foundation. Here is a taste of what it makes possible:
- Editorial and publishing tools — multi-column magazine layouts, flowing long-form text, drop caps, floats, and rich inline typography
- Live document editors — canvas preview in the browser, PDF export on demand, fonts loaded remotely or from cache
- Programmatic document generation — legal filings, technical reports, invoices, books — authored as data and settled by the simulation engine into pixel-perfect pages
- Reactive documents — scripted live content: auto-generated TOCs, dynamic page counts, content that adapts to its own layout
- Multilingual typesetting — full Unicode bidi (UAX #9), Arabic shaping, complex scripts, and JIT font loading for CJK and global scripts
VMPrint started as a question: what would a layout engine look like if it were designed from first principles for the modern web, without the baggage of decades of pagination assumptions?
Version 1.0 is my answer. I hope it sparks your imagination.
Full technical changelog: CHANGELOG.md
v0.3.1: VMPrint & Draft2Final: fix
- Improved RTL support in mixed-language paragraphs, especially Arabic embedded in LTR text.
- Direction handling is now more robust with paragraph-level direction: auto resolution.
- Neutral whitespace/punctuation handling in bidi runs was fixed to avoid phrase fragmentation.
- draft2final bumped to 1.0.2; monorepo bumped to 0.3.1.
- Engine bidi/RTL
- Hardened paragraph-level direction resolution for mixed LTR/RTL content.
- Improved neutral run assignment (spaces/punctuation) between strong bidi runs.
- Neutral whitespace now inherits active script/font run during segmentation, preventing Arabic run splitting and improving visual ordering stability.
- Added/expanded auto-direction and mixed-bidi coverage:
- engine/tests/auto-direction.spec.ts
- engine/tests/module-extractions.spec.ts
- Refreshed regression layout snapshots to match deterministic output after bidi fixes.
- Fixed regression fixture PDF generator for standard-font fixture:
- engine/tests/fixtures/regression/generate-fixture-pdfs.mjs
- 16-standard-fonts-pdf14.json now correctly uses StandardFontManager (fixes Symbol/ZapfDingbats render failure).
vmprint: 0.3.0 -> 0.3.1 draft2final: 1.0.1 -> 1.0.2
This release includes broad snapshot updates because mixed-script whitespace/font-run behavior affects line wrapping and pagination across many fixtures.
draft2final v1.0.0 — Official Launch
I am proud to announce the official 1.0.0 launch of draft2final -- the very reason this whole project was started. It took a while because I had to take a detour to build the engine first. LOL. But finally, it is here!
This version marks a radical simplification of the CLI experience, removing implementation details and developer jargon in favor of a premium, industrial-strength environment for writers, screenwriters, and researchers.
- Simplified Vocabulary: Standardized on
--as(Form) and--style(Aesthetic) flags. - Zero-Friction CLI: Run
draft2final story.mdwith zero flags for professional defaults. - Unified Frontmatter: Specify your document's form with a simple
as: screenplaykey in your Markdown file. - Premium UX: A completely redesigned welcome screen and help system for the discerning user.
- Industrial Accuracy: Powered by our state-of-the-art native typesetting engine (no browser-based hacks).
npm install -g draft2final
🚀 VMPrint / Draft2Final 0.3.0: The Global JIT Typesetting Release
I am incredibly excited to announce version 0.3.0 of VMPrint and Draft2Final. This release transforms the tooling from a developer-centric layout engine into a highly polished, production-ready, globally aware application for writers and publishers.
Draft2Final is no longer just a wrapper—it is now a zero-dependency, standalone CLI that instantly provides publication-grade PDF compilation.
I built Draft2Final to give developers and writers absolute typographic control without bloat. The biggest challenge with global language support is file size: a full set of high-quality CJK fonts can exceed 60MB.
In 0.3.0, I solved this with the JIT Downloader:
- Tiny Core: The CLI is now distributed as a standalone 4.4MB binary, bundling only a lightweight "Latin Pack" of core fonts (Caladea, Cousine, Arimo) and PDF metrics for instant offline rendering.
- Intelligent Pruning: The layout engine deeply analyzes your Document AST before rendering. If it detects Chinese, Japanese, Hebrew, Arabic, Thai, or Indic scripts, it dynamically disables unused fallbacks and only fetches what your document requires.
- Auto-Downloading: The required scripts are securely downloaded from a high-speed CDN, displayed in the CLI via a buttery-smooth concurrent progress tracker, and permanently cached in your local
~/.vmprint/fonts/folder.
You get world-class global typography, on-demand, without bloating your hard drive or the repository.
Installing Draft2Final is now faster and more reliable than ever. I've replaced the sprawling monorepo NPM dependencies with a single, highly-optimized tsup bundle. It just works.
Starting a new book or screenplay? I added an initialization command to get you running immediately without memorizing YAML configs:
draft2final --init my-new-book
cd my-new-book
draft2final document.md --config config.yaml --theme theme.yaml
- Smarter Fallbacks: I fixed an issue where standard English punctuation (like the em-dash) would accidentally trigger the download of 10MB Chinese fonts.
- Beautiful Terminal Output: Enjoy precise timing reports and a flicker-free concurrent download UI.
- Lean Open-Source Repo: I extracted 50MB+ of binary fonts from the core repository into a dedicated
assetsbranch, keepinggit clonetimes lightning fast for new contributors.
Global Install (Recommended for frequent use):
npm install -g @draft2final/cli
draft2final --init my-book
Run Instantly via npx (Zero install):
npx @draft2final/cli --init my-book
Write in plaintext. Compile to perfection. Welcome to Draft2Final.
v0.2.0: Transmuter Architecture Overhaul + New draft2final
This release introduces a major architecture upgrade centered on one idea:
A Transmuter converts source text (for now, Markdown) into VMPrint’s canonical document model (DocumentInput).
In short:
source -> transmuter -> DocumentInput -> renderer -> PDF
Instead of one monolithic formatter trying to do everything, each transmuter is responsible for interpreting a specific writing intent (academic, literature, manuscript, screenplay, general markdown).
You can keep your source in plain Markdown and target different output conventions by swapping transmuters/themes.
- Transmuters handle semantic interpretation
- Engine handles deterministic layout/pagination/rendering
draft2finalhandles orchestration (select transmuter, resolve config/theme, output PDF or AST)
This makes the system easier to reason about and extend.
New formats no longer require touching a monolithic compiler path. Transmuters can evolve independently with smaller, safer changes.
Shared Markdown compilation now lives in @vmprint/markdown-core, so multiple transmuters can reuse the same robust core behavior.
- New shared compiler package:
@vmprint/markdown-core - Refactored
@vmprint/transmuter-mkd-mkdinto a thin wrapper over markdown-core - Standardized transmuter contracts in
@vmprint/contracts - New transmuter packages:
@vmprint/transmuter-mkd-academic@vmprint/transmuter-mkd-literature@vmprint/transmuter-mkd-manuscript@vmprint/transmuter-mkd-screenplay
draft2finalreworked into a transmuter-first CLI- Documentation updates and tutorial/theme additions for onboarding
- Standard-font measurement/render encoding consistency fix
- Writers who want plain-text drafting without format lock-in
- Screenwriters/directors who need screenplay-style output from lightweight source
- Academics/students who need clean output while staying focused on content
This release lays the foundation for adding new format targets without reworking the entire pipeline.
v0.1.3: Full Bidi, Tiny Footprint: Arabic + RTL Done Without HarfBuzz!
This release is a substantial engine upgrade:
VMPrint now delivers full Unicode bidirectional text handling and materially improved Arabic/RTL rendering while keeping the runtime lean. We added complete UAX #9 bidi processing, improved shaping integration, and stabilized mixed LTR/RTL layout and rendering behavior, all without pulling in HarfBuzz or a heavyweight shaping stack.
The result is better correctness for real multilingual documents without compromising the small, deployable profile that makes VMPrint practical in browser, edge, and constrained environments.
v0.1.1 - Multi-Column Layouts, Zero-Byte Fonts, & Manuscript Format
A zero-asset FontManager that supports all 14 PDF standard fonts without requiring any font files to be installed or bundled.
- New
@vmprint/font-managers/standardpackage withStandardFontManager - Alias table covering all 14 standard fonts plus metric-compatible families: Arimo, Tinos, Cousine, Carlito, Caladea, Noto Sans, and Courier Prime
- Engine: sentinel detection in the font cache loader;
AfmFontProxybacked by static AFM metric tables (generated from PDFKit's.afmfiles); per-glyph advance widths and bounding boxes - AFM tables keyed by Unicode codepoint (not Adobe Standard Encoding) so extended characters — en-dash, em-dash, smart quotes, etc. — resolve correctly
contexts/pdf: suppresses font embedding for standard fonts and passes the PostScript name directly to PDFKit using WinAnsiEncodingfont-managers/local: added Symbol and ZapfDingbats aliases pointing to Noto Sans Symbols 2- Architecture documentation:
documents/STANDARD-FONTS.md
- Story packager extended with full multi-column layout support
- Column count, gutter width, and per-column flow are driven by the existing engine document model
- New engine regression test and fixture:
15-story-multi-column
- New industry-compliant
manuscriptformat fordraft2finalwith two themes: default and classic - Smart quotes and smart dashes applied automatically within manuscript documents
- Manuscript format includes its own config defaults, validator, and theme YAML files
- New layout snapshot fixtures:
manuscript-layout-sampleandmanuscript-classic-layout-sample draft2final/MANUSCRIPT.md— authoring and format reference
- New
VmprintOutputStreaminterface in@vmprint/contracts: a portablewrite/end/waitForFinishabstraction that callers implement against their own I/O transport Contextcontract now requires apipe(stream: VmprintOutputStream): voidmethod; no-op implementations are explicitly allowed for contexts that manage their own outputNodeWriteStreamAdapteradded in CLI anddraft2finalto bridge Node.jsfs.WriteStreamintoVmprintOutputStream, keeping filesystem I/O in the caller
The draft2final package was substantially restructured to make creating new formats straightforward and reduce per-format boilerplate.
- "Flavor" renamed to "Theme" throughout the codebase — themes are now the canonical term for format variants
- Each format (
academic,literature,markdown,screenplay) was extracted from a monolithic index file into a dedicatedformat.tsmodule with aconfig.defaults.yamland athemes/directory containing per-theme YAML - New shared compiler infrastructure under
draft2final/src/formats/compiler/:compile.ts— orchestrates format compilationconfig-resolver.ts— resolves layered configuration (defaults → theme → user overrides)format-context.ts— shared format rendering contextformat-handler.ts— base handler interfaceinline.ts— shared inline element compilationimage.ts— image handling utilitiesnumbering.ts— numbering utilitiestheme-loader.ts— theme YAML loadingmarkdown-base-format.ts— shared base for Markdown-derived formatsrule-based-handler.ts— declarative rule-based element dispatcher
build.tsandcli.tsupdated to use the new format registryformat-loader.ts(previouslyflavor-loader.ts) removed in favour of the newformats/index.tsregistry
Margin behaviour changed from collapsing to additive across the engine and all draft2final formats.
- Adjacent block margins now sum rather than collapse, matching standard typesetting conventions
- All
draft2finalformat themes (academic, literature, markdown, screenplay) updated with recalibrated margin values - All layout snapshot fixtures regenerated to reflect the new behaviour
- Engine:
paginate-packagers.tsupdated with the new margin accumulation logic
Variable font (.wdf / wght-axis) support has been removed from the engine and context to simplify font handling and make writing new contexts easier.
- Engine: variable-font axis resolution removed from
layout-utils.ts,text-processor.ts, andfont-registration.ts contexts/pdf: variable font subsetting code removed;fontkit.d.tsshim removed;pdfkit-fontkitdependency droppedfont-managers/local: variable font assets (ArimoVariable) replaced with four static TTF files (Regular, Bold, Italic, BoldItalic)contracts:FontManagerinterface simplified — variable-font fields removed- Engine font-management ops simplified accordingly
The --context flag has been removed from the CLI.
- The flag's pluggability was illusory: the undocumented two-argument constructor made third-party contexts non-functional
- The CLI is now an honest PDF tool;
PdfContextis used directly PdfContextconstructor simplified to(options: ContextFactoryOptions)only;pipe()now bridges via PDFKit'sdata/endevents intoVmprintOutputStreaminstead of accepting a Node.js stream directly- CLI's
--font-managerflag resolution fixed: bare package names are resolved viarequire.resolve; file paths viapath.resolve
- Superscript rendering in the engine (
engine/src/engine/layout/text-wrap-core.ts,rich-line-draw.ts) - AFM proxy
glyphForCodePointnow does a direct Unicode lookup, removing the intermediate WIN_ANSI_CODE_MAP that caused extended characters to resolve incorrectly
samples/directory restructured for discoverability:samples/draft2final/source/— source documents grouped by formatsamples/engine/tests/— all engine regression PDFssamples/overlay/— overlay pipeline outputs
documents/readme-assets/— README images and hero assets moved out ofdocuments/readme/- Removed stale
documents/ROADMAP.mdanddocuments/PERFORMANCE_OPTIMIZATION_LOG.md