A while back, I got tired of explaining to people how to convert images to pixel art using Photoshop, Aseprite, or some obscure command-line tool. The friction was real — install this, export that, tweak the palette manually.
So I built PixelCrafts — a fully client-side pixel art converter that runs entirely in the browser using the Canvas API. No backend, no file uploads, no account required.
Here's how it works and why I made certain technical decisions.
The Core: Canvas API + Pixel Downsampling
The fundamental operation is simple: take an image, downsample it to a low resolution, then scale it back up with imageSmoothingEnabled = false to get that hard-edged pixel look.
const offscreen = document.createElement('canvas');
offscreen.width = Math.floor(img.width / pixelSize);
offscreen.height = Math.floor(img.height / pixelSize);
const ctx = offscreen.getContext('2d');
ctx.imageSmoothingEnabled = false;
ctx.drawImage(img, 0, 0, offscreen.width, offscreen.height);
// Scale back up — pixels stay sharp
outputCtx.imageSmoothingEnabled = false;
outputCtx.drawImage(offscreen, 0, 0, outputCanvas.width, outputCanvas.height);
The pixelSize slider controls the block size — higher values = chunkier pixels, lower = finer detail. Everything is computed in-memory, frame by frame as you drag the slider.
Color Palette Quantization
This was the trickiest part. Retro hardware had strict color limits (NES: 54 colors, Game Boy: 4 shades of green), so I needed palette quantization — mapping every pixel to the nearest color in a fixed set.
The approach I use is nearest-neighbor in RGB space:
function nearestColor(r, g, b, palette) {
let minDist = Infinity;
let nearest = palette[0];
for (const [pr, pg, pb] of palette) {
const dist = (r - pr) ** 2 + (g - pg) ** 2 + (b - pb) ** 2;
if (dist < minDist) {
minDist = dist;
nearest = [pr, pg, pb];
}
}
return nearest;
}
For best results with photos, I also implemented an adaptive palette generator that clusters the image's dominant colors using a median-cut algorithm — so if you don't want to pick a retro preset, you can auto-extract a palette directly from the image.
You can also import palettes from Lospec or PixilArt by slug or URL — the palette data is fetched client-side and parsed into HEX arrays.
Style Presets
PixelCrafts ships with 10 retro presets:
| Preset | Palette | Vibe |
|---|---|---|
| NES | 54-color hardware palette | Classic platformer |
| Game Boy | 4-tone greenscale | Handheld nostalgia |
| PICO-8 | 16-color | Fantasy console |
| Vaporwave | Purples, pinks, teals | Aesthetic |
| Matrix | Green-on-black | Terminal |
| Glitch Art | Distorted + chromatic | Experimental |
| Thermal | Heat map tones | Infrared look |
| Old Movie | Sepia + grain | Silent film era |
| Anime | High contrast + clean | Cel-shaded |
| SNES | Extended 256-color | 16-bit era |
Each preset sets the palette, pixel size default, and enables relevant post-processing effects automatically.
Post-Processing Effects (All on Canvas)
Beyond pixelation, I layered several real-time visual effects — all implemented as canvas compositing passes:
- Scanlines — overlays alternating dark horizontal lines to mimic CRT rows
- Bloom — a Gaussian blur blended additively over bright areas
- CRT mask — RGB sub-pixel dot pattern overlay
- Chromatic aberration — offsets the R and B channels by a few pixels
- Noise / grain — per-pixel random alpha overlay
- Outline — edge detection pass using a simple Sobel-like kernel
-
Hue shift / temperature / tint — pixel-level HSL adjustments via
getImageData
All effects run after the quantization step, so the pixelated palette stays intact while the CRT effects sit on top.
Privacy by Default: Zero Uploads
Everything runs locally. When you drag an image into PixelCrafts:
- The browser reads it via
FileReaderorcreateObjectURL - It's drawn onto an offscreen
<canvas> - All transformations happen in-memory
- You download the result via
canvas.toBlob()→URL.createObjectURL()
Your image data never leaves your device. There's no server, no S3 bucket, no logs. This was a deliberate choice — many of the use cases (profile photos, game assets in development, client work) involve images people reasonably don't want uploaded to a stranger's server.
Minecraft Mode
One of the more fun features: a dedicated Minecraft Pixel Art mode. Instead of color palette quantization with arbitrary HEX values, it maps each pixel to the nearest Minecraft block by color (using a pre-built block → average color lookup table). The output includes:
- A pixelated block-by-block preview
- A full material list with block counts
- Scale controls for the final structure size
Useful for Minecraft map art builders who want to turn a photo into a buildable plan.
Batch Conversion
For indie devs converting sprite sheets or icon sets, there's also a batch mode — upload multiple images, apply the same style settings to all of them, and download individually or as a zip.
Try It
PixelCrafts is free, no account needed, and works on mobile too.
If you're building something similar or have thoughts on the palette quantization approach, drop a comment — I'm always looking to improve the algorithm, especially for edge cases like skin tones and gradients.
Feedback and feature requests welcome: support@pixelcrafts.art
Top comments (0)