Skip to content

lovelaced/pixfix

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

61 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

        _       __ _
  _ __ (_)_  __/ _(_)_  __
 | '_ \| \ \/ / |_| \ \/ /
 | |_) | |>  <|  _| |>  <
 | .__/|_/_/\_\_| |_/_/\_\
 |_|

Clean up AI-generated pixel art.
Snap to grid. Remove AA fuzz. Reduce to a palette. Remove backgrounds.

CI codecov License: MIT Release

Docs (with an in-browser demo) · Download · Features · CLI Reference · How It Works


pixfix welcome screen

pixfix settings with live preview



AI image generators produce "pixel art" riddled with mixels (mixed-resolution pixels), anti-aliasing artifacts, and colors that don't snap to any grid. pixfix takes that messy output and produces clean, uniform pixel art — while preserving the vibrancy and character of the original.

Available as a native desktop app (macOS, Windows, Linux) and a CLI tool for scripting and automation.


Features

Desktop App

  • Side-by-side original / processed preview
  • Live settings — tweak parameters, see results instantly
  • Grid detection diagnostics and color histograms
  • 3000+ palettes via Lospec, or load custom .hex files
  • Sprite sheet auto-splitter with GIF animation export
  • Batch processing — drag in a folder, process everything
  • Full keyboard navigation

Processing Pipeline

  • Auto-detect pixel grid size and phase offset
  • Snap mode — enforces clean grid at original resolution
  • Multiple downscale modes (center-weighted, majority-vote, center-pixel)
  • OKLAB color quantization — perceptually accurate palette matching
  • Anti-aliasing removal via triangle inequality in OKLAB space
  • Background removal — flood-fill or global replacement
  • Output resize — upscale for game engines (2x, 3x...)

Install

Desktop App

Download the latest release for your platform:

Platform Download
macOS (Apple Silicon) .dmg
macOS (Intel) .dmg
Windows .msi · .exe installer
Linux .deb · .AppImage

CLI

# From source (requires Rust 1.70+)
git clone https://github.com/lovelaced/pixfix.git
cd pixfix
cargo build --release

# Binary at target/release/pixfix

Pre-built CLI binaries for all platforms are also available on the Releases page.


Desktop App

Keyboard Shortcuts

Key Action
O Open image
S Save processed image
Space Reprocess with current settings
R Reset settings to defaults
Tab Switch tabs
Esc Back to Preview

Tabs

Tab What it does
Preview Side-by-side original vs. processed
Settings All pipeline parameters with live preview
Diagnostics Grid detection scores, color histogram
Batch Process multiple images at once
Sheet Split sprite sheets, normalize tiles, export GIFs

CLI Quick Start

# Auto-detect grid, normalize
pixfix process input.png output.png

# Force grid size, snap to PICO-8 palette
pixfix process input.png output.png --grid-size 4 --palette pico-8

# Remove background
pixfix process input.png output.png --grid-size 4 --remove-bg

# Chroma key: make a color transparent everywhere (green-screen style)
pixfix process input.png output.png --chroma-key 00FF00

# Inspect without writing anything
pixfix analyze input.png --json

# Batch process a folder
pixfix batch sprites/ output/ --grid-size 4 --palette sweetie-16

# Auto-split an AI sprite sheet
pixfix sheet ai_sheet.png --output-dir sprites/

# Interactive terminal editor (Sixel/halfblock preview)
pixfix tui input.png

How It Works

Input Image
    │
    ▼
┌─────────────────┐
│  Grid Detection  │  Find NxN pixel grid size and phase offset
└────────┬────────┘
         ▼
┌─────────────────┐
│   AA Removal     │  Remove anti-aliasing artifacts (optional)
└────────┬────────┘
         ▼
┌─────────────────┐
│ Grid Normalize   │  Snap/downscale pixels to the detected grid
└────────┬────────┘
         ▼
┌─────────────────┐
│   Quantize       │  Snap colors to a palette (optional)
└────────┬────────┘
         ▼
┌─────────────────┐
│  Background Rm   │  Remove solid backgrounds (optional)
└────────┬────────┘
         ▼
┌─────────────────┐
│  Final Resize    │  Scale to output dimensions if needed
└────────┬────────┘
         ▼
    Output Image
Grid Detection

For each candidate grid size (2..max), measures edge alignment — the ratio of color gradients at grid boundaries vs. non-boundary positions. The correct grid size maximizes this ratio because all real color transitions align to its grid lines. Phase detection scans all possible offsets to find where the grid starts, even when --grid-size is manually set.

Snap Mode (Default)

For each NxN block, finds the dominant color via center-weighted majority voting and paints every pixel in the block with that single color. Eliminates mixels and stray pixels while preserving dithering patterns across blocks (adjacent blocks can still have different colors). The output stays at the original resolution.

Color Quantization (OKLAB)

All color operations use OKLAB color space, which is perceptually uniform — Euclidean distance in OKLAB closely matches how humans see color differences. K-means clustering produces vibrant, meaningful centroids instead of muddy averages. Palette snapping picks the perceptually closest match.

Anti-Aliasing Removal

For each pixel, examines its 8-connected neighbors. If the pixel lies "between" the two most dominant neighbor colors in OKLAB space (triangle inequality test), it's identified as an AA artifact and snapped to the closer neighbor. Off by default — AI art has intentional edge detail that this can destroy.


CLI Reference

-h shows a curated set of flags — the ones that change results, like --grid-size and --coarsen. Tuning flags for detection thresholds and edge cases only appear in --help, which is always complete.

process — Normalize a single image

pixfix process [OPTIONS] <INPUT> [OUTPUT]

Output defaults to <input>_normalized.png.

Animated GIFs. A GIF with more than one frame is normalized as one animation, not as independent images: the grid is detected once on the first frame, the background color is resolved once, and a single palette is extracted from all frames together, so nothing drifts or flickers between frames. Each frame is then snapped with those shared settings. Per-frame timing is preserved and the output is always an animated GIF (<input>_normalized.gif). Static GIFs take the normal single-image path.

All options

Grid

Flag Description
--grid-size <N> Override auto-detected grid size (fractional values like 10.667 work)
--grid-phase <X,Y> Override grid phase offset (requires --grid-size)
--no-grid-detect Skip grid detection (requires --grid-size)
--max-grid-candidate <N> Max pitch to test (default: scales with image size)
--coarsen <N> Multiply the final grid pitch by an integer (see below)
--min-confidence <0-1> Detection confidence floor (default: 0.35); below it the pipeline declines to snap and reports its best guess. Lower it for heavily anti-aliased images

--coarsen, exactly: detection finds the render quantum — the grid the generator physically painted on (often ~2px at 1024). The intended artistic resolution is usually a multiple of that: a 1024px image at 2px pitch is a 512x512 sprite, nothing like 16-bit-era art, while --coarsen 2 snaps the same image at 4px for an honest 256x256. The multiplier applies to the auto-detected pitch or to --grid-size (so --grid-size 2.714 --coarsen 2 snaps at 5.428); phase is preserved, so coarse blocks stay aligned with the fine grid; it does nothing when detection declines (there is no pitch to multiply); and reported grid values (--json included) show the multiplied pitch, while grid_best_guess diagnostics keep the raw detection.

Detection handles fractional pitch — AI upscales often render, say, 48 cells across 512px (10.667px per cell), and the comb search finds that directly. When confidence is too low to trust, the pipeline reports its best guess and leaves the image unsnapped instead of inventing a grid; pass --grid-size to force one.

Downscale

Mode Description
snap Default. Clean grid at original resolution. Best for AI art.
center-weighted Reduce to logical resolution, center pixels weighted more.
majority-vote Reduce to logical resolution, most common color wins.
center-pixel Reduce to logical resolution, center pixel only. Fastest.

Color

Flag Description
--palette <NAME> Built-in palette (pico-8, sweetie-16, endesga-32, endesga-64, gameboy, nes)
--palette-file <PATH> Custom .hex palette file
--lospec <SLUG> Fetch palette from Lospec by slug
--colors <N> Auto-extract N colors via k-means
--no-quantize Skip quantization
--seed <N> RNG seed — same input and seed always produce identical bytes
--flatten-dither Turn off dither preservation (detected dither pairs are normally pinned so quantization can't flatten them)

The palette source flags are mutually exclusive. Extracted palettes use each cluster's most representative real color, never invented averages.

Anti-aliasing

Flag Description
--aa-threshold <0-1> Enable AA removal; higher = more aggressive (off by default)
--aa-passes <N> Max removal passes for wide AA ramps (default: 3)

Background

Flag Description
--remove-bg Enable background removal
--bg-color <HEX> Explicit background color
--bg-threshold <0-1> Border detection threshold (default: 0.4)
--bg-tolerance <N> Color tolerance in OKLAB (default: 0.05)
--no-flood-fill Global replacement instead of flood-fill
--chroma-key <HEX> Green-screen removal: this color becomes transparent everywhere, interior regions included; repeat for multiple keys, combinable with --remove-bg
--chroma-tolerance <N> Chroma key match tolerance in OKLAB (default: 0.05)

Output

Flag Description
--target-width <N> / --target-height <N> Explicit output size
--logical-size Reduced modes: emit the true logical resolution instead of the default crisp integer re-upscale
--keep-alpha Preserve per-pixel alpha instead of binarizing blocks to opaque/transparent
--output-format <png|webp|bmp|gif> Output encoding; also sets the derived extension (default: png; animated inputs always produce gif)
--overwrite / --no-overwrite Overwrite policy (no-clobber by default)
--debug-overlay <PATH> Also write a diagnostic PNG: source dimmed, blocks tinted red by how contested their color vote was — a wrong pitch or phase lights up instantly

Derived output names always get the output format's extension — a .jpg input produces _normalized.png. Pass - as input to read from stdin, or as output to write PNG to stdout for piping.

analyze — Inspect without writing

pixfix analyze input.png --json

Runs grid detection, background detection, and color counting with zero writes — pitch, phase, confidence, logical size, unique colors, detected background. When a grid is found it also probes snapping at 1x/2x/4x of the detected pitch and reports contested-block rates per factor, suggesting a --coarsen value when the content reads cleanly at a coarser artistic resolution. Add --sheet to preview the auto-split sprite count. Ideal for scripts and agents that want to look before they process.

batch — Process multiple images

pixfix batch [OPTIONS] <INPUT> <OUTPUT_DIR>

INPUT can be a directory or glob pattern (extensions match case-insensitively). Pipeline flags from process apply; --target-width/ --target-height are per-image and not available in batch.

Flag Description
--suffix <S> Output name suffix (default: _normalized; '' for none)
--preserve-dirs Recreate the input directory structure (recursive globs that would collide are rejected otherwise)
--output-format <F> Output encoding for every file

One bad file never aborts the run; every file's outcome is itemized, and a partial failure exits with code 6.

sheet — Sprite sheet processing

pixfix sheet [OPTIONS] <INPUT> [OUTPUT]

Fixed grid — specify --tile-width and --tile-height for known layouts. Auto-split — omit tile dimensions to auto-detect sprite boundaries.

Sheet options
Flag Description
--tile-width <N> / --tile-height <N> Fixed tile size (omit for auto-split)
--spacing <N> Gap between tiles (default: 0)
--margin <N> Sheet border (default: 0)
--separator-threshold <0-1> Auto-split separator detection (default: 0.90)
--min-sprite-size <N> Filter small artifacts (default: 8)
--pad <N> Output padding per sprite (default: 0)
--output-dir <PATH> Save individual tiles
--no-normalize Split/reassemble only

tui — Interactive terminal editor

pixfix tui [INPUT]

Terminal UI with live image preview (Sixel/halfblock). Requires building with the tui feature (cargo install --features tui); it is not in the default feature set.

palette — Palette utilities

pixfix palette list                        # Show built-in palettes
pixfix palette fetch endesga-32            # Download from Lospec
pixfix palette extract input.png -o p.hex  # Extract from image

Fetched palettes are cached in the platform cache directory; --refresh bypasses the cache.


Scripting and agents

Every command takes a global --json flag that emits exactly one JSON document on stdout (stable schema, fields always present); logs and progress stay on stderr, as NDJSON events in JSON mode. --quiet silences everything except errors. Results are deterministic: the same input and --seed produce identical bytes.

For language models there's a plain-text version of the whole manual: llms.txt and llms-full.txt.

pixfix analyze sprite.png --json | jq .grid.pitch_x
pixfix process sprite.png out.png --json | jq .colors_after

Exit codes:

Code Meaning
0 Success
2 Usage or config error
3 Input could not be read
4 Processing failed
5 Output already exists (pass --overwrite)
6 Batch finished with some files failed

Config File

Save settings in .pixfix.toml — CLI arguments override config values, which override the built-in defaults. An explicit --config path that doesn't exist is an error; --no-config ignores config files entirely (useful for scripted runs in arbitrary directories).

Example config
[grid]
size = 4
max_candidate = 16

[aa]
threshold = 0.3

[quantize]
palette = "pico-8"

[background]
enabled = true
color = "FF00FF"
flood_fill = true

[output]
overwrite = false

Performance — parallelized via rayon. Grid detection, AA removal, batch mode, and sprite sheet tiles all process in parallel. A 1024x1024 image typically completes in under 1 second.


MIT License

About

makes AI-generated pixel art not mixelated

Resources

Stars

10 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors