Skip to main content

SVG

Draw shapes, text, and images at precise coordinates — diagrams, charts, icons, seals, decorative chrome. You author them the way you already know: as SVG. Element names and properties mirror SVGcx/cy/r, x1/y1/x2/y2, d, fill, stroke, viewBox — so an SVG snippet transfers with minimal translation. Everything renders as native vector in both PDF and DOCX — same JSON, same output, zero raster images.

Live example

A real-world architecture diagram: a 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.

The svg block

An SVG graphic is a Content item with an svg block — a viewBox plus a list of children. It reads like an <svg> root element:

{
"svg": {
"viewBox": [0, 0, 24, 24],
"children": [
{ "path": { "d": "M12 2 C8 2 5 5 5 9 c0 5 7 13 7 13 s7-8 7-13 c0-4-3-7-7-7 Z", "style": "pin" } },
{ "circle": { "cx": 12, "cy": 9, "r": 2.5, "style": "hole" } }
]
}
}
PropertyTypeDefaultDescription
viewBox[W, H] or [minX, minY, W, H]auto from childrenCoordinate extents as a numeric array — the same convention as table / columns widths. Omit to derive the tight box from the children (paths and curves included).
widthnumberviewBox scaleRendered display width in points. The viewBox stays the coordinate space the children are drawn in; width scales the graphic to this size. Omit to render at 1 unit = 1 point.
heightnumberderived from aspectRendered display height in points. Give one of width/height to scale uniformly (the other follows the viewBox aspect), or both.
childrenarrayDrawing elements (see below).

Pasting a real icon? Keep its d data and viewBox exactly as-is, convert the viewBox string to an array, and add width for the size you want — e.g. a 0 0 1024 1024 glyph with "width": 24 renders as a 24 pt icon. No coordinate math.

Each child is { "<element>": { …props } } — one drawing element keyed by its name, exactly as SVG nests elements inside <svg>. Every element carries a style reference into document.styles for its fill / stroke / etc.

Coordinates are box-relative, top-left originx grows right, y grows down. A 4-number viewBox ([minX, minY, W, H]) shifts the origin the same way SVG does, so negative author-coordinates land inside the box.

Elements

Every element renders identically in PDF and DOCX — same JSON, same output.

The vocabulary is standard SVG plus a few DocPayload conveniences:

CategoryElements
SVG primitivesrect, circle, ellipse, line, polygon, pathStandard SVG.
SVG contenttext, textPath, imageStandard SVG.
SVG groupingg, useStandard SVG — group under one transform; instantiate a reusable symbol.
Shape shortcuts (extension)arc, triangle, diamond, pentagon, hexagon, octagon, plus, parallelogram, trapezoid, rightArrow, leftArrow, upArrow, downArrow, chevronConvenience shapes SVG can express only via hand-computed polygon points or path arcs. Each fits a width × height box you supply; the vertices are derived for you.
Barcode (extension)barcodeA render-time barcode generator — no SVG equivalent. Encodes a payload (often $data-bound) as native vector.

SVG vocabulary + DocPayload extensions. Everything in the first three rows is standard SVG. The shape shortcuts and barcode are DocPayload additions layered on top — they live alongside the SVG elements in the same children, so you never leave the SVG model to reach them. Use path / polygon when you want strict SVG; reach for the shortcuts and barcode when they save you the arithmetic.

The path / textPath elements accept raw SVG d strings, making them the most flexible primitive — anything you can draw in SVG (Beziers, arcs, compound paths, decorative flourishes) transfers directly. See the Patterns Gallery tutorial for a full reference of decorative compositions (mandala, sunburst, Greek key, Lissajous, guilloché).

Drawing elements

Each element is { "<name>": { …props } }. Every element 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" } }

Shape shortcuts (extension)

triangle, diamond, pentagon, hexagon, octagon, plus, parallelogram, trapezoid. All take x, y, width, height; the vertices fit inside that box. (In strict SVG these would be a <polygon> with hand-computed points.)

{ "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" } }

Directional arrows follow the same rule — rightArrow, leftArrow, upArrow, downArrow, chevron. The orientation is encoded in the name; the renderer adjusts the vertex math.

{ "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",
"children": [
{ "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 symbol and use it with per-instance data — see order-lifecycle-states.json and org-chart.json.

Live examplearchitecture-diagram.json (a hexagon edge node as a g, plus four arch-node symbols 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 (extension)

Sweep from startAngle to endAngle (degrees, CCW from +x) around (cx, cy). A shortcut for a path with an A command when you'd rather give a center and angles than compute arc endpoints.

{ "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 element using the same d if you want a visible curve too.

PropertyTypeDescription
dstringSVG path data (same syntax as path).
textstringText 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).
alignmentenumstart (default) · middle · end — anchors the text along the path.
startOffsetnumberDistance in points from path start before the first glyph.
sideenumabove (default) — baseline on path; below — glyph hangs below the path.
stylestringText 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 (extension)

Place any supported barcode symbology at exact coordinates — PDF417, DataMatrix, QR, Code128, Code39, MaxiCode, and the 2D specialty codes. There is no SVG equivalent: the encoder runs at render time and emits native vector, 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" }
}
}
PropertyTypeDescription
x, ynumberTop-left of the barcode in local coordinates.
width, heightnumberRender dimensions in points. For square 2D codes, set both equal. Omit to use per-symbology defaults.
spec.typestringSymbology — 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.codestringThe payload to encode. Supports $data.* and $item.* references.

This is the positioned barcode primitive — distinct from the [barcode, …] Shortcode which renders inline with text flow. Use this form when you need the barcode at a precise location alongside other elements (the center of a seal, a corner of a form, an edge sidebar).

Live examplesofficial-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

text and textPath are shaped with the same engine that shapes flowing paragraphs — at render time. 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 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 examplesworld-languages-proclamation.json (one 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.

SVG styles

SVG elements use a different property schema than paragraph styles. Use the keys below — color/backgroundColor/border are paragraph properties and will be silently ignored on drawing elements.

Naming aligns with SVG presentation attributes. Same semantics as SVG, JSON-style camelCase.

PropertyApplies toDescription
fillshapesInterior fill.
strokeshapes, lines, pathsBorder / line / stroke color.
strokeWidthshapes, lines, pathsStroke width in points.
strokeDasharrayshapes, lines, pathsDash 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 — drawing state is sticky, so a dash pattern set earlier in the stream persists until overridden.
strokeDashoffsetpathsStarting offset into the dash pattern (defaults to 0).
strokeLinecapshapes, lines, pathsbutt (default) / round / square — line-end shape. Combined with strokeDasharray, round turns tiny on-segments into round dots instead of square pixels.
strokeLinejoinpathsmiter (default) / round / bevel — corner join style at polyline vertices.
strokeMiterlimitpathsPositive float — controls how long a miter spike can extend before being chopped to a bevel.
opacityall0.01.0 transparency.
colortext, textPathText fill color.
fontSizetext, textPathText size in points.
fontWeight / fontStyletext, textPathWeight (bold, normal, 100900) and style (italic, normal).
fontFamilytext, textPathFont family for embedded custom fonts.
letterSpacingtext, textPathInter-character tracking in points (positive widens, negative tightens).
textAligntextleft / center / right — domain is the text's width when set, the anchor point otherwise.
textRenderingModetext, textPathfill (default) / stroke / fillstroke / invisible / fillclip / strokeclip / fillstrokeclip / clip.
skewpaths[skewX] or [skewX, skewY] in degrees — applies a 2D skew transform.
transformpaths6-element affine matrix [a, b, c, d, e, f] — raw ConcatMatrix.
rotateshapesRotation 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 symbol is a document whose content is a single SVG graphic; a use element stamps it into another graphic at a destination box, scaling it from the symbol's viewBox and binding per-instance data — exactly like SVG's <use>.

Declaring a symbol

A symbol is an ordinary document file with a metadata.name handle and an SVG 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": [
{
"svg": {
"viewBox": [150, 150],
"children": [
{ "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 symbol's named styles travel with it — they resolve in whatever document uses it.

Instantiating with use

Inside any SVG graphic, a use element names the symbol and gives a destination box. width/height scale the symbol from its viewBox; params supplies that instance's values.

{
"svg": {
"viewBox": [472, 175],
"children": [
{ "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.

use fieldMeaning
nameThe symbol's metadata.name (the handle authors write).
idOptional GUID pin; wins over name when both are present.
x / yDestination top-left, in the host graphic's coordinates.
width / heightDestination size; the scale is derived against the symbol's viewBox.
paramsPer-instance values bound to the symbol'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 / transformOptional transforms applied to the instance (degrees / degrees / 6-element matrix).
styleNamed style cascaded to the instance's shapes that declare none.

Transforms compose in SVG order (translate → rotate → skew → scale, then the raw transform matrix). Symbols can use other symbols; nesting is depth-limited with a cycle guard.

DOCX note. In Word output a use becomes 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.

A second live example exercising the more decorative end of the 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."

What's next

  • Watermarks — translucent text/image overlays that repeat across pages.
  • Tables — tabular layouts that flow with paragraphs.
  • Columns — multi-column flow layouts.