From aa8fa3ddf9e57871de46ce3eb84de2561487b9af Mon Sep 17 00:00:00 2001 From: Jurjen Ladenius Date: Wed, 29 Jul 2026 21:34:14 +0200 Subject: [PATCH] Art: emit the palette as .gpl/.ase/.aco as well as .act The .act files only helped Photoshop. Affinity imports .ase and .aco; Inkscape, GIMP, Krita and Aseprite want .gpl. tools/make_palettes.py now generates all four plus swatch PNGs, for both the full 16 and the 11-colour portrait subset, all derived from the same PALETTE table shared with kissaten.c so nothing can drift. Colour names ride along in .gpl/.ase/.aco, so the swatches show up labelled ("skin", "lamp glow", "dusk violet") rather than as anonymous chips. .ase output verified by reading it back and checking all 11 colours round-trip exactly. Co-Authored-By: Claude Opus 5 --- .../art/affinity-aki-neutral.png | Bin 0 -> 4661 bytes .../kissaten_yugure/art/aki-neutral-48b.png | Bin 0 -> 610 bytes .../kissaten_yugure/art/kissaten-full.aco | Bin 0 -> 704 bytes .../kissaten_yugure/art/kissaten-full.ase | Bin 0 -> 740 bytes .../kissaten_yugure/art/kissaten-full.gpl | 20 ++++ .../kissaten_yugure/art/kissaten-full.png | Bin 0 -> 650 bytes .../kissaten_yugure/art/kissaten-portrait.aco | Bin 0 -> 468 bytes .../kissaten_yugure/art/kissaten-portrait.ase | Bin 0 -> 494 bytes .../kissaten_yugure/art/kissaten-portrait.gpl | 15 +++ .../kissaten_yugure/art/kissaten-portrait.png | Bin 0 -> 474 bytes .../kissaten_yugure/tools/make_palettes.py | 87 ++++++++++++++++++ 11 files changed, 122 insertions(+) create mode 100644 projects/kissaten_yugure/art/affinity-aki-neutral.png create mode 100644 projects/kissaten_yugure/art/aki-neutral-48b.png create mode 100644 projects/kissaten_yugure/art/kissaten-full.aco create mode 100644 projects/kissaten_yugure/art/kissaten-full.ase create mode 100644 projects/kissaten_yugure/art/kissaten-full.gpl create mode 100644 projects/kissaten_yugure/art/kissaten-full.png create mode 100644 projects/kissaten_yugure/art/kissaten-portrait.aco create mode 100644 projects/kissaten_yugure/art/kissaten-portrait.ase create mode 100644 projects/kissaten_yugure/art/kissaten-portrait.gpl create mode 100644 projects/kissaten_yugure/art/kissaten-portrait.png create mode 100644 projects/kissaten_yugure/tools/make_palettes.py diff --git a/projects/kissaten_yugure/art/affinity-aki-neutral.png b/projects/kissaten_yugure/art/affinity-aki-neutral.png new file mode 100644 index 0000000000000000000000000000000000000000..1ecd221483c4447e6a6ee861d2beec6ddb2939f6 GIT binary patch literal 4661 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 D&sX$b literal 0 HcmV?d00001 diff --git a/projects/kissaten_yugure/art/aki-neutral-48b.png b/projects/kissaten_yugure/art/aki-neutral-48b.png new file mode 100644 index 0000000000000000000000000000000000000000..08586713039a03f1311356f84f425966bb0465a9 GIT binary patch literal 610 zcmV-o0-gPdP)%N#>04-4%4$RMAY&Jn|%(mvsuX(AgIb{Jt?%!kEZ4!YHc|X)zscr z0nIdFAdx0)q0JbOF&h8k5}*O&!CUw-0zj{pe+YB>8STDPBB5glgic-Do2Zm*Ah*QX zLZC7FZXo@yfyQ#dDj;jL+kOn_aK?NL1fBN20VXjK$U?ID)Iv1ddLXyOtPPhS-&qLs zVY>5zOkV(*3J}V%Tkk0^;nG3OjRJ01}_>W09`^Y2V`)U23*Z@BgK_XZ$^W5 z%2@&E*_%_<9`j8?b2DKuVdqCc1)AN`04f53ABBN58X#57neHB%ARyA)!>AuRIPG^D`i}%0?hIPG=sGOqIvrFngIj40i8|Bf|&HJbQY;6<+Yq zUbD$jRf0m(BrFu8Syc(mbBqg0X`19ytoW2)e5#F6(UgoPG|%!1nU%hpW>)glxzx_I zl$dtC=7=W@=uzW@Gd}t5(Gm~p==^byfRWw~M@CykeJ4Di$(0}2;=;_pZ<_Cl4UCn| zI_?VKF?ZhMz!|F^t_`PjoML3T#hy5D7EODV9dV1d%wJhF*O2`!^KXAS)U5B6w9j4$pJ*rP34`9)TJdgh#qUVbS&bI(AgM||^r;yf|lF|XG| xza;LsQNTMN@uB%`IY+TNE4Cw(ahbE+95S6orok|3!)qAVEY#T)1+XprGz`=_)m`EhZgFQVXtp1g-C)@6!4(o_jOn zjA?17g>!GdbIx4cU0q`Z^6Kk(iXAklkYa)w&pa#S{M`VzHq@+e922Iz!WM_9vy<{%SZb-(-(mVlwu9CFK?a&KY% z+2?l{GU{tc8X0rTN%Jp_V7v6<)i2D&aCh!{ahV8t;L%T1)YqMDG{)dYNVb literal 0 HcmV?d00001 diff --git a/projects/kissaten_yugure/art/kissaten-full.gpl b/projects/kissaten_yugure/art/kissaten-full.gpl new file mode 100644 index 0000000..243c00c --- /dev/null +++ b/projects/kissaten_yugure/art/kissaten-full.gpl @@ -0,0 +1,20 @@ +GIMP Palette +Name: Kissaten Yugure (full) +Columns: 16 +# + 0 0 0 transparent + 36 36 36 outline + 73 36 36 dark wood +146 73 36 mid wood +182 109 73 light wood +255 182 73 lamp glow +255 219 146 cream +109 73 73 muted wall + 73 36 146 dusk deep +146 73 182 dusk violet +219 109 109 dusk rose +255 146 73 horizon amber +109 36 0 coffee + 73 109 182 coat blue +255 182 146 skin +255 255 219 warm white diff --git a/projects/kissaten_yugure/art/kissaten-full.png b/projects/kissaten_yugure/art/kissaten-full.png new file mode 100644 index 0000000000000000000000000000000000000000..937b0b61ce4926ae625645a251573fdb3b5ce22b GIT binary patch literal 650 zcmeAS@N?(olHy`uVBq!ia0y~yU;;8395_JKs1*KtJAX<-+h;nuN76V9`)6& o+WO|b-ZGHcqhLgbz=8e08Cw#I0yPhJ7=r@B)78&qol`;+0E>n*Z~y=R literal 0 HcmV?d00001 diff --git a/projects/kissaten_yugure/art/kissaten-portrait.aco b/projects/kissaten_yugure/art/kissaten-portrait.aco new file mode 100644 index 0000000000000000000000000000000000000000..98e72181f310ca164f71462ea7730cc181b55d6c GIT binary patch literal 468 zcmY*VTM~jW5R1MW&fg?&3 z_~3~%1~M)GSvegJ5Gu=MKWCHwJV6l_8 z=6nhHt2skKeXHtx5A3M6xbv&hhUr4|)?N|PU8(FNL(|RP8+^IHUWfI+Bj`MY+ep}} IA){0655*T^u>b%7 literal 0 HcmV?d00001 diff --git a/projects/kissaten_yugure/art/kissaten-portrait.ase b/projects/kissaten_yugure/art/kissaten-portrait.ase new file mode 100644 index 0000000000000000000000000000000000000000..dd52a89983666da910413d60688042916dfc2e02 GIT binary patch literal 494 zcmZ9JO-{m46h@CE;tvzT0!(9!AuhlnjV9_`hK`C9Ft*evgsDqF+>7o7Sd8DjK4{Z6 zP1E$;@16I(oBrKB2iVo}_XWok%$bq#!ju#qA8w;wd-=6{XgJyBlpzW4yb`g{RH5&G zdbRql(U+W%D{)w7{@@~CCU*FV3#^?GA76_ZRRId7uJnl0qxCh;fu zL`g?9d6sqR6D9Su*_unmA@?5A;G8Ho3;PS}R~*hcQfk3Sce-!QI5p?}maQ3=_|67O qobPFCK@;X1EY3LOL;c!Gl&1P$GhO&Ou`?n6XI~soqh-b_I literal 0 HcmV?d00001 diff --git a/projects/kissaten_yugure/art/kissaten-portrait.gpl b/projects/kissaten_yugure/art/kissaten-portrait.gpl new file mode 100644 index 0000000..df13a9a --- /dev/null +++ b/projects/kissaten_yugure/art/kissaten-portrait.gpl @@ -0,0 +1,15 @@ +GIMP Palette +Name: Kissaten Yugure (portrait) +Columns: 11 +# + 36 36 36 outline + 73 36 36 dark wood +146 73 36 mid wood +182 109 73 light wood +255 182 73 lamp glow +255 219 146 cream +109 73 73 muted wall +109 36 0 coffee + 73 109 182 coat blue +255 182 146 skin +255 255 219 warm white diff --git a/projects/kissaten_yugure/art/kissaten-portrait.png b/projects/kissaten_yugure/art/kissaten-portrait.png new file mode 100644 index 0000000000000000000000000000000000000000..f61ed293ea0bd00645c2afbe44473850da27a9b7 GIT binary patch literal 474 zcmeAS@N?(olHy`uVBq!ia0y~yU`znA9XObPigh}%Mb6D{u`2dU%P5H", len(n) + 1) + nm + b"RGB " + + struct.pack(">fff", c[0] / 255, c[1] / 255, c[2] / 255) + + struct.pack(">H", 2)) # 2 = normal colour + blocks += struct.pack(">HI", 0x0001, len(body)) + body + open(path, "wb").write(b"ASEF" + struct.pack(">HHI", 1, 0, len(cols)) + blocks) + + +def aco(path, cols, names): + # v1 then v2 concatenated — v1 for old readers, v2 carries the names + v1 = struct.pack(">HH", 1, len(cols)) + for c in cols: + v1 += struct.pack(">HHHHH", 0, c[0] * 257, c[1] * 257, c[2] * 257, 0) + v2 = struct.pack(">HH", 2, len(cols)) + for c, n in zip(cols, names): + v2 += struct.pack(">HHHHH", 0, c[0] * 257, c[1] * 257, c[2] * 257, 0) + v2 += struct.pack(">I", len(n) + 1) + n.encode("utf-16-be") + b"\x00\x00" + open(path, "wb").write(v1 + v2) + + +def act(path, cols): + d = bytearray() + for c in cols: + d += bytes(c) + d += bytes(768 - len(d)) + open(path, "wb").write(bytes(d)) + + +def swatches(path, cols, sw=32, h=64): + write_png(path, [[c for c in cols for _ in range(sw)]] * h) + + +def emit(stem, idx, title): + cols = [PALETTE[i] for i in idx] + names = [NAMES[i] for i in idx] + p = lambda ext: os.path.normpath(os.path.join(OUT, f"{stem}.{ext}")) + gpl(p("gpl"), cols, names, title) + ase(p("ase"), cols, names) + aco(p("aco"), cols, names) + act(p("act"), cols) + swatches(p("png"), cols) + print(f"{stem}: {len(cols)} colours -> .gpl .ase .aco .act .png") + + +if __name__ == "__main__": + emit("kissaten-full", list(range(16)), "Kissaten Yugure (full)") + emit("kissaten-portrait", PORTRAIT_IDX, "Kissaten Yugure (portrait)") + # exact 1px-per-entry image, for generators that take a palette image + write_png(os.path.normpath(os.path.join(OUT, "palette.png")), [list(PALETTE)]) + print("palette.png: 16x1 exact")