Canvas
A canvas is a Content item with a shapes array. Each entry is a single drawing primitive (line, rect, circle, path, text, …) keyed by its shape name. Naming and properties mirror SVG presentation attributes — authors fluent in SVG will recognize cx/cy/r, x1/y1/x2/y2, d, fill, stroke.
Live example
A real-world architecture diagram authored as a single shapes array: hexagon for the edge service, rounded rectangles for compute, ellipse-on-rectangle cylinders for databases, color-coded connectors. Open the Template tab to see the JSON.
- Output
- Template
- Data
Container
{
"shapes": [ ... ],
"viewBox": [720, 240],
"padding": 0,
"style": "defaultShapeStyle"
}
| Property | Type | Default | Description |
|---|---|---|---|
shapes | array | — | Drawing commands (see below). |
viewBox | [W, H] | auto from commands | Explicit reservation in points. Omit to derive the tight bbox from commands. |
padding | number | 0 | Padding in points added around the auto-computed bbox. Ignored when viewBox is set. |
style | string | — | Default style applied to commands that don't carry their own. |
Coordinates are box-relative top-left origin — x grows right, y grows down. Commands with negative coordinates are shifted into the box automatically when viewBox is omitted.
Built-in shapes
Every shape renders identically in PDF and DOCX — same JSON, same output.
- Output
- Template
- Data
| Tier | Shapes |
|---|---|
| Tier 1 — primitives | rect, circle, ellipse, line, arc |
| Tier 2 — polygons | triangle, diamond, pentagon, hexagon, octagon, plus, parallelogram, trapezoid |
| Tier 3 — directional arrows | rightArrow, leftArrow, upArrow, downArrow, chevron |
| Custom | polygon — N-point closed polygon, auto-closed |
| Paths | path — arbitrary SVG path data; textPath — text flowed along a path |
| Content | text, image, barcode |
| Grouping | g — groups child shapes under one transform + cascaded style; use — instantiates a reusable graphics component |
Each polygon and arrow fits inside the bounding box you supply via width × height; the renderer derives the vertex positions automatically. The path / textPath commands accept raw SVG d strings, which makes them the most flexible primitive — anything you can draw in SVG (Beziers, arcs, compound paths, decorative flourishes) renders directly. See the Canvas Patterns Gallery tutorial for a full reference of decorative compositions (mandala, sunburst, Greek key, Lissajous, guilloché).
Drawing commands
Each command is { "<shapeName>": { …props } } — a discriminated union keyed by the shape's property name. Every shape carries a style reference into document.styles.
Geometry primitives
Rectangle
{ "rect": { "x": 100, "y": 100, "width": 150, "height": 80, "rx": 6, "ry": 6, "style": "card" } }
rx / ry are optional corner radii — omit them for square corners.
Circle
{ "circle": { "cx": 200, "cy": 100, "r": 30, "style": "node" } }
Ellipse
{ "ellipse": { "cx": 200, "cy": 100, "rx": 55, "ry": 6, "style": "dbCap" } }
Tier 2 polygons
triangle, diamond, pentagon, hexagon, octagon, plus, parallelogram, trapezoid. All take x, y, width, height; the polygon vertices fit inside that bounding box.
{ "triangle": { "x": 0, "y": 0, "width": 80, "height": 80, "style": "shape" } }
{ "diamond": { "x": 110, "y": 0, "width": 80, "height": 80, "style": "shape" } }
{ "pentagon": { "x": 220, "y": 0, "width": 80, "height": 80, "style": "shape" } }
{ "hexagon": { "x": 330, "y": 0, "width": 80, "height": 80, "style": "shape" } }
{ "octagon": { "x": 0, "y": 100, "width": 80, "height": 80, "style": "shape" } }
{ "plus": { "x": 110, "y": 100, "width": 80, "height": 80, "style": "shape" } }
{ "parallelogram": { "x": 220, "y": 100, "width": 80, "height": 80, "style": "shape" } }
{ "trapezoid": { "x": 330, "y": 100, "width": 80, "height": 80, "style": "shape" } }
Tier 3 arrows
rightArrow, leftArrow, upArrow, downArrow, chevron. The orientation is encoded in the name; the renderer adjusts vertex math accordingly.
{ "rightArrow": { "x": 0, "y": 0, "width": 90, "height": 60 } }
{ "leftArrow": { "x": 110, "y": 0, "width": 90, "height": 60 } }
{ "upArrow": { "x": 220, "y": 0, "width": 60, "height": 90 } }
{ "downArrow": { "x": 290, "y": 0, "width": 60, "height": 90 } }
{ "chevron": { "x": 360, "y": 0, "width": 80, "height": 60 } }
Labeled nodes (group a shape + label)
A diagram node — a shape with a centered label — is a g group: the shape plus a text centered in the same box. Children draw in the group's local coordinates, so translate places the node and the group's style cascades to children that declare none (here, the shape inherits the node fill while the label keeps its own white-text style).
{ "g": {
"translate": [30, 85],
"style": "node",
"shapes": [
{ "hexagon": { "x": 0, "y": 0, "width": 110, "height": 50 } },
{ "text": { "x": 0, "y": 20.5, "width": 110, "text": "API Gateway", "style": "nodeLabel" } }
]
} }
Centre the label vertically with y = height/2 − fontSize/2. When the same node recurs across a diagram (the common case), define it once as a graphics component and use it with per-instance data — see order-lifecycle-states.json and org-chart.json.
Live example — architecture-diagram.json (a hexagon edge node as a g, plus four arch-node components instantiated via use).
Polygon
Closed polygon defined by N points. Useful for stars, badges, custom flowchart shapes. Auto-closed (last vertex back to first).
{
"polygon": {
"points": [
{ "x": 100, "y": 10 },
{ "x": 140, "y": 40 },
{ "x": 125, "y": 90 },
{ "x": 75, "y": 90 },
{ "x": 60, "y": 40 }
],
"style": "star"
}
}
Lines and arcs
Line
{ "line": { "x1": 50, "y1": 50, "x2": 200, "y2": 150, "style": "connector" } }
Arc
Sweep from startAngle to endAngle (degrees, CCW from +x) around (cx, cy).
{ "arc": { "cx": 200, "cy": 200, "r": 60, "startAngle": 0, "endAngle": 180, "style": "arc" } }
Paths & text on path
Path
Arbitrary SVG path data via the d attribute. Supports the standard SVG commands: M/m (moveto), L/l (lineto), H/h / V/v (horizontal/vertical lineto), C/c / S/s (cubic Bezier + smooth), Q/q / T/t (quadratic Bezier + smooth), A/a (elliptical arc), Z/z (close path). Strokes and/or fills based on which color properties the style supplies (stroke → stroke, fill → fill, both → fill+stroke).
{ "path": { "d": "M 0 50 Q 100 0 200 50 T 400 50", "style": "wave" } }
Full circle as two semicircular arcs:
{ "path": { "d": "M 100 6 A 94 94 0 0 1 100 194 A 94 94 0 0 1 100 6", "style": "outerRing" } }
textPath
Flows text along a path with per-glyph rotation. The path itself is not drawn — pair with a path command using the same d if you want a visible curve too.
| Property | Type | Description |
|---|---|---|
d | string | SVG path data (same syntax as path). |
text | string | Text to flow; supports Shortcodes ([b], [i], [color], [fontsize], [caps], [font, Family], …). Shaped at render time — complex scripts join/stack correctly (see Multi-script text and seals). |
alignment | enum | start (default) · middle · end — anchors the text along the path. |
startOffset | number | Distance in points from path start before the first glyph. |
side | enum | above (default) — baseline on path; below — glyph hangs below the path. |
style | string | Canvas text style. |
{
"textPath": {
"d": "M 24 100 A 76 76 0 0 1 176 100",
"text": "OFFICIAL · [color, #7A1F2E]STATE CORPORATION COMMISSION[/color]",
"alignment": "middle",
"style": "sealTopText"
}
}
Content
Text
{ "text": { "x": 150, "y": 200, "text": "Section header", "style": "label" } }
When width is set, (x, y) is the top-left of a text box and the style's textAlign centers/right-aligns the text within that box. Without width, the anchor is the alignment pivot — center alignment pivots on (x, y), right alignment ends at it.
{ "text": { "x": 0, "y": 10, "width": 180, "text": "EDGE", "style": "laneHeader" } }
Set fontFamily on the text style to use an embedded font, and switch fonts mid-string with the [font, Family] Shortcode — both text and textPath are shaped at render time (see Multi-script text and seals).
Image
{ "image": { "x": 50, "y": 30, "width": 100, "height": 40, "href": "images/logos/acme.png" } }
Barcode
Place any supported barcode symbology at canvas coordinates — PDF417, DataMatrix, QR, Code128, Code39, MaxiCode, and the 2D specialty codes. The barcode encoder runs at render time, so the encoded value can be a $data.* reference.
{
"barcode": {
"x": 80, "y": 56,
"width": 40, "height": 40,
"spec": { "type": "datamatrix", "code": "$data.credential.payload" }
}
}
| Property | Type | Description |
|---|---|---|
x, y | number | Top-left of the barcode in canvas coordinates. |
width, height | number | Render dimensions in points. For square 2D codes, set both equal. Omit to use per-symbology defaults. |
spec.type | string | Symbology — datamatrix, qrcode, pdf417, code128, code39, aztec, maxicode, microqr, rmqr, micropdf417, dotcode, hanxin, code16k, codablockf, ultracode, gridmatrix, upnqr, and all 1D linear types. See Symbologies. |
spec.code | string | The payload to encode. Supports $data.* and $item.* references. |
This is the canvas barcode primitive — distinct from the [barcode, …] Shortcode which renders inline with text flow. Use the canvas form when you need the barcode at a precise location alongside other canvas shapes (the center of a seal, a corner of a form, an edge sidebar).
Live examples — official-seal.json (PDF417 verification record next to control numbers), graduation-certificate.json and achievement-certificate.json (DataMatrix at the visual center of an academic seal), stock-certificate.json (DataMatrix verification badge), void-check.json (edge-mounted Code128 watermark).
Multi-script text and seals
Canvas text and textPath are shaped with HarfBuzz at render time — the same engine that shapes flowing paragraphs. Arabic and Hebrew join into their contextual forms and set right-to-left, Devanagari builds conjuncts, Thai stacks vowel and tone marks, and Chinese/Japanese/Korean render from a CJK family. Choose the face with fontFamily on the canvas text style, and switch fonts per run with the [font, Family] Shortcode. Each textPath ring can therefore carry a different script — which is what makes a multi-script seal possible.
Live examples — world-languages-proclamation.json (one canvas seal carrying Arabic, Latin, Greek and Devanagari on concentric textPath rings around a CJK character) and multilingual-device-guide.json (Latin + CJK outer rings, Devanagari + Thai inner rings around a bold CJK character). See Custom Fonts for the shaping and subsetting details.
Canvas styles
Canvas shapes use a different property schema than paragraph styles. Use the keys below — color/backgroundColor/border are paragraph properties and will be silently ignored on shape commands.
Naming aligns with SVG presentation attributes. Same semantics as SVG, JSON-style camelCase.
| Property | Applies to | Description |
|---|---|---|
fill | shapes | Interior fill. |
stroke | shapes, lines, paths | Border / line / stroke color. |
strokeWidth | shapes, lines, paths | Stroke width in points. |
strokeDasharray | shapes, lines, paths | Dash pattern as number array: [on, off] for simple dash, [a, b, c, d, …] for dash-dot, [0.5, 2.5] paired with strokeLinecap: "round" for dotted. Use [0] or [] to explicitly reset to solid — the PDF canvas state is sticky, so a dash pattern set earlier in the command stream persists until overridden. |
strokeDashoffset | paths | Starting offset into the dash pattern (defaults to 0). |
strokeLinecap | shapes, lines, paths | butt (default) / round / square — line-end shape. Combined with strokeDasharray, round turns tiny on-segments into round dots instead of square pixels. |
strokeLinejoin | paths | miter (default) / round / bevel — corner join style at polyline vertices. |
strokeMiterlimit | paths | Positive float — controls how long a miter spike can extend before being chopped to a bevel. |
opacity | all | 0.0–1.0 transparency. |
color | text, textPath | Text fill color. |
fontSize | text, textPath | Text size in points. |
fontWeight / fontStyle | text, textPath | Weight (bold, normal, 100…900) and style (italic, normal). |
fontFamily | text, textPath | Font family for embedded custom fonts. |
letterSpacing | text, textPath | Inter-character tracking in points (positive widens, negative tightens). |
textAlign | text | left / center / right — domain is the text's width when set, the anchor point otherwise. |
textRenderingMode | text, textPath | fill (default) / stroke / fillstroke / invisible / fillclip / strokeclip / fillstrokeclip / clip. |
skew | paths | [skewX] or [skewX, skewY] in degrees — applies a 2D skew transform. |
transform | paths | 6-element affine matrix [a, b, c, d, e, f] — raw ConcatMatrix. |
rotate | shapes | Rotation in degrees around the shape's center. |
{
"styles": {
"card": { "fill": "#1E40AF", "stroke": "#1E3A8A", "strokeWidth": 0.5 },
"cardLabel": { "fontSize": 9, "fontWeight": "bold", "color": "#FFFFFF", "textAlign": "center" },
"connector": { "stroke": "#16A34A", "strokeWidth": 1.5 }
}
}
Symbols & reuse — use
Draw a graphic once, instantiate it many times. A graphics component is a document whose content is a single canvas; a use command stamps it into another canvas at a destination box, scaling it from the component's viewBox and binding per-instance data.
Declaring a graphics component
A component is an ordinary document file with a metadata.name handle and a canvas payload. The name is what authors reference — it's independent of the file name and folder.
{
"component": {
"metadata": { "name": "quality-seal" },
"styles": {
"sealOuter": { "stroke": "#10243E", "strokeWidth": 2 },
"sealGrade": { "fontSize": 46, "fontWeight": "bold", "color": "#10243E", "textAlign": "center" }
},
"content": [
{
"viewBox": [150, 150],
"shapes": [
{ "circle": { "cx": 75, "cy": 75, "r": 72, "style": "sealOuter" } },
{ "text": { "x": 0, "y": 45, "width": 150, "text": "$data.grade", "style": "sealGrade" } }
]
}
]
}
}
$data.grade is a placeholder filled in per instance (see Data Binding). The component's named styles travel with it — they resolve in whatever document uses it.
Instantiating with use
Inside any canvas, a use command names the component and gives a destination box. width/height scale the component from its viewBox; params supplies that instance's values.
{
"viewBox": [472, 175],
"shapes": [
{ "use": { "name": "quality-seal", "x": 16, "y": 12, "width": 150, "height": 150, "params": { "grade": "A" } } },
{ "use": { "name": "quality-seal", "x": 206, "y": 27, "width": 120, "height": 120, "params": { "grade": "B" } } },
{ "use": { "name": "quality-seal", "x": 372, "y": 39, "width": 100, "height": 100, "params": { "grade": "A+" } } }
]
}
One definition, three sizes, three grades — no duplicated geometry. The rings, text, and any nested shapes scale as a unit.
- Output
- Template
- Data
use field | Meaning |
|---|---|
name | The component's metadata.name (the handle authors write). |
id | Optional GUID pin; wins over name when both are present. |
x / y | Destination top-left, in the host canvas's coordinates. |
width / height | Destination size; the scale is derived against the component's viewBox. |
params | Per-instance values bound to the component's $data.* placeholders. May also carry x/y/width/height/rotate to make this use's own geometry dynamic (e.g. "params": { "width": "$data.columnWidth" } }) — a value here wins over the literal field of the same name. |
rotate / skew / transform | Optional transforms applied to the instance (degrees / degrees / 6-element matrix). |
style | Named style cascaded to the instance's shapes that declare none. |
Transforms compose in SVG order (translate → rotate → skew → scale, then the raw transform matrix). Components can use other components; nesting is depth-limited with a cycle guard.
DOCX note. In Word output a
usebecomes a nested group carrying translate, scale, and rotate. Skew and raw-matrix transforms aren't expressible on a Word group and are dropped (the PDF honors them in full), and a rotated group pivots on its center rather than its top-left.
Patterns gallery — paths, curves, and textPath
A second live example exercising the more decorative end of the canvas API: SVG path data, quadratic and cubic Bezier curves, arcs, textPath (text flowed along a curve), polygon shapes, and overlapping compositions. Useful as a reference when authoring seals, ornamental borders, math/geometry illustrations, or anything where the layout language is "place these curves exactly here."
- Output
- Template
- Data
What's next
- Watermarks — translucent text/image overlays that repeat across pages.
- Tables — tabular layouts that flow with paragraphs.
- Columns — multi-column flow layouts.