Skip to content

Pixel Art Palette Editor — Indexed Colour and Lospec

A palette editor that works on the sprite itself. Convert a picture to indexed colour, then reorder, recolour or replace palette entries while every frame keeps its look, pull a named palette from Lospec, and write the palette in the formats Aseprite, GIMP and Photoshop read.

Drop a sprite, frames, a GIF or an .aseprite file to paint on — or an upscaled picture to clean up
Runs in your browser. Files are not uploaded.
Studio Pixel workspace: a CC0 sprite in indexed colour mode with its palette, the transparent index and the colour audit per frame
The real Studio with a CC0 asset (OpenGameArt).
Exports to
  • .asepriteVerified· Aseprite 1.3.18
  • Palette filesMeasured· read back
  • Engine bundlesVerified· Godot 4.7.2 · Unity 6000.5
  • Frame PNG · .nerulioPlain files

What it does

  • Colour mode RGB ↔ indexed: from the exact colours of the picture, the current palette or DB32, nearest colour chosen in Oklab, dithering off by default (ordered dither in linear light when you want it). The transparent index is its own entry, so black stays black.
  • Dragging a palette entry to a new slot rewrites every cel of an indexed sprite through the index map, so the picture never changes. Sort by brightness, hue, saturation or use, add, remove, and pick the transparent index.
  • Hue-shifted ramps in OkLCh around a base colour: shadows move toward cool hues and lights toward warm ones, with the step count, hue shift and darkest and lightest levels set in a dialog. The base colour is kept exactly.
  • Team-colour variants: select a ramp in the palette and each team colour gets its own ramp mapped onto every frame and layer, each variant as a new sprite. In an indexed sprite a single palette edit recolours every frame.
  • The Audit panel counts colours per frame against a budget, lists off-palette colours and near duplicates, and can select the stray pixels or snap them to the palette in one step.

How to do it

  1. Drop the sprite, frames or an .aseprite file on this page; the Pixel workspace opens with its palette in the Palette panel.
  2. Open Pixel › Colour mode, choose Indexed and the palette source (the picture's exact colours, the current palette or DB32), and keep dithering off for clean pixel art.
  3. Double-click an entry to edit it, drag entries to reorder, or open Pixel › Lospec palette and type a palette name after the one-time consent.
  4. Export the palette as .gpl, .pal, .hex, .ase, .act or .json from the Palette menu, and save the sprite as an indexed .aseprite.

Palette formats in and out

All are read and written by the Palette menu; "checked" means written and read back identical.

FormatMade byReadWrite
.gplGIMP, Lospec, AsepriteYes (RGBA as Lospec writes it)Yes, checked
.palPaint Shop Pro (JASC), RIFF palettesBoth variantsYes, checked
.hexLospecYesYes, checked
.ase (swatches)Adobe Photoshop, IllustratorYes (a real 16-colour file read)Yes, checked
.actAdobe colour tableYesYes, checked
.json / .asepriteLospec JSON / an Aseprite spriteYes / its paletteJSON, checked

Engine exports and how each was checked

"Verified" means the exported files were loaded by the real engine or tool on real CC0 assets and the result was compared with the source. Anything that was not loaded is labelled as such.

TargetFilesCheck
.asepritelayers · blend · opacity · locked · indexed palette · frames · tagsVerified Aseprite 1.3.18The real Aseprite command line reopened the file as INDEXED with 2 layers, Multiply at opacity 160 and the locked layer not editable; the frames are pixel-identical.
Palette files.gpl · .pal · .hex · .ase · .act · .jsonMeasured read backEach format was written and read back identical; Aseprite's own .gpl, .pal, .hex and .act and a real Adobe .ase (16 colours) were read.
Engine bundlesGodot 4 · Unity 6 · Phaser 3/4 · PixiJS 8 … through Pack & ExportVerified Godot 4.7.2 · Unity 6000.5The sprite you drew is packed in Pack & Export; those engine files were loaded in each engine on real CC0 assets (47 of 49 runs pass; the 2 failures are a Phaser 3.90 bug the Phaser 3 preset avoids).
Frame PNG · .nerulioPNG-8 with the palette when an indexed frame fits it · project filePlain filesPlain files for any tool; no engine run is claimed for them.

Evidence

Cleanup benchmark, 69 CC0 cases with a known 1× original: the exact size found for 81 % (±1 px: 90 %) and 74.0 % of pixels exact with the background kept; the best competitor found 30 % of sizes (perfectPixel) and the best exact-pixel score was 44.6 % (unfake.js). An Aseprite-made ×4 nearest upscale came back 100 % exact and a ×3.78 bilinear resize 99.7 %, both with the size found automatically. A 1 px outline and a drop shadow matched Aseprite pixel for pixel (1846 and 705 px). .aseprite files written here reopen in Aseprite 1.3.18 as indexed, with their layers, blend mode and lock.

Limits

  • Not in the Pixel workspace (Aseprite has them): layer groups, linked cels, tilemap layers, reference layers, RotSprite and free rotation or scaling of a selection (only flips and 90°), gradient, spray, contour and text tools, custom brushes (square or round, 1–16 px), tiled drawing, Lua scripting and a command line.
  • The symmetry axis is typed, not dragged on the canvas. On touch there is no right button, so the background colour needs the swap button or X.
  • Cleanup: JPEG input comes back close (84 % of pixels within ΔE 0.02 with the background kept) but rarely exact (12 %); simulated generated art gets the exact size 20 % of the time (±1 px: 80 %); none of 7 real generated images was snapped automatically — you type the pixel size the panel suggests.
  • Indexed conversion picks the nearest colour in Oklab, not Aseprite's RGB distance: 68 % of the test sprite's pixels got a different (perceptually closer) pick. The Lospec search is the only network request and asks first.

Questions

Why does the indexed conversion pick different colours than Aseprite?

The nearest colour is chosen in Oklab, a perceptual colour space, while Aseprite measures RGB distance. On the test sprite converted to PICO-8, every opaque pixel got its Oklab-nearest colour, which differed from the RGB-nearest pick on 68 % of pixels.

What does the Lospec search send over the network?

Only the palette name you type, turned into a lospec.com/palette-list/<name>.json request without cookies or a referrer, after a consent dialog. It is the only network request in the whole workspace; declining sends nothing.

Can it read palettes from Photoshop and Paint Shop Pro?

Yes: Adobe .ase swatch exchange and .act files, JASC and RIFF .pal, GIMP .gpl, plain .hex and Lospec JSON, plus the palette inside an .aseprite. Each format was written and read back identical, and a real Adobe .ase with 16 colours was read.

Is it free, and do I need an account?

Everything on these pages is free and works without an account. There is no watermark and no export that is held back.

Are my sprites uploaded?

No. The Studio decodes, packs and exports in this browser tab. Projects are autosaved in the browser (IndexedDB) and can be saved as a .nerulio file.

Does it need Aseprite or an engine plugin installed?

No. .aseprite files are read and written in the browser, and each engine bundle carries what that engine needs (for Godot, the import settings and scene; for Unity and the Godot TileSet, a small editor script).