Watermarks
Watermarks are page chrome. They render across every page, behind the body content, without affecting flow — in Word they anchor as background objects (still individually editable). The same JSON renders identically in both formats.
A watermark's content is a full content node — not just text or an image. Anything the body vocabulary can express works here: paragraphs with Shortcodes, complete SVG graphics with textPath rings and positioned barcodes, even a reusable component stamped via use. "DRAFT in gray" is the simplest watermark, not the extent of them: decorative page frames, edge sidebars, certification seals and repeating brand patterns are all watermarks.
Live example
A real-world Mutual NDA with a DRAFT watermark layered behind page content. Open Template to see the JSON.
- Output
- Template
- Data
Schema
Watermarks live at the root of the document definition as an array — they apply to the document as a whole, not to a particular position in the content flow.
{
"document": {
"watermarks": [
{
"content": { "p": "DRAFT" },
"angle": -30,
"repeat": false,
"style": "draft"
}
],
"content": [ ... ]
}
}
| Property | Type | Default | Description |
|---|---|---|---|
content | Content | — | Any content shape — { "p": "..." } paragraph, { "svg": { … } } SVG block, or Shortcodes ([image, …], [barcode, …]). Same content vocabulary as body content. |
angle | number | 0 | Rotation in degrees. Negative = counter-clockwise. The content rotates around its own visual center. |
repeat | boolean | false | true = tile across the page using spacing as the step. false = single instance; placement comes from spacing if provided, otherwise centered on the page. |
spacing | [x, y] | — | In points. Meaning depends on repeat: tile step when repeat: true, explicit page-coordinate placement of the visual center when repeat: false. Omit or use [0, 0] for centered placement. |
style | string | — | Named style applied to the watermark content (font size, opacity, color). |
Text watermark
The most common shape — bold rotated text with low opacity behind the document body.
{
"document": {
"styles": {
"draft": { "fontSize": 96, "fontWeight": "bold", "color": "#CCCCCC", "opacity": 0.30 }
},
"watermarks": [
{
"content": { "p": "DRAFT" },
"angle": -30,
"repeat": false,
"style": "draft"
}
],
"content": [
{ "p": "Body content sits beneath the centered DRAFT mark." }
]
}
}
Image watermark
The watermark content is just a paragraph — drop in an [image, …] Shortcode and it renders as an image watermark. Style provides the opacity for "faintness".
{
"document": {
"styles": {
"logoFaint": { "opacity": 0.15 }
},
"watermarks": [
{
"content": { "p": "[image, images/logos/acme.png, 240|72]" },
"angle": -30,
"repeat": false,
"style": "logoFaint"
}
],
"content": [ ... ]
}
}
SVG watermark — frames, seals, any graphic
Because the content is a full content node, an entire svg graphic can be the watermark. A decorative page frame is four corner brackets in one graphic, centered on the page (LETTER 612×792, 20 pt in from each edge):
{
"styles": { "bracket": { "stroke": "#B8860B", "strokeWidth": 2 } },
"watermarks": [
{
"content": {
"svg": {
"viewBox": [572, 752],
"children": [
{ "path": { "d": "M 0 40 L 0 0 L 40 0", "style": "bracket" } },
{ "path": { "d": "M 532 0 L 572 0 L 572 40", "style": "bracket" } },
{ "path": { "d": "M 572 712 L 572 752 L 532 752", "style": "bracket" } },
{ "path": { "d": "M 40 752 L 0 752 L 0 712", "style": "bracket" } }
]
}
},
"repeat": false
}
]
}
Everything an svg block can draw is available — textPath rings, shape shortcuts, positioned barcode elements, and use: declare a decorative frame or certification seal once as a component and stamp it into the watermark of every template that needs it.
Repeating tile pattern
For internal-doc branding, tile a small mark across the page.
{
"watermarks": [
{
"content": { "p": "[image, images/logos/acme.png, 120|60]" },
"spacing": [250, 200],
"angle": 0,
"repeat": true,
"style": "logoFaint"
}
]
}
| Layout | repeat | spacing |
|---|---|---|
| Single, centered | false | omitted or [0, 0] |
| Single, positioned | false | [centerX, centerY] in page points |
| Tiled across page | true | [xStep, yStep] in page points |
Positioned watermark — edge-mounted elements
For control numbers, vertical sidebars, edge-mounted barcodes, and other elements anchored to a specific page region, set repeat: false and provide explicit page coordinates in spacing. The values are the visual center of the watermark content in page points (origin at bottom-left).
A vertical sidebar running down the left edge of a portrait LETTER page (612×792):
{
"watermarks": [
{
"content": {
"svg": {
"viewBox": [22, 620],
"children": [
{ "line": { "x1": 6, "y1": 14, "x2": 6, "y2": 606, "style": "edgeRule" } },
{ "textPath": {
"d": "M 14 606 L 14 14",
"text": "[caps]control no. dpa-doc-2026-0457 · scan to verify[/caps]",
"alignment": "middle",
"style": "edgeText"
} }
]
}
},
"repeat": false,
"spacing": [25, 396]
}
]
}
The SVG (22pt wide × 620pt tall) is anchored with its visual center at [25, 396] — 25pt from the page's left edge, page-center vertically. A mirror watermark with spacing: [587, 396] does the same on the right edge (612 − 25 = 587).
This works for any content shape — a barcode [barcode, code128, …] paragraph rotated with angle: 90 becomes a vertical edge barcode; a small text block at [306, 80] becomes a bottom-edge control number.
achievement-certificate and void-check both ship live examples of this pattern.
Multiple watermarks & layering
The array order is the z-order: the first watermark paints deepest, later ones above it — all beneath the body content. The full page stack, bottom to top: page background color → watermarks (in array order) → body content → page borders, headers and footers.
Layer a faint logo behind a bold DRAFT text overlay:
{
"watermarks": [
{
"content": { "p": "[image, images/logos/acme.png, 200|80]" },
"spacing": [300, 250],
"repeat": true,
"style": "logoFaint"
},
{
"content": { "p": "DRAFT" },
"angle": -35,
"repeat": false,
"style": "draftBold"
}
]
}
Per-section watermarks
A section break can carry its own watermarks array, with three distinct states:
Section watermarks | Effect |
|---|---|
| absent | Inherits the document-level watermarks. |
[] (empty array) | Suppresses watermarks for this section — clean cover or signature pages. |
| populated | Replaces the document-level set for this section. |
{
"document": {
"watermarks": [ { "content": { "p": "DRAFT" }, "angle": -30, "style": "draft" } ],
"content": [
{ "h1": "Body under the DRAFT mark" },
{ "break": "section", "watermarks": [] },
{ "p": "This section renders clean — the empty array suppresses inheritance." },
{ "break": "section", "watermarks": [
{ "content": { "p": "CONFIDENTIAL ANNEX" }, "angle": -30, "style": "draft" } ] },
{ "p": "This annex carries its own mark instead." }
]
}
}
Dynamic watermark content
Anywhere $data.* references appear (text, image src, even $data.<key> substitutions inside Shortcodes), they resolve at render time the same way they do in body content:
{
"watermarks": [
{
"content": { "p": "[image, $data.tenant.logoPath, 120|60]" },
"repeat": true,
"style": "logoFaint"
},
{
"content": { "p": "$data.classification" },
"repeat": false,
"style": "classification"
}
]
}
Style properties that matter for watermarks
| Property | Description |
|---|---|
fontSize | Text size — typically large (60–120pt) for a single centered mark. |
color | Text color. |
bold / italic | Boolean. |
font | Font family — useful for Helvetica-BoldOblique italic-bold combos. |
opacity | 0.0–1.0 translucency. Most watermarks use 0.05–0.30. |
{
"styles": {
"draft": { "fontSize": 96, "fontWeight": "bold", "color": "#94A3B8", "opacity": 0.25 },
"verified": { "fontSize": 80, "fontWeight": "bold", "color": "#15803D", "opacity": 0.35 },
"logoFaint": { "opacity": 0.15 }
}
}