Skip to content

struong/plate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

45 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

plate

Turn any image into pixel art. One command definition serves both CLI and HTTP API via incur. Deployable to Cloudflare Workers with mppx payment gating via the Machine Payments Protocol.

Built with @cf-wasm/photon (Rust/Wasm), incur (linked locally — file:../incur — for multipart/form-data and binary body support), and mppx (MPP payment gating).

Install

bun install
bun run build:cli            # build + link `plate` globally

CLI Usage

# PNG output (pipe to file)
plate photo.png > out.png
plate photo.png -s 32 -c 8 > out.png        # 32px grid, 8 colors

# Named palettes
plate photo.png -p pico8 > out.png           # PICO-8 (16 colors)
plate photo.png -p gameboy > out.png         # Game Boy (4 colors)
plate photo.png -p nes > out.png             # NES
plate photo.png -p mono > out.png            # Black & white
plate photo.png -p grayscale > out.png       # 8-shade grayscale

# Custom palette (one hex color per line)
plate photo.png --palette-file colors.hex > out.png

# Dithering
plate photo.png -d floyd-steinberg > out.png # error diffusion
plate photo.png -d ordered > out.png         # 4×4 Bayer pattern

# SVG and JSON output
plate photo.png -f svg > out.svg             # scalable vector (rects)
plate photo.png -f json                      # { width, height, grid[][] }

# Piping (stdin → stdout)
cat photo.png | plate -s 16 > pixel.png

# Specify total blocks (auto-calculates grid preserving aspect ratio)
plate photo.png -b 256 > out.png

# Subcommands
plate health                                 # health check
plate palettes                               # list available palettes

Options

Flag Alias Default Description
--size -s 64 Grid size in pixels (longest side)
--blocks -b Total block count (auto-sizes grid)
--colors -c 16 Max colors in palette
--palette -p Named palette: pico8, gameboy, nes, mono, grayscale
--palette-file Custom palette file (hex colors, one per line)
--dither -d none Dithering: none, floyd-steinberg, ordered
--format -f png Output format: png, svg, json
--scale -x 8 Output scale multiplier

HTTP API

The same incur command definition serves as an HTTP API via cli.fetch. Path segments map to commands, form fields map to options. The image arg uses file() from incur (not z.file() from zod) for transport-aware file input that works across CLI, HTTP multipart, and MCP.

The root pixelate endpoint (POST /) is gated behind a 0.01 pathUSD payment via mppx on the Tempo moderato testnet. Health and palettes endpoints are free. The worker (src/worker.ts) exports a Workers fetch handler that routes by path: root requests go through mppx payment gating wrapping cli.fetch, non-root paths (/health, /palettes, etc.) pass through to cli.fetch directly.

Local Development

bun run dev              # Vite dev server with HMR on :5173

Endpoints

# Help — list all endpoints and usage (free)
curl localhost:5173/help

# Health check (free)
curl localhost:5173/health

# List available palettes (free)
curl localhost:5173/palettes

# Pixelate an image (POST multipart to root — requires payment in production)
curl -F image=@photo.png \
     -F size=32 \
     -F palette=pico8 \
     -F dither=floyd-steinberg \
     localhost:5173/ -o out.png

The root endpoint accepts multipart form data with these fields: image (required file), size, blocks, colors, scale, dither, palette, format.

Paid Requests with tempo request

In production, the root endpoint returns 402 Payment Required. Use tempo request to automatically handle the MPP payment flow:

# Pixelate via paid endpoint (0.01 pathUSD per request, Tempo moderato testnet)
tempo request -n tempo-moderato \
  -F image=@photo.png \
  -F size=32 \
  -F palette=pico8 \
  https://plate.struong996.workers.dev/ -o out.png

# Free endpoints work with plain curl
curl https://plate.struong996.workers.dev/help
curl https://plate.struong996.workers.dev/health
curl https://plate.struong996.workers.dev/palettes

Deploy to Cloudflare Workers

bun run build            # vite build → dist/_worker.js
bun run deploy           # wrangler deploy

Set secrets for mppx payment gating (Tempo moderato testnet):

wrangler secret put MPP_SECRET_KEY       # mppx signing key
wrangler secret put PAYMENT_RECIPIENT    # pathUSD recipient address

Library

import { pixelate } from 'plate'

const result = pixelate(imageBytes, {
  size: 32,
  colors: 8,
  dither: 'floyd-steinberg',
})

// result.buffer      — PNG as Uint8Array
// result.pixelData   — raw RGB grid pixels
// result.width       — output width
// result.height      — output height
// result.colorsUsed  — number of colors used
// result.grid        — { w, h } grid dimensions

Development

bun run dev              # Vite dev server with HMR
bun run build            # vite build for Workers
bun run build:cli        # tsc + chmod + bun link
bun run build:lib        # tsc → dist/ (library)
bun run typecheck        # type-check without emitting
bun run deploy           # wrangler deploy to CF Workers

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors