{"id":48305475,"url":"https://github.com/productdevbook/portakal","last_synced_at":"2026-06-05T23:31:11.631Z","repository":{"id":348703819,"uuid":"1199331211","full_name":"productdevbook/portakal","owner":"productdevbook","description":"Universal printer language SDK — 9 languages, 9 parsers, 63 cross-compilers. TSC, ZPL, EPL, ESC/POS, CPCL, DPL, SBPL, Star PRNT, IPL. Zero dependencies. Pure TypeScript.","archived":false,"fork":false,"pushed_at":"2026-04-02T18:41:08.000Z","size":1894,"stargazers_count":36,"open_issues_count":3,"forks_count":3,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-20T13:03:20.462Z","etag":null,"topics":["barcode","cpcl","dpl","epl","escpos","esm","ipl","label-printer","printer-sdk","qr-code","receipt-printer","sato","sbpl","star-prnt","thermal-printer","tsc","tspl","typescript","zero-dependency","zpl"],"latest_commit_sha":null,"homepage":"https://portakal.productdevbook.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/productdevbook.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null},"funding":{"github":["productdevbook"]}},"created_at":"2026-04-02T08:46:33.000Z","updated_at":"2026-04-19T17:01:57.000Z","dependencies_parsed_at":null,"dependency_job_id":"87522596-2ede-4797-bc2c-831f262b9f80","html_url":"https://github.com/productdevbook/portakal","commit_stats":null,"previous_names":["productdevbook/portakal"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/productdevbook/portakal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/productdevbook%2Fportakal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/productdevbook%2Fportakal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/productdevbook%2Fportakal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/productdevbook%2Fportakal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/productdevbook","download_url":"https://codeload.github.com/productdevbook/portakal/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/productdevbook%2Fportakal/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33964367,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-05T02:00:06.157Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["barcode","cpcl","dpl","epl","escpos","esm","ipl","label-printer","printer-sdk","qr-code","receipt-printer","sato","sbpl","star-prnt","thermal-printer","tsc","tspl","typescript","zero-dependency","zpl"],"created_at":"2026-04-05T00:00:38.368Z","updated_at":"2026-06-05T23:31:11.624Z","avatar_url":"https://github.com/productdevbook.png","language":"TypeScript","funding_links":["https://github.com/sponsors/productdevbook"],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cbr\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/productdevbook/portakal/main/.github/assets/cover.png\" alt=\"portakal — Universal printer language SDK\" width=\"100%\"\u003e\n  \u003cbr\u003e\u003cbr\u003e\n  \u003cb style=\"font-size: 2em;\"\u003eportakal\u003c/b\u003e\n  \u003cbr\u003e\u003cbr\u003e\n  Universal printer language SDK — 9 languages, one API.\n  \u003cbr\u003e\n  Text, barcodes, QR codes, images, shapes — anything you can print.\n  \u003cbr\u003e\n  One API, every thermal printer. Pure TypeScript, zero dependencies.\n  \u003cbr\u003e\u003cbr\u003e\n  \u003ca href=\"https://npmjs.com/package/portakal\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/portakal?style=flat\u0026colorA=18181B\u0026colorB=F97316\" alt=\"npm version\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://npmjs.com/package/portakal\"\u003e\u003cimg src=\"https://img.shields.io/npm/dm/portakal?style=flat\u0026colorA=18181B\u0026colorB=F97316\" alt=\"npm downloads\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://bundlephobia.com/result?p=portakal\"\u003e\u003cimg src=\"https://img.shields.io/bundlephobia/minzip/portakal?style=flat\u0026colorA=18181B\u0026colorB=F97316\" alt=\"bundle size\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/productdevbook/portakal/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/productdevbook/portakal?style=flat\u0026colorA=18181B\u0026colorB=F97316\" alt=\"license\"\u003e\u003c/a\u003e\n  \u003cbr\u003e\u003cbr\u003e\n  \u003ca href=\"https://portakal.productdevbook.com\"\u003ePlayground\u003c/a\u003e · \u003ca href=\"https://github.com/productdevbook/portakal\"\u003eGitHub\u003c/a\u003e · \u003ca href=\"https://npmjs.com/package/portakal\"\u003enpm\u003c/a\u003e\n\u003c/p\u003e\n\n\u003e [!IMPORTANT]\n\u003e **We need your help testing!** If you have a thermal printer, please try portakal and [report any differences](https://github.com/productdevbook/portakal/issues/new) between our preview and your actual printed output. Even \"looks correct\" confirmations help. See [Help Us Test](#help-us-test--real-printer-output-needed) below.\n\n\u003e [!NOTE]\n\u003e portakal has **two ways** to print barcodes and QR codes:\n\u003e\n\u003e 1. **Printer-native** (`.barcode()` / `.qrcode()`) — sends commands to the printer's built-in encoder. Fast, zero dependencies, minimal data transfer. Works for most use cases.\n\u003e 2. **Software-rendered** (`.image()` + [`etiket`](https://github.com/productdevbook/etiket)) — renders barcodes/QR codes as images on the host, sends pixels to the printer. Pixel-perfect output, 40+ formats, styled QR codes, guaranteed consistency across all printers. You install `etiket` yourself — portakal stays zero-dependency.\n\n## Quick Start\n\n```sh\nnpm install portakal\n```\n\n### Product label\n\n```ts\nimport { label } from \"portakal/core\";\nimport { tsc } from \"portakal/lang/tsc\";\n\nconst myLabel = label({ width: 40, height: 30, unit: \"mm\" })\n  .text(\"ACME Corp\", { x: 10, y: 10, size: 2 })\n  .text(\"SKU: PRD-00123\", { x: 10, y: 35 })\n  .line({ x1: 5, y1: 55, x2: 310, y2: 55 })\n  .box({ x: 5, y: 5, width: 310, height: 230, thickness: 2 });\n\nconst code = tsc.compile(myLabel); // TSC/TSPL2 commands\nconst svg = tsc.preview(myLabel); // SVG preview with TSC font metrics\n```\n\n### Same label → any language\n\n```ts\nimport { label } from \"portakal/core\";\nimport { tsc } from \"portakal/lang/tsc\";\nimport { zpl } from \"portakal/lang/zpl\";\nimport { epl } from \"portakal/lang/epl\";\nimport { escpos } from \"portakal/lang/escpos\";\n\nconst myLabel = label({ width: 40, height: 30, unit: \"mm\" }).text(\"Hello World\", {\n  x: 10,\n  y: 10,\n  size: 2,\n});\n\ntsc.compile(myLabel); // TSC/TSPL2  — TSC, Gprinter, Xprinter, iDPRT\nzpl.compile(myLabel); // Zebra ZPL II — GK420, ZT410, ZD620\nepl.compile(myLabel); // Eltron EPL2 — LP/TLP 2824, GX420, ZD220\nescpos.compile(myLabel); // ESC/POS — Epson, Bixolon, Star, Citizen (Uint8Array)\n```\n\nOnly the imported languages enter your bundle — 100% tree-shakeable.\n\n### Receipt (ESC/POS)\n\n```ts\nimport { label } from \"portakal/core\";\nimport { escpos } from \"portakal/lang/escpos\";\n\nconst receipt = label({ width: 80, unit: \"mm\" })\n  .text(\"MY STORE\", { align: \"center\", bold: true, size: 2 })\n  .text(\"123 Market St\", { align: \"center\" })\n  .text(\"================================\")\n  .text(\"Hamburger           x2    $25.98\")\n  .text(\"Cola                x1     $3.50\")\n  .text(\"================================\")\n  .text(\"TOTAL                     $29.48\", { bold: true, size: 2 });\n\nconst bytes = escpos.compile(receipt); // Uint8Array\nconst svg = escpos.preview(receipt); // Receipt-style SVG\n```\n\n### Each module: compile + parse + preview + validate\n\n```ts\nimport { tsc } from \"portakal/lang/tsc\";\n\n// Compile: label → printer commands\ntsc.compile(myLabel);\n\n// Preview: label → SVG (per-language font metrics)\ntsc.preview(myLabel);\n\n// Parse: printer commands → structured data\ntsc.parse(tscCode); // { commands, elements, widthDots, ... }\n\n// Validate: check for errors\ntsc.validate(tscCode); // { valid, errors, issues }\n```\n\nAvailable: `tsc`, `zpl`, `epl`, `cpcl`, `dpl`, `sbpl`, `escpos`, `starprnt`, `ipl`\n\n### Barcode/QR via etiket\n\nUse [`etiket`](https://github.com/productdevbook/etiket) for barcode/QR generation, then embed as image:\n\n```ts\nimport { label } from \"portakal/core\";\nimport { tsc } from \"portakal/lang/tsc\";\nimport { barcodePNG, qrcodePNG } from \"etiket\";\n\nconst myLabel = label({ width: 40, height: 30, unit: \"mm\" })\n  .text(\"Product Label\", { x: 10, y: 5 })\n  .image(barcodePNG(\"123456789\", { type: \"code128\" }), { x: 10, y: 40, width: 200 })\n  .image(qrcodePNG(\"https://example.com\"), { x: 220, y: 40, width: 80 });\n\nconst code = tsc.compile(myLabel);\n```\n\n| **Best for** | Simple labels, fast printing | Pixel-perfect, guaranteed output |\n\n## API\n\n### `label(config)`\n\nCreates a new label builder.\n\n```ts\nconst builder = label({\n  width: 40, // Label width\n  height: 30, // Label height (omit for receipt/continuous)\n  unit: \"mm\", // \"mm\" | \"inch\" | \"dot\" (default: \"mm\")\n  dpi: 203, // Printer DPI (default: 203)\n  gap: 3, // Gap between labels in mm (default: 3)\n  speed: 4, // Print speed 1-10 (default: 4)\n  density: 8, // Darkness 0-15 (default: 8)\n  copies: 1, // Number of copies (default: 1)\n});\n```\n\n### `.text(content, options?)`\n\n```ts\nbuilder.text(\"Hello\", {\n  x: 10, // X position in dots\n  y: 20, // Y position in dots\n  font: \"2\", // Font name/ID (printer-specific)\n  size: 2, // Magnification (1-10)\n  rotation: 0, // 0 | 90 | 180 | 270\n  bold: true, // Bold (ESC/POS only)\n  underline: true, // Underline (ESC/POS only)\n  reverse: false, // White on black\n  align: \"center\", // \"left\" | \"center\" | \"right\"\n  maxWidth: 300, // Word-wrap width in dots\n});\n```\n\n### `.image(bitmap, options?)`\n\n```ts\nbuilder.image(monochromeBitmap, {\n  x: 10,\n  y: 10, // Position\n  width: 200, // Target width in dots\n  height: 100, // Target height in dots\n});\n```\n\nThe `bitmap` must be a `MonochromeBitmap`:\n\n```ts\ninterface MonochromeBitmap {\n  data: Uint8Array; // 1-bit packed, row-major, MSB-first\n  width: number; // Width in pixels\n  height: number; // Height in pixels\n  bytesPerRow: number; // ceil(width / 8)\n}\n```\n\n### `.box(options)` / `.line(options)` / `.circle(options)`\n\n```ts\nbuilder.box({ x: 0, y: 0, width: 200, height: 100, thickness: 2, radius: 5 });\nbuilder.line({ x1: 0, y1: 50, x2: 300, y2: 50, thickness: 1 });\nbuilder.circle({ x: 100, y: 100, diameter: 60, thickness: 2 });\n```\n\n### `.raw(content)`\n\nEscape hatch for printer-specific commands:\n\n```ts\nbuilder.raw(\"SET CUTTER ON\"); // TSC\nbuilder.raw(\"^FO10,10^FDCustom^FS\"); // ZPL\nbuilder.raw(new Uint8Array([0x1b, 0x70, 0x00, 0x32, 0x32])); // ESC/POS cash drawer\n```\n\n### Language Module Methods\n\nEach language module (`tsc`, `zpl`, `epl`, `cpcl`, `dpl`, `sbpl`, `escpos`, `starprnt`, `ipl`) has:\n\n| Method                | Output                   | Description                              |\n| :-------------------- | :----------------------- | :--------------------------------------- |\n| `lang.compile(label)` | `string` or `Uint8Array` | Compile to printer commands              |\n| `lang.preview(label)` | `string`                 | SVG preview with language-specific fonts |\n| `lang.parse(code)`    | `object`                 | Parse printer commands → structured data |\n| `lang.validate(code)` | `object`                 | Validate commands for errors/warnings    |\n\n### Image Processing\n\nConvert any RGBA image to monochrome bitmap with dithering:\n\n```ts\nimport { imageToMonochrome } from \"portakal\";\n\nconst bitmap = imageToMonochrome(rgbaPixels, width, height, {\n  dither: \"floyd-steinberg\", // \"threshold\" | \"floyd-steinberg\" | \"atkinson\" | \"ordered\"\n});\n\ntsc.compile(label({ width: 40, height: 30 }).image(bitmap, { x: 10, y: 10 }));\n```\n\n### Receipt Layout\n\n```ts\nimport { formatPair, separator, formatTable } from \"portakal\";\n\n// Same-line left+right alignment\nformatPair(\"Hamburger x2\", \"$25.98\", 48);\n// → \"Hamburger x2                              $25.98\"\n\n// Separator line\nseparator(\"=\", 48);\n// → \"================================================\"\n\n// Multi-column table\nformatTable(\n  [\n    { width: 30, align: \"left\" },\n    { width: 5, align: \"center\" },\n    { width: 13, align: \"right\" },\n  ],\n  [\n    [\"Item\", \"Qty\", \"Price\"],\n    [\"Hamburger\", \"2\", \"$25.98\"],\n  ],\n  48,\n);\n```\n\n### Cross-Compiler\n\nConvert between any printer languages — world's first thermal printer translator:\n\n```ts\nimport { convert } from \"portakal\";\n\n// TSC → ZPL\nconst { output } = convert(tscCode, \"tsc\", \"zpl\");\n\n// ZPL → ESC/POS\nconst { output } = convert(zplCode, \"zpl\", \"escpos\");\n\n// EPL → CPCL\nconst { output } = convert(eplCode, \"epl\", \"cpcl\");\n```\n\n7 source × 9 target = **63 conversion paths**.\n\n### Validation\n\nCheck printer commands for errors before sending to printer:\n\n```ts\nimport { validate } from \"portakal\";\n\nconst result = validate(code, \"tsc\");\n// { valid: false, errors: 1, warnings: 2, issues: [\n//   { level: \"error\", message: \"CLS must appear before label elements\" },\n//   { level: \"warning\", message: \"No PRINT command found\" },\n// ]}\n```\n\nTSC validation: SIZE order, CLS before elements, PRINT required, DENSITY 0-15, SPEED 1-18.\nZPL validation: ^XA/^XZ required, ^FD without ^FO, ^PW range.\n\n### Printer Profiles\n\nAuto-configure DPI, paper width, and capabilities based on printer model:\n\n```ts\nimport { label, getProfile, findByVendorId } from \"portakal\";\n\n// Auto-DPI from profile\nlabel({ width: 40, height: 30, printer: \"tsc-te310\" }); // 300 DPI\nlabel({ width: 80, printer: \"epson-tm-t88vi\" }); // 203 DPI\n\n// Lookup profiles\ngetProfile(\"zebra-zd420\"); // { name, dpi, paperWidth, ... }\nfindByVendorId(0x04b8); // All Epson printers\n```\n\n20 built-in profiles: Epson, Star, Bixolon, Citizen, TSC, Zebra, SATO, Honeywell, Generic.\n\n## Supported Printer Languages\n\n| Language        | Printers                                       | Status             |\n| :-------------- | :--------------------------------------------- | :----------------- |\n| **TSC/TSPL2**   | TSC, Gprinter, Xprinter, iDPRT, Munbyn, Polono | :white_check_mark: |\n| **ZPL II**      | Zebra GK420, ZT410, ZD620, ZQ series           | :white_check_mark: |\n| **EPL2**        | Zebra LP/TLP 2824, GX420, ZD220, ZD420         | :white_check_mark: |\n| **CPCL**        | Zebra QLn, ZQ mobile printers                  | :white_check_mark: |\n| **DPL**         | Honeywell/Datamax label printers               | :white_check_mark: |\n| **SBPL**        | SATO label printers                            | :white_check_mark: |\n| **ESC/POS**     | Epson, Bixolon, Citizen, Star (compat mode)    | :white_check_mark: |\n| **Star PRNT**   | Star TSP100/143/600/700 (native mode)          | :white_check_mark: |\n| **IPL**         | Intermec/Honeywell printers                    | :white_check_mark: |\n| **PPLA/PPLB**   | Argox (use DPL/EPL/ZPL)                        | :white_check_mark: |\n| **Fingerprint** | Honeywell Smart Printers                       | Planned            |\n\n## Transport\n\nportakal generates commands only — it does **not** handle printer connections. Send the output over any transport you choose:\n\n```ts\nimport { label } from \"portakal/core\";\nimport { tsc } from \"portakal/lang/tsc\";\nimport { escpos } from \"portakal/lang/escpos\";\nimport net from \"node:net\";\n\nconst myLabel = label({ width: 40, height: 30 }).text(\"Hello\", { x: 10, y: 10 });\nconst commands = tsc.compile(myLabel);\n\n// TCP (port 9100)\nconst socket = net.createConnection({ host: \"192.168.1.100\", port: 9100 });\nsocket.write(commands);\nsocket.end();\n\n// ESC/POS (binary) over WebUSB\nconst receipt = label({ width: 80 }).text(\"Receipt\");\nconst bytes = escpos.compile(receipt);\nawait usbDevice.transferOut(endpointNumber, bytes);\n```\n\n## Comparison\n\n| Feature                      |            portakal            | [node-thermal-printer](https://github.com/Klemen1337/node-thermal-printer) | [escpos](https://github.com/node-escpos/driver) | [jszpl](https://github.com/DanieLeeuwner/JSZPL) |\n| :--------------------------- | :----------------------------: | :------------------------------------------------------------------------: | :---------------------------------------------: | :---------------------------------------------: |\n| Zero dependencies            |       :white_check_mark:       |                          :x: (pngjs, iconv-lite)                           |             :x: (get-pixels, jimp)              |               :white_check_mark:                |\n| TypeScript-first             |       :white_check_mark:       |                                  Partial                                   |                     Partial                     |               :white_check_mark:                |\n| Multi-language output        | :white_check_mark: 9 languages |                              :x: ESC/POS only                              |                :x: ESC/POS only                 |                  :x: ZPL only                   |\n| Transport-agnostic           |       :white_check_mark:       |                               :x: (coupled)                                |                  :x: (coupled)                  |               :white_check_mark:                |\n| Label printers (TSC/ZPL/EPL) |       :white_check_mark:       |                                    :x:                                     |                       :x:                       |                    ZPL only                     |\n| Receipt printers (ESC/POS)   |       :white_check_mark:       |                             :white_check_mark:                             |               :white_check_mark:                |                       :x:                       |\n| Image support                |       :white_check_mark:       |                             :white_check_mark:                             |               :white_check_mark:                |               :white_check_mark:                |\n| Barcode/QR (via etiket)      |       :white_check_mark:       |                             :white_check_mark:                             |               :white_check_mark:                |               :white_check_mark:                |\n| Image dithering              |       :white_check_mark:       |                                    :x:                                     |                       :x:                       |                       :x:                       |\n| Receipt layout engine        |       :white_check_mark:       |                                  Partial                                   |                       :x:                       |                       :x:                       |\n| SVG preview                  |       :white_check_mark:       |                                    :x:                                     |                       :x:                       |                       :x:                       |\n| Command parser (reverse)     |  :white_check_mark: 9 parsers  |                                    :x:                                     |                       :x:                       |                       :x:                       |\n| Cross-compiler (translate)   |  :white_check_mark: 63 paths   |                                    :x:                                     |                       :x:                       |                       :x:                       |\n| Command validation           |       :white_check_mark:       |                                    :x:                                     |                       :x:                       |                       :x:                       |\n| Printer profiles             |     :white_check_mark: 20      |                                    :x:                                     |                       :x:                       |                       :x:                       |\n| Works in browser             |       :white_check_mark:       |                                    :x:                                     |                       :x:                       |               :white_check_mark:                |\n| No native modules (no gyp)   |       :white_check_mark:       |                                    :x:                                     |                       :x:                       |               :white_check_mark:                |\n| Pure ESM                     |       :white_check_mark:       |                                 :x: (CJS)                                  |                    :x: (CJS)                    |                    :x: (CJS)                    |\n\n**portakal is the only library that generates** 9 printer languages from a single API with zero dependencies.\n\n## Features\n\n- Zero dependencies — pure computation, no native modules, no node-gyp\n- **9 printer languages** — TSC, ZPL, EPL, CPCL, DPL, SBPL, ESC/POS, Star PRNT, IPL\n- **Tree-shakeable** — sub-path exports for every module (`portakal/tsc`, `portakal/image`, etc.)\n- Pure ESM, edge-runtime compatible (Cloudflare Workers, Deno, Bun)\n- TypeScript-first with strict types (tsgo)\n- Transport-agnostic — generates commands, you handle the connection\n- Fluent builder API — one label definition compiles to any language\n- **Image processing** — RGBA → monochrome with 4 dithering algorithms (Floyd-Steinberg, Atkinson, ordered, threshold)\n- **Receipt layout engine** — same-line left+right alignment, tables, word-wrap, separators\n- **SVG preview** — `lang.preview(label)` renders labels without a physical printer\n- **9 parsers** — reverse-parse printer commands back to structured data (TSC, ZPL, EPL, CPCL, ESC/POS, DPL, SBPL, Star PRNT, IPL)\n- Drawing primitives — box, line, circle, diagonal\n- Raw command passthrough for advanced/unsupported features\n- Optional [`etiket`](https://github.com/productdevbook/etiket) integration for barcode/QR images (40+ formats)\n- Works in browser, Node.js, Deno, Bun, Electron\n- **UTF-8 encoding engine** — auto code page selection (CP437, CP858, CP1252, CP866, CP857)\n- **Cross-compiler** — convert between any languages (63 paths: TSC↔ZPL↔EPL↔CPCL↔DPL↔SBPL↔IPL↔ESC/POS↔Star)\n- **Real validation** — parameter ranges, command order, structure checks\n- **20 printer profiles** — auto-DPI, auto-width by model (Epson, Star, Zebra, TSC, SATO, etc.)\n- **Language modules** — each language is a standalone module (compile + parse + preview + validate)\n- **Per-language SVG preview** — TSC fonts differ from ZPL fonts, ESC/POS renders receipt-style\n- 447 tests across 28 test files\n\n## Help Us Test — Real Printer Output Needed\n\nWe're building the most accurate open-source printer language SDK, but we need **real-world validation**. If you have access to a thermal printer, we'd love your help comparing portakal's output against actual printed labels.\n\n### How to help\n\n1. **Pick a language** — ZPL, TSC, EPL, CPCL, or any supported language\n2. **Write a test label** — use portakal to generate commands, or paste raw printer code into the [Playground](https://portakal.productdevbook.com)\n3. **Print it** — send the commands to a real printer\n4. **Compare** — take a photo of the printed label and a screenshot of portakal's SVG preview\n5. **Report** — open an [issue](https://github.com/productdevbook/portakal/issues/new) with:\n   - The printer code (ZPL, TSC, etc.)\n   - Screenshot of portakal's preview\n   - Photo of the actual printed label\n   - What's different (position, font size, spacing, barcode, etc.)\n\n### Example: ZPL test label\n\n```zpl\n^XA\n^CF0,60\n^FO50,50^GB100,100,100^FS\n^FO75,75^FR^GB100,100,100^FS\n^FO93,93^GB40,40,40^FS\n^FO220,50^FDIntershipping, Inc.^FS\n^CF0,30\n^FO220,115^FD1000 Shipping Lane^FS\n^FO220,155^FDShelbyville TN 38102^FS\n^FO50,250^GB700,3,3^FS\n^CFA,30\n^FO50,300^FDJohn Doe^FS\n^FO50,340^FD100 Main Street^FS\n^FO50,380^FDSpringfield TN 39021^FS\n^BY5,2,270\n^FO100,550^BC^FD12345678^FS\n^FO50,900^GB700,250,3^FS\n^FO400,900^GB3,250,3^FS\n^CF0,40\n^FO100,960^FDCtr. X34B-1^FS\n^CF0,190\n^FO470,955^FDCA^FS\n^XZ\n```\n\nPaste this into the [Playground](https://portakal.productdevbook.com) (Validate tab, select ZPL) and compare with [Labelary](http://labelary.com/viewer.html) or your real printer.\n\n### What we're looking for\n\n| Area                      | What to check                                                                                            |\n| :------------------------ | :------------------------------------------------------------------------------------------------------- |\n| **Text positioning**      | Are texts at the correct x,y? Do they overflow?                                                          |\n| **Font sizes**            | Does `^CF0,60` look the same size as the real printer?                                                   |\n| **Font rendering**        | Font 0 should be proportional (Helvetica-like), Font A should be monospace                               |\n| **^FR reverse (XOR)**     | The Intershipping logo (3 overlapping boxes) should show black L-shape + white area + small black square |\n| **Barcodes**              | Correct height from `^BY`? Correct width? Readable interpretation line?                                  |\n| **Box/line thickness**    | Does `^GB` draw borders inward? Correct corner radius?                                                   |\n| **^LH, ^LS, ^LT offsets** | Do label home / shift / top offsets apply correctly?                                                     |\n| **ESC/POS receipts**      | Alignment, bold, text sizing on Epson/Star/Bixolon                                                       |\n\nEven a \"looks correct\" confirmation is helpful. Every report makes the SDK more reliable for everyone.\n\n\u003e [!TIP]\n\u003e No printer? You can still help by comparing our preview against [Labelary](http://labelary.com/viewer.html) (ZPL) or other online viewers and reporting any visual differences.\n\n## Contributing\n\nContributions are welcome! Here are areas where help is especially appreciated:\n\n- **Arabic/Hebrew RTL** support (bidi algorithm + Arabic shaping)\n- **GS1/UDI label standards** (SSCC, GTIN, FMD, DSCSA templates)\n- **Star TSP100** raster-only text rendering\n- **CJK encoding** (GB18030, Shift_JIS, Big5, EUC-KR)\n- **Fingerprint** (Honeywell BASIC-like) compiler\n- **WebUSB/WebSerial/Web Bluetooth** transport adapters\n- Additional printer profiles\n- Parser validation rules for more languages\n\n```bash\npnpm install    # Install dependencies\npnpm dev        # Run tests in watch mode\npnpm test       # Lint + typecheck + test\npnpm build      # Build for production\n```\n\n## License\n\nPublished under the [MIT](https://github.com/productdevbook/portakal/blob/main/LICENSE) license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fproductdevbook%2Fportakal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fproductdevbook%2Fportakal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fproductdevbook%2Fportakal/lists"}