# perler-beads: an open source pattern generator for bead crafts

> Zippland/perler-beads converts an image into a printable perler bead pattern, using dominant colour extraction, connected region merging and flood fill background removal, with five brand colour systems and an export that produces both the chart and a shopping list.

**Zippland/perler-beads** — 拼豆底稿生成器 (Perler Beads Generator)

- Repository: https://github.com/Zippland/perler-beads
- Website: https://perlerbeads.zippland.com
- Stars: 1,066 · Forks: 260
- Language: TypeScript
- License: NOASSERTION
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/zippland-perler-beads

## What the generator produces

Perler beads, known in China as pin dou, are small plastic beads that are arranged on a pegboard and fused with heat. The craft needs two things to be practical: a chart that shows which colour goes in which cell, and a list of how many beads of each colour to buy. Zippland/perler-beads produces both from an image.

The project is a TypeScript and Next.js application, with Tailwind CSS for styling and the Canvas API for all image processing, which means the pixels are processed in the browser rather than on a server. Deployment is on Vercel, and the README describes two interfaces, a mobile version in portrait for quick generation and a desktop version in landscape for careful editing. Both are hosted, and the maintainer states that the project is permanently open source and run at no charge.

The feature list covers the whole path from picture to kit. There is intelligent pixelation, multi brand colour code support, automatic merging of stray colours, automatic background removal, colour exclusion with remapping to the nearest available colour, manual touch-up of individual cells, a PNG export of the chart with colour codes and grid lines, and an export of the shopping list as an image.

The README declares the licence AGPL-3.0, and the last push to the repository was on 2026-05-14. The project publishes no GitHub releases, so the deployed sites are the way to use it.

## Running it locally

The project is a standard Next.js application and runs from a clone:

```bash
git clone https://github.com/Zippland/perler-beads.git
cd perler-beads
npm install
npm run dev
```

The browser then opens http://localhost:3000. There is no backend to configure and no API key to obtain, which follows from the decision to do the image processing with the Canvas API in the browser.

The repository root shows what else is there. next.config.ts holds the Next.js configuration, eslint.config.mjs the linting rules, postcss.config.mjs the PostCSS setup for Tailwind, and server.js a standalone server file. The src/ directory holds the application, including the palette data and the main page, and there is a scripts/ directory for the build and utility scripts, a public/ directory for static assets, and a CSV at the root named 色号对应表.csv, which is the colour code correspondence table as a spreadsheet.

There is also a file called final_review_gate.py at the root, a Python script in an otherwise TypeScript project, and a CLAUDE.md, which suggests the maintainer uses an assistant in the workflow.

Contributing follows a familiar shape, with the fork and branch steps written out:

```bash
git checkout -b feature/your-feature
git commit -m 'Add some feature'
git push origin feature/your-feature
```

## Dominant colour extraction instead of average pooling

The pixelation algorithm is the core of the tool, and the README is specific about why it is built the way it is.

For each grid cell, the algorithm extracts the RGB value that occurs most frequently in the corresponding region of the source image, the dominant colour, and maps it to the closest colour in the active palette using Euclidean distance. The stated reason for that choice is that mean pooling, the obvious approach, produces grey fringes at the boundaries between colour blocks. Averaging a red and a white region gives a pink, and a grid of averaged cells turns an edge into a band of muddy intermediate tones that no bead colour matches. Taking the most common value instead keeps the edge crisp, because the boundary cell simply takes the colour of whichever side dominates it.

The mapping is done in Euclidean distance over RGB, which is a known weakness: RGB distance does not correspond well to perceived colour difference, and a saturated blue and a muted teal can be far apart in RGB but close on screen. The README's roadmap lists CIEDE2000, the Delta E colour distance formula, as the planned replacement, so the limitation is acknowledged rather than hidden.

The second consequence of the algorithm is that a cell is never a blend. Every cell is a real bead colour, which is exactly what a bead kit requires.

## Region merging and flood fill background removal

Two more algorithms clean up the result, and both are named with the technique they use.

Region merging is a breadth first search. The search starts from an unvisited cell and groups neighbouring cells whose Euclidean distance is below a threshold into a connected region, then sets the whole region to the colour code that occurs most often inside it. The purpose is to remove stray colours, the single-cell speckles that appear where noise in the photo pushes a cell just over a palette boundary, and the README says the step noticeably reduces them and improves the purity of the colour blocks. The threshold is adjustable, which is the right knob to expose: too low and real detail is flattened, too high and the speckles survive.

Background removal is a flood fill from the edges. A list of background colour codes is defined, and the fill starts from every boundary cell, marking cells that are connected to the boundary and belong to a background colour as external. Those external cells are then ignored when the counts and the export are computed, so a photo of a small object on a plain surface produces a pattern with no background, and the shopping list contains only the colours the object needs.

This works because a background is, by definition, connected to the edges of the image. It fails on a background that is broken up by shadow, a gradient or other objects touching the border, and a user who needs a pattern with the background included can simply not use this step.

The fourth piece is colour exclusion with remapping. When a user excludes a colour, the algorithm finds the nearest replacement within the set of colours that are currently present and not excluded, and remaps the cells to it. Restoring a colour triggers a full reprocessing pass, which is the expensive path, but it keeps the result consistent rather than leaving half-converted cells.

## Palette data and the manual editing step

The colour systems are the practical heart of the tool, because a pattern is only useful if the codes can be bought.

Five brand systems are built in: MARD, COCO, and the Chinese brands 漫漫, 盼盼 and 咪小窝. Several palette sizes are supported, with 168, 144 and 96 listed, which correspond to the number of colours in a standard set. The colour data lives in a single JSON file, src/app/colorSystemMapping.json, and holds a complete mapping of 291 standard colours onto the five brand code systems. The combinations of palette and size are configured in src/app/page.tsx under paletteOptions.

The manual editing step sits on top of all of this. Individual cells can be recoloured by hand, which matters because no automatic algorithm gets a character or a face right, and a maker would rather fix four cells by hand than accept a wrong reading of the subject.

The export produces a PNG with the colour codes annotated and the grid lines drawn, so it can be printed and used directly, and a second export generates the shopping list image with the count per colour. That second artefact is the one that turns a picture into a kit.

One constraint is worth stating plainly. The mapping covers 291 standard colours mapped onto the brand systems, so a colour in a photograph that falls outside that set is approximated by the nearest available one, and the result is limited by the smallest palette a maker owns.

## Roadmap, licence and where the tool is the wrong choice

The roadmap is short and honest about the current limits. CIEDE2000 colour distance is listed to replace RGB Euclidean distance. Floyd-Steinberg dithering is planned, to simulate richer colour transitions under a limited palette. Web Workers for background computation are planned to improve performance on large images. User uploaded custom palettes are on the list, and so is a WeChat mini program version.

Each of those is a real limitation today. Without Delta E, two colours that look similar can be mapped far apart. Without dithering, a gradient becomes bands. Without a worker, a large image makes the browser tab unresponsive during processing. And without custom palettes, a maker with a brand set outside the five supported ones is out of luck.

The AGPL-3.0 licence is the other thing to understand before building on this code. The README's co-creation statement asks that derivatives keep the original copyright notice and are released under the same licence, and it explicitly asks that the code not be copied into a closed source commercial product. That is what AGPL means, and for a web application the copyleft reaches users of the hosted service, so a company that wanted to run a modified version as a paid product would need to read the licence carefully.

The tool is the wrong choice for a maker who wants a hand-drawn pattern with artistic control, since it is an automatic converter and the manual editing is per cell rather than per shape. It is also the wrong choice for colour-critical work, such as reproducing a brand logo exactly, where the dominant colour approach and the RGB distance will not give the fidelity a vector conversion would. For a photo of a cartoon character turned into a weekend kit, it is the right tool, and the shopping list export is the reason.

## Conclusion

perler-beads fits a hobbyist who wants a printable chart from a photo and a shopping list that matches the colours they can actually buy, and the client side canvas pipeline means the image never has to be uploaded anywhere. It does not fit a maker who needs colour-accurate results, since the roadmap still lists CIEDE2000 distance and dithering as future work. Check first that your chosen brand palette is one of the five supported, because the mapping covers 291 standard colours and nothing else.

## FAQ

### How do I run the perler-beads generator locally?

Clone the repository, run npm install and then npm run dev, and open http://localhost:3000. The project is a Next.js application and all image processing happens in the browser with the Canvas API, so there is no server to configure.

### Which bead brands and palette sizes does the generator support?

Five brand systems are built in, MARD, COCO, 漫漫, 盼盼 and 咪小窝, with palette sizes including 168, 144 and 96 colours. The mapping of 291 standard colours onto the brand systems is defined in src/app/colorSystemMapping.json.

### How does the tool remove the background from a picture?

It uses a flood fill starting from all boundary cells. Cells connected to the boundary that belong to a listed background colour are marked as external and are ignored when the counts and the export are computed.

### What can the generator export?

A PNG chart with the colour codes annotated and grid lines drawn, which can be printed directly, and a shopping list image that counts how many beads of each colour are needed.

## Sources

- [Issues](https://github.com/Zippland/perler-beads/issues)
- [Project website](https://perlerbeads.zippland.com)
- [README](https://github.com/Zippland/perler-beads/blob/master/README.md)
- [Zippland/perler-beads on GitHub](https://github.com/Zippland/perler-beads)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/zippland-perler-beads
