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

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

← Overview Architecture →