ci-platforms / darwin amd64 smoke (push) Skipped
ci-platforms / windows amd64 smoke (push) Skipped
ci-platforms / darwin arm64 smoke (push) Skipped
ci / checks (push) Successful in 9m10s
ci / build (amd64, linux, ubuntu-24.04) (push) Successful in 12m25s
ci / release (push) Failing after 4m59s
asset.pixels: pixel art as a character grid and a palette; frames of one size become an atlas with a sprite per frame and a flipbook clip; a preview image in the answer.
asset.svg: an SVG subset drawn by an in-tree rasterizer (format/svg) for tiles, UI and icons.
art module: project.aego art { palette pixelsPerUnit }, the default palette and scale for drawings; Project Health HLT009 for pixel art outside the palette.
The agent prompts say to draw instead of building sprites from rectangles.
Agent runs open the asset index shared without a warning; prefab.create on a scene open in the editor goes through the prefab service, so unsaved scenes work.
scene_run with shot names xvfb when there is no display; local make ci lists untracked files outside .gitignore.
66 lines
1.8 KiB
Go
66 lines
1.8 KiB
Go
package pixelart
|
|
|
|
import (
|
|
"image"
|
|
"image/color"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestFramesMakeAnAtlas(t *testing.T) {
|
|
pal, err := ParsePalette(`{"r": "#d0312d", "s": "#f4c7a1", ".": "transparent"}`)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s, err := Parse("idle:\n.rr.\nrssr\nrun1:\nr..r\n.ss.\n", pal, 2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if s.Image.Bounds() != image.Rect(0, 0, 16, 4) || len(s.Cells) != 2 || s.Cells[1] != image.Rect(8, 0, 16, 4) {
|
|
t.Fatalf("atlas %v cells %v", s.Image.Bounds(), s.Cells)
|
|
}
|
|
if s.Names[0] != "idle" || s.Names[1] != "run1" {
|
|
t.Fatalf("names %v", s.Names)
|
|
}
|
|
red := color.NRGBA{0xd0, 0x31, 0x2d, 255}
|
|
if s.Image.NRGBAAt(2, 0) != red || s.Image.NRGBAAt(3, 1) != red || s.Image.NRGBAAt(0, 0).A != 0 {
|
|
t.Fatal("scale 2 did not repeat the pixels")
|
|
}
|
|
if s.Image.NRGBAAt(8, 0) != red {
|
|
t.Fatal("the second frame is not in its cell")
|
|
}
|
|
}
|
|
|
|
func TestPairsPaletteAndSingleFrame(t *testing.T) {
|
|
pal, err := ParsePalette("a=#000 b=white")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s, err := Parse("ab\nba", pal, 1)
|
|
if err != nil || len(s.Names) != 1 || s.Names[0] != "" {
|
|
t.Fatalf("%v %v", s, err)
|
|
}
|
|
if off, opaque := OffPalette(s.Image, []color.NRGBA{{0, 0, 0, 255}}); off != 2 || opaque != 4 {
|
|
t.Fatalf("off %d of %d", off, opaque)
|
|
}
|
|
}
|
|
|
|
func TestMistakesAreNamed(t *testing.T) {
|
|
pal, _ := ParsePalette("a=#000")
|
|
for in, want := range map[string]string{
|
|
"ax": `'x' is not in the palette`,
|
|
"a:\naa\naa\nb:\naa": "has 1 rows",
|
|
"a:\naa\nb:\naaa": "rows of 3 and 2",
|
|
"": "empty",
|
|
"a:\naa\na:\naa": "twice",
|
|
} {
|
|
_, err := Parse(in, pal, 1)
|
|
if err == nil || !strings.Contains(err.Error(), want) {
|
|
t.Errorf("%q: %v, want %q", in, err, want)
|
|
}
|
|
}
|
|
if _, err := ParsePalette("ab=#000"); err == nil {
|
|
t.Error("a two-character key was accepted")
|
|
}
|
|
}
|