PDF Export Engine
PDF Export Engine (@atlcli/pdf)
Section titled “PDF Export Engine (@atlcli/pdf)”packages/pdf is the host-neutral preparation, Typst serialization, validation, and export
orchestration layer. It consumes the same structured Confluence ExportBlock[] tree as the
DOCX engine, but PDF and DOCX remain independent pipelines with format-specific ports, reports,
and output semantics.
The low-level Typst-WASM implementation lives in the private browser-only package
@atlcli/pdf-compiler-browser. A host injects it through PdfCompilePort; importing
@atlcli/pdf or @atlcli/pdf/browser does not pull compiler or WASM code into preparation-only
consumers. Authentication, worker/job topology, persistence, cancellation policy, download/save
behavior, and UI remain host-owned.
Architecture
Section titled “Architecture”Confluence storage -> ExportBlock[] -> @atlcli/pdf -> PdfCompilePort -> PDF bytes ^ | | +-- browser: @atlcli/pdf-compiler-browser +-- assets/output supplied by the hostThe extension implements PdfCompilePort over its offscreen document, dedicated worker, and
IndexedDB job store. The neutral Vite harness uses a direct module Worker and in-memory output
sink. These are intentionally different topologies exercising the same package contracts.
Built-in document design
Section titled “Built-in document design”The standard template is a brand-neutral editorial A4 design. It bundles Source Serif 4 for flowing body copy, Source Sans 3 for headings, tables, metadata and other structural text, and Source Code Pro for code. Body copy uses 10 pt text, a relaxed 0.74 em leading value, and 10 pt paragraph spacing. Heading levels use progressively larger separation so a heading remains visually attached to the content it introduces while sections are easy to scan.
The Editorial Indigo cover uses a warm paper tone, a Source Serif title and a left-aligned
metadata rail. It is followed by the table of contents and does not display a page number.
The running header preserves the page title and space key above a fine horizontal rule;
the centered footer contains the page number. An automatically generated document-integrity
page closes every export with the document title, version, export date, final page count and a
clickable link to atlcli.sh; it does not repeat the running header. Unordered list levels use an en dash, filled
bullet and open bullet; ordered levels use 1., a) and i.. Task lists use standalone
checkbox markers without an additional bullet. Tables preserve meaningful authored column
widths. Equal default widths may be replaced by a
conservative content-aware ratio when one narrative column is substantially longer than the
remaining short status columns. Complex tables and balanced prose tables remain unchanged.
Very wide tables
Section titled “Very wide tables”Tables with at least nine effective columns keep the standard A4 portrait page and the existing column calculation, but use an adaptive inline policy for values that otherwise behave like indivisible UI elements. Ordinary cell prose remains Source Sans 3 at 9 pt with language-aware hyphenation. Dense cells reduce horizontal padding from 6 pt to 2 pt and use Typst’s simple line breaker; the optimized breaker can deliberately accept visibly overfull lines at these extreme widths. Tables below the dense threshold retain optimized line breaking and their existing 6 pt padding.
- A raw HTTP(S) URL first uses its complete visible form. If it does not fit, the renderer
tries
hostname/…and then a delimiter-aware, wrapping hostname. The PDF annotation always retains the complete original target. Custom human-readable link labels are never shortened. - A status always remains a colored badge with its complete label. Badges use Source Code Pro Bold, try normal and reduced horizontal padding, and finally wrap the complete label inside the available cell width while retaining their background, foreground color, and radius.
- Mentions keep their complete display name. In dense cells, an invisible break opportunity
after
@and after safe account-ID delimiters prevents technical identifiers from painting into the next column. These break characters are rendering-only and do not change the source model.
The exporter does not automatically switch page orientation, clip a paragraph or table cell, or shrink every table font. Landscape pages and user-configurable wide-table policies remain outside the current standard template.
Code highlighting
Section titled “Code highlighting”RunPdfExportInput.codeTheme accepts the same generated Shiki theme IDs as
DOCX and defaults to github-light. Highlighting happens during preparation,
before the durable render checkpoint: prepared blocks contain explicit token
text, RGB colors, and the selected theme background. Typst only lays out those
tokens; it does not choose a second syntax theme.
This keeps preview, direct export, recovered background jobs, and DOCX/PDF
color semantics aligned. PdfExportReport.codeTheme names the effective ID.
Unknown languages degrade to plain readable code and a report note.
Runtime matrix
Section titled “Runtime matrix”| Component | Pinned value | Verification |
|---|---|---|
| Web compiler wrapper | @myriaddreamin/typst-ts-web-compiler 0.7.0 |
Exact package version and Bun patch |
| Embedded Typst engine | 0.14.2 | PDF Creator metadata and compiler fixture |
| Compiler WASM | SHA-256 1fc968438a672366dfec39c96c842c26ed29caff4eb1bcaab19a6c60867de5fd |
Build inventory gate |
| Source Sans 3 Regular / Italic / SemiBold / Bold | Adobe commit and SHA-256 values pinned in ensure-fonts.ts |
Build fetch and inventory gates |
| Source Serif 4 Regular / Italic / SemiBold / Bold | Adobe commit and SHA-256 values pinned in ensure-fonts.ts |
Build fetch and inventory gates |
| Source Code Pro Regular / Bold | Adobe commit and SHA-256 values pinned in ensure-fonts.ts |
Build fetch and inventory gates |
Each production browser host artifact includes the 28.3 MB compiler WASM, ten static font files and their shipped license texts. The build gates fail if any runtime asset is absent, the WASM is unexpectedly small, or generated JavaScript contains a known Manifest V3-incompatible dynamic-code constructor.
The TTF binaries are not stored in Git. bun run build, extension development, extension
typechecking and the PDF fixture first run fonts:ensure. It downloads missing files from
immutable Adobe commit URLs into the gitignored packages/pdf/.fonts/ cache and installs a
file only after its SHA-256 value matches the manifest. A valid cache performs no network
request. OFL license texts remain tracked and ship in the extension. PDF export itself never
contacts Adobe, Google Fonts, Fontsource or another font service.
Neutral export flow
Section titled “Neutral export flow”- Convert Confluence storage to exhaustive
ExportBlock[]values. - Resolve approved assets through the host’s
PdfAssetResolverand render Mermaid through@atlcli/diagram. - Serialize deterministic
main.typ, the pinned template, assets and nested source mappings. - Compile through the injected
PdfCompilePortand normalized diagnostics contract. - Validate pages, tag structure and embedded font programs.
- Emit through the host’s
PdfOutputSink, with an abort check before emission. The sink receives aPdfBytesHandlerather than the byte array, so a host that needs aBlobor an object URL asks the handle for one instead of building a second copy of the whole document — see Emitting compiled bytes.
The extension adapter additionally stores binary jobs in IndexedDB, sends bounded control
messages, compiles FIFO in its offscreen worker, downloads as application/pdf, and removes job
state in finally. Those policies are not part of @atlcli/pdf or the compiler package.
The completion report shows total time together with preparation, compilation, and download time. Preparation includes attachment resolution and Mermaid rendering, which makes network- or asset-heavy exports distinguishable from compiler time.
Cancellation terminates an active compiler worker. A 60-second timeout also terminates it, so the next attempt starts in a clean compiler and virtual filesystem rather than merely rejecting an unresolved promise.
Browser conformance harness
Section titled “Browser conformance harness”apps/browser-export-harness is a private vanilla Vite consumer that imports only public package
exports. Its production artifact is served below a nested path with a local CSP and exercised by
Playwright Chromium. The test performs a real Worker/WASM/font compile, verifies deterministic
warm output and abort-without-emission, and scans all JavaScript and assets for native-runtime or
extension leaks. This is package conformance evidence, not certification for every browser host.
Verification fixture
Section titled “Verification fixture”Run the deterministic feature fixture locally:
bun run --cwd apps/extension pdf:fixturepdfinfo tmp/pdfs/pdf-export-feature-zoo.pdfpdftoppm -png tmp/pdfs/pdf-export-feature-zoo.pdf tmp/pdfs/pdf-export-feature-zooThe fixed fixture produces an A4 document with title and author metadata, outline, internal TOC links, semantic tags, embedded font programs, highlighted code, a native vector Mermaid diagram, a normal four-column table, and a synthetic fourteen-column dense table. The dense section covers full-target raw links, custom link labels, complete visual status badges, mentions, and normal wrapping prose. A warm repeat compile is required to be byte-identical.
Known profile boundary
Section titled “Known profile boundary”Standard export requires tagged output and rejects an untagged result. The pinned compiler does not expose a PDF/UA-1 selector. Therefore the engine deliberately makes no PDF/UA or PDF/A claim; adding either profile requires a separately validated implementation and independent conformance evidence.
Related topics
Section titled “Related topics”- PDF Template Settings
- PDF Template Contract — the
wiki.pdf-template/v1render contract. - Template Pack Format — the
.wiki-pdf-templatesharing container. - DOCX and PDF Export
- DOCX Export Engine