All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog.
This release gathers the engine work since the last GitHub release into one public milestone. The headline is mixed page geometry: VMPrint can now resolve different page sizes and margins within a single document, carry those resolved dimensions through the layout stream, and render matching PDF media boxes.
- Document-level page templates:
layout.pageTemplatescan override page size, orientation, and margins by zero-basedpageIndexor by selectors such asfirst,odd,even, andall. - Mixed-size PDF output: Renderers receive resolved
page.widthandpage.heightper page, so saved layout streams and direct renders preserve odd-sized sheets instead of forcing every page back to the document default. - Partial simulation:
engine.layout({ stopAtPage })and lower-level simulation options can intentionally stop after an inclusive zero-based page prefix, with reports marking the stop reason aspage-limit. - Flow-friendly engine substrate: The runtime now has stronger hosted-region, world-plain, and persistent child-actor behavior, including live mutation paths for zone-hosted and story-hosted content.
- Exclusion assembly and shape work: Added weighted exclusion assemblies, compression/generation tooling, circle and ellipse exclusion support, polygon carry-over, and a micro-lane policy for controlling tiny wrap lanes.
- Text and rendering capabilities: Added letter spacing support, CSS/browser line-height calculation mode, a contract-level text delegate surface, and pre-resolved renderer font handling.
- Authoring and documentation coverage: Updated the quickstart, AST reference, CLI reference, page-control guide, engine README, architecture docs, internals guide, docs index, and VMPrint authoring skill for the new page geometry and partial simulation surfaces.
- Renderer architecture: Refactored rendering around
ContextRenderer, separating box traversal from context-specific drawing and trimming stale renderer surfaces. - Engine runtime ownership: Moved more layout subsystems into runtime-owned boundaries, tightened session/collaborator coordination, and made capture and region identity clearer in the simulation report.
- Page identity model: Reduced brittle
pageIndex * pageHeightassumptions by carrying chunk/frontier state more explicitly through checkpoints, provenance, redraw, hosted-region settlement, and finalization. - Repository and release workflow: Clarified the shared-engine sync workflow, contracted the repository around the engine/CLI/docs, and kept companion runtime packages external to the CLI bundle.
- Browser demo evolution: The docs playground gained engine-native selection, cross-actor copy, copy-as-Markdown behavior, improved bidi selection highlighting, and a richer dashboard-style preview surface.
- Empty trailing page in odd-size documents: The new page-template fixture now produces only the intended pages, with no blank page after the second sheet.
- Deferred total-pages materialization: Finalized page publication now exposes deferred header/footer content in page-region summaries.
- Contained text stability: Fixed contained grapheme overflow, strict contained line-box wrapping, contained host-width import, and assembly lane caps.
- Splitting and continuation stability: Fixed constrained-height paragraph splitting, hosted-region orphan-limit candidates, spanning-zone recovery, table continuation metadata, and zone overlays.
- Performance regressions: Restored fast paths around ASCII segmentation, cached cluster/font resolution, optional interaction-map construction, and the temporal presentation collaborator path.
- Packaging and typings: Refreshed publish-time typings, dual CJS/ESM exports, CLI runtime bundling, and packaged integration smoke checks.
pressrunBootstrap Example: Added a minimal, non-packaged bootstrap program underpressrun/to serve as the simplest practical engine integration example.
- Repository Contraction and Repositioning: Removed the in-repo preview package, static docs site, generated API docs, and related build scripts so the repository now centers on the engine, the CLI, focused guides/references, and the small
pressrunbootstrap. - Engine-First Public Surface: Introduced the simplified
VMPrintEngine/loadDocumentsurface and rewired the CLI to use that higher-level API for its normal render path, while keeping the olderLayoutEnginebootstrap path available as a supported advanced surface. - Developer-Facing Documentation Refresh: Reworked the quickstart and package-facing docs to match the narrower audience and current structure, with
pressrunpositioned as the hello-world example and the CLI positioned as the operational tool rather than the canonical bootstrap. - Contracts Positioning Update: Reframed
contracts/as a workspace-local and source-copy contract layer instead of a repo surface actively positioned as a public package for extension authors.
- CLI Warm Profiling Semantics: Restored
vmprint --profile-layoutwarm timing to the historical warmed-runtime behavior by reusing and priming a shared profiling runtime, avoiding misleading regressions caused by rebuilding a fresh engine and font manager for each warm sample. - Root Test Workflow: Updated the packaged integration smoke test path so root
npm testbuilds the required workspace artifacts before checking packaged output. - Workspace Lockfile Hygiene: Removed stale preview workspace metadata from
package-lock.jsonafter the repo split.
- Standalone Package Infrastructure: Successfully decoupled the repository into a set of independent, publishable npm packages for contexts, font managers, and transmuters.
- Local Theme Assets: Added self-contained YAML themes to
docs/examples/mkd-to-astto ensure the browser demonstration is fully functional without external repository dependencies. - Zero-Config Browser Preview: Introduced a standalone browser preview example in
docs/examples/previewthat demonstrates the complete@vmprint/previewworkflow.
- Repository Cleanup: Removed obsolete local directories (
contexts/,font-managers/,transmuters/) that are now published as independent packages in the@vmprintorganization. - Standardized Documentation Examples: Updated all examples in
docs/examples/to resolve dependencies fromnode_modulesinstead of internal source aliases, matching real-world usage patterns. - Dual-Mode Package Updates: Updated
@vmprint/preview(v1.0.1) and other core packages for robust dual-mode (ESM and CommonJS) support. - Externalized Contracts: Standardized
@vmprint/contractsas a shared external dependency across the bundling pipeline to prevent code duplication in browser environments. - Streamlined Build Process: Simplified
scripts/build-docs-examples.mjsandpreview/scripts/build-demo.mjsby removing complex workspace workarounds in favor of standard npm resolution.
- Doc Build Resolution: Resolved a build failure in the Markdown-to-AST example caused by missing external theme references.
- Static Examples Archive: Fixed the
vmprint-static-examples.zipbuild process to correctly include all required assets for the new decoupled architecture.
- Rebuilt the engine around an explicit simulation kernel, session world, placement runtime, collision runtime, physics runtime, transition runtime, and lifecycle/event dispatch infrastructure instead of a paginator-centered control loop.
- Introduced the collaborator model for engine-owned coordination concerns such as keep-with-next planning, continuation artifacts, page reservations/exclusions, page regions, heading telemetry, transform capabilities, script runtime integration, and debug overlays.
- Added simulation reports and report readers so benchmarks, diagnostics, and downstream tooling can consume post-layout facts without reaching into layout-session internals.
- Added restore-point and snapshot machinery that makes speculative layout, rollback, and deterministic replay first-class engine behavior.
- Added a post-settlement scripting runtime with document and element lifecycle hooks, direct messaging, receiver-oriented mutation, and structural replacement, insertion, and deletion flows.
- Added script-focused packagers and fixtures covering ready/refresh timing, live replacement, insertion, deletion, and cross-actor interactions.
- Added a dedicated
documents/SCRIPTING-API.mdreference and expanded authoring documentation for runtime document behavior.
- Added block-level floats for non-image content inside stories when explicit dimensions are provided.
- Added story column spanning via
properties.columnSpan, including full-width spans inside multi-column stories. - Added
zone-mapas a first-class layout primitive for bounded side-by-side regions with independent strip layout. - Added strip-layout and zone continuation coverage, plus new regression fixtures for nested-table continuation, nested-story continuation, live TOC reactivity, and total-pages footer scenarios.
- Upgraded the document model to AST 1.1 and refreshed engine fixtures plus transmuters to emit and consume the newer shape consistently.
- Formalized blueprint preprocessing so
onLoadandonCreaterun as a distinct preprocessing phase before layout settlement. - Kept AST-driven authoring first-class while aligning the engine internals with the new simulation runtime.
- Added
@vmprint/context-canvas, which builds SVG-backed page scenes and renders them into canvas targets for live browser preview. - Added
@vmprint/web-fonts, a browser-first font manager with remote font loading and optional persistent caching. - Added browser demos for AST-to-canvas and AST-to-pdf web-font workflows, and expanded the docs examples index to showcase them.
- Made actor formation, splitting, continuation ownership, and placement negotiation explicit in the substrate instead of inferred late in pagination.
- Moved geometry authority toward the spatial subsystem and session runtime, reducing special-case orchestration in packagers.
- Unified flow, table, drop-cap, and continuation behavior around shared fragment-state and session-managed artifact generation.
- Reworked text, image, and table layout paths to cooperate with the simulation runtime while preserving deterministic output.
- Rewrote the README around the simulation model, scripting surface, browser story, and architecture direction for the 1.0 release.
- Added
documents/ENGINE-INTERNALS.md, a multi-part authoring guide underdocuments/authoring/, and broader architecture/API refreshes across the docs set. - Updated examples, fixtures, and authoring references to match AST 1.1, zone maps, column spans, scripting, canvas rendering, and web fonts.
- Promoted the workspace packages, including
@vmprint/engine, to1.0.0. - Corrected
draft2finalfrom an accidental rollback to1.0.0on 2026-03-18 and released it as1.0.3.
- Restored the intended
draft2finalversion progression after the cleanup-pass regression from1.0.2to1.0.0. - Fixed transmuter compatibility with AST 1.1 and resolved the mkd-to-ast version mismatch in the browser demo pipeline.
- Optimized static-demo payloads and canvas/browser packaging so the browser examples are viable release artifacts rather than experimental leftovers.
- Fixed long-document snapshot handling during the simulation overhaul.
- Fixed
finalizePagesWithCallbacksduring the late 1.0 cleanup cycle. - Preserved deterministic regression coverage across the architecture rewrite with expanded engine, scripting, strip-layout, spatial-IR, and browser-facing test assets.
- Paragraph-level
direction: autoresolution was hardened so mixed LTR/RTL lines consistently use the paragraph base direction instead of drifting line-by-line. - Improved bidi run handling for neutral segments (especially spaces and punctuation) to prevent Arabic/Hebrew phrase fragmentation in mixed-language paragraphs.
- Neutral whitespace now inherits the active script/font run during segmentation, reducing incorrect LTR space splits inside RTL phrases and improving render order stability.
- Added and expanded regression coverage for auto-direction and mixed bidi rendering (
engine/tests/auto-direction.spec.ts, module extraction assertions).
- Refreshed engine regression layout snapshots to reflect deterministic output after the bidi/segmentation fixes.
- Fixed
engine/tests/fixtures/regression/generate-fixture-pdfs.mjsso16-standard-fonts-pdf14.jsonusesStandardFontManagerinstead ofLocalFontManager. - Resolved fixture generation failure:
[FontProcessor] Requested font family not registered: Symbol.
- Bumped monorepo version to
0.3.1. - Bumped
draft2finalpackage version to1.0.2.
- Draft2Final and the vmprint CLI now selectively auto-download massive CJK and complex script fonts from the jsDelivr CDN, caching them persistently in the user's
~/.vmprint/fontsdirectory. - Added extensive language mappings in
LocalFontManagerfor global fallback support (Hebrew, Bengali, Tamil, Telugu, Malayalam, Gujarati, Kannada, Gurmukhi, Khmer, Lao, Sinhala, Arabic, and Indic scripts).
- The
draft2finalorchestrator is now distributed as a single 4.4MB compiled executable viatsup, drastically improving global installation speed, execution startup time, and cross-platform reliability. - Smart Asset Bundling: The essential Latin Pack fonts (Caladea, Cousine, Arimo, Tinos, Courier Prime) and core PDF metrics are bundled directly in the
@draft2final/clidistribution for instant out-of-the-box offline support.
- Interactive Scaffolding: Added
draft2final --init <project>command to instantly generate new Markdown, Config, and Theme boilerplate. - Progress Tracking: Concurrent background downloads for global fonts now display a smooth, unified terminal progress indicator using the Web Streams API.
- Added
-v/--versionflags and improved stage timing logs.
- The core CLI and Draft2Final both deeply scan the Document AST prior to layout to extract literal used characters. The engine instantly prunes and disables unused fallback fonts to prevent unnecessary network downloads.
- Extracted heavy 50MB+ CJK font binaries (Noto Sans JP, KR, SC) to an orphan
assetsGit branch to keep the core developer repository lean and extremely fast to clone.
- Stopped standard English punctuation (like the em-dash) from erroneously triggering heavy Chinese/Japanese fallback font downloads by removing overlapping general punctuation blocks from the CJK Unicode ranges.
- Prevented terminal flickering and layout overlaps during concurrent multi-font JIT downloads.
- Added a new follow-along user tutorial at
draft2final/TUTORIAL.mdcovering technical manual, screenplay, manuscript, and format remix workflows - Added a dedicated
tutorialtheme formkd-mkdatdraft2final/themes/mkd-mkd/tutorial.yamlwith guidebook-oriented typography and spacing - Added tutorial sample outputs under
samples/tutorial/including generated PDF/AST artifacts
- Extracted shared Markdown compilation logic into the new
@vmprint/markdown-coreworkspace - Refactored
@vmprint/transmuter-mkd-mkdinto a thinner wrapper around shared markdown-core functionality - Standardized transmuter contracts by moving shared types into
@vmprint/contracts - Updated docs example assets and configuration flow to keep theme YAML ownership explicit
- Updated tutorial command style for end users to prefer
draft2final ...examples over dev-only invocation patterns - Added document-level tutorial frontmatter config for typography/drop-cap behavior without changing global defaults
- Added opening-paragraph drop-cap support in markdown-core via document config (
dropCap.openingParagraph)
- Fixed a rendering/measurement mismatch so standard-font text measurement and PDF output now use the same encoding path
- Removed deprecated
showPageNumbersusage from AST-to-PDF docs fixtures - Refreshed docs to align with the markdown-core extraction and updated transmuter structure
- New comprehensive documentation at
documents/AST-REFERENCE.mdcovering the complete VMPrint document input format - Detailed reference for every supported node type, property, style field, and configuration option
- Examples for
DocumentInput,LayoutConfig, elements, and page regions
- Complete implementation of Unicode Bidirectional Algorithm (UAX #9) for proper RTL/LTR text handling
- New
bidi-jsdependency added to engine for embedding level calculation - New
splitByBidiDirection()function intext-script-segmentation.tsfor BIDI run segmentation - Intelligent neutral character handling - spaces and punctuation between LTR/RTL runs are now properly assigned based on neighboring strong characters
- New engine test fixture:
18-multilingual-arabicwith comprehensive Arabic and mixed bidi layout coverage
- RTL text now renders with full UAX #9 compliance
- Mixed LTR/RTL text within paragraphs now displays with correct visual ordering
- Arabic text shaping correctly applies contextual forms (initial, medial, final, isolated) with proper glyph connection
- Embedded LTR runs within RTL paragraphs (and vice versa) now render in the correct visual order
- Fixed item-order reversal for LTR runs within RTL lines to ensure proper visual placement
reorderItemsForRtl()now respects pre-computed BIDI direction from layout engine instead of re-sniffing text- Text processor measurement cache keys now include direction and script class for context-aware caching
- Font shaping integration improved - script tags (
arab,deva,thai, etc.) and direction (ltr/rtl) now properly passed to fontkit - RTL runs now use explicit OpenType feature list for consistent shaping across measurement and rendering
- All layout snapshot fixtures regenerated to reflect the improved bidi handling
- README updated to remove note about partial RTL/bidi support - full support is now implemented
- All language showcase images regenerated with improved bidi rendering
A lightweight PDF rendering context powered by jsPDF for embeddable and browser-friendly PDF output.
- New
contexts/pdf-litepackage - Packaged integration coverage for the built engine + standard fonts + pdf-lite stack
- Root build now includes the pdf-lite workspace
- New self-contained static AST-to-PDF showcase under
docs/examples/ast-to-pdf/ - New self-contained static Markdown-to-AST showcase under
docs/examples/mkd-to-ast/ - Example bundling/build pipeline added under
scripts/build-docs-examples.mjs docs/README.mdand example landing pages expanded to cover the static demos
- New
@vmprint/transmuter-mkd-mkdpackage for converting Markdown into VMPrintDocumentInput - Theme-aware transmutation with bundled default, novel, and opensource themes
- New transmuter documentation under
transmuters/README.mdandtransmuters/mkd-mkd/README.md
- New top-level
header/footerdocument regions withdefault,firstPage,odd, andevenselectors - New per-element
pageOverridesfor page-local header/footer replacement or suppression - New physical/logical page-number token substitution in region content
- New engine regression fixture and design docs for page-region behavior
- New
noveltheme fordraft2finalmarkdown output - Matching bundled
noveltheme for the Markdown transmuter - New layout snapshot coverage for the markdown novel sample
- Rich inline baseline alignment and rendering metrics were tightened engine-wide
- Renderer and debug drawing paths were updated to match the new rich-line metrics flow
- Header/footer geometry now lives inside page margins rather than spanning the full page width
- Region content is laid out under a region-local, non-paginating context and clipped to the available margin box
- Theme loading now supports document-level
header/footerdefinitions in addition to layout and styles - Markdown themes were updated to use page-region-driven folios instead of the old flat page-number settings
- Test fixtures and layout snapshots were expanded for the new region model
@vmprint/transmuter-mkd-mkdbuild breakage in the bundlednoveltheme source- Packaged integration flow after a clean root build by ensuring pdf-lite artifacts are generated
- Header/footer regression fixtures and assertions so they validate the intended margin-bounded region model
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:
execute-simulation-march.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