Files
ModelTest20260714/Kimi-K3/tools/aseprite/helpers.lua
T

230 lines
8.1 KiB
Lua

-- helpers.lua — shared palette + pixel primitives for asset generation
-- Usage: local H = dofile(ROOT .. "tools/aseprite/helpers.lua")
-- All draw helpers operate on an Aseprite Image via a "pen" table bound to an origin.
local H = {}
H.ROOT = "/Users/leidianyayi/Documents/GitHub/ModelTest20260714/Kimi-K3/"
-- ----------------------------------------------------------------------------
-- Candy palette (CONTRACT §1) + white-layer grays + a few flat utility shades.
-- Stored as {r,g,b}. No gradients, no AA — every pixel is one of these.
-- ----------------------------------------------------------------------------
H.P = {
-- grass greens
grass = {125, 201, 94}, -- #7DC95E
grass_d = { 95, 179, 74}, -- #5FB34A
grass_dd = { 74, 148, 58},
grass_l = {158, 216, 128},
-- cream
cream = {255, 243, 214}, -- #FFF3D6
cream_d = {238, 220, 178},
cream_dd = {216, 196, 150},
-- honey orange
honey = {245, 166, 35}, -- #F5A623
honey_d = {224, 143, 18},
honey_dd = {196, 120, 10},
honey_l = {250, 193, 96},
-- sky blue
sky = {143, 211, 255}, -- #8FD3FF
sky_d = {110, 186, 240},
-- stone road
stone = {232, 220, 200}, -- #E8DCC8
stone_d = {206, 190, 162},
stone_dd = {178, 160, 130},
stone_l = {245, 237, 224},
-- lake water
water = {110, 193, 228}, -- #6EC1E4
water_d = { 79, 168, 216}, -- #4FA8D8
water_dd = { 56, 140, 190},
water_l = {158, 216, 242},
-- pink
pink = {247, 183, 203}, -- #F7B7CB
pink_d = {232, 150, 176},
pink_dd = {208, 120, 150},
pink_l = {252, 208, 222},
-- brown (trunk / wood dark)
brown = {139, 90, 43}, -- #8B5A2B
brown_d = {108, 68, 30},
brown_dd = { 84, 52, 22},
brown_l = {172, 122, 72},
-- dirt road
dirt = {205, 172, 122},
dirt_d = {182, 148, 98},
dirt_l = {220, 190, 146},
-- white-layer grays (CONTRACT §1)
w_hi = {245, 245, 245}, -- #F5F5F5
w_mid = {218, 218, 218}, -- #DADADA
w_lo = {189, 189, 189}, -- #BDBDBD
w_dk = {150, 150, 150},
w_dd = {110, 110, 110},
-- reds
red = {226, 87, 77},
red_d = {198, 66, 56},
red_l = {240, 130, 120},
-- blues
blue = { 91, 155, 213},
blue_d = { 62, 125, 190},
blue_l = {140, 190, 232},
-- yellows
yellow = {247, 214, 92},
yellow_d = {224, 186, 55},
yellow_l = {252, 228, 140},
-- foliage
leaf = { 86, 168, 78},
leaf_d = { 64, 138, 60},
leaf_dd = { 46, 108, 44},
leaf_l = {120, 192, 110},
-- wood
wood = {201, 152, 96},
wood_d = {176, 126, 74},
wood_dd = {150, 104, 58},
wood_l = {220, 178, 124},
-- stone wall (cool gray)
swall = {196, 190, 178},
swall_d = {164, 158, 146},
swall_dd = {134, 128, 116},
swall_l = {214, 209, 200},
-- berry
berry = {206, 62, 96},
berry_d = {172, 44, 76},
-- misc
skin = {255, 224, 190},
skin_d = {238, 198, 156},
hair = {120, 84, 52},
hair_d = { 96, 66, 40},
hair_l = {152, 112, 74},
black = { 54, 44, 40},
ink = { 40, 34, 30},
white = {255, 255, 255},
grey = {150, 150, 150},
grey_d = {108, 108, 108},
grey_l = {196, 196, 196},
screen = { 44, 58, 54},
screen_l = {120, 220, 160},
metal = {178, 184, 190},
metal_d = {140, 146, 152},
flame = {255, 214, 92},
flame_d = {245, 140, 40},
leaf2 = { 60, 150, 70},
}
-- make an Aseprite color from a palette name (or {r,g,b} table) + optional alpha
function H.col(name, a)
local t = name
if type(name) == "string" then t = H.P[name] end
return app.pixelColor.rgba(t[1], t[2], t[3], a or 255)
end
-- ----------------------------------------------------------------------------
-- Pen: a table of draw methods bound to an image + origin (ox, oy).
-- All coordinates passed to pen methods are LOCAL to the origin.
-- ----------------------------------------------------------------------------
function H.at(img, ox, oy)
local t = { img = img, ox = ox, oy = oy }
function t.p(x, y, c) img:drawPixel(ox + x, oy + y, c) end
function t.pn(x, y, name, a) img:drawPixel(ox + x, oy + y, H.col(name, a)) end
function t.rect(x, y, w, h, c)
for j = 0, h - 1 do for i = 0, w - 1 do img:drawPixel(ox + x + i, oy + y + j, c) end end
end
function t.rectn(x, y, w, h, name, a)
local c = H.col(name, a)
for j = 0, h - 1 do for i = 0, w - 1 do img:drawPixel(ox + x + i, oy + y + j, c) end end
end
function t.hl(x, y, len, c) for i = 0, len - 1 do img:drawPixel(ox + x + i, oy + y, c) end end
function t.hln(x, y, len, name, a)
local c = H.col(name, a); for i = 0, len - 1 do img:drawPixel(ox + x + i, oy + y, c) end
end
function t.vl(x, y, len, c) for j = 0, len - 1 do img:drawPixel(ox + x, oy + y + j, c) end end
function t.vln(x, y, len, name, a)
local c = H.col(name, a); for j = 0, len - 1 do img:drawPixel(ox + x, oy + y + j, c) end
end
-- outline rectangle
function t.frame(x, y, w, h, c)
t.hl(x, y, w, c); t.hl(x, y + h - 1, w, c)
t.vl(x, y, h, c); t.vl(x + w - 1, y, h, c)
end
function t.framen(x, y, w, h, name, a)
t.frame(x, y, w, h, H.col(name, a))
end
-- filled disc (filled circle), integer radius
function t.disc(cx, cy, r, c)
for yy = -r, r do for xx = -r, r do
if xx * xx + yy * yy <= r * r then t.p(cx + xx, cy + yy, c) end
end end
end
function t.discn(cx, cy, r, name, a) t.disc(cx, cy, r, H.col(name, a)) end
-- filled ellipse
function t.ellipse(cx, cy, rx, ry, c)
for yy = -ry, ry do for xx = -rx, rx do
if (xx * xx) * (ry * ry) + (yy * yy) * (rx * rx) <= (rx * rx) * (ry * ry) then
t.p(cx + xx, cy + yy, c)
end
end end
end
function t.ellipsen(cx, cy, rx, ry, name, a) t.ellipse(cx, cy, rx, ry, H.col(name, a)) end
return t
end
-- pen for a 16x16 tile by id (tileset is 16 columns)
function H.tile(img, id)
local ox = (id % 16) * 16
local oy = math.floor(id / 16) * 16
return H.at(img, ox, oy)
end
-- ----------------------------------------------------------------------------
-- Motif helpers (drawn through a pen `t`, local coords)
-- ----------------------------------------------------------------------------
-- a small 5-petal flower centered at (cx,cy)
function H.flower(t, cx, cy, petal, center)
local pc = H.col(petal); local cc = H.col(center or "yellow")
t.p(cx, cy - 1, pc); t.p(cx, cy + 1, pc)
t.p(cx - 1, cy, pc); t.p(cx + 1, cy, pc)
t.p(cx, cy, cc)
end
-- a window with brown frame + sky panes, top-left (x,y), size w x h
function H.window(t, x, y, w, h, glass)
glass = glass or "sky"
t.rectn(x, y, w, h, "brown_d")
t.rectn(x + 1, y + 1, w - 2, h - 2, glass)
-- mullions
local mx = x + math.floor(w / 2)
local my = y + math.floor(h / 2)
t.vln(mx, y + 1, h - 2, "brown_d")
t.hln(x + 1, my, w - 2, "brown_d")
-- glass highlight
t.pn(x + 2, y + 2, "sky_l" == glass and "white" or "water_l")
end
-- ----------------------------------------------------------------------------
-- Mirror pen: wraps a pen `t`, flipping x within a `w`-wide frame.
-- Lets one directional drawing serve both left and right facings.
-- ----------------------------------------------------------------------------
function H.mirrorX(t, w)
local m = {}
function m.p(x, y, c) t.p(w - 1 - x, y, c) end
function m.pn(x, y, name, a) t.pn(w - 1 - x, y, name, a) end
function m.rect(x, y, ww, h, c) t.rect(w - x - ww, y, ww, h, c) end
function m.rectn(x, y, ww, h, name, a) t.rectn(w - x - ww, y, ww, h, name, a) end
function m.hl(x, y, len, c) t.hl(w - x - len, y, len, c) end
function m.hln(x, y, len, name, a) t.hln(w - x - len, y, len, name, a) end
function m.vl(x, y, len, c) t.vl(w - 1 - x, y, len, c) end
function m.vln(x, y, len, name, a) t.vln(w - 1 - x, y, len, name, a) end
function m.framen(x, y, ww, h, name, a) t.framen(w - x - ww, y, ww, h, name, a) end
function m.discn(cx, cy, r, name, a) t.discn(w - 1 - cx, cy, r, name, a) end
function m.ellipsen(cx, cy, rx, ry, name, a) t.ellipsen(w - 1 - cx, cy, rx, ry, name, a) end
return m
end
-- create a fresh RGB sprite + return (sprite, image)
function H.new(w, h)
local spr = Sprite(w, h, ColorMode.RGB)
local img = app.activeImage
return spr, img
end
return H