Image-to-Pixel

Pixel art from any image or video.

Resize, quantise and dither in your browser. Sixteen dither methods, two dozen palettes plus your own, batches, video, sprite sheets. Free and open source, and nothing is uploaded anywhere.

npm i image-to-pixel
OriginalPixel
16dither methods
24built-in palettes
GPUWebGL 2, CPU fallback
1runtime dependency

What the editor does

Every control updates the preview as you move it. Settings are shared across every file you open, so a batch looks consistent.

Dithering

Bayer 2–16, clustered dot, blue noise and your own matrices; Floyd–Steinberg, Atkinson, Sierra, Burkes, Jarvis and Stucki diffusion.

Palettes

Built-ins from Lospec, palettes pulled from the image, colours picked by hand, and .gpl, .hex, .pal or Lospec imports.

Batches

Drop a folder's worth of images, tune once, and download them all as one ZIP with the settings file inside.

Video

Preview while it plays, step frame by frame, then export GIF, WebM, MP4 or a PNG sequence. Every frame is processed exactly once.

Game-ready output

Integer-scaled PNGs, indexed PNGs, sprite sheets with a JSON atlas, and deduplicated tilesets with a tile map.

Share a look

Copy a link that carries your settings, or save them as JSON. Undo and redo cover every change.

Use the engine in your own code

The editor is built on a small library with no UI. Import it as an ES module or drop in a script tag; TypeScript types are included.

  • Same output everywhere. The GPU path and the CPU fallback produce identical pixels.
  • Runs in Node for { width, height, data } buffers, on the CPU.
  • Compatible with the old pixelate({ image, width, … }) call.

Library reference

JavaScript
import { createPixelator } from 'image-to-pixel';

const px = await createPixelator();
const result = await px.process(imageElement, {
  size: { width: 128 },
  palette: { source: 'builtin', id: 'pico-8' },
  dither: { method: 'floyd-steinberg', strength: 0.8 },
});

document.body.append(result.toCanvas(4));     // 4× nearest-neighbour
const png = await result.toBlob({ scale: 4 });  // indexed PNG

How it renders

Each step is a WebGL fragment shader run through ShaderMate. Error diffusion is normally one pixel at a time; here it runs as a diagonal wavefront, so every pixel on a wave is solved in parallel and the result still matches the sequential algorithm.

How it works

  • Prepare. Box-filter resample, brightness, contrast, saturation, gamma, alpha cut.
  • Quantise. Nearest palette colour in OKLab, with an ordered threshold or a diffusion wave.
  • Clean up. Stray-pixel removal, majority smoothing, inner or outer outline.
  • Export. Read back once; PNG, GIF, ZIP and video encoders run in the page.