Doop
Doop is an open-source multiplayer design canvas and design MCP for Claude Code, Codex, and any AI agent. Design side by side with agents — free in beta.
翻译准备中
尚未收集仓库信息。
尚未检测到更新。GitHub 发布版本后会显示在这里。
supporting various label printers using webusb
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗Design labels and print them straight from your browser to DYMO LabelWriter and Brother P-touch / QL label printers. No drivers, no CUPS, no server: the page renders your design to the exact dots the printer will burn and sends them over WebUSB or Web Serial (Bluetooth). Continuous rolls are first class: a label is as long as its content, or any length you choose.
See it at its real size before you print. Under the editor, the label is drawn at its actual size on your screen: calibrate once by holding a bank card against it, then hold the label, the cable or the jar lid up to the screen to check it fits. As far as we know, none of the other label editors listed under Other tools do this.
Open it: https://mofosyne.github.io/web-label-editor/ (Chrome, Edge or another Chromium browser on desktop to print; any browser to design)
This editor is for you if:
Another tool may suit you better if:
More in Other tools.
Label printers are simple machines: they take rows of dots and burn them onto paper or tape. Yet on Linux, using one is a chore:
A web page that talks to the printer directly fixes that for everyone at once: the same editor on Linux, Windows, macOS and ChromeOS, no installs, and continuous rolls treated as the normal case rather than an afterthought.
Ease of use over features. It does less on purpose. The aim is not the longest feature list: it is that making a label is quick and obvious. Click the text and type; it fits its box; the preview is what prints; the printer just works. A feature earns its place only if it doesn't make that everyday case harder, and the rest below follows from this.
Reuse the lessons commercial label software already learned the hard way, instead of relearning them. Over years of users, programs like the original DYMO Label and Brother's P-touch Editor settled on things that work: text you edit right on the label, text that shrinks to fit rather than getting cut off, a canvas that is the real label size with the unprintable edges shown, picking the label from a list instead of typing dimensions, quick reprints of past labels, and undo for everything. Where they got it right, copy it; don't make users discover the same problems again.
| Printer | Status | Protocol | Connection | Labels / notes |
|---|---|---|---|---|
| DYMO LabelWriter 450 | ✅ Tested | DYMO LabelWriter raster | USB | LabelWriter labels, up to 62 mm; 300 × 600 dpi tested |
| DYMO LabelWriter 450 Turbo | 🧪 Experimental | DYMO LabelWriter raster | USB | LabelWriter labels, up to 62 mm |
| DYMO LabelWriter 400 / 400 Turbo | 🧪 Experimental | DYMO LabelWriter raster | USB | LabelWriter labels, up to 62 mm |
| DYMO LabelWriter 450 Duo (label side) | 🧪 Experimental | DYMO LabelWriter raster | USB | LabelWriter labels, up to 62 mm |
| DYMO LabelWriter 450 Twin Turbo | 🧪 Experimental | DYMO LabelWriter raster | USB | LabelWriter labels, up to 62 mm |
| DYMO LabelWriter 4XL | 🧪 Experimental | DYMO LabelWriter raster | USB | LabelWriter labels, up to 104 mm |
| DYMO LabelWriter SE450 | 🧪 Experimental | DYMO LabelWriter raster (SE450 subset) | USB | LabelWriter labels, up to 62 mm |
| DYMO LabelManager PnP / 280 / 420P / 500TS (D1 tape label makers) | ⬜ Unimplemented | DYMO LabelManager | DYMO's tape label makers, like P-touch. Different protocol, and some first appear as a USB drive; Labelle supports them. | |
| Brother PT-P710BT (USB) | ✅ Tested | Brother P-touch raster | USB | TZe tape, up to 24 mm |
| Brother PT-P710BT (Bluetooth) | 🧪 Experimental | Brother P-touch raster | Bluetooth | TZe tape, up to 24 mm |
| Brother PT-P700 | 🧪 Experimental | Brother P-touch raster | USB | TZe tape, up to 24 mm |
| Brother PT-P750W | 🧪 Experimental | Brother P-touch raster | USB | TZe tape, up to 24 mm |
| Brother PT-H500 | 🧪 Experimental | Brother P-touch raster | USB | TZe tape, up to 24 mm |
| Brother PT-E500 | 🧪 Experimental | Brother P-touch raster | USB |
Tried a printer? Report how it went, whether it worked or not: reports are how printers move from 🧪 to ✅. Missing a label or tape size? Request it. The app links to these forms pre-filled with your printer, label, OS and browser.
✅ Tested: printed on real hardware. 🧪 Experimental: uses a protocol path checked against a reference implementation, but nobody has printed on that model with this app yet. ⬜ Unimplemented: not supported yet.
The same table is in the app under Help → Printers. Adding a printer is described below.
sudo ./install-udev-rules.sh
once (USB access for DYMO and Brother printers, --remove to undo), then
./start.sh: it serves the app on this computer only, at
http://localhost:8737/, and opens it in Chromium, Chrome or Edge. It
needs Python 3, which most Linux systems have. Opening index.html
directly doesn't work: browsers only allow USB on secure pages, and
localhost is one, a file isn't.A computer with the printer plugged in (a Raspberry Pi, a NAS, even an ESP32) can host the editor for every device on the network: phones, tablets, Firefox and Safari included, none of which can reach a USB printer themselves. The editor finds the printer on that server by itself, and Print sends the label there.
python3 scripts/print-server.py --model dymo-lw450 --device /dev/usb/lp0
That is the reference server (standard-library Python, also in the offline download). Other servers, such as brother_ql_web or a home-made one, can do the same by serving the editor's files next to two small endpoints: docs/PRINT-SERVER-API.md is the contract.
The app has its own welcome page and Help with the same information.
{{Name}} (a column),
{{n}} (a counter) or {{date}} / {{time}} in any text, QR code or
barcode (double braces, as in most mail merges, so a single {brace} in
a label stays text).
The Batch… button, next to Copies, walks through it: open a data file or paste cells (Try an
example shows the same example data as CSV, JSON, a Markdown table and so on), click the fields to put on the label, check each label, print. Data comes from
spreadsheet cells, a CSV, a Markdown table, JSON or a GNU recfile. A CSV or a pasted list
without column names (say, a list of serial numbers) is spotted, and its columns are
{{A}}, {{B}}…; a tick box says otherwise when the guess is wrong. Print makes one label per chosen row, as one job
where the printer allows. Step through the labels before printing to check
each one fits; the counter carries on from where the last print stopped.
The data is saved with the label, so a saved label is a template.This editor does not go through the operating system's print system (CUPS on Linux and macOS, the spooler on Windows). The browser opens the printer's USB or Bluetooth connection itself and sends the printer's own raster commands.
Why:
The trade-offs:
usblp kernel driver, which holds the printer for as long as it's
plugged in (see Linux setup below).The browser opens the printer's USB device itself (see Direct USB above). If you see "Failed to execute 'open' on 'USBDevice': Access denied", the operating system is keeping the browser out. The fix depends on the OS.
Give your desktop user access to the printers with a udev rule:
sudo tee /etc/udev/rules.d/60-label-printers.rules <<'RULES'
# DYMO
SUBSYSTEM=="usb", ATTRS{idVendor}=="0922", TAG+="uaccess"
# Brother
SUBSYSTEM=="usb", ATTRS{idVendor}=="04f9", TAG+="uaccess"
RULES
sudo udevadm control --reload-rules && sudo udevadm trigger
Then unplug and replug the printer. (uaccess grants the logged-in desktop
user access. On a system without it, use MODE="0666" instead of
TAG+="uaccess".)
Browser installed as a snap or Flatpak? You also need this. Ubuntu ships Chromium as a snap, and snaps and Flatpaks are sandboxed away from USB devices even after the udev rule. Grant access once, then quit and restart the browser:
# Snap (Ubuntu's Chromium; check with: snap list chromium)
sudo snap connect chromium:raw-usb
# Flatpak (check with: flatpak list --app; use your browser's app ID)
flatpak override --user --device=all com.google.Chrome
flatpak override --user --device=all org.chromium.Chromium
If a Flatpak browser still can't see the printer, a browser from your distribution's regular packages (or Google's own Chrome package) avoids the sandbox.
lsusb -t shows the printer's Driver=: usblp is the kernel
printer driver (below); usbfs means a program has it, usually CUPS mid-job,
so close it or sudo systemctl stop cups while printing from here. If
modprobe -r usblp reports the module is in use, stop CUPS first.
sudo modprobe -r usblp. It comes back on the
next plug-in or reboot.echo 'blacklist usblp' | sudo tee /etc/modprobe.d/no-usblp.conf.
This applies to every USB printer. Check lpstat -v first: a usb://
address means CUPS uses its own libusb backend and does not need usblp;
a /dev/usb/lp0 address means it does, so use the temporary option.sudo rm /etc/modprobe.d/no-usblp.conf && sudo modprobe usblp.sudo rm /etc/udev/rules.d/60-label-printer.rules,
then replug.Windows' own printer driver (usbprint) owns the device. Either
Usually works. If access is denied, another program has the printer: quit DYMO Connect, the DYMO Web Service (menu bar) or P-touch Editor, then unplug and replug.
Usually works. On ChromeOS, remove the printer from Settings → Printers if it was added there.
The app explains this itself: when the browser is refused, a How to fix… button opens the steps for your system, with the commands for your exact printer.
P-touch models with Bluetooth (PT-P710BT, D460BT, D610BT, E310BT, E560BT) print over Bluetooth Classic (Serial Port Profile), which browsers reach through Web Serial. That is not Web Bluetooth, which only covers Bluetooth Low Energy.
This needs Chrome or Edge 117 or later on the desktop; Android support for Bluetooth serial is not confirmed. On Windows this is the easiest route because it needs no driver swap. Bluetooth is slower than USB, so long labels take a few seconds to send.
Try it first with "Custom size…". On a LabelWriter or a Brother QL, the last entry in Media takes any size (third-party rolls, round stickers): die-cut or continuous, width and length, corner radius or round, and a safe margin. Print the Grid test, then Generate report opens a label request with a ready record for the catalogue (or copy it, or save it as a file). Round labels show as a circle, with the safe area a circle inset from the edge. On a Brother QL it is experimental: the printer is sent the size, so enter the roll's own, and where it can print is an estimate (3 mm less than the label, the offset of the nearest Brother size) to fine-tune with the Grid test. Brother's round DK labels (12, 24 and 58 mm) are in the list.
Label and tape sizes live in catalog/media.rec, a
GNU recutils file: one record per
label, one field per line, with comments. Each record belongs to a printer
family (dymo-lw, brother-pt, brother-ql); every model in the family whose
head is wide enough offers it. To add one, copy a similar record,
give it a new Id, and fill in the sizes in millimetres. The comments at the
top of the file describe every field.
Id: 30252
Family: dymo-lw
Name: 30252 Address 28 × 89 mm
Kind: diecut
WidthMm: 27.86
LengthMm: 88.9
MarginLeftMm: 5.84
MarginRightMm: 1.52
MarginTopMm: 1.02
MarginBottomMm: 1.52
CornerMm: 3
Source: lw450.ppd 30252: 78.96 x 252 pt, imageable 4.32 4.32 76.08 235.44
Id: saved designs refer to labels by it.Source (a driver file, a datasheet,
or "measured").recfix catalog/media.rec (from the recutils
package). CI runs that too, and checks that the app's parser reads the file
exactly as recsel does.Why recutils: the catalogue is flat, hand-edited data where every number
needs a comment saying where it came from. One field per line keeps diffs and
merges clean, and recfix validates types, required fields and unique ids.
Designs stay JSON because they are nested and written by the app.
Not listed? Try "Other printer". Pick Other printer (ZPL, TSPL or
ESC/POS) and describe yours: the language it speaks (ZPL for Zebra and its
many compatibles, TSPL for most budget 4 × 6 shipping printers, ESC/POS
raster for receipt-style printers), its resolution, head width and label
size. Print the Grid test, adjust until it lines up, and send the report:
the app fills in the settings you used, and a set that works becomes the
printer's own entry (in catalog/printers.rec).
This is experimental by design: these printers differ in how they sense
labels and which way round they print. Generate report in that panel
shows the settings to copy or save as a file, and opens the GitHub issue
with them filled in.
Maintainers: docs/MAINTAINING.md says how each kind of report becomes support, and the checks to run.
src/printers/generic.js), add an entry to MODELS in
src/printers/models.js with its USB IDs, head
width and quirks. Otherwise add an encoder (bitmap → bytes) next to the
others, ported from a reference implementation, with tests that check its
output against that reference.tested only once
someone has printed on that model with this app, otherwise
experimental. Devices not supported yet go in
src/compat.js.npm run docs to regenerate the table above, and npm test.Tested a printer marked experimental, or one that isn't listed? Report how it went (the app's report link pre-fills your printer, label, OS and browser).
design (mm, per label)
│ render.js: each label of the row, plus any overprint border
▼
view bitmap (printer dots) ◀── layout.js: label slots, overprint border,
│ and what the head can reach
│ x = along the feed, y = across the head
│ layout.js jobBitmap: position adjustment, leading-margin skip,
│ crop to the reach
▼
job bitmap ──encoder (per printer family)──▶ bytes ──▶ WebUSB / Web Serial
The preview and the printer get the same view bitmap, which is what makes the preview exact. Design decisions worth knowing:
layout.js pageToStrip). Items on the
second label of a 2-up row carry lane: 1.band is the printable part
(ptouch-print's and brother_ql's printable dots, centred on the tape or
label); the preview hatches the rest and the job sent to the printer is
just the band, so the encoders still receive printable-width bitmaps.src/ by npm run docs, and
the help pages read the same data, so neither drifts from the app.Files:
src/app.js: the editor UI, preview, printing and storage.src/render.js: design → bitmap for one label, via an off-screen canvas.src/layout.js: the view (row of labels, overprint border, reach of the
head), row modes, and the view → job transform.src/printers/dymo-labelwriter.js: LabelWriter 400/450/4XL commands
(ESC L, ESC D, SYN raster lines, ESC G/ESC E), from DYMO's
dymo-cups-drivers.src/printers/brother-ptouch.js: P-touch raster mode with per-model
quirks, from
ptouch-print.src/printers/brother-ql.js: QL raster mode, from
brother_ql.src/printers/models.js, src/compat.js: printer models, their status and
the compatibility table.catalog/media.rec, src/recfile.js, src/catalog.js: the label catalogue,
a small recutils reader, and the code that turns records into media.src/calibration.js, src/rolls.js: test print patterns, and saved rolls
with their calibration codes.src/codes/qr.js, src/codes/barcode.js: QR (byte mode, versions 1–40,
levels L/M/Q/H), Code 128, EAN-13 and UPC-A encoders, verified by decoding
every QR version and level at full capacity, and the linear codes, with
the zxing-cpp reader.src/undo.js, src/library.js: undo history; saved labels and print
history.src/about.js, src/help.js, src/others.js, src/report.js: the
welcome and help pages, connection help, the other-tools list, and the
pre-filled issue links.src/transport.js: WebUSB and Web Serial. The printer is claimed only while
printing, so other programs can use it in between.Plain HTML and JavaScript modules, no build step.
npm run serve # http://localhost:8000
npm test # unit tests
npm run docs # regenerate this README's generated sections and sw.js's file list
npm run package # dist/: the site as deployed, and the offline download (zip)
npm run screenshots # regenerate docs/screenshots (needs Playwright + Chromium)
The published site registers a service worker (sw.js) that caches the app
for offline use; it isn't registered on plain http, so local development
always loads the files as they are.
Before merging a change a user can see, go through docs/UX-CHECKLIST.md.
Tests check every encoder's command stream byte by byte against its reference
implementation's logic, the catalogue against recsel/recfix (when
recutils is installed), the layout and undo logic, and that this README's
generated sections match the code.
.github/workflows/ci.yml runs the tests on every push and pull request and
deploys main to GitHub Pages, with the offline zip built by npm run package.
This editor does less on purpose: fewer features than some of the tools below, but the everyday label is quick to make and prints where you expect. Low-level libraries for these printers are plentiful; label editors are rarer, mostly cover one brand, and often print through CUPS or a small server. This one aims at DYMO LabelWriter and Brother printers together, continuous rolls, text edited in place that fits its box, and a true preview of the printable area, also at real size; if one of these fits you better, use it. Developers: the libraries are where most of the protocol knowledge lives.
🤖 AI-assisted marks projects written largely with AI coding assistants ("vibe coded"), judged from their own commits, README or AI config files as of October 2026. This editor is AI-assisted too: written largely with Claude Code, but steered by use rather than by a feature list. Its author tries each change on real printers and labels, and judges it by how it feels to use: whether the everyday label got quicker or clearer, often by borrowing what commercial label software already learned. Many requests end up smaller than first asked, or as a ticket for later.
Label editors in the browser, printing directly
Desktop label editors
Self-hosted web interfaces (a server, e.g. a Raspberry Pi, drives the printer)
Libraries, drivers and command-line tools
More
This editor stands on work others did first. No third-party files are bundled, but parts of the code are ports of the projects below, kept under licences compatible with this project's GPL-3.0 and credited in each file; the tests check the ports against their sources' behaviour.
Printer protocols
Ported code (which of our files comes from where)
Standards and tools
Measurements
GPL-3.0-or-later (see LICENSE), with one file held at GPL-3.0
only: each source file says which in its SPDX-License-Identifier line.
src/printers/brother-ptouch.js is GPL-3.0-only: it is ported from
ptouch-print,
which is licensed under GPL version 3 without the "or later" option.src/codes/qr.js is GPL-3.0-or-later and keeps Project Nayuki's MIT
notice, as its structure follows their QR Code generator library.So the editor as a whole can be used under GPL-3.0 today, and every part but the P-touch encoder under any later version too. See Credits for the sources.
| TZe tape, up to 24 mm |
| Brother PT-D600 | 🧪 Experimental | Brother P-touch raster | USB | TZe tape, up to 24 mm |
| Brother PT-D410 | 🧪 Experimental | Brother P-touch raster | USB | TZe tape, up to 18 mm |
| Brother PT-D460BT | 🧪 Experimental | Brother P-touch raster | USB, Bluetooth | TZe tape, up to 18 mm |
| Brother PT-D610BT | 🧪 Experimental | Brother P-touch raster | USB, Bluetooth | TZe tape, up to 24 mm |
| Brother PT-E310BT | 🧪 Experimental | Brother P-touch raster | USB, Bluetooth | TZe tape, up to 18 mm |
| Brother PT-E560BT | 🧪 Experimental | Brother P-touch raster | USB, Bluetooth | TZe tape, up to 24 mm |
| Brother PT-P900 / P900W / P950NW | ⬜ Unimplemented | Brother P-touch raster | 360 dpi with a 560-dot head; needs its own tape table. |
| Brother PT-P300BT | ⬜ Unimplemented | Brother PT-P300BT (BLE) | Bluetooth Low Energy only. |
| Brother QL-500 | 🧪 Experimental | Brother QL raster | USB | DK rolls and labels, up to 62 mm |
| Brother QL-550 | 🧪 Experimental | Brother QL raster | USB | DK rolls and labels, up to 62 mm |
| Brother QL-560 | 🧪 Experimental | Brother QL raster | USB | DK rolls and labels, up to 62 mm |
| Brother QL-570 | ✅ Tested | Brother QL raster | USB | DK rolls and labels, up to 62 mm; printing and cutting tested; 300 × 600 dpi and batches not yet |
| Brother QL-580N | 🧪 Experimental | Brother QL raster | USB | DK rolls and labels, up to 62 mm |
| Brother QL-650TD | 🧪 Experimental | Brother QL raster | USB | DK rolls and labels, up to 62 mm |
| Brother QL-700 | 🧪 Experimental | Brother QL raster | USB | DK rolls and labels, up to 62 mm |
| Brother QL-710W | 🧪 Experimental | Brother QL raster | USB | DK rolls and labels, up to 62 mm |
| Brother QL-720NW | 🧪 Experimental | Brother QL raster | USB | DK rolls and labels, up to 62 mm |
| Brother QL-800 | 🧪 Experimental | Brother QL raster | USB | DK rolls and labels, up to 62 mm |
| Brother QL-810W | 🧪 Experimental | Brother QL raster | USB | DK rolls and labels, up to 62 mm |
| Brother QL-820NWB | 🧪 Experimental | Brother QL raster | USB | DK rolls and labels, up to 62 mm |
| Brother QL-1050 | 🧪 Experimental | Brother QL raster | USB | DK rolls and labels, up to 104 mm |
| Brother QL-1060N | 🧪 Experimental | Brother QL raster | USB | DK rolls and labels, up to 104 mm |
| Brother QL-1100 | 🧪 Experimental | Brother QL raster | USB | DK rolls and labels, up to 104 mm |
| Brother QL-1110NWB | 🧪 Experimental | Brother QL raster | USB | DK rolls and labels, up to 104 mm |
| Brother QL-1115NWB | 🧪 Experimental | Brother QL raster | USB | DK rolls and labels, up to 104 mm |
| Zebra GK420d / GK420t | 🧪 Experimental | ZPL | USB, Bluetooth | Any size you enter |
| Zebra GC420d / GC420t | 🧪 Experimental | ZPL | USB, Bluetooth | Any size you enter |
| Zebra GX420d / GX420t | 🧪 Experimental | ZPL | USB, Bluetooth | Any size you enter |
| Zebra GX430t (300 dpi) | 🧪 Experimental | ZPL | USB, Bluetooth | Any size you enter |
| Zebra LP 2844-Z | 🧪 Experimental | ZPL | USB, Bluetooth | Any size you enter |
| Zebra ZD420 / ZD421 (203 dpi) | 🧪 Experimental | ZPL | USB, Bluetooth | Any size you enter |
| Zebra ZD410 / ZD411 (203 dpi) | 🧪 Experimental | ZPL | USB, Bluetooth | Any size you enter |
| Rollo X1038 | 🧪 Experimental | TSPL | USB, Bluetooth | Any size you enter |
| Rollo Wireless X1040 (by USB) | 🧪 Experimental | TSPL | USB, Bluetooth | Any size you enter |
| Other label printers speaking ZPL, TSPL or ESC/POS raster | 🧪 Experimental | ZPL, TSPL or ESC/POS raster (you describe the printer) | USB, Bluetooth | Any size you enter |
K7QX) to write on the
roll's core. Its calibration code (e.g. K7QX/30252/F5.0/A0.0: ID, label
type, Feed and Across in mm) sets the roll up on another computer via Add
roll from code….