Getting started
Three ways to use designer-core: as a Node.js library, through the CLI, or embedded in a browser application. Each path below is self-contained — pick the one that matches your setup.
If you're embedding the designer into a Vue or React application, also see Embedding → Vue or Embedding → React.
Path 1 — Node.js script
pnpm add @burnmark-io/designer-core @napi-rs/canvas@napi-rs/canvas is an optional peer dependency. Install it only on Node.js — in the browser, designer-core uses the built-in OffscreenCanvas and the peer is never resolved.
Build a document in code, render it, and write a PNG to disk:
import { writeFile } from 'node:fs/promises';
import { Buffer } from 'node:buffer';
import { LabelDesigner, exportPng } from '@burnmark-io/designer-core';
const designer = new LabelDesigner({
canvas: { widthDots: 696, heightDots: 0, dpi: 300 },
});
designer.add({
type: 'text',
x: 20,
y: 20,
width: 656,
height: 60,
rotation: 0,
opacity: 1,
locked: false,
visible: true,
color: '#000000',
content: 'Order #{{order_id}} — {{name}}',
fontFamily: 'Burnmark Sans',
fontSize: 36,
fontWeight: 'bold',
fontStyle: 'normal',
textAlign: 'left',
verticalAlign: 'top',
letterSpacing: 0,
lineHeight: 1.2,
invert: false,
wrap: true,
autoHeight: false,
});
designer.add({
type: 'barcode',
x: 20,
y: 100,
width: 240,
height: 80,
rotation: 0,
opacity: 1,
locked: false,
visible: true,
color: '#000000',
format: 'qrcode',
data: 'https://example.com/orders/{{order_id}}',
options: { eclevel: 'M' },
});
const blob = await exportPng(designer.document, {
variables: { order_id: '12345', name: 'Piet' },
});
await writeFile('preview.png', Buffer.from(await blob.arrayBuffer()));Expected output: a file preview.png (696 × ~190 px) with the text and a QR code linking to the order URL. The continuous-height canvas (heightDots: 0) auto-crops to content.
Render a CSV batch
import { readFile } from 'node:fs/promises';
import { LabelDesigner, parseCsv, renderBatch } from '@burnmark-io/designer-core';
const designer = new LabelDesigner({
canvas: { widthDots: 696, heightDots: 200, dpi: 300 },
});
// …add text/barcode objects referencing `{{name}}`, `{{order_id}}`, etc…
const csvText = await readFile('orders.csv', 'utf-8');
const csv = await parseCsv(csvText);
for await (const result of renderBatch(designer, csv.rows)) {
const plane = result.planes.get('black');
if (!plane) continue;
// `plane` is a 1bpp LabelBitmap — hand it to your printer driver, save
// it to disk, etc. Each iteration is memory-cheap: the previous bitmap
// is eligible for GC once the loop advances.
}Load a .label file from disk
import { readFile } from 'node:fs/promises';
import { LabelDesigner } from '@burnmark-io/designer-core';
const json = await readFile('my-label.label', 'utf-8');
const designer = new LabelDesigner();
designer.fromJSON(json);Path 2 — CLI
Install the CLI globally, or use it via pnpm dlx:
pnpm add -g burnmark-cli
# or
pnpm dlx burnmark-cli <command>Install any printer drivers you want to use alongside the CLI. Drivers are optional peer dependencies — the CLI only loads what's present:
pnpm add -g @thermal-label/brother-ql-nodeCreate a my-label.label file (JSON — see the .label format reference for the full schema):
{
"id": "example-label-1",
"version": 1,
"name": "Hello",
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T00:00:00.000Z",
"canvas": {
"widthDots": 696,
"heightDots": 0,
"dpi": 300,
"margins": { "top": 10, "right": 10, "bottom": 10, "left": 10 },
"background": "#ffffff",
"grid": { "enabled": false, "spacingDots": 10 }
},
"objects": [
{
"id": "t1",
"type": "text",
"x": 20,
"y": 20,
"width": 656,
"height": 60,
"rotation": 0,
"opacity": 1,
"locked": false,
"visible": true,
"color": "#000000",
"content": "Hello {{name}}",
"fontFamily": "Burnmark Sans",
"fontSize": 40,
"fontWeight": "bold",
"fontStyle": "normal",
"textAlign": "left",
"verticalAlign": "top",
"letterSpacing": 0,
"lineHeight": 1.2,
"invert": false,
"wrap": true,
"autoHeight": false
}
],
"metadata": {}
}Render to PNG:
burnmark render --template my-label.label --var name="Piet" --output preview.pngRender to a multi-page PDF from a CSV (one page per row):
burnmark render --template my-label.label --csv people.csv --output preview.pdfRender to a sticker sheet (PDF) using a built-in sheet template:
burnmark render --template my-label.label --sheet avery-l7160 --csv skus.csv --output sheet.pdfValidate that a CSV has every variable the label expects, before a big batch:
burnmark validate --template my-label.label --csv people.csvPrint — requires a @thermal-label/* driver to be installed:
burnmark print --template my-label.label --var name="Piet" --printer usb://brother-qlShow which drivers are installed and which sheet templates are built in:
burnmark list-printers
burnmark list-sheetsSee the CLI guide for the full flags table and scripting recipes.
Path 3 — Browser
In a Vite / webpack / Rollup / ESM-any app, install @burnmark-io/designer-core and use it directly. OffscreenCanvas is the only prerequisite — no @napi-rs/canvas is needed in the browser:
import { LabelDesigner, exportPng } from '@burnmark-io/designer-core';
const designer = new LabelDesigner({
canvas: { widthDots: 696, heightDots: 0, dpi: 300 },
});
designer.add({
type: 'text',
x: 20,
y: 20,
width: 656,
height: 60,
rotation: 0,
opacity: 1,
locked: false,
visible: true,
color: '#000000',
content: 'Hello {{name}}',
fontFamily: 'Burnmark Sans',
fontSize: 40,
fontWeight: 'bold',
fontStyle: 'normal',
textAlign: 'left',
verticalAlign: 'top',
letterSpacing: 0,
lineHeight: 1.2,
invert: false,
wrap: true,
autoHeight: false,
});
const blob = await exportPng(designer.document, {
variables: { name: 'Piet' },
});
const url = URL.createObjectURL(blob);
const img = document.querySelector<HTMLImageElement>('#preview');
if (img) img.src = url;Trigger a download:
const a = document.createElement('a');
a.href = url;
a.download = 'preview.png';
a.click();
URL.revokeObjectURL(url);Browser requirements
OffscreenCanvas is used internally for rendering and PNG export. Minimum versions: Safari 16.4+, Chrome 69+, Firefox 105+. See the FAQ if you hit OffscreenCanvas is not defined.
If you're rendering in a Node.js-style server-side environment inside a browser codebase (for example, Next.js server components), designer-core will try to dynamically import @napi-rs/canvas for rendering. Add it to your server-side dependencies or gate the render call behind a typeof window !== 'undefined' check.
What's next
- Colour model — the most important conceptual page. Explains how CSS colours become printer planes.
- Document model — the shape of a label, its objects, and the
.labelfile format. - Template engine — placeholders and CSV batch, with a full Christmas-card address-label walkthrough.
- Export — PNG, PDF, sheet tiling, and
.zipbundles. - Embedding → Vue or Embedding → React if you're adding a designer UI to an app.