The previous posts covered the rendering pipeline: the .vpdf format, Hierarchical Tables, Signature Zones, and the audit trail. This one is more hands-on. It covers how you actually write the YAML files that power Structured Content and Supplementary Annex blocks, what each block type requires, where most authoring mistakes happen, and how the VPDF Blueprint Validator catches those mistakes before The REFRACT Engine ever sees the file.
If you've spent time writing blueprint YAML by hand and had it fail silently at render time, this is the post you wanted to read first.
What a Blueprint File Is
When a template contains a structured_content or supplementary_annex block, that block references a separate YAML asset stored in SharePoint. The YAML file is the blueprint. It defines the document section independently of the template, with its own block structure, conditional rules, and data bindings.
The separation matters for a practical reason. A subcontract terms section can live in one file and be referenced by multiple templates. When Legal updates a clause for a new jurisdiction, they update one blueprint file. Every template that references it picks up the change on the next render, with no template edits and no developer queue.
A minimal blueprint looks like this:
↳A complete section blueprint: heading, paragraph, important note, and a two-column signature block — four blocks, enough for a fully rendered document section.
Four blocks. Two required top-level fields beyond documentType and version. That's enough for a complete document section. The four required root-level fields for any blueprint are documentType, version, title, and sections.
The Ten Block Types
Every entry in the sections array must have a type field. The REFRACT Engine recognises exactly ten type values.
heading
- type: heading
level: 2
text: "4.1 Change Orders"
level accepts 1, 2, or 3. Level 1 renders as a primary section heading, level 2 as a sub-heading, and level 3 as a tertiary label. The Table of Contents is built from heading blocks at levels 1 and 2 unless you configure maxDepth in templateSettings.
paragraph
- type: paragraph
text: "The Subcontractor shall furnish all **labour**, __materials__, and
==special equipment== as described in the accompanying specifications."
The text field supports four inline formatting tokens: **bold**, __underline__, ==highlight==, and _italic_. Multi-line strings use standard YAML folded or block scalars. All other Markdown syntax is treated as literal text. No HTML is interpreted.
list
- type: list
style: bullet
items:
- "Site clearing and grading per issued drawings"
- "Foundation formwork and concrete placement"
- "Structural steel erection (see {{structuralSpec}})"
- "Electrical rough-in per {{electricalSpec}}"
style is either bullet or ordered. The items array is required and must contain at least one entry. Items are plain strings and support the same inline formatting tokens as paragraph.
note
- type: note
variant: warning
text: "Failure to obtain a signed Change Order before commencing changed
work may result in non-payment for that portion of the work."
Six valid variants: info, warning, error, success, important, and neutral. Each renders with a distinct left-border colour: sky blue, amber, red, green, rose, and slate, respectively. variant is required. An unrecognised variant value is a validation error, not a silent fallback.
clause
- type: clause
number: "4.1.1"
title: "Initiation of Changes"
text: "No changes to the scope of work shall be made without a written
Change Order executed by both parties and referencing Contract No. {{contract.number}}."
subclauses:
- text: "Emergency verbal authorisations must be confirmed in writing within 48 hours."
- text: "All approved changes shall be recorded in the project log at {{projectLog.url}}."
clause is designed for numbered legal and contractual provisions. number and title are optional display decorators. subclauses is an array of objects, each with its own text field. A clause block with no text and no subclauses is technically valid but produces empty output.
signature_block
- type: signature_block
title: "Authorised Signatures"
columns: 2
signatories:
- name: "{{owner.name}}"
role: "Owner's Representative"
date: "{{contract.date}}"
- name: "{{subcontractor.name}}"
role: "Subcontractor"
date: "{{contract.date}}"
columns controls how many signature columns appear side by side. signatories defines each signer's name, role, and date, all of which accept {{token}} bindings resolved from the runtime payload. When verification.signatureZones is enabled in templateSettings, Signature Zones compatible with DocuSign, Adobe Sign, and Dropbox Sign are overlaid on these blocks at render time.
checkbox and radio
- type: checkbox
label: "Site safety conditions reviewed and confirmed"
checked: true
- type: radio
label: "Payment method: EFT (Electronic Funds Transfer)"
selected: true
- type: radio
label: "Payment method: Cheque"
selected: false
Both types render a visual form element in the PDF. They are display-only; they do not produce interactive PDF form fields. label is required for both. checked and selected accept boolean values and control the rendered state of the element. A radio group is simply two or more consecutive radio blocks with one set to selected: true.
page_break
- type: page_break
No additional fields required. Inserts a hard page break at that position in the section. Useful for structuring multi-section documents where a new major topic should always begin on a fresh page.
The condition Field
Every block type accepts an optional condition field. It takes a JavaScript expression that The REFRACT Engine evaluates against the conditionContext object passed in the runtime payload.
Add an imageSrc prop to show a real PDF screenshot
↳The condition field accepts a JavaScript expression evaluated against conditionContext at render time. Falsy blocks are silently omitted — no empty space, no placeholder, no ghost Table of Contents entry.
When conditionContext.contract.isUK is falsy, both the heading and the note are omitted entirely from the rendered output. No empty space. No placeholder. The blocks do not exist in the output PDF.
This is the mechanism that lets one blueprint file cover multiple document variants. A subcontract that handles UK statutory provisions, Australian WHS requirements, and a standard international version is one file with conditional blocks, not three separate files with diverging content that someone has to keep in sync.
The expression is a strict subset of JavaScript, evaluated with the conditionContext as the variable scope. Deep property access (contract.region.code), comparison operators, and logical operators (&&, ||, !) all work. The expression must resolve to a truthy or falsy value. Expressions that throw are treated as falsy and the block is suppressed.
supplementary_annex Blueprints
A supplementary_annex blueprint uses the same block types as structured_content but adds a tenth: supplementary_Annex (capital A, matching the internal type registry). This block drives the per-item repeating evidence sections.
Add an imageSrc prop to show a real PDF screenshot
↳The supplementary_Annex block iterates every item in data_source and generates a self-contained section per item: themed header, notes paragraph, and photo grid. Items without notes or images are skipped automatically.
The supplementary_Annex block has two required fields that have no equivalent in other block types:
data_source: a{{token}}binding that resolves to the array of items to iterate over.item_template: the layout applied to each item. It accepts three sub-types:sub_header,repeat_notes, andimage_grid.
The renderer iterates every item in data_source, applies the item_template to produce a self-contained section per item, and assembles those sections at the end of the document. Items without notes or images are conditionally skipped based on field presence.
Images referenced via images_field are pre-fetched from SharePoint and downsampled by The Image Lab Node before embedding. target_dpi and image_quality control the output size. For a 150-page annex with 200 photos, that pre-fetch and downsampling step runs in parallel across Isolated Rendering Workers, which is why a large annex does not block the primary document sections from rendering.
Where Blueprint Files Break
Most blueprint failures at render time fall into one of four categories.
Wrong block type name. Naming a block para instead of paragraph, or sig_block instead of signature_block. The REFRACT Engine does not attempt to guess intent. Unrecognised types are ignored in some render paths and throw in others, depending on where in the pipeline the block is encountered.
Missing required fields. A list block without a style field, or a supplementary_Annex block without item_template. No error appears at storage time because the YAML parses correctly. The failure surfaces at render time when the renderer tries to access a field that is not present.
Invalid variant on a note block. The valid values are info, warning, error, success, important, and neutral. Alternatives like caution, alert, or critical fall through to the default renderer path, which may produce visible output in some versions and nothing at all in others.
Structural errors inside item_template. Each item_template sub-type has its own required fields. A sub_header without text, or an image_grid without source, produces an empty block in the annex output that looks like a layout bug rather than a validation problem.
None of these issues surface when you open the YAML file in a text editor. They surface at render time, in a document that has already been delivered, or in a pre-deployment review that has to go back through the approval chain.
The VPDF Blueprint Validator
The VPDF Blueprint Validator is a static analysis tool for both blueprint file types. It runs entirely in your browser. Nothing is uploaded, no server call is made, and no data leaves your machine.
Open it, paste your YAML, and analysis begins immediately.
What it checks
The validator runs the following rules:
- Document-level required fields:
documentType,version,title, andsectionsmust all be present. - Valid
documentType: must bestructured_contentorsupplementary_annex. - Unknown block types: any
typevalue outside the ten valid types is flagged as an error with the block index in the path. - Missing required fields per type:
listrequiresstyleanditems,supplementary_Annexrequiresdata_sourceanditem_template, and so on for all ten types. - Invalid
variantonnoteblocks: all six valid values are checked explicitly. - Invalid
styleonlistblocks:bulletandorderedare the only accepted values. - Heading
levelout of range: levels 1, 2, and 3 are valid; anything outside that range is flagged. item_templateblock validation: every entry insideitem_templateis validated independently for known type and required fields.
Errors appear in the Blueprint Insights sidebar immediately as the validator processes the document. Warnings appear for conditions that parse correctly but may produce unexpected output, such as a clause block with no text and no subclauses.
The Block Preview panel
The Block Preview panel is the part of the tool that changes how blueprint authoring works in practice.
As you move your cursor through the YAML, the panel renders a live visual preview of the block your cursor is currently inside. Move to a note block and you see the coloured variant card. Move to a heading and you see it styled at the correct level: H1 as a bold white section header, H2 as a smaller semibold sub-heading, and H3 as a tertiary italic label. Move to a signature_block and the panel shows a column grid with the actual {{token}} values you wrote as names and roles.
For list blocks, move your cursor onto any line inside items and the panel shows all items in the list, rendered with bullet points or decimal numbers depending on style. For signature_block, move your cursor anywhere inside the signatories list and the mock signature grid appears with the actual names and roles extracted from your YAML.
This is the feedback loop that is missing from writing blueprints in a plain text editor. You do not have to trigger a full render to see whether a level-2 heading looks different from level-1, or whether your signatories structure is correct.
JSON mode
If your blueprint exists as JSON rather than YAML, paste it directly into the editor. The validator detects valid JSON automatically, switches the editor to JSON mode, and a conversion tip appears next to the JSON button pointing you to the JSON to YAML toolbar button. One click converts the document to YAML, reformats it with consistent indentation, and runs the full cursor-aware block analysis.
This is useful for teams whose Power Automate flows or source systems produce JSON. You can validate the JSON, convert to YAML for the blueprint file, and download the result in one session.
Downloading the validated file
Once the validator reports no errors, the Download button becomes active. Enter a filename in the input field to the left of it and click Download. The output is a .yaml file named {your-name}-blueprint.yaml, formatted with 2-space indentation and no extraneous whitespace. This is the file you commit to your SharePoint document library.
Download requires a signed-in VaultPDF account. You can validate and copy the validated YAML without signing in.
A Practical Authoring Workflow
This sequence avoids most blueprint mistakes before they reach the renderer.
1. Load a sample first. The Try Sample button in the toolbar offers two built-in blueprints: a structured_content contract section with heading, paragraph, note, list, clause, checkbox, radio, and signature_block examples, and a supplementary_annex inspection layout with condition fields throughout. Study the structure before writing from scratch.
2. Write in YAML. YAML is significantly more readable than JSON for multi-line text values, subclauses arrays, and condition expressions. The readability benefit compounds as the blueprint grows.
3. Validate as you write, not after you finish. Paste or type incrementally. A missing required field introduced ten seconds ago is much easier to diagnose than one buried in a 200-line file you finished an hour ago.
4. Check each block in the preview panel. After writing each block, click somewhere inside it and confirm the Block Preview renders what you expect. Pay particular attention to note variant colours, heading level styling, and signature_block column layout.
5. Add condition fields last. Get the unconditional version of the blueprint passing validation before layering in conditional logic. This makes it easier to isolate whether a render issue comes from the block structure or the condition expression.
6. Download and commit. Once validation passes with no errors, download the formatted file and commit it to your SharePoint document library. Use a name that ages well: scope-of-work-v1-blueprint.yaml is more useful six months from now than new-template-final.yaml.
If you are working on a specific document type and want to see what a blueprint file should look like for your data shape, whether that's a multi-jurisdiction services agreement, a capital project inspection annex, or a compliance report with conditional sections, reach out. The hard cases are the ones we find most useful to work through.