Add palette quantization and automatic shading tools#8
Merged
Conversation
Adds quantize_palette tool with three algorithms (median_cut, k-means, octree) and optional Floyd-Steinberg dithering. Adds apply_auto_shading tool with geometry-based shading, per-pixel normal calculations, three styles, and eight light directions. Fixes ImportImage color mode conversion using BlendMode.SRC for proper indexed-to-RGB palette handling. Includes examples and integration tests for both tools. Fixes #7
Updates ImportImage test assertions to match new cel creation pattern. Fixes MedianCutQuantization to stop splitting when all colors are identical instead of continuing to request more buckets. Corrects CountUniqueColors test to use three distinct opaque colors instead of mixing transparent and opaque black pixels.
There was a problem hiding this comment.
Pull Request Overview
Adds two new MCP tools to enhance pixel art workflows: palette quantization and automatic shading. Also updates import behavior, examples, and documentation.
- New tools: quantize_palette (median_cut, kmeans, octree; optional dithering; transparency handling; indexed conversion) and apply_auto_shading (3 styles, 8 light directions, intensity, optional hue shift)
- Bug fixes: ImportImage color conversion and ApplyAutoShadingResult cel creation
- Examples and tests: Integration and unit tests; example programs producing visual outputs
Reviewed Changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/tools/quantization.go | Implements quantize_palette tool and image export/quantize/apply flow |
| pkg/tools/auto_shading.go | Implements apply_auto_shading tool and shaded image apply flow |
| pkg/tools/quantization_integration_test.go | Integration tests for quantization algorithms and dithering |
| pkg/tools/auto_shading_integration_test.go | Integration tests for auto-shading styles and directions |
| pkg/server/server.go | Registers new tools with MCP server |
| pkg/aseprite/quantization.go | Core quantization algorithms and helpers (median cut, octree, dithering utils) |
| pkg/aseprite/quantization_test.go | Unit tests and benchmarks for quantization and dithering utilities |
| pkg/aseprite/lua_quantization.go | Lua generator to apply quantized palette and report JSON |
| pkg/aseprite/lua_auto_shading.go | Lua generator to apply shaded result and report JSON |
| pkg/aseprite/lua_export.go | Fixes ImportImage to use newCel with converted image |
| pkg/aseprite/lua_canvas.go | Adds FlattenLayers Lua helper |
| examples/quantization/main.go | End-to-end example for quantization comparisons |
| examples/shading/main.go | End-to-end example for auto-shading comparisons |
| examples/README.md | Documents the new examples and outputs |
| README.md | Adds quantization and auto-shading features to overview |
| CLAUDE.md | Documents new modules and patterns |
| CHANGELOG.md | Bumps to 0.4.0 with features and fixes |
Comments suppressed due to low confidence (2)
pkg/aseprite/lua_quantization.go:1
- Go's fmt.Sprintf will eagerly consume the %s placeholders intended for Lua's string.format, resulting in missing arguments and malformed JSON (you only pass two runtime args: colorMode and the palette string). Escape the two Lua-side placeholders as %%s so Go leaves them intact, and ensure the remaining placeholders are satisfied by the Go fmt arguments. For example, change lines 114-115 to use "%%s" and "[%%s]" respectively; keep original_colors, quantized_colors, and algorithm_used filled by Go.
package aseprite
pkg/aseprite/lua_auto_shading.go:1
- Same formatting issue as in ApplyQuantizedPalette: Go's fmt.Sprintf will treat %s as its own placeholder, but you only supply two integers (colors_added and regions_shaded) to the outer fmt. Escape the Lua-side %s as %%s so the palette is provided by Lua string.format at runtime, and keep the two %d placeholders satisfied by the Go fmt arguments.
package aseprite
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
- Implement Floyd-Steinberg dithering with pixel remapping - Add ReplaceWithImage function to apply dithered results back to sprite - Set default values for preserve_transparency and convert_to_indexed - Remove redundant file close in auto_shading - Use gen.ExportSprite instead of inline Lua script for consistency - Add integration test covering full dithering workflow
The dither parameter was never used in QuantizePalette since the function only computes a color palette and doesn't modify image pixels. Dithering is applied separately at the tool layer via RemapPixelsWithDithering when input.Dither is true.
Test was hanging due to 4,096 separate ExecuteLua calls to draw individual pixels. Now batches all pixels into a single DrawPixels call. Also updates function signatures to match current API.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds two new MCP tools for advanced pixel art workflows:
quantize_palette- Reduces sprite colors using industry-standard algorithmsapply_auto_shading- Automatically adds geometry-based shading to spritesFixes #7
Changes
New Tools
quantize_palette:
apply_auto_shading:
Bug Fixes
ImportImagecolor mode conversion usingBlendMode.SRCfor proper indexed→RGB palette handlingApplyAutoShadingResultto create new cel instead of drawing onto existing celExamples
examples/quantization/- Demonstrates all three algorithms with side-by-side comparisonexamples/shading/- Shows all styles, intensities, light directions, and hue shifting effectsTesting
Output Examples
Quantization:
Shading:
Documentation