Perler Beads Pattern Generator
Project Overview
Beads Deck is a web app that generates perler bead (拼豆) patterns from uploaded images. It was built to solve problems common in existing bead-pattern software: fuzzy gray pixel borders from naive color averaging, no way to merge nearby similar colors, difficulty hand-editing individual cells, no automatically generated purchase list, and restrictive export/printing options. Users upload a JPG/PNG, choose a grid granularity and one of several preset bead color palettes (168, 144, 96 colors, etc.), and the app produces a clean, color-mapped grid pattern with an accompanying bead-count shopping list, ready to download and print.
Technical Details
Built with Next.js (App Router) and TypeScript, styled with Tailwind CSS, and packaged as a PWA (next-pwa) with Vercel Analytics. All image processing happens client-side using the Canvas API and React hooks (useState, useRef, useEffect, useMemo) — no server-side image pipeline is needed. The core algorithm runs in four stages: (1) dominant-color extraction per grid cell using pixel-frequency counting instead of RGB averaging, mapped to the nearest palette color by Euclidean distance, which eliminates the fuzzy gray borders that mean-based pooling produces; (2) region merging via breadth-first search over cells whose color distance falls under a similarity threshold, unifying each connected region to its most frequent bead color to remove speckled noise; (3) background removal via flood fill starting from the grid's border cells, marking any boundary-connected cell whose color is in a defined background set as 'external' so it's excluded from counts and downloads; (4) color exclusion and remapping, where removing a color from the active palette triggers remapping of affected cells to the nearest still-available color that originally existed in the image. Palette data (hex-to-color-code mappings for systems like MARD, COCO, and others) lives in a JSON mapping file.
Features
- ✓Drag-and-drop or click-to-upload JPG/PNG image input
- ✓Adjustable pixelation granularity and color-merge similarity threshold via sliders
- ✓Multiple preset bead color palettes (168, 144, 96 colors, etc.) with palette-aware color mapping
- ✓Click-to-exclude/restore individual colors, with automatic smart remapping of affected regions
- ✓Real-time canvas preview with hover/long-press to inspect a cell's color code and swatch
- ✓Automatic background detection, shown as light gray in the preview and excluded from counts
- ✓Downloadable pattern sheet with grid lines and color-key labels (PNG)
- ✓Downloadable color/bead-count summary sheet for shopping
- ✓Installable as a PWA for offline-friendly use
Technologies Used
Challenges and Solutions
Challenge 1
Naive mean-based RGB pooling when downsampling produced muddy gray 'fuzzy' borders between color regions instead of clean edges
Solution:
Replaced mean pooling with per-cell dominant-color selection (most frequent pixel RGB value) before nearest-neighbor palette matching, which preserves clean color boundaries
Challenge 2
Without any color-merging step, pattern output was full of scattered single-cell noise from minor color variation in the source photo, instead of smooth same-color regions
Solution:
Implemented BFS-based region growing that connects cells within a color-distance threshold and unifies each region to its most common bead color, smoothing out speckled noise
Challenge 3
Existing tools couldn't produce an accurate bead purchase list because they had no way to distinguish intentional background from foreground design
Solution:
Added a boundary flood-fill pass over a configurable set of background color codes, marking connected border-adjacent cells as external so they're excluded from both the preview count and the downloaded shopping list
Challenge 4
When a user excludes a color they don't want to buy beads for, the affected regions need a visually sensible replacement rather than an arbitrary nearest-palette color
Solution:
Built a remapping step that restricts replacement colors to the set of colors that originally existed in the processed image (minus other excluded colors), so remapped regions blend naturally instead of jumping to an unrelated palette color