Skip to main content

@deckify/dsvg

pnpm add @deckify/dsvg

The TypeScript package is the reference compiler for DSVG 0.1. It parses, validates, templates, measures flex <text> with supplied OpenType fonts, applies Yoga layout, and emits static SVG.

@deckify/dsvg is ESM-only. Use import / dynamic import() — CommonJS require() is not supported.

Quick start

import { compileDsvg } from '@deckify/dsvg';
import { readFileSync } from 'node:fs';

const interRegular = readFileSync('./fonts/Inter-Regular.ttf');

const source = `
<svg xmlns="http://www.w3.org/2000/svg" data-dsvg-version="0.1" width="400" height="120">
<g
data-dsvg-layout="flex"
data-dsvg-justify-content="center"
data-dsvg-align-items="center"
data-dsvg-gap="16"
data-dsvg-width="400"
data-dsvg-height="120"
>
<circle r="24" fill="#3366ff" />
<text font-family="Inter" font-size="24" fill="#111">{{title}}</text>
</g>
</svg>
`;

const { svg } = await compileDsvg(source, {
variables: { title: 'Hello DSVG' },
fonts: [
{
name: 'Inter',
data: interRegular,
weight: 400,
style: 'normal',
},
],
});

In the browser, load font bytes with fetch(url).then((response) => response.arrayBuffer()) instead of readFileSync.

Text in flex layout

Flex <text> children are sized from supplied font files, not Canvas or installed system fonts.

  1. Put <text> inside a data-dsvg-layout="flex" group.
  2. Set SVG typography attributes: font-family, font-size, optional font-weight / font-style.
  3. Pass matching faces in fonts. The name must match font-family.
  4. After templating, DSVG normalizes flex text whitespace (collapse + trim), then measures advance width and ascender/descender height.
  5. Layout writes x / y using the font baseline. Output stays SVG <text> (glyphs are not converted to paths).
await compileDsvg(source, {
fonts: [
{ name: 'Inter', data: interRegular, weight: 400, style: 'normal' },
{ name: 'Inter', data: interBold, weight: 700, style: 'normal' },
],
});

Overrides and skip mode

NeedApproach
Fixed boxSet data-dsvg-width / data-dsvg-height on the <text>
No fonts availablePass textMeasurement: 'skip' (legacy 0 × 0 unless explicit dims)
Missing face for intrinsic textThrows TEXT_MEASUREMENT_REQUIRED
await compileDsvg(source, {
textMeasurement: 'skip',
});

0.1 scope: single-line text only. Multi-line wrap, kerning, ligatures, and RTL are out of scope.

Exports

SymbolDescription
parseDsvgParse XML string → AST
serializeDsvgAST → XML string
validateDsvgReturn { ok: true } or { ok: false, errors }
renderTemplateResolve Mustache variables
applyYogaLayoutApply flex layout (fonts / textMeasurement)
compileDsvgFull compile pipeline
compileDsvgDocumentCompile from an existing AST
createFontMeasurerBuild an OpenType text measurer
isDsvgFilenameRecognize .dsvg / .d.svg
toCompiledSvgFilenameMap source filename → .svg
DSVG_SPEC_VERSION"0.1"
DsvgCompileErrorThrown on compile/template failures

Compile options

type CompileOptions = {
variables?: Record<string, unknown>;
strictMissing?: boolean;
stripDsvgAttributes?: boolean;
fonts?: FontOptions[];
textMeasurement?: 'font' | 'skip'; // default: 'font'
};

type FontOptions = {
name: string;
data: ArrayBuffer | Uint8Array;
weight?: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 'normal' | 'bold';
style?: 'normal' | 'italic';
};

applyYogaLayout(document, { fonts, textMeasurement }) accepts the same font options when you run layout alone.

Errors

type DsvgError = {
code: DsvgErrorCode;
message: string;
path?: string;
};

DsvgCompileError.errors contains the full batch when multiple issues are found.

CodeWhen
PARSE_ERRORXML/SVG source failed to parse
INVALID_ROOTDocument root is missing or not <svg>
UNSUPPORTED_VERSIONdata-dsvg-version is missing or not 0.1
INVALID_ATTRIBUTEUnknown or misplaced data-dsvg-* attribute
INVALID_VALUEAttribute value fails validation (keyword, number, or token)
UNSUPPORTED_MUSTACHEUnsupported Mustache feature ({{#, {{^, {{/, {{>)
MISSING_VARIABLERequired template variable is absent (strict mode)
INVALID_VARIABLE_TYPETemplate variable resolved to a non-primitive value
LAYOUT_ERRORYoga layout failed unexpectedly
TEXT_MEASUREMENT_REQUIREDIntrinsic flex text needs fonts, but none match / none provided
TEXT_MEASUREMENT_FAILEDFont parse or glyph measurement failed

Try it

Use the Playground to compile flex text with the bundled Inter faces in the browser.