npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

p1-printer-sdk

v1.0.1

Published

Node.js and TypeScript SDK with template rendering for Paperang P1 thermal printers.

Readme

Paperang P1 Printer SDK

English

这是一个面向 Paperang P1(喵喵机 P1)的 Node.js 22 + TypeScript SDK,同时提供本地可视化模板编辑器。

你可以在浏览器编辑器中设计 384 点宽的打印模板,把模板 JSON 保存在自己的项目里,再通过 模板 ID + 变量数据 从 Node.js 后端、Nuxt 服务端接口、Electron 主进程或自动化脚本中打印。

本项目已在 Windows 上通过蓝牙 SPP 虚拟 COM 端口和真实 Paperang P1 测试。

功能

  • 384 点宽可视化模板编辑器和 1:1 黑白打印预览。
  • 模板 JSON 保存在当前项目中,并可通过下拉列表切换。
  • 支持固定文字、变量文字、固定图片和变量图片。
  • 支持字号、字重、对齐方式和行距。
  • 支持图片亮度、对比度、裁切方式、阈值、Floyd-Steinberg 和 Bayer 抖动。
  • 支持自动纸张高度和手动纸张高度。
  • 根据模板生成 TypeScript 类型,自动提示模板 ID 和变量名。
  • 支持 Windows COM 端口配置、连接状态和详细打印日志。
  • 内置 P1 协议分包、CRC32、位图转换、打印浓度和走纸处理。

使用条件

  • Node.js 22 或更高版本。
  • 推荐使用 Windows。
  • 一台已经与电脑完成蓝牙配对的 Paperang P1。
  • Windows 为打印机创建的蓝牙 SPP 传出 COM 端口。

SDK 需要在 Node.js 环境中访问串口和处理图片,不能直接运行在纯浏览器代码中。Nuxt 应放在服务端接口中,Electron 应放在主进程中。

新手教程

第 1 步:配对打印机并找到 COM 口

  1. 打开 Paperang P1 电源。
  2. 在 Windows 蓝牙设置中完成配对。
  3. 打开高级蓝牙设置,找到属于打印机的传出 COM 端口。
  4. 记住端口号,例如 COM13

如果 Windows 显示多个蓝牙端口,请选择与打印机对应的“传出”串行端口(SPP),不要选择传入端口。

第 2 步:安装 SDK

进入你的 Node.js、Nuxt 或 Electron 项目目录,运行:

npm install p1-printer-sdk

npm 可能会隐藏依赖包的 postinstall 提示。即使安装后没有显示提示,也可以直接继续初始化。

第 3 步:初始化项目

npx p1-printer init

初始化程序会依次询问:

Template directory [./printer-templates]:
Printer COM port [COM13]:
Add an npm run printer script? [y]:

直接按 Enter 会采用方括号中的默认值,也可以输入自己的模板目录和 COM 口。初始化完成后会在当前项目中创建:

你的项目/
├── p1-printer.config.json
├── printer-templates/
│   └── hello-world.json
└── package.json

模板不会保存到 node_modules,也不会保存到操作系统的隐藏目录中。

如果要跳过提问并直接使用 ./printer-templatesCOM13

npx p1-printer init --yes

第 4 步:打开可视化编辑器

如果初始化时选择了添加 npm 脚本,运行:

npm run printer

否则运行:

npx p1-printer editor

命令会启动本地服务器、自动选择一个可用端口并打开浏览器。服务器只监听 127.0.0.1,不会暴露给局域网中的其他电脑。

在编辑器中按下面的顺序操作:

  1. 从下拉列表选择已有模板,或点击 New 新建模板。
  2. 添加文字或图片元素。
  3. 在左侧设计画布中拖动元素。
  4. 在属性面板中调整内容、位置和样式。
  5. 在右侧 1:1 预览中检查最终黑白效果。
  6. 点击 Save,模板会写入配置的模板目录。
  7. 确认右上角 COM 口,点击 Test Print 测试打印。

Import 用来导入外部模板 JSON,Export 用来下载当前模板 JSON,Delete 用来删除当前模板目录中的选中模板。

第 5 步:理解固定元素和变量元素

每个文字或图片元素都有一种角色:

  • static:内容保存在模板中,每次打印都不会变化。
  • variable:打印时由你的代码通过变量名传入真实内容。

例如,一个变量文字元素可以设置为:

Binding: customerName
Placeholder: 预览姓名

Binding 是代码传值时使用的变量名。Placeholder 只用于编辑器预览,正式打印时必须传入 customerName;缺少变量会直接报错,不会偷偷打印占位内容。

变量图片支持本地文件路径、HTTP/HTTPS 地址和 Base64 Data URL。

第 6 步:生成 TypeScript 自动提示

保存或修改模板后运行:

npx p1-printer generate-types

命令会扫描模板目录,并默认生成 p1-printer.generated.ts。如果模板中包含 customerNameavatar,生成的类型类似:

export type P1TemplateRegistry = {
  "customer-label": {
    customerName: string | number | boolean | null
    avatar: string
  }
}

这样 TypeScript 就能在运行前发现不存在的模板 ID、拼错的变量名和缺少的变量值。

第 7 步:从 Node.js 或 TypeScript 打印

import { createP1PrinterSDK, loadP1Config } from "p1-printer-sdk"
import type { P1TemplateRegistry } from "./p1-printer.generated.js"

const config = await loadP1Config()

const sdk = createP1PrinterSDK<P1TemplateRegistry>({
  printer: {
    port: config.printer.port
  },
  templates: {
    dir: config.templatesPath
  }
})

await sdk.printTemplate("hello-world", {
  text: "你好,喵喵机 P1"
})

请从包含 p1-printer.config.json 的项目中启动程序。配置加载器会从当前目录开始向上查找配置文件。

配置文件

npx p1-printer init 会创建 p1-printer.config.json

{
  "templatesDir": "./printer-templates",
  "printer": {
    "port": "COM13"
  },
  "generatedTypes": "./p1-printer.generated.ts"
}

| 字段 | 作用 | | ---------------- | ---------------------------------------------------------------- | | templatesDir | 模板 JSON 所在目录,可以使用项目相对路径或绝对路径。 | | printer.port | Windows COM 口或其他受支持的串口/蓝牙目标。 | | generatedTypes | 生成的 TypeScript 类型文件路径,可以使用项目相对路径或绝对路径。 |

编辑器启动时会读取这份配置。你也可以在编辑器中临时修改 COM 口。

模板规则

  • 文件名就是模板 ID:customer-label.json 对应 customer-label
  • JSON 内的 id 必须和去掉 .json 后的文件名一致。
  • ID 可以包含字母、数字、下划线和连字符。
  • Paperang P1 画布宽度固定为 384 点。
  • 变量元素必须设置唯一、容易理解的 binding
  • 无效的 JSON 会在模板列表中显示为无效项,不会导致整个编辑器崩溃。

模板元素示例:

{
  "id": "el_customer_name",
  "name": "Customer Name",
  "type": "text",
  "role": "variable",
  "binding": "customerName",
  "placeholder": "预览姓名",
  "x": 24,
  "y": 24,
  "width": 336,
  "height": 52,
  "style": {
    "fontSize": 32,
    "fontWeight": 700,
    "align": "center",
    "lineSpacing": 1.15
  }
}

CLI 命令

npx p1-printer init
npx p1-printer editor
npx p1-printer templates list
npx p1-printer generate-types

常用选项:

init --yes                     直接采用初始化默认值
init --templates <path>        指定模板目录
init --port <COM13|13>         指定打印机端口
init --no-script               不添加 npm run printer
editor --templates <path>      临时覆盖模板目录
editor --port <COM13|13>       临时覆盖打印机端口
editor --port-number <number>  指定本地网页服务器端口
editor --no-open               启动后不自动打开浏览器
generate-types --out <path>    临时覆盖类型文件输出位置

Nuxt 服务端示例

打印代码应放在 Nuxt 服务端接口中,不要放在浏览器中的 Vue 组件里:

// server/api/print.post.ts
import { createP1PrinterSDK, loadP1Config } from "p1-printer-sdk"
import type { P1TemplateRegistry } from "../../p1-printer.generated.js"

export default defineEventHandler(async (event) => {
  const body = await readBody<{ text: string }>(event)
  const config = await loadP1Config()
  const sdk = createP1PrinterSDK<P1TemplateRegistry>({
    printer: { port: config.printer.port },
    templates: { dir: config.templatesPath }
  })

  await sdk.printTemplate("hello-world", {
    text: body.text
  })

  return { ok: true }
})

Nuxt 服务端必须运行在连接打印机的 Windows 电脑上。部署在远程服务器上的程序无法访问你电脑上的 COM 口。

主要 SDK API

createP1PrinterSDK(options)

创建高级 SDK 实例。只需要配置一次打印机目标和模板目录。

sdk.printTemplate(templateId, data, options?)

渲染并打印指定模板。可选参数可以临时覆盖 densityfeedLines

sdk.renderTemplatePreview(templateId, data)

只渲染黑白 PNG Buffer,不会连接打印机。

sdk.listTemplates() / sdk.getTemplate(id)

列出或读取配置目录中的模板。

sdk.saveTemplate(template)

验证并保存模板 JSON。

P1Printer

当你不需要模板 SDK 时,可以使用这个类进行更底层的连接和图片打印。

常见问题

找不到 p1-printer.config.json

在你的项目目录中运行:

npx p1-printer init

无法打开 COM 口

  • 确认打印机已经开机并完成配对。
  • 在 Windows 蓝牙设置中再次确认传出 COM 口。
  • 修改 p1-printer.config.json 中的 printer.port
  • 关闭可能占用同一个 COM 口的其他程序。

预览正常,但打印时提示缺少变量

预览可以显示 Placeholder,正式打印要求 data 包含所有变量元素的 Binding。修改 Binding 后请重新生成类型。

图片打印效果不好

  • threshold 适合文字、二维码和边缘清晰的图形。
  • floyd-steinberg 适合照片。
  • bayer 适合规则网点效果。
  • 可以继续调整图片元素的亮度、对比度和阈值。

安装 bluetooth-serial-port 时出现警告

它是可选依赖。Windows 推荐使用下面的连接方式:

Windows 蓝牙配对 -> 传出虚拟 COM 口 -> serialport

协议参考

协议实现参考公开 Python 项目 ihciah/miaomiaoji-tool

  • 经典蓝牙 SPP / RFCOMM。
  • 固定宽度 384 点,每行 48 字节。
  • 黑点为 1,白点为 0
  • 使用 CRC32 协议分包。
  • 单个数据包最大 payload 为 2016 字节。

许可证

MIT