To Pixel Art Tools
Turn any image into pixel art, entirely inside Unity. No external tools, no Python, no third party packages, no internet connection — the whole conversion is native C#.
Section 1Overview
To Pixel Art Tools converts photographs, renders, illustrations and existing sprites into pixel art through a configurable pipeline of eight stages. It is built around a live preview, because the right colour count or merge tolerance for a given image is something you find by watching the image, not by reasoning about numbers.
Requirements
| Item | Requirement |
|---|---|
| Unity | 6000.x (Unity 6) or newer |
| Render pipeline | Any — Built-in, URP and HDRP. The tool does not render anything. |
| Platforms | All. The runtime API works in every build target, including WebGL. |
| Dependencies | None. No packages, no native plugins, no network access. |
What is in the package
| Folder | Contents |
|---|---|
Runtime/ | The conversion pipeline, settings, profile and palette assets. Assembly CloudedStudio.ToPixelArtTools. |
Editor/ | The window, inspectors, batch tools and exporters. Assembly CloudedStudio.ToPixelArtTools.Editor, editor only. |
Documentation/ | This document and a plain text manual. |
The package can be moved or renamed anywhere inside Assets. It locates its own files at
runtime, so reorganising your project will not break it.
If you never call the API from your own code, the runtime assembly costs a few kilobytes and nothing else — Unity strips assemblies that nothing references. The editor assembly is never included in a build.
Section 2Getting started
Your first conversion
- Open Window ▸ Clouded Studio ▸ To Pixel Art Tools ▸ Convert to Pixel Art.
- Drag an image into the window, assign a project texture in Source, or choose Open External Image… for a PNG/JPG/JPEG that should remain outside the project.
- Pick a starting point from the Presets menu in the toolbar — see section 6 for which one suits your source.
- Adjust the settings on the left. The preview reconverts as you go.
- Press Convert and Save.
The result is written into Assets with a _PixelArt suffix, already imported
with point filtering, no compression and no mipmaps — the settings pixel art needs in order to stay
crisp in game. Project sources can save beside themselves; external originals are never imported.
Where everything lives
| Menu | What it does |
|---|---|
| Window ▸ Clouded Studio ▸ To Pixel Art Tools ▸ Convert to Pixel Art | Opens the main conversion window. |
| Window ▸ … ▸ Batch Convert… | Converts a whole project selection with a saved profile. |
| Window ▸ … ▸ Create Preset Profiles | Writes one profile asset per built in preset. |
| Window ▸ … ▸ Documentation | Opens the text manual. |
| Assets ▸ Clouded Studio ▸ To Pixel Art Tools ▸ Convert to Pixel Art… | Right-click an image in the Project window to open it in the tool. |
| Assets ▸ … ▸ Batch Convert… | Right-click a selection or a folder to batch convert it. |
| Assets ▸ … ▸ Create Palette from Image | Extracts a palette asset from the selected image. |
| Assets ▸ Create ▸ Clouded Studio ▸ To Pixel Art Tools | Creates an empty Pixel Art Profile or Color Palette asset. |
Section 3The conversion window
Settings on the left, live preview on the right.
Preview controls
| Action | How |
|---|---|
| Zoom | Mouse wheel over the preview, or the − and + buttons. Zooming follows the cursor, so the detail you are pointing at stays under the pointer. |
| Pan | Middle mouse drag, or Alt + left drag. |
| Fit to window | Fit |
| Actual size | 1:1 |
| Compare before and after | Set the view mode to Compare, then drag the white divider. |
| Pixel grid | Grid, drawn once you pass 8× magnification. |
| Scale reference | Scale Reference ▸ Choose Image…, then drag the overlay around. |
Compare draws both images into the same rectangle rather than side by side, so the divider reveals the same region of each. That is what makes it possible to judge whether a shape survived the conversion, instead of only whether the two images look similar.
The overlay exists for one question that comes up constantly: is this the right resolution for my game? Drop in a character sprite you already ship and compare directly, rather than guessing from a pixel count.
Live preview
The preview reconverts a fraction of a second after you stop changing something. Conversion runs on a background thread and is cancelled the moment another change arrives, so dragging a slider stays responsive even on large images.
Turn Live Preview off in the toolbar when working with a long animation and use Refresh to convert on demand. Above 24 frames the window tells you so.
The information bar
128 × 128 px · factor 4× · palette 32 · 41 colours in output · 86 ms
Palette is how many colours the quantizer produced. Colours in output is what the final image actually contains. They differ when a stage placed after Pixel Art blends new colours in — Outline and Diffuse both do. If you need the palette to be exact, move those stages above Pixel Art or turn them off.
Section 4How the pipeline works
A conversion is a list of stages run top to bottom. You can drag them into any order in the Pipeline list, and the order changes the result more than most of the individual settings do.
Pixel Art is the pivot. Everything above it works on the full resolution source; everything below it works on the finished low resolution grid, where every pixel is one of only a few thousand and each one is clearly visible.
What moving a stage actually changes
| Stage | Above Pixel Art | Below Pixel Art |
|---|---|---|
| Smooth | Stops noise from being baked into pixels. This is where it belongs. | Just blurs the finished result. |
| Background Removal | Edge peeling has full resolution material to work with. Almost always correct. | Each peeled layer costs a whole output pixel. |
| Color Removal | Matches colours sampled from the source before quantization changes them. The usual placement. | Useful when you specifically want to remove colours from the final palette. |
| Despeckle | Nothing meaningful to do — stray pixels do not exist yet. | Removes the specks quantization left. This is where it belongs. |
| Outline | Drawn at full resolution then reduced: softer, thinner, partly anti-aliased. | Drawn onto the grid: exactly the thickness you asked for. |
| Diffuse | A painting effect applied to the source. | Scatters your finished pixels. Occasionally the effect you want, usually not. |
| Island Removal | Measures components in source pixels, so the configured size rarely means what you intend. | Measures detached fragments on the final grid. This is where it belongs. |
Section 5Stage reference
Each stage has an Enabled checkbox, shown both in the Pipeline list and inside its own section. Pixel Art is the exception: it is the conversion itself, so it always runs.
5.1Smooth
Noise reduction that preserves edges, applied to the colour channels only. Alpha is never touched — softening it would reintroduce exactly the semi transparent fringe the rest of the pipeline works to remove.
| Setting | Range | What it does |
|---|---|---|
| Method | Bilateral · Total Variation | Which algorithm to run. |
| Sigma Color | 0.02 – 0.5 | Bilateral. How different two colours may be and still be averaged together. Higher smooths across stronger colour changes. |
| Sigma Spatial | 0.5 – 10 | Bilateral. Radius of influence in pixels. Cost grows with the square of this value. |
| Weight | 0.02 – 0.5 | Total Variation. Higher produces broader, flatter blocks of colour. |
Bilateral is a blur whose weights are additionally scaled by how similar each neighbour's colour is. A neighbour across a strong edge contributes almost nothing, so noise inside a flat region is averaged away while the edge stays exactly where it was. That property is the point: an edge blurred before the resolution drop becomes a visibly wrong pixel afterwards.
Total Variation minimises the total amount of change across the image while staying close to the original. The result is piecewise constant — regions collapse into flat plateaus separated by sharp steps, which is a very good match for what pixel art wants.
Smooth runs at full source resolution by default and is by far the most expensive stage. If the preview feels sluggish, this is almost always why. Lower Sigma Spatial first.
5.2Background Removal
Turns a flat background colour into transparency, in two passes.
| Setting | Range | What it does |
|---|---|---|
| Key Color | any | The background colour to remove. White by default. |
| Tolerance | 0 – 255 | First pass, applied everywhere. Keep it low. |
| Edge Tolerance | 0 – 255 | Second pass, applied only to pixels touching background already removed. |
| Edge Passes | 0 – 15 | How many layers of blended edge to peel away. 0 disables the second pass. |
The split is the whole design. A single threshold cannot tell a background apart from a light area inside your subject, so set low it leaves a halo and set high it punches holes. The second pass can be far more permissive precisely because an enclosed area never touches the outside and is therefore unreachable by it.
Distance is measured as the largest single channel difference from the key colour, which is stricter than an average — a pixel matching on two channels but clearly off on the third is correctly kept.
Start at tolerance 25, edge tolerance 80, 3 passes. If a halo remains, raise Edge Passes before you touch either tolerance. If part of your subject vanished, lower Tolerance — that is the pass that reaches everywhere.
5.3Color Removal
Turns pixels matching any selected colour into full transparency. Use Add Color as many times as needed; each swatch participates in the same pass, and the corresponding Remove button deletes only that entry.
| Setting | Range | What it does |
|---|---|---|
| Colors | zero or more | The list of RGB colours to remove. The stage makes no change while the list is empty. |
| Tolerance | 0 – 255 | Maximum allowed difference on every RGB channel. 0 removes exact matches only. |
Matching uses the largest difference on any RGB channel. With tolerance 10, a pixel is removed only when its red, green and blue channels are each no more than 10 away from at least one selected colour. The selected swatch's alpha is ignored, and a match clears all four channels to zero.
Keep Color Removal above Pixel Art when the swatches came from the original image, before quantization changes those colours. Move it below Pixel Art only when you intend to remove colours produced by the final palette.
5.4Pixel Art
The conversion itself: resolution reduction, then colour quantization, then optional clean up.
Downscale
| Method | Use when |
|---|---|
| Nearest | Art with clean shapes. Samples the centre of each block, so edges stay perfectly hard. |
| Box | Heavy anti aliasing or fine detail, where Nearest would sample noise at random. |
| LAB Average | Same as Box, but mixes colour perceptually. Blue and yellow average to green rather than to mud. |
Both averaging methods weight the average by alpha, so fully transparent pixels cannot drag the visible colour of a block toward whatever arbitrary value they happen to store.
Factor is how many source pixels become one output pixel; a factor of 4 turns 512 into 128. Automatic Factor measures how wide the image's existing runs of identical colour already are — that recovers the real block size of art that was drawn small and scaled up. If the source has no block structure at all, it falls back to whatever factor lands the longest side near 256 pixels. It is a starting point, not an answer.
Quantization
| Method | Notes |
|---|---|
| K-Means | Clusters the image's colours perceptually. Best quality and the default. Deterministic from a seed. |
| Median Cut | The classic fast algorithm. Splits along RGB axes, so it can spend entries on wide but visually unimportant gradients. |
| Fixed Palette | Maps onto a palette asset you supply. Guarantees consistency across every asset using it. |
| Setting | Range | What it does |
|---|---|---|
| Colors | 2 – 256 | Requested palette size. Hidden when a fixed palette is assigned. |
| Palette Seed | 0 – 9999 | K-Means. A different seed gives a different but equally valid palette. |
| Ignore Transparent Pixels | on / off | Leaves fully transparent pixels out of palette building. |
If two or three colours land somewhere you dislike, nudging the seed is usually faster than fighting the colour count. Clustering has many good answers; the seed picks which one you get, and the same seed always gives the same result.
Ignore Transparent Pixels is on by default and should usually stay on. The colour stored underneath a transparent pixel is arbitrary and never visible, so including it just consumes palette entries you will never see.
Dithering
Dithering spreads the quantization error so a small palette can suggest colours it does not actually contain. Without it, a gradient mapped onto twelve colours becomes twelve hard bands. With it, the boundary between two palette colours becomes a mix of both and reads as smooth from a normal viewing distance.
Interactive illustration of the principle: one gradient reduced to the same few colours three ways. Drag the slider down to see how far dithering can stretch a very small palette.
| Method | Character |
|---|---|
| Floyd–Steinberg | Error diffusion. Organic, irregular texture that follows the image. The closest match to the original, and the best choice for a still image. |
| Ordered 2×2 | Very coarse, strongly visible pattern. |
| Ordered 4×4 | The classic retro cross hatch. A good default when the dithering should read as a deliberate style. |
| Ordered 8×8 | The finest, smoothest ordered pattern. |
Dither Strength (0 – 1) scales how much error is spread. Below 1 keeps the pattern subtle while still breaking up the worst banding, which usually suits artwork better than full strength does.
Both methods measure error perceptually. The ordered methods nudge each pixel along the direction of its own quantization error rather than along a fixed axis — so they dither correctly across boundaries between colours that differ in hue, not only across boundaries in brightness. Floyd–Steinberg scans in a serpentine pattern, alternating direction every row, which cancels the diagonal streaking that a single scan direction leaves in flat areas.
Dithering works by placing isolated, alternating pixels — which is exactly what Merge Runs and the Despeckle stage exist to remove. Use one or the other. The window warns you when both are on.
Ordered patterns depend only on pixel position, so they are identical from frame to frame. Error diffusion depends on the whole image, so a small change between frames reshuffles the noise and the pattern visibly crawls during playback.
Merge Runs
Sweeps rows and then columns, collapsing sequences of near identical colours into one flat colour. This is the automated version of the clean up an artist does by hand — a region that already reads as one flat colour still contains a dozen barely different values, and actually making it one colour is what makes the result look deliberate. Sweeping rows and columns also reinforces horizontal and vertical structure, which is the bias hand made pixel art has.
| Setting | Range | What it does |
|---|---|---|
| Merge Tolerance | 0 – 50 | Maximum perceptual distance for two pixels to join the same run. |
| Merge Passes | 1 – 8 | How many horizontal plus vertical sweeps to run. |
Tolerance is measured perceptually, so the numbers correspond to something real: about 2 is the threshold of human vision, 8–12 merges what already looks the same, and 15–25 deliberately flattens shading into bands.
Color Transfer
Applies the tone, saturation and contrast of any reference image to the result. The two images need nothing in common — a sunset photograph will push a sprite toward warm tones and lift its contrast the way the sunset's own does. Statistics are gathered from visible pixels only, so a large transparent margin cannot dictate the result.
Because the transfer moves every pixel independently and produces a continuous gradient, the image is re-quantized afterwards to bring it back to a pixel art palette.
Alpha Threshold and Sharpen
Alpha Threshold (0 – 255) forces alpha to be either fully transparent or fully opaque. Anti aliasing leaves a rim of partially transparent pixels that is invisible at full resolution but becomes a row of washed out pixels on a grid — and a visible seam wherever the sprite is drawn over a different background. Set it to 0 to keep the original alpha.
Sharpen applies a light sharpening kernel to the colour channels, useful after Box or LAB Average downscaling. Alpha is deliberately excluded so it cannot undo the alpha threshold that just ran.
5.5Despeckle
Removes connected regions smaller than Minimum Region Size (1 – 30), repainting them with the colour that occurs most often immediately around them. Regions of transparency count too. Passes (1 – 8) repeats the sweep; it stops early once nothing changes.
This catches what Merge Runs structurally cannot. A single misplaced pixel forms no run in either direction, so a row and column sweep always leaves it behind — and it is exactly the kind of speck that makes an image read as noisy rather than drawn.
5.6Outline
Darkens the boundary between distinct colour regions and around the silhouette, which is what gives hand drawn pixel art its readable shape.
| Setting | Range | What it does |
|---|---|---|
| Thickness | 1 – 4 | Outline width in pixels, grown inward. |
| Strength | 0 – 1 | How far to blend toward the outline colour. 1 replaces the pixel outright. |
| Color | any | The outline colour. |
| Minimum Contrast | 0 – 255 | How different two neighbouring colours must be to count as an edge. |
Minimum Contrast is the setting that decides whether this looks good. Too low and the outline traces every small step the quantizer left behind, turning the sprite into a wireframe. Around 90 is a good starting point for sprites; at 255 only the silhouette is drawn.
The outline is drawn on the inside of the silhouette, so it never grows the sprite's footprint. The image border is never treated as an edge — a full bleed background will not come back with a frame drawn around it.
5.7Diffuse
| Mode | What it does |
|---|---|
| Anisotropic | Blends the four quadrants around each pixel, weighted by how uniform each one is. Edges survive because a quadrant straddling an edge always has high variance and contributes little; flat areas are cleanly averaged. An oil painting effect. |
| Random | Replaces each pixel with a random neighbour. |
| Darken | Same, but only when the neighbour is darker. |
| Lighten | Same, but only when the neighbour is lighter. |
| Setting | Range | What it does |
|---|---|---|
| Radius | 1 – 6 | Quadrant size in Anisotropic; how far a pixel may travel in the scattering modes. |
| Sharpness | 0 – 10 | Anisotropic. How strongly the most uniform quadrant dominates. |
| Iterations | 1 – 10 | Scattering modes. How many times to repeat. |
| Fixed Seed / Seed | 0 – 9999 | Scattering modes. Turn Fixed Seed off for a different scatter every run. |
Anisotropic blends the quadrants rather than picking a single winner as a classic Kuwahara filter does. Near an edge the four variances end up similar, so no quadrant dominates and the result is a slight mix right at the boundary — that soft transition is what reads as a brush stroke instead of hard posterisation. Low Sharpness around 0.2–0.4 blends generously; 8 and above converges on the hard classic look.
5.8Island Removal
Deletes small foreground components that are disconnected from the rest of the image by transparency. Unlike Despeckle, it does not look for a small patch of one colour or repaint it from its neighbours: it considers all connected non-transparent pixels part of the same island and makes qualifying islands fully transparent.
| Setting | Range | What it does |
|---|---|---|
| Maximum Island Size | 1 – 4096 | Removes components containing this many pixels or fewer. A value of 3 removes islands of 1, 2 or 3 pixels and preserves islands of 4 or more. |
| Transparency Threshold | 1 – 255 | Alpha values below this threshold count as transparent while connected components are found. |
Connectivity includes all eight neighbours, so pixels touching diagonally belong to the same island. Transparency Threshold only controls this classification; it does not otherwise change partially transparent pixels that belong to a preserved component. Use Pixel Art's Alpha Threshold as well when the output itself should have hard alpha edges.
Keep Island Removal below Pixel Art so sizes are measured on the final pixel grid and it can remove fragments introduced by downscaling or quantization.
Section 6Presets
The settings interact, and the useful combinations are not obvious from the individual controls. A photograph needs smoothing before the resolution drop or the quantizer spends its palette on noise; clean vector style art needs none and is only softened by it. The presets encode those pairings.
Pick one from the Presets menu in the toolbar. Nothing is written to disk — use Window ▸ … ▸ Create Preset Profiles if you want them as assets.
| Preset | Built for | Key choices |
|---|---|---|
| Clean Sprite | Character and object art that already has clear shapes. | Nearest · K-Means 32 · merge runs · despeckle · alpha threshold |
| Bold Outline Sprite | Sprites that must read over busy backgrounds. | Clean Sprite plus a 1 px outline at contrast 90 |
| Photo to Pixel Art | Photographs and highly detailed renders. | Bilateral smoothing · Box downscale · K-Means 32 · despeckle |
| Environment and Backgrounds | Large scenes rather than single objects. | LAB Average · K-Means 64 · gentle merge tolerance |
| Retro 16 Colors | A deliberate hardware era look. | K-Means 16 · heavy merging and despeckling |
| Dithered Retro | Gradients on a very limited palette. | K-Means 12 · Ordered 4×4 dither at 0.8 · merging and despeckling off |
| Painted | A painted rather than sampled feel. | Diffuse moved above Pixel Art · Box downscale · K-Means 48 |
Section 7Animations
If your file name ends in a number — walk_001.png, walk01.png,
walk-1.png, frame1.png — the other frames beside it are detected
automatically and an Animation Sequence checkbox appears.
With it on, every frame is converted together against one shared palette. This is not a convenience. Quantizing frames independently lets each shade drift by a step or two between frames, which is invisible in a still comparison and impossible to miss once the animation plays.
Use the timeline under the preview to scrub or play back at a chosen frame rate. Convert and Save writes every frame, each keeping its original file name.
Detection needs the same prefix, the same extension and a trailing number. If your frames do not match, select them all in the Project window and use Batch Convert with Share One Palette instead — it reaches the same result without renaming anything.
Section 8Batch conversion
Select any number of images or folders in the Project window, then Assets ▸ Clouded Studio ▸ To Pixel Art Tools ▸ Batch Convert…. Pick a profile, decide whether to share one palette, and convert.
You can also add external PNG, JPG and JPEG files or folders, or drag several into the batch window.
Project and external sources can be mixed. External results always go to the configured folder inside
Assets, even when Save Next to Source is enabled, so originals remain outside
the project.
The progress bar is cancellable, and anything that fails is reported at the end rather than stopping the run at the first error.
Share One Palette builds a single palette from every selected image and applies it to all of them. Worth considering for tilesets, icon sets and anything else that is seen together: converted image by image, they end up with colours that almost match, which reads as sloppy in a way that is hard to name but easy to see.
The More menu in the conversion window batches the current selection using the settings you are looking at, which is convenient once you have dialled them in.
Section 9Profiles
A profile is an asset holding a complete set of conversion settings plus the palette and reference image they use. Finding the settings that suit a project's art style takes real experimentation, and once found they should be applied identically to everything from then on.
| Task | How |
|---|---|
| Create from current settings | Save As… in the window toolbar. |
| Create empty | Assets ▸ Create ▸ Clouded Studio ▸ To Pixel Art Tools ▸ Pixel Art Profile |
| Update an existing one | Save. |
| Discard changes | Revert. |
| Edit with a live preview | Open in To Pixel Art Window, at the top of the profile inspector. |
| Share across projects | Import and export JSON, from the window's More menu or the profile inspector. |
Profiles are plain assets, so they diff and merge in version control like anything else. Editing one in its inspector supports undo normally.
A profile saved by an older version that is missing a stage added later still loads — the stage list is rebuilt and the new stage takes its default position, rather than the file being rejected.
Section 10Palettes
Locking a set of assets to one palette is the difference between a collection of sprites and a coherent art style. Create one with Assets ▸ Create ▸ Clouded Studio ▸ To Pixel Art Tools ▸ Color Palette.
| Tool | What it does |
|---|---|
| Import… | Reads .hex, .txt and GIMP .gpl files. Blank lines and comments are ignored, so a file mixing notes with colours still loads. |
| Export… | Writes the palette out as a plain hexadecimal list. |
| Extract From | Derives a palette from an image by clustering its colours — the usual way an artist gets a palette is by pointing at art they like. |
| Sort by Hue | Groups by colour family, near greys first. Makes a large palette far easier to read. |
| Sort by Luminance | Orders from darkest to lightest. |
To use a palette, set Quantization to Fixed Palette and assign it. Right clicking an image in the Project window also offers Create Palette from Image directly.
Section 11Output and import settings
By default the result is written next to the source with a _PixelArt suffix.
Overwrite Existing is off: re-running a conversion while dialling in settings is
normal, and silently replacing a result that prefabs and scenes may already reference is not a
sensible default. Writing over the source image is blocked outright.
Apply Import Settings configures the written texture the way pixel art needs:
| Import setting | Value | Why |
|---|---|---|
| Filter Mode | Point | Anything else blurs the pixels you just created. |
| Compression | Uncompressed | Block compression mottles flat colour areas. |
| Mip Maps | Off | 2D art is drawn at a fixed scale. |
| Non-Power-of-2 | None | Rescaling on import would destroy the pixel grid. |
| Max Size | Large enough for the result | Stops the importer shrinking the image. |
| Alpha Is Transparency | On | Correct filtering around transparent edges. |
| Wrap Mode | Clamp | No bleeding from the opposite edge. |
Turn on Import as Sprite to set the texture type and pixels per unit at the same time.
Import settings such as maximum size and compression therefore do not affect the conversion, and your source does not need Read/Write enabled. The artwork on disk is the source of truth. Textures with no file behind them — generated at runtime, for instance — are read from the texture itself.
Section 12Scripting API
Everything the window does is available from code, in the editor and in builds. Namespace:
CloudedStudio.ToPixelArtTools.
Converting textures
Converts a texture with a saved profile. Returns a new point filtered texture that you own — destroy it when you are done.
Converts with settings built in code.
Converts several textures against one shared palette, as animation frames must be.
Runs the processing off the main thread. The texture is read before the task starts and the result texture created after it finishes, both on the calling thread, so no Unity object is ever touched from a worker.
// With a profile asset.
Texture2D result = PixelArtConverter.Convert(source, profile);
// With settings built in code.
var settings = new PixelArtPipelineSettings();
settings.PixelArt.ColorCount = 24;
settings.PixelArt.AutomaticFactor = false;
settings.PixelArt.Factor = 4;
settings.PixelArt.Dither = DitherMethod.Ordered4x4;
settings.ColorRemoval.Enabled = true;
settings.ColorRemoval.Colors.Add(new Rgba32(255, 0, 255));
settings.ColorRemoval.Colors.Add(new Rgba32(0, 255, 0));
settings.ColorRemoval.Tolerance = 8;
settings.Despeckle.Enabled = true;
settings.IslandRemoval.Enabled = true;
settings.IslandRemoval.MaximumIslandSize = 3;
settings.IslandRemoval.TransparencyThreshold = 1;
Texture2D custom = PixelArtConverter.Convert(source, settings);
// Starting from a preset, then adjusting.
var photo = PixelArtPresets.CreateByName("Photo to Pixel Art");
photo.PixelArt.ColorCount = 48;
// Animation frames sharing one palette.
Texture2D[] frames = PixelArtConverter.ConvertSequence(sourceFrames, settings);
Working with buffers directly
PixelBuffer is a plain RGBA32 byte buffer with no engine dependency — which is what makes
the pipeline safe to run on a background thread, and what lets it be unit tested outside Unity.
PixelBuffer buffer = TextureConverter.ToPixelBuffer(sourceTexture);
PixelArtConversionResult result = PixelArtPipeline.ProcessDetailed(buffer, settings);
Debug.Log($"factor {result.DownscaleFactor}, palette {result.Palette.Count}");
Texture2D texture = TextureConverter.ToTexture2D(result.Frame);
byte[] png = TextureConverter.EncodeToPng(result.Frame);
| Member | Meaning |
|---|---|
PixelArtConversionResult.Frames | Converted images, in the order supplied. |
PixelArtConversionResult.Frame | The first frame. Convenient for single image conversions. |
PixelArtConversionResult.DownscaleFactor | The factor used, whether configured or detected. |
PixelArtConversionResult.Palette | The palette every frame was mapped onto. |
PixelBuffer.CountDistinctColors() | How many distinct colours the result actually contains. |
Palettes and resources
var palette = new ColorPalette(new[]
{
new Rgba32(0, 0, 0),
new Rgba32(255, 255, 255),
});
var resources = new PixelArtPipelineResources { FixedPalette = palette };
settings.PixelArt.Quantization = QuantizationMethod.FixedPalette;
Texture2D result = PixelArtConverter.Convert(source, settings, resources);
| Resource | Used when |
|---|---|
FixedPalette | Quantization is set to Fixed Palette. Ignored otherwise. |
PrecomputedPalette | Always. Overrides palette generation entirely — this is how batch conversion shares one palette across many images. |
ColorTransferReference | Colour transfer is enabled. |
Settings object
| Member | Type | Notes |
|---|---|---|
Order | List<PipelineStep> | Execution order. Every stage appears exactly once. |
Smooth | SmoothSettings | Enabled, Method, SigmaColor, SigmaSpatial, TvWeight |
BackgroundRemoval | BackgroundRemovalSettings | Enabled, KeyColor, Tolerance, EdgeTolerance, EdgePasses |
ColorRemoval | ColorRemovalSettings | Enabled, Colors, Tolerance |
PixelArt | PixelArtSettings | Downscale, AutomaticFactor, Factor, Quantization, ColorCount, IgnoreTransparentPixels, PaletteSeed, Dither, DitherStrength, MergeRuns, MergeTolerance, MergePasses, ColorTransferEnabled, ColorTransferStrength, AlphaThreshold, Sharpen |
Despeckle | DespeckleSettings | Enabled, MinimumRegionSize, Passes |
Outline | OutlineSettings | Enabled, Thickness, Strength, Color, MinimumContrast |
Diffuse | DiffuseSettings | Enabled, Mode, Radius, Sharpness, Iterations, UseFixedSeed, Seed |
IslandRemoval | IslandRemovalSettings | Enabled, MaximumIslandSize, TransparencyThreshold |
Clone() returns a deep copy safe to hand to another thread.
Normalize() repairs a settings object loaded from disk: it fills in null sections and
rebuilds an incomplete stage order. Call it after deserialising settings yourself.
Determinism
Given the same input and settings, the pipeline produces byte identical output on
every platform and regardless of how many threads it used. Nothing depends on
UnityEngine.Random, System.Random or wall clock time. The single exception
is Diffuse with Fixed Seed turned off, which is opt in.
This matters more than it might seem: it means a conversion can run in CI, results can be committed, and a regression in your art pipeline shows up as a real diff rather than as noise.
Section 13Performance
Indicative figures for a 512 × 512 source on a modern desktop CPU, reducing by 4×:
| Configuration | Time |
|---|---|
| Pixel Art only, K-Means 32 colours | ~40 ms |
| Plus bilateral smoothing (Sigma Spatial 2) | ~120 ms |
| Plus total variation smoothing | ~600 ms |
- Smooth is the expensive stage. It runs at full source resolution by default, and bilateral cost grows with the square of Sigma Spatial.
- Everything after the resolution drop operates on a much smaller image and is effectively free.
- Row parallel work is spread across CPU cores automatically, and falls back to a single thread where threads are unavailable (WebGL). Results are identical either way.
- Palette building clusters the distinct colours of an image weighted by how often each occurs, rather than the individual pixels. That is mathematically identical to clustering every pixel and dramatically faster.
- Floyd–Steinberg dithering is inherently sequential and cannot be parallelised. The ordered methods can, and are.
Section 14Troubleshooting
The result has more colours than my colour count
A stage after Pixel Art is blending new colours in — Outline and Diffuse both do. Move them above Pixel Art in the pipeline list, or turn them off. The information bar shows both numbers so you can see it happening.
The output looks noisy and speckled
The source has detail in every pixel and Nearest is sampling it at random. Switch Downscale to Box or LAB Average, enable Smooth, and turn on Despeckle.
I turned on dithering but the pattern is gone
Merge Runs or Despeckle removed it. Both exist to delete isolated pixels, and the dither pattern is made of isolated pixels. Turn them off.
The dither pattern crawls when my animation plays
Switch from Floyd–Steinberg to one of the ordered methods. Error diffusion depends on the whole image, so any small change between frames reshuffles the noise; ordered patterns depend only on position and stay locked in place.
I see banding in a gradient
The palette has run out of colours. Raise Colors, or turn on Dither to trade the bands for texture — often the better trade at low colour counts.
Background removal ate part of my subject
Lower Tolerance — that is the pass which reaches everywhere. Raise Edge Passes instead to clean the remaining halo, since the edge pass cannot reach enclosed areas.
Background removal left a halo
Raise Edge Passes first, then Edge Tolerance. Leave Tolerance low.
I need to remove several unrelated colours
Use Color Removal instead of Background Removal, add every colour to its list, and raise Tolerance gradually. Keep it above Pixel Art when the swatches came from the source image. At tolerance 0 only exact RGB matches are removed.
Small disconnected pixels remain after removing the background
Enable Island Removal, keep it below Pixel Art, and set Maximum Island Size to the largest fragment that should disappear. Raise Transparency Threshold if a semi-transparent fringe is still joining the fragment to the subject.
The outline is everywhere and the sprite looks like a wireframe
Raise Minimum Contrast. It is tracing quantization steps rather than real transitions.
Colours shimmer between animation frames
Turn on Animation Sequence so all frames share one palette. If your frames are not numbered consistently, select them all and use Batch Convert with Share One Palette.
The preview does not match my imported asset
Expected. The tool reads the original file rather than the imported texture, so import settings such as maximum size and compression do not affect the conversion. See section 11.
The window is slow with a long animation
Turn off Live Preview in the toolbar and use Refresh to convert on demand. Above 24 frames the window says so.
“Fixed palette quantization was selected but no palette was supplied.”
Assign a palette asset in the Pixel Art section, or switch the quantization method to K-Means or Median Cut.
Section 15Support
Questions, bug reports and feature requests are welcome. To get a useful answer quickly, please include:
- Your Unity version and target platform.
- The source image, or one that reproduces the problem.
- The settings you used — export them as JSON from the window's More menu.
- What you expected and what you got.
To Pixel Art Tools · Version 1.0 · Clouded Studio