Skip to content

Introduction

papermint is a fast, multi-vendor, type-safe thermal receipt printing engine designed from first principles in Rust.


For decades, developers building Point-of-Sale (POS) systems, kitchen ticket routers, self-checkout kiosks, and mobile receipts relied on fragile legacy libraries in Python or JavaScript (such as python-escpos or node-thermal-printer).

These legacy libraries share fundamental architectural flaws:

  • Ad-hoc byte concatenation: Functions directly append raw hex escape bytes into an array buffer. If you need to switch printer vendors (e.g. from Epson to Star Micronics), you have to rewrite your formatting logic.
  • Jagged, broken tables: They calculate character padding using str.length. When printing international characters (Japanese, Chinese, Arabic, emojis, or accents), table columns distort and misalign because they fail to account for monospace terminal cell widths.
  • Kernel driver crashes: USB communication in legacy libraries often requires pyusb and kernel driver detachment (detach_kernel_driver(0)), which destabilizes operating system USB hubs and requires root (sudo) privileges.
  • Printer buffer overflows: Sending large images without chunking exceeds the 4KB–64KB volatile RAM limits of thermal printers, causing printers to freeze, spit out random characters, or crash.

papermint redesigns thermal printing around an Intermediate Representation (IR):

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 1. Layout Engine (Receipt Builder) β”‚
β”‚ Produces an abstract stream of instructions β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ Vec<Command>
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 2. Dialect Encoders (EscPos / StarPRNT) β”‚
β”‚ Translates commands into vendor wire bytes on demand β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ Wire Bytes (Vec<u8>)
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 3. Driverless Transports β”‚
β”‚ TCP Port 9100 | Raw USB (nusb) | RS-232 | In-Memory Mock β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  1. Universal Portability: Write your receipt logic once. Render it on Epson ESC/POS, StarPRNT, or an in-memory mock sink for testing.
  2. Typographic Monospace Precision: Monospace column mathematics powered by Unicode Standard Annex #11 (East Asian Width) with synchronized multiline row wrapping.
  3. Driverless USB: Communicates directly with operating system USB bulk endpoints via nusb without vendor drivers or sudo.
  4. Universal Ecosystem: Use papermint in pure Rust, in Node.js/TypeScript via N-API (papermint), over HTTP via papermintd, in React Native/Expo (expo-papermint), in Flutter (dart:ffi), or in native iOS (Swift), Android (Kotlin), and Kotlin Multiplatform (KMP).