Skill reference: mif-to-pdf
Skill reference: mif-to-pdf
Section titled “Skill reference: mif-to-pdf”The mif-to-pdf skill is a substrate helper: it converts a MIF JSON-LD
document into a real, typeset PDF — headings, lists, tables, links, and
figures actually rendered, not a plain-text dump of the body — while
embedding every frontmatter field the source carries into the produced
PDF’s own metadata. This reference describes its single input surface, how
it renders markdown and produces metadata, when it earns its place, and its
sources.
| Property | Value |
|---|---|
| Authors | One typeset PDF file carrying the source document’s complete frontmatter as richly structured metadata |
| Purpose group | Authoring helpers |
MIF conceptType |
substrate |
| Target MIF level | 3 (round-trips a document’s provenance/citations/relationships blocks) |
| Primary constraint | The PDF Info dictionary has no slot for non-standard fields; the SVG renderer covers only this suite’s own svg-charts output shape |
What this document type is
Section titled “What this document type is”mif-to-pdf does not author a document genre; it converts an already-MIF-
conformant JSON-LD document into a portable, single-file PDF rendering. The
skill has exactly one input surface — MIF JSON-LD — and does not parse
Markdown or YAML frontmatter itself. A Markdown source is converted to
JSON-LD first with this suite’s own existing tooling
(mif-convert emit-jsonld, the same projection mif-validate already
performs), so the frontmatter-parsing logic that lives in
scripts/lib/projection.mjs is never duplicated inside this skill.
How the skill produces one
Section titled “How the skill produces one”mif-to-pdf renders the body and writes its metadata in one pass, via
scripts/mif-to-pdf.mjs (pdf-lib, pure JavaScript, no native binary or
headless-browser dependency for everything except mermaid diagrams — see
below):
- Markdown rendering. The
contentfield is real markdown text, parsed and typeset — not wrapped as an undifferentiated blob. Most of the scope is exactly whatmif-validate’s own markdown-to-JSON-LD projection (scripts/lib/projection.mjs) round-trips losslessly: h1–h3 headings (bold, sized by level), paragraphs, flat bullet lists, bordered tables with a bold header row, inlinecode(monospace), bold text, and[text](url)/<url>links rendered as real clickable PDF link annotations (per ISO 32000-1 §12.5.6.5, the Link annotation subtype), not just colored text. Long bodies paginate rather than truncate. Constructs outside that round-trip-safe subset are handled too, since real documents contain them: fenced code blocks render as a legible monospace block labeled with the language tag, preserving each line’s exact spacing as long as it fits the page width (an overlong line falls back to word-wrapping, which loses that alignment). Single-level blockquotes (a fenced code block immediately inside one is unwrapped into its own code block, the one nested case handled) render with their>marker stripped rather than leaking it as visible text. mermaidfences render as real diagram images, not source text. Every other language’s fence renders as legible monospace source (see above); a```mermaidfence is rendered by an actual Mermaid layout engine — a headless Chromium instance launched via@mermaid-js/mermaid-cliand Puppeteer — and the resulting PNG is embedded in the page, the same way a figure is. This is the one genuinely non-offline-by-default part of the skill: Puppeteer downloads its own Chromium binary at install time (no network calls happen at conversion time — the render is fully local, but the binary itself is a real few-hundred-MB dependency this skill did not previously carry). A browser is launched once per document (shared across every mermaid fence in it, not one browser per diagram) and only when the document actually contains one. If a diagram fails to render — malformed Mermaid syntax, a rendering-engine error — the fence falls back to the same legible-source-text rendering as every other language rather than aborting the whole conversion.- Figures.
and<img src="path" alt="...">are resolved relative to the source JSON file’s directory and embedded, not skipped: PNG/JPG viapdf-lib’s native image embedding, and.svgvia a minimal vector renderer scoped to what this suite’s ownsvg-chartsskill produces (rect/text/line/circle/path/polyline/polygon,<style>-block or attribute-driven fill/font styling,<g transform="translate(dx,dy)">grouping — only the translate form, not rotate/scale/skew) — usingpdf-lib’sdrawSvgPathfor raw path data and manual coordinate mapping for the rest, sincepdf-libhas no built-in SVG rasterizer. A missing figure file draws a visible placeholder rather than silently vanishing. - Standard Info dictionary. Title/Author/Subject/Keywords/Creator/
CreationDate/ModDate are set from a best-effort mapping of the source
fields (ISO 32000-1 §14.3
defines the Info dictionary’s fixed key set). This mapping is necessarily
lossy: the Info dictionary has no key for
citations[]orrelationships[], which is exactly why the next two layers exist. - Structured XMP: real Dublin Core plus a typed
mif:tree. A/Metadatastream on the PDF’s document catalog carries actual Dublin Core properties (dc:title,dc:creator,dc:subject,dc:description,dc:identifier,xmp:CreateDate/xmp:ModifyDate— Dublin Core Metadata Element Set 1.1) plus a fullmif:-namespaced RDF/XML tree with one real, individually inspectable property per top-level MIF field: nested objects (provenance,entity, …) become nestedrdf:Descriptions, arrays (citations[],relationships[],tags[]) becomerdf:Seq— generically, via one recursive JS-value-to-RDF serializer, so a future extension field needs no new code to appear structurally. This is what makes the metadata genuinely readable by an XMP-aware tool without parsing JSON — the opposite of one opaque blob. mif:rawDocument: the losslessness guarantee. The complete source JSON-LD document is additionally embedded verbatim under this one property, per the XMP packet format (XMP Specification Part 1). Extracting and parsing just this property back must deep-equal the source document, field for field — proven by the skill’s own test suite (tests/mif-to-pdf.test.mjs), which converts a fully-populated L1–L3 fixture and asserts every source key survives, independent of whatever the typed Dublin-Core-plus-mif:tree above does or doesn’t yet special-case.- Input guard. Input missing a required MIF L1 field (
@id/conceptType/created) is rejected rather than silently converted into a garbage PDF — the skill has no undefined behavior for non-MIF JSON.
When it is beneficial
Section titled “When it is beneficial”Reach for mif-to-pdf whenever a MIF document needs a portable, readable,
single-file rendering that keeps its provenance, citations, and
relationships inspectable as real metadata, not only as prose in the body —
for example, handing a reviewer a document whose sourcing can be checked
with a metadata tool (pdfinfo -meta, or any XMP-aware reader) rather than
by re-reading the frontmatter, with its headings/tables/figures still
legible on the page.
Do not reach for it when the source is still Markdown — convert with
mif-convert emit-jsonld first, since this skill does not read frontmatter
— when the body uses markdown constructs outside this suite’s supported set
(nested/numbered lists, footnotes, raw HTML beyond <img>), which render as
literal text rather than being interpreted — when a figure is a
general-purpose SVG rather than this suite’s own svg-charts output shape,
which may render partially or not at all — or in an environment where
launching a local headless Chromium process is genuinely infeasible (a
heavily sandboxed or resource-constrained runner with no browser-sandbox
support), since any document containing a mermaid fence now depends on
that.
Example
Section titled “Example”A reviewer needs docs/reference/skills/mif-to-pdf.md — headings, tables,
and all — as one portable file with its citations and provenance still
attached as inspectable metadata.
node scripts/mif-convert.mjs emit-jsonld docs/reference/skills/mif-to-pdf.md > mif-to-pdf.jsonnode scripts/mif-to-pdf.mjs mif-to-pdf.json --output mif-to-pdf-reference.pdfThe result is a PDF with the document’s headings and tables actually
rendered, whose Info dictionary shows the title and keywords at a glance,
and whose XMP packet — inspectable with pdfinfo -meta mif-to-pdf-reference.pdf — shows real dc:title/dc:creator/
mif:provenance properties individually, while still carrying the full
provenance, citations, and relationships blocks losslessly under
mif:rawDocument.
Provenance & citations
Section titled “Provenance & citations”- PDF metadata streams and link annotations (the Info dictionary, the
/Metadataobject, and the Link annotation subtype): ISO 32000-1:2008, §14.3 and §12.5.6.5. - XMP packet format (the RDF/XML container for both the Dublin Core
properties and the
mif:tree): XMP Specification Part 1. - Dublin Core property set (
dc:title/dc:creator/dc:subject/dc:description/dc:identifier): Dublin Core Metadata Element Set 1.1. - PDF generation library: pdf-lib — pure
JavaScript, no native binary, used via its low-level context API to
attach the custom XMP stream and Link annotations (no high-level API for
either exists in pdf-lib 1.17.1) and its
drawSvgPathhelper for the embedded-SVG figure renderer’s path data. - Mermaid diagram rendering: @mermaid-js/mermaid-cli’s
programmatic
renderMermaidAPI, run against a Puppeteer-launched headless Chromium — the only part of this skill that depends on a browser binary or draws PDF content from anything other than pdf-lib’s own primitives. - Skill provenance: authored by the
mif-to-pdfskill in the mif-docs plugin, https://github.com/modeled-information-format/mif-docs-plugin. - MIF conformance: projects to canonical JSON-LD under the MIF specification, https://mif-spec.dev, proven lossless by mif-validate.
- Index: one entry in the skills by purpose catalog, in the Authoring helpers group alongside mif-frontmatter and mif-validate.