High-Speed Palette Quantization using the Median-Cut Algorithm
This Lua script for Aseprite implements the Median-Cut algorithm, an industry-standard technique for generating an optimal palette in the shortest time possible. It achieves fast and high-quality color reduction, even for large sprites with thousands of unique colors.
SAVE YOUR WORK BEFORE RUNNING THIS SCRIPT!
π PERFORMANCE IMPROVED: The algorithm has been optimized from
$O(N^2)$ to$O(N \log K)$ . This drastically reduces the risk of Aseprite freezing or crashing with large images. However, as a standard precaution:
- Save your work (
Ctrl+S/Cmd+S)- Duplicate your sprite (File > Save As)
- Test on a small copy first
- Download
color_reducer.lua - In Aseprite: File β Scripts β Open Scripts Folder
- Copy the
.luafile into the folder - File β Scripts β Rescan Scripts
- Open your sprite or animation in Aseprite
- Show/Hide layers as needed (only visible layers will be processed)
- File β Scripts β Color Reducer
- Enter target color count (e.g.,
32) - Click "Generate Palette" and wait for processing
This method uses a spatial approximation to find the representative colors, avoiding the computationally expensive "all-pairs" comparison that slows down clustering algorithms.
- Extract all unique colors from visible layers.
- Identify a bounding box containing all colors in the 3D RGB space.
- Split the box into two smaller boxes by cutting it at the median of its longest color axis (R, G, or B).
-
Repeat the splitting process recursively until the exact target color count (
$K$ ) is reached. - Final Color: The final color for each box is the average of all colors contained within it.
- Remap all pixels to the nearest color in the final palette.
-
Time Complexity:
$O(N \log K)$ -
$N$ : Number of unique initial pixels/colors. -
$K$ : Number of target colors (e.g., 16, 32). -
Result: Performance is near-linear and extremely fast, even with
$10,000+$ unique colors.
-
- Best for: All palette sizes, including large, high-color images where speed is critical.
- Memory usage: Moderate, due to caching of unique colors.
- RGB Mode: Processed directly
- Indexed Mode: Automatically converted to RGB Note: Original palette indexes will be lost
AI tools often create color noise with slightly varying hues. This script reduces them to clean, consistent colors.
Before: 450 colors with noise Β After: 32 clean colors Β Result: Ready for pixel art editing
Reduce sprite colors to match platform limitations (GameBoy: 4 colors, NES: 64 colors, etc.)
Force all frames in an animation to use the exact same color palette
The following features are not currently implemented and are considered future features:
-
Undo Guarantee (
Ctrl+Z)- Ensure that the use of
app.transactionreliably groups and allows undoing all changes.
- Ensure that the use of
-
Selection Support (
MTool)- Allow the script to act only on pixels within the active selection, instead of the entire sprite.
-
Dithering Option
- Integrate a dithering algorithm (e.g., Floyd-Steinberg) to smooth color transitions after reduction.
-
Preset Palettes
- Option to reassign simplified colors to an external fixed palette (e.g., DB32, GameBoy).
- Aseprite v1.2.40 or higher
Test with various image types:
- Small sprites (64x64)
- Large images (1024x1024)
- Animations with multiple frames
- Different color depths
- Fork the repository
- Create a feature branch
- Test your changes
- Submit a pull request
This script is licensed under the MIT License. See LICENSE for details.
If this script helped you, consider:
- β Starring this repository
- π Reporting issues
- π‘ Suggesting features
Created by: @deveduar
This Lua script for Aseprite automates the import of animation sequences and their metadata directly from a Pixel Lab JSON export file.
The script creates a new Sprite in Aseprite, imports the individual PNG frames, and generates the corresponding Animation Tags for immediate use in your project.
This tool is specifically developed to process the metadata.json structure generated when exporting character assets from the Pixel Lab tool. It ensures stable and correct parsing of the animation structure, paths, and frame data.
-
Pixel Lab Compatibility: Built to read the standard JSON structure output by Pixel Lab, including
rotationsand namedanimations. -
Bulk Import: Loads multiple animations and static poses (rotations) in a single run.
-
Animation Tags (
Tags): Automatically creates Aseprite Tags based on the animation name and direction (e.g.,picking-up_east,Idle_Static_south). -
Robust JSON Decoder: Uses a Lua JSON decoder to handle complex metadata files within the constrained Aseprite environment, avoiding the common "index nil value" errors.
Ensure your project structure matches the relative paths in your metadata.json file. The script expects the JSON file to be in the parent directory of the image folders (rotations, animations).
/your_character_project
|-- metadata.json
|-- /rotations
| |-- south.png
| |-- north.png
|-- /animations
|-- /picking-up
|-- /east
|-- frame_000.png
|-- frame_001.png
|-- ...
- Save the Lua script code as
pixel-lab-impoter-json.lua. - Place the file in Aseprite's scripts folder.
- Restart Aseprite.
- In Aseprite, go to
File>Scriptsand selectpixel-lab-impoter-json.lua. - A dialog will appear. Click the file selection button and choose your
metadata.jsonfile. - Click
Import.
The script will create a new Sprite with the correct dimensions, all frames imported, and all animations set up as Aseprite Tags.
The script reads the following primary objects from the Pixel Lab export:
Used to initialize the Aseprite Sprite dimensions and initial filename.
JSON
{
"character": {
"name": "Character_Name",
"size": {
"width": 48,
"height": 48
}
},
// ...
This object dictates which images to import and how to name the animation tags.
| JSON Key | Content Type | Resulting Tag Naming Convention |
|---|---|---|
rotations |
Single image path per direction. | Idle_Static_{direction} (e.g., Idle_Static_south) |
animations |
Array of image paths per direction. | {animation_name}_{direction} (e.g., picking-up_east) |
JSON
"frames": {
"rotations": {
"south": "rotations/south.png",
"west": "rotations/west.png"
},
"animations": {
"picking-up": {
"east": [
"animations/picking-up/east/frame_000.png",
"animations/picking-up/east/frame_001.png"
],
"west": [
// ... list of paths
]
}
}
}
}
Note: Although Pixel Lab exports may contain
keypointsdata, the current version of this script ignores those fields and focuses solely on importing the frames and tags.
Aseprite script that instantly resizes sprites using the native C++ engine for maximum speed and performance.
- Aseprite v1.2.40 or higher
- Script extension enabled
- Download the
auto_resize_by_block_matrix_C_Module.luafile - In Aseprite, go to File β Scripts β Open Scripts Folder
- Copy the file into the opened folder
- Restart Aseprite or rescan scripts (File β Scripts β Rescan Scripts Folder)
- Open a sprite in Aseprite
- Go to File β Scripts β Auto Resize by Block Matrix (C++ Module)
- Enter a Division Factor:
- 2 = Reduce to 50% (half the original size)
- 4 = Reduce to 25% (quarter of the size)
- 1.5 = Reduce to 66.6%
- The script will show the new size in real-time
- Click "INSTANT RESIZE" to apply
This script uses Aseprite's internal app.command.SpriteSize command (written in C++) to resize the entire sprite at once, including all layers and frames.
- Scaling method:
bilinearinterpolation - Origin position:
Top-Leftcorner - Aspect ratio: Locked (
lockRatio = true) - Scope: Entire sprite (all frames and layers)
- Only allows reduction (factor > 1)
- Factor must be a number greater than 1
- Prevents resizing to 0x0 pixels
- Result is rounded down (floor)
- For extreme reductions (e.g., 16x to 1x), consider applying multiple progressive reductions
- The bilinear method is ideal for pixel art that needs controlled anti-aliasing
- Always work on a copy of your original file
This script is distributed under the MIT License. You can freely modify and distribute it.
If you encounter issues:
- Verify that a sprite is active
- Ensure you're using a numeric factor greater than 1
- Check that your Aseprite version is compatible (v1.2.40+)
Note: This script is perfect for workflows requiring frequent asset resizing, such as tileset preparation, multiple icon creation, or sprite optimization for different resolutions.