Skip to content

Core

@thermal-label/labelwriter-core is the shared protocol layer used by both the Node.js and Web packages. It contains the ESC/raster encoder, the 450 / 550 / Duo-tape status parsers, the device and media registries, and the offline preview helper. It also re-exports the @thermal-label/contracts base types.

Consume *-core directly when you need the protocol encoder or offline preview without a live printer.

Looking for byte-level details?

The wire protocols are documented separately:

  • LW raster — LabelWriter 300 / 400 / 450 / 4XL.
  • LW5 raster — LabelWriter 550 / 550 Turbo / 5XL.
  • D1 tape protocol — Duo tape engine, shared with the LabelManager driver (in @thermal-label/d1-core).

This page documents the *-core API surface that emits and parses those byte streams.

Install

bash
pnpm add @thermal-label/labelwriter-core

Core exports

ExportDescription
DEVICES / findDeviceDevice registry (family, transports, engines)
MEDIA / DEFAULT_MEDIAMedia registry and the 89×28 mm fallback for assumed previews
findMediaByDimensions(w, h)Match a 550-status response to a registry entry
STATUS_REQUEST / buildStatusRequest(device, lock?)Static ESC A (450) or device-aware status request (550)
parseStatus(device, bytes)Parse the status response into PrinterStatus (1 / 32 bytes)
statusByteCount(device)1 for lw-raster, 32 for lw5-raster. d1-tape status (also 1 byte) routes through d1-core.
createPreviewOffline(image, media)Render PreviewResult without a live printer connection
encodeLabel(device, bitmap, opts, media)Full job byte stream for lw-raster, lw5-raster, and d1-tape (dispatched on engine.protocol)
isEngineDrivable(engine) / isDuoTapeEngine(engine)Routing helpers for adapters with multiple engines
buildReset, buildDensity, buildRasterRow, build550…Per-command byte builders
parseSkuInfo(bytes) / parseEngineVersion(bytes)Parsers for ESC U / ESC V 550-family responses
LabelWriterDeviceDevice descriptor type (extends contracts DeviceDescriptor)
LabelWriterMediaMedia descriptor type (extends contracts MediaDescriptor)
LabelWriterPrintOptionsProtocol options (density, mode, compress, copies, engine, jobId)
Density'light' | 'medium' | 'normal' | 'high'
PrinterAdapter, MediaDescriptor, PrinterStatus, Transport, …Re-exported from @thermal-label/contracts

Encoding a label

ts
import { encodeLabel, DEVICES, type LabelBitmap } from '@thermal-label/labelwriter-core';

const bitmap: LabelBitmap = {
  widthPx: 672,
  heightPx: 200,
  data: new Uint8Array((672 / 8) * 200),
};
const bytes = encodeLabel(DEVICES.LW_450, bitmap);
// bytes is a Uint8Array ready to send to the printer transport

encodeLabel reads engine.protocol and dispatches to the right encoder. For the LabelWriter Duo's tape side, the dispatcher routes to @thermal-label/d1-core's buildPrinterStream; the caller still has to provide the tape transport via engineTransports.tape (the tape engine sits on a separate USB interface, so auto-mapping the primary transport would point at the wrong endpoint).

Per-protocol routing

Engine protocolEncoderStatus replySpec source
lw-rasterencodeLabel(device, …)1 byteLW 450 Series Tech Ref
lw5-rasterencodeLabel(device, …)encode550Label32 bytesLW 550 Tech Ref
d1-tapeencodeLabel(device, …) → d1-core's buildPrinterStream1 byted1-core protocol

Adapters with multiple engines (the Duo) use isDuoTapeEngine(engine) to pick the right transport for status queries (the tape engine needs the tape USB interface, not the label one).