Live UI Try the pixel-art converter instantly at https://gametorch.app/image-to-pixel-art Free forever · no sign-up required · runs 100 % in your browser A tiny Rust → WebAssembly library that turns any raster image into low-color pixel-art. Features K-means palette extraction with user-selectable color count or supply your own palette. supply your own palette. Keeps transparency intact – only opaque pixels are processed. Down-samples to a fixed tile grid (e.g. 64 × 64) using nearest-neighbour then scales back up – aspect-ratio preserved. Pure client-side: the heavy lifting happens completely inside your browser thanks to WASM. The public API exported via wasm-bindgen : // palette is optional: string[ ] of 6-char HEX, e.g. ["FFAA00", "112233"] // returns { image: Uint8Array, palette: string[ ] } function pixelate ( input : Uint8Array , n_colors : number , scale : number , output_size ?: number , palette ?: string [ ] ) : { image : Uint8Array ; palette : string [ ] } ; It returns PNG-encoded bytes plus the palette actually used (either supplied or discovered). Building the WebAssembly bundle Prerequisites Rust nightly or stable (≥ 1.70). wasm-pack ( cargo install wasm-pack ). Compile: wasm-pack build --release --target web Under pkg/ you will get: image_to_pixel_art_wasm_bg.wasm – the WebAssembly binary. – the WebAssembly binary. image_to_pixel_art_wasm.js – a tiny ES module wrapper generated by wasm-bindgen . Building with plain cargo If you prefer not to use wasm-pack , compile directly via Cargo after setting the getrandom backend flag: # Unix RUSTFLAGS= ' --cfg getrandom_backend="wasm_js" ' \ cargo build --release --target wasm32-unknown-unknown # Windows (PowerShell) $Env :RUSTFLAGS= ' --cfg getrandom_backend="wasm_js" ' cargo build --release --target wasm32-unknown-unknown This produces the raw WebAssembly binary at target/wasm32-unknown-unknown/release/image_to_pixel_art_wasm.wasm You will then need to run the wasm-bindgen CLI to create the JavaScript glue files (equivalent to what wasm-pack did automatically): wasm-bindgen --target web --out-dir ./pkg \ target/wasm32-unknown-unknown/release/image_to_pixel_art_wasm.wasm After this step the pkg/ directory will contain the same two files described earlier ( *.wasm and the corresponding ES-module wrapper). Using from vanilla JavaScript / TypeScript < script type =" module " > import init , { pixelate } from './pkg/image_to_pixel_art_wasm.js' ; // Wait for WASM to finish loading await init ( ) ; const file = await fetch ( 'my_photo.jpg' ) . then ( r => r . arrayBuffer ( ) ) ; const pngBytes = pixelate ( new Uint8Array ( file ) , /* n_colors */ 8 , /* scale */ 64 ) ; const blob = new Blob ( [ pngBytes ] , { type : 'image/png' } ) ; document . getElementById ( 'out' ) . src = URL . createObjectURL ( blob ) ; < img id =" out " /> No bundler required — modern browsers understand ES modules & WASM directly. crate-type = ["cdylib", "rlib"] — what & why? Rust's crate type controls which artifacts Cargo builds: rlib – Rust static library. Other Rust crates can link to it, enabling unit tests, benches or workspace integration. This is the default for library crates. – Rust static library. Other Rust crates can link to it, enabling unit tests, benches or workspace integration. This is the default for library crates. cdylib – C dynamic library. It strips out Rust-specific metadata, producing a clean binary that can be loaded by foreign tool-chains. In the WASM world wasm-bindgen requires cdylib so it can massage the output into a .wasm file plus the JS glue code. By declaring both we keep the crate usable as a normal Rust dependency and ready for WebAssembly packaging. License This project is released under the MIT license. CLI Tool and Bulk Conversions If you prefer a native command-line workflow (and want to batch-process many files) you can build the optional pixelate-cli binary. Build it (native only – no WASM): cargo build --release --features native-bin --bin pixelate-cli # binary at target/release/pixelate-cli Usage overview: pixelate-cli < INPUTS > ... [options] OPTIONS -k, --n-colors < N > Number of colors for k-means (ignored when you supply a palette) [default: 8] -s, --scale < S > Down-sample size for the longest side [default: 64] --output-size < S > Final upscale size (longest side). Defaults to the original dimensions. -c, --palette < HEX,… > Comma-separated list of 6-char hex colors to use instead of running k-means. -d, --out-dir < DIR > Directory to write results into (keeps original stems). -p, --prefix < STR > Prefix for output filenames when not using --out-dir [default: pixelated_] Examples # Basic bulk conversion with default options target/release/pixelate-cli photos/ * .jpg # Custom palette & write into `out/` directory target/release/pixelate-cli sprites/ * .png \ --palette " FF0000,00FF00,0000FF " \ --scale 32 \ --out-dir out Original WASM crate authored entirely with o3 in 30 minutes — see the git commit timestamps for proof.