Open-source project
LunarXuan/Pindo avatar
LunarXuan/Pindo

Pindo: a local-first fuse bead pattern generator for photos and pixel art

Local-first fuse bead pattern generator|将图片与像素画转换为带编号、色号和用量统计的拼豆图纸

394 stars16 forksTypeScriptGPL-3.0

At a glance

What is it?
Pindo turns images and unlabeled bead charts into numbered patterns with brand color codes and bead counts, running entirely in the browser. It is a static Next.js app you build and host yourself, not a service.
Who is it for?
Adopt Pindo if you already work with Hama, Perler, Artkal S or one of the other five palettes it ships and you want pattern generation to stay on your own machine; the static export and the browser-side processing make that the default rather than an option. Skip it if you need server-side batch conversion of many images, a documented public API, or a published release history, because none of those appear in the repository.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 17, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap Pindo fills between a photo and a bead tray

Most image-to-pixel-art tools stop at a grid of colored squares. That is not what you need at a table with a tray of beads. You need to know which color code goes in each cell and how many beads of each code to pull. Pindo is built around that second half of the job. The README describes it as a tool for turning photos, illustrations and pixel art into numbered fuse-bead patterns, and it also recognizes existing unlabeled bead charts and adds grid, color-code and usage information to them. The target user is someone working with a specific brand: the project ships eight palettes, MARD, Hama, Perler, Artkal S, COCO, Manman, Panpan and Mixiaowo. If you bead with one of those, the output maps to codes you can order. If you bead with something else, the palette list is the first thing to check. The second audience is people who already have a chart, perhaps a screenshot or a scan, and want it labeled rather than regenerated. That recognition path is a different problem from conversion and the repository keeps it in the same engine directory.

How the conversion pipeline is organized in lib/engine

The repository layout puts the image work in lib/engine/, described as scaling, matching, cleanup and chart recognition. Export lives separately in lib/export/, with PNG and PDF modules, and the compiled brand palettes sit in lib/data/palettes/. That split matters when you evaluate the tool, because the palette data is plain project data rather than something fetched at runtime. The README states that uploaded images are decoded and processed with browser Canvas APIs and typed arrays, and that the application has no image-upload API or application backend. So the data flow is: your file is read in the page, drawn to a canvas, reduced to a bead grid by the scaling and matching code, then rendered with grid lines, color codes and a usage legend. The color matching dependency is color-diff, which suggests nearest-color lookup against the palette entries rather than a learned model. That is a reasonable design for this problem and it also means the quality ceiling is set by the palette data and the dithering strategy, not by training. Dithering is exposed as a user choice, alongside a creative mode, a palette limit and image adjustments. Those are the knobs that decide whether a gradient reads as a gradient or as banding.

Installing Pindo and converting your first image

There is a hosted instance at https://pindo-eight.vercel.app, and the README points there first. For a local install, the development path is two commands. The README gives this example, and npm ci installs from the lockfile rather than resolving fresh versions.

bash
npm ci
npm run dev

The README says to open http://localhost:3000 after that. On Windows there is a double-click path: clone or download the repository and run 启动 Pindo.cmd, which on first launch installs locked dependencies, builds the static application and opens the local server. If you want something closer to production than the dev server, the README gives a separate sequence that builds the static export into out/ and serves it.

bash
npm ci
npm run build
node server.mjs --open

The README states that the static export is generated in out/ and served only on 127.0.0.1 by default. Once the page is open, the workflow is: upload an image, set width and height in beads with the optional aspect-ratio lock, pick a palette and a palette limit, choose a dithering strategy, then read the usage statistics panel for the color codes and bead quantities. PNG export writes the chart with its grid, color codes and usage legend. The Android path is separate and requires generating the project locally first.

bash
npm run android:add
npm run android:sync
npm run android:open

The Capacitor configuration uses application ID com.pindo.app and web directory out. The README warns that Android signing keys such as pindo-release.jks must not be committed.

Where Pindo stops being the right tool

The privacy model is also the main constraint. Because there is no application backend and no image-upload API, there is nothing to call from a script. If you want to convert a folder of two hundred images on a schedule, Pindo gives you no documented way to do it; the engine is TypeScript in lib/engine/ and you would be importing and driving it yourself, which the README does not describe or promise to keep stable. The same applies to the recognition feature: it is a UI path, not an exposed endpoint. A second limitation is the palette list. Eight brands is a real set, but it is a closed set in the shipped data, and the README does not document a supported way to add a ninth palette without touching the project. A third is that no releases were retrieved for this repository, so there is no versioned artifact to pin, no changelog to read, and no migration story if the palette format changes. You are tracking main. The last push was on 2026-09-14, which is recent, but recency of commits is not the same as a release process, and the README documents neither rollback nor upgrade steps. Finally, if your source image is a photograph with fine texture, no amount of dithering choice will beat the bead resolution limit; the tool will faithfully produce a chart that is mostly noise.

Pindo compared with a general pixel-art converter

The obvious alternative is a general pixel-art or image-to-pixel converter, of which there are many, and the difference is not the resizing step. A general converter gives you a downsampled image and a color count. Pindo's output is a build sheet: numbered cells, brand color codes, and a usage legend, with the PNG export carrying the grid and the legend together. The palette is the other difference. A general converter typically quantizes to an arbitrary N-color palette derived from your image, which produces attractive results you cannot buy. Pindo quantizes to a fixed brand palette so the result is orderable. That trade-off cuts both ways: fixed palettes lose fidelity on images whose dominant colors fall between the brand's offerings, and dithering is the compensation. The recognition feature has no real equivalent in a plain converter, since converting an already-pixelated chart back through a downsampler usually destroys the grid alignment. If your goal is a nice-looking pixel image for a screen, a general converter is the better fit. If your goal is a bag of beads and a Saturday, Pindo is aimed at you.

Maintenance, licensing and what GPL-3.0-only means here

Pindo is licensed under GPL-3.0-only, and package.json declares "license": "GPL-3.0-only" with the copyright line Copyright © 2026 LunarXuan. The README links the LICENSE file. This is a copyleft licence, so if you fork Pindo, modify it and distribute it, the usual obligations attach to the distributed work; the repository does not offer a separate commercial or permissive option. If you only run it locally or self-host it for your own use, that is a different situation from shipping a modified build to other people. This is not legal advice and the LICENSE file is the authority. On maintenance cost, the honest picture is that there is no release channel: no releases were retrieved, and the README does not document an upgrade path. The practical cost of adopting Pindo is therefore the cost of tracking main and rebuilding. The build is a Next.js 16 static export, so a rebuild is npm ci followed by npm run build, and the test suite is Vitest via npm test. That is a light maintenance burden for a self-hosted static site, but it does mean you are the one who notices when a dependency bump changes rendering output. The README treats changes to dependencies, launch scripts, local file serving and native bridges as security-sensitive, which is a fair description of where the risk sits.

Editorial conclusion

Adopt Pindo if you already work with Hama, Perler, Artkal S or one of the other five palettes it ships and you want pattern generation to stay on your own machine; the static export and the browser-side processing make that the default rather than an option. Skip it if you need server-side batch conversion of many images, a documented public API, or a published release history, because none of those appear in the repository. Before trusting it with a real project, clone it, run npm ci and npm test, then convert one of your own photos and check the usage statistics against the beads you actually own. The palette data in lib/data/palettes/ is the part to inspect first: if your brand or color series is missing there, no amount of tuning in the UI will produce a chart you can build from.

Frequently asked questions

What is Pindo and what does it do?

Pindo is a local-first fuse bead pattern generator. It converts photos, illustrations and pixel art into numbered bead charts, and it can also recognize existing unlabeled bead charts and add a grid, color codes and usage information.

What is the meaning of Pindo in this project?

The repository does not state a meaning for the name. The README only uses Pindo as the product name for the fuse bead pattern generator, and the project description gives the Chinese name 拼豆, which refers to fuse beads.

Does Pindo upload my images to a server?

No. The README states that all image processing runs in the browser, that images are decoded and processed with browser Canvas APIs and typed arrays, and that the application has no image-upload API or application backend. When self-hosting, the static host still serves the application assets as usual.

Which bead brands does Pindo support?

The README lists eight brand palettes: MARD, Hama, Perler, Artkal S, COCO, Manman, Panpan and Mixiaowo. Palette filters let you include or exclude color series and individual color codes.

Can I run Pindo on Android?

Yes, there is a Capacitor Android path. The README gives npm run android:add, npm run android:sync and npm run android:open, with application ID com.pindo.app and web directory out, and points to ANDROID.md for details.

Official sources

  1. Issues
  2. License: GPL-3.0
  3. LunarXuan/Pindo on GitHub
  4. Project website
  5. README
Community notes

Community notes