How a conversion works
A conversion is three steps: reading the source file, translating it into a neutral Intermediate Representation, writing it in the destination format. All in the browser, all synchronous.
1. Reading (reader)
Every format has its own reader — a function
read(bytes: Uint8Array): Pattern in packages/core.
The reader decodes the file's bytes, handles the format's quirks
(compression, XOR, byte order, offset tables) and returns a
Pattern with absolute stitches in 0.1 mm
units, threads with RGB and catalog info, and commands (STITCH,
JUMP, TRIM, COLOR_CHANGE,
STOP, END).
Some readers are simple (DST is text with coordinates; EXP is a stream of signed bytes). Others have more scaffolding: VIP is a HUS body compressed with EmbCompress inside a Husqvarna header; PES embeds a PEC block with its color palette; VP3 carries thread tables with manufacturer metadata.
2. Intermediate Representation
The Pattern is the heart of the converter: every writer consumes it, every reader produces it. It is neutral, so any two formats can talk to each other without knowing anything about one another. See the IR page for the details of the type.
Commands
STITCH— a normal stitch; the needle goes down and sews.JUMP— move the needle without sewing (for jumps between areas of the design).TRIM— cut the thread. Not every format knows how.COLOR_CHANGE— the machine's color change.STOP— a pause: the operator changes thread or adjusts the fabric.END— end of the design; the last command every writer must always emit.
3. Writing (writer)
Every format has a writer write(pattern: Pattern,
settings): Uint8Array. The writer takes the absolute coordinates,
converts them to the format's delta encoding (1/10 mm in ZHS, 0.1 mm with
scaling in DST, and so on), and encodes the special commands with the
bytes of its own dialect.
If the destination format cannot express one of the Pattern's commands
(for instance, ZHS cannot write STOP as an arbitrary pause,
and some older formats have no concept of TRIM), the writer
applies the fallback strategy documented for that format and attaches a
structured warning to the
response. The UI shows the warnings in the results list.
4. The convert() function
import { convert } from '@embroidery/core';
// en: source bytes, fromFmt, toFmt → destination bytes
const out = await convert({
bytes: vipBytes,
from: 'vip',
to: 'zhs',
settings: { hoop: 'auto', trims: 'drop' },
});
// out.bytes : Uint8Array
// out.warnings : Warning[] (empty when everything went smoothly)
// out.note? : string (caveat for the destination format) What it does NOT do
- It doesn't digitize. It doesn't generate stitches from an SVG or a vector drawing — it reads one embroidery file and writes another.
- It doesn't touch your file's colors. If a format only knows its own thread palette, it snaps them to the nearest matches and reports
warn.COLOR_QUANTIZED. - It doesn't reshape the geometry: it moves or centers the design in the hoop only if you ask it to.
- It sends nothing over the network. See Privacy.